mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 21:00:17 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9eb639e891 | ||
|
|
4968dc4bab | ||
|
|
e14c440795 | ||
|
|
4edd139967 | ||
|
|
366e760f7a | ||
|
|
3b1a38621a | ||
|
|
3c4de59674 | ||
|
|
08a1bc8d97 | ||
|
|
c8f3772753 | ||
|
|
c7b6231cd5 | ||
|
|
1cec200638 | ||
|
|
b046942a28 | ||
|
|
4c49036b8a | ||
|
|
6909d49683 | ||
|
|
32471953ed | ||
|
|
60272479a1 | ||
|
|
fb7681ddc5 | ||
|
|
8b581a0a0f | ||
|
|
33a01f2773 | ||
|
|
3c517f514f | ||
|
|
48680d68ed | ||
|
|
871fc0a40a | ||
|
|
5a3a499f37 | ||
|
|
5ee18388c4 | ||
|
|
c98a30f82b | ||
|
|
427206abf7 | ||
|
|
2eb4267e6e | ||
|
|
f547b63bca | ||
|
|
fd71928e3a | ||
|
|
77c0177d23 | ||
|
|
b10bcca047 | ||
|
|
4618ca7b6e | ||
|
|
27dea3bc57 | ||
|
|
b275068569 | ||
|
|
9d86c3270c | ||
|
|
7ea3d7b9b4 | ||
|
|
d81a370fca | ||
|
|
5849001d00 | ||
|
|
f75ea6ea24 | ||
|
|
35e4d452c0 | ||
|
|
7c31ca2ac2 | ||
|
|
35bba14b2c | ||
|
|
89b976121f | ||
|
|
f5b08bbea6 | ||
|
|
ca2bdbca19 | ||
|
|
8dfdfdf6ef | ||
|
|
f8b8d21698 | ||
|
|
d6d4f84c3b | ||
|
|
12fcf96e93 | ||
|
|
5875a121db | ||
|
|
19ff098db5 | ||
|
|
c0724d904f | ||
|
|
97bc2c5c66 | ||
|
|
b130d14de4 | ||
|
|
cec52253fb | ||
|
|
31d5805681 | ||
|
|
fda087e24f | ||
|
|
1d8935d0ab | ||
|
|
b49730f255 | ||
|
|
537d1599f3 | ||
|
|
7eb7b9f802 | ||
|
|
73822b9e54 | ||
|
|
a71adc5950 | ||
|
|
49a37c7d6f | ||
|
|
df3d236408 | ||
|
|
8c536e4d58 | ||
|
|
6f7f0867af | ||
|
|
7bdf53291b | ||
|
|
44a6bfd874 | ||
|
|
76551e5648 | ||
|
|
64482ed07b | ||
|
|
c0ec3d92db | ||
|
|
c1a2f418a2 | ||
|
|
6d23625601 | ||
|
|
094d429ff0 | ||
|
|
2a574e8c92 | ||
|
|
da766dd84f | ||
|
|
e2d11ce0fc | ||
|
|
fd5c5a18a4 | ||
|
|
011fe6a8d2 | ||
|
|
9275f09cf9 | ||
|
|
43a14c986c | ||
|
|
9d5aecc51d | ||
|
|
a4498925d6 | ||
|
|
36ec090ee3 | ||
|
|
079038b09e | ||
|
|
11a5229f37 | ||
|
|
1387aecceb | ||
|
|
6edde868e6 | ||
|
|
1cade38b79 | ||
|
|
e9fd3005b9 | ||
|
|
40815c9c78 | ||
|
|
397fe29bb2 | ||
|
|
9e3525408f | ||
|
|
55a2688dc0 | ||
|
|
f4b0ecd0a0 | ||
|
|
6fc4ffef0a | ||
|
|
cf3c41acc7 | ||
|
|
9bf9c00474 | ||
|
|
a2cdd72db0 | ||
|
|
8230b5faf4 | ||
|
|
9e934738b5 | ||
|
|
5a3b3d797f | ||
|
|
6331635f25 | ||
|
|
0ff9277dea | ||
|
|
5dce162a29 | ||
|
|
adc45149ae | ||
|
|
29bdbfc10f | ||
|
|
57504f2359 | ||
|
|
c2a1d188c9 | ||
|
|
bd8b9b3336 | ||
|
|
2bcbfe8747 | ||
|
|
98617a4ba5 | ||
|
|
0a6e13b153 | ||
|
|
93eee39355 | ||
|
|
f791c70643 | ||
|
|
51afcc5ca8 | ||
|
|
7a0ed4c462 | ||
|
|
45376f0dab | ||
|
|
34c426a549 | ||
|
|
1ed3b22db4 | ||
|
|
085d80792f | ||
|
|
aabddede8f | ||
|
|
d62038e509 | ||
|
|
e0095d235f | ||
|
|
5270983dc4 | ||
|
|
0cf3108af7 | ||
|
|
217d039bb7 | ||
|
|
fda4d386c9 | ||
|
|
2fc664f12a | ||
|
|
3d989dbaff | ||
|
|
f281b4b4cb | ||
|
|
8bfa6b817f | ||
|
|
f295212360 | ||
|
|
7b2b639d1e | ||
|
|
c6031a7806 | ||
|
|
d111518352 | ||
|
|
a5ceb2a61d | ||
|
|
bd72eb5693 | ||
|
|
e3dcb4b0dc | ||
|
|
b6b64c6dc5 | ||
|
|
030d332a79 | ||
|
|
54d3e33616 | ||
|
|
1c465b55e6 | ||
|
|
687b66da43 | ||
|
|
710ab4ae3f | ||
|
|
06f4ca6983 | ||
|
|
8cedcccfb0 | ||
|
|
70a8bea8f6 | ||
|
|
8512a26319 | ||
|
|
778a2866e4 | ||
|
|
08a74989b7 | ||
|
|
68522c82a6 | ||
|
|
ec2d1547c9 | ||
|
|
eb6c050cf0 | ||
|
|
0e5ce3e07e | ||
|
|
14791ce7eb | ||
|
|
a8bee07d8f | ||
|
|
184d3e158a | ||
|
|
f8679f06aa | ||
|
|
102e6dd2fb | ||
|
|
7806ad8ac8 | ||
|
|
da23514424 | ||
|
|
e39201147e | ||
|
|
c8d5f9edc5 | ||
|
|
9248964191 | ||
|
|
5cc4d02b80 | ||
|
|
1b18f85e42 | ||
|
|
e3cb700cf7 | ||
|
|
82b1763431 | ||
|
|
cc54724ff1 | ||
|
|
5eebc9e093 | ||
|
|
ba2b0ef809 | ||
|
|
2531d33880 | ||
|
|
d66cb54a82 | ||
|
|
e28dbfb377 | ||
|
|
83caa146d1 | ||
|
|
cf61d7349a | ||
|
|
87de3ec3e3 | ||
|
|
311b373455 | ||
|
|
7f13185f2f | ||
|
|
612138db4f | ||
|
|
c39eef1d5a | ||
|
|
41bb09e361 | ||
|
|
6b9590a6a9 | ||
|
|
8583f38ec1 | ||
|
|
6e11a46b2a | ||
|
|
801443a7d0 | ||
|
|
2284247b56 | ||
|
|
33986848f3 | ||
|
|
a55928dbee | ||
|
|
6536ccf003 | ||
|
|
548dfdc26d | ||
|
|
4428dbf885 | ||
|
|
f11dc7e3f6 | ||
|
|
b91dc754b0 | ||
|
|
b2c1ad7abc | ||
|
|
730f80447e | ||
|
|
90743e68d4 | ||
|
|
23f56e4c1b | ||
|
|
c16d631b58 | ||
|
|
e000905aca | ||
|
|
85685afc68 | ||
|
|
dfd81fd125 | ||
|
|
78fd9b4fe4 | ||
|
|
504d1e3004 | ||
|
|
b4a87d8c0b | ||
|
|
884b96c300 | ||
|
|
14667c1756 | ||
|
|
b324cfbfde | ||
|
|
7047d08ca4 | ||
|
|
28c486dad5 | ||
|
|
d6fd82c1ab | ||
|
|
bcf53458ad | ||
|
|
15a6ba791e | ||
|
|
5bce7e0616 | ||
|
|
696f69e442 | ||
|
|
96b8904d88 | ||
|
|
6438a838ce | ||
|
|
d7d870cb4c | ||
|
|
6b33613bb0 | ||
|
|
1caa9d5294 | ||
|
|
251a3babad | ||
|
|
a0d3aed347 | ||
|
|
5cc074ec3b | ||
|
|
4c7b9fd6e5 | ||
|
|
f76170eab4 | ||
|
|
a63da98032 | ||
|
|
1d411df274 | ||
|
|
4c50a92e12 | ||
|
|
92e71b2d08 | ||
|
|
ff69959acc | ||
|
|
10f3ce070d | ||
|
|
e2d3e6f02a | ||
|
|
867b7466f4 | ||
|
|
e95e465a0a | ||
|
|
e5a8ce5ecb | ||
|
|
227256e6ba | ||
|
|
875956f966 | ||
|
|
50ff4cc45e | ||
|
|
a26aee4afe | ||
|
|
a76f5e4143 | ||
|
|
0bff771c03 | ||
|
|
0620f27c10 |
No files matched your search
@@ -2,7 +2,7 @@
|
||||
Source/Common/cpp-optparse/*
|
||||
|
||||
# Files with human-indented tables for readability - don't mess with these
|
||||
FEXCore/Source/Interface/Core/X86Tables/*
|
||||
FEXCore/Source/Interface/Core/X86Tables/*.cpp
|
||||
|
||||
# Inline headers with list-like content that can't be processed individually
|
||||
Source/Tools/LinuxEmulation/LinuxSyscalls/x*/SyscallsNames.inl
|
||||
|
||||
@@ -22,3 +22,6 @@
|
||||
|
||||
# Minor reformat with clang-format-19
|
||||
9fdd96af61c969cb5732471223f00eda64b7a069
|
||||
|
||||
# Reformat of X86Tables.h
|
||||
ba2b0ef809f66f1a6d334f000798fa2ceafab26f
|
||||
+85
-185
@@ -24,238 +24,138 @@ jobs:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: '0'
|
||||
fetch-tags: 'true'
|
||||
|
||||
- name: Set runner label
|
||||
run: echo "runner_label=${{ matrix.arch[1] }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Set rootfs paths
|
||||
- name: Set runner info
|
||||
run: |
|
||||
echo "FEX_ROOTFS_MOUNT=/mnt/AutoNFS/rootfs/" >> $GITHUB_ENV
|
||||
echo "FEX_ROOTFS_PATH=$HOME/Rootfs/" >> $GITHUB_ENV
|
||||
echo "FEX_ROOTFS=$HOME/Rootfs/" >> $GITHUB_ENV
|
||||
echo "runner_label=${{ matrix.arch[1] }}" >> $GITHUB_ENV
|
||||
echo "runner_name=$(hostname)" >> $GITHUB_ENV
|
||||
|
||||
- name: Update RootFS cache
|
||||
# Use a bash shell so we can use the same syntax for environment variable
|
||||
# access regardless of the host operating system
|
||||
shell: bash
|
||||
run: $GITHUB_WORKSPACE/Scripts/CI_FetchRootFS.py
|
||||
|
||||
- name : submodule checkout
|
||||
# Need to update submodules
|
||||
run: |
|
||||
git submodule sync --recursive
|
||||
git submodule update --init --depth 1
|
||||
|
||||
- name: Clean Build Environment
|
||||
run: rm -Rf ${{runner.workspace}}/build
|
||||
|
||||
- name: Create Build Environment
|
||||
# Some projects don't allow in-source building, so create a separate build directory
|
||||
# We'll use this as our working directory for all subsequent commands
|
||||
run: cmake -E make_directory ${{runner.workspace}}/build
|
||||
- name: Setup Build Environment
|
||||
uses: ./.github/workflows/setup-env
|
||||
|
||||
- name: Configure CMake
|
||||
# Use a bash shell so we can use the same syntax for environment variable
|
||||
# access regardless of the host operating system
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
# Note the current convention is to use the -S and -B options here to specify source
|
||||
# and build directories, but this is only available with CMake 3.13 and higher.
|
||||
# The CMake binaries on the Github Actions machines are (as of this writing) 3.12
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G Ninja -DENABLE_LTO=False -DENABLE_ASSERTIONS=True -DENABLE_X86_HOST_DEBUG=True -DBUILD_FEX_LINUX_TESTS=True -DBUILD_THUNKS=True -DCMAKE_INSTALL_PREFIX=${{runner.workspace}}/build/install
|
||||
run: |
|
||||
cmake -S . -B build -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G Ninja -DENABLE_LTO=False -DENABLE_ASSERTIONS=True \
|
||||
-DENABLE_X86_HOST_DEBUG=True -DBUILD_FEX_LINUX_TESTS=True -DBUILD_THUNKS=True \
|
||||
-DCMAKE_INSTALL_PREFIX="$PWD"/build/install
|
||||
|
||||
# These steps make a lot of noise but rarely fail.
|
||||
# Put them in a separate step to make normal build logs easier to parse
|
||||
- name: Noisy Build Targets
|
||||
run: cmake --build build --target asm_files 32bit_asm_files JemallocLibs Catch2 vixl cephes_128bit
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
# Execute the build. You can specify a specific target with "--target <NAME>"
|
||||
run: cmake --build . --config $BUILD_TYPE
|
||||
run: cmake --build build
|
||||
|
||||
- name: Install
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
run: cmake --build . --config $BUILD_TYPE --target install
|
||||
run: cmake --build build --target install
|
||||
|
||||
- name: gcc target tests 64
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
# Execute the gvisor tests
|
||||
run: cmake --build . --config $BUILD_TYPE --target gcc_target_tests_64
|
||||
|
||||
- name: GCC64 Test Results move
|
||||
# GCC tests
|
||||
- name: GCC64 Target Tests
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: mv ${{runner.workspace}}/build/Testing/Temporary/LastTest.log ${{runner.workspace}}/build/Testing/Temporary/LastTest_GCC64.log || true
|
||||
uses: ./.github/workflows/test
|
||||
with:
|
||||
target: gcc_target_tests_64
|
||||
|
||||
- name: gcc target tests 32
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
# Execute the gvisor tests
|
||||
run: cmake --build . --config $BUILD_TYPE --target gcc_target_tests_32
|
||||
|
||||
- name: GCC32 Test Results move
|
||||
- name: GCC32 Target Tests
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: mv ${{runner.workspace}}/build/Testing/Temporary/LastTest.log ${{runner.workspace}}/build/Testing/Temporary/LastTest_GCC32.log || true
|
||||
uses: ./.github/workflows/test
|
||||
with:
|
||||
target: gcc_target_tests_32
|
||||
|
||||
- name: APITest tests
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
run: cmake --build . --config $BUILD_TYPE --target api_tests
|
||||
|
||||
- name: APITest Test Results move
|
||||
# API tests
|
||||
- name: API Tests
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: mv ${{runner.workspace}}/build/Testing/Temporary/LastTest.log ${{runner.workspace}}/build/Testing/Temporary/LastTest_APITests.log || true
|
||||
uses: ./.github/workflows/test
|
||||
with:
|
||||
target: api_tests
|
||||
|
||||
- name: FEXCore APITest tests
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
run: cmake --build . --config $BUILD_TYPE --target fexcore_apitests
|
||||
|
||||
- name: FEXCore APITest Test Results move
|
||||
- name: FEXCore API Tests
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: mv ${{runner.workspace}}/build/Testing/Temporary/LastTest.log ${{runner.workspace}}/build/Testing/Temporary/LastTest_FEXCoreAPITests.log || true
|
||||
uses: ./.github/workflows/test
|
||||
with:
|
||||
target: fexcore_apitests
|
||||
|
||||
- name: ARMEmitter tests
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
run: cmake --build . --config $BUILD_TYPE --target emitter_tests
|
||||
|
||||
- name: ARMEmitter Test Results move
|
||||
# ARM emission tests
|
||||
- name: ARM Emitter Tests
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: mv ${{runner.workspace}}/build/Testing/Temporary/LastTest.log ${{runner.workspace}}/build/Testing/Temporary/LastTest_ARMEmitterTests.log || true
|
||||
uses: ./.github/workflows/test
|
||||
with:
|
||||
target: emitter_tests
|
||||
|
||||
- name: FEXLinuxTests
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
# Linux tests
|
||||
- name: FEX Linux Tests
|
||||
if: ${{ always() }}
|
||||
uses: ./.github/workflows/test
|
||||
with:
|
||||
target: fex_linux_tests_all
|
||||
env:
|
||||
# These tests require non-portable install due to thunks.
|
||||
FEX_PORTABLE: 0
|
||||
run: cmake --build . --config $BUILD_TYPE --target fex_linux_tests_all
|
||||
|
||||
- name: FEXLinuxTests Results move
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: mv ${{runner.workspace}}/build/Testing/Temporary/LastTest.log ${{runner.workspace}}/build/Testing/Temporary/LastTest_FEXLinuxTests.log || true
|
||||
|
||||
# Thunking
|
||||
- name: Thunkgen tests
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
run: cmake --build . --config $BUILD_TYPE --target thunkgen_tests
|
||||
|
||||
- name: Thunkgen Results move
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: mv ${{runner.workspace}}/build/Testing/Temporary/LastTest.log ${{runner.workspace}}/build/Testing/Temporary/LastTest_ThunkgenTests.log || true
|
||||
uses: ./.github/workflows/test
|
||||
with:
|
||||
target: thunkgen_tests
|
||||
|
||||
- name: Test GL No-Thunks
|
||||
if: matrix.arch[1] == 'x64'
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
if: ${{ always() && matrix.arch[1] == 'x64' }}
|
||||
uses: ./.github/workflows/test
|
||||
with:
|
||||
target: thunk_functional_tests_nothunks
|
||||
env:
|
||||
DISPLAY: ":0"
|
||||
run: cmake --build . --config $BUILD_TYPE --target thunk_functional_tests_nothunks
|
||||
|
||||
- name: No thunks Results move
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: mv ${{runner.workspace}}/build/Testing/Temporary/LastTest.log ${{runner.workspace}}/build/Testing/Temporary/LastTest_NoThunkResults.log || true
|
||||
DISPLAY: ':0'
|
||||
|
||||
- name: Test GL Thunks
|
||||
if: matrix.arch[1] == 'x64'
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
if: ${{ always() && matrix.arch[1] == 'x64' }}
|
||||
uses: ./.github/workflows/test
|
||||
with:
|
||||
target: thunk_functional_tests_thunks
|
||||
env:
|
||||
DISPLAY: ":0"
|
||||
run: cmake --build . --config $BUILD_TYPE --target thunk_functional_tests_thunks
|
||||
|
||||
- name: Thunks Results move
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: mv ${{runner.workspace}}/build/Testing/Temporary/LastTest.log ${{runner.workspace}}/build/Testing/Temporary/LastTest_ThunkResults.log || true
|
||||
DISPLAY: ':0'
|
||||
|
||||
# ASM tests
|
||||
- name: ASM Tests
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
# Execute the unit tests
|
||||
run: cmake --build . --config $BUILD_TYPE --target asm_tests
|
||||
|
||||
- name: ASM Test Results move
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: mv ${{runner.workspace}}/build/Testing/Temporary/LastTest.log ${{runner.workspace}}/build/Testing/Temporary/LastTest_ASM.log || true
|
||||
uses: ./.github/workflows/test
|
||||
with:
|
||||
target: asm_tests
|
||||
|
||||
- name: Posix Tests
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
# Execute the posixtest
|
||||
run: cmake --build . --config $BUILD_TYPE --target posix_tests
|
||||
|
||||
- name: Posix Test Results move
|
||||
# POSIX tests
|
||||
- name: POSIX Tests
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: mv ${{runner.workspace}}/build/Testing/Temporary/LastTest.log ${{runner.workspace}}/build/Testing/Temporary/LastTest_Posix.log || true
|
||||
uses: ./.github/workflows/test
|
||||
with:
|
||||
target: posix_tests
|
||||
|
||||
- name: gvisor tests
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
# Execute the gvisor tests
|
||||
run: cmake --build . --config $BUILD_TYPE --target gvisor_tests
|
||||
|
||||
- name: GVisor Test Results move
|
||||
# GVisor tests
|
||||
- name: GVisor Tests
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: mv ${{runner.workspace}}/build/Testing/Temporary/LastTest.log ${{runner.workspace}}/build/Testing/Temporary/LastTest_GVisor.log || true
|
||||
uses: ./.github/workflows/test
|
||||
with:
|
||||
target: gvisor_tests
|
||||
|
||||
# Struct verifier tests
|
||||
- name: Struct verifier tests
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
run: cmake --build . --config $BUILD_TYPE --target struct_verifier
|
||||
|
||||
- name: Struct verifier Test Results move
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: mv ${{runner.workspace}}/build/Testing/Temporary/LastTest.log ${{runner.workspace}}/build/Testing/Temporary/LastTest_StructVerifier.log || true
|
||||
|
||||
- name: Truncate test results
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
# Cap out the log files at 20M in case something crash spins and dumps fault text
|
||||
# ASM tests get quite close to 10MB
|
||||
run: truncate --size="<20M" ${{runner.workspace}}/build/Testing/Temporary/LastTest_*.log || true
|
||||
uses: ./.github/workflows/test
|
||||
with:
|
||||
target: struct_verifier
|
||||
|
||||
- name: Remove old SHM regions
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: cmake --build . --config $BUILD_TYPE --target remove_old_shm_regions
|
||||
|
||||
- name: Set runner name
|
||||
if: ${{ always() }}
|
||||
run: echo "runner_name=$(hostname)" >> $GITHUB_ENV
|
||||
run: cmake --build build --target remove_old_shm_regions
|
||||
|
||||
- name: Upload results
|
||||
if: ${{ always() }}
|
||||
uses: 'actions/upload-artifact@v4'
|
||||
uses: actions/upload-artifact@v6
|
||||
timeout-minutes: 1
|
||||
with:
|
||||
name: Results-${{ env.runner_name }}
|
||||
path: ${{runner.workspace}}/build/Testing/Temporary/LastTest_*.log
|
||||
name: Results-${{ env.runner_name }}-${{ env.runner_label }}
|
||||
path: results/*.log
|
||||
retention-days: 3
|
||||
@@ -31,163 +31,94 @@ jobs:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: '0'
|
||||
fetch-tags: 'true'
|
||||
|
||||
- name: Set runner label
|
||||
run: echo "runner_label=${{ matrix.arch[1] }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Set rootfs paths
|
||||
- name: Set runner info
|
||||
run: |
|
||||
echo "FEX_ROOTFS_MOUNT=/mnt/AutoNFS/rootfs/" >> $GITHUB_ENV
|
||||
echo "FEX_ROOTFS_PATH=$HOME/Rootfs/" >> $GITHUB_ENV
|
||||
echo "FEX_ROOTFS=$HOME/Rootfs/" >> $GITHUB_ENV
|
||||
echo "runner_label=${{ matrix.arch[1] }}" >> $GITHUB_ENV
|
||||
echo "runner_name=$(hostname)" >> $GITHUB_ENV
|
||||
|
||||
- name: Update RootFS cache
|
||||
# Use a bash shell so we can use the same syntax for environment variable
|
||||
# access regardless of the host operating system
|
||||
shell: bash
|
||||
run: $GITHUB_WORKSPACE/Scripts/CI_FetchRootFS.py
|
||||
|
||||
- name : submodule checkout
|
||||
# Need to update submodules
|
||||
run: |
|
||||
git submodule sync --recursive
|
||||
git submodule update --init --depth 1
|
||||
|
||||
- name: Clean Build Environment
|
||||
run: rm -Rf ${{runner.workspace}}/build
|
||||
|
||||
- name: Create Build Environment
|
||||
# Some projects don't allow in-source building, so create a separate build directory
|
||||
# We'll use this as our working directory for all subsequent commands
|
||||
run: cmake -E make_directory ${{runner.workspace}}/build
|
||||
- name: Setup Build Environment
|
||||
uses: ./.github/workflows/setup-env
|
||||
|
||||
- name: Configure CMake
|
||||
# Use a bash shell so we can use the same syntax for environment variable
|
||||
# access regardless of the host operating system
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
# Note the current convention is to use the -S and -B options here to specify source
|
||||
# and build directories, but this is only available with CMake 3.13 and higher.
|
||||
# The CMake binaries on the Github Actions machines are (as of this writing) 3.12
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G Ninja -DENABLE_LTO=False -DENABLE_ASSERTIONS=True -DENABLE_X86_HOST_DEBUG=True -DBUILD_FEX_LINUX_TESTS=True -DENABLE_GLIBC_ALLOCATOR_HOOK_FAULT=True -DENABLE_JEMALLOC_GLIBC_ALLOC=False -DCMAKE_INSTALL_PREFIX=${{runner.workspace}}/build/install
|
||||
run: |
|
||||
cmake -S . -B build -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G Ninja -DENABLE_LTO=False \
|
||||
-DENABLE_ASSERTIONS=True -DENABLE_X86_HOST_DEBUG=True -DBUILD_FEX_LINUX_TESTS=True \
|
||||
-DENABLE_GLIBC_ALLOCATOR_HOOK_FAULT=True -DENABLE_JEMALLOC_GLIBC_ALLOC=False \
|
||||
-DCMAKE_INSTALL_PREFIX="$PWD"/build/install
|
||||
|
||||
# These steps make a lot of noise but rarely fail.
|
||||
# Put them in a separate step to make normal build logs easier to parse
|
||||
- name: Noisy Build Targets
|
||||
run: cmake --build build --target asm_files 32bit_asm_files JemallocLibs Catch2 vixl cephes_128bit
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
# Execute the build. You can specify a specific target with "--target <NAME>"
|
||||
run: cmake --build . --config $BUILD_TYPE
|
||||
run: cmake --build build
|
||||
|
||||
- name: Install
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
run: cmake --build . --config $BUILD_TYPE --target install
|
||||
run: cmake --build build --target install
|
||||
|
||||
- name: gcc target tests 64
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
# Execute the gvisor tests
|
||||
run: cmake --build . --config $BUILD_TYPE --target gcc_target_tests_64
|
||||
|
||||
- name: GCC64 Test Results move
|
||||
# GCC tests
|
||||
- name: GCC64 Target Tests
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: mv ${{runner.workspace}}/build/Testing/Temporary/LastTest.log ${{runner.workspace}}/build/Testing/Temporary/LastTest_GCC64.log || true
|
||||
uses: ./.github/workflows/test
|
||||
with:
|
||||
target: gcc_target_tests_64
|
||||
|
||||
- name: gcc target tests 32
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
# Execute the gvisor tests
|
||||
run: cmake --build . --config $BUILD_TYPE --target gcc_target_tests_32
|
||||
|
||||
- name: GCC32 Test Results move
|
||||
- name: GCC32 Target Tests
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: mv ${{runner.workspace}}/build/Testing/Temporary/LastTest.log ${{runner.workspace}}/build/Testing/Temporary/LastTest_GCC32.log || true
|
||||
uses: ./.github/workflows/test
|
||||
with:
|
||||
target: gcc_target_tests_32
|
||||
|
||||
- name: APITest tests
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
run: cmake --build . --config $BUILD_TYPE --target api_tests
|
||||
|
||||
- name: APITest Test Results move
|
||||
# API Tests
|
||||
- name: API Tests
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: mv ${{runner.workspace}}/build/Testing/Temporary/LastTest.log ${{runner.workspace}}/build/Testing/Temporary/LastTest_APITests.log || true
|
||||
uses: ./.github/workflows/test
|
||||
with:
|
||||
target: api_tests
|
||||
|
||||
- name: FEXCore APITest tests
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
run: cmake --build . --config $BUILD_TYPE --target fexcore_apitests
|
||||
|
||||
- name: FEXCore APITest Test Results move
|
||||
- name: FEXCore API Tests
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: mv ${{runner.workspace}}/build/Testing/Temporary/LastTest.log ${{runner.workspace}}/build/Testing/Temporary/LastTest_FEXCoreAPITests.log || true
|
||||
uses: ./.github/workflows/test
|
||||
with:
|
||||
target: fexcore_apitests
|
||||
|
||||
- name: FEXLinuxTests
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
run: cmake --build . --config $BUILD_TYPE --target fex_linux_tests_all
|
||||
|
||||
- name: FEXLinuxTests Results move
|
||||
# Linux tests
|
||||
- name: FEX Linux Tests
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: mv ${{runner.workspace}}/build/Testing/Temporary/LastTest.log ${{runner.workspace}}/build/Testing/Temporary/LastTest_FEXLinuxTests.log || true
|
||||
uses: ./.github/workflows/test
|
||||
with:
|
||||
target: fex_linux_tests_all
|
||||
|
||||
# ASM Tests
|
||||
- name: ASM Tests
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
# Execute the unit tests
|
||||
run: cmake --build . --config $BUILD_TYPE --target asm_tests
|
||||
|
||||
- name: ASM Test Results move
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: mv ${{runner.workspace}}/build/Testing/Temporary/LastTest.log ${{runner.workspace}}/build/Testing/Temporary/LastTest_ASM.log || true
|
||||
uses: ./.github/workflows/test
|
||||
with:
|
||||
target: asm_tests
|
||||
|
||||
- name: Posix Tests
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
# Execute the posixtest
|
||||
run: cmake --build . --config $BUILD_TYPE --target posix_tests
|
||||
|
||||
- name: Posix Test Results move
|
||||
# POSIX Tests
|
||||
- name: POSIX Tests
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: mv ${{runner.workspace}}/build/Testing/Temporary/LastTest.log ${{runner.workspace}}/build/Testing/Temporary/LastTest_Posix.log || true
|
||||
|
||||
- name: Truncate test results
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
# Cap out the log files at 20M in case something crash spins and dumps fault text
|
||||
# ASM tests get quite close to 10MB
|
||||
run: truncate --size="<20M" ${{runner.workspace}}/build/Testing/Temporary/LastTest_*.log || true
|
||||
uses: ./.github/workflows/test
|
||||
with:
|
||||
target: posix_tests
|
||||
|
||||
- name: Remove old SHM regions
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: cmake --build . --config $BUILD_TYPE --target remove_old_shm_regions
|
||||
|
||||
- name: Set runner name
|
||||
if: ${{ always() }}
|
||||
run: echo "runner_name=$(hostname)" >> $GITHUB_ENV
|
||||
run: cmake --build build --target remove_old_shm_regions
|
||||
|
||||
- name: Upload results
|
||||
if: ${{ always() }}
|
||||
uses: 'actions/upload-artifact@v4'
|
||||
uses: actions/upload-artifact@v6
|
||||
timeout-minutes: 1
|
||||
with:
|
||||
name: Results-${{ env.runner_name }}
|
||||
path: ${{runner.workspace}}/build/Testing/Temporary/LastTest_*.log
|
||||
name: Results-${{ env.runner_name }}-${{ env.runner_label }}
|
||||
path: results/*.log
|
||||
retention-days: 3
|
||||
|
||||
@@ -24,83 +24,45 @@ jobs:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: '0'
|
||||
fetch-tags: 'true'
|
||||
|
||||
- name: Set runner label
|
||||
run: echo "runner_label=${{ matrix.arch[1] }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Set rootfs paths
|
||||
- name: Set runner info
|
||||
run: |
|
||||
echo "FEX_ROOTFS_MOUNT=/mnt/AutoNFS/rootfs/" >> $GITHUB_ENV
|
||||
echo "FEX_ROOTFS_PATH=$HOME/Rootfs/" >> $GITHUB_ENV
|
||||
echo "FEX_ROOTFS=$HOME/Rootfs/" >> $GITHUB_ENV
|
||||
echo "runner_label=${{ matrix.arch[1] }}" >> $GITHUB_ENV
|
||||
echo "runner_name=$(hostname)" >> $GITHUB_ENV
|
||||
|
||||
- name: Update RootFS cache
|
||||
# Use a bash shell so we can use the same syntax for environment variable
|
||||
# access regardless of the host operating system
|
||||
shell: bash
|
||||
run: $GITHUB_WORKSPACE/Scripts/CI_FetchRootFS.py
|
||||
|
||||
- name : submodule checkout
|
||||
# Need to update submodules
|
||||
run: |
|
||||
git submodule sync --recursive
|
||||
git submodule update --init --depth 1
|
||||
|
||||
- name: Clean Build Environment
|
||||
run: rm -Rf ${{runner.workspace}}/build
|
||||
|
||||
- name: Create Build Environment
|
||||
# Some projects don't allow in-source building, so create a separate build directory
|
||||
# We'll use this as our working directory for all subsequent commands
|
||||
run: cmake -E make_directory ${{runner.workspace}}/build
|
||||
- name: Setup Build Environment
|
||||
uses: ./.github/workflows/setup-env
|
||||
|
||||
- name: Configure CMake
|
||||
# Use a bash shell so we can use the same syntax for environment variable
|
||||
# access regardless of the host operating system
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
# Note the current convention is to use the -S and -B options here to specify source
|
||||
# and build directories, but this is only available with CMake 3.13 and higher.
|
||||
# The CMake binaries on the Github Actions machines are (as of this writing) 3.12
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G Ninja -DENABLE_LTO=False -DENABLE_ASSERTIONS=True -DENABLE_X86_HOST_DEBUG=True
|
||||
run: |
|
||||
cmake -S . -B build -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G Ninja -DENABLE_LTO=False \
|
||||
-DENABLE_ASSERTIONS=True -DENABLE_X86_HOST_DEBUG=True
|
||||
|
||||
# These steps make a lot of noise but rarely fail.
|
||||
# Put them in a separate step to make normal build logs easier to parse
|
||||
- name: Noisy Build Targets
|
||||
run: cmake --build build --target asm_files 32bit_asm_files JemallocLibs Catch2 vixl cephes_128bit
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
# Execute the build. You can specify a specific target with "--target <NAME>"
|
||||
run: cmake --build . --config $BUILD_TYPE
|
||||
run: cmake --build build
|
||||
|
||||
# ASM tests
|
||||
- name: ASM Tests
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
# Execute the unit tests
|
||||
run: cmake --build . --config $BUILD_TYPE --target asm_tests
|
||||
|
||||
- name: ASM Test Results move
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: mv ${{runner.workspace}}/build/Testing/Temporary/LastTest.log ${{runner.workspace}}/build/Testing/Temporary/LastTest_ASM.log || true
|
||||
|
||||
- name: Truncate test results
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
# Cap out the log files at 20M in case something crash spins and dumps fault text
|
||||
# ASM tests get quite close to 10MB
|
||||
run: truncate --size="<20M" ${{runner.workspace}}/build/Testing/Temporary/LastTest_*.log || true
|
||||
|
||||
- name: Set runner name
|
||||
if: ${{ always() }}
|
||||
run: echo "runner_name=$(hostname)" >> $GITHUB_ENV
|
||||
uses: ./.github/workflows/test
|
||||
with:
|
||||
target: asm_tests
|
||||
|
||||
- name: Upload results
|
||||
if: ${{ always() }}
|
||||
uses: 'actions/upload-artifact@v4'
|
||||
uses: actions/upload-artifact@v6
|
||||
timeout-minutes: 1
|
||||
with:
|
||||
name: Results-${{ env.runner_name }}
|
||||
path: ${{runner.workspace}}/build/Testing/Temporary/LastTest_*.log
|
||||
name: Results-${{ env.runner_name }}-${{ env.runner_label }}
|
||||
path: results/*.log
|
||||
retention-days: 3
|
||||
|
||||
@@ -23,123 +23,56 @@ jobs:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: '0'
|
||||
fetch-tags: 'true'
|
||||
|
||||
- name: Set runner label
|
||||
run: echo "runner_label=${{ matrix.arch[1] }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Set rootfs paths
|
||||
- name: Set runner info
|
||||
run: |
|
||||
echo "FEX_ROOTFS_MOUNT=/mnt/AutoNFS/rootfs/" >> $GITHUB_ENV
|
||||
echo "FEX_ROOTFS_PATH=$HOME/Rootfs/" >> $GITHUB_ENV
|
||||
echo "FEX_ROOTFS=$HOME/Rootfs/" >> $GITHUB_ENV
|
||||
echo "runner_label=${{ matrix.arch[1] }}" >> $GITHUB_ENV
|
||||
echo "runner_name=$(hostname)" >> $GITHUB_ENV
|
||||
|
||||
- name: Update RootFS cache
|
||||
# Use a bash shell so we can use the same syntax for environment variable
|
||||
# access regardless of the host operating system
|
||||
shell: bash
|
||||
run: $GITHUB_WORKSPACE/Scripts/CI_FetchRootFS.py
|
||||
- name: Setup Build Environment
|
||||
uses: ./.github/workflows/setup-env
|
||||
|
||||
- name : submodule checkout
|
||||
# Need to update submodules
|
||||
- name: Set VIXL_SIM_ENABLED
|
||||
run: |
|
||||
git submodule sync --recursive
|
||||
git submodule update --init --depth 1
|
||||
|
||||
- name: Clean Build Environment
|
||||
run: rm -Rf ${{runner.workspace}}/build
|
||||
|
||||
- name: Create Build Environment
|
||||
# Some projects don't allow in-source building, so create a separate build directory
|
||||
# We'll use this as our working directory for all subsequent commands
|
||||
run: cmake -E make_directory ${{runner.workspace}}/build
|
||||
|
||||
- name: Set vixl_sim x86
|
||||
if: matrix.arch[1] == 'x64'
|
||||
run: |
|
||||
echo "VIXL_SIM_ENABLED=True" >> $GITHUB_ENV
|
||||
|
||||
- name: Set vixl_sim Arm64
|
||||
if: matrix.arch[1] == 'ARM64'
|
||||
run: |
|
||||
echo "VIXL_SIM_ENABLED=False" >> $GITHUB_ENV
|
||||
case '${{ matrix.arch[1] }}' in
|
||||
x64) _sim=True ;;
|
||||
ARM64) _sim=False ;;
|
||||
esac
|
||||
echo "VIXL_SIM_ENABLED=$_sim" >> $GITHUB_ENV
|
||||
|
||||
- name: Configure CMake
|
||||
# Use a bash shell so we can use the same syntax for environment variable
|
||||
# access regardless of the host operating system
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
# Note the current convention is to use the -S and -B options here to specify source
|
||||
# and build directories, but this is only available with CMake 3.13 and higher.
|
||||
# The CMake binaries on the Github Actions machines are (as of this writing) 3.12
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G Ninja -DENABLE_VIXL_SIMULATOR=$VIXL_SIM_ENABLED -DENABLE_VIXL_DISASSEMBLER=True -DENABLE_LTO=False -DENABLE_ASSERTIONS=True -DENABLE_X86_HOST_DEBUG=True
|
||||
run: |
|
||||
cmake -S . -B build -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G Ninja -DENABLE_VIXL_SIMULATOR=$VIXL_SIM_ENABLED \
|
||||
-DENABLE_VIXL_DISASSEMBLER=True -DENABLE_LTO=False -DENABLE_ASSERTIONS=True -DENABLE_X86_HOST_DEBUG=True
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
env:
|
||||
FEX_DISABLETELEMETRY: 1
|
||||
# Execute the build. You can specify a specific target with "--target <NAME>"
|
||||
run: cmake --build . --config $BUILD_TYPE --target CodeSizeValidation instcountci_test_files
|
||||
run: cmake --build build --target CodeSizeValidation instcountci_test_files
|
||||
|
||||
- name: Instruction Count Tests
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
# Execute the unit tests
|
||||
run: cmake --build . --config $BUILD_TYPE --target instcountci_tests
|
||||
|
||||
- name: Instruction Count Test Results move
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: mv ${{runner.workspace}}/build/Testing/Temporary/LastTest.log ${{runner.workspace}}/build/Testing/Temporary/LastTest_InstCountCI.log || true
|
||||
uses: ./.github/workflows/test
|
||||
with:
|
||||
target: instcountci_tests
|
||||
|
||||
- name: Update local repo instcount
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: cmake --build . --config $BUILD_TYPE --target instcountci_update_tests
|
||||
run: cmake --build build --target instcountci_update_tests
|
||||
|
||||
- name: Get instcountCI diff
|
||||
- name: Check InstCountCI diff
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{github.workspace}}/
|
||||
run: git diff --output=${{runner.workspace}}/build/InstCountCI.diff
|
||||
|
||||
- name: Check if InstCountCI Diff exists
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{github.workspace}}/
|
||||
# Check if the file is empty
|
||||
run: sh -c "! test -s ${{runner.workspace}}/build/InstCountCI.diff"
|
||||
|
||||
- name: Truncate test results
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
# Cap out the log files at 20M in case something crash spins and dumps fault text
|
||||
# ASM tests get quite close to 10MB
|
||||
run: truncate --size="<20M" ${{runner.workspace}}/build/Testing/Temporary/LastTest_*.log || true
|
||||
|
||||
- name: Set runner name
|
||||
if: ${{ always() }}
|
||||
run: echo "runner_name=$(hostname)" >> $GITHUB_ENV
|
||||
run: git --no-pager diff --exit-code HEAD
|
||||
|
||||
- name: Upload results
|
||||
if: ${{ always() }}
|
||||
uses: 'actions/upload-artifact@v4'
|
||||
uses: actions/upload-artifact@v6
|
||||
timeout-minutes: 1
|
||||
with:
|
||||
name: Results-${{ env.runner_name }}
|
||||
path: ${{runner.workspace}}/build/Testing/Temporary/LastTest_*.log
|
||||
name: Results-${{ env.runner_name }}-${{ env.runner_label }}
|
||||
path: results/*.log
|
||||
retention-days: 3
|
||||
|
||||
- name: Upload results InstCountCI
|
||||
if: ${{ always() }}
|
||||
uses: 'actions/upload-artifact@v4'
|
||||
timeout-minutes: 1
|
||||
with:
|
||||
name: Results-${{ env.runner_name }}-instcountci
|
||||
path: ${{runner.workspace}}/build/InstCountCI.diff
|
||||
retention-days: 3
|
||||
|
||||
@@ -20,7 +20,10 @@ jobs:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: '0'
|
||||
fetch-tags: 'true'
|
||||
|
||||
- name: Set runner label
|
||||
run: echo "runner_label=${{ matrix.arch[1] }}" >> $GITHUB_ENV
|
||||
@@ -28,73 +31,23 @@ jobs:
|
||||
- name: Add MingGW to PATH
|
||||
run: echo "$HOME/llvm-mingw/build/bin/" >> $GITHUB_PATH
|
||||
|
||||
- name: Set CC x86
|
||||
if: matrix.arch[1] == 'x64'
|
||||
- name: Set CC
|
||||
run: |
|
||||
echo "MINGW_TRIPLE=x86_64-w64-mingw32" >> $GITHUB_ENV
|
||||
case '${{ matrix.arch[1] }}' in
|
||||
x64) _cpu=x86_64 ;;
|
||||
ARM64) _cpu=aarch64 ;;
|
||||
ARM64EC) _cpu=arm64ec ;;
|
||||
esac
|
||||
echo "MINGW_TRIPLE=${_cpu}-w64-mingw32" >> $GITHUB_ENV
|
||||
|
||||
- name: Set CC Arm64
|
||||
if: matrix.arch[1] == 'ARM64'
|
||||
run: |
|
||||
echo "MINGW_TRIPLE=aarch64-w64-mingw32" >> $GITHUB_ENV
|
||||
|
||||
- name: Set CC Arm64EC
|
||||
if: matrix.arch[1] == 'ARM64EC'
|
||||
run: |
|
||||
echo "MINGW_TRIPLE=arm64ec-w64-mingw32" >> $GITHUB_ENV
|
||||
|
||||
- name: Set rootfs paths
|
||||
run: |
|
||||
echo "FEX_ROOTFS_MOUNT=/mnt/AutoNFS/rootfs/" >> $GITHUB_ENV
|
||||
echo "FEX_ROOTFS_PATH=$HOME/Rootfs/" >> $GITHUB_ENV
|
||||
echo "FEX_ROOTFS=$HOME/Rootfs/" >> $GITHUB_ENV
|
||||
|
||||
- name: Update RootFS cache
|
||||
# Use a bash shell so we can use the same syntax for environment variable
|
||||
# access regardless of the host operating system
|
||||
shell: bash
|
||||
run: $GITHUB_WORKSPACE/Scripts/CI_FetchRootFS.py
|
||||
|
||||
- name : submodule checkout
|
||||
# Need to update submodules
|
||||
run: |
|
||||
git submodule sync --recursive
|
||||
git submodule update --init --depth 1
|
||||
|
||||
- name: Clean Build Environment
|
||||
run: rm -Rf ${{runner.workspace}}/build
|
||||
|
||||
- name: Create Build Environment
|
||||
# Some projects don't allow in-source building, so create a separate build directory
|
||||
# We'll use this as our working directory for all subsequent commands
|
||||
run: cmake -E make_directory ${{runner.workspace}}/build
|
||||
- name: Setup Build Environment
|
||||
uses: ./.github/workflows/setup-env
|
||||
|
||||
- name: Configure CMake
|
||||
# Use a bash shell so we can use the same syntax for environment variable
|
||||
# access regardless of the host operating system
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
# Note the current convention is to use the -S and -B options here to specify source
|
||||
# and build directories, but this is only available with CMake 3.13 and higher.
|
||||
# The CMake binaries on the Github Actions machines are (as of this writing) 3.12
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_TOOLCHAIN_FILE=$GITHUB_WORKSPACE/Data/CMake/toolchain_mingw.cmake -DMINGW_TRIPLE=$MINGW_TRIPLE -G Ninja -DENABLE_LTO=False -DENABLE_ASSERTIONS=True -DENABLE_X86_HOST_DEBUG=True -DBUILD_TESTING=False -DCMAKE_INSTALL_PREFIX=${{runner.workspace}}/build/install
|
||||
run: |
|
||||
cmake -S . -B build -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_TOOLCHAIN_FILE=$GITHUB_WORKSPACE/Data/CMake/toolchain_mingw.cmake \
|
||||
-DMINGW_TRIPLE=$MINGW_TRIPLE -G Ninja -DENABLE_LTO=False -DENABLE_ASSERTIONS=True -DENABLE_X86_HOST_DEBUG=True -DBUILD_TESTING=False \
|
||||
-DCMAKE_INSTALL_PREFIX="$PWD"/build/install
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
# Execute the build. You can specify a specific target with "--target <NAME>"
|
||||
run: cmake --build . --config $BUILD_TYPE
|
||||
|
||||
- name: Set runner name
|
||||
if: ${{ always() }}
|
||||
run: echo "runner_name=$(hostname)" >> $GITHUB_ENV
|
||||
|
||||
- name: Upload results
|
||||
if: ${{ always() }}
|
||||
uses: 'actions/upload-artifact@v4'
|
||||
timeout-minutes: 1
|
||||
with:
|
||||
name: Results-${{ env.runner_name }}
|
||||
path: ${{runner.workspace}}/build/Testing/Temporary/LastTest_*.log
|
||||
retention-days: 3
|
||||
|
||||
run: cmake --build build
|
||||
@@ -1,7 +1,7 @@
|
||||
# Inspired by LLVM's pr-code-format.yml at
|
||||
# Inspired by LLVM's pr-code-format.yml at
|
||||
# https://github.com/llvm/llvm-project/blob/main/.github/workflows/pr-code-format.yml
|
||||
|
||||
name: "Check code formatting"
|
||||
name: Check code formatting
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
if: github.repository == 'FEX-Emu/FEX'
|
||||
|
||||
steps:
|
||||
- name: Fetch FEX sources
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
@@ -27,18 +27,13 @@ jobs:
|
||||
deepen_length: 500
|
||||
|
||||
- name: Get changed files
|
||||
id: changed-files
|
||||
uses: step-security/changed-files@3dbe17c78367e7d60f00d78ae6781a35be47b4a1 # v45.0.1
|
||||
with:
|
||||
separator: ","
|
||||
skip_initial_fetch: true
|
||||
|
||||
- name: "Listed files"
|
||||
env:
|
||||
CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
|
||||
run: |
|
||||
echo "Formatting files:"
|
||||
echo "$CHANGED_FILES"
|
||||
BASE=$(git merge-base main HEAD)
|
||||
FILES=$(git diff --name-only "$BASE" | tr '\n' ',' | sed 's/,$//')
|
||||
echo "CHANGED_FILES=$FILES" >> $GITHUB_ENV
|
||||
|
||||
echo "Changed files:"
|
||||
echo "$FILES"
|
||||
|
||||
- name: Check git-clang-format-19 exists
|
||||
run: which git-clang-format-19
|
||||
@@ -46,24 +41,23 @@ jobs:
|
||||
- name: Setup Python env
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.11'
|
||||
cache: 'pip'
|
||||
cache-dependency-path: './External/code-format-helper/requirements_formatting.txt'
|
||||
python-version: 3.11
|
||||
cache: pip
|
||||
cache-dependency-path: ./External/code-format-helper/requirements_formatting.txt
|
||||
|
||||
- name: Install python dependencies
|
||||
run: pip install -r ./External/code-format-helper/requirements_formatting.txt
|
||||
|
||||
- name: Run code formatter
|
||||
env:
|
||||
CLANG_FORMAT_PATH: 'git-clang-format-19'
|
||||
CLANG_FORMAT_PATH: git-clang-format-19
|
||||
GITHUB_PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
START_REV: ${{ github.event.pull_request.base.sha }}
|
||||
END_REV: ${{ github.event.pull_request.head.sha }}
|
||||
CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
|
||||
run: |
|
||||
python ./External/code-format-helper/code-format-helper.py \
|
||||
--repo "FEX-emu/FEX" \
|
||||
--issue-number $GITHUB_PR_NUMBER \
|
||||
--start-rev $START_REV \
|
||||
--end-rev $END_REV \
|
||||
--repo "FEX-Emu/FEX" \
|
||||
--issue-number "$GITHUB_PR_NUMBER" \
|
||||
--start-rev "$START_REV" \
|
||||
--end-rev "$END_REV" \
|
||||
--changed-files "$CHANGED_FILES"
|
||||
@@ -0,0 +1,33 @@
|
||||
name: Setup Build Environment
|
||||
description: Setup RootFS and build environment
|
||||
|
||||
inputs:
|
||||
setup-rootfs:
|
||||
description: 'Whether or not to set up the rootfs'
|
||||
default: true
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Set rootfs paths
|
||||
if: ${{ inputs.setup-rootfs == 'true' }}
|
||||
shell: bash
|
||||
run: |
|
||||
echo "FEX_ROOTFS_MOUNT=/mnt/AutoNFS/rootfs/" >> $GITHUB_ENV
|
||||
echo "FEX_ROOTFS_PATH=$HOME/Rootfs/" >> $GITHUB_ENV
|
||||
echo "FEX_ROOTFS=$HOME/Rootfs/" >> $GITHUB_ENV
|
||||
|
||||
- name: Update RootFS cache
|
||||
if: ${{ inputs.setup-rootfs == 'true' }}
|
||||
shell: bash
|
||||
run: python3 Scripts/CI_FetchRootFS.py
|
||||
|
||||
- name: Checkout Submodules
|
||||
shell: bash
|
||||
run: |
|
||||
git submodule sync --recursive
|
||||
git submodule update --init --depth 1
|
||||
|
||||
- name: Clean Build Environment
|
||||
shell: bash
|
||||
run: rm -Rf build
|
||||
@@ -9,6 +9,7 @@ on:
|
||||
- main
|
||||
|
||||
env:
|
||||
DEBIAN_FRONTEND: noninteractive
|
||||
BUILD_TYPE: Release
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
@@ -22,20 +23,18 @@ jobs:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: '0'
|
||||
fetch-tags: 'true'
|
||||
|
||||
- name: Set runner label
|
||||
run: echo "runner_label=${{ matrix.arch[1] }}" >> $GITHUB_ENV
|
||||
|
||||
- name : submodule checkout
|
||||
run: |
|
||||
git submodule sync --recursive
|
||||
git submodule update --init --depth 1
|
||||
|
||||
- name: Clean Build Environment
|
||||
run: |
|
||||
rm -Rf ${{runner.workspace}}/build
|
||||
cmake -E make_directory ${{runner.workspace}}/build
|
||||
- name: Setup Build Environment
|
||||
uses: ./.github/workflows/setup-env
|
||||
with:
|
||||
setup-rootfs: false
|
||||
|
||||
# Setup everything required.
|
||||
- name : distrobox setup
|
||||
@@ -49,31 +48,25 @@ jobs:
|
||||
libstdc++-14-dev-i386-cross libgcc-14-dev-i386-cross \
|
||||
libstdc++-14-dev-amd64-cross libgcc-14-dev-amd64-cross
|
||||
|
||||
- name: Create Build Environment
|
||||
run: distrobox enter --name steamrt4 -- cmake -E make_directory ${{runner.workspace}}/build
|
||||
|
||||
- name: Configure CMake
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: distrobox enter --name steamrt4 -- cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G Ninja -DBUILD_STEAM_SUPPORT=True -DENABLE_LTO=True -DENABLE_ASSERTIONS=False -DBUILD_THUNKS=True -DBUILD_FEXCONFIG=False -DBUILD_TESTING=False -DENABLE_CLANG_THUNKS=True -DUSE_LINKER=lld -DCMAKE_INSTALL_PREFIX=/usr
|
||||
run: |
|
||||
distrobox enter --name steamrt4 -- cmake -S . -B build -DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-G Ninja -DBUILD_STEAM_SUPPORT=True -DENABLE_LTO=True -DENABLE_ASSERTIONS=False -DBUILD_THUNKS=True \
|
||||
-DBUILD_FEXCONFIG=False -DBUILD_TESTING=False -DENABLE_CLANG_THUNKS=True -DUSE_LINKER=lld \
|
||||
-DCMAKE_INSTALL_PREFIX=/usr
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
run: distrobox enter --name steamrt4 -- cmake --build . --config $BUILD_TYPE
|
||||
run: distrobox enter --name steamrt4 -- cmake --build build
|
||||
|
||||
- name: install
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
env:
|
||||
DESTDIR: ${{runner.workspace}}/install
|
||||
run: distrobox enter --name steamrt4 -- cmake --build . --config $BUILD_TYPE -t install
|
||||
run: DESTDIR="$PWD"/install distrobox enter --name steamrt4 -- cmake --build build -t install
|
||||
|
||||
- name: Upload libraries
|
||||
uses: 'actions/upload-artifact@v4'
|
||||
uses: actions/upload-artifact@v6
|
||||
timeout-minutes: 1
|
||||
with:
|
||||
overwrite: true
|
||||
name: steamrt4_steampipe_depot
|
||||
path: ${{runner.workspace}}/install/*
|
||||
path: ${{ github.workspace }}/install/*
|
||||
retention-days: 60
|
||||
compression-level: 9
|
||||
@@ -0,0 +1,21 @@
|
||||
name: Run Test and Store Logs
|
||||
description: Run a test and store the log.
|
||||
inputs:
|
||||
target:
|
||||
description: 'The test target to run'
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Run Tests
|
||||
shell: bash
|
||||
run: cmake --build build --target ${{ inputs.target }}
|
||||
|
||||
- name: Move and Truncate Results
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p results
|
||||
mv build/Testing/Temporary/LastTest.log results/${{ inputs.target }}.log || true
|
||||
truncate --size="<20M" results/${{ inputs.target }}.log || true
|
||||
@@ -25,111 +25,59 @@ jobs:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: '0'
|
||||
fetch-tags: 'true'
|
||||
|
||||
- name: Set runner label
|
||||
run: echo "runner_label=${{ matrix.arch[1] }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Set rootfs paths
|
||||
- name: Set runner info
|
||||
run: |
|
||||
echo "FEX_ROOTFS_MOUNT=/mnt/AutoNFS/rootfs/" >> $GITHUB_ENV
|
||||
echo "FEX_ROOTFS_PATH=$HOME/Rootfs/" >> $GITHUB_ENV
|
||||
echo "FEX_ROOTFS=$HOME/Rootfs/" >> $GITHUB_ENV
|
||||
echo "runner_label=${{ matrix.arch[1] }}" >> $GITHUB_ENV
|
||||
echo "runner_name=$(hostname)" >> $GITHUB_ENV
|
||||
|
||||
- name: Update RootFS cache
|
||||
# Use a bash shell so we can use the same syntax for environment variable
|
||||
# access regardless of the host operating system
|
||||
shell: bash
|
||||
run: $GITHUB_WORKSPACE/Scripts/CI_FetchRootFS.py
|
||||
|
||||
- name : submodule checkout
|
||||
# Need to update submodules
|
||||
run: |
|
||||
git submodule sync --recursive
|
||||
git submodule update --init --depth 1
|
||||
|
||||
- name: Clean Build Environment
|
||||
run: rm -Rf ${{runner.workspace}}/build
|
||||
|
||||
- name: Create Build Environment
|
||||
# Some projects don't allow in-source building, so create a separate build directory
|
||||
# We'll use this as our working directory for all subsequent commands
|
||||
run: cmake -E make_directory ${{runner.workspace}}/build
|
||||
- name: Setup Build Environment
|
||||
uses: ./.github/workflows/setup-env
|
||||
|
||||
- name: Configure CMake
|
||||
# Use a bash shell so we can use the same syntax for environment variable
|
||||
# access regardless of the host operating system
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
# Note the current convention is to use the -S and -B options here to specify source
|
||||
# and build directories, but this is only available with CMake 3.13 and higher.
|
||||
# The CMake binaries on the Github Actions machines are (as of this writing) 3.12
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G Ninja -DENABLE_VIXL_SIMULATOR=True -DENABLE_VIXL_DISASSEMBLER=True -DENABLE_LTO=False -DENABLE_ASSERTIONS=True -DENABLE_X86_HOST_DEBUG=True
|
||||
run: |
|
||||
cmake -S . -B build -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G Ninja -DENABLE_VIXL_SIMULATOR=True -DENABLE_LTO=False \
|
||||
-DENABLE_VIXL_DISASSEMBLER=True -DENABLE_ASSERTIONS=True -DENABLE_X86_HOST_DEBUG=True
|
||||
|
||||
# These steps make a lot of noise but rarely fail.
|
||||
# Put them in a separate step to make normal build logs easier to parse
|
||||
- name: Noisy Build Targets
|
||||
run: cmake --build build --target asm_files 32bit_asm_files JemallocLibs Catch2 vixl cephes_128bit
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
# Execute the build. You can specify a specific target with "--target <NAME>"
|
||||
run: cmake --build . --config $BUILD_TYPE
|
||||
run: cmake --build build
|
||||
|
||||
- name: ASM Tests - SVE256
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
# Execute the unit tests
|
||||
run: cmake --build . --config $BUILD_TYPE --target asm_tests
|
||||
|
||||
- name: ASM Test SVE256 Results move
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: mv ${{runner.workspace}}/build/Testing/Temporary/LastTest.log ${{runner.workspace}}/build/Testing/Temporary/LastTest_ASM_SVE256Bit.log || true
|
||||
uses: ./.github/workflows/test
|
||||
with:
|
||||
target: asm_tests
|
||||
|
||||
- name: ASM Tests - SVE128
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
if: ${{ always() }}
|
||||
uses: ./.github/workflows/test
|
||||
env:
|
||||
FEX_FORCESVEWIDTH: "128"
|
||||
# Execute the unit tests
|
||||
run: cmake --build . --config $BUILD_TYPE --target asm_tests
|
||||
|
||||
- name: ASM Test 128-bit Results move
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: mv ${{runner.workspace}}/build/Testing/Temporary/LastTest.log ${{runner.workspace}}/build/Testing/Temporary/LastTest_ASM_SVE128Bit.log || true
|
||||
with:
|
||||
target: asm_tests
|
||||
|
||||
- name: ASM Tests - ASIMD
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
shell: bash
|
||||
if: ${{ always() }}
|
||||
uses: ./.github/workflows/test
|
||||
env:
|
||||
FEX_HOSTFEATURES: "disablesve"
|
||||
# Execute the unit tests
|
||||
run: cmake --build . --config $BUILD_TYPE --target asm_tests
|
||||
|
||||
- name: ASM Test ASIMD Results move
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: mv ${{runner.workspace}}/build/Testing/Temporary/LastTest.log ${{runner.workspace}}/build/Testing/Temporary/LastTest_ASM_ASIMD.log || true
|
||||
|
||||
- name: Truncate test results
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
# Cap out the log files at 20M in case something crash spins and dumps fault text
|
||||
# ASM tests get quite close to 10MB
|
||||
run: truncate --size="<20M" ${{runner.workspace}}/build/Testing/Temporary/LastTest_*.log || true
|
||||
|
||||
- name: Set runner name
|
||||
if: ${{ always() }}
|
||||
run: echo "runner_name=$(hostname)" >> $GITHUB_ENV
|
||||
with:
|
||||
target: asm_tests
|
||||
|
||||
- name: Upload results
|
||||
if: ${{ always() }}
|
||||
uses: 'actions/upload-artifact@v4'
|
||||
uses: actions/upload-artifact@v6
|
||||
timeout-minutes: 1
|
||||
with:
|
||||
name: Results-${{ env.runner_name }}
|
||||
path: ${{runner.workspace}}/build/Testing/Temporary/LastTest_*.log
|
||||
name: Results-${{ env.runner_name }}-${{ env.runner_label }}
|
||||
path: results/*.log
|
||||
retention-days: 3
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
name: Wine DLL Build
|
||||
description: Build a wow64 or arm64ec Wine DLL
|
||||
|
||||
inputs:
|
||||
target:
|
||||
description: 'The target (arm64ec or wow64)'
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Clean Build Environment
|
||||
shell: bash
|
||||
run: rm -Rf build_${{ inputs.target }}
|
||||
|
||||
- name: Configure CMake
|
||||
shell: bash
|
||||
run: |
|
||||
case "${{ inputs.target }}" in
|
||||
wow64) _cc=aarch64 ;;
|
||||
arm64ec) _cc=arm64ec ;;
|
||||
esac
|
||||
|
||||
cmake -S . -B build_${{ inputs.target }} -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_TOOLCHAIN_FILE=Data/CMake/toolchain_mingw.cmake \
|
||||
-DMINGW_TRIPLE=${_cc}-w64-mingw32 -DCMAKE_INSTALL_LIBDIR=/usr/lib/wine/aarch64-windows -G Ninja \
|
||||
-DENABLE_LTO=False -DENABLE_ASSERTIONS=False -DENABLE_JEMALLOC_GLIBC_ALLOC=False \
|
||||
-DBUILD_TESTING=False -DCMAKE_INSTALL_PREFIX=/usr -DTUNE_ARCH=generic -DTUNE_CPU=none
|
||||
|
||||
- name: Build
|
||||
shell: bash
|
||||
run: cmake --build build_${{ inputs.target }}
|
||||
|
||||
- name: Install
|
||||
shell: bash
|
||||
run: DESTDIR="$PWD"/install cmake --build build_${{ inputs.target }} -t install
|
||||
@@ -17,72 +17,39 @@ jobs:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: '0'
|
||||
fetch-tags: 'true'
|
||||
|
||||
- name: Add MingGW to PATH
|
||||
run: echo "$HOME/llvm-mingw/build/bin/" >> $GITHUB_PATH
|
||||
|
||||
- name : submodule checkout
|
||||
- name: Checkout Submodules
|
||||
# Need to update submodules
|
||||
run: |
|
||||
git submodule sync --recursive
|
||||
git submodule update --init --depth 1
|
||||
|
||||
- name: Clean install directory
|
||||
run: |
|
||||
rm -Rf ${{runner.workspace}}/build_install
|
||||
mkdir ${{runner.workspace}}/build_install
|
||||
run: rm -Rf install
|
||||
|
||||
- name: Clean Build Environment
|
||||
run: |
|
||||
rm -Rf ${{runner.workspace}}/build_arm64ec
|
||||
rm -Rf ${{runner.workspace}}/build_wow64
|
||||
- name: Build (wow64)
|
||||
uses: ./.github/workflows/wine_build
|
||||
with:
|
||||
target: wow64
|
||||
|
||||
- name: Create Build Environment arm64ec
|
||||
run: |
|
||||
cmake -E make_directory ${{runner.workspace}}/build_arm64ec
|
||||
cmake -E make_directory ${{runner.workspace}}/build_wow64
|
||||
|
||||
- name: Configure CMake arm64ec
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build_arm64ec
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_TOOLCHAIN_FILE=$GITHUB_WORKSPACE/Data/CMake/toolchain_mingw.cmake -DMINGW_TRIPLE=arm64ec-w64-mingw32 -DCMAKE_INSTALL_LIBDIR=/usr/lib/wine/aarch64-windows -G Ninja -DENABLE_LTO=False -DENABLE_ASSERTIONS=False -DENABLE_JEMALLOC_GLIBC_ALLOC=False -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_TESTING=False -DCMAKE_INSTALL_PREFIX=/usr
|
||||
|
||||
- name: Configure CMake wow64
|
||||
shell: bash
|
||||
working-directory: ${{runner.workspace}}/build_wow64
|
||||
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_TOOLCHAIN_FILE=$GITHUB_WORKSPACE/Data/CMake/toolchain_mingw.cmake -DMINGW_TRIPLE=aarch64-w64-mingw32 -DCMAKE_INSTALL_LIBDIR=/usr/lib/wine/aarch64-windows -G Ninja -DENABLE_LTO=False -DENABLE_ASSERTIONS=False -DENABLE_JEMALLOC_GLIBC_ALLOC=False -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_TESTING=False -DCMAKE_INSTALL_PREFIX=/usr
|
||||
|
||||
- name: Build arm64ec
|
||||
working-directory: ${{runner.workspace}}/build_arm64ec
|
||||
shell: bash
|
||||
run: cmake --build . --config $BUILD_TYPE
|
||||
|
||||
- name: install arm64ec
|
||||
working-directory: ${{runner.workspace}}/build_arm64ec
|
||||
shell: bash
|
||||
env:
|
||||
DESTDIR: ${{runner.workspace}}/build_install
|
||||
run: cmake --build . --config $BUILD_TYPE -t install
|
||||
|
||||
- name: Build wow64
|
||||
working-directory: ${{runner.workspace}}/build_wow64
|
||||
shell: bash
|
||||
run: cmake --build . --config $BUILD_TYPE
|
||||
|
||||
- name: install wow64
|
||||
working-directory: ${{runner.workspace}}/build_wow64
|
||||
shell: bash
|
||||
env:
|
||||
DESTDIR: ${{runner.workspace}}/build_install
|
||||
run: cmake --build . --config $BUILD_TYPE -t install
|
||||
- name: Build (arm64ec)
|
||||
uses: ./.github/workflows/wine_build
|
||||
with:
|
||||
target: arm64ec
|
||||
|
||||
- name: Upload libraries
|
||||
uses: 'actions/upload-artifact@v4'
|
||||
uses: actions/upload-artifact@v6
|
||||
timeout-minutes: 1
|
||||
with:
|
||||
overwrite: true
|
||||
name: wine_dll_artifacts
|
||||
path: ${{runner.workspace}}/build_install/usr/lib/wine/aarch64-windows/lib*.dll
|
||||
path: ${{ github.workspace }}/install/usr/lib/wine/aarch64-windows/lib*.dll
|
||||
retention-days: 60
|
||||
compression-level: 9
|
||||
@@ -11,3 +11,5 @@ out/
|
||||
.vs/
|
||||
*.pyc
|
||||
.cache
|
||||
.idea/
|
||||
CMakeLists.txt.user
|
||||
@@ -0,0 +1,32 @@
|
||||
variables:
|
||||
DEBIAN_FRONTEND: noninteractive
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
GIT_DEPTH: 0
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
|
||||
aarch64:
|
||||
image: registry.gitlab.steamos.cloud/steamrt/steamrt4/sdk/arm64:4.0.20251117.183306
|
||||
tags:
|
||||
- docker
|
||||
- linux
|
||||
- arm64
|
||||
- aarch64
|
||||
script:
|
||||
- apt-get -y update
|
||||
- apt-get install -y
|
||||
git cmake ninja-build ccache
|
||||
lld clang
|
||||
libclang-dev llvm-dev
|
||||
libstdc++-14-dev-i386-cross libgcc-14-dev-i386-cross
|
||||
libstdc++-14-dev-amd64-cross libgcc-14-dev-amd64-cross
|
||||
- cmake -E make_directory build/
|
||||
- cmake -DCMAKE_BUILD_TYPE=Release -G Ninja -DBUILD_STEAM_SUPPORT=True -DENABLE_LTO=True -DENABLE_ASSERTIONS=False -DBUILD_THUNKS=True -DBUILD_FEXCONFIG=False -DBUILD_TESTING=False -DENABLE_CLANG_THUNKS=True -DUSE_LINKER=lld -DCMAKE_INSTALL_PREFIX=/usr -DTUNE_ARCH=armv8.2-a -DTUNE_CPU=none . -B build/
|
||||
- cmake --build build/ --config Release
|
||||
- DESTDIR=$(pwd)/install/ cmake --build build/ --config Release -t install
|
||||
|
||||
artifacts:
|
||||
name: "steamrt artifacts"
|
||||
untracked: false
|
||||
paths:
|
||||
- install/
|
||||
+10
-7
@@ -17,9 +17,6 @@
|
||||
shallow = true
|
||||
path = External/fex-gcc-target-tests-bins
|
||||
url = https://github.com/FEX-Emu/fex-gcc-target-tests-bins.git
|
||||
[submodule "External/jemalloc"]
|
||||
path = External/jemalloc
|
||||
url = https://github.com/FEX-Emu/jemalloc.git
|
||||
[submodule "External/fmt"]
|
||||
path = External/fmt
|
||||
url = https://github.com/fmtlib/fmt.git
|
||||
@@ -32,10 +29,6 @@
|
||||
[submodule "External/Catch2"]
|
||||
path = External/Catch2
|
||||
url = https://github.com/catchorg/Catch2.git
|
||||
[submodule "External/robin-map"]
|
||||
shallow = true
|
||||
path = External/robin-map
|
||||
url = https://github.com/FEX-Emu/robin-map.git
|
||||
[submodule "External/Vulkan-Headers"]
|
||||
shallow = true
|
||||
path = External/Vulkan-Headers
|
||||
@@ -49,3 +42,13 @@
|
||||
[submodule "External/range-v3"]
|
||||
path = External/range-v3
|
||||
url = https://github.com/ericniebler/range-v3.git
|
||||
[submodule "External/zydis"]
|
||||
shallow = true
|
||||
path = External/zydis
|
||||
url = https://github.com/zyantific/zydis.git
|
||||
[submodule "External/unordered_dense"]
|
||||
path = External/unordered_dense
|
||||
url = https://github.com/martinus/unordered_dense.git
|
||||
[submodule "External/rpmalloc"]
|
||||
path = External/rpmalloc
|
||||
url = https://github.com/FEX-Emu/rpmalloc.git
|
||||
+79
-40
@@ -20,7 +20,7 @@ option(ENABLE_ASSERTIONS "Enable debug assertions" FALSE)
|
||||
option(ENABLE_GDB_SYMBOLS "Enable GDBSymbols integration support" ${HAVE_GDB_JIT_READER_H})
|
||||
option(ENABLE_STRICT_WERROR "Enable stricter -Werror" FALSE)
|
||||
option(ENABLE_WERROR "Enable -Werror" FALSE)
|
||||
option(ENABLE_JEMALLOC "Enable jemalloc allocator" TRUE)
|
||||
option(ENABLE_FEX_ALLOCATOR "Enable allocator for FEX" TRUE)
|
||||
option(ENABLE_JEMALLOC_GLIBC_ALLOC "Enable jemalloc glibc allocator" TRUE)
|
||||
option(ENABLE_OFFLINE_TELEMETRY "Enable FEX offline telemetry" TRUE)
|
||||
option(ENABLE_COMPILE_TIME_TRACE "Enable time trace compile option" FALSE)
|
||||
@@ -28,6 +28,7 @@ option(ENABLE_LIBCXX "Use LLVM's libc++ instead of the GNU libstdc++" FALSE)
|
||||
option(ENABLE_CCACHE "Enable ccache for build caching" TRUE)
|
||||
option(ENABLE_VIXL_SIMULATOR "Use the VIXL simulator for emulation (only useful for CI testing)" FALSE)
|
||||
option(ENABLE_VIXL_DISASSEMBLER "Enable debug disassembler output with VIXL" FALSE)
|
||||
option(ENABLE_ZYDIS "Enable x86/x86-64 guest disassembler output with Zydis" FALSE)
|
||||
option(USE_LEGACY_BINFMTMISC "Use legacy method of setting up binfmt_misc" FALSE)
|
||||
option(ENABLE_FEXCORE_PROFILER "Enable FEXCore's timeline profiling capabilities" FALSE)
|
||||
set(FEXCORE_PROFILER_BACKEND "gpuvis" CACHE STRING "Set which backend to use for FEXCore's profiler")
|
||||
@@ -74,7 +75,7 @@ elseif (MSVC)
|
||||
message(FATAL_ERROR "FEX doesn't support MSVC! Use Clang on MinGW instead.")
|
||||
elseif (MINGW)
|
||||
message(STATUS "Building for MinGW")
|
||||
set(ENABLE_JEMALLOC TRUE)
|
||||
set(ENABLE_FEX_ALLOCATOR TRUE)
|
||||
set(ENABLE_JEMALLOC_GLIBC_ALLOC FALSE)
|
||||
else ()
|
||||
message(STATUS "Clang version ${CMAKE_CXX_COMPILER_VERSION}")
|
||||
@@ -97,16 +98,16 @@ if (processor MATCHES "x86|amd64")
|
||||
endif()
|
||||
|
||||
set(ARCHITECTURE_x86_64 1)
|
||||
add_definitions(-DARCHITECTURE_x86_64=1)
|
||||
add_compile_definitions(ARCHITECTURE_x86_64=1)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcx16")
|
||||
elseif (processor MATCHES "^aarch64|^arm64|^armv8\.*")
|
||||
set(ARCHITECTURE_arm64 1)
|
||||
add_definitions(-DARCHITECTURE_arm64=1)
|
||||
add_compile_definitions(ARCHITECTURE_arm64=1)
|
||||
|
||||
# arm64ec needs to define both arm64 and arm64ec
|
||||
if (processor MATCHES "^arm64ec")
|
||||
set(ARCHITECTURE_arm64ec 1)
|
||||
add_definitions(-DARCHITECTURE_arm64ec=1)
|
||||
add_compile_definitions(ARCHITECTURE_arm64ec=1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -116,28 +117,28 @@ if (NOT (ARCHITECTURE_arm64 OR ARCHITECTURE_arm64ec OR ARCHITECTURE_x86_64))
|
||||
endif()
|
||||
|
||||
if (BUILD_STEAM_SUPPORT)
|
||||
add_definitions(-DFEX_STEAM_SUPPORT=1)
|
||||
add_compile_definitions(FEX_STEAM_SUPPORT=1)
|
||||
endif()
|
||||
|
||||
if (ENABLE_FEXCORE_PROFILER)
|
||||
add_definitions(-DENABLE_FEXCORE_PROFILER=1)
|
||||
add_compile_definitions(ENABLE_FEXCORE_PROFILER=1)
|
||||
string(TOUPPER "${FEXCORE_PROFILER_BACKEND}" FEXCORE_PROFILER_BACKEND)
|
||||
|
||||
if (FEXCORE_PROFILER_BACKEND STREQUAL "GPUVIS")
|
||||
add_definitions(-DFEXCORE_PROFILER_BACKEND=1)
|
||||
add_compile_definitions(FEXCORE_PROFILER_BACKEND=1)
|
||||
elseif (FEXCORE_PROFILER_BACKEND STREQUAL "TRACY")
|
||||
add_definitions(-DFEXCORE_PROFILER_BACKEND=2)
|
||||
add_definitions(-DTRACY_ENABLE=1)
|
||||
add_compile_definitions(FEXCORE_PROFILER_BACKEND=2)
|
||||
add_compile_definitions(TRACY_ENABLE=1)
|
||||
# Required so that Tracy will only start in the selected guest application
|
||||
add_definitions(-DTRACY_MANUAL_LIFETIME=1)
|
||||
add_definitions(-DTRACY_DELAYED_INIT=1)
|
||||
add_compile_definitions(TRACY_MANUAL_LIFETIME=1)
|
||||
add_compile_definitions(TRACY_DELAYED_INIT=1)
|
||||
# This interferes with FEX's signal handling
|
||||
add_definitions(-DTRACY_NO_CRASH_HANDLER=1)
|
||||
add_compile_definitions(TRACY_NO_CRASH_HANDLER=1)
|
||||
# Tracy can gather call stack samples in regular intervals, but this
|
||||
# isn't useful for us since it would usually sample opaque JIT code
|
||||
add_definitions(-DTRACY_NO_SAMPLING=1)
|
||||
add_compile_definitions(TRACY_NO_SAMPLING=1)
|
||||
# This pulls in libbacktrace which allocators in global constructors (before FEX can set up its allocator hooks)
|
||||
add_definitions(-DTRACY_NO_CALLSTACK=1)
|
||||
add_compile_definitions(TRACY_NO_CALLSTACK=1)
|
||||
if (MINGW)
|
||||
message(FATAL_ERROR "Tracy profiler not supported on MinGW")
|
||||
endif()
|
||||
@@ -151,7 +152,7 @@ if (ENABLE_JEMALLOC_GLIBC_ALLOC AND ENABLE_GLIBC_ALLOCATOR_HOOK_FAULT)
|
||||
endif()
|
||||
|
||||
if (ENABLE_GLIBC_ALLOCATOR_HOOK_FAULT)
|
||||
add_definitions(-DGLIBC_ALLOCATOR_FAULT=1)
|
||||
add_compile_definitions(GLIBC_ALLOCATOR_FAULT=1)
|
||||
endif()
|
||||
|
||||
# uninstall target
|
||||
@@ -178,12 +179,12 @@ endif()
|
||||
|
||||
if (ENABLE_ASSERTIONS)
|
||||
message(STATUS "Assertions enabled")
|
||||
add_definitions(-DASSERTIONS_ENABLED=1)
|
||||
add_compile_definitions(ASSERTIONS_ENABLED=1)
|
||||
endif()
|
||||
|
||||
if (ENABLE_GDB_SYMBOLS)
|
||||
message(STATUS "GDBSymbols support enabled")
|
||||
add_definitions(-DGDB_SYMBOLS_ENABLED=1)
|
||||
add_compile_definitions(GDB_SYMBOLS_ENABLED=1)
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
@@ -220,14 +221,24 @@ if (HAS_CLANG_PRESERVE_ALL)
|
||||
endif()
|
||||
|
||||
if (ARCHITECTURE_arm64 AND HAS_CLANG_PRESERVE_ALL)
|
||||
add_definitions("-DFEX_PRESERVE_ALL_ATTR=__attribute__((preserve_all))" "-DFEX_HAS_PRESERVE_ALL_ATTR=1")
|
||||
add_compile_definitions("FEX_PRESERVE_ALL_ATTR=__attribute__((preserve_all))" "FEX_HAS_PRESERVE_ALL_ATTR=1")
|
||||
else()
|
||||
add_definitions("-DFEX_PRESERVE_ALL_ATTR=" "-DFEX_HAS_PRESERVE_ALL_ATTR=0")
|
||||
add_compile_definitions("FEX_PRESERVE_ALL_ATTR=" "FEX_HAS_PRESERVE_ALL_ATTR=0")
|
||||
endif()
|
||||
|
||||
check_cxx_source_compiles(
|
||||
"
|
||||
#define _GNU_SOURCE
|
||||
#include <errno.h>
|
||||
int main() {
|
||||
return program_invocation_name == nullptr;
|
||||
}"
|
||||
HAS_PROGRAM_INVOCATION_NAME)
|
||||
add_compile_definitions("HAS_PROGRAM_INVOCATION_NAME=${HAS_PROGRAM_INVOCATION_NAME}")
|
||||
|
||||
if (ENABLE_VIXL_SIMULATOR)
|
||||
# We can run the simulator on both x86-64 or AArch64 hosts
|
||||
add_definitions(-DVIXL_SIMULATOR=1 -DVIXL_INCLUDE_SIMULATOR_AARCH64=1)
|
||||
add_compile_definitions(VIXL_SIMULATOR=1 VIXL_INCLUDE_SIMULATOR_AARCH64=1)
|
||||
endif()
|
||||
|
||||
if (ENABLE_CCACHE)
|
||||
@@ -263,7 +274,7 @@ endif()
|
||||
|
||||
if (NOT ENABLE_OFFLINE_TELEMETRY)
|
||||
# Disable FEX offline telemetry entirely if asked
|
||||
add_definitions(-DFEX_DISABLE_TELEMETRY=1)
|
||||
add_compile_definitions(FEX_DISABLE_TELEMETRY=1)
|
||||
endif()
|
||||
|
||||
if (ENABLE_UBSAN)
|
||||
@@ -274,13 +285,13 @@ if (ENABLE_UBSAN)
|
||||
# that are regularly access unaligned.
|
||||
# function: syscalls cast function pointers to void (*)(unsigned long...), causing warnings
|
||||
# related to this access.
|
||||
add_definitions(-DENABLE_UBSAN=1)
|
||||
add_compile_definitions(ENABLE_UBSAN=1)
|
||||
add_compile_options(-fno-omit-frame-pointer -fsanitize=undefined -fno-sanitize=alignment -fno-sanitize=function -fno-sanitize-recover=undefined)
|
||||
link_libraries(-fno-omit-frame-pointer -fsanitize=undefined -fno-sanitize=alignment -fno-sanitize=function -fno-sanitize-recover=undefined)
|
||||
endif()
|
||||
|
||||
if (ENABLE_ASAN)
|
||||
add_definitions(-DENABLE_ASAN=1)
|
||||
add_compile_definitions(ENABLE_ASAN=1)
|
||||
add_compile_options(-fno-omit-frame-pointer -fsanitize=address -fsanitize-address-use-after-scope)
|
||||
link_libraries(-fno-omit-frame-pointer -fsanitize=address -fsanitize-address-use-after-scope)
|
||||
endif()
|
||||
@@ -308,12 +319,12 @@ elseif (NOT MINGW)
|
||||
" Use at your own risk!")
|
||||
endif()
|
||||
|
||||
if (ENABLE_JEMALLOC)
|
||||
# The jemalloc subproject that all FEXCore fextl objects allocate through.
|
||||
add_subdirectory(External/jemalloc/)
|
||||
if (ENABLE_FEX_ALLOCATOR)
|
||||
# The rpmalloc subproject that all FEXCore fextl objects allocate through.
|
||||
add_subdirectory(External/rpmalloc/)
|
||||
elseif (NOT MINGW)
|
||||
message(STATUS
|
||||
" jemalloc disabled!\n"
|
||||
message (STATUS
|
||||
" FEX allocator is disabled!\n"
|
||||
" This is not a recommended configuration!\n"
|
||||
" This will very explicitly break 32-bit application execution!\n"
|
||||
" Use at your own risk!")
|
||||
@@ -336,19 +347,36 @@ list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/Data/CMake/)
|
||||
include(LinkerGC)
|
||||
|
||||
## Externals ##
|
||||
include_directories(External/robin-map/include/)
|
||||
|
||||
find_package(unordered_dense QUIET CONFIG)
|
||||
if (NOT unordered_dense_FOUND)
|
||||
add_subdirectory(External/unordered_dense)
|
||||
endif()
|
||||
|
||||
include(CTest)
|
||||
if (BUILD_TESTING OR ENABLE_VIXL_DISASSEMBLER OR ENABLE_VIXL_SIMULATOR)
|
||||
add_subdirectory(External/vixl/)
|
||||
include_directories(SYSTEM External/vixl/src/)
|
||||
endif()
|
||||
|
||||
if (ENABLE_ZYDIS)
|
||||
find_package(Zycore 1.5 MODULE QUIET)
|
||||
find_package(Zydis 4.0 MODULE QUIET)
|
||||
|
||||
if (TARGET Zydis::Zydis AND TARGET Zycore::Zycore)
|
||||
message(STATUS "Using system Zydis")
|
||||
else()
|
||||
set(ZYDIS_BUILD_TOOLS OFF CACHE BOOL "" FORCE)
|
||||
set(ZYDIS_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
|
||||
|
||||
message(STATUS "Using bundled Zydis")
|
||||
add_subdirectory(External/zydis/)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (ENABLE_FEXCORE_PROFILER AND FEXCORE_PROFILER_BACKEND STREQUAL "TRACY")
|
||||
add_subdirectory(External/tracy)
|
||||
endif()
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
find_package(Python 3.9 REQUIRED COMPONENTS Interpreter)
|
||||
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
@@ -363,8 +391,8 @@ if (NOT TARGET xxHash::xxhash)
|
||||
add_subdirectory(External/xxhash/cmake_unofficial/)
|
||||
endif()
|
||||
|
||||
add_definitions(-Wno-trigraphs)
|
||||
add_definitions(-DGLOBAL_DATA_DIRECTORY="${DATA_DIRECTORY}/")
|
||||
add_compile_options(-Wno-trigraphs)
|
||||
add_compile_definitions(GLOBAL_DATA_DIRECTORY="${DATA_DIRECTORY}/")
|
||||
|
||||
if (BUILD_TESTING)
|
||||
find_package(Catch2 3 QUIET)
|
||||
@@ -395,7 +423,6 @@ if (NOT range-v3_FOUND)
|
||||
endif()
|
||||
|
||||
add_subdirectory(External/tiny-json/)
|
||||
include_directories(External/tiny-json/)
|
||||
|
||||
include_directories(Source/)
|
||||
include_directories("${CMAKE_BINARY_DIR}/Source/")
|
||||
@@ -496,25 +523,37 @@ else()
|
||||
set(GIT_DESCRIBE_STRING "${OVERRIDE_VERSION}")
|
||||
endif()
|
||||
|
||||
set(GIT_SHORT_HASH "Unknown")
|
||||
set(GIT_HASH "Unknown")
|
||||
|
||||
if (OVERRIDE_HASH STREQUAL "detect")
|
||||
find_package(Git)
|
||||
|
||||
if (GIT_FOUND)
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXECUTABLE} rev-parse --short=7 HEAD
|
||||
COMMAND ${GIT_EXECUTABLE} rev-parse HEAD
|
||||
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
|
||||
OUTPUT_VARIABLE GIT_SHORT_HASH
|
||||
OUTPUT_VARIABLE GIT_HASH
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
endif()
|
||||
else()
|
||||
set(GIT_SHORT_HASH "${OVERRIDE_HASH}")
|
||||
set(GIT_HASH "${OVERRIDE_HASH}")
|
||||
endif()
|
||||
|
||||
message(STATUS "FEX version: ${GIT_DESCRIBE_STRING}")
|
||||
message(STATUS "FEX commit: ${GIT_HASH}")
|
||||
|
||||
# Prepends 0x to every two-character sequence in the hash,
|
||||
# OR the final character of the hash, to plumb it for C++ usage. e.g.:
|
||||
# -DOVERRIDE_HASH=123456aa => 0x12, 0x34, 0x56, 0xaa,
|
||||
# -DOVERRIDE_HASH=12345678a => 0x12, 0x34, 0x56, 0x78, 0xa,
|
||||
string(REGEX
|
||||
REPLACE "(..|.$)" "0x\\1, "
|
||||
GIT_HASH_ARRAY "${GIT_HASH}")
|
||||
|
||||
if (ENABLE_IWYU)
|
||||
find_program(IWYU_EXE "iwyu")
|
||||
find_program(IWYU_EXE
|
||||
NAMES iwyu include-what-you-use)
|
||||
if (IWYU_EXE)
|
||||
message(STATUS "IWYU enabled")
|
||||
set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE "${IWYU_EXE}")
|
||||
|
||||
@@ -53,6 +53,7 @@ public:
|
||||
if (!CurrentAlignment) {
|
||||
return;
|
||||
}
|
||||
std::memset(CurrentOffset, 0, Size - CurrentAlignment);
|
||||
CurrentOffset += Size - CurrentAlignment;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
if (CMAKE_CROSSCOMPILING)
|
||||
return()
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_package(Zycore QUIET CONFIG)
|
||||
|
||||
if (Zycore_CONSIDERED_CONFIGS)
|
||||
find_package_handle_standard_args(Zycore CONFIG_MODE)
|
||||
else()
|
||||
find_package(PkgConfig QUIET)
|
||||
pkg_search_module(Zycore QUIET IMPORTED_TARGET zycore)
|
||||
find_package_handle_standard_args(Zycore
|
||||
REQUIRED_VARS zycore_LINK_LIBRARIES
|
||||
VERSION_VAR zycore_VERSION)
|
||||
|
||||
if (TARGET PkgConfig::zycore)
|
||||
add_library(Zycore::Zycore ALIAS PkgConfig::zycore)
|
||||
endif()
|
||||
endif()
|
||||
@@ -0,0 +1,23 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
if (CMAKE_CROSSCOMPILING)
|
||||
return()
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_package(Zydis QUIET CONFIG)
|
||||
|
||||
if (Zydis_CONSIDERED_CONFIGS)
|
||||
find_package_handle_standard_args(Zydis CONFIG_MODE)
|
||||
else()
|
||||
find_package(PkgConfig QUIET)
|
||||
pkg_search_module(Zydis QUIET IMPORTED_TARGET zydis)
|
||||
find_package_handle_standard_args(Zydis
|
||||
REQUIRED_VARS zydis_LINK_LIBRARIES
|
||||
VERSION_VAR zydis_VERSION)
|
||||
|
||||
if (TARGET PkgConfig::zydis)
|
||||
add_library(Zydis::Zydis ALIAS PkgConfig::zydis)
|
||||
endif()
|
||||
endif()
|
||||
+167
-118
@@ -36,71 +36,91 @@ certifi==2025.7.14 \
|
||||
# via
|
||||
# -r requirements_formatting.txt.in
|
||||
# requests
|
||||
cffi==1.15.1 \
|
||||
--hash=sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5 \
|
||||
--hash=sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef \
|
||||
--hash=sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104 \
|
||||
--hash=sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426 \
|
||||
--hash=sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405 \
|
||||
--hash=sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375 \
|
||||
--hash=sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a \
|
||||
--hash=sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e \
|
||||
--hash=sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc \
|
||||
--hash=sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf \
|
||||
--hash=sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185 \
|
||||
--hash=sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497 \
|
||||
--hash=sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3 \
|
||||
--hash=sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35 \
|
||||
--hash=sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c \
|
||||
--hash=sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83 \
|
||||
--hash=sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21 \
|
||||
--hash=sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca \
|
||||
--hash=sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984 \
|
||||
--hash=sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac \
|
||||
--hash=sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd \
|
||||
--hash=sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee \
|
||||
--hash=sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a \
|
||||
--hash=sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2 \
|
||||
--hash=sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192 \
|
||||
--hash=sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7 \
|
||||
--hash=sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585 \
|
||||
--hash=sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f \
|
||||
--hash=sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e \
|
||||
--hash=sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27 \
|
||||
--hash=sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b \
|
||||
--hash=sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e \
|
||||
--hash=sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e \
|
||||
--hash=sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d \
|
||||
--hash=sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c \
|
||||
--hash=sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415 \
|
||||
--hash=sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82 \
|
||||
--hash=sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02 \
|
||||
--hash=sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314 \
|
||||
--hash=sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325 \
|
||||
--hash=sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c \
|
||||
--hash=sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3 \
|
||||
--hash=sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914 \
|
||||
--hash=sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045 \
|
||||
--hash=sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d \
|
||||
--hash=sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9 \
|
||||
--hash=sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5 \
|
||||
--hash=sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2 \
|
||||
--hash=sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c \
|
||||
--hash=sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3 \
|
||||
--hash=sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2 \
|
||||
--hash=sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8 \
|
||||
--hash=sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d \
|
||||
--hash=sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d \
|
||||
--hash=sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9 \
|
||||
--hash=sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162 \
|
||||
--hash=sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76 \
|
||||
--hash=sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4 \
|
||||
--hash=sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e \
|
||||
--hash=sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9 \
|
||||
--hash=sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6 \
|
||||
--hash=sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b \
|
||||
--hash=sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01 \
|
||||
--hash=sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0
|
||||
cffi==2.0.0 \
|
||||
--hash=sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb \
|
||||
--hash=sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b \
|
||||
--hash=sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f \
|
||||
--hash=sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9 \
|
||||
--hash=sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44 \
|
||||
--hash=sha256:0f6084a0ea23d05d20c3edcda20c3d006f9b6f3fefeac38f59262e10cef47ee2 \
|
||||
--hash=sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c \
|
||||
--hash=sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75 \
|
||||
--hash=sha256:1cd13c99ce269b3ed80b417dcd591415d3372bcac067009b6e0f59c7d4015e65 \
|
||||
--hash=sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e \
|
||||
--hash=sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a \
|
||||
--hash=sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e \
|
||||
--hash=sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25 \
|
||||
--hash=sha256:2081580ebb843f759b9f617314a24ed5738c51d2aee65d31e02f6f7a2b97707a \
|
||||
--hash=sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe \
|
||||
--hash=sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b \
|
||||
--hash=sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91 \
|
||||
--hash=sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592 \
|
||||
--hash=sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187 \
|
||||
--hash=sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c \
|
||||
--hash=sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1 \
|
||||
--hash=sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94 \
|
||||
--hash=sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba \
|
||||
--hash=sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb \
|
||||
--hash=sha256:3f4d46d8b35698056ec29bca21546e1551a205058ae1a181d871e278b0b28165 \
|
||||
--hash=sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529 \
|
||||
--hash=sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca \
|
||||
--hash=sha256:4647afc2f90d1ddd33441e5b0e85b16b12ddec4fca55f0d9671fef036ecca27c \
|
||||
--hash=sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6 \
|
||||
--hash=sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c \
|
||||
--hash=sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0 \
|
||||
--hash=sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743 \
|
||||
--hash=sha256:61d028e90346df14fedc3d1e5441df818d095f3b87d286825dfcbd6459b7ef63 \
|
||||
--hash=sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5 \
|
||||
--hash=sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5 \
|
||||
--hash=sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4 \
|
||||
--hash=sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d \
|
||||
--hash=sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b \
|
||||
--hash=sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93 \
|
||||
--hash=sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205 \
|
||||
--hash=sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27 \
|
||||
--hash=sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512 \
|
||||
--hash=sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d \
|
||||
--hash=sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c \
|
||||
--hash=sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037 \
|
||||
--hash=sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26 \
|
||||
--hash=sha256:89472c9762729b5ae1ad974b777416bfda4ac5642423fa93bd57a09204712322 \
|
||||
--hash=sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb \
|
||||
--hash=sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c \
|
||||
--hash=sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8 \
|
||||
--hash=sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4 \
|
||||
--hash=sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414 \
|
||||
--hash=sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9 \
|
||||
--hash=sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664 \
|
||||
--hash=sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9 \
|
||||
--hash=sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775 \
|
||||
--hash=sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739 \
|
||||
--hash=sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc \
|
||||
--hash=sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062 \
|
||||
--hash=sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe \
|
||||
--hash=sha256:b882b3df248017dba09d6b16defe9b5c407fe32fc7c65a9c69798e6175601be9 \
|
||||
--hash=sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92 \
|
||||
--hash=sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5 \
|
||||
--hash=sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13 \
|
||||
--hash=sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d \
|
||||
--hash=sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26 \
|
||||
--hash=sha256:cb527a79772e5ef98fb1d700678fe031e353e765d1ca2d409c92263c6d43e09f \
|
||||
--hash=sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495 \
|
||||
--hash=sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b \
|
||||
--hash=sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6 \
|
||||
--hash=sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c \
|
||||
--hash=sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef \
|
||||
--hash=sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5 \
|
||||
--hash=sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18 \
|
||||
--hash=sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad \
|
||||
--hash=sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3 \
|
||||
--hash=sha256:de8dad4425a6ca6e4e5e297b27b5c824ecc7581910bf9aee86cb6835e6812aa7 \
|
||||
--hash=sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5 \
|
||||
--hash=sha256:e6e73b9e02893c764e7e8d5bb5ce277f1a009cd5243f8228f75f842bf937c534 \
|
||||
--hash=sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49 \
|
||||
--hash=sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2 \
|
||||
--hash=sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5 \
|
||||
--hash=sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453 \
|
||||
--hash=sha256:fe562eb1a64e67dd297ccc4f5addea2501664954f2692b69a76449ec7913ecbf
|
||||
# via
|
||||
# cryptography
|
||||
# pynacl
|
||||
@@ -185,44 +205,56 @@ click==8.1.7 \
|
||||
--hash=sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28 \
|
||||
--hash=sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de
|
||||
# via black
|
||||
cryptography==45.0.5 \
|
||||
--hash=sha256:0027d566d65a38497bc37e0dd7c2f8ceda73597d2ac9ba93810204f56f52ebc7 \
|
||||
--hash=sha256:101ee65078f6dd3e5a028d4f19c07ffa4dd22cce6a20eaa160f8b5219911e7d8 \
|
||||
--hash=sha256:12e55281d993a793b0e883066f590c1ae1e802e3acb67f8b442e721e475e6463 \
|
||||
--hash=sha256:14d96584701a887763384f3c47f0ca7c1cce322aa1c31172680eb596b890ec30 \
|
||||
--hash=sha256:1e1da5accc0c750056c556a93c3e9cb828970206c68867712ca5805e46dc806f \
|
||||
--hash=sha256:206210d03c1193f4e1ff681d22885181d47efa1ab3018766a7b32a7b3d6e6afd \
|
||||
--hash=sha256:2089cc8f70a6e454601525e5bf2779e665d7865af002a5dec8d14e561002e135 \
|
||||
--hash=sha256:3a264aae5f7fbb089dbc01e0242d3b67dffe3e6292e1f5182122bdf58e65215d \
|
||||
--hash=sha256:3af26738f2db354aafe492fb3869e955b12b2ef2e16908c8b9cb928128d42c57 \
|
||||
--hash=sha256:3fcfbefc4a7f332dece7272a88e410f611e79458fab97b5efe14e54fe476f4fd \
|
||||
--hash=sha256:460f8c39ba66af7db0545a8c6f2eabcbc5a5528fc1cf6c3fa9a1e44cec33385e \
|
||||
--hash=sha256:57c816dfbd1659a367831baca4b775b2a5b43c003daf52e9d57e1d30bc2e1b0e \
|
||||
--hash=sha256:5aa1e32983d4443e310f726ee4b071ab7569f58eedfdd65e9675484a4eb67bd1 \
|
||||
--hash=sha256:6ff8728d8d890b3dda5765276d1bc6fb099252915a2cd3aff960c4c195745dd0 \
|
||||
--hash=sha256:7259038202a47fdecee7e62e0fd0b0738b6daa335354396c6ddebdbe1206af2a \
|
||||
--hash=sha256:72e76caa004ab63accdf26023fccd1d087f6d90ec6048ff33ad0445abf7f605a \
|
||||
--hash=sha256:7760c1c2e1a7084153a0f68fab76e754083b126a47d0117c9ed15e69e2103492 \
|
||||
--hash=sha256:8c4a6ff8a30e9e3d38ac0539e9a9e02540ab3f827a3394f8852432f6b0ea152e \
|
||||
--hash=sha256:9024beb59aca9d31d36fcdc1604dd9bbeed0a55bface9f1908df19178e2f116e \
|
||||
--hash=sha256:90cb0a7bb35959f37e23303b7eed0a32280510030daba3f7fdfbb65defde6a97 \
|
||||
--hash=sha256:91098f02ca81579c85f66df8a588c78f331ca19089763d733e34ad359f474174 \
|
||||
--hash=sha256:926c3ea71a6043921050eaa639137e13dbe7b4ab25800932a8498364fc1abec9 \
|
||||
--hash=sha256:982518cd64c54fcada9d7e5cf28eabd3ee76bd03ab18e08a48cad7e8b6f31b18 \
|
||||
--hash=sha256:9b4cf6318915dccfe218e69bbec417fdd7c7185aa7aab139a2c0beb7468c89f0 \
|
||||
--hash=sha256:ad0caded895a00261a5b4aa9af828baede54638754b51955a0ac75576b831b27 \
|
||||
--hash=sha256:b85980d1e345fe769cfc57c57db2b59cff5464ee0c045d52c0df087e926fbe63 \
|
||||
--hash=sha256:b8fa8b0a35a9982a3c60ec79905ba5bb090fc0b9addcfd3dc2dd04267e45f25e \
|
||||
--hash=sha256:b9e38e0a83cd51e07f5a48ff9691cae95a79bea28fe4ded168a8e5c6c77e819d \
|
||||
--hash=sha256:bd4c45986472694e5121084c6ebbd112aa919a25e783b87eb95953c9573906d6 \
|
||||
--hash=sha256:be97d3a19c16a9be00edf79dca949c8fa7eff621763666a145f9f9535a5d7f42 \
|
||||
--hash=sha256:c648025b6840fe62e57107e0a25f604db740e728bd67da4f6f060f03017d5097 \
|
||||
--hash=sha256:d05a38884db2ba215218745f0781775806bde4f32e07b135348355fe8e4991d9 \
|
||||
--hash=sha256:dd420e577921c8c2d31289536c386aaa30140b473835e97f83bc71ea9d2baf2d \
|
||||
--hash=sha256:e357286c1b76403dd384d938f93c46b2b058ed4dfcdce64a770f0537ed3feb6f \
|
||||
--hash=sha256:e6c00130ed423201c5bc5544c23359141660b07999ad82e34e7bb8f882bb78e0 \
|
||||
--hash=sha256:e74d30ec9c7cb2f404af331d5b4099a9b322a8a6b25c4632755c8757345baac5 \
|
||||
--hash=sha256:f3562c2f23c612f2e4a6964a61d942f891d29ee320edb62ff48ffb99f3de9ae8
|
||||
cryptography==46.0.5 \
|
||||
--hash=sha256:02f547fce831f5096c9a567fd41bc12ca8f11df260959ecc7c3202555cc47a72 \
|
||||
--hash=sha256:039917b0dc418bb9f6edce8a906572d69e74bd330b0b3fea4f79dab7f8ddd235 \
|
||||
--hash=sha256:1abfdb89b41c3be0365328a410baa9df3ff8a9110fb75e7b52e66803ddabc9a9 \
|
||||
--hash=sha256:2ae6971afd6246710480e3f15824ed3029a60fc16991db250034efd0b9fb4356 \
|
||||
--hash=sha256:2b7a67c9cd56372f3249b39699f2ad479f6991e62ea15800973b956f4b73e257 \
|
||||
--hash=sha256:351695ada9ea9618b3500b490ad54c739860883df6c1f555e088eaf25b1bbaad \
|
||||
--hash=sha256:38946c54b16c885c72c4f59846be9743d699eee2b69b6988e0a00a01f46a61a4 \
|
||||
--hash=sha256:3b4995dc971c9fb83c25aa44cf45f02ba86f71ee600d81091c2f0cbae116b06c \
|
||||
--hash=sha256:3ce58ba46e1bc2aac4f7d9290223cead56743fa6ab94a5d53292ffaac6a91614 \
|
||||
--hash=sha256:3ee190460e2fbe447175cda91b88b84ae8322a104fc27766ad09428754a618ed \
|
||||
--hash=sha256:4108d4c09fbbf2789d0c926eb4152ae1760d5a2d97612b92d508d96c861e4d31 \
|
||||
--hash=sha256:420d0e909050490d04359e7fdb5ed7e667ca5c3c402b809ae2563d7e66a92229 \
|
||||
--hash=sha256:47fb8a66058b80e509c47118ef8a75d14c455e81ac369050f20ba0d23e77fee0 \
|
||||
--hash=sha256:4c3341037c136030cb46e4b1e17b7418ea4cbd9dd207e4a6f3b2b24e0d4ac731 \
|
||||
--hash=sha256:4d7e3d356b8cd4ea5aff04f129d5f66ebdc7b6f8eae802b93739ed520c47c79b \
|
||||
--hash=sha256:4d8ae8659ab18c65ced284993c2265910f6c9e650189d4e3f68445ef82a810e4 \
|
||||
--hash=sha256:4e817a8920bfbcff8940ecfd60f23d01836408242b30f1a708d93198393a80b4 \
|
||||
--hash=sha256:50bfb6925eff619c9c023b967d5b77a54e04256c4281b0e21336a130cd7fc263 \
|
||||
--hash=sha256:556e106ee01aa13484ce9b0239bca667be5004efb0aabbed28d353df86445595 \
|
||||
--hash=sha256:582f5fcd2afa31622f317f80426a027f30dc792e9c80ffee87b993200ea115f1 \
|
||||
--hash=sha256:5be7bf2fb40769e05739dd0046e7b26f9d4670badc7b032d6ce4db64dddc0678 \
|
||||
--hash=sha256:60ee7e19e95104d4c03871d7d7dfb3d22ef8a9b9c6778c94e1c8fcc8365afd48 \
|
||||
--hash=sha256:61aa400dce22cb001a98014f647dc21cda08f7915ceb95df0c9eaf84b4b6af76 \
|
||||
--hash=sha256:68f68d13f2e1cb95163fa3b4db4bf9a159a418f5f6e7242564fc75fcae667fd0 \
|
||||
--hash=sha256:7d1f30a86d2757199cb2d56e48cce14deddf1f9c95f1ef1b64ee91ea43fe2e18 \
|
||||
--hash=sha256:7d731d4b107030987fd61a7f8ab512b25b53cef8f233a97379ede116f30eb67d \
|
||||
--hash=sha256:803812e111e75d1aa73690d2facc295eaefd4439be1023fefc4995eaea2af90d \
|
||||
--hash=sha256:80a8d7bfdf38f87ca30a5391c0c9ce4ed2926918e017c29ddf643d0ed2778ea1 \
|
||||
--hash=sha256:8293f3dea7fc929ef7240796ba231413afa7b68ce38fd21da2995549f5961981 \
|
||||
--hash=sha256:8456928655f856c6e1533ff59d5be76578a7157224dbd9ce6872f25055ab9ab7 \
|
||||
--hash=sha256:890bcb4abd5a2d3f852196437129eb3667d62630333aacc13dfd470fad3aaa82 \
|
||||
--hash=sha256:94a76daa32eb78d61339aff7952ea819b1734b46f73646a07decb40e5b3448e2 \
|
||||
--hash=sha256:9f16fbdf4da055efb21c22d81b89f155f02ba420558db21288b3d0035bafd5f4 \
|
||||
--hash=sha256:a3d1fae9863299076f05cb8a778c467578262fae09f9dc0ee9b12eb4268ce663 \
|
||||
--hash=sha256:a3d507bb6a513ca96ba84443226af944b0f7f47dcc9a399d110cd6146481d24c \
|
||||
--hash=sha256:abace499247268e3757271b2f1e244b36b06f8515cf27c4d49468fc9eb16e93d \
|
||||
--hash=sha256:ba2a27ff02f48193fc4daeadf8ad2590516fa3d0adeeb34336b96f7fa64c1e3a \
|
||||
--hash=sha256:bc84e875994c3b445871ea7181d424588171efec3e185dced958dad9e001950a \
|
||||
--hash=sha256:bfd56bb4b37ed4f330b82402f6f435845a5f5648edf1ad497da51a8452d5d62d \
|
||||
--hash=sha256:c18ff11e86df2e28854939acde2d003f7984f721eba450b56a200ad90eeb0e6b \
|
||||
--hash=sha256:c3bcce8521d785d510b2aad26ae2c966092b7daa8f45dd8f44734a104dc0bc1a \
|
||||
--hash=sha256:c4143987a42a2397f2fc3b4d7e3a7d313fbe684f67ff443999e803dd75a76826 \
|
||||
--hash=sha256:c69fd885df7d089548a42d5ec05be26050ebcd2283d89b3d30676eb32ff87dee \
|
||||
--hash=sha256:ced80795227d70549a411a4ab66e8ce307899fad2220ce5ab2f296e687eacde9 \
|
||||
--hash=sha256:d66e421495fdb797610a08f43b05269e0a5ea7f5e652a89bfd5a7d3c1dee3648 \
|
||||
--hash=sha256:d861ee9e76ace6cf36a6a89b959ec08e7bc2493ee39d07ffe5acb23ef46d27da \
|
||||
--hash=sha256:e9251e3be159d1020c4030bd2e5f84d6a43fe54b6c19c12f51cde9542a2817b2 \
|
||||
--hash=sha256:f145bba11b878005c496e93e257c1e88f154d278d2638e6450d17e0f31e558d2 \
|
||||
--hash=sha256:fe346b143ff9685e40192a4960938545c699054ba11d4f9029f94751e3f71d87
|
||||
# via
|
||||
# -r requirements_formatting.txt.in
|
||||
# pyjwt
|
||||
@@ -278,18 +310,35 @@ pyjwt==2.8.0 \
|
||||
--hash=sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de \
|
||||
--hash=sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320
|
||||
# via pygithub
|
||||
pynacl==1.5.0 \
|
||||
--hash=sha256:06b8f6fa7f5de8d5d2f7573fe8c863c051225a27b61e6860fd047b1775807858 \
|
||||
--hash=sha256:0c84947a22519e013607c9be43706dd42513f9e6ae5d39d3613ca1e142fba44d \
|
||||
--hash=sha256:20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93 \
|
||||
--hash=sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1 \
|
||||
--hash=sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92 \
|
||||
--hash=sha256:61f642bf2378713e2c2e1de73444a3778e5f0a38be6fee0fe532fe30060282ff \
|
||||
--hash=sha256:8ac7448f09ab85811607bdd21ec2464495ac8b7c66d146bf545b0f08fb9220ba \
|
||||
--hash=sha256:a36d4a9dda1f19ce6e03c9a784a2921a4b726b02e1c736600ca9c22029474394 \
|
||||
--hash=sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b \
|
||||
--hash=sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543
|
||||
# via pygithub
|
||||
pynacl==1.6.2 \
|
||||
--hash=sha256:018494d6d696ae03c7e656e5e74cdfd8ea1326962cc401bcf018f1ed8436811c \
|
||||
--hash=sha256:04316d1fc625d860b6c162fff704eb8426b1a8bcd3abacea11142cbd99a6b574 \
|
||||
--hash=sha256:22de65bb9010a725b0dac248f353bb072969c94fa8d6b1f34b87d7953cf7bbe4 \
|
||||
--hash=sha256:26bfcd00dcf2cf160f122186af731ae30ab120c18e8375684ec2670dccd28130 \
|
||||
--hash=sha256:2fef529ef3ee487ad8113d287a593fa26f48ee3620d92ecc6f1d09ea38e0709b \
|
||||
--hash=sha256:320ef68a41c87547c91a8b58903c9caa641ab01e8512ce291085b5fe2fcb7590 \
|
||||
--hash=sha256:3bffb6d0f6becacb6526f8f42adfb5efb26337056ee0831fb9a7044d1a964444 \
|
||||
--hash=sha256:44081faff368d6c5553ccf55322ef2819abb40e25afaec7e740f159f74813634 \
|
||||
--hash=sha256:46065496ab748469cdd999246d17e301b2c24ae2fdf739132e580a0e94c94a87 \
|
||||
--hash=sha256:5811c72b473b2f38f7e2a3dc4f8642e3a3e9b5e7317266e4ced1fba85cae41aa \
|
||||
--hash=sha256:622d7b07cc5c02c666795792931b50c91f3ce3c2649762efb1ef0d5684c81594 \
|
||||
--hash=sha256:62985f233210dee6548c223301b6c25440852e13d59a8b81490203c3227c5ba0 \
|
||||
--hash=sha256:68be3a09455743ff9505491220b64440ced8973fe930f270c8e07ccfa25b1f9e \
|
||||
--hash=sha256:834a43af110f743a754448463e8fd61259cd4ab5bbedcf70f9dabad1d28a394c \
|
||||
--hash=sha256:8845c0631c0be43abdd865511c41eab235e0be69c81dc66a50911594198679b0 \
|
||||
--hash=sha256:8a66d6fb6ae7661c58995f9c6435bda2b1e68b54b598a6a10247bfcdadac996c \
|
||||
--hash=sha256:8b097553b380236d51ed11356c953bf8ce36a29a3e596e934ecabe76c985a577 \
|
||||
--hash=sha256:a84bf1c20339d06dc0c85d9aea9637a24f718f375d861b2668b2f9f96fa51145 \
|
||||
--hash=sha256:a9f9932d8d2811ce1a8ffa79dcbdf3970e7355b5c8eb0c1a881a57e7f7d96e88 \
|
||||
--hash=sha256:bc4a36b28dd72fb4845e5d8f9760610588a96d5a51f01d84d8c6ff9849968c14 \
|
||||
--hash=sha256:c8a231e36ec2cab018c4ad4358c386e36eede0319a0c41fed24f840b1dac59f6 \
|
||||
--hash=sha256:c949ea47e4206af7c8f604b8278093b674f7c79ed0d4719cc836902bf4517465 \
|
||||
--hash=sha256:d071c6a9a4c94d79eb665db4ce5cedc537faf74f2355e4d502591d850d3913c0 \
|
||||
--hash=sha256:d29bfe37e20e015a7d8b23cfc8bd6aa7909c92a1b8f41ee416bbb3e79ef182b2 \
|
||||
--hash=sha256:fe9847ca47d287af41e82be1dd5e23023d3c31a951da134121ab02e42ac218c9
|
||||
# via
|
||||
# -r requirements_formatting.txt.in
|
||||
# pygithub
|
||||
requests==2.32.4 \
|
||||
--hash=sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c \
|
||||
--hash=sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422
|
||||
@@ -306,9 +355,9 @@ typing-extensions==4.14.1 \
|
||||
--hash=sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36 \
|
||||
--hash=sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76
|
||||
# via pygithub
|
||||
urllib3==2.6.0 \
|
||||
--hash=sha256:c90f7a39f716c572c4e3e58509581ebd83f9b59cced005b7db7ad2d22b0db99f \
|
||||
--hash=sha256:cb9bcef5a4b345d5da5d145dc3e30834f58e8018828cbc724d30b4cb7d4d49f1
|
||||
urllib3==2.6.3 \
|
||||
--hash=sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed \
|
||||
--hash=sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4
|
||||
# via
|
||||
# -r requirements_formatting.txt.in
|
||||
# pygithub
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
black~=25.1
|
||||
darker==2.1.1
|
||||
PyGithub==2.6.1
|
||||
cryptography>=43.0.1
|
||||
urllib3>=2.6.0
|
||||
cryptography>=46.0.5
|
||||
urllib3>=2.6.3
|
||||
requests>=2.32.4
|
||||
idna>=3.7
|
||||
certifi>=2024.7.4
|
||||
PyNaCl>=1.6.2
|
||||
Vendored
-1
Submodule External/jemalloc deleted from 97d986993d.
Vendored
-1
Submodule External/robin-map deleted from d5683d9f18.
+1
Submodule External/rpmalloc added at 1f6fb494f2.
Vendored
+3
@@ -1,3 +1,6 @@
|
||||
set(NAME tiny-json)
|
||||
set(SRCS tiny-json.c)
|
||||
add_library(${NAME} STATIC ${SRCS})
|
||||
|
||||
target_include_directories(${NAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR})
|
||||
add_library(${NAME}::${NAME} ALIAS ${NAME})
|
||||
+1
Submodule External/unordered_dense added at 3234af2c03.
Vendored
+1
-1
Submodule External/vixl updated: ed690c9eca...5f418449c4.
+1
Submodule External/zydis added at 9bfadd6a55.
@@ -24,12 +24,6 @@ include(CheckCXXCompilerFlag)
|
||||
include(CheckIncludeFileCXX)
|
||||
include(CheckCXXSourceCompiles)
|
||||
|
||||
if (EXISTS ${CMAKE_CURRENT_DIR}/External/vixl/)
|
||||
# Useful to have for freestanding libFEXCore
|
||||
add_subdirectory(External/vixl/)
|
||||
include_directories(External/vixl/src/)
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ def print_man_environment_tail():
|
||||
"APP_CONFIG_LOCATION",
|
||||
[
|
||||
"Allows the user to override where FEX looks for configuration files",
|
||||
"By default FEX will look in {$HOME, $XDG_CONFIG_HOME}/.fex-emu/",
|
||||
"By default FEX will look in ${XDG_CONFIG_HOME, $HOME/.config}/fex-emu/",
|
||||
"This will override the full path",
|
||||
"If FEX_PORTABLE is declared then relative paths are also supported",
|
||||
"For FEX: Relative to the FEX binary",
|
||||
@@ -168,7 +168,7 @@ def print_man_environment_tail():
|
||||
"APP_CONFIG",
|
||||
[
|
||||
"Allows the user to override where FEX looks for only the application config file",
|
||||
"By default FEX will look in {$HOME, $XDG_CONFIG_HOME}/.fex-emu/Config.json",
|
||||
"By default FEX will look in ${XDG_CONFIG_HOME, $HOME/.config}/fex-emu/Config.json",
|
||||
"This will override this file location",
|
||||
"One must be careful with this option as it will override any applications that load with execve as well"
|
||||
"If you need to support applications that execve then use FEX_APP_CONFIG_LOCATION instead"
|
||||
@@ -182,7 +182,7 @@ def print_man_environment_tail():
|
||||
"APP_DATA_LOCATION",
|
||||
[
|
||||
"Allows the user to override where FEX looks for data files",
|
||||
"By default FEX will look in {$HOME, $XDG_DATA_HOME}/.fex-emu/",
|
||||
"By default FEX will look in {$XDG_DATA_HOME, $HOME/.local/share}/fex-emu/",
|
||||
"This will override the full path",
|
||||
"This is the folder where FEX stores generated files like IR cache"
|
||||
],
|
||||
@@ -204,7 +204,7 @@ def print_man_environment_tail():
|
||||
"APP_CACHE_LOCATION",
|
||||
[
|
||||
"Allows the user to override where FEX stores and loads cache files",
|
||||
"By default FEX will look in $XDG_CACHE_HOME/fex-emu/ or $HOME/.cache/fex-emu/",
|
||||
"By default FEX will look in ${XDG_CACHE_HOME, $HOME/.cache}/fex-emu/",
|
||||
"This will override the full path, trailing forward-slash is expected to exist",
|
||||
],
|
||||
"''", True)
|
||||
@@ -234,7 +234,7 @@ FEX is very much work in progress, so expect things to change.
|
||||
def print_man_tail():
|
||||
tail ='''.Sh FILES
|
||||
.Bl -tag -width "$prefix/share/fex-emu/GuestThunks" -compact
|
||||
.It Pa $XDG_HOME_DIR/.fex-emu
|
||||
.It Pa $XDG_CONFIG_DIR/fex-emu
|
||||
Default FEX user configuration directory
|
||||
.It Pa $prefix/share/fex-emu/AppConfig
|
||||
System level application configuration files
|
||||
|
||||
@@ -678,6 +678,7 @@ def print_ir_allocator_helpers():
|
||||
# Generate helpers with operands
|
||||
for op in IROps:
|
||||
if op.Name != "Last":
|
||||
output_file.write("\t///\n".join(["\t/// {}\n" .format(comment) for comment in op.Desc]))
|
||||
output_file.write("\tIRPair<IROp_{}> _{}(" .format(op.Name, op.Name))
|
||||
|
||||
# Output SSA args first
|
||||
@@ -751,6 +752,7 @@ def print_ir_allocator_helpers():
|
||||
|
||||
# Now do the OrderedNode * version if necessary
|
||||
if op.SSAArgNum:
|
||||
output_file.write("\t///\n".join(["\t/// {}\n" .format(comment) for comment in op.Desc]))
|
||||
output_file.write("\tIRPair<IROp_{}> _{}(" .format(op.Name, op.Name))
|
||||
|
||||
for i, arg in enumerate(op.Arguments):
|
||||
|
||||
@@ -94,6 +94,10 @@ if (ENABLE_VIXL_DISASSEMBLER)
|
||||
list(APPEND DEFINES -DVIXL_DISASSEMBLER=1)
|
||||
endif()
|
||||
|
||||
if (ENABLE_ZYDIS)
|
||||
list(APPEND DEFINES -DZYDIS_DISASSEMBLER=1)
|
||||
endif()
|
||||
|
||||
if (ARCHITECTURE_arm64 AND HAS_CLANG_PRESERVE_ALL)
|
||||
list(APPEND DEFINES "-DFEXCORE_PRESERVE_ALL_ATTR=__attribute__((preserve_all));-DFEXCORE_HAS_PRESERVE_ALL_ATTR=1")
|
||||
else()
|
||||
@@ -103,7 +107,11 @@ endif()
|
||||
set(LIBS fmt::fmt xxHash::xxhash FEXHeaderUtils CodeEmitter cephes_128bit)
|
||||
|
||||
if (ENABLE_VIXL_DISASSEMBLER OR ENABLE_VIXL_SIMULATOR)
|
||||
list(APPEND LIBS vixl)
|
||||
list(APPEND LIBS vixl::vixl)
|
||||
endif()
|
||||
|
||||
if (ENABLE_ZYDIS)
|
||||
list(APPEND LIBS Zydis::Zydis)
|
||||
endif()
|
||||
|
||||
if (NOT MINGW)
|
||||
@@ -238,15 +246,16 @@ function(AddDefaultOptionsToTarget Name)
|
||||
endif()
|
||||
|
||||
LinkerGC(${Name})
|
||||
target_link_libraries(${Name} PUBLIC unordered_dense::unordered_dense)
|
||||
endfunction()
|
||||
|
||||
# Build FEXCore_Base static library
|
||||
add_library(FEXCore_Base STATIC ${FEXCORE_BASE_SRCS})
|
||||
target_link_libraries(FEXCore_Base ${LIBS})
|
||||
target_link_libraries(FEXCore_Base PUBLIC ${LIBS})
|
||||
AddDefaultOptionsToTarget(FEXCore_Base)
|
||||
|
||||
if (ENABLE_FEXCORE_PROFILER AND FEXCORE_PROFILER_BACKEND STREQUAL "TRACY")
|
||||
target_link_libraries(FEXCore_Base TracyClient)
|
||||
target_link_libraries(FEXCore_Base PUBLIC TracyClient)
|
||||
endif()
|
||||
|
||||
function(AddObject Name)
|
||||
@@ -264,7 +273,7 @@ function(AddLibrary Name Type)
|
||||
# During generation of the import library (dll.a), MinGW needs some extra symbols from libraries
|
||||
# such as fmt, which are propagated by FEXCore_Base. Wonderful.
|
||||
if (MINGW)
|
||||
target_link_libraries(${Name} FEXCore_Base)
|
||||
target_link_libraries(${Name} PRIVATE FEXCore_Base)
|
||||
endif()
|
||||
AddDefaultOptionsToTarget(${Name})
|
||||
endfunction()
|
||||
@@ -282,9 +291,9 @@ endif()
|
||||
# Meta-library to link jemalloc libraries enabled in the build configuration.
|
||||
# Only needed for targets that run emulation. For others, use JemallocDummy.
|
||||
add_library(JemallocLibs STATIC Utils/AllocatorHooks.cpp)
|
||||
if (ENABLE_JEMALLOC)
|
||||
target_compile_definitions(JemallocLibs PRIVATE ENABLE_JEMALLOC=1 JEMALLOC_NO_RENAME=1)
|
||||
target_link_libraries(JemallocLibs PUBLIC FEX_jemalloc)
|
||||
if (ENABLE_FEX_ALLOCATOR)
|
||||
target_compile_definitions(JemallocLibs PRIVATE ENABLE_FEX_ALLOCATOR=1)
|
||||
target_link_libraries(JemallocLibs PUBLIC rpmalloc)
|
||||
endif()
|
||||
if (ENABLE_JEMALLOC_GLIBC_ALLOC)
|
||||
set_source_files_properties(Interface/HLE/Thunks/Thunks.cpp PROPERTIES COMPILE_DEFINITIONS ENABLE_JEMALLOC_GLIBC=1)
|
||||
@@ -299,4 +308,4 @@ if (NOT MINGW)
|
||||
endif()
|
||||
|
||||
# The shared library should always link enabled jemalloc libraries
|
||||
target_link_libraries(${PROJECT_NAME}_shared JemallocLibs)
|
||||
target_link_libraries(${PROJECT_NAME}_shared PRIVATE JemallocLibs)
|
||||
@@ -37,22 +37,26 @@ struct FEX_PACKED X80SoftFloat {
|
||||
#error No 128bit float for this target!
|
||||
#endif
|
||||
|
||||
uint64_t Significand : 64;
|
||||
uint16_t Exponent : 15;
|
||||
uint16_t Sign : 1;
|
||||
uint64_t Significand;
|
||||
union {
|
||||
uint16_t Raw;
|
||||
struct {
|
||||
uint16_t Exponent : 15;
|
||||
uint16_t Sign : 1;
|
||||
};
|
||||
} Top;
|
||||
|
||||
X80SoftFloat() {
|
||||
memset(this, 0, sizeof(*this));
|
||||
}
|
||||
X80SoftFloat(uint16_t _Sign, uint16_t _Exponent, uint64_t _Significand)
|
||||
: Significand {_Significand}
|
||||
, Exponent {_Exponent}
|
||||
, Sign {_Sign} {}
|
||||
, Top {.Raw = static_cast<uint16_t>((_Exponent & 0x7FFF) | (_Sign << 15))} {}
|
||||
|
||||
fextl::string str() const {
|
||||
fextl::ostringstream string;
|
||||
string << std::hex << Sign;
|
||||
string << "_" << Exponent;
|
||||
string << std::hex << Top.Sign;
|
||||
string << "_" << Top.Exponent;
|
||||
string << "_" << (Significand >> 63);
|
||||
string << "_" << (Significand & ((1ULL << 63) - 1));
|
||||
return string.str();
|
||||
@@ -163,18 +167,18 @@ struct FEX_PACKED X80SoftFloat {
|
||||
X80SoftFloat result = 0;
|
||||
if (HandleInfinityOp(state, lhs, result)) {
|
||||
return result;
|
||||
} else if (lhs.Exponent == 0x7FFF && (lhs.Significand & 0x7FFFFFFFFFFFFFFFULL)) { // NaN
|
||||
} else if (lhs.Top.Exponent == 0x7FFF && (lhs.Significand & 0x7FFFFFFFFFFFFFFFULL)) { // NaN
|
||||
// propagate NaN
|
||||
state->exceptionFlags |= softfloat_flag_invalid;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
// Check for zero divisor - fprem(x, 0) is invalid operation
|
||||
if (rhs.Exponent == 0 && rhs.Significand == 0) {
|
||||
if (rhs.Top.Exponent == 0 && rhs.Significand == 0) {
|
||||
state->exceptionFlags |= softfloat_flag_invalid;
|
||||
// Return QNaN
|
||||
result.Sign = 0;
|
||||
result.Exponent = 0x7FFF;
|
||||
result.Top.Sign = 0;
|
||||
result.Top.Exponent = 0x7FFF;
|
||||
result.Significand = 0xC000000000000000ULL;
|
||||
return result;
|
||||
}
|
||||
@@ -253,12 +257,12 @@ struct FEX_PACKED X80SoftFloat {
|
||||
return Result;
|
||||
#else
|
||||
// Zero is a special case, the significand for +/- 0 is +/- zero.
|
||||
if (lhs.Exponent == 0x0 && lhs.Significand == 0x0) {
|
||||
if (lhs.Top.Exponent == 0x0 && lhs.Significand == 0x0) {
|
||||
return lhs;
|
||||
}
|
||||
X80SoftFloat Tmp = lhs;
|
||||
Tmp.Exponent = 0x3FFF;
|
||||
Tmp.Sign = lhs.Sign;
|
||||
Tmp.Top.Exponent = 0x3FFF;
|
||||
Tmp.Top.Sign = lhs.Top.Sign;
|
||||
return Tmp;
|
||||
#endif
|
||||
}
|
||||
@@ -280,12 +284,12 @@ struct FEX_PACKED X80SoftFloat {
|
||||
return Result;
|
||||
#else
|
||||
// Zero is a special case, the exponent is always -inf
|
||||
if (lhs.Exponent == 0x0 && lhs.Significand == 0x0) {
|
||||
if (lhs.Top.Exponent == 0x0 && lhs.Significand == 0x0) {
|
||||
X80SoftFloat Result(1, 0x7FFFUL, 0x8000'0000'0000'0000UL);
|
||||
return Result;
|
||||
}
|
||||
|
||||
int32_t TrueExp = lhs.Exponent - ExponentBias;
|
||||
int32_t TrueExp = lhs.Top.Exponent - ExponentBias;
|
||||
return i32_to_extF80(TrueExp);
|
||||
#endif
|
||||
}
|
||||
@@ -572,8 +576,7 @@ struct FEX_PACKED X80SoftFloat {
|
||||
|
||||
X80SoftFloat(extFloat80_t rhs) {
|
||||
Significand = rhs.signif;
|
||||
Exponent = rhs.signExp & 0x7FFF;
|
||||
Sign = rhs.signExp >> 15;
|
||||
Top.Raw = rhs.signExp;
|
||||
}
|
||||
|
||||
X80SoftFloat(softfloat_state* state, const float rhs) {
|
||||
@@ -606,8 +609,7 @@ struct FEX_PACKED X80SoftFloat {
|
||||
|
||||
void operator=(extFloat80_t rhs) {
|
||||
Significand = rhs.signif;
|
||||
Exponent = rhs.signExp & 0x7FFF;
|
||||
Sign = rhs.signExp >> 15;
|
||||
Top.Raw = rhs.signExp;
|
||||
}
|
||||
|
||||
operator FEXCore::VectorRegType() const {
|
||||
@@ -617,16 +619,16 @@ struct FEX_PACKED X80SoftFloat {
|
||||
operator extFloat80_t() const {
|
||||
extFloat80_t Result {};
|
||||
Result.signif = Significand;
|
||||
Result.signExp = Exponent | (Sign << 15);
|
||||
Result.signExp = Top.Raw;
|
||||
return Result;
|
||||
}
|
||||
|
||||
static bool IsNan(const X80SoftFloat& lhs) {
|
||||
return (lhs.Exponent == 0x7FFF) && (lhs.Significand & IntegerBit) && (lhs.Significand & Bottom62Significand);
|
||||
return (lhs.Top.Exponent == 0x7FFF) && (lhs.Significand & IntegerBit) && (lhs.Significand & Bottom62Significand);
|
||||
}
|
||||
|
||||
static bool SignBit(const X80SoftFloat& lhs) {
|
||||
return lhs.Sign;
|
||||
return lhs.Top.Sign;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -637,11 +639,11 @@ private:
|
||||
// Helper function to check for infinity and set invalid operation flag.
|
||||
// Returns true if infinity is dealt with, false otherwise.
|
||||
FEXCORE_PRESERVE_ALL_ATTR static bool HandleInfinityOp(softfloat_state* state, const X80SoftFloat& arg, X80SoftFloat& result) {
|
||||
if (arg.Exponent == 0x7FFF && arg.Significand == 0x8000000000000000ULL) {
|
||||
if (arg.Top.Exponent == 0x7FFF && arg.Significand == 0x8000000000000000ULL) {
|
||||
state->exceptionFlags |= softfloat_flag_invalid;
|
||||
// Return QNaN.
|
||||
result.Sign = 0;
|
||||
result.Exponent = 0x7FFF;
|
||||
result.Top.Sign = 0;
|
||||
result.Top.Exponent = 0x7FFF;
|
||||
result.Significand = 0xC000000000000000ULL;
|
||||
return true;
|
||||
}
|
||||
@@ -649,9 +651,4 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef _WIN32
|
||||
static_assert(sizeof(X80SoftFloat) == 10, "tword must be 10bytes in size");
|
||||
#else
|
||||
// Padding on this extends to 16-bytes rather than 10-bytes on WIN32.
|
||||
static_assert(sizeof(X80SoftFloat) == 16, "tword must be 16bytes in size");
|
||||
#endif
|
||||
@@ -307,12 +307,10 @@ constexpr char ContainerManager[] = "/run/host/container-manager";
|
||||
fextl::string FindContainer() {
|
||||
// We only support pressure-vessel at the moment
|
||||
if (FHU::Filesystem::Exists(ContainerManager)) {
|
||||
fextl::vector<char> Manager {};
|
||||
fextl::string Manager {};
|
||||
if (FEXCore::FileLoading::LoadFile(Manager, ContainerManager)) {
|
||||
// Trim the whitespace, may contain a newline
|
||||
fextl::string ManagerStr = Manager.data();
|
||||
ManagerStr = FEXCore::StringUtils::Trim(ManagerStr);
|
||||
return ManagerStr;
|
||||
return FEXCore::StringUtils::Trim(Manager);
|
||||
}
|
||||
}
|
||||
return {};
|
||||
@@ -321,12 +319,10 @@ fextl::string FindContainer() {
|
||||
fextl::string FindContainerPrefix() {
|
||||
// We only support pressure-vessel at the moment
|
||||
if (FHU::Filesystem::Exists(ContainerManager)) {
|
||||
fextl::vector<char> Manager {};
|
||||
fextl::string Manager {};
|
||||
if (FEXCore::FileLoading::LoadFile(Manager, ContainerManager)) {
|
||||
// Trim the whitespace, may contain a newline
|
||||
fextl::string ManagerStr = Manager.data();
|
||||
ManagerStr = FEXCore::StringUtils::Trim(ManagerStr);
|
||||
if (strncmp(ManagerStr.data(), "pressure-vessel", Manager.size()) == 0) {
|
||||
if (FEXCore::StringUtils::Trim(Manager) == "pressure-vessel") {
|
||||
// We are running inside of pressure vessel
|
||||
// Our $CMAKE_INSTALL_PREFIX paths are now inside of /run/host/$CMAKE_INSTALL_PREFIX
|
||||
return "/run/host/";
|
||||
|
||||
@@ -109,6 +109,13 @@
|
||||
"Scales the cycle counter on systems that have low frequencies."
|
||||
]
|
||||
},
|
||||
"HideHybrid": {
|
||||
"Type": "bool",
|
||||
"Default": "true",
|
||||
"Desc": [
|
||||
"Hides hybrid CPU core arrangement."
|
||||
]
|
||||
},
|
||||
"CPUFeatureRegisters": {
|
||||
"Type": "str",
|
||||
"Default": "",
|
||||
@@ -127,9 +134,9 @@
|
||||
"\teg: ~/RootFS/Debian_x86_64",
|
||||
"Or this can be a name of a rootfs",
|
||||
"If the named rootfs exists in the FEX data folder then it will use that one",
|
||||
"\teg: $HOME/.fex-emu/RootFS/<RootFS name>/",
|
||||
"Or if you have XDG_DATA_HOME the config will search in that directory",
|
||||
"\teg: $XDG_DATA_HOME/.fex-emu/RootFS/<RootFS name>/"
|
||||
"\teg: $XDG_DATA_HOME/fex-emu/RootFS/<RootFS name>/",
|
||||
"If XDG_DATA_HOME is unset, ~/.local/share will be used in its place.",
|
||||
"\teg: $HOME/.local/share/fex-emu/RootFS/<RootFS name>/"
|
||||
]
|
||||
},
|
||||
"ThunkHostLibs": {
|
||||
@@ -155,9 +162,9 @@
|
||||
"\teg: ~/MyThunkConfig.json",
|
||||
"Or this can be a named of a Thunk config file",
|
||||
"If the named config file exists in the FEX data folder folder the it will use that one",
|
||||
"\teg: $HOME/.fex-emu/ThunkConfigs/<ThunkConfig name>",
|
||||
"Or if you have XDG_DATA_HOME the config will search in that directory",
|
||||
"\teg: $XDG_DATA_HOME/.fex-emu/ThunkConfigs/<ThunkConfig name>"
|
||||
"\teg: $XDG_DATA_HOME/fex-emu/ThunkConfigs/<ThunkConfig name>",
|
||||
"If XDG_DATA_HOME is unset, ~/.local/share will be used in its place.",
|
||||
"\teg: $HOME/.local/share/fex-emu/ThunkConfigs/<ThunkConfig name>"
|
||||
]
|
||||
},
|
||||
"Env": {
|
||||
@@ -334,13 +341,21 @@
|
||||
"STATS": "stats"
|
||||
},
|
||||
"Desc": [
|
||||
"Allows controlling of the vixl disassembler.",
|
||||
"Allows controlling of the vixl disassembler for generated ARM code.",
|
||||
"\toff: No disassembly will be output",
|
||||
"\tdispatcher: Will enable disassembly of the JIT dispatcher loop",
|
||||
"\tblocks: Will enable disassembly of the translated instruction code blocks",
|
||||
"\tstats: Will print stats when disassembling the code"
|
||||
]
|
||||
},
|
||||
"X86Disassemble": {
|
||||
"Type": "bool",
|
||||
"Default": "false",
|
||||
"Desc": [
|
||||
"Enables x86/x86-64 guest disassembly output for compiled blocks.",
|
||||
"Requires FEX to be built with -DENABLE_ZYDIS=TRUE"
|
||||
]
|
||||
},
|
||||
"ForceSVEWidth": {
|
||||
"Type": "uint32",
|
||||
"Default": "0",
|
||||
@@ -379,7 +394,7 @@
|
||||
"Default": "",
|
||||
"Desc": [
|
||||
"Redirects the telemetry folder that FEX usually writes to.",
|
||||
"By default telemetry data is stored in {$FEX_APP_DATA_LOCATION,{$XDG_DATA_HOME,$HOME}/.fex-emu/Telemetry/}"
|
||||
"By default telemetry data is stored in {$FEX_APP_DATA_LOCATION,{$XDG_DATA_HOME,$HOME}/fex-emu/Telemetry/}"
|
||||
]
|
||||
},
|
||||
"ProfileStats": {
|
||||
|
||||
@@ -677,7 +677,7 @@ void Arm64Emitter::FillSpecialRegs(ARMEmitter::Register TmpReg, ARMEmitter::Regi
|
||||
}
|
||||
}
|
||||
|
||||
void Arm64Emitter::SpillStaticRegs(ARMEmitter::Register TmpReg, bool FPRs, uint32_t GPRSpillMask, uint32_t FPRSpillMask) {
|
||||
void Arm64Emitter::SpillStaticRegs(ARMEmitter::Register TmpReg, bool FPRs, uint32_t GPRSpillMask, uint32_t FPRSpillMask, bool NZCV) {
|
||||
#ifndef VIXL_SIMULATOR
|
||||
if (EmitterCTX->HostFeatures.SupportsAFP) {
|
||||
// Disable AFP features when spilling registers.
|
||||
@@ -698,13 +698,15 @@ void Arm64Emitter::SpillStaticRegs(ARMEmitter::Register TmpReg, bool FPRs, uint3
|
||||
}
|
||||
#endif
|
||||
|
||||
// Regardless of what GPRs/FPRs we're spilling, we need to spill NZCV since it
|
||||
// is always static and almost certainly clobbered by the subsequent code.
|
||||
//
|
||||
// TODO: Can we prove that NZCV is not used across a call in some cases and
|
||||
// omit this? Might help x87 perf? Future idea.
|
||||
mrs(TmpReg, ARMEmitter::SystemRegister::NZCV);
|
||||
str(TmpReg.W(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.flags[24]));
|
||||
if (NZCV) {
|
||||
// Regardless of what GPRs/FPRs we're spilling, we need to spill NZCV since it
|
||||
// is always static and almost certainly clobbered by the subsequent code.
|
||||
//
|
||||
// TODO: Can we prove that NZCV is not used across a call in some cases and
|
||||
// omit this? Might help x87 perf? Future idea.
|
||||
mrs(TmpReg, ARMEmitter::SystemRegister::NZCV);
|
||||
str(TmpReg.W(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.flags[24]));
|
||||
}
|
||||
|
||||
// PF/AF are special, remove them from the mask
|
||||
uint32_t PFAFMask = ((1u << REG_PF.Idx()) | ((1u << REG_AF.Idx())));
|
||||
@@ -726,7 +728,7 @@ void Arm64Emitter::SpillStaticRegs(ARMEmitter::Register TmpReg, bool FPRs, uint3
|
||||
}
|
||||
|
||||
// Now handle PF/AF
|
||||
if (PFAFSpillMask) {
|
||||
if (NZCV && PFAFSpillMask) {
|
||||
auto PFOffset = offsetof(FEXCore::Core::CpuStateFrame, State.pf_raw);
|
||||
auto AFOffset = offsetof(FEXCore::Core::CpuStateFrame, State.af_raw);
|
||||
LOGMAN_THROW_A_FMT(PFAFSpillMask == PFAFMask, "PF/AF not spilled together");
|
||||
@@ -776,7 +778,7 @@ void Arm64Emitter::SpillStaticRegs(ARMEmitter::Register TmpReg, bool FPRs, uint3
|
||||
}
|
||||
|
||||
void Arm64Emitter::FillStaticRegs(bool FPRs, uint32_t GPRFillMask, uint32_t FPRFillMask, std::optional<ARMEmitter::Register> OptionalReg,
|
||||
std::optional<ARMEmitter::Register> OptionalReg2) {
|
||||
std::optional<ARMEmitter::Register> OptionalReg2, bool NZCV) {
|
||||
auto FindTempReg = [this](uint32_t* GPRFillMask) -> std::optional<ARMEmitter::Register> {
|
||||
for (auto Reg : StaticRegisters) {
|
||||
if (((1U << Reg.Idx()) & *GPRFillMask)) {
|
||||
@@ -810,13 +812,15 @@ void Arm64Emitter::FillStaticRegs(bool FPRs, uint32_t GPRFillMask, uint32_t FPRF
|
||||
|
||||
ldr(REG_CALLRET_SP, STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.callret_sp));
|
||||
|
||||
// Regardless of what GPRs/FPRs we're filling, we need to fill NZCV since it
|
||||
// is always static and was almost certainly clobbered.
|
||||
//
|
||||
// TODO: Can we prove that NZCV is not used across a call in some cases and
|
||||
// omit this? Might help x87 perf? Future idea.
|
||||
ldr(TmpReg.W(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.flags[24]));
|
||||
msr(ARMEmitter::SystemRegister::NZCV, TmpReg);
|
||||
if (NZCV) {
|
||||
// Regardless of what GPRs/FPRs we're filling, we need to fill NZCV since it
|
||||
// is always static and was almost certainly clobbered.
|
||||
//
|
||||
// TODO: Can we prove that NZCV is not used across a call in some cases and
|
||||
// omit this? Might help x87 perf? Future idea.
|
||||
ldr(TmpReg.W(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.flags[24]));
|
||||
msr(ARMEmitter::SystemRegister::NZCV, TmpReg);
|
||||
}
|
||||
|
||||
FillSpecialRegs(TmpReg, TmpReg2, true, FPRs);
|
||||
|
||||
@@ -877,7 +881,7 @@ void Arm64Emitter::FillStaticRegs(bool FPRs, uint32_t GPRFillMask, uint32_t FPRF
|
||||
}
|
||||
|
||||
// Now handle PF/AF
|
||||
if (PFAFFillMask) {
|
||||
if (NZCV && PFAFFillMask) {
|
||||
LOGMAN_THROW_A_FMT(PFAFFillMask == PFAFMask, "PF/AF not filled together");
|
||||
|
||||
ldp<ARMEmitter::IndexType::OFFSET>(REG_PF.W(), REG_AF.W(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.pf_raw));
|
||||
|
||||
@@ -135,10 +135,10 @@ protected:
|
||||
// Returning REG_INVALID if there was no mapping.
|
||||
FEXCore::X86State::X86Reg GetX86RegRelationToARMReg(ARMEmitter::Register Reg);
|
||||
|
||||
void SpillStaticRegs(ARMEmitter::Register TmpReg, bool FPRs = true, uint32_t GPRSpillMask = ~0U, uint32_t FPRSpillMask = ~0U);
|
||||
void SpillStaticRegs(ARMEmitter::Register TmpReg, bool FPRs = true, uint32_t GPRSpillMask = ~0U, uint32_t FPRSpillMask = ~0U, bool NZCV = true);
|
||||
void FillStaticRegs(bool FPRs = true, uint32_t GPRFillMask = ~0U, uint32_t FPRFillMask = ~0U,
|
||||
std::optional<ARMEmitter::Register> OptionalReg = std::nullopt,
|
||||
std::optional<ARMEmitter::Register> OptionalReg2 = std::nullopt);
|
||||
std::optional<ARMEmitter::Register> OptionalReg2 = std::nullopt, bool NZCV = true);
|
||||
|
||||
// Register 0-18 + 29 + 30 are caller saved
|
||||
static constexpr uint32_t CALLER_GPR_MASK = 0b0110'0000'0000'0111'1111'1111'1111'1111U;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include "FEXCore/Config/Config.h"
|
||||
#include "Interface/Context/Context.h"
|
||||
#include "Interface/Core/CPUBackend.h"
|
||||
#include "Interface/Core/LookupCache.h"
|
||||
@@ -349,7 +350,7 @@ namespace CPU {
|
||||
}
|
||||
|
||||
CodeBuffer::CodeBuffer(size_t Size)
|
||||
: Size(Size) {
|
||||
: AllocatedSize(Size) {
|
||||
Ptr = static_cast<uint8_t*>(FEXCore::Allocator::VirtualAlloc(Size, true));
|
||||
LOGMAN_THROW_A_FMT(!!Ptr, "Couldn't allocate code buffer");
|
||||
|
||||
@@ -366,7 +367,7 @@ namespace CPU {
|
||||
}
|
||||
|
||||
CodeBuffer::~CodeBuffer() {
|
||||
FEXCore::Allocator::VirtualFree(Ptr, Size);
|
||||
FEXCore::Allocator::VirtualFree(Ptr, AllocatedSize);
|
||||
}
|
||||
|
||||
auto CodeBufferManager::AllocateNew(size_t Size) -> fextl::shared_ptr<CodeBuffer> {
|
||||
@@ -407,7 +408,13 @@ namespace CPU {
|
||||
|
||||
fextl::shared_ptr<CodeBuffer> CodeBufferManager::GetLatest() {
|
||||
if (!Latest) {
|
||||
AllocateNew(INITIAL_CODE_SIZE);
|
||||
if (FEXCore::Config::Get_ENABLECODECACHINGWIP()) {
|
||||
// Start with a larger code buffer to avoid resizes that would discard
|
||||
// code loaded from caches
|
||||
AllocateNew(MAX_CODE_SIZE);
|
||||
} else {
|
||||
AllocateNew(INITIAL_CODE_SIZE);
|
||||
}
|
||||
}
|
||||
return Latest;
|
||||
}
|
||||
@@ -418,7 +425,7 @@ namespace CPU {
|
||||
return GetLatest();
|
||||
}
|
||||
|
||||
auto NewCodeBufferSize = GetLatest()->Size;
|
||||
auto NewCodeBufferSize = GetLatest()->AllocatedSize;
|
||||
NewCodeBufferSize = std::min<size_t>(NewCodeBufferSize * 2, MAX_CODE_SIZE);
|
||||
return AllocateNew(NewCodeBufferSize);
|
||||
}
|
||||
@@ -428,7 +435,7 @@ namespace CPU {
|
||||
auto CheckCodeBuffer = [](CodeBuffer& Buffer, uintptr_t Address) {
|
||||
// The last page of the code buffer is protected, so we need to exclude it from the valid range
|
||||
// when checking if the address is in the code buffer.
|
||||
uintptr_t LastPageAddr = AlignDown(reinterpret_cast<uintptr_t>(Buffer.Ptr) + Buffer.Size - 1, FEXCore::Utils::FEX_PAGE_SIZE);
|
||||
uintptr_t LastPageAddr = AlignDown(reinterpret_cast<uintptr_t>(Buffer.Ptr) + Buffer.AllocatedSize - 1, FEXCore::Utils::FEX_PAGE_SIZE);
|
||||
return (Address >= reinterpret_cast<uintptr_t>(Buffer.Ptr) && Address < LastPageAddr);
|
||||
};
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ struct GuestToHostMap;
|
||||
namespace CPU {
|
||||
struct CodeBuffer {
|
||||
uint8_t* Ptr;
|
||||
size_t Size;
|
||||
size_t AllocatedSize; // including guard page; see UsableSize()
|
||||
|
||||
fextl::unique_ptr<GuestToHostMap> LookupCache;
|
||||
|
||||
@@ -54,6 +54,11 @@ namespace CPU {
|
||||
CodeBuffer& operator=(CodeBuffer&&) = delete;
|
||||
|
||||
~CodeBuffer();
|
||||
|
||||
/// Returns the number of bytes available for storing code
|
||||
size_t UsableSize() const {
|
||||
return AllocatedSize - FEXCore::Utils::FEX_PAGE_SIZE;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace ProductNames {
|
||||
static const char ARM_Ampere_1[] = "AmpereOne";
|
||||
static const char ARM_Ampere_1A[] = "AmpereOneA";
|
||||
static const char ARM_Ampere_1B[] = "AmpereOneB";
|
||||
#else
|
||||
static const char ARM_Ampere_1C[] = "AmpereOneC";
|
||||
#endif
|
||||
} // namespace ProductNames
|
||||
|
||||
@@ -154,6 +154,7 @@ uint32_t GetCPUID_TPIDRRO() {
|
||||
}
|
||||
|
||||
void CPUIDEmu::SetupHostHybridFlag() {
|
||||
FEX_CONFIG_OPT(HideHybrid, HIDEHYBRID);
|
||||
PerCPUData.resize(Cores);
|
||||
|
||||
uint64_t MIDR {};
|
||||
@@ -170,6 +171,11 @@ void CPUIDEmu::SetupHostHybridFlag() {
|
||||
MIDR = NewMIDR;
|
||||
}
|
||||
|
||||
if (HideHybrid()) {
|
||||
// Hide the hybrid flag.
|
||||
Hybrid = false;
|
||||
}
|
||||
|
||||
struct CPUMIDR {
|
||||
uint8_t Implementer;
|
||||
uint16_t Part;
|
||||
@@ -180,7 +186,7 @@ void CPUIDEmu::SetupHostHybridFlag() {
|
||||
// CPU priority order
|
||||
// This is mostly arbitrary but will sort by some sort of CPU priority by performance
|
||||
// Relative list so things they will commonly end up in big.little configurations sort of relate
|
||||
static constexpr std::array<CPUMIDR, 66> CPUMIDRs = {{
|
||||
static constexpr std::array<CPUMIDR, 67> CPUMIDRs = {{
|
||||
// Typically big CPU cores
|
||||
{0x51, 0x001, 1, ProductNames::ARM_ORYON_1}, // Qualcomm Oryon-1
|
||||
|
||||
@@ -229,6 +235,7 @@ void CPUIDEmu::SetupHostHybridFlag() {
|
||||
{0xc0, 0xac3, 1, ProductNames::ARM_Ampere_1}, // AmpereOne
|
||||
{0xc0, 0xac4, 1, ProductNames::ARM_Ampere_1A}, // AmpereOneA
|
||||
{0xc0, 0xac5, 1, ProductNames::ARM_Ampere_1B}, // AmpereOneB
|
||||
{0xc0, 0xac7, 1, ProductNames::ARM_Ampere_1C}, // AmpereOneC
|
||||
|
||||
{0x4e, 0x010, 1, ProductNames::ARM_Olympus}, // Olympus
|
||||
{0x4e, 0x004, 1, ProductNames::ARM_Carmel}, // Carmel
|
||||
@@ -386,7 +393,8 @@ void CPUIDEmu::SetupHostHybridFlag() {
|
||||
} else {
|
||||
// If we aren't hybrid then just claim everything is big
|
||||
for (size_t i = 0; i < Cores; ++i) {
|
||||
uint32_t MIDR = PerCPUData[i].MIDR;
|
||||
const auto MIDRIndex = HideHybrid() ? 0 : i;
|
||||
uint32_t MIDR = PerCPUData[MIDRIndex].MIDR;
|
||||
auto MIDROption = FindDefinedMIDR(MIDR);
|
||||
|
||||
PerCPUData[i].IsBig = true;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <Interface/IR/PassManager.h>
|
||||
|
||||
#include <FEXCore/Core/Thunks.h>
|
||||
#include <FEXCore/HLE/SourcecodeResolver.h>
|
||||
#include <FEXCore/HLE/SyscallHandler.h>
|
||||
|
||||
#include <FEXHeaderUtils/Filesystem.h>
|
||||
@@ -29,6 +30,7 @@ ExecutableFileInfo::ExecutableFileInfo(fextl::unique_ptr<HLE::SourcecodeMap> Map
|
||||
, FileId(FileId)
|
||||
, Filename(Filename) {}
|
||||
#endif
|
||||
ExecutableFileInfo::~ExecutableFileInfo() = default;
|
||||
|
||||
fextl::string CodeMap::GetBaseFilename(const ExecutableFileInfo& MainExecutable, bool AddNombSuffix) {
|
||||
auto FileId = MainExecutable.FileId;
|
||||
@@ -232,11 +234,12 @@ uint64_t CodeCache::ComputeCodeMapId(std::string_view Filename, int FD) {
|
||||
struct CodeCacheHeader {
|
||||
std::array<char, 4> Magic = ExpectedMagic;
|
||||
uint32_t FormatVersion = 1;
|
||||
char FEXVersion[8] = {};
|
||||
uint8_t FEXVersion[20] = {};
|
||||
uint32_t NumBlocks;
|
||||
uint32_t NumCodePages;
|
||||
uint32_t CodeBufferSize;
|
||||
uint32_t NumRelocations;
|
||||
uint32_t padding;
|
||||
uint64_t SerializedBaseAddress;
|
||||
// TODO: Consider including information from LookupCache.BlockLinks
|
||||
|
||||
@@ -253,9 +256,8 @@ bool CodeCache::SaveData(Core::InternalThreadState& Thread, int fd, const Execut
|
||||
|
||||
// Write file header
|
||||
CodeCacheHeader header {};
|
||||
constexpr std::string_view git_hash = GIT_SHORT_HASH;
|
||||
static_assert(git_hash.size() <= sizeof(header.FEXVersion));
|
||||
std::ranges::copy(git_hash, header.FEXVersion);
|
||||
static_assert(GIT_HASH.size() == sizeof(header.FEXVersion));
|
||||
std::ranges::copy(GIT_HASH, header.FEXVersion);
|
||||
header.NumBlocks = LookupCache.BlockList.size();
|
||||
header.NumCodePages = LookupCache.CodePages.size();
|
||||
header.CodeBufferSize = CTX.LatestOffset;
|
||||
@@ -307,7 +309,7 @@ bool CodeCache::SaveData(Core::InternalThreadState& Thread, int fd, const Execut
|
||||
}
|
||||
|
||||
// Dump the host code (relocated for position-independent serialization)
|
||||
std::vector CodeBufferData(reinterpret_cast<std::byte*>(CodeBuffer->Ptr), reinterpret_cast<std::byte*>(CodeBuffer->Ptr) + CTX.LatestOffset);
|
||||
std::span CodeBufferData(reinterpret_cast<std::byte*>(CodeBuffer->Ptr), reinterpret_cast<std::byte*>(CodeBuffer->Ptr) + CTX.LatestOffset);
|
||||
if (!ApplyCodeRelocations(SerializedBaseAddress, CodeBufferData, Relocations, true)) {
|
||||
LOGMAN_THROW_A_FMT(false, "Failed to apply code relocations");
|
||||
return false;
|
||||
@@ -351,11 +353,9 @@ bool CodeCache::LoadData(Core::InternalThreadState* Thread, std::byte* MappedCac
|
||||
return false;
|
||||
}
|
||||
|
||||
char ExpectedVersion[8] = GIT_SHORT_HASH;
|
||||
ranges::fill(ranges::find(ExpectedVersion, 0), std::end(ExpectedVersion), 0);
|
||||
if (!ranges::equal(header.FEXVersion, ExpectedVersion)) {
|
||||
LogMan::Msg::IFmt("Cache generated from old FEX version {}, current is {}; skipping", fmt::join(header.FEXVersion, ""),
|
||||
fmt::join(ExpectedVersion, ""));
|
||||
if (!ranges::equal(header.FEXVersion, GIT_HASH)) {
|
||||
LogMan::Msg::IFmt("Cache generated from old FEX version {:02x}, current is {:02x}; skipping", fmt::join(header.FEXVersion, ""),
|
||||
fmt::join(GIT_HASH, ""));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -427,16 +427,15 @@ bool CodeCache::LoadData(Core::InternalThreadState* Thread, std::byte* MappedCac
|
||||
}
|
||||
|
||||
auto CodeBuffer = CTX.GetLatest();
|
||||
LOGMAN_THROW_A_FMT(header.CodeBufferSize <= CodeBuffer->Size, "CodeBuffer too small to load code cache");
|
||||
LOGMAN_THROW_A_FMT(reinterpret_cast<uintptr_t>(CodeBuffer->Ptr) % 0x1000 == 0, "Expected CodeBuffer base to be page-aligned");
|
||||
const auto Delta = AlignUp(CTX.LatestOffset, 0x1000) - CTX.LatestOffset;
|
||||
CTX.LatestOffset += Delta;
|
||||
|
||||
while (CTX.LatestOffset + header.CodeBufferSize > CodeBuffer->Size - Utils::FEX_PAGE_SIZE) {
|
||||
while (CTX.LatestOffset + header.CodeBufferSize > CodeBuffer->UsableSize()) {
|
||||
if (Thread) {
|
||||
CTX.ClearCodeCache(Thread);
|
||||
CodeBuffer = CTX.GetLatest();
|
||||
LogMan::Msg::IFmt("Increased code buffer size to {} MiB for cache load", CodeBuffer->Size / 1024 / 1024);
|
||||
LogMan::Msg::IFmt("Increased code buffer size to {} MiB for cache load", CodeBuffer->AllocatedSize / 1024 / 1024);
|
||||
} else {
|
||||
ERROR_AND_DIE_FMT("Cannot extend codebuffer without thread!");
|
||||
}
|
||||
@@ -444,7 +443,8 @@ bool CodeCache::LoadData(Core::InternalThreadState* Thread, std::byte* MappedCac
|
||||
|
||||
// Read CodeBuffer data from file. Make sure the destination is page-aligned.
|
||||
// TODO: Only load the data needed for the selected section
|
||||
auto CodeBufferRange = std::as_writable_bytes(std::span {CodeBuffer->Ptr, CodeBuffer->Size}).subspan(CTX.LatestOffset, header.CodeBufferSize);
|
||||
auto CodeBufferRange =
|
||||
std::as_writable_bytes(std::span {CodeBuffer->Ptr, CodeBuffer->UsableSize()}).subspan(CTX.LatestOffset, header.CodeBufferSize);
|
||||
::memcpy(CodeBufferRange.data(), MappedCacheFile, header.CodeBufferSize);
|
||||
MappedCacheFile += header.CodeBufferSize;
|
||||
CTX.LatestOffset += header.CodeBufferSize;
|
||||
@@ -537,9 +537,14 @@ void CodeCache::Validate(const ExecutableFileSectionInfo& Section, fextl::set<ui
|
||||
}
|
||||
|
||||
auto NewCodeBuffer = ValidationCTX->GetLatest();
|
||||
while (CachedCode.size_bytes() > NewCodeBuffer->UsableSize()) {
|
||||
ValidationCTX->ClearCodeCache(ValidationThread.get());
|
||||
NewCodeBuffer = ValidationCTX->GetLatest();
|
||||
LogMan::Msg::IFmt("Increased cache validation code buffer size to {} MiB", NewCodeBuffer->AllocatedSize / 1024 / 1024);
|
||||
}
|
||||
|
||||
std::span<std::byte> CodeBufferRangeRef =
|
||||
std::as_writable_bytes(std::span {NewCodeBuffer->Ptr, NewCodeBuffer->Ptr + NewCodeBuffer->Size}).subspan(0, CachedCode.size_bytes());
|
||||
std::as_writable_bytes(std::span {NewCodeBuffer->Ptr, NewCodeBuffer->Ptr + NewCodeBuffer->UsableSize()}).subspan(0, CachedCode.size_bytes());
|
||||
|
||||
while (!GuestBlocks.empty()) {
|
||||
auto [CompiledBlocks, _, _2, _3, _4] = ValidationCTX->CompileCode(ValidationThread.get(), *GuestBlocks.begin(), 0 /* TODO: Set MaxInst? */);
|
||||
@@ -633,9 +638,10 @@ bool CodeCache::ApplyCodeRelocations(uint64_t GuestEntry, std::span<std::byte> C
|
||||
if (Pointer == ~0ULL) {
|
||||
return false;
|
||||
}
|
||||
// Pointers are required to fit within 48-bit VA space.
|
||||
// TODO: Pointers are required to fit within 48-bit VA space.
|
||||
// But forcing 6-byte broke relocations.
|
||||
Emitter.LoadConstant(ARMEmitter::Size::i64Bit, ARMEmitter::Register(Reloc.NamedThunkMove.RegisterIndex), Pointer,
|
||||
CPU::Arm64Emitter::PadType::DOPAD, 6);
|
||||
CPU::Arm64Emitter::PadType::DOPAD);
|
||||
break;
|
||||
}
|
||||
case FEXCore::CPU::RelocationTypes::RELOC_GUEST_RIP_LITERAL: {
|
||||
@@ -644,9 +650,9 @@ bool CodeCache::ApplyCodeRelocations(uint64_t GuestEntry, std::span<std::byte> C
|
||||
}
|
||||
case FEXCore::CPU::RelocationTypes::RELOC_GUEST_RIP_MOVE: {
|
||||
uint64_t Pointer = Reloc.GuestRIP.GuestRIP + GuestEntry;
|
||||
// Pointers are required to fit within 48-bit VA space.
|
||||
Emitter.LoadConstant(ARMEmitter::Size::i64Bit, ARMEmitter::Register(Reloc.GuestRIP.RegisterIndex), Pointer,
|
||||
CPU::Arm64Emitter::PadType::DOPAD, 6);
|
||||
// TODO: Pointers are required to fit within 48-bit VA space.
|
||||
// But forcing 6-byte broke relocations.
|
||||
Emitter.LoadConstant(ARMEmitter::Size::i64Bit, ARMEmitter::Register(Reloc.GuestRIP.RegisterIndex), Pointer, CPU::Arm64Emitter::PadType::DOPAD);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,9 @@ $end_info$
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#ifdef ZYDIS_DISASSEMBLER
|
||||
#include <Zydis/Zydis.h>
|
||||
#endif
|
||||
#include "Interface/Core/ArchHelpers/Arm64Emitter.h"
|
||||
#include "Interface/Core/LookupCache.h"
|
||||
#include "Interface/Core/CPUBackend.h"
|
||||
@@ -468,7 +471,7 @@ void ContextImpl::LockBeforeFork(FEXCore::Core::InternalThreadState* Thread) {
|
||||
|
||||
void ContextImpl::OnCodeBufferAllocated(const fextl::shared_ptr<CPU::CodeBuffer>& Buffer) {
|
||||
if (Config.GlobalJITNaming()) {
|
||||
Symbols.RegisterJITSpace(Buffer->Ptr, Buffer->Size);
|
||||
Symbols.RegisterJITSpace(Buffer->Ptr, Buffer->AllocatedSize);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -539,9 +542,24 @@ ContextImpl::GenerateIR(FEXCore::Core::InternalThreadState* Thread, uint64_t Gue
|
||||
|
||||
const auto GPRSize = Thread->OpDispatcher->GetGPROpSize();
|
||||
|
||||
#ifdef ZYDIS_DISASSEMBLER
|
||||
const auto ZydisMachineMode = Config.Is64BitMode ? ZYDIS_MACHINE_MODE_LONG_64 : ZYDIS_MACHINE_MODE_LEGACY_32;
|
||||
if (FEXCore::Config::Get_X86DISASSEMBLE()) {
|
||||
const uint64_t DecodedMin = Thread->FrontendDecoder->DecodedMinAddress;
|
||||
const uint64_t DecodedMax = Thread->FrontendDecoder->DecodedMaxAddress;
|
||||
LogMan::Msg::IFmt("Guest x86 Begin (RIP={:#x}, {:#x}-{:#x})", GuestRIP, DecodedMin, DecodedMax);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (size_t j = 0; j < CodeBlocks->size(); ++j) {
|
||||
const FEXCore::Frontend::Decoder::DecodedBlocks& Block = CodeBlocks->at(j);
|
||||
|
||||
#ifdef ZYDIS_DISASSEMBLER
|
||||
if (FEXCore::Config::Get_X86DISASSEMBLE() && CodeBlocks->size() > 1) {
|
||||
LogMan::Msg::IFmt(" Block {} Entry={:#x} NumInsts={}", j, Block.Entry, Block.NumInstructions);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool BlockInForceTSOValidRange = false;
|
||||
auto InstForceTSOIt = ForceTSOInstructions.end();
|
||||
if (ForceTSOValidRanges.Contains({Block.Entry, Block.Entry + Block.Size})) {
|
||||
@@ -573,6 +591,19 @@ ContextImpl::GenerateIR(FEXCore::Core::InternalThreadState* Thread, uint64_t Gue
|
||||
|
||||
TableInfo = Block.DecodedInstructions[i].TableInfo;
|
||||
DecodedInfo = &Block.DecodedInstructions[i];
|
||||
|
||||
#ifdef ZYDIS_DISASSEMBLER
|
||||
if (FEXCore::Config::Get_X86DISASSEMBLE()) {
|
||||
const uint8_t* InstBytes = reinterpret_cast<const uint8_t*>(InstAddress);
|
||||
ZydisDisassembledInstruction ZydisInst;
|
||||
if (ZYAN_SUCCESS(ZydisDisassembleIntel(ZydisMachineMode, InstAddress, InstBytes, DecodedInfo->InstSize, &ZydisInst))) {
|
||||
LogMan::Msg::IFmt(" {:#x}: {}", InstAddress, ZydisInst.text);
|
||||
} else {
|
||||
LogMan::Msg::IFmt(" {:#x}: (decode failed, {} bytes)", InstAddress, DecodedInfo->InstSize);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool IsLocked = DecodedInfo->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_LOCK;
|
||||
|
||||
// Do a partial register cache flush before every instruction. This
|
||||
@@ -693,6 +724,12 @@ ContextImpl::GenerateIR(FEXCore::Core::InternalThreadState* Thread, uint64_t Gue
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ZYDIS_DISASSEMBLER
|
||||
if (FEXCore::Config::Get_X86DISASSEMBLE()) {
|
||||
LogMan::Msg::IFmt("Guest x86 End");
|
||||
}
|
||||
#endif
|
||||
|
||||
Thread->OpDispatcher->Finalize();
|
||||
|
||||
Thread->FrontendDecoder->DelayedDisownBuffer();
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
|
||||
#include <array>
|
||||
#include <bit>
|
||||
#include <csignal>
|
||||
#include <cstring>
|
||||
|
||||
namespace FEXCore::CPU {
|
||||
@@ -626,6 +625,226 @@ void Dispatcher::ExecuteJITCallback(FEXCore::Core::CpuStateFrame* Frame, uint64_
|
||||
|
||||
#endif
|
||||
|
||||
void Dispatcher::EmitI32ToExtF80() {
|
||||
ARMEmitter::ForwardLabel ZeroCase;
|
||||
ARMEmitter::ForwardLabel Done;
|
||||
|
||||
(void)cbz(ARMEmitter::Size::i32Bit, TMP2, &ZeroCase);
|
||||
|
||||
lsr(ARMEmitter::Size::i32Bit, TMP4, TMP2, 31);
|
||||
tst(ARMEmitter::Size::i32Bit, TMP2, TMP2);
|
||||
neg(ARMEmitter::Size::i32Bit, TMP3, TMP2);
|
||||
csel(ARMEmitter::Size::i32Bit, TMP3, TMP3, TMP2, ARMEmitter::Condition::CC_MI);
|
||||
|
||||
clz(ARMEmitter::Size::i32Bit, TMP1, TMP3);
|
||||
|
||||
mov(ARMEmitter::Size::i32Bit, TMP2, 0x401E);
|
||||
sub(ARMEmitter::Size::i32Bit, TMP2, TMP2, TMP1);
|
||||
orr(ARMEmitter::Size::i32Bit, TMP2, TMP2, TMP4, ARMEmitter::ShiftType::LSL, 15);
|
||||
|
||||
lslv(ARMEmitter::Size::i32Bit, TMP3, TMP3, TMP1);
|
||||
|
||||
lsl(ARMEmitter::Size::i64Bit, TMP3, TMP3, 32);
|
||||
|
||||
fmov(ARMEmitter::Size::i64Bit, VTMP1.D(), TMP3);
|
||||
ins(ARMEmitter::SubRegSize::i16Bit, VTMP1, 4, TMP2);
|
||||
|
||||
(void)b(&Done);
|
||||
|
||||
(void)Bind(&ZeroCase);
|
||||
movi(ARMEmitter::SubRegSize::i64Bit, VTMP1.Q(), 0);
|
||||
|
||||
(void)Bind(&Done);
|
||||
}
|
||||
|
||||
void Dispatcher::EmitI16ToExtF80() {
|
||||
sxth(ARMEmitter::Size::i32Bit, TMP2, TMP2);
|
||||
|
||||
ARMEmitter::ForwardLabel ZeroCase;
|
||||
ARMEmitter::ForwardLabel Done;
|
||||
|
||||
(void)cbz(ARMEmitter::Size::i32Bit, TMP2, &ZeroCase);
|
||||
|
||||
lsr(ARMEmitter::Size::i32Bit, TMP4, TMP2, 31);
|
||||
tst(ARMEmitter::Size::i32Bit, TMP2, TMP2);
|
||||
neg(ARMEmitter::Size::i32Bit, TMP3, TMP2);
|
||||
csel(ARMEmitter::Size::i32Bit, TMP3, TMP3, TMP2, ARMEmitter::Condition::CC_MI);
|
||||
|
||||
clz(ARMEmitter::Size::i32Bit, TMP1, TMP3);
|
||||
|
||||
mov(ARMEmitter::Size::i32Bit, TMP2, 0x401E);
|
||||
sub(ARMEmitter::Size::i32Bit, TMP2, TMP2, TMP1);
|
||||
orr(ARMEmitter::Size::i32Bit, TMP2, TMP2, TMP4, ARMEmitter::ShiftType::LSL, 15);
|
||||
|
||||
lslv(ARMEmitter::Size::i32Bit, TMP3, TMP3, TMP1);
|
||||
|
||||
lsl(ARMEmitter::Size::i64Bit, TMP3, TMP3, 32);
|
||||
|
||||
fmov(ARMEmitter::Size::i64Bit, VTMP1.D(), TMP3);
|
||||
ins(ARMEmitter::SubRegSize::i16Bit, VTMP1, 4, TMP2);
|
||||
|
||||
(void)b(&Done);
|
||||
|
||||
(void)Bind(&ZeroCase);
|
||||
movi(ARMEmitter::SubRegSize::i64Bit, VTMP1.Q(), 0);
|
||||
|
||||
(void)Bind(&Done);
|
||||
}
|
||||
|
||||
void Dispatcher::EmitF32ToExtF80() {
|
||||
ARMEmitter::ForwardLabel InfNaN;
|
||||
ARMEmitter::ForwardLabel ZeroDenormal;
|
||||
ARMEmitter::ForwardLabel Denormal;
|
||||
ARMEmitter::ForwardLabel NaN;
|
||||
ARMEmitter::ForwardLabel Done;
|
||||
ARMEmitter::BiDirectionalLabel NormalPath;
|
||||
ARMEmitter::ForwardLabel ZeroResult;
|
||||
|
||||
fmov(ARMEmitter::Size::i32Bit, TMP1, VTMP1.S());
|
||||
|
||||
ubfx(ARMEmitter::Size::i32Bit, TMP2, TMP1, 23, 8);
|
||||
and_(ARMEmitter::Size::i32Bit, TMP3, TMP1, 0x007FFFFF);
|
||||
lsr(ARMEmitter::Size::i32Bit, TMP4, TMP1, 31);
|
||||
|
||||
cmp(ARMEmitter::Size::i32Bit, TMP2, 0xFF);
|
||||
(void)b(ARMEmitter::Condition::CC_EQ, &InfNaN);
|
||||
|
||||
(void)cbz(ARMEmitter::Size::i32Bit, TMP2, &ZeroDenormal);
|
||||
|
||||
(void)Bind(&NormalPath);
|
||||
// Exponent bias adjustment, where bias is 0x3F80
|
||||
LoadConstant(ARMEmitter::Size::i32Bit, TMP1, 0x3F80);
|
||||
add(ARMEmitter::Size::i32Bit, TMP2, TMP2, TMP1);
|
||||
orr(ARMEmitter::Size::i32Bit, TMP2, TMP2, TMP4, ARMEmitter::ShiftType::LSL, 15);
|
||||
|
||||
// Set implicit bit and shift fraction to extF80 position
|
||||
LoadConstant(ARMEmitter::Size::i64Bit, TMP1, 0x00800000ULL);
|
||||
orr(ARMEmitter::Size::i64Bit, TMP3, TMP3, TMP1);
|
||||
lsl(ARMEmitter::Size::i64Bit, TMP3, TMP3, 40);
|
||||
|
||||
fmov(ARMEmitter::Size::i64Bit, VTMP1.D(), TMP3);
|
||||
ins(ARMEmitter::SubRegSize::i16Bit, VTMP1, 4, TMP2);
|
||||
(void)b(&Done);
|
||||
|
||||
(void)Bind(&ZeroDenormal);
|
||||
(void)cbz(ARMEmitter::Size::i32Bit, TMP3, &ZeroResult);
|
||||
|
||||
(void)Bind(&Denormal);
|
||||
clz(ARMEmitter::Size::i32Bit, TMP1, TMP3);
|
||||
sub(ARMEmitter::Size::i32Bit, TMP1, TMP1, 8);
|
||||
mov(ARMEmitter::Size::i32Bit, TMP2, 1);
|
||||
sub(ARMEmitter::Size::i32Bit, TMP2, TMP2, TMP1);
|
||||
lslv(ARMEmitter::Size::i32Bit, TMP3, TMP3, TMP1);
|
||||
(void)b(&NormalPath);
|
||||
|
||||
(void)Bind(&ZeroResult);
|
||||
lsl(ARMEmitter::Size::i32Bit, TMP2, TMP4, 15);
|
||||
movi(ARMEmitter::SubRegSize::i64Bit, VTMP1.Q(), 0);
|
||||
ins(ARMEmitter::SubRegSize::i16Bit, VTMP1, 4, TMP2);
|
||||
(void)b(&Done);
|
||||
|
||||
(void)Bind(&InfNaN);
|
||||
(void)cbnz(ARMEmitter::Size::i32Bit, TMP3, &NaN);
|
||||
|
||||
lsl(ARMEmitter::Size::i32Bit, TMP2, TMP4, 15);
|
||||
orr(ARMEmitter::Size::i32Bit, TMP2, TMP2, 0x7FFF);
|
||||
|
||||
LoadConstant(ARMEmitter::Size::i64Bit, TMP3, 0x8000000000000000ULL);
|
||||
fmov(ARMEmitter::Size::i64Bit, VTMP1.D(), TMP3);
|
||||
ins(ARMEmitter::SubRegSize::i16Bit, VTMP1, 4, TMP2);
|
||||
(void)b(&Done);
|
||||
|
||||
(void)Bind(&NaN);
|
||||
lsl(ARMEmitter::Size::i32Bit, TMP2, TMP4, 15);
|
||||
orr(ARMEmitter::Size::i32Bit, TMP2, TMP2, 0x7FFF);
|
||||
|
||||
lsl(ARMEmitter::Size::i64Bit, TMP3, TMP3, 40);
|
||||
LoadConstant(ARMEmitter::Size::i64Bit, TMP1, 0xC000000000000000ULL);
|
||||
orr(ARMEmitter::Size::i64Bit, TMP3, TMP3, TMP1);
|
||||
|
||||
fmov(ARMEmitter::Size::i64Bit, VTMP1.D(), TMP3);
|
||||
ins(ARMEmitter::SubRegSize::i16Bit, VTMP1, 4, TMP2);
|
||||
|
||||
(void)Bind(&Done);
|
||||
}
|
||||
|
||||
void Dispatcher::EmitF64ToExtF80() {
|
||||
ARMEmitter::ForwardLabel InfNaN;
|
||||
ARMEmitter::ForwardLabel ZeroDenormal;
|
||||
ARMEmitter::ForwardLabel Denormal;
|
||||
ARMEmitter::ForwardLabel NaN;
|
||||
ARMEmitter::ForwardLabel Done;
|
||||
ARMEmitter::BiDirectionalLabel NormalPath;
|
||||
ARMEmitter::ForwardLabel ZeroResult;
|
||||
|
||||
fmov(ARMEmitter::Size::i64Bit, TMP1, VTMP1.D());
|
||||
|
||||
lsr(ARMEmitter::Size::i64Bit, TMP4, TMP1, 63);
|
||||
ubfx(ARMEmitter::Size::i64Bit, TMP2, TMP1, 52, 11);
|
||||
LoadConstant(ARMEmitter::Size::i64Bit, TMP3, 0x000FFFFFFFFFFFFFULL);
|
||||
and_(ARMEmitter::Size::i64Bit, TMP3, TMP1, TMP3);
|
||||
|
||||
cmp(ARMEmitter::Size::i64Bit, TMP2, 0x7FF);
|
||||
(void)b(ARMEmitter::Condition::CC_EQ, &InfNaN);
|
||||
|
||||
(void)cbz(ARMEmitter::Size::i64Bit, TMP2, &ZeroDenormal);
|
||||
|
||||
(void)Bind(&NormalPath);
|
||||
// Exponent bias adjustment where bias difference is 0x3C00
|
||||
add(ARMEmitter::Size::i64Bit, TMP2, TMP2, 0x3000);
|
||||
add(ARMEmitter::Size::i64Bit, TMP2, TMP2, 0xC00);
|
||||
orr(ARMEmitter::Size::i64Bit, TMP2, TMP2, TMP4, ARMEmitter::ShiftType::LSL, 15);
|
||||
|
||||
LoadConstant(ARMEmitter::Size::i64Bit, TMP1, 0x0010000000000000ULL);
|
||||
orr(ARMEmitter::Size::i64Bit, TMP3, TMP3, TMP1);
|
||||
lsl(ARMEmitter::Size::i64Bit, TMP3, TMP3, 11);
|
||||
|
||||
fmov(ARMEmitter::Size::i64Bit, VTMP1.D(), TMP3);
|
||||
ins(ARMEmitter::SubRegSize::i16Bit, VTMP1, 4, TMP2);
|
||||
(void)b(&Done);
|
||||
|
||||
(void)Bind(&ZeroDenormal);
|
||||
(void)cbz(ARMEmitter::Size::i64Bit, TMP3, &ZeroResult);
|
||||
|
||||
(void)Bind(&Denormal);
|
||||
clz(ARMEmitter::Size::i64Bit, TMP1, TMP3);
|
||||
sub(ARMEmitter::Size::i64Bit, TMP1, TMP1, 11);
|
||||
mov(ARMEmitter::Size::i64Bit, TMP2, 1);
|
||||
sub(ARMEmitter::Size::i64Bit, TMP2, TMP2, TMP1);
|
||||
lslv(ARMEmitter::Size::i64Bit, TMP3, TMP3, TMP1);
|
||||
(void)b(&NormalPath);
|
||||
|
||||
(void)Bind(&ZeroResult);
|
||||
lsl(ARMEmitter::Size::i64Bit, TMP2, TMP4, 15);
|
||||
movi(ARMEmitter::SubRegSize::i64Bit, VTMP1.Q(), 0);
|
||||
ins(ARMEmitter::SubRegSize::i16Bit, VTMP1, 4, TMP2);
|
||||
(void)b(&Done);
|
||||
|
||||
(void)Bind(&InfNaN);
|
||||
(void)cbnz(ARMEmitter::Size::i64Bit, TMP3, &NaN);
|
||||
|
||||
lsl(ARMEmitter::Size::i64Bit, TMP2, TMP4, 15);
|
||||
orr(ARMEmitter::Size::i64Bit, TMP2, TMP2, 0x7FFF);
|
||||
|
||||
LoadConstant(ARMEmitter::Size::i64Bit, TMP3, 0x8000000000000000ULL);
|
||||
fmov(ARMEmitter::Size::i64Bit, VTMP1.D(), TMP3);
|
||||
ins(ARMEmitter::SubRegSize::i16Bit, VTMP1, 4, TMP2);
|
||||
(void)b(&Done);
|
||||
|
||||
(void)Bind(&NaN);
|
||||
lsl(ARMEmitter::Size::i64Bit, TMP2, TMP4, 15);
|
||||
orr(ARMEmitter::Size::i64Bit, TMP2, TMP2, 0x7FFF);
|
||||
|
||||
lsl(ARMEmitter::Size::i64Bit, TMP3, TMP3, 11);
|
||||
LoadConstant(ARMEmitter::Size::i64Bit, TMP1, 0xC000000000000000ULL);
|
||||
orr(ARMEmitter::Size::i64Bit, TMP3, TMP3, TMP1);
|
||||
|
||||
fmov(ARMEmitter::Size::i64Bit, VTMP1.D(), TMP3);
|
||||
ins(ARMEmitter::SubRegSize::i16Bit, VTMP1, 4, TMP2);
|
||||
|
||||
(void)Bind(&Done);
|
||||
}
|
||||
|
||||
uint64_t Dispatcher::GenerateABICall(FallbackABI ABI) {
|
||||
auto Address = GetCursorAddress<uint64_t>();
|
||||
constexpr static auto FallbackPointerReg = TMP4;
|
||||
@@ -696,65 +915,33 @@ uint64_t Dispatcher::GenerateABICall(FallbackABI ABI) {
|
||||
|
||||
switch (ABI) {
|
||||
case FABI_F80_I16_F32_PTR: {
|
||||
// Linux Reg/Win32 Reg:
|
||||
// tmp4 (x4/x13): FallbackHandler
|
||||
// x30: return
|
||||
// vtmp1 (v0/v16): source
|
||||
SpillForABICall(CTX->HostFeatures.SupportsPreserveAllABI, TMP3, true);
|
||||
|
||||
if (!TMP_ABIARGS) {
|
||||
fmov(VABI1.S(), VTMP1.S());
|
||||
}
|
||||
ldrh(ARMEmitter::WReg::w0, STATE, offsetof(FEXCore::Core::CPUState, FCW));
|
||||
mov(ARMEmitter::XReg::x1, STATE);
|
||||
if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] {
|
||||
GenerateIndirectRuntimeCall<FEXCore::VectorRegType, uint16_t, float, uint64_t>(FallbackPointerReg);
|
||||
} else {
|
||||
blr(FallbackPointerReg);
|
||||
}
|
||||
|
||||
FillF80Result();
|
||||
// Save NZCV - it's a static register (guest x86 flags) and the inline code clobbers it
|
||||
mrs(TMP1, ARMEmitter::SystemRegister::NZCV);
|
||||
str(TMP1.W(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.flags[24]));
|
||||
EmitF32ToExtF80();
|
||||
ldr(TMP1.W(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.flags[24]));
|
||||
msr(ARMEmitter::SystemRegister::NZCV, TMP1);
|
||||
} break;
|
||||
case FABI_F80_I16_F64_PTR: {
|
||||
// Linux Reg/Win32 Reg:
|
||||
// tmp4 (x4/x13): FallbackHandler
|
||||
// x30: return
|
||||
// vtmp1 (v0/v16): source
|
||||
SpillForABICall(CTX->HostFeatures.SupportsPreserveAllABI, TMP3, true);
|
||||
|
||||
if (!TMP_ABIARGS) {
|
||||
fmov(VABI1.D(), VTMP1.D());
|
||||
}
|
||||
ldrh(ARMEmitter::WReg::w0, STATE, offsetof(FEXCore::Core::CPUState, FCW));
|
||||
mov(ARMEmitter::XReg::x1, STATE);
|
||||
if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] {
|
||||
GenerateIndirectRuntimeCall<FEXCore::VectorRegType, uint16_t, double, uint64_t>(FallbackPointerReg);
|
||||
} else {
|
||||
blr(FallbackPointerReg);
|
||||
}
|
||||
|
||||
FillF80Result();
|
||||
mrs(TMP1, ARMEmitter::SystemRegister::NZCV);
|
||||
str(TMP1.W(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.flags[24]));
|
||||
EmitF64ToExtF80();
|
||||
ldr(TMP1.W(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.flags[24]));
|
||||
msr(ARMEmitter::SystemRegister::NZCV, TMP1);
|
||||
} break;
|
||||
case FABI_F80_I16_I16_PTR: {
|
||||
mrs(TMP1, ARMEmitter::SystemRegister::NZCV);
|
||||
str(TMP1.W(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.flags[24]));
|
||||
EmitI16ToExtF80();
|
||||
ldr(TMP1.W(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.flags[24]));
|
||||
msr(ARMEmitter::SystemRegister::NZCV, TMP1);
|
||||
} break;
|
||||
case FABI_F80_I16_I16_PTR:
|
||||
case FABI_F80_I16_I32_PTR: {
|
||||
// Linux Reg/Win32 Reg:
|
||||
// tmp4 (x4/x13): FallbackHandler
|
||||
// x30: return
|
||||
// tmp2 (x1/x11): source
|
||||
SpillForABICall(CTX->HostFeatures.SupportsPreserveAllABI, TMP3, true);
|
||||
|
||||
if (!TMP_ABIARGS) {
|
||||
mov(ARMEmitter::Size::i64Bit, ARMEmitter::Reg::r1, TMP2);
|
||||
}
|
||||
ldrh(ARMEmitter::WReg::w0, STATE, offsetof(FEXCore::Core::CPUState, FCW));
|
||||
mov(ARMEmitter::XReg::x2, STATE);
|
||||
if (!CTX->Config.DisableVixlIndirectCalls) [[unlikely]] {
|
||||
GenerateIndirectRuntimeCall<FEXCore::VectorRegType, uint16_t, uint32_t, uint64_t>(FallbackPointerReg);
|
||||
} else {
|
||||
blr(FallbackPointerReg);
|
||||
}
|
||||
|
||||
FillF80Result();
|
||||
mrs(TMP1, ARMEmitter::SystemRegister::NZCV);
|
||||
str(TMP1.W(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.flags[24]));
|
||||
EmitI32ToExtF80();
|
||||
ldr(TMP1.W(), STATE.R(), offsetof(FEXCore::Core::CpuStateFrame, State.flags[24]));
|
||||
msr(ARMEmitter::SystemRegister::NZCV, TMP1);
|
||||
} break;
|
||||
case FABI_F32_I16_F80_PTR: {
|
||||
// Linux Reg/Win32 Reg:
|
||||
|
||||
@@ -98,6 +98,13 @@ private:
|
||||
void EmitDispatcher();
|
||||
uint64_t GenerateABICall(FallbackABI ABI);
|
||||
|
||||
// Inline softfloat conversion emitters - avoid FPCR save/restore overhead
|
||||
// These emit ARM64 code that performs the conversion using only integer ops
|
||||
void EmitI16ToExtF80();
|
||||
void EmitI32ToExtF80();
|
||||
void EmitF32ToExtF80();
|
||||
void EmitF64ToExtF80();
|
||||
|
||||
FEX_CONFIG_OPT(DisableL2Cache, DISABLEL2CACHE);
|
||||
};
|
||||
|
||||
|
||||
@@ -769,13 +769,23 @@ bool Decoder::NormalOpHeader(const FEXCore::X86Tables::X86InstInfo* Info, uint16
|
||||
|
||||
if (Op == 0xC5) { // Two byte VEX
|
||||
pp = Byte1 & 0b11;
|
||||
options.vvvv = 15 - ((Byte1 & 0b01111000) >> 3);
|
||||
const uint8_t vvvv = ((Byte1 & 0b01111000) >> 3);
|
||||
if (!BlockInfo.Is64BitMode && vvvv <= 0b0111) {
|
||||
// Invalid on 32-bit, can't use the high registers.
|
||||
return false;
|
||||
}
|
||||
options.vvvv = 15 - vvvv;
|
||||
options.L = (Byte1 & 0b100) != 0;
|
||||
} else { // 0xC4 = Three byte VEX
|
||||
const uint8_t Byte2 = ReadByte();
|
||||
pp = Byte2 & 0b11;
|
||||
map_select = Byte1 & 0b11111;
|
||||
options.vvvv = 15 - ((Byte2 & 0b01111000) >> 3);
|
||||
const uint8_t vvvv = ((Byte2 & 0b01111000) >> 3);
|
||||
if (!BlockInfo.Is64BitMode && vvvv <= 0b0111) {
|
||||
// Invalid on 32-bit, can't use the high registers.
|
||||
return false;
|
||||
}
|
||||
options.vvvv = 15 - vvvv;
|
||||
options.w = (Byte2 & 0b10000000) != 0;
|
||||
options.L = (Byte2 & 0b100) != 0;
|
||||
if ((Byte1 & 0b01000000) == 0) {
|
||||
|
||||
@@ -435,12 +435,12 @@ struct OpHandlers<IR::OP_F80BCDSTORE> {
|
||||
FEXCORE_PROFILE_INSTANT_INCREMENT(Frame->Thread, AccumulatedFloatFallbackCount, 1);
|
||||
X80SoftFloat Src1 = Src1q;
|
||||
ScopedSoftFloatState State {FCW, Frame};
|
||||
bool Negative = Src1.Sign;
|
||||
bool Negative = Src1.Top.Sign;
|
||||
|
||||
Src1 = X80SoftFloat::FRNDINT(&State.State, Src1);
|
||||
|
||||
// Clear the Sign bit
|
||||
Src1.Sign = 0;
|
||||
Src1.Top.Sign = 0;
|
||||
|
||||
uint64_t Tmp = Src1.ToI64(&State.State);
|
||||
X80SoftFloat Rv;
|
||||
@@ -503,7 +503,7 @@ struct OpHandlers<IR::OP_F80BCDLOAD> {
|
||||
X80SoftFloat Tmp;
|
||||
|
||||
Tmp = BCD;
|
||||
Tmp.Sign = Negative;
|
||||
Tmp.Top.Sign = Negative;
|
||||
return Tmp;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -29,7 +29,8 @@ void Arm64JITCore::InsertNamedThunkRelocation(ARMEmitter::Register Reg, const IR
|
||||
uint64_t Pointer = reinterpret_cast<uint64_t>(EmitterCTX->ThunkHandler->LookupThunk(Sum));
|
||||
|
||||
// Pointers are required to fit within 48-bit VA space.
|
||||
LoadConstant(ARMEmitter::Size::i64Bit, Reg, Pointer, FEXCore::CPU::Arm64Emitter::PadType::AUTOPAD, 6);
|
||||
// TODO: Force 6-byte `MaxSize`, with zext extension to 64-bit. Current code not smart enough to handle negatives.
|
||||
LoadConstant(ARMEmitter::Size::i64Bit, Reg, Pointer, FEXCore::CPU::Arm64Emitter::PadType::AUTOPAD);
|
||||
Relocations.emplace_back(MoveABI);
|
||||
}
|
||||
|
||||
|
||||
@@ -322,7 +322,7 @@ DEF_OP(Thunk) {
|
||||
// X0: CTX
|
||||
// X1: Args (from guest stack)
|
||||
|
||||
SpillStaticRegs(TMP1); // spill to ctx before ra64 spill
|
||||
SpillStaticRegs(TMP1, true, ~0U, ~0U, false); // spill to ctx before ra64 spill
|
||||
|
||||
PushDynamicRegs(TMP1);
|
||||
|
||||
@@ -337,7 +337,7 @@ DEF_OP(Thunk) {
|
||||
|
||||
PopDynamicRegs();
|
||||
|
||||
FillStaticRegs(); // load from ctx after ra64 refill
|
||||
FillStaticRegs(true, ~0U, ~0U, std::nullopt, std::nullopt, false); // load from ctx after ra64 refill
|
||||
}
|
||||
|
||||
DEF_OP(ValidateCode) {
|
||||
|
||||
@@ -676,7 +676,7 @@ void Arm64JITCore::ClearCache() {
|
||||
auto lk = PrevCodeBuffer->LookupCache->AcquireWriteLock();
|
||||
|
||||
auto CodeBuffer = GetEmptyCodeBuffer();
|
||||
SetBuffer(CodeBuffer->Ptr, CodeBuffer->Size);
|
||||
SetBuffer(CodeBuffer->Ptr, CodeBuffer->AllocatedSize);
|
||||
EmitDetectionString();
|
||||
|
||||
ThreadState->LookupCache->ChangeGuestToHostMapping(*PrevCodeBuffer, *CurrentCodeBuffer->LookupCache, lk);
|
||||
@@ -1082,14 +1082,13 @@ CPUBackend::CompiledCode Arm64JITCore::CompileCode(uint64_t Entry, uint64_t Size
|
||||
}
|
||||
|
||||
// NOTE: 16-byte alignment of the new cursor offset must be preserved for block linking records
|
||||
SetBuffer(CurrentCodeBuffer->Ptr, CurrentCodeBuffer->Size);
|
||||
SetCursorOffset(AlignUp(CodeBuffers.LatestOffset, 16));
|
||||
if ((GetCursorOffset() + TempSize) > (CurrentCodeBuffer->Size - Utils::FEX_PAGE_SIZE)) {
|
||||
SetBuffer(CurrentCodeBuffer->Ptr, CurrentCodeBuffer->AllocatedSize);
|
||||
SetCursorOffset(CodeBuffers.LatestOffset);
|
||||
Align16B();
|
||||
if ((GetCursorOffset() + TempSize) > CurrentCodeBuffer->UsableSize()) {
|
||||
CTX->ClearCodeCache(ThreadState);
|
||||
}
|
||||
|
||||
Align16B();
|
||||
|
||||
CodeBuffers.LatestOffset = GetCursorOffset();
|
||||
}
|
||||
|
||||
|
||||
@@ -566,6 +566,24 @@ DEF_OP(LoadDF) {
|
||||
ldrsb(Dst.X(), STATE, offsetof(FEXCore::Core::CPUState, flags[Flag]));
|
||||
}
|
||||
|
||||
DEF_OP(ContextClear) {
|
||||
auto Op = IROp->C<IR::IROp_ContextClear>();
|
||||
if (CTX->HostFeatures.SupportsCLZERO) {
|
||||
// We can use CLZero directly when hardware supports it.
|
||||
// Provides a fairly generous speed-up on Ampere1A hardware.
|
||||
// TODO: When FEAT_MOPS hardware ships, test memset using MOPS.
|
||||
for (size_t i = 0; i < Op->Size; i += 64) {
|
||||
add(ARMEmitter::Size::i64Bit, TMP1, STATE.R(), Op->Offset + i);
|
||||
dc(ARMEmitter::DataCacheOperation::ZVA, TMP1);
|
||||
}
|
||||
} else {
|
||||
movi(ARMEmitter::SubRegSize::i64Bit, VTMP1.Q(), 0);
|
||||
for (size_t i = 0; i < Op->Size; i += 32) {
|
||||
stp<ARMEmitter::IndexType::OFFSET>(VTMP1.Q(), VTMP1.Q(), STATE.R(), Op->Offset + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ARMEmitter::ExtendedMemOperand Arm64JITCore::GenerateMemOperand(
|
||||
IR::OpSize AccessSize, ARMEmitter::Register Base, IR::OrderedNodeWrapper Offset, IR::MemOffsetType OffsetType, uint8_t OffsetScale) {
|
||||
if (Offset.IsInvalid()) {
|
||||
|
||||
@@ -1117,6 +1117,29 @@ DEF_OP(VAddP) {
|
||||
}
|
||||
}
|
||||
|
||||
DEF_OP(VOrn) {
|
||||
const auto Op = IROp->C<IR::IROp_VOrn>();
|
||||
const auto OpSize = IROp->Size;
|
||||
|
||||
const auto Is256Bit = OpSize == IR::OpSize::i256Bit;
|
||||
const auto Is128Bit = OpSize == IR::OpSize::i128Bit;
|
||||
LOGMAN_THROW_A_FMT(!Is256Bit || HostSupportsSVE256, "Need SVE256 support in order to use {} with 256-bit operation", __func__);
|
||||
|
||||
const auto Dst = GetVReg(Node);
|
||||
const auto Vector1 = GetVReg(Op->Vector1);
|
||||
const auto Vector2 = GetVReg(Op->Vector2);
|
||||
|
||||
if (HostSupportsSVE256 && Is256Bit) {
|
||||
const auto Pred = PRED_TMP_32B.Merging();
|
||||
not_(ARMEmitter::SubRegSize::i8Bit, VTMP1.Z(), Pred, Vector2.Z());
|
||||
orr(Dst.Z(), Vector1.Z(), VTMP1.Z());
|
||||
} else if (Is128Bit) {
|
||||
orn(Dst.Q(), Vector1.Q(), Vector2.Q());
|
||||
} else {
|
||||
orn(Dst.D(), Vector1.D(), Vector2.D());
|
||||
}
|
||||
}
|
||||
|
||||
DEF_OP(VFAddV) {
|
||||
const auto Op = IROp->C<IR::IROp_VFAddV>();
|
||||
const auto OpSize = IROp->Size;
|
||||
|
||||
@@ -1039,6 +1039,34 @@ void OpDispatchBuilder::TESTOp(OpcodeArgs, uint32_t SrcIndex) {
|
||||
InvalidateAF();
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::ARPLOp(OpcodeArgs) {
|
||||
// ARPL r/m16, r16
|
||||
// If the RPL field in the destination selector is less privileged than the
|
||||
// RPL field in the source selector, then adjust destination RPL to match
|
||||
// source RPL and set ZF=1. Otherwise ZF=0 and destination is unchanged.
|
||||
//
|
||||
// Only ZF is modified by ARPL.
|
||||
constexpr auto Size = OpSize::i16Bit;
|
||||
|
||||
Ref Dest = LoadSourceGPR_WithOpSize(Op, Op->Dest, Size, Op->Flags, {.AllowUpperGarbage = true});
|
||||
Ref Src = LoadSourceGPR_WithOpSize(Op, Op->Src[0], Size, Op->Flags, {.AllowUpperGarbage = true});
|
||||
|
||||
// RPL is the low two bits of the selector.
|
||||
Ref DestRPL = _Bfe(OpSize::i32Bit, 2, 0, Dest);
|
||||
Ref SrcRPL = _Bfe(OpSize::i32Bit, 2, 0, Src);
|
||||
|
||||
// NeedUpdate is 1 when DestRPL < SrcRPL, else 0.
|
||||
Ref NeedUpdate = _Select(OpSize::i32Bit, OpSize::i32Bit, CondClass::ULT, DestRPL, SrcRPL, Constant(1), Constant(0));
|
||||
SetRFLAG<FEXCore::X86State::RFLAG_ZF_RAW_LOC>(NeedUpdate);
|
||||
|
||||
// Compute adjusted destination selector: (Dest & ~3) | SrcRPL.
|
||||
auto NewDest = _Bfxil(OpSize::i32Bit, 2, 0, Dest, SrcRPL);
|
||||
|
||||
// Conditionally select updated selector based on NeedUpdate.
|
||||
Ref FinalDest = _Select(OpSize::i32Bit, OpSize::i32Bit, CondClass::NEQ, NeedUpdate, Constant(0), NewDest, Dest);
|
||||
StoreResultGPR_WithOpSize(Op, Op->Dest, FinalDest, Size);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::MOVSXDOp(OpcodeArgs) {
|
||||
// This instruction is a bit special
|
||||
// if SrcSize == 2
|
||||
|
||||
@@ -27,6 +27,42 @@
|
||||
#include <xxhash.h>
|
||||
|
||||
namespace FEXCore::IR {
|
||||
enum class VectorCompareType {
|
||||
// SSE comparisons.
|
||||
EQ_OQ = 0,
|
||||
LT_OS = 1,
|
||||
LE_OS = 2,
|
||||
UNORD_Q = 3,
|
||||
NEQ_UQ = 4,
|
||||
NLT_US = 5,
|
||||
NLE_US = 6,
|
||||
ORD_Q = 7,
|
||||
// AVX-only comparisons.
|
||||
EQ_UQ = 8,
|
||||
NGE_US = 9,
|
||||
NGT_US = 10,
|
||||
FALSE_OQ = 11,
|
||||
NEQ_OQ = 12,
|
||||
GE_OS = 13,
|
||||
GT_OS = 14,
|
||||
TRUE_UQ = 15,
|
||||
EQ_OS = 16,
|
||||
LT_OQ = 17,
|
||||
LE_OQ = 18,
|
||||
UNORD_S = 19,
|
||||
NEQ_US = 20,
|
||||
NLT_UQ = 21,
|
||||
NLE_UQ = 22,
|
||||
ORD_S = 23,
|
||||
EQ_US = 24,
|
||||
NGE_UQ = 25,
|
||||
NGT_UQ = 26,
|
||||
FALSE_OS = 27,
|
||||
NEQ_OS = 28,
|
||||
GE_OQ = 29,
|
||||
GT_OQ = 30,
|
||||
TRUE_US = 31,
|
||||
};
|
||||
|
||||
enum class MemoryAccessType {
|
||||
// Choose TSO or Non-TSO depending on access type
|
||||
@@ -356,6 +392,7 @@ public:
|
||||
void CALLFARIndirectOp(OpcodeArgs);
|
||||
void RETFARIndirectOp(OpcodeArgs);
|
||||
void TESTOp(OpcodeArgs, uint32_t SrcIndex);
|
||||
void ARPLOp(OpcodeArgs);
|
||||
void MOVSXDOp(OpcodeArgs);
|
||||
void MOVSXOp(OpcodeArgs);
|
||||
void MOVZXOp(OpcodeArgs);
|
||||
@@ -2069,6 +2106,12 @@ private:
|
||||
RegCache.Written |= Bit;
|
||||
}
|
||||
|
||||
void InvalidateHighAVXRegisters() {
|
||||
for (size_t i = 0; i < 16; ++i) {
|
||||
InvalidateReg(AVXHigh0Index + i);
|
||||
}
|
||||
}
|
||||
|
||||
void StoreRegister(uint8_t Reg, bool FPR, Ref Value) {
|
||||
StoreContext(Reg + (FPR ? FPR0Index : GPR0Index), Value);
|
||||
}
|
||||
|
||||
@@ -340,16 +340,12 @@ void OpDispatchBuilder::AVX128_VZERO(OpcodeArgs) {
|
||||
AVX128_StoreXMMRegister(i, ZeroVector, false);
|
||||
}
|
||||
|
||||
// More efficient for non-SRA upper-halves to use a cached constant and store directly.
|
||||
for (uint32_t i = 0; i < NumRegs; i++) {
|
||||
AVX128_StoreXMMRegister(i, ZeroVector, true);
|
||||
}
|
||||
InvalidateHighAVXRegisters();
|
||||
_ContextClear(offsetof(FEXCore::Core::CPUState, avx_high), sizeof(FEXCore::Core::CPUState::avx_high[0]) * NumRegs);
|
||||
} else {
|
||||
// Likewise, VZEROUPPER will only ever zero only up to the first 16 registers
|
||||
const auto ZeroVector = LoadZeroVector(OpSize::i128Bit);
|
||||
for (uint32_t i = 0; i < NumRegs; i++) {
|
||||
AVX128_StoreXMMRegister(i, ZeroVector, true);
|
||||
}
|
||||
InvalidateHighAVXRegisters();
|
||||
_ContextClear(offsetof(FEXCore::Core::CPUState, avx_high), sizeof(FEXCore::Core::CPUState::avx_high[0]) * NumRegs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -676,10 +672,10 @@ void OpDispatchBuilder::AVX128_VFCMP(OpcodeArgs, IR::OpSize ElementSize) {
|
||||
|
||||
struct {
|
||||
FEXCore::X86Tables::DecodedOp Op;
|
||||
uint8_t CompType {};
|
||||
uint32_t CompType {};
|
||||
} Capture {
|
||||
.Op = Op,
|
||||
.CompType = CompType,
|
||||
.CompType = CompType & 0b11111u,
|
||||
};
|
||||
|
||||
AVX128_VectorBinaryImpl(Op, OpSizeFromSrc(Op), ElementSize, [this, &Capture](IR::OpSize _ElementSize, Ref Src1, Ref Src2) {
|
||||
@@ -705,7 +701,7 @@ void OpDispatchBuilder::AVX128_InsertScalarFCMP(OpcodeArgs, IR::OpSize ElementSi
|
||||
const uint8_t CompType = Op->Src[2].Literal();
|
||||
|
||||
RefPair Result {};
|
||||
Result.Low = InsertScalarFCMPOpImpl(OpSize::i128Bit, OpSize::i128Bit, ElementSize, Src1.Low, Src2.Low, CompType, false);
|
||||
Result.Low = InsertScalarFCMPOpImpl(OpSize::i128Bit, OpSize::i128Bit, ElementSize, Src1.Low, Src2.Low, CompType & 0b11111, false);
|
||||
Result.High = LoadZeroVector(OpSize::i128Bit);
|
||||
AVX128_StoreResult_WithOpSize(Op, Op->Dest, Result);
|
||||
}
|
||||
|
||||
@@ -562,31 +562,90 @@ template void OpDispatchBuilder::AVXInsertScalarRound<OpSize::i64Bit>(OpcodeArgs
|
||||
|
||||
Ref OpDispatchBuilder::InsertScalarFCMPOpImpl(OpSize Size, IR::OpSize OpDstSize, IR::OpSize ElementSize, Ref Src1, Ref Src2,
|
||||
uint8_t CompType, bool ZeroUpperBits) {
|
||||
switch (CompType & 7) {
|
||||
case 0x0: // EQ
|
||||
return _VFCMPScalarInsert(Size, ElementSize, Src1, Src2, FloatCompareOp::EQ, ZeroUpperBits);
|
||||
case 0x1: // LT, GT(Swapped operand)
|
||||
return _VFCMPScalarInsert(Size, ElementSize, Src1, Src2, FloatCompareOp::LT, ZeroUpperBits);
|
||||
case 0x2: // LE, GE(Swapped operand)
|
||||
return _VFCMPScalarInsert(Size, ElementSize, Src1, Src2, FloatCompareOp::LE, ZeroUpperBits);
|
||||
case 0x3: // Unordered
|
||||
return _VFCMPScalarInsert(Size, ElementSize, Src1, Src2, FloatCompareOp::UNO, ZeroUpperBits);
|
||||
case 0x4: // NEQ
|
||||
return _VFCMPScalarInsert(Size, ElementSize, Src1, Src2, FloatCompareOp::NEQ, ZeroUpperBits);
|
||||
case 0x5: { // NLT, NGT(Swapped operand)
|
||||
switch (static_cast<VectorCompareType>(CompType)) {
|
||||
case VectorCompareType::EQ_OQ:
|
||||
case VectorCompareType::EQ_OS: return _VFCMPScalarInsert(Size, ElementSize, Src1, Src2, FloatCompareOp::EQ, ZeroUpperBits);
|
||||
case VectorCompareType::LT_OS: // GT(Swapped operand)
|
||||
case VectorCompareType::LT_OQ: return _VFCMPScalarInsert(Size, ElementSize, Src1, Src2, FloatCompareOp::LT, ZeroUpperBits);
|
||||
case VectorCompareType::LE_OS: // GE(Swapped operand)
|
||||
case VectorCompareType::LE_OQ: return _VFCMPScalarInsert(Size, ElementSize, Src1, Src2, FloatCompareOp::LE, ZeroUpperBits);
|
||||
case VectorCompareType::UNORD_Q:
|
||||
case VectorCompareType::UNORD_S: return _VFCMPScalarInsert(Size, ElementSize, Src1, Src2, FloatCompareOp::UNO, ZeroUpperBits);
|
||||
case VectorCompareType::NEQ_UQ:
|
||||
case VectorCompareType::NEQ_US: return _VFCMPScalarInsert(Size, ElementSize, Src1, Src2, FloatCompareOp::NEQ, ZeroUpperBits);
|
||||
case VectorCompareType::NLT_US: // NGT(Swapped operand)
|
||||
case VectorCompareType::NLT_UQ: {
|
||||
Ref Result = _VFCMPLT(ElementSize, ElementSize, Src1, Src2);
|
||||
Result = _VNot(ElementSize, ElementSize, Result);
|
||||
// Insert the lower bits
|
||||
return _VInsElement(OpDstSize, ElementSize, 0, 0, Src1, Result);
|
||||
}
|
||||
case 0x6: { // NLE, NGE(Swapped operand)
|
||||
case VectorCompareType::NLE_US: // NGE(Swapped operand)
|
||||
case VectorCompareType::NLE_UQ: {
|
||||
Ref Result = _VFCMPLE(ElementSize, ElementSize, Src1, Src2);
|
||||
Result = _VNot(ElementSize, ElementSize, Result);
|
||||
// Insert the lower bits
|
||||
return _VInsElement(OpDstSize, ElementSize, 0, 0, Src1, Result);
|
||||
}
|
||||
case 0x7: // Ordered
|
||||
return _VFCMPScalarInsert(Size, ElementSize, Src1, Src2, FloatCompareOp::ORD, ZeroUpperBits);
|
||||
case VectorCompareType::ORD_Q:
|
||||
case VectorCompareType::ORD_S: return _VFCMPScalarInsert(Size, ElementSize, Src1, Src2, FloatCompareOp::ORD, ZeroUpperBits);
|
||||
case VectorCompareType::NGT_UQ:
|
||||
case VectorCompareType::NGT_US: {
|
||||
Ref Result = _VFCMPLT(ElementSize, ElementSize, Src2, Src1);
|
||||
Result = _VNot(ElementSize, ElementSize, Result);
|
||||
// Insert the lower bits
|
||||
return _VInsElement(OpDstSize, ElementSize, 0, 0, Src1, Result);
|
||||
}
|
||||
case VectorCompareType::NGE_UQ:
|
||||
case VectorCompareType::NGE_US: {
|
||||
Ref Result = _VFCMPLE(ElementSize, ElementSize, Src2, Src1);
|
||||
Result = _VNot(ElementSize, ElementSize, Result);
|
||||
// Insert the lower bits
|
||||
return _VInsElement(OpDstSize, ElementSize, 0, 0, Src1, Result);
|
||||
}
|
||||
case VectorCompareType::GT_OQ:
|
||||
case VectorCompareType::GT_OS: {
|
||||
Ref Result = _VFCMPLT(ElementSize, ElementSize, Src2, Src1);
|
||||
// Insert the lower bits
|
||||
return _VInsElement(OpDstSize, ElementSize, 0, 0, Src1, Result);
|
||||
}
|
||||
case VectorCompareType::GE_OQ:
|
||||
case VectorCompareType::GE_OS: {
|
||||
Ref Result = _VFCMPLE(ElementSize, ElementSize, Src2, Src1);
|
||||
// Insert the lower bits
|
||||
return _VInsElement(OpDstSize, ElementSize, 0, 0, Src1, Result);
|
||||
}
|
||||
case VectorCompareType::EQ_UQ:
|
||||
case VectorCompareType::EQ_US: {
|
||||
// If either of the sources are unordered, then returns true.
|
||||
Ref Src1_U = _VFCMPEQ(Size, ElementSize, Src1, Src1);
|
||||
Ref Src2_U = _VFCMPEQ(Size, ElementSize, Src2, Src2);
|
||||
auto Ordered = _VAnd(Size, ElementSize, Src1_U, Src2_U);
|
||||
|
||||
Ref Compare_Ordered = _VFCMPEQ(Size, ElementSize, Src1, Src2);
|
||||
Ref Result = _VOrn(Size, ElementSize, Compare_Ordered, Ordered);
|
||||
|
||||
// Insert the lower bits
|
||||
return _VInsElement(OpDstSize, ElementSize, 0, 0, Src1, Result);
|
||||
}
|
||||
case VectorCompareType::NEQ_OQ:
|
||||
case VectorCompareType::NEQ_OS: {
|
||||
// If either of the sources are unordered, then returns false.
|
||||
Ref Src1_U = _VFCMPEQ(Size, ElementSize, Src1, Src1);
|
||||
Ref Src2_U = _VFCMPEQ(Size, ElementSize, Src2, Src2);
|
||||
|
||||
Ref Compare_Ordered = _VFCMPEQ(Size, ElementSize, Src1, Src2);
|
||||
Ref Result = _VAndn(Size, ElementSize, Src1_U, Compare_Ordered);
|
||||
Result = _VAnd(Size, ElementSize, Result, Src2_U);
|
||||
|
||||
// Insert the lower bits
|
||||
return _VInsElement(OpDstSize, ElementSize, 0, 0, Src1, Result);
|
||||
}
|
||||
case VectorCompareType::FALSE_OQ:
|
||||
case VectorCompareType::FALSE_OS: return _VInsElement(OpDstSize, ElementSize, 0, 0, Src1, LoadZeroVector(OpSize::i128Bit));
|
||||
case VectorCompareType::TRUE_UQ:
|
||||
case VectorCompareType::TRUE_US:
|
||||
return _VInsElement(OpDstSize, ElementSize, 0, 0, Src1, _VectorImm(OpSize::i128Bit, OpSize::i8Bit, -1, 0));
|
||||
}
|
||||
FEX_UNREACHABLE;
|
||||
}
|
||||
@@ -600,7 +659,7 @@ void OpDispatchBuilder::InsertScalarFCMPOp(OpcodeArgs) {
|
||||
Ref Src1 = LoadSourceFPR_WithOpSize(Op, Op->Dest, DstSize, Op->Flags);
|
||||
Ref Src2 = LoadSourceFPR_WithOpSize(Op, Op->Src[0], SrcSize, Op->Flags, {.AllowUpperGarbage = true});
|
||||
|
||||
Ref Result = InsertScalarFCMPOpImpl(DstSize, OpSizeFromDst(Op), ElementSize, Src1, Src2, CompType, false);
|
||||
Ref Result = InsertScalarFCMPOpImpl(DstSize, OpSizeFromDst(Op), ElementSize, Src1, Src2, CompType & 0b111, false);
|
||||
StoreResultFPR_WithOpSize(Op, Op->Dest, Result, DstSize);
|
||||
}
|
||||
|
||||
@@ -619,7 +678,7 @@ void OpDispatchBuilder::AVXInsertScalarFCMPOp(OpcodeArgs) {
|
||||
Ref Src1 = LoadSourceFPR_WithOpSize(Op, Op->Src[0], DstSize, Op->Flags);
|
||||
Ref Src2 = LoadSourceFPR_WithOpSize(Op, Op->Src[1], SrcSize, Op->Flags, {.AllowUpperGarbage = true});
|
||||
|
||||
Ref Result = InsertScalarFCMPOpImpl(DstSize, OpSizeFromDst(Op), ElementSize, Src1, Src2, CompType, true);
|
||||
Ref Result = InsertScalarFCMPOpImpl(DstSize, OpSizeFromDst(Op), ElementSize, Src1, Src2, CompType & 0b11111, true);
|
||||
StoreResultFPR_WithOpSize(Op, Op->Dest, Result, DstSize);
|
||||
}
|
||||
|
||||
@@ -2424,26 +2483,67 @@ void OpDispatchBuilder::MOVBetweenGPR_FPR(OpcodeArgs, VectorOpType VectorType) {
|
||||
}
|
||||
|
||||
Ref OpDispatchBuilder::VFCMPOpImpl(OpSize Size, IR::OpSize ElementSize, Ref Src1, Ref Src2, uint8_t CompType) {
|
||||
Ref Result {};
|
||||
switch (CompType & 0x7) {
|
||||
case 0x0: // EQ
|
||||
return _VFCMPEQ(Size, ElementSize, Src1, Src2);
|
||||
case 0x1: // LT, GT(Swapped operand)
|
||||
return _VFCMPLT(Size, ElementSize, Src1, Src2);
|
||||
case 0x2: // LE, GE(Swapped operand)
|
||||
return _VFCMPLE(Size, ElementSize, Src1, Src2);
|
||||
case 0x3: // Unordered
|
||||
return _VFCMPUNO(Size, ElementSize, Src1, Src2);
|
||||
case 0x4: // NEQ
|
||||
return _VFCMPNEQ(Size, ElementSize, Src1, Src2);
|
||||
case 0x5: // NLT, NGT(Swapped operand)
|
||||
Result = _VFCMPLT(Size, ElementSize, Src1, Src2);
|
||||
switch (static_cast<VectorCompareType>(CompType)) {
|
||||
case VectorCompareType::EQ_OQ:
|
||||
case VectorCompareType::EQ_OS: return _VFCMPEQ(Size, ElementSize, Src1, Src2);
|
||||
case VectorCompareType::LT_OS: // GT(Swapped operand)
|
||||
case VectorCompareType::LT_OQ: return _VFCMPLT(Size, ElementSize, Src1, Src2);
|
||||
case VectorCompareType::LE_OS: // GE(Swapped operand)
|
||||
case VectorCompareType::LE_OQ: return _VFCMPLE(Size, ElementSize, Src1, Src2);
|
||||
case VectorCompareType::UNORD_Q:
|
||||
case VectorCompareType::UNORD_S: return _VFCMPUNO(Size, ElementSize, Src1, Src2);
|
||||
case VectorCompareType::NEQ_UQ:
|
||||
case VectorCompareType::NEQ_US: return _VFCMPNEQ(Size, ElementSize, Src1, Src2);
|
||||
case VectorCompareType::NLT_US: // NGT(Swapped operand)
|
||||
case VectorCompareType::NLT_UQ: {
|
||||
Ref Result = _VFCMPLT(Size, ElementSize, Src1, Src2);
|
||||
return _VNot(Size, ElementSize, Result);
|
||||
case 0x6: // NLE, NGE(Swapped operand)
|
||||
Result = _VFCMPLE(Size, ElementSize, Src1, Src2);
|
||||
}
|
||||
case VectorCompareType::NLE_US: // NGE(Swapped operand)
|
||||
case VectorCompareType::NLE_UQ: {
|
||||
Ref Result = _VFCMPLE(Size, ElementSize, Src1, Src2);
|
||||
return _VNot(Size, ElementSize, Result);
|
||||
case 0x7: // Ordered
|
||||
return _VFCMPORD(Size, ElementSize, Src1, Src2);
|
||||
}
|
||||
case VectorCompareType::ORD_Q:
|
||||
case VectorCompareType::ORD_S: return _VFCMPORD(Size, ElementSize, Src1, Src2);
|
||||
case VectorCompareType::NGT_UQ:
|
||||
case VectorCompareType::NGT_US: {
|
||||
Ref Result = _VFCMPLT(Size, ElementSize, Src2, Src1);
|
||||
return _VNot(Size, ElementSize, Result);
|
||||
}
|
||||
case VectorCompareType::NGE_UQ:
|
||||
case VectorCompareType::NGE_US: {
|
||||
Ref Result = _VFCMPLE(Size, ElementSize, Src2, Src1);
|
||||
return _VNot(Size, ElementSize, Result);
|
||||
}
|
||||
case VectorCompareType::GT_OQ:
|
||||
case VectorCompareType::GT_OS: return _VFCMPLT(Size, ElementSize, Src2, Src1);
|
||||
case VectorCompareType::GE_OQ:
|
||||
case VectorCompareType::GE_OS: return _VFCMPLE(Size, ElementSize, Src2, Src1);
|
||||
case VectorCompareType::EQ_UQ:
|
||||
case VectorCompareType::EQ_US: {
|
||||
// If either of the sources are unordered, then returns true.
|
||||
Ref Src1_U = _VFCMPEQ(Size, ElementSize, Src1, Src1);
|
||||
Ref Src2_U = _VFCMPEQ(Size, ElementSize, Src2, Src2);
|
||||
auto Ordered = _VAnd(Size, ElementSize, Src1_U, Src2_U);
|
||||
|
||||
Ref Compare_Ordered = _VFCMPEQ(Size, ElementSize, Src1, Src2);
|
||||
return _VOrn(Size, ElementSize, Compare_Ordered, Ordered);
|
||||
}
|
||||
case VectorCompareType::NEQ_OQ:
|
||||
case VectorCompareType::NEQ_OS: {
|
||||
// If either of the sources are unordered, then returns false.
|
||||
Ref Src1_U = _VFCMPEQ(Size, ElementSize, Src1, Src1);
|
||||
Ref Src2_U = _VFCMPEQ(Size, ElementSize, Src2, Src2);
|
||||
|
||||
Ref Compare_Ordered = _VFCMPEQ(Size, ElementSize, Src1, Src2);
|
||||
Ref Result = _VAndn(Size, ElementSize, Src1_U, Compare_Ordered);
|
||||
return _VAnd(Size, ElementSize, Result, Src2_U);
|
||||
}
|
||||
case VectorCompareType::FALSE_OQ:
|
||||
case VectorCompareType::FALSE_OS: return LoadZeroVector(Size);
|
||||
case VectorCompareType::TRUE_UQ:
|
||||
case VectorCompareType::TRUE_US: return _VectorImm(Size, OpSize::i8Bit, -1, 0);
|
||||
}
|
||||
FEX_UNREACHABLE;
|
||||
}
|
||||
@@ -2459,7 +2559,7 @@ void OpDispatchBuilder::VFCMPOp(OpcodeArgs) {
|
||||
Ref Dest = LoadSourceFPR_WithOpSize(Op, Op->Dest, DstSize, Op->Flags);
|
||||
const uint8_t CompType = Op->Src[1].Data.Literal.Value;
|
||||
|
||||
Ref Result = VFCMPOpImpl(OpSizeFromSrc(Op), ElementSize, Dest, Src, CompType);
|
||||
Ref Result = VFCMPOpImpl(OpSizeFromSrc(Op), ElementSize, Dest, Src, CompType & 0b111);
|
||||
|
||||
StoreResultFPR(Op, Result);
|
||||
}
|
||||
@@ -2477,7 +2577,7 @@ void OpDispatchBuilder::AVXVFCMPOp(OpcodeArgs) {
|
||||
|
||||
Ref Src1 = LoadSourceFPR_WithOpSize(Op, Op->Src[0], DstSize, Op->Flags);
|
||||
Ref Src2 = LoadSourceFPR_WithOpSize(Op, Op->Src[1], SrcSize, Op->Flags);
|
||||
Ref Result = VFCMPOpImpl(OpSizeFromSrc(Op), ElementSize, Src1, Src2, CompType);
|
||||
Ref Result = VFCMPOpImpl(OpSizeFromSrc(Op), ElementSize, Src1, Src2, CompType & 0b11111);
|
||||
|
||||
StoreResultFPR(Op, Result);
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ constexpr std::array<X86InstInfo[2], ENTRY_MAX> Primary_ArchSelect_LUT = {{
|
||||
},
|
||||
// ENTRY_63
|
||||
{
|
||||
{"ARPL", TYPE_INVALID, FLAGS_NONE, 0, { .OpDispatch = nullptr } },
|
||||
{"ARPL", TYPE_INST, GenFlagsSameSize(SIZE_16BIT) | FLAGS_MODRM | FLAGS_SF_MOD_DST, 0, { .OpDispatch = &IR::OpDispatchBuilder::ARPLOp } },
|
||||
{"MOVSXD", TYPE_INST, GenFlagsDstSize(SIZE_64BIT) | FLAGS_MODRM, 0, { .OpDispatch = &IR::OpDispatchBuilder::MOVSXDOp } },
|
||||
},
|
||||
// ENTRY_9A
|
||||
@@ -436,4 +436,3 @@ const std::array<X86InstInfo, MAX_PRIMARY_TABLE_SIZE> BaseOps = []() consteval {
|
||||
}();
|
||||
|
||||
}
|
||||
|
||||
@@ -24,92 +24,98 @@ namespace FEXCore::X86Tables {
|
||||
struct X86InstInfo;
|
||||
|
||||
namespace DecodeFlags {
|
||||
constexpr uint32_t FLAG_OPERAND_SIZE = (1 << 0);
|
||||
constexpr uint32_t FLAG_ADDRESS_SIZE = (1 << 1);
|
||||
constexpr uint32_t FLAG_LOCK = (1 << 2);
|
||||
constexpr uint32_t FLAG_LEGACY_PREFIX = (1 << 3);
|
||||
constexpr uint32_t FLAG_REX_PREFIX = (1 << 4);
|
||||
constexpr uint32_t FLAG_VSIB_BYTE = (1 << 5);
|
||||
constexpr uint32_t FLAG_OPTION_AVX_W = (1 << 6);
|
||||
constexpr uint32_t FLAG_REX_WIDENING = (1 << 7);
|
||||
constexpr uint32_t FLAG_REX_XGPR_B = (1 << 8);
|
||||
constexpr uint32_t FLAG_REX_XGPR_X = (1 << 9);
|
||||
constexpr uint32_t FLAG_REX_XGPR_R = (1 << 10);
|
||||
constexpr uint32_t FLAG_NO_PREFIX = (0b000 << 11);
|
||||
constexpr uint32_t FLAG_ES_PREFIX = (0b001 << 11);
|
||||
constexpr uint32_t FLAG_CS_PREFIX = (0b010 << 11);
|
||||
constexpr uint32_t FLAG_SS_PREFIX = (0b011 << 11);
|
||||
constexpr uint32_t FLAG_DS_PREFIX = (0b100 << 11);
|
||||
constexpr uint32_t FLAG_FS_PREFIX = (0b101 << 11);
|
||||
constexpr uint32_t FLAG_GS_PREFIX = (0b110 << 11);
|
||||
constexpr uint32_t FLAG_SEGMENTS = (0b111 << 11);
|
||||
constexpr uint32_t FLAG_FORCE_TSO = (1 << 14);
|
||||
constexpr uint32_t FLAG_DECODED_MODRM = (1 << 15);
|
||||
constexpr uint32_t FLAG_DECODED_SIB = (1 << 16);
|
||||
constexpr uint32_t FLAG_REP_PREFIX = (1 << 17);
|
||||
constexpr uint32_t FLAG_REPNE_PREFIX = (1 << 18);
|
||||
// Size flags
|
||||
constexpr uint32_t FLAG_SIZE_DST_OFF = 19;
|
||||
constexpr uint32_t FLAG_SIZE_SRC_OFF = FLAG_SIZE_DST_OFF + 3;
|
||||
constexpr uint32_t SIZE_MASK = 0b111;
|
||||
constexpr uint32_t SIZE_DEF = 0b000; // This should be invalid past decoding
|
||||
constexpr uint32_t SIZE_8BIT = 0b001;
|
||||
constexpr uint32_t SIZE_16BIT = 0b010;
|
||||
constexpr uint32_t SIZE_32BIT = 0b011;
|
||||
constexpr uint32_t SIZE_64BIT = 0b100;
|
||||
constexpr uint32_t SIZE_128BIT = 0b101;
|
||||
constexpr uint32_t SIZE_256BIT = 0b110;
|
||||
constexpr uint32_t FLAG_OPERAND_SIZE = (1 << 0);
|
||||
constexpr uint32_t FLAG_ADDRESS_SIZE = (1 << 1);
|
||||
constexpr uint32_t FLAG_LOCK = (1 << 2);
|
||||
constexpr uint32_t FLAG_LEGACY_PREFIX = (1 << 3);
|
||||
constexpr uint32_t FLAG_REX_PREFIX = (1 << 4);
|
||||
constexpr uint32_t FLAG_VSIB_BYTE = (1 << 5);
|
||||
constexpr uint32_t FLAG_OPTION_AVX_W = (1 << 6);
|
||||
constexpr uint32_t FLAG_REX_WIDENING = (1 << 7);
|
||||
constexpr uint32_t FLAG_REX_XGPR_B = (1 << 8);
|
||||
constexpr uint32_t FLAG_REX_XGPR_X = (1 << 9);
|
||||
constexpr uint32_t FLAG_REX_XGPR_R = (1 << 10);
|
||||
constexpr uint32_t FLAG_NO_PREFIX = (0b000 << 11);
|
||||
constexpr uint32_t FLAG_ES_PREFIX = (0b001 << 11);
|
||||
constexpr uint32_t FLAG_CS_PREFIX = (0b010 << 11);
|
||||
constexpr uint32_t FLAG_SS_PREFIX = (0b011 << 11);
|
||||
constexpr uint32_t FLAG_DS_PREFIX = (0b100 << 11);
|
||||
constexpr uint32_t FLAG_FS_PREFIX = (0b101 << 11);
|
||||
constexpr uint32_t FLAG_GS_PREFIX = (0b110 << 11);
|
||||
constexpr uint32_t FLAG_SEGMENTS = (0b111 << 11);
|
||||
constexpr uint32_t FLAG_FORCE_TSO = (1 << 14);
|
||||
constexpr uint32_t FLAG_DECODED_MODRM = (1 << 15);
|
||||
constexpr uint32_t FLAG_DECODED_SIB = (1 << 16);
|
||||
constexpr uint32_t FLAG_REP_PREFIX = (1 << 17);
|
||||
constexpr uint32_t FLAG_REPNE_PREFIX = (1 << 18);
|
||||
// Size flags
|
||||
constexpr uint32_t FLAG_SIZE_DST_OFF = 19;
|
||||
constexpr uint32_t FLAG_SIZE_SRC_OFF = FLAG_SIZE_DST_OFF + 3;
|
||||
constexpr uint32_t SIZE_MASK = 0b111;
|
||||
constexpr uint32_t SIZE_DEF = 0b000; // This should be invalid past decoding
|
||||
constexpr uint32_t SIZE_8BIT = 0b001;
|
||||
constexpr uint32_t SIZE_16BIT = 0b010;
|
||||
constexpr uint32_t SIZE_32BIT = 0b011;
|
||||
constexpr uint32_t SIZE_64BIT = 0b100;
|
||||
constexpr uint32_t SIZE_128BIT = 0b101;
|
||||
constexpr uint32_t SIZE_256BIT = 0b110;
|
||||
|
||||
constexpr uint32_t FLAG_OPADDR_OFF = (FLAG_SIZE_SRC_OFF + 3);
|
||||
constexpr uint32_t FLAG_OPADDR_STACKSIZE = 4; // Two level deep stack
|
||||
constexpr uint32_t FLAG_OPADDR_FLAG_SIZE = 2;
|
||||
constexpr uint32_t FLAG_OPADDR_MASK = (((1 << FLAG_OPADDR_STACKSIZE) - 1) << FLAG_OPADDR_OFF);
|
||||
constexpr uint32_t FLAG_OPADDR_OFF = (FLAG_SIZE_SRC_OFF + 3);
|
||||
constexpr uint32_t FLAG_OPADDR_STACKSIZE = 4; // Two level deep stack
|
||||
constexpr uint32_t FLAG_OPADDR_FLAG_SIZE = 2;
|
||||
constexpr uint32_t FLAG_OPADDR_MASK = (((1 << FLAG_OPADDR_STACKSIZE) - 1) << FLAG_OPADDR_OFF);
|
||||
|
||||
// 00 = NONE
|
||||
constexpr uint32_t FLAG_OPERAND_SIZE_LAST = 0b01;
|
||||
constexpr uint32_t FLAG_WIDENING_SIZE_LAST = 0b10;
|
||||
// 00 = NONE
|
||||
constexpr uint32_t FLAG_OPERAND_SIZE_LAST = 0b01;
|
||||
constexpr uint32_t FLAG_WIDENING_SIZE_LAST = 0b10;
|
||||
|
||||
constexpr uint32_t GetSizeDstFlags(uint32_t Flags) { return (Flags >> FLAG_SIZE_DST_OFF) & SIZE_MASK; }
|
||||
constexpr uint32_t GetSizeSrcFlags(uint32_t Flags) { return (Flags >> FLAG_SIZE_SRC_OFF) & SIZE_MASK; }
|
||||
|
||||
constexpr uint32_t GenSizeDstSize(uint32_t Size) { return Size << FLAG_SIZE_DST_OFF; }
|
||||
constexpr uint32_t GenSizeSrcSize(uint32_t Size) { return Size << FLAG_SIZE_SRC_OFF; }
|
||||
|
||||
constexpr uint32_t GetOpAddr(uint32_t Flags, uint32_t Index) {
|
||||
return (((Flags & FLAG_OPADDR_MASK) >> FLAG_OPADDR_OFF) >> (Index * 2)) & ((1 << FLAG_OPADDR_FLAG_SIZE) - 1);
|
||||
}
|
||||
|
||||
inline void PushOpAddr(uint32_t *Flags, uint32_t Flag) {
|
||||
uint32_t TmpFlags = *Flags;
|
||||
uint32_t BottomOfStack = ((TmpFlags & FLAG_OPADDR_MASK) >> FLAG_OPADDR_OFF) & ((1 << FLAG_OPADDR_FLAG_SIZE) - 1);
|
||||
|
||||
TmpFlags &= ~(FLAG_OPADDR_MASK);
|
||||
TmpFlags |=
|
||||
(BottomOfStack << (FLAG_OPADDR_OFF + FLAG_OPADDR_FLAG_SIZE)) |
|
||||
(Flag << FLAG_OPADDR_OFF);
|
||||
|
||||
*Flags = TmpFlags;
|
||||
}
|
||||
|
||||
inline void PopOpAddrIf(uint32_t *Flags, uint32_t Flag) {
|
||||
uint32_t TmpFlags = *Flags;
|
||||
uint32_t BottomOfStack = ((TmpFlags & FLAG_OPADDR_MASK) >> FLAG_OPADDR_OFF) & ((1 << FLAG_OPADDR_FLAG_SIZE) - 1);
|
||||
|
||||
// Only pop the stack if the bottom flag is the one we care about
|
||||
// Necessary for escape prefixes that overlap regular prefixes
|
||||
if (BottomOfStack != Flag) {
|
||||
return;
|
||||
constexpr uint32_t GetSizeDstFlags(uint32_t Flags) {
|
||||
return (Flags >> FLAG_SIZE_DST_OFF) & SIZE_MASK;
|
||||
}
|
||||
constexpr uint32_t GetSizeSrcFlags(uint32_t Flags) {
|
||||
return (Flags >> FLAG_SIZE_SRC_OFF) & SIZE_MASK;
|
||||
}
|
||||
|
||||
uint32_t TopOfStack = ((TmpFlags & FLAG_OPADDR_MASK) >> (FLAG_OPADDR_OFF + FLAG_OPADDR_FLAG_SIZE)) & ((1 << FLAG_OPADDR_FLAG_SIZE) - 1);
|
||||
constexpr uint32_t GenSizeDstSize(uint32_t Size) {
|
||||
return Size << FLAG_SIZE_DST_OFF;
|
||||
}
|
||||
constexpr uint32_t GenSizeSrcSize(uint32_t Size) {
|
||||
return Size << FLAG_SIZE_SRC_OFF;
|
||||
}
|
||||
|
||||
TmpFlags &= ~(FLAG_OPADDR_MASK);
|
||||
TmpFlags |= (TopOfStack << FLAG_OPADDR_OFF);
|
||||
constexpr uint32_t GetOpAddr(uint32_t Flags, uint32_t Index) {
|
||||
return (((Flags & FLAG_OPADDR_MASK) >> FLAG_OPADDR_OFF) >> (Index * 2)) & ((1 << FLAG_OPADDR_FLAG_SIZE) - 1);
|
||||
}
|
||||
|
||||
*Flags = TmpFlags;
|
||||
}
|
||||
inline void PushOpAddr(uint32_t* Flags, uint32_t Flag) {
|
||||
uint32_t TmpFlags = *Flags;
|
||||
uint32_t BottomOfStack = ((TmpFlags & FLAG_OPADDR_MASK) >> FLAG_OPADDR_OFF) & ((1 << FLAG_OPADDR_FLAG_SIZE) - 1);
|
||||
|
||||
}
|
||||
TmpFlags &= ~(FLAG_OPADDR_MASK);
|
||||
TmpFlags |= (BottomOfStack << (FLAG_OPADDR_OFF + FLAG_OPADDR_FLAG_SIZE)) | (Flag << FLAG_OPADDR_OFF);
|
||||
|
||||
*Flags = TmpFlags;
|
||||
}
|
||||
|
||||
inline void PopOpAddrIf(uint32_t* Flags, uint32_t Flag) {
|
||||
uint32_t TmpFlags = *Flags;
|
||||
uint32_t BottomOfStack = ((TmpFlags & FLAG_OPADDR_MASK) >> FLAG_OPADDR_OFF) & ((1 << FLAG_OPADDR_FLAG_SIZE) - 1);
|
||||
|
||||
// Only pop the stack if the bottom flag is the one we care about
|
||||
// Necessary for escape prefixes that overlap regular prefixes
|
||||
if (BottomOfStack != Flag) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t TopOfStack = ((TmpFlags & FLAG_OPADDR_MASK) >> (FLAG_OPADDR_OFF + FLAG_OPADDR_FLAG_SIZE)) & ((1 << FLAG_OPADDR_FLAG_SIZE) - 1);
|
||||
|
||||
TmpFlags &= ~(FLAG_OPADDR_MASK);
|
||||
TmpFlags |= (TopOfStack << FLAG_OPADDR_OFF);
|
||||
|
||||
*Flags = TmpFlags;
|
||||
}
|
||||
|
||||
} // namespace DecodeFlags
|
||||
|
||||
struct DecodedOperand {
|
||||
enum class OpType : uint8_t {
|
||||
@@ -194,8 +200,8 @@ struct DecodedOperand {
|
||||
int64_t Offset;
|
||||
uint8_t Scale;
|
||||
uint8_t Index; // ~0 invalid
|
||||
uint8_t Base; // ~0 invalid
|
||||
} SIB; // Shared with SIBRelocation
|
||||
uint8_t Base; // ~0 invalid
|
||||
} SIB; // Shared with SIBRelocation
|
||||
};
|
||||
|
||||
TypeUnion Data;
|
||||
@@ -209,7 +215,7 @@ struct DecodedInst {
|
||||
DecodedOperand Src[3];
|
||||
|
||||
// Constains the dispatcher handler pointer
|
||||
X86InstInfo const* TableInfo;
|
||||
const X86InstInfo* TableInfo;
|
||||
|
||||
uint32_t Flags;
|
||||
uint16_t OP;
|
||||
@@ -222,18 +228,18 @@ struct DecodedInst {
|
||||
};
|
||||
|
||||
union ModRMDecoded {
|
||||
uint8_t Hex{};
|
||||
uint8_t Hex {};
|
||||
struct {
|
||||
uint8_t rm : 3;
|
||||
uint8_t rm : 3;
|
||||
uint8_t reg : 3;
|
||||
uint8_t mod : 2;
|
||||
};
|
||||
};
|
||||
|
||||
union SIBDecoded {
|
||||
uint8_t Hex{};
|
||||
uint8_t Hex {};
|
||||
struct {
|
||||
uint8_t base : 3;
|
||||
uint8_t base : 3;
|
||||
uint8_t index : 3;
|
||||
uint8_t scale : 2;
|
||||
};
|
||||
@@ -304,123 +310,136 @@ enum InstType {
|
||||
|
||||
namespace InstFlags {
|
||||
|
||||
using InstFlagType = uint64_t;
|
||||
using InstFlagType = uint64_t;
|
||||
|
||||
constexpr InstFlagType FLAGS_NONE = 0;
|
||||
// The secondary Opcode Map uses prefix bytes to overlay more instruction
|
||||
// But some instructions need to ignore this overlay and consume these prefixes.
|
||||
constexpr InstFlagType FLAGS_NO_OVERLAY = (1ULL << 0);
|
||||
// Some instructions partially ignore overlay
|
||||
// Ignore OpSize (0x66) in this case
|
||||
constexpr InstFlagType FLAGS_NO_OVERLAY66 = (1ULL << 1);
|
||||
constexpr InstFlagType FLAGS_DEBUG_MEM_ACCESS = (1ULL << 2);
|
||||
// Only SEXT if the instruction is operating in 64bit operand size
|
||||
constexpr InstFlagType FLAGS_SRC_SEXT64BIT = (1ULL << 3);
|
||||
constexpr InstFlagType FLAGS_BLOCK_END = (1ULL << 4);
|
||||
constexpr InstFlagType FLAGS_SETS_RIP = (1ULL << 5);
|
||||
constexpr InstFlagType FLAGS_NONE = 0;
|
||||
// The secondary Opcode Map uses prefix bytes to overlay more instruction
|
||||
// But some instructions need to ignore this overlay and consume these prefixes.
|
||||
constexpr InstFlagType FLAGS_NO_OVERLAY = (1ULL << 0);
|
||||
// Some instructions partially ignore overlay
|
||||
// Ignore OpSize (0x66) in this case
|
||||
constexpr InstFlagType FLAGS_NO_OVERLAY66 = (1ULL << 1);
|
||||
constexpr InstFlagType FLAGS_DEBUG_MEM_ACCESS = (1ULL << 2);
|
||||
// Only SEXT if the instruction is operating in 64bit operand size
|
||||
constexpr InstFlagType FLAGS_SRC_SEXT64BIT = (1ULL << 3);
|
||||
constexpr InstFlagType FLAGS_BLOCK_END = (1ULL << 4);
|
||||
constexpr InstFlagType FLAGS_SETS_RIP = (1ULL << 5);
|
||||
|
||||
constexpr InstFlagType FLAGS_DISPLACE_SIZE_MUL_2 = (1ULL << 6);
|
||||
constexpr InstFlagType FLAGS_DISPLACE_SIZE_DIV_2 = (1ULL << 7);
|
||||
constexpr InstFlagType FLAGS_SRC_SEXT = (1ULL << 8);
|
||||
constexpr InstFlagType FLAGS_MEM_OFFSET = (1ULL << 9);
|
||||
constexpr InstFlagType FLAGS_DISPLACE_SIZE_MUL_2 = (1ULL << 6);
|
||||
constexpr InstFlagType FLAGS_DISPLACE_SIZE_DIV_2 = (1ULL << 7);
|
||||
constexpr InstFlagType FLAGS_SRC_SEXT = (1ULL << 8);
|
||||
constexpr InstFlagType FLAGS_MEM_OFFSET = (1ULL << 9);
|
||||
|
||||
// Enables XMM based subflags
|
||||
// Current reserved range for this SF is [10, 15]
|
||||
constexpr InstFlagType FLAGS_XMM_FLAGS = (1ULL << 10);
|
||||
// Enables XMM based subflags
|
||||
// Current reserved range for this SF is [10, 15]
|
||||
constexpr InstFlagType FLAGS_XMM_FLAGS = (1ULL << 10);
|
||||
|
||||
// X87 flags aliased to XMM flags selection
|
||||
// Allows X87 instruction table that is abusing the flag for 64BIT selection to work
|
||||
constexpr InstFlagType FLAGS_X87_FLAGS = (1ULL << 10);
|
||||
// X87 flags aliased to XMM flags selection
|
||||
// Allows X87 instruction table that is abusing the flag for 64BIT selection to work
|
||||
constexpr InstFlagType FLAGS_X87_FLAGS = (1ULL << 10);
|
||||
|
||||
// Non-XMM subflags
|
||||
constexpr InstFlagType FLAGS_SF_DST_RAX = (1ULL << 11);
|
||||
constexpr InstFlagType FLAGS_SF_DST_RDX = (1ULL << 12);
|
||||
constexpr InstFlagType FLAGS_SF_SRC_RAX = (1ULL << 13);
|
||||
constexpr InstFlagType FLAGS_SF_SRC_RCX = (1ULL << 14);
|
||||
constexpr InstFlagType FLAGS_SF_REX_IN_BYTE = (1ULL << 15);
|
||||
constexpr InstFlagType FLAGS_SF_DST_RAX = (1ULL << 11);
|
||||
constexpr InstFlagType FLAGS_SF_DST_RDX = (1ULL << 12);
|
||||
constexpr InstFlagType FLAGS_SF_SRC_RAX = (1ULL << 13);
|
||||
constexpr InstFlagType FLAGS_SF_SRC_RCX = (1ULL << 14);
|
||||
constexpr InstFlagType FLAGS_SF_REX_IN_BYTE = (1ULL << 15);
|
||||
|
||||
// XMM subflags
|
||||
constexpr InstFlagType FLAGS_SF_UNUSED = (1ULL << 11); // No assigned behavior yet
|
||||
constexpr InstFlagType FLAGS_SF_DST_GPR = (1ULL << 12);
|
||||
constexpr InstFlagType FLAGS_SF_SRC_GPR = (1ULL << 13);
|
||||
constexpr InstFlagType FLAGS_SF_MMX_DST = (1ULL << 14);
|
||||
constexpr InstFlagType FLAGS_SF_MMX_SRC = (1ULL << 15);
|
||||
constexpr InstFlagType FLAGS_SF_MMX = FLAGS_SF_MMX_DST | FLAGS_SF_MMX_SRC;
|
||||
constexpr InstFlagType FLAGS_SF_UNUSED = (1ULL << 11); // No assigned behavior yet
|
||||
constexpr InstFlagType FLAGS_SF_DST_GPR = (1ULL << 12);
|
||||
constexpr InstFlagType FLAGS_SF_SRC_GPR = (1ULL << 13);
|
||||
constexpr InstFlagType FLAGS_SF_MMX_DST = (1ULL << 14);
|
||||
constexpr InstFlagType FLAGS_SF_MMX_SRC = (1ULL << 15);
|
||||
constexpr InstFlagType FLAGS_SF_MMX = FLAGS_SF_MMX_DST | FLAGS_SF_MMX_SRC;
|
||||
|
||||
// Enables MODRM specific subflags
|
||||
// Current reserved range for this SF is [14, 17]
|
||||
constexpr InstFlagType FLAGS_MODRM = (1ULL << 16);
|
||||
// Enables MODRM specific subflags
|
||||
// Current reserved range for this SF is [14, 17]
|
||||
constexpr InstFlagType FLAGS_MODRM = (1ULL << 16);
|
||||
|
||||
// With ModRM SF flag enabled
|
||||
// Direction of ModRM. Dst ^ Src
|
||||
// Set means destination is rm bits
|
||||
// Unset means src is rm bits
|
||||
constexpr InstFlagType FLAGS_SF_MOD_DST = (1ULL << 17);
|
||||
constexpr InstFlagType FLAGS_SF_MOD_DST = (1ULL << 17);
|
||||
|
||||
// If the instruction is restricted to mem or reg only
|
||||
// 0b00 = Regular ModRM support
|
||||
// 0b01 = Memory accesses only
|
||||
// 0b10 = Register accesses only
|
||||
// 0b11 = <Reserved>
|
||||
constexpr InstFlagType FLAGS_SF_MOD_MEM_ONLY = (1ULL << 18);
|
||||
constexpr InstFlagType FLAGS_SF_MOD_REG_ONLY = (1ULL << 19);
|
||||
constexpr InstFlagType FLAGS_SF_MOD_MEM_ONLY = (1ULL << 18);
|
||||
constexpr InstFlagType FLAGS_SF_MOD_REG_ONLY = (1ULL << 19);
|
||||
|
||||
constexpr InstFlagType FLAGS_SF_MOD_ZERO_REG = (1ULL << 20);
|
||||
constexpr InstFlagType FLAGS_SF_MOD_ZERO_REG = (1ULL << 20);
|
||||
|
||||
// x87
|
||||
constexpr InstFlagType FLAGS_POP = (1ULL << 21);
|
||||
// x87
|
||||
constexpr InstFlagType FLAGS_POP = (1ULL << 21);
|
||||
|
||||
// Whether or not the instruction has a VEX prefix for the dest, first, or second source.
|
||||
constexpr InstFlagType FLAGS_VEX_SRC_MASK = (0b11ULL << 22);
|
||||
constexpr InstFlagType FLAGS_VEX_NO_OPERAND = (0b00ULL << 22);
|
||||
constexpr InstFlagType FLAGS_VEX_DST = (0b01ULL << 22);
|
||||
constexpr InstFlagType FLAGS_VEX_1ST_SRC = (0b10ULL << 22);
|
||||
constexpr InstFlagType FLAGS_VEX_2ND_SRC = (0b11ULL << 22);
|
||||
// Whether or not the instruction has a VSIB byte
|
||||
constexpr InstFlagType FLAGS_VEX_VSIB = (1ULL << 24);
|
||||
constexpr InstFlagType FLAGS_VEX_L_IGNORE = (1ULL << 25);
|
||||
constexpr InstFlagType FLAGS_VEX_L_0 = (1ULL << 26);
|
||||
constexpr InstFlagType FLAGS_VEX_L_1 = (1ULL << 27);
|
||||
// Whether or not the instruction has a VEX prefix for the dest, first, or second source.
|
||||
constexpr InstFlagType FLAGS_VEX_SRC_MASK = (0b11ULL << 22);
|
||||
constexpr InstFlagType FLAGS_VEX_NO_OPERAND = (0b00ULL << 22);
|
||||
constexpr InstFlagType FLAGS_VEX_DST = (0b01ULL << 22);
|
||||
constexpr InstFlagType FLAGS_VEX_1ST_SRC = (0b10ULL << 22);
|
||||
constexpr InstFlagType FLAGS_VEX_2ND_SRC = (0b11ULL << 22);
|
||||
// Whether or not the instruction has a VSIB byte
|
||||
constexpr InstFlagType FLAGS_VEX_VSIB = (1ULL << 24);
|
||||
constexpr InstFlagType FLAGS_VEX_L_IGNORE = (1ULL << 25);
|
||||
constexpr InstFlagType FLAGS_VEX_L_0 = (1ULL << 26);
|
||||
constexpr InstFlagType FLAGS_VEX_L_1 = (1ULL << 27);
|
||||
|
||||
constexpr InstFlagType FLAGS_REX_W_0 = (1ULL << 28);
|
||||
constexpr InstFlagType FLAGS_REX_W_1 = (1ULL << 29);
|
||||
constexpr InstFlagType FLAGS_REX_W_0 = (1ULL << 28);
|
||||
constexpr InstFlagType FLAGS_REX_W_1 = (1ULL << 29);
|
||||
|
||||
constexpr InstFlagType FLAGS_CALL = (1ULL << 30);
|
||||
constexpr InstFlagType FLAGS_CALL = (1ULL << 30);
|
||||
|
||||
constexpr InstFlagType FLAGS_SIZE_DST_OFF = 58;
|
||||
constexpr InstFlagType FLAGS_SIZE_SRC_OFF = FLAGS_SIZE_DST_OFF + 3;
|
||||
constexpr InstFlagType FLAGS_SIZE_DST_OFF = 58;
|
||||
constexpr InstFlagType FLAGS_SIZE_SRC_OFF = FLAGS_SIZE_DST_OFF + 3;
|
||||
|
||||
constexpr InstFlagType SIZE_MASK = 0b111;
|
||||
constexpr InstFlagType SIZE_DEF = 0b000;
|
||||
constexpr InstFlagType SIZE_8BIT = 0b001;
|
||||
constexpr InstFlagType SIZE_16BIT = 0b010;
|
||||
constexpr InstFlagType SIZE_32BIT = 0b011;
|
||||
constexpr InstFlagType SIZE_64BIT = 0b100;
|
||||
constexpr InstFlagType SIZE_128BIT = 0b101;
|
||||
constexpr InstFlagType SIZE_256BIT = 0b110;
|
||||
constexpr InstFlagType SIZE_64BITDEF = 0b111; // Default mode is 64bit instead of typical 32bit
|
||||
constexpr InstFlagType SIZE_MASK = 0b111;
|
||||
constexpr InstFlagType SIZE_DEF = 0b000;
|
||||
constexpr InstFlagType SIZE_8BIT = 0b001;
|
||||
constexpr InstFlagType SIZE_16BIT = 0b010;
|
||||
constexpr InstFlagType SIZE_32BIT = 0b011;
|
||||
constexpr InstFlagType SIZE_64BIT = 0b100;
|
||||
constexpr InstFlagType SIZE_128BIT = 0b101;
|
||||
constexpr InstFlagType SIZE_256BIT = 0b110;
|
||||
constexpr InstFlagType SIZE_64BITDEF = 0b111; // Default mode is 64bit instead of typical 32bit
|
||||
|
||||
#ifndef _WIN32
|
||||
constexpr uint32_t DEFAULT_SYSCALL_FLAGS = FLAGS_NO_OVERLAY;
|
||||
#else
|
||||
// Syscall ends a block on WIN32 because the instruction can update the CPU's RIP.
|
||||
// Syscall ends a block on WIN32 because the instruction can update the CPU's RIP.
|
||||
constexpr uint32_t DEFAULT_SYSCALL_FLAGS = FLAGS_NO_OVERLAY | FLAGS_BLOCK_END;
|
||||
#endif
|
||||
|
||||
constexpr InstFlagType GetSizeDstFlags(InstFlagType Flags) { return (Flags >> FLAGS_SIZE_DST_OFF) & SIZE_MASK; }
|
||||
constexpr InstFlagType GetSizeSrcFlags(InstFlagType Flags) { return (Flags >> FLAGS_SIZE_SRC_OFF) & SIZE_MASK; }
|
||||
constexpr InstFlagType GetSizeDstFlags(InstFlagType Flags) {
|
||||
return (Flags >> FLAGS_SIZE_DST_OFF) & SIZE_MASK;
|
||||
}
|
||||
constexpr InstFlagType GetSizeSrcFlags(InstFlagType Flags) {
|
||||
return (Flags >> FLAGS_SIZE_SRC_OFF) & SIZE_MASK;
|
||||
}
|
||||
|
||||
constexpr InstFlagType GenFlagsDstSize(InstFlagType Size) { return Size << FLAGS_SIZE_DST_OFF; }
|
||||
constexpr InstFlagType GenFlagsSrcSize(InstFlagType Size) { return Size << FLAGS_SIZE_SRC_OFF; }
|
||||
constexpr InstFlagType GenFlagsSameSize(InstFlagType Size) { return (Size << FLAGS_SIZE_DST_OFF) | (Size << FLAGS_SIZE_SRC_OFF); }
|
||||
constexpr InstFlagType GenFlagsSizes(InstFlagType Dest, InstFlagType Src) { return (Dest << FLAGS_SIZE_DST_OFF) | (Src << FLAGS_SIZE_SRC_OFF); }
|
||||
constexpr InstFlagType GenFlagsDstSize(InstFlagType Size) {
|
||||
return Size << FLAGS_SIZE_DST_OFF;
|
||||
}
|
||||
constexpr InstFlagType GenFlagsSrcSize(InstFlagType Size) {
|
||||
return Size << FLAGS_SIZE_SRC_OFF;
|
||||
}
|
||||
constexpr InstFlagType GenFlagsSameSize(InstFlagType Size) {
|
||||
return (Size << FLAGS_SIZE_DST_OFF) | (Size << FLAGS_SIZE_SRC_OFF);
|
||||
}
|
||||
constexpr InstFlagType GenFlagsSizes(InstFlagType Dest, InstFlagType Src) {
|
||||
return (Dest << FLAGS_SIZE_DST_OFF) | (Src << FLAGS_SIZE_SRC_OFF);
|
||||
}
|
||||
|
||||
// If it has an xmm subflag
|
||||
#define HAS_XMM_SUBFLAG(x, flag) (((x) & (FEXCore::X86Tables::InstFlags::FLAGS_XMM_FLAGS | (flag))) == (FEXCore::X86Tables::InstFlags::FLAGS_XMM_FLAGS | (flag)))
|
||||
#define HAS_XMM_SUBFLAG(x, flag) \
|
||||
(((x) & (FEXCore::X86Tables::InstFlags::FLAGS_XMM_FLAGS | (flag))) == (FEXCore::X86Tables::InstFlags::FLAGS_XMM_FLAGS | (flag)))
|
||||
|
||||
// If it has non-xmm subflag
|
||||
#define HAS_NON_XMM_SUBFLAG(x, flag) (((x) & (FEXCore::X86Tables::InstFlags::FLAGS_XMM_FLAGS | (flag))) == (flag))
|
||||
}
|
||||
} // namespace InstFlags
|
||||
|
||||
constexpr uint8_t OpToIndex(uint8_t Op) {
|
||||
switch (Op) {
|
||||
@@ -450,32 +469,30 @@ constexpr uint8_t OpToIndex(uint8_t Op) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
using DecodedOp = DecodedInst const*;
|
||||
using DecodedOp = const DecodedInst*;
|
||||
using OpDispatchPtr = void (IR::OpDispatchBuilder::*)(DecodedOp);
|
||||
|
||||
union OpDispatchPtrWrapper {
|
||||
OpDispatchPtr OpDispatch;
|
||||
const struct X86InstInfo *Indirect;
|
||||
const struct X86InstInfo* Indirect;
|
||||
};
|
||||
|
||||
struct X86InstInfo {
|
||||
char const *Name;
|
||||
const char* Name;
|
||||
InstType Type;
|
||||
InstFlags::InstFlagType Flags; ///< Must be larger than InstFlags enum
|
||||
uint8_t MoreBytes;
|
||||
OpDispatchPtrWrapper OpcodeDispatcher;
|
||||
|
||||
bool operator==(const X86InstInfo &b) const {
|
||||
if (strcmp(Name, b.Name) != 0 ||
|
||||
Type != b.Type ||
|
||||
Flags != b.Flags ||
|
||||
MoreBytes != b.MoreBytes)
|
||||
bool operator==(const X86InstInfo& b) const {
|
||||
if (strcmp(Name, b.Name) != 0 || Type != b.Type || Flags != b.Flags || MoreBytes != b.MoreBytes) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We don't care if the opcode dispatcher differs
|
||||
return true;
|
||||
}
|
||||
bool operator!=(const X86InstInfo &b) const {
|
||||
bool operator!=(const X86InstInfo& b) const {
|
||||
return !operator==(b);
|
||||
}
|
||||
};
|
||||
@@ -527,7 +544,7 @@ extern const std::array<X86InstInfo, MAX_VEX_GROUP_TABLE_SIZE> VEXTableGroupOps;
|
||||
extern const std::array<X86InstInfo, MAX_VEX_TABLE_SIZE> VEXTableOps_AVX128;
|
||||
extern const std::array<X86InstInfo, MAX_VEX_GROUP_TABLE_SIZE> VEXTableGroupOps_AVX128;
|
||||
|
||||
template <typename OpcodeType>
|
||||
template<typename OpcodeType>
|
||||
struct X86TablesInfoStruct {
|
||||
OpcodeType first;
|
||||
uint8_t second;
|
||||
@@ -537,11 +554,11 @@ using U8U8InfoStruct = X86TablesInfoStruct<uint8_t>;
|
||||
using U16U8InfoStruct = X86TablesInfoStruct<uint16_t>;
|
||||
|
||||
template<typename OpcodeType>
|
||||
constexpr static inline void GenerateTable(X86InstInfo *FinalTable, X86TablesInfoStruct<OpcodeType> const *LocalTable, size_t TableSize) {
|
||||
constexpr static inline void GenerateTable(X86InstInfo* FinalTable, const X86TablesInfoStruct<OpcodeType>* LocalTable, size_t TableSize) {
|
||||
for (size_t j = 0; j < TableSize; ++j) {
|
||||
X86TablesInfoStruct<OpcodeType> const &Op = LocalTable[j];
|
||||
const X86TablesInfoStruct<OpcodeType>& Op = LocalTable[j];
|
||||
auto OpNum = Op.first;
|
||||
X86InstInfo const &Info = Op.Info;
|
||||
const X86InstInfo& Info = Op.Info;
|
||||
for (uint32_t i = 0; i < Op.second; ++i) {
|
||||
if (FinalTable[OpNum + i].Type != TYPE_UNKNOWN) {
|
||||
LOGMAN_MSG_A_FMT("Duplicate Entry {}->{}", FinalTable[OpNum + i].Name, Info.Name);
|
||||
@@ -555,19 +572,19 @@ constexpr static inline void GenerateTable(X86InstInfo *FinalTable, X86TablesInf
|
||||
};
|
||||
|
||||
template<typename OpcodeType>
|
||||
constexpr static inline void GenerateTableWithCopy(X86InstInfo *FinalTable, X86TablesInfoStruct<OpcodeType> const *LocalTable, size_t TableSize, const X86InstInfo *OtherLocal) {
|
||||
constexpr static inline void GenerateTableWithCopy(X86InstInfo* FinalTable, const X86TablesInfoStruct<OpcodeType>* LocalTable,
|
||||
size_t TableSize, const X86InstInfo* OtherLocal) {
|
||||
for (size_t j = 0; j < TableSize; ++j) {
|
||||
X86TablesInfoStruct<OpcodeType> const &Op = LocalTable[j];
|
||||
const X86TablesInfoStruct<OpcodeType>& Op = LocalTable[j];
|
||||
auto OpNum = Op.first;
|
||||
X86InstInfo const &Info = Op.Info;
|
||||
const X86InstInfo& Info = Op.Info;
|
||||
for (uint32_t i = 0; i < Op.second; ++i) {
|
||||
if (FinalTable[OpNum + i].Type != TYPE_UNKNOWN) {
|
||||
LOGMAN_MSG_A_FMT("Duplicate Entry {}->{}", FinalTable[OpNum + i].Name, Info.Name);
|
||||
}
|
||||
if (Info.Type == TYPE_COPY_OTHER) {
|
||||
FinalTable[OpNum + i] = OtherLocal[OpNum + i];
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
FinalTable[OpNum + i] = Info;
|
||||
}
|
||||
}
|
||||
@@ -575,11 +592,11 @@ constexpr static inline void GenerateTableWithCopy(X86InstInfo *FinalTable, X86T
|
||||
};
|
||||
|
||||
template<typename OpcodeType>
|
||||
constexpr static inline void GenerateX87Table(X86InstInfo *FinalTable, X86TablesInfoStruct<OpcodeType> const *LocalTable, size_t TableSize) {
|
||||
constexpr static inline void GenerateX87Table(X86InstInfo* FinalTable, const X86TablesInfoStruct<OpcodeType>* LocalTable, size_t TableSize) {
|
||||
for (size_t j = 0; j < TableSize; ++j) {
|
||||
X86TablesInfoStruct<OpcodeType> const &Op = LocalTable[j];
|
||||
const X86TablesInfoStruct<OpcodeType>& Op = LocalTable[j];
|
||||
auto OpNum = Op.first;
|
||||
X86InstInfo const &Info = Op.Info;
|
||||
const X86InstInfo& Info = Op.Info;
|
||||
for (uint32_t i = 0; i < Op.second; ++i) {
|
||||
if (FinalTable[OpNum + i].Type != TYPE_UNKNOWN) {
|
||||
LOGMAN_MSG_A_FMT("Duplicate Entry {}->{}", FinalTable[OpNum + i].Name, Info.Name);
|
||||
@@ -587,8 +604,7 @@ constexpr static inline void GenerateX87Table(X86InstInfo *FinalTable, X86Tables
|
||||
if ((OpNum & 0b11'000'000) == 0b11'000'000) {
|
||||
// If the mod field is 0b11 then it is a regular op
|
||||
FinalTable[OpNum + i] = Info;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// If the mod field is !0b11 then this instruction is duplicated through the whole mod [0b00, 0b10] range
|
||||
// and the modrm.rm space because that is used part of the instruction encoding
|
||||
if ((OpNum & 0b11'000'000) != 0) {
|
||||
|
||||
@@ -17,7 +17,7 @@ using namespace IR;
|
||||
// All OPDReg versions need it
|
||||
#define OPDReg(op, reg) ((1 << 15) | ((op - 0xD8) << 8) | (reg << 3))
|
||||
#define OPD(op, modrmop) (((op - 0xD8) << 8) | modrmop)
|
||||
constexpr std::array<DispatchTableEntry, 133> X87F64OpTable = {{
|
||||
constexpr std::array<DispatchTableEntry, 140> X87F64OpTable = {{
|
||||
{OPDReg(0xD8, 0) | 0x00, 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FADDF64, OpSize::i32Bit, false, OpDispatchBuilder::OpResult::RES_ST0>},
|
||||
|
||||
{OPDReg(0xD8, 1) | 0x00, 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FMULF64, OpSize::i32Bit, false, OpDispatchBuilder::OpResult::RES_ST0>},
|
||||
@@ -194,6 +194,10 @@ constexpr std::array<DispatchTableEntry, 133> X87F64OpTable = {{
|
||||
|
||||
{OPD(0xDC, 0xC0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FADDF64, OpSize::f80Bit, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDC, 0xC8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FMULF64, OpSize::f80Bit, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDC, 0xD0), 8,
|
||||
&OpDispatchBuilder::Bind<&OpDispatchBuilder::FCOMIF64, OpSize::f80Bit, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>},
|
||||
{OPD(0xDC, 0xD8), 8,
|
||||
&OpDispatchBuilder::Bind<&OpDispatchBuilder::FCOMIF64, OpSize::f80Bit, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>},
|
||||
{OPD(0xDC, 0xE0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSUBF64, OpSize::f80Bit, false, true, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDC, 0xE8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSUBF64, OpSize::f80Bit, false, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDC, 0xF0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FDIVF64, OpSize::f80Bit, false, true, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
@@ -215,6 +219,7 @@ constexpr std::array<DispatchTableEntry, 133> X87F64OpTable = {{
|
||||
{OPDReg(0xDD, 7) | 0x00, 8, &OpDispatchBuilder::X87FNSTSW},
|
||||
|
||||
{OPD(0xDD, 0xC0), 8, &OpDispatchBuilder::X87FFREE},
|
||||
{OPD(0xDD, 0xC8), 8, &OpDispatchBuilder::FXCH},
|
||||
{OPD(0xDD, 0xD0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSTToStack>}, // register-register from regular X87
|
||||
{OPD(0xDD, 0xD8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSTToStack>}, //^
|
||||
|
||||
@@ -247,6 +252,8 @@ constexpr std::array<DispatchTableEntry, 133> X87F64OpTable = {{
|
||||
|
||||
{OPD(0xDE, 0xC0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FADDF64, OpSize::f80Bit, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDE, 0xC8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FMULF64, OpSize::f80Bit, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDE, 0xD0), 8,
|
||||
&OpDispatchBuilder::Bind<&OpDispatchBuilder::FCOMIF64, OpSize::f80Bit, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>},
|
||||
{OPD(0xDE, 0xD9), 1,
|
||||
&OpDispatchBuilder::Bind<&OpDispatchBuilder::FCOMIF64, OpSize::f80Bit, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, true>},
|
||||
{OPD(0xDE, 0xE0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSUBF64, OpSize::f80Bit, false, true, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
@@ -273,6 +280,9 @@ constexpr std::array<DispatchTableEntry, 133> X87F64OpTable = {{
|
||||
// XXX: This should also set the x87 tag bits to empty
|
||||
// We don't support this currently, so just pop the stack
|
||||
{OPD(0xDF, 0xC0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87ModifySTP, true>},
|
||||
{OPD(0xDF, 0xC8), 8, &OpDispatchBuilder::FXCH},
|
||||
{OPD(0xDF, 0xD0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSTToStack>},
|
||||
{OPD(0xDF, 0xD8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSTToStack>},
|
||||
|
||||
{OPD(0xDF, 0xE0), 8, &OpDispatchBuilder::X87FNSTSW},
|
||||
{OPD(0xDF, 0xE8), 8,
|
||||
@@ -281,7 +291,7 @@ constexpr std::array<DispatchTableEntry, 133> X87F64OpTable = {{
|
||||
&OpDispatchBuilder::Bind<&OpDispatchBuilder::FCOMIF64, OpSize::f80Bit, false, OpDispatchBuilder::FCOMIFlags::FLAGS_RFLAGS, false>},
|
||||
}};
|
||||
|
||||
constexpr std::array<DispatchTableEntry, 133> X87F80OpTable = {{
|
||||
constexpr std::array<DispatchTableEntry, 140> X87F80OpTable = {{
|
||||
{OPDReg(0xD8, 0) | 0x00, 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FADD, OpSize::i32Bit, false, OpDispatchBuilder::OpResult::RES_ST0>},
|
||||
|
||||
{OPDReg(0xD8, 1) | 0x00, 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FMUL, OpSize::i32Bit, false, OpDispatchBuilder::OpResult::RES_ST0>},
|
||||
@@ -453,6 +463,8 @@ constexpr std::array<DispatchTableEntry, 133> X87F80OpTable = {{
|
||||
|
||||
{OPD(0xDC, 0xC0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FADD, OpSize::f80Bit, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDC, 0xC8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FMUL, OpSize::f80Bit, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDC, 0xD0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FCOMI, OpSize::f80Bit, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>},
|
||||
{OPD(0xDC, 0xD8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FCOMI, OpSize::f80Bit, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>},
|
||||
{OPD(0xDC, 0xE0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSUB, OpSize::f80Bit, false, true, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDC, 0xE8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSUB, OpSize::f80Bit, false, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDC, 0xF0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FDIV, OpSize::f80Bit, false, true, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
@@ -474,6 +486,7 @@ constexpr std::array<DispatchTableEntry, 133> X87F80OpTable = {{
|
||||
{OPDReg(0xDD, 7) | 0x00, 8, &OpDispatchBuilder::X87FNSTSW},
|
||||
|
||||
{OPD(0xDD, 0xC0), 8, &OpDispatchBuilder::X87FFREE},
|
||||
{OPD(0xDD, 0xC8), 8, &OpDispatchBuilder::FXCH},
|
||||
{OPD(0xDD, 0xD0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSTToStack>},
|
||||
{OPD(0xDD, 0xD8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSTToStack>},
|
||||
|
||||
@@ -502,6 +515,7 @@ constexpr std::array<DispatchTableEntry, 133> X87F80OpTable = {{
|
||||
|
||||
{OPD(0xDE, 0xC0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FADD, OpSize::f80Bit, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDE, 0xC8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FMUL, OpSize::f80Bit, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDE, 0xD0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FCOMI, OpSize::f80Bit, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, false>},
|
||||
{OPD(0xDE, 0xD9), 1, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FCOMI, OpSize::f80Bit, false, OpDispatchBuilder::FCOMIFlags::FLAGS_X87, true>},
|
||||
{OPD(0xDE, 0xE0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSUB, OpSize::f80Bit, false, true, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
{OPD(0xDE, 0xE8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSUB, OpSize::f80Bit, false, false, OpDispatchBuilder::OpResult::RES_STI>},
|
||||
@@ -527,6 +541,9 @@ constexpr std::array<DispatchTableEntry, 133> X87F80OpTable = {{
|
||||
// XXX: This should also set the x87 tag bits to empty
|
||||
// We don't support this currently, so just pop the stack
|
||||
{OPD(0xDF, 0xC0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::X87ModifySTP, true>},
|
||||
{OPD(0xDF, 0xC8), 8, &OpDispatchBuilder::FXCH},
|
||||
{OPD(0xDF, 0xD0), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSTToStack>},
|
||||
{OPD(0xDF, 0xD8), 8, &OpDispatchBuilder::Bind<&OpDispatchBuilder::FSTToStack>},
|
||||
|
||||
{OPD(0xDF, 0xE0), 8, &OpDispatchBuilder::X87FNSTSW},
|
||||
{OPD(0xDF, 0xE8), 8,
|
||||
@@ -688,9 +705,9 @@ auto GenerateX87TableLambda = [](const auto DispatchTable) consteval {
|
||||
// / 1
|
||||
{OPD(0xDC, 0xC8), 8, X86InstInfo{"FMUL", TYPE_X87, FLAGS_NONE, 0}},
|
||||
// / 2
|
||||
{OPD(0xDC, 0xD0), 8, X86InstInfo{"", TYPE_INVALID, FLAGS_NONE, 0}},
|
||||
{OPD(0xDC, 0xD0), 8, X86InstInfo{"FCOM", TYPE_X87, FLAGS_X87_FLAGS, 0}},
|
||||
// / 3
|
||||
{OPD(0xDC, 0xD8), 8, X86InstInfo{"", TYPE_INVALID, FLAGS_NONE, 0}},
|
||||
{OPD(0xDC, 0xD8), 8, X86InstInfo{"FCOMP", TYPE_X87, FLAGS_X87_FLAGS | FLAGS_POP, 0}},
|
||||
// / 4
|
||||
{OPD(0xDC, 0xE0), 8, X86InstInfo{"FSUBR", TYPE_X87, FLAGS_NONE, 0}},
|
||||
// / 5
|
||||
@@ -711,7 +728,7 @@ auto GenerateX87TableLambda = [](const auto DispatchTable) consteval {
|
||||
// / 0
|
||||
{OPD(0xDD, 0xC0), 8, X86InstInfo{"FFREE", TYPE_X87, FLAGS_NONE, 0}},
|
||||
// / 1
|
||||
{OPD(0xDD, 0xC8), 8, X86InstInfo{"", TYPE_INVALID, FLAGS_NONE, 0}},
|
||||
{OPD(0xDD, 0xC8), 8, X86InstInfo{"FXCH", TYPE_X87, FLAGS_NONE, 0}},
|
||||
// / 2
|
||||
{OPD(0xDD, 0xD0), 8, X86InstInfo{"FST", TYPE_INST, FLAGS_SF_MOD_DST, 0}},
|
||||
// / 3
|
||||
@@ -738,7 +755,7 @@ auto GenerateX87TableLambda = [](const auto DispatchTable) consteval {
|
||||
// / 1
|
||||
{OPD(0xDE, 0xC8), 8, X86InstInfo{"FMULP", TYPE_X87, FLAGS_POP, 0}},
|
||||
// / 2
|
||||
{OPD(0xDE, 0xD0), 8, X86InstInfo{"", TYPE_INVALID, FLAGS_NONE, 0}},
|
||||
{OPD(0xDE, 0xD0), 8, X86InstInfo{"FCOMP", TYPE_X87, FLAGS_X87_FLAGS | FLAGS_POP, 0}},
|
||||
// / 3
|
||||
{OPD(0xDE, 0xD8), 1, X86InstInfo{"", TYPE_INVALID, FLAGS_NONE, 0}},
|
||||
{OPD(0xDE, 0xD9), 1, X86InstInfo{"FCOMPP", TYPE_X87, FLAGS_POP, 0}},
|
||||
@@ -771,11 +788,11 @@ auto GenerateX87TableLambda = [](const auto DispatchTable) consteval {
|
||||
// Almost all x86 CPUs implement this, and it is expected to be around
|
||||
{OPD(0xDF, 0xC0), 8, X86InstInfo{"FFREEP", TYPE_X87, FLAGS_POP, 0}},
|
||||
// / 1
|
||||
{OPD(0xDF, 0xC8), 8, X86InstInfo{"", TYPE_INVALID, FLAGS_NONE, 0}},
|
||||
{OPD(0xDF, 0xC8), 8, X86InstInfo{"FXCH", TYPE_X87, FLAGS_NONE, 0}},
|
||||
// / 2
|
||||
{OPD(0xDF, 0xD0), 8, X86InstInfo{"", TYPE_INVALID, FLAGS_NONE, 0}},
|
||||
{OPD(0xDF, 0xD0), 8, X86InstInfo{"FSTP", TYPE_X87, FLAGS_SF_MOD_DST | FLAGS_POP, 0}},
|
||||
// / 3
|
||||
{OPD(0xDF, 0xD8), 8, X86InstInfo{"", TYPE_INVALID, FLAGS_NONE, 0}},
|
||||
{OPD(0xDF, 0xD8), 8, X86InstInfo{"FSTP", TYPE_X87, FLAGS_SF_MOD_DST | FLAGS_POP, 0}},
|
||||
// / 4
|
||||
{OPD(0xDF, 0xE0), 1, X86InstInfo{"FNSTSW", TYPE_INST, GenFlagsSameSize(SIZE_16BIT) | FLAGS_SF_DST_RAX, 0}},
|
||||
{OPD(0xDF, 0xE1), 7, X86InstInfo{"", TYPE_INVALID, FLAGS_NONE, 0}},
|
||||
|
||||
@@ -488,7 +488,7 @@
|
||||
"HasSideEffects": true,
|
||||
"Desc": ["Spills an SSA value to memory",
|
||||
"Spill slots are register allocated and has live ranges calculated to handle slot calculation",
|
||||
"```diff\n- !Don't use this op. It is for RA to handle spilling and filling!\n```"
|
||||
"!Don't use this op. It is for RA to handle spilling and filling!"
|
||||
],
|
||||
"EmitValidation": [
|
||||
"WalkFindRegClass($Value) == $Class"
|
||||
@@ -498,7 +498,7 @@
|
||||
"SSA = FillRegister OpSize:#Size, OpSize:#ElementSize, u32:$Slot, RegisterClass:$Class": {
|
||||
"Desc": ["Fills a register from a spill slot",
|
||||
"Spill slots are register allocated and has live ranges calculated to handle slot calculation",
|
||||
"```diff\n- !Don't use this op. It is for RA to handle spilling and filling!\n```"
|
||||
"!Don't use this op. It is for RA to handle spilling and filling!"
|
||||
],
|
||||
"DestSize": "Size",
|
||||
"ElementSize": "ElementSize"
|
||||
@@ -777,6 +777,17 @@
|
||||
"RegisterSize == FEXCore::IR::OpSize::i128Bit || RegisterSize == FEXCore::IR::OpSize::i256Bit",
|
||||
"Offset % IR::OpSizeToSize(RegisterSize) == 0"
|
||||
]
|
||||
},
|
||||
"ContextClear u32:$Offset, u32:$Size": {
|
||||
"Desc": [
|
||||
"Clears a region of the context by CLZero size",
|
||||
"Both the offset and size alignment need to be by CLZero size"
|
||||
],
|
||||
"HasSideEffects": true,
|
||||
"EmitValidation": [
|
||||
"Offset % 64 == 0",
|
||||
"Size % 64 == 0"
|
||||
]
|
||||
}
|
||||
},
|
||||
"Atomic": {
|
||||
@@ -2151,6 +2162,14 @@
|
||||
]
|
||||
},
|
||||
|
||||
"FPR = VOrn OpSize:#RegisterSize, OpSize:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
||||
"DestSize": "RegisterSize",
|
||||
"ElementSize": "ElementSize",
|
||||
"EmitValidation": [
|
||||
"RegisterSize == FEXCore::IR::OpSize::i256Bit || RegisterSize == FEXCore::IR::OpSize::i128Bit || RegisterSize == FEXCore::IR::OpSize::i64Bit"
|
||||
]
|
||||
},
|
||||
|
||||
"FPR = VOr OpSize:#RegisterSize, OpSize:#ElementSize, FPR:$Vector1, FPR:$Vector2": {
|
||||
"DestSize": "RegisterSize",
|
||||
"ElementSize": "ElementSize",
|
||||
|
||||
@@ -59,7 +59,14 @@ void* FEX_mmap(void* addr, size_t length, int prot, int flags, int fd, off_t off
|
||||
}
|
||||
|
||||
void VirtualName(const char* Name, void* Ptr, size_t Size) {
|
||||
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, Ptr, Size, Name);
|
||||
static bool Supports {true};
|
||||
if (Supports) {
|
||||
auto Result = prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, Ptr, Size, Name);
|
||||
if (Result == -1) {
|
||||
// Disable any additional attempts.
|
||||
Supports = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int FEX_munmap(void* addr, size_t length) {
|
||||
@@ -72,71 +79,23 @@ int FEX_munmap(void* addr, size_t length) {
|
||||
return Result;
|
||||
}
|
||||
|
||||
// This function disables glibc's ability to allocate memory through the `sbrk` interface.
|
||||
// This is run early in the lifecycle of FEX in order to make sure no 64-bit pointers can make it to the guest 32-bit application.
|
||||
//
|
||||
// How this works is that this allocates a single page at the current sbrk pointer (aligned upward to page size). This makes it
|
||||
// so that when the sbrk syscall is used to allocate more memory, it fails with an ENOMEM since it runs in to the allocated guard page.
|
||||
//
|
||||
// glibc notices the sbrk failure and falls back to regular mmap based allocations when this occurs. Ensuring that memory can still be allocated.
|
||||
void* DisableSBRKAllocations() {
|
||||
void* INVALID_PTR = reinterpret_cast<void*>(~0ULL);
|
||||
// Get the starting sbrk pointer.
|
||||
void* StartingSBRK = sbrk(0);
|
||||
if (StartingSBRK == INVALID_PTR) {
|
||||
// If sbrk is already returning invalid pointers then nothing to do here.
|
||||
return INVALID_PTR;
|
||||
}
|
||||
|
||||
// Now allocate the next page after the sbrk address to ensure it can't grow.
|
||||
// In most cases at the start of `main` this will already be page aligned, which means subsequent `sbrk`
|
||||
// calls won't allocate any memory through that.
|
||||
void* AlignedBRK = reinterpret_cast<void*>(FEXCore::AlignUp(reinterpret_cast<uintptr_t>(StartingSBRK), FEXCore::Utils::FEX_PAGE_SIZE));
|
||||
void* AfterBRK =
|
||||
::mmap(AlignedBRK, FEXCore::Utils::FEX_PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE | MAP_NORESERVE, -1, 0);
|
||||
if (AfterBRK == INVALID_PTR) {
|
||||
// Couldn't allocate the page after the aligned brk? This should never happen.
|
||||
// FEXCore::LogMan isn't configured yet so we just need to print the message.
|
||||
fextl::fmt::print("Couldn't allocate page after SBRK.\n");
|
||||
FEX_TRAP_EXECUTION;
|
||||
return INVALID_PTR;
|
||||
}
|
||||
|
||||
// Now that the page after sbrk is allocated, FEX needs to consume the remaining sbrk space.
|
||||
// This will be anywhere from [0, 4096) bytes.
|
||||
// Start allocating from 1024 byte increments just to make any steps a bit faster.
|
||||
intptr_t IncrementAmount = 1024;
|
||||
for (; IncrementAmount != 0; IncrementAmount >>= 1) {
|
||||
while (sbrk(IncrementAmount) != INVALID_PTR)
|
||||
;
|
||||
}
|
||||
return AlignedBRK;
|
||||
}
|
||||
|
||||
void ReenableSBRKAllocations(void* Ptr) {
|
||||
const void* INVALID_PTR = reinterpret_cast<void*>(~0ULL);
|
||||
if (Ptr != INVALID_PTR) {
|
||||
munmap(Ptr, FEXCore::Utils::FEX_PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
static void AssignHookOverrides() {
|
||||
SetJemallocMmapHook(FEX_mmap);
|
||||
SetJemallocMunmapHook(FEX_munmap);
|
||||
|
||||
static void AssignHookOverrides(size_t PageSize) {
|
||||
SetupAllocatorHooks(FEX_mmap, FEX_munmap);
|
||||
FEXCore::Allocator::mmap = FEX_mmap;
|
||||
FEXCore::Allocator::munmap = FEX_munmap;
|
||||
InitializeAllocator(PageSize);
|
||||
}
|
||||
|
||||
void SetupHooks() {
|
||||
void SetupHooks(size_t PageSize) {
|
||||
Alloc64 = Alloc::OSAllocator::Create64BitAllocator();
|
||||
AssignHookOverrides();
|
||||
AssignHookOverrides(PageSize);
|
||||
}
|
||||
|
||||
void ClearHooks() {
|
||||
SetJemallocMmapHook(::mmap);
|
||||
SetJemallocMunmapHook(::munmap);
|
||||
SetupAllocatorHooks(::mmap, ::munmap);
|
||||
FEXCore::Allocator::mmap = ::mmap;
|
||||
FEXCore::Allocator::munmap = ::munmap;
|
||||
|
||||
@@ -293,7 +252,8 @@ fextl::vector<MemoryRegion> StealMemoryRegion(uintptr_t Begin, uintptr_t End) {
|
||||
auto Alloc =
|
||||
::mmap(StackRegionIt->Ptr, StackRegionIt->Size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE | MAP_FIXED, -1, 0);
|
||||
|
||||
LogMan::Throw::AFmt(Alloc != MAP_FAILED, "mmap({},{:x}) failed", fmt::ptr(StackRegionIt->Ptr), StackRegionIt->Size);
|
||||
LogMan::Throw::AFmt(Alloc != MAP_FAILED, "StealMemoryRegion:Stack: mmap({}, {:x}) failed: {}", fmt::ptr(StackRegionIt->Ptr),
|
||||
StackRegionIt->Size, errno);
|
||||
LogMan::Throw::AFmt(Alloc == StackRegionIt->Ptr, "mmap returned {} instead of {}", Alloc, fmt::ptr(StackRegionIt->Ptr));
|
||||
|
||||
Regions.erase(StackRegionIt);
|
||||
@@ -304,14 +264,14 @@ fextl::vector<MemoryRegion> StealMemoryRegion(uintptr_t Begin, uintptr_t End) {
|
||||
for (auto RegionIt = Regions.begin(); RegionIt != Regions.end(); ++RegionIt) {
|
||||
auto Alloc = ::mmap(RegionIt->Ptr, RegionIt->Size, PROT_NONE, MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE | MAP_FIXED_NOREPLACE, -1, 0);
|
||||
|
||||
LogMan::Throw::AFmt(Alloc != MAP_FAILED, "mmap({},{:x}) failed", fmt::ptr(RegionIt->Ptr), RegionIt->Size);
|
||||
LogMan::Throw::AFmt(Alloc != MAP_FAILED, "StealMemoryRegion: mmap({}, {:x}) failed: {}", fmt::ptr(RegionIt->Ptr), RegionIt->Size, errno);
|
||||
LogMan::Throw::AFmt(Alloc == RegionIt->Ptr, "mmap returned {} instead of {}", Alloc, fmt::ptr(RegionIt->Ptr));
|
||||
}
|
||||
|
||||
return Regions;
|
||||
}
|
||||
|
||||
fextl::vector<MemoryRegion> Setup48BitAllocatorIfExists() {
|
||||
fextl::vector<MemoryRegion> Setup48BitAllocatorIfExists(size_t PageSize) {
|
||||
size_t Bits = FEXCore::Allocator::DetermineVASize();
|
||||
if (Bits < 48) {
|
||||
return {};
|
||||
@@ -322,7 +282,7 @@ fextl::vector<MemoryRegion> Setup48BitAllocatorIfExists() {
|
||||
auto Regions = StealMemoryRegion(Begin48BitVA, End48BitVA);
|
||||
|
||||
Alloc64 = Alloc::OSAllocator::Create64BitAllocatorWithRegions(Regions);
|
||||
AssignHookOverrides();
|
||||
AssignHookOverrides(PageSize);
|
||||
|
||||
return Regions;
|
||||
}
|
||||
|
||||
@@ -1,60 +1,175 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifdef ENABLE_JEMALLOC
|
||||
#include <jemalloc/jemalloc.h>
|
||||
#ifdef ENABLE_FEX_ALLOCATOR
|
||||
#include <rpmalloc/rpmalloc.h>
|
||||
#ifndef _WIN32
|
||||
#include <linux/prctl.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/mman.h>
|
||||
#else
|
||||
#define NTDDI_VERSION 0x0A000005
|
||||
#include <memoryapi.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <cstdint>
|
||||
#include <malloc.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace FEXCore::Allocator {
|
||||
|
||||
#ifndef _WIN32
|
||||
using mmap_hook_type = void* (*)(void* addr, size_t length, int prot, int flags, int fd, off_t offset);
|
||||
using munmap_hook_type = int (*)(void* addr, size_t length);
|
||||
|
||||
#ifdef ENABLE_FEX_ALLOCATOR
|
||||
typedef void* (*rp_mmap_hook_type)(size_t size, size_t alignment, size_t* offset, size_t* mapped_size);
|
||||
typedef void (*rp_munmap_hook_type)(void* address, size_t offset, size_t mapped_size);
|
||||
extern "C" rp_mmap_hook_type rp_mmap_hook;
|
||||
extern "C" rp_munmap_hook_type rp_munmap_hook;
|
||||
|
||||
#ifndef _WIN32
|
||||
mmap_hook_type fex_mmap_hook = ::mmap;
|
||||
munmap_hook_type fex_munmap_hook = ::munmap;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_JEMALLOC
|
||||
// Assume a 64KB page size until told otherwise.
|
||||
static rpmalloc_config_t global_config {
|
||||
.page_size = 64 * 1024,
|
||||
// THP causes crashes for some reason.
|
||||
.enable_huge_pages = 0,
|
||||
.disable_decommit = 0,
|
||||
.page_name = "FEXAllocator",
|
||||
.huge_page_name = "FEXAllocator",
|
||||
.unmap_on_finalize = 0,
|
||||
};
|
||||
|
||||
void* malloc(size_t size) {
|
||||
return ::je_malloc(size);
|
||||
return ::rpmalloc(size);
|
||||
}
|
||||
void* calloc(size_t n, size_t size) {
|
||||
return ::je_calloc(n, size);
|
||||
return ::rpcalloc(n, size);
|
||||
}
|
||||
void* memalign(size_t align, size_t s) {
|
||||
return ::je_memalign(align, s);
|
||||
return ::rpmemalign(align, s);
|
||||
}
|
||||
void* valloc(size_t size) {
|
||||
return ::je_valloc(size);
|
||||
return ::rpaligned_alloc(global_config.page_size, size);
|
||||
}
|
||||
int posix_memalign(void** r, size_t a, size_t s) {
|
||||
return ::je_posix_memalign(r, a, s);
|
||||
void* ptr;
|
||||
auto res = ::rpposix_memalign(&ptr, a, s);
|
||||
*r = ptr;
|
||||
return res;
|
||||
}
|
||||
void* realloc(void* ptr, size_t size) {
|
||||
return ::je_realloc(ptr, size);
|
||||
return ::rprealloc(ptr, size);
|
||||
}
|
||||
void free(void* ptr) {
|
||||
return ::je_free(ptr);
|
||||
return ::rpfree(ptr);
|
||||
}
|
||||
size_t malloc_usable_size(void* ptr) {
|
||||
return ::je_malloc_usable_size(ptr);
|
||||
return ::rpmalloc_usable_size(ptr);
|
||||
}
|
||||
void* aligned_alloc(size_t a, size_t s) {
|
||||
return ::je_aligned_alloc(a, s);
|
||||
return ::rpaligned_alloc(a, s);
|
||||
}
|
||||
void aligned_free(void* ptr) {
|
||||
return ::je_free(ptr);
|
||||
return ::rpfree(ptr);
|
||||
}
|
||||
|
||||
void InitializeThread() {
|
||||
rpmalloc_thread_initialize();
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
extern "C" mmap_hook_type je___mmap_hook;
|
||||
extern "C" munmap_hook_type je___munmap_hook;
|
||||
|
||||
void SetJemallocMmapHook(mmap_hook_type Hook) {
|
||||
je___mmap_hook = Hook;
|
||||
[[nodiscard]]
|
||||
constexpr uint64_t AlignUp(uint64_t value, uint64_t size) {
|
||||
return value + (size - value % size) % size;
|
||||
}
|
||||
void SetJemallocMunmapHook(munmap_hook_type Hook) {
|
||||
je___munmap_hook = Hook;
|
||||
|
||||
static void* FEX_rp_mmap(size_t size, size_t alignment, size_t* offset, size_t* mapped_size) {
|
||||
#define pointer_offset(ptr, ofs) (void*)((char*)(ptr) + (ptrdiff_t)(ofs))
|
||||
// If the alignment is less than the operating page size then alignment is guaranteed. Just remove it.
|
||||
if (alignment < global_config.page_size) {
|
||||
alignment = 0;
|
||||
}
|
||||
|
||||
size_t map_size = AlignUp(size + alignment, global_config.page_size);
|
||||
auto ptr = fex_mmap_hook(0, map_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||
|
||||
if (ptr == MAP_FAILED) {
|
||||
ptr = nullptr;
|
||||
} else {
|
||||
#ifndef PR_SET_VMA
|
||||
#define PR_SET_VMA 0x53564d41
|
||||
#endif
|
||||
|
||||
#ifndef PR_SET_VMA_ANON_NAME
|
||||
#define PR_SET_VMA_ANON_NAME 0
|
||||
#endif
|
||||
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, map_size, global_config.page_name);
|
||||
}
|
||||
|
||||
if (ptr == nullptr) {
|
||||
fprintf(stderr, "Failed to map VMA region.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (alignment) {
|
||||
size_t padding = ((uintptr_t)ptr & (uintptr_t)(alignment - 1));
|
||||
if (padding) {
|
||||
padding = alignment - padding;
|
||||
}
|
||||
ptr = pointer_offset(ptr, padding);
|
||||
*offset = padding;
|
||||
}
|
||||
*mapped_size = map_size;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void FEX_rp_memory_commit(void* address, size_t size) {
|
||||
// NOP-implementation.
|
||||
}
|
||||
|
||||
static void FEX_rp_memory_decommit(void* address, size_t size) {
|
||||
if (global_config.disable_decommit) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (madvise(address, size, MADV_DONTNEED)) {
|
||||
fprintf(stderr, "Failed to decommit VMA region.");
|
||||
}
|
||||
}
|
||||
|
||||
static void FEX_rp_memory_unmap(void* address, size_t offset, size_t mapped_size) {
|
||||
address = pointer_offset(address, -(int32_t)offset);
|
||||
int Result = fex_munmap_hook(address, mapped_size);
|
||||
if (Result == -1) {
|
||||
fprintf(stderr, "Failed to unmap VMA region.");
|
||||
}
|
||||
#undef pointer_offset
|
||||
}
|
||||
|
||||
void SetupAllocatorHooks(mmap_hook_type MMapHook, munmap_hook_type MunmapHook) {
|
||||
fex_mmap_hook = MMapHook;
|
||||
fex_munmap_hook = MunmapHook;
|
||||
}
|
||||
|
||||
static rpmalloc_interface_t global_interface {
|
||||
.memory_map = FEX_rp_mmap,
|
||||
.memory_commit = FEX_rp_memory_commit,
|
||||
.memory_decommit = FEX_rp_memory_decommit,
|
||||
.memory_unmap = FEX_rp_memory_unmap,
|
||||
.map_fail_callback = nullptr,
|
||||
.error_callback = nullptr,
|
||||
};
|
||||
|
||||
void InitializeAllocator(size_t PageSize) {
|
||||
global_config.page_size = PageSize;
|
||||
rpmalloc_initialize_config(&global_interface, &global_config);
|
||||
rp_mmap_hook = FEX_rp_mmap;
|
||||
rp_munmap_hook = FEX_rp_memory_unmap;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -62,6 +177,8 @@ void SetJemallocMunmapHook(munmap_hook_type Hook) {
|
||||
#error "Tried building _WIN32 without jemalloc"
|
||||
|
||||
#else
|
||||
void InitializeThread() {}
|
||||
|
||||
void* malloc(size_t size) {
|
||||
return ::malloc(size);
|
||||
}
|
||||
@@ -93,8 +210,9 @@ void aligned_free(void* ptr) {
|
||||
return ::free(ptr);
|
||||
}
|
||||
|
||||
void SetJemallocMmapHook(mmap_hook_type) {}
|
||||
void SetJemallocMunmapHook(munmap_hook_type) {}
|
||||
void SetupAllocatorHooks(mmap_hook_type MMapHook, munmap_hook_type MunmapHook) {}
|
||||
|
||||
void InitializeAllocator(size_t PageSize) {}
|
||||
|
||||
#endif
|
||||
} // namespace FEXCore::Allocator
|
||||
@@ -39,8 +39,10 @@ static bool LoadFileImpl(T& Data, const fextl::string& Filepath, size_t FixedSiz
|
||||
if (FileSize) {
|
||||
// File size is known upfront
|
||||
Data.resize(FileSize);
|
||||
while (CurrentOffset != FileSize && (Read = pread(FD, &Data.at(CurrentOffset), FileSize, 0)) > 0) {
|
||||
size_t Remaining = FileSize;
|
||||
while (CurrentOffset != FileSize && (Read = pread(FD, &Data.at(CurrentOffset), Remaining, CurrentOffset)) > 0) {
|
||||
CurrentOffset += Read;
|
||||
Remaining -= Read;
|
||||
}
|
||||
|
||||
LoadedFile = CurrentOffset == FileSize && Read != -1;
|
||||
|
||||
@@ -5,10 +5,6 @@
|
||||
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#ifndef _WIN32
|
||||
#include <sys/signal.h>
|
||||
#include <sys/syscall.h>
|
||||
#endif
|
||||
|
||||
namespace FEXCore::Threads {
|
||||
static fextl::unique_ptr<FEXCore::Threads::Thread> CreateThread_Default(ThreadFunc Func, void* Arg) {
|
||||
@@ -35,21 +31,4 @@ void FEXCore::Threads::Thread::CleanupAfterFork() {
|
||||
void FEXCore::Threads::Thread::SetInternalPointers(const Pointers& _Ptrs) {
|
||||
Ptrs = _Ptrs;
|
||||
}
|
||||
|
||||
uint64_t SetSignalMask(uint64_t Mask) {
|
||||
#ifndef _WIN32
|
||||
::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &Mask, &Mask, 8);
|
||||
return Mask;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void SetThreadName(const char* name) {
|
||||
#ifndef _WIN32
|
||||
pthread_setname_np(pthread_self(), name);
|
||||
#else
|
||||
// TODO:
|
||||
#endif
|
||||
}
|
||||
} // namespace FEXCore::Threads
|
||||
@@ -31,16 +31,6 @@ namespace Handler {
|
||||
}
|
||||
return "0";
|
||||
}
|
||||
static inline std::optional<fextl::string> CacheObjectCodeHandler(std::string_view Value) {
|
||||
if (Value == "none") {
|
||||
return "0";
|
||||
} else if (Value == "read") {
|
||||
return "1";
|
||||
} else if (Value == "write") {
|
||||
return "2";
|
||||
}
|
||||
return "0";
|
||||
}
|
||||
} // namespace Handler
|
||||
|
||||
enum ConfigOption {
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <FEXCore/fextl/string.h>
|
||||
#include <FEXCore/fextl/vector.h>
|
||||
#include <FEXCore/fextl/robin_map.h>
|
||||
#include <FEXCore/HLE/SourcecodeResolver.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
@@ -32,6 +31,8 @@ enum class GuestRelocationType : uint32_t { Rel32, Rel64 };
|
||||
|
||||
// Generic information associated with an executable file.
|
||||
struct ExecutableFileInfo {
|
||||
~ExecutableFileInfo();
|
||||
|
||||
#if __clang_major__ < 16
|
||||
// Workaround for broken aggregate-initialization with std::piecewise_construct
|
||||
ExecutableFileInfo(fextl::unique_ptr<HLE::SourcecodeMap>, uint64_t, fextl::string);
|
||||
|
||||
@@ -71,7 +71,7 @@ static_assert(std::is_standard_layout_v<NonAtomicRefCounter<uint64_t>>, "Needs t
|
||||
static_assert(std::is_trivially_copyable_v<NonAtomicRefCounter<uint64_t>>, "needs to be trivially copyable");
|
||||
static_assert(sizeof(NonAtomicRefCounter<uint64_t>) == sizeof(uint64_t), "Needs to be correct size");
|
||||
|
||||
struct CPUState {
|
||||
struct alignas(64) CPUState {
|
||||
// Allows more efficient handling of the register
|
||||
// file in the event AVX is not supported.
|
||||
union XMMRegs {
|
||||
@@ -87,6 +87,7 @@ struct CPUState {
|
||||
SSE sse;
|
||||
};
|
||||
|
||||
// Cacheline: 0
|
||||
uint64_t InlineJITBlockHeader {};
|
||||
// Reference counter for FEX's per-thread deferred signals.
|
||||
// Counts the nesting depth of program sections that cause signals to be deferred.
|
||||
@@ -95,21 +96,27 @@ struct CPUState {
|
||||
// PF/AF raw values. Really only a byte of each matters, but this layout
|
||||
// (32-bits and in the first 256 bytes) is necessary to use ldp/stp to
|
||||
// spill/fill these togethers efficiently.
|
||||
uint32_t pf_raw {};
|
||||
// pf_raw must be initialized to 1 so that reconstructed PF = 0 (matching x86 reset state).
|
||||
// PF reconstruction: popcount(pf_raw ^ 1) & 1, so pf_raw=1 gives PF=0.
|
||||
uint32_t pf_raw {1};
|
||||
uint32_t af_raw {};
|
||||
|
||||
uint64_t rip {}; ///< Current core's RIP. May not be entirely accurate while JIT is active
|
||||
|
||||
// The high 128-bits of AVX registers when not being emulated by SVE256.
|
||||
uint64_t avx_high[16][2];
|
||||
|
||||
uint64_t gregs[16] {};
|
||||
uint64_t L1Pointer {};
|
||||
uint64_t L1Mask {};
|
||||
uint64_t callret_sp {};
|
||||
uint64_t _pad1 {};
|
||||
|
||||
// Cacheline: 1,2,3,4
|
||||
// The high 128-bits of AVX registers when not being emulated by SVE256.
|
||||
uint64_t avx_high[16][2];
|
||||
|
||||
// Cacheline: 5-12
|
||||
XMMRegs xmm {};
|
||||
|
||||
// Cacheline: 13 and onwards.
|
||||
// Raw segment register indexes
|
||||
uint16_t es_idx {}, cs_idx {}, ss_idx {}, ds_idx {};
|
||||
uint16_t gs_idx {}, fs_idx {};
|
||||
@@ -244,13 +251,20 @@ struct CPUState {
|
||||
};
|
||||
static_assert(std::is_trivially_copyable_v<CPUState>, "Needs to be trivial");
|
||||
static_assert(std::is_standard_layout_v<CPUState>, "This needs to be standard layout");
|
||||
static_assert(offsetof(CPUState, avx_high) % 16 == 0, "avx_high needs to be 128-bit aligned!");
|
||||
static_assert(alignof(CPUState) == 64, "CPUState needs to be 64-byte aligned!");
|
||||
static_assert(offsetof(CPUState, avx_high) % 64 == 0, "avx_high needs to be 64-byte aligned!");
|
||||
static_assert(offsetof(CPUState, xmm) % 32 == 0, "xmm needs to be 256-bit aligned!");
|
||||
static_assert(offsetof(CPUState, mm) % 16 == 0, "mm needs to be 128-bit aligned!");
|
||||
static_assert(offsetof(CPUState, gregs[15]) <= 504, "gregs maximum offset must be <= 504 for ldp/stp to work");
|
||||
static_assert(offsetof(CPUState, DeferredSignalRefCount) % 8 == 0, "Needs to be 8-byte aligned");
|
||||
static_assert(offsetof(CPUState, L1Pointer) <= 504, "This needs to be <= 504 for ldp");
|
||||
static_assert(offsetof(CPUState, L1Mask) == (offsetof(CPUState, L1Pointer) + 8), "These two variables are paired");
|
||||
static_assert(offsetof(CPUState, pf_raw) <= 252, "pf_raw must be within ldp imm offset range");
|
||||
static_assert((offsetof(CPUState, pf_raw) + 4) == offsetof(CPUState, af_raw), "pf_raw and af_raw must be sequential");
|
||||
|
||||
// Some CPU architectures have a penalty for alignment of ldp/stp not being 2 * <element_size>.
|
||||
static_assert(offsetof(CPUState, gregs[0]) % 16 == 0, "gregs should be 16-byte aligned");
|
||||
static_assert(offsetof(CPUState, pf_raw) % 8 == 0, "pf_raw must be 8-byte aligned.");
|
||||
|
||||
struct InternalThreadState;
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ struct alignas(FEXCore::Utils::FEX_PAGE_SIZE) InternalThreadState : public FEXCo
|
||||
FEXCore::UncheckedLongJump::JumpBuf RestartJump;
|
||||
|
||||
// BaseFrameState should always be at the end, directly before the interrupt fault page
|
||||
alignas(16) FEXCore::Core::CpuStateFrame BaseFrameState {};
|
||||
FEXCore::Core::CpuStateFrame BaseFrameState {};
|
||||
|
||||
// Can be reprotected as RO to trigger an interrupt at generated code block entrypoints
|
||||
alignas(FEXCore::Utils::FEX_PAGE_SIZE) uint8_t InterruptFaultPage[FEXCore::Utils::FEX_PAGE_SIZE];
|
||||
|
||||
@@ -12,7 +12,7 @@ struct InternalThreadState;
|
||||
}
|
||||
|
||||
namespace FEXCore::Allocator {
|
||||
FEX_DEFAULT_VISIBILITY void SetupHooks();
|
||||
FEX_DEFAULT_VISIBILITY void SetupHooks(size_t PageSize);
|
||||
FEX_DEFAULT_VISIBILITY void ClearHooks();
|
||||
|
||||
FEX_DEFAULT_VISIBILITY size_t DetermineVASize();
|
||||
@@ -63,13 +63,6 @@ public:
|
||||
};
|
||||
#endif
|
||||
|
||||
// Disable allocations through glibc's sbrk allocation method.
|
||||
// Returns a pointer at the end of the sbrk region.
|
||||
FEX_DEFAULT_VISIBILITY void* DisableSBRKAllocations();
|
||||
|
||||
// Allow sbrk again. Pass in the pointer returned by `DisableSBRKAllocations`
|
||||
FEX_DEFAULT_VISIBILITY void ReenableSBRKAllocations(void* Ptr);
|
||||
|
||||
struct MemoryRegion {
|
||||
void* Ptr;
|
||||
size_t Size;
|
||||
@@ -84,7 +77,7 @@ FEX_DEFAULT_VISIBILITY void ReclaimMemoryRegion(const fextl::vector<MemoryRegion
|
||||
// AArch64 canonical addresses are only up to bits 48/52 with the remainder being other things
|
||||
// Use this to reserve the top 128TB of VA so the guest never see it
|
||||
// Returns nullptr on host VA < 48bits
|
||||
FEX_DEFAULT_VISIBILITY fextl::vector<MemoryRegion> Setup48BitAllocatorIfExists();
|
||||
FEX_DEFAULT_VISIBILITY fextl::vector<MemoryRegion> Setup48BitAllocatorIfExists(size_t PageSize);
|
||||
|
||||
#ifndef _WIN32
|
||||
FEX_DEFAULT_VISIBILITY void RegisterTLSData(FEXCore::Core::InternalThreadState* Thread);
|
||||
|
||||
@@ -139,9 +139,11 @@ size_t malloc_usable_size(void* ptr);
|
||||
void* aligned_alloc(size_t a, size_t s);
|
||||
void aligned_free(void* ptr);
|
||||
|
||||
FEX_DEFAULT_VISIBILITY extern void InitializeThread();
|
||||
|
||||
#ifndef _WIN32
|
||||
void SetJemallocMmapHook(void* (*)(void* addr, size_t length, int prot, int flags, int fd, off_t offset));
|
||||
void SetJemallocMunmapHook(int (*)(void* addr, size_t length));
|
||||
void InitializeAllocator(size_t PageSize);
|
||||
void SetupAllocatorHooks(void* (*)(void* addr, size_t length, int prot, int flags, int fd, off_t offset), int (*)(void* addr, size_t length));
|
||||
#endif
|
||||
|
||||
struct FEXAllocOperators {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <FEXCore/fextl/memory.h>
|
||||
#include <cstdint>
|
||||
|
||||
namespace FEXCore::Threads {
|
||||
using ThreadFunc = void* (*)(void* user_ptr);
|
||||
@@ -38,15 +37,4 @@ public:
|
||||
// Set API functions
|
||||
static void SetInternalPointers(const Pointers& _Ptrs);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Sets the calling thread's signal mask to the one provided
|
||||
*
|
||||
* @param Mask The new 64-bit signal mask to set
|
||||
*
|
||||
* @return The previous signal mask
|
||||
*/
|
||||
uint64_t SetSignalMask(uint64_t Mask);
|
||||
|
||||
void SetThreadName(const char* name);
|
||||
} // namespace FEXCore::Threads
|
||||
@@ -2,9 +2,9 @@
|
||||
#pragma once
|
||||
#include <FEXCore/fextl/allocator.h>
|
||||
|
||||
#include <tsl/robin_map.h>
|
||||
#include <ankerl/unordered_dense.h>
|
||||
|
||||
namespace fextl {
|
||||
template<class Key, class T, class Hash = std::hash<Key>, class KeyEqual = std::equal_to<Key>, class Allocator = fextl::FEXAlloc<std::pair<const Key, T>>>
|
||||
using robin_map = tsl::robin_map<Key, T, Hash, KeyEqual, Allocator>;
|
||||
template<class Key, class T, class Hash = std::hash<Key>, class KeyEqual = std::equal_to<Key>, class Allocator = fextl::FEXAlloc<std::pair<Key, T>>>
|
||||
using robin_map = ankerl::unordered_dense::map<Key, T, Hash, KeyEqual, Allocator>;
|
||||
}
|
||||
@@ -2,9 +2,9 @@
|
||||
#pragma once
|
||||
#include <FEXCore/fextl/allocator.h>
|
||||
|
||||
#include <tsl/robin_set.h>
|
||||
#include <ankerl/unordered_dense.h>
|
||||
|
||||
namespace fextl {
|
||||
template<class Key, class Hash = std::hash<Key>, class KeyEqual = std::equal_to<Key>, class Allocator = fextl::FEXAlloc<Key>>
|
||||
using robin_set = tsl::robin_set<Key, Hash, KeyEqual, Allocator>;
|
||||
using robin_set = ankerl::unordered_dense::set<Key, Hash, KeyEqual, Allocator>;
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#pragma once
|
||||
|
||||
#define GIT_SHORT_HASH "@GIT_SHORT_HASH@"
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
static constexpr std::array<uint8_t, 20> GIT_HASH = {@GIT_HASH_ARRAY@};
|
||||
#define GIT_DESCRIBE_STRING "@GIT_DESCRIBE_STRING@"
|
||||
@@ -1,6 +1,6 @@
|
||||
file(GLOB_RECURSE TESTS CONFIGURE_DEPENDS *.cpp)
|
||||
|
||||
set(LIBS fmt::fmt vixl Catch2::Catch2WithMain FEXCore_Base JemallocLibs)
|
||||
set(LIBS fmt::fmt vixl::vixl Catch2::Catch2WithMain FEXCore_Base JemallocLibs)
|
||||
foreach(TEST ${TESTS})
|
||||
get_filename_component(TEST_NAME ${TEST} NAME_WLE)
|
||||
add_executable(FEXCore_Tests_${TEST_NAME} ${TEST})
|
||||
|
||||
@@ -2030,18 +2030,18 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: ASIMD: Advanced SIMD modified immed
|
||||
// XXX: MVNI - Shifted immediate
|
||||
// XXX: BIC
|
||||
TEST_SINGLE(movi(SubRegSize::i8Bit, QReg::q30, 0xFE), "movi v30.16b, #0xfe");
|
||||
TEST_SINGLE(movi(SubRegSize::i16Bit, QReg::q30, 0xFE, 0), "movi v30.8h, #0xfe, lsl #0");
|
||||
TEST_SINGLE(movi(SubRegSize::i16Bit, QReg::q30, 0xFE, 0), "movi v30.8h, #0xfe");
|
||||
TEST_SINGLE(movi(SubRegSize::i16Bit, QReg::q30, 0xFE, 8), "movi v30.8h, #0xfe, lsl #8");
|
||||
TEST_SINGLE(movi(SubRegSize::i32Bit, QReg::q30, 0xFE, 0), "movi v30.4s, #0xfe, lsl #0");
|
||||
TEST_SINGLE(movi(SubRegSize::i32Bit, QReg::q30, 0xFE, 0), "movi v30.4s, #0xfe");
|
||||
TEST_SINGLE(movi(SubRegSize::i32Bit, QReg::q30, 0xFE, 8), "movi v30.4s, #0xfe, lsl #8");
|
||||
TEST_SINGLE(movi(SubRegSize::i32Bit, QReg::q30, 0xFE, 16), "movi v30.4s, #0xfe, lsl #16");
|
||||
TEST_SINGLE(movi(SubRegSize::i32Bit, QReg::q30, 0xFE, 24), "movi v30.4s, #0xfe, lsl #24");
|
||||
TEST_SINGLE(movi(SubRegSize::i64Bit, QReg::q30, 0xFF00FF), "movi v30.2d, #0xff00ff");
|
||||
|
||||
TEST_SINGLE(movi(SubRegSize::i8Bit, DReg::d30, 0xFE), "movi v30.8b, #0xfe");
|
||||
TEST_SINGLE(movi(SubRegSize::i16Bit, DReg::d30, 0xFE, 0), "movi v30.4h, #0xfe, lsl #0");
|
||||
TEST_SINGLE(movi(SubRegSize::i16Bit, DReg::d30, 0xFE, 0), "movi v30.4h, #0xfe");
|
||||
TEST_SINGLE(movi(SubRegSize::i16Bit, DReg::d30, 0xFE, 8), "movi v30.4h, #0xfe, lsl #8");
|
||||
TEST_SINGLE(movi(SubRegSize::i32Bit, DReg::d30, 0xFE, 0), "movi v30.2s, #0xfe, lsl #0");
|
||||
TEST_SINGLE(movi(SubRegSize::i32Bit, DReg::d30, 0xFE, 0), "movi v30.2s, #0xfe");
|
||||
TEST_SINGLE(movi(SubRegSize::i32Bit, DReg::d30, 0xFE, 8), "movi v30.2s, #0xfe, lsl #8");
|
||||
TEST_SINGLE(movi(SubRegSize::i32Bit, DReg::d30, 0xFE, 16), "movi v30.2s, #0xfe, lsl #16");
|
||||
TEST_SINGLE(movi(SubRegSize::i32Bit, DReg::d30, 0xFE, 24), "movi v30.2s, #0xfe, lsl #24");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
file(GLOB_RECURSE TESTS CONFIGURE_DEPENDS *.cpp)
|
||||
|
||||
set(LIBS fmt::fmt vixl Catch2::Catch2WithMain FEXCore_Base JemallocLibs)
|
||||
set(LIBS fmt::fmt vixl::vixl Catch2::Catch2WithMain FEXCore_Base JemallocLibs)
|
||||
foreach(TEST ${TESTS})
|
||||
get_filename_component(TEST_NAME ${TEST} NAME_WLE)
|
||||
add_executable(Emitter_${TEST_NAME} ${TEST})
|
||||
|
||||
@@ -1,26 +1,16 @@
|
||||
#!/bin/sh
|
||||
for binfmt in "$@"
|
||||
do
|
||||
|
||||
for binfmt in "$@"; do
|
||||
result=0
|
||||
if command -v update-binfmts>/dev/null; then
|
||||
update-binfmts --find "$binfmt" 1>&- 2>&-
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
# If we found the binfmt_misc file passed in then error
|
||||
result=1
|
||||
fi
|
||||
if command -v update-binfmts >/dev/null; then
|
||||
# If we found the binfmt_misc file passed in then error
|
||||
update-binfmts --find "$binfmt" 1>&- 2>&- && result=1
|
||||
fi
|
||||
|
||||
if [ $result -eq 0 ]
|
||||
then
|
||||
if [ -f "$binfmt" ]; then
|
||||
# If the binfmt_misc file exists then error
|
||||
result=1
|
||||
fi
|
||||
fi
|
||||
# If the binfmt_misc file exists then error
|
||||
[ -f "$binfmt" ] && result=1
|
||||
|
||||
if [ $result -eq 1 ]
|
||||
then
|
||||
if [ $result -eq 1 ]; then
|
||||
echo "==============================================================="
|
||||
echo "$binfmt binfmt file is installed!"
|
||||
echo "This conflicts with FEX-Emu's binfmt_misc!"
|
||||
|
||||
@@ -1,31 +1,33 @@
|
||||
#!/bin/bash
|
||||
#!/bin/sh
|
||||
FEX=${1:-FEXLoader}
|
||||
echo Using $FEX
|
||||
echo "Using $FEX"
|
||||
|
||||
for fileid in ~/.fex-emu/aotir/*.path; do
|
||||
filename=`cat "$fileid"`
|
||||
filename=$(cat "$fileid")
|
||||
args=""
|
||||
if [ "${fileid: -6 : 1}" == "L" ]; then
|
||||
args="$args --abilocalflags"
|
||||
else
|
||||
args="$args --no-abilocalflags"
|
||||
fi
|
||||
|
||||
if [ "${fileid: -7 : 1}" == "T" ]; then
|
||||
args="$args --tsoenabled"
|
||||
else
|
||||
args="$args --no-tsoenabled"
|
||||
fi
|
||||
# if L is 6 chars from the end, use localflags
|
||||
case $fileid in
|
||||
*L?????) _abi=--abilocalflags ;;
|
||||
*) _abi=--no-abilocalflags ;;
|
||||
esac
|
||||
|
||||
if [ "${fileid: -8 : 1}" == "S" ]; then
|
||||
args="$args --smc=full"
|
||||
else
|
||||
args="$args --smc=mman"
|
||||
fi
|
||||
# if T is 7 chars from the end, use tso
|
||||
case $fileid in
|
||||
*T??????) _tso=--tsoenabled ;;
|
||||
*) _tso=--no-tsoenabled ;;
|
||||
esac
|
||||
|
||||
# if S is 8 chars from the end, use full smc
|
||||
case $fileid in
|
||||
*S???????) _smc=full ;;
|
||||
*) _smc=mman ;;
|
||||
esac
|
||||
|
||||
if [ -f "${fileid%.path}.aotir" ]; then
|
||||
echo "`basename $fileid` has already been generated"
|
||||
echo "$(basename "$fileid") has already been generated"
|
||||
else
|
||||
echo "Processing `basename $fileid` ($filename) with $args"
|
||||
$FEX --aotirgenerate $args "$filename"
|
||||
echo "Processing $(basename "$fileid") ($filename) with $args"
|
||||
$FEX --aotirgenerate "$_abi" "$_tso" --smc="$_smc" "$filename"
|
||||
fi
|
||||
done
|
||||
+27
-17
@@ -161,8 +161,8 @@ def InstallPPA():
|
||||
|
||||
DidInstall = False
|
||||
try:
|
||||
CmdResult = subprocess.call(["sudo", "add-apt-repository", "-y", "ppa:fex-emu/fex"])
|
||||
DidInstall = CmdResult == 0
|
||||
CmdResult = subprocess.run(["sudo", "add-apt-repository", "-y", "ppa:fex-emu/fex"])
|
||||
DidInstall = CmdResult.returncode == 0
|
||||
except KeyboardInterrupt:
|
||||
DidInstall = False
|
||||
pass
|
||||
@@ -195,8 +195,8 @@ def UpdatePPA():
|
||||
|
||||
DidUpdate = False
|
||||
try:
|
||||
CmdResult = subprocess.call(["sudo", "apt-get", "update"])
|
||||
DidUpdate = CmdResult == 0
|
||||
CmdResult = subprocess.run(["sudo", "apt-get", "update"])
|
||||
DidUpdate = CmdResult.returncode == 0
|
||||
except KeyboardInterrupt:
|
||||
DidUpdate = False
|
||||
pass
|
||||
@@ -211,8 +211,8 @@ def UpdatePPA():
|
||||
def InstallPackages(PackagesToInstall):
|
||||
DidInstall = False
|
||||
try:
|
||||
CmdResult = subprocess.call(["sudo", "apt-get", "-y", "install"] + PackagesToInstall)
|
||||
DidInstall = CmdResult == 0
|
||||
CmdResult = subprocess.run(["sudo", "apt-get", "-y", "install"] + PackagesToInstall)
|
||||
DidInstall = CmdResult.returncode == 0
|
||||
except KeyboardInterrupt:
|
||||
print ("Keyboard interrupt")
|
||||
DidInstall = False
|
||||
@@ -256,8 +256,8 @@ def CheckAndInstallPackageUpdates(PackagesToInstall, InstallIfNotFound=False):
|
||||
def CheckPackageInstallStatus():
|
||||
PackagesToInstall = GetPackagesToInstall()
|
||||
for Package in PackagesToInstall[:]:
|
||||
CmdResult = subprocess.call(["dpkg", "-s", Package], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
if CmdResult == 0:
|
||||
CmdResult = subprocess.run(["dpkg", "-s", Package], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
if CmdResult.returncode == 0:
|
||||
PackagesToInstall.remove(Package)
|
||||
|
||||
return PackagesToInstall
|
||||
@@ -267,8 +267,8 @@ def InstallPackages(Packages):
|
||||
|
||||
DidInstall = False
|
||||
try:
|
||||
CmdResult = subprocess.call(["sudo", "apt-get", "-y", "install"] + Packages)
|
||||
DidInstall = CmdResult == 0
|
||||
CmdResult = subprocess.run(["sudo", "apt-get", "-y", "install"] + Packages)
|
||||
DidInstall = CmdResult.returncode == 0
|
||||
except KeyboardInterrupt:
|
||||
print ("Keyboard interrupt")
|
||||
DidInstall = False
|
||||
@@ -293,18 +293,22 @@ def GetRootFSPath():
|
||||
if HomeDir == None:
|
||||
HomeDir = "."
|
||||
|
||||
Path = HomeDir
|
||||
Path = HomeDir + "/.local/share"
|
||||
DataXDG = os.getenv("XDG_DATA_HOME")
|
||||
if DataXDG != None:
|
||||
Path = DataXDG
|
||||
|
||||
Path = Path + "/.fex-emu"
|
||||
Path = Path + "/fex-emu"
|
||||
|
||||
DataOverride = os.getenv("FEX_APP_DATA_LOCATION")
|
||||
|
||||
if DataOverride != None:
|
||||
Path = DataOverride
|
||||
|
||||
LegacyDir = HomeDir + "/.fex-emu"
|
||||
if os.path.isdir(LegacyDir):
|
||||
Path = LegacyDir
|
||||
|
||||
_RootFSPath = Path + "/RootFS/"
|
||||
|
||||
return _RootFSPath
|
||||
@@ -327,20 +331,26 @@ def CheckRootFSInstallStatus():
|
||||
def TryInstallRootFS():
|
||||
DidInstall = False
|
||||
try:
|
||||
CmdResult = subprocess.call(["FEXRootFSFetcher"])
|
||||
DidInstall = CmdResult == 0
|
||||
with open("/dev/tty", "r") as tty:
|
||||
CmdResult = subprocess.run(["FEXRootFSFetcher"], stdin=tty)
|
||||
DidInstall = CmdResult.returncode == 0
|
||||
except KeyboardInterrupt:
|
||||
print ("Keyboard interrupt")
|
||||
DidInstall = False
|
||||
pass
|
||||
except OSError:
|
||||
print ("No TTY available")
|
||||
DidInstall = False
|
||||
pass
|
||||
return DidInstall
|
||||
|
||||
def TryBasicProgramExecution():
|
||||
return subprocess.call(["FEX", "/usr/bin/uname", "-a"]) == 0
|
||||
CmdResult = subprocess.run(["FEX", "/usr/bin/uname", "-a"])
|
||||
return CmdResult.returncode == 0
|
||||
|
||||
def ExitWithStatus(Status):
|
||||
# Remove the cached credentials
|
||||
subprocess.call(["sudo", "-K"])
|
||||
subprocess.run(["sudo", "-K"])
|
||||
sys.exit(Status)
|
||||
|
||||
def GetKernelVersion():
|
||||
@@ -420,4 +430,4 @@ def main():
|
||||
ExitWithStatus(0)
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
sys.exit(main())
|
||||
@@ -82,6 +82,11 @@ BigCoreIDs = {
|
||||
],
|
||||
# QEmu HVF 10.2+
|
||||
tuple([0x61, 0]): "apple-a13", # Can't determine variant, choose lowest.
|
||||
# Ampere Computing
|
||||
tuple([0xc0, 0xac3]): "ampere1",
|
||||
tuple([0xc0, 0xac4]): "ampere1a",
|
||||
tuple([0xc0, 0xac5]): "ampere1b",
|
||||
tuple([0xc0, 0xac7]): "ampere1c",
|
||||
}
|
||||
|
||||
LittleCoreIDs = {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#!/bin/env bash
|
||||
if [ "$#" -ne 2 ];
|
||||
then
|
||||
echo "$0: <PEV-TAG> <NEXT-TAG>"
|
||||
exit -1
|
||||
#!/bin/sh
|
||||
|
||||
if [ "$#" -ne 2 ]; then
|
||||
echo "$0: <PEV-TAG> <NEXT-TAG>"
|
||||
exit 255
|
||||
fi
|
||||
|
||||
git log "$1..HEAD" --pretty="%b (%h)" --abbrev-commit --merges | Scripts/changelog_generator.py "$2"
|
||||
@@ -1,11 +1,12 @@
|
||||
#!/bin/env bash
|
||||
echo \# `git describe --always`
|
||||
#!/bin/sh
|
||||
|
||||
echo "# $(git describe --always)"
|
||||
echo
|
||||
|
||||
./Scripts/doc_outline_generator.py "`pwd`" "`pwd`/FEXCore" "../"
|
||||
./Scripts/doc_outline_generator.py "`pwd`" "`pwd`/ThunkLibs" "../"
|
||||
./Scripts/doc_outline_generator.py "`pwd`" "`pwd`/Source/Tests" "../"
|
||||
./Scripts/doc_outline_generator.py "`pwd`" "`pwd`/unittests" "../"
|
||||
./Scripts/doc_outline_generator.py "$(pwd)" "$(pwd)/FEXCore" "../"
|
||||
./Scripts/doc_outline_generator.py "$(pwd)" "$(pwd)/ThunkLibs" "../"
|
||||
./Scripts/doc_outline_generator.py "$(pwd)" "$(pwd)/Source/Tests" "../"
|
||||
./Scripts/doc_outline_generator.py "$(pwd)" "$(pwd)/unittests" "../"
|
||||
|
||||
# These don't have useful documentation at this point
|
||||
#./Scripts/doc_outline_generator.py "`pwd`" "`pwd`/Scripts" "../"
|
||||
|
||||
@@ -1,30 +1,28 @@
|
||||
#!/bin/env bash
|
||||
#!/bin/sh
|
||||
|
||||
# Allow release maintainer to override PREVIOUS and CURRENT by setting it before launching the script
|
||||
PREVIOUS=${PREVIOUS:-FEX-$(date --date='-1 month' +%y%m)}
|
||||
CURRENT=${CURRENT:-FEX-$(date +%y%m)}
|
||||
|
||||
if ! git rev-list $PREVIOUS > /dev/null 2>&1 ;
|
||||
then
|
||||
if ! git rev-list "$PREVIOUS" > /dev/null 2>&1 ; then
|
||||
echo "$PREVIOUS tag doesn't exist"
|
||||
exit
|
||||
fi
|
||||
|
||||
if git rev-list $CURRENT > /dev/null 2>&1 ;
|
||||
then
|
||||
if git rev-list "$CURRENT" > /dev/null 2>&1 ; then
|
||||
echo "$CURRENT tag already exists!"
|
||||
exit
|
||||
fi
|
||||
|
||||
echo "Tagging $CURRENT, previous release $PREVIOUS"
|
||||
echo "Press cltr-c to cancel within 10 seconds"
|
||||
echo "Press Ctrl-C to cancel within 10 seconds"
|
||||
sleep 10
|
||||
|
||||
git tag $CURRENT -a -m "temporary"
|
||||
git tag "$CURRENT" -a -m "temporary"
|
||||
Scripts/generate_doc_outline.sh > docs/SourceOutline.md
|
||||
git commit docs/SourceOutline.md -m "Docs: Update for release $CURRENT"
|
||||
git tag -d $CURRENT
|
||||
git tag -a $CURRENT -m "$(Scripts/generate_changelog.sh $PREVIOUS $CURRENT)" --edit
|
||||
git tag -d "$CURRENT"
|
||||
git tag -a "$CURRENT" -m "$(Scripts/generate_changelog.sh "$PREVIOUS" "$CURRENT")" --edit
|
||||
|
||||
echo "Inspect if everything went smoothly via 'git log -6 $CURRENT' "
|
||||
echo "if all is good, do 'git push upstream $CURRENT'"
|
||||
+5
-5
@@ -1,4 +1,4 @@
|
||||
#! /bin/bash
|
||||
#!/bin/sh -e
|
||||
|
||||
# Save current directory
|
||||
DIR=$(pwd)
|
||||
@@ -7,7 +7,7 @@ DIR=$(pwd)
|
||||
CHANGED_ONLY=false
|
||||
TARGET_DIR=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
while [ $# -gt 0 ]; do
|
||||
case $1 in
|
||||
--changed) # Only reformat changed files (staged and unstaged)
|
||||
CHANGED_ONLY=true
|
||||
@@ -35,13 +35,13 @@ if [ "$CHANGED_ONLY" = true ]; then
|
||||
|
||||
CHANGED_FILES=$(git ls-files -m '*.cpp' '*.h' '*.inl')
|
||||
if [ -n "$CHANGED_FILES" ]; then
|
||||
echo "$CHANGED_FILES" | xargs -d '\n' -n 1 -P $(nproc) clang-format-19 -i
|
||||
echo "$CHANGED_FILES" | xargs -d '\n' -n 1 -P "$(nproc)" clang-format-19 -i
|
||||
else
|
||||
echo "No changed files to format."
|
||||
fi
|
||||
else
|
||||
# Reformat whole tree (original behavior)
|
||||
git ls-files -z '*.cpp' '*.h' '*.inl' | xargs -0 -n 1 -P $(nproc) clang-format-19 -i
|
||||
git ls-files -z '*.cpp' '*.h' '*.inl' | xargs -0 -n 1 -P "$(nproc)" clang-format-19 -i
|
||||
fi
|
||||
|
||||
cd $DIR
|
||||
cd "$DIR"
|
||||
@@ -1,5 +1,4 @@
|
||||
#! /bin/bash
|
||||
set -e
|
||||
#!/bin/sh -e
|
||||
|
||||
# Make sure we actually build
|
||||
ninja
|
||||
|
||||
@@ -13,11 +13,12 @@ set(SRCS
|
||||
if (NOT MINGW)
|
||||
list(APPEND SRCS
|
||||
FEXServerClient.cpp
|
||||
FileFormatCheck.cpp)
|
||||
FileFormatCheck.cpp
|
||||
Linux/SBRKAllocations.cpp)
|
||||
endif()
|
||||
|
||||
add_library(${NAME} STATIC ${SRCS})
|
||||
target_link_libraries(${NAME} FEXCore_Base cpp-optparse tiny-json FEXHeaderUtils range-v3::range-v3)
|
||||
target_link_libraries(${NAME} FEXCore_Base cpp-optparse tiny-json::tiny-json FEXHeaderUtils range-v3::range-v3)
|
||||
target_include_directories(${NAME} PRIVATE ${CMAKE_BINARY_DIR}/generated)
|
||||
|
||||
set_target_properties(${NAME} PROPERTIES
|
||||
|
||||
+102
-38
@@ -7,11 +7,13 @@
|
||||
#include <FEXCore/fextl/fmt.h>
|
||||
#include <FEXCore/fextl/map.h>
|
||||
#include <FEXCore/fextl/string.h>
|
||||
#include <FEXCore/Utils/Allocator.h>
|
||||
#include <FEXCore/Utils/FileLoading.h>
|
||||
#include <FEXHeaderUtils/Filesystem.h>
|
||||
#include <FEXHeaderUtils/SymlinkChecks.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <fmt/format.h>
|
||||
#include <functional>
|
||||
#ifndef _WIN32
|
||||
#include <linux/limits.h>
|
||||
@@ -21,6 +23,9 @@
|
||||
#include <utility>
|
||||
#include <tiny-json.h>
|
||||
|
||||
#include <range/v3/view/split.hpp>
|
||||
#include <range/v3/view/transform.hpp>
|
||||
|
||||
namespace FEX::Config {
|
||||
namespace JSON {
|
||||
static void LoadJSonConfig(const fextl::string& Config, std::function<void(const char* Name, const char* ConfigSring)> Func) {
|
||||
@@ -493,20 +498,66 @@ void LoadConfig(fextl::string ProgramName, char** const envp, const PortableInfo
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
const char* FindUserHomeThroughUID() {
|
||||
auto passwd = getpwuid(geteuid());
|
||||
if (passwd) {
|
||||
return passwd->pw_dir;
|
||||
fextl::string FindUserHomeThroughUID() {
|
||||
// `getpwuid` allocates memory, parse `/etc/passwd` manually.
|
||||
// Format is trivial: `<name>:<password hash>:<uid>:<gid>:<comment>:<home>:<shell>`
|
||||
|
||||
fextl::vector<char> Data;
|
||||
if (!FEXCore::FileLoading::LoadFile(Data, "/etc/passwd")) {
|
||||
return {};
|
||||
}
|
||||
return nullptr;
|
||||
|
||||
auto to_string_view = [](auto rng) {
|
||||
return std::string_view(&*rng.begin(), ranges::distance(rng));
|
||||
};
|
||||
|
||||
const auto uid = geteuid();
|
||||
|
||||
for (const auto entry : ranges::views::split(Data, '\n') | ranges::views::transform(to_string_view)) {
|
||||
const auto elements = ranges::views::split(entry, ':') | ranges::views::transform(to_string_view);
|
||||
// Reject bad entries.
|
||||
if (std::distance(elements.begin(), elements.end()) != 7) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto iter = elements.begin();
|
||||
++iter; // name
|
||||
++iter; // password hash
|
||||
++iter; // comment
|
||||
// uid
|
||||
const auto uid_s = *iter;
|
||||
++iter;
|
||||
++iter; // gid
|
||||
// home
|
||||
const auto home_s = *iter;
|
||||
++iter;
|
||||
++iter; // shell
|
||||
|
||||
uint64_t element_uid;
|
||||
auto Results = std::from_chars(uid_s.begin(), uid_s.end(), element_uid, 10);
|
||||
|
||||
// Error parsing.
|
||||
if (Results.ptr == uid_s.begin()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (element_uid == uid) {
|
||||
return fextl::string(home_s);
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
const char* GetHomeDirectory() {
|
||||
fextl::string GetHomeDirectory() {
|
||||
const char* HomeDir = getenv("HOME");
|
||||
|
||||
// Try to get home directory from uid
|
||||
if (!HomeDir || !FHU::Filesystem::Exists(HomeDir)) {
|
||||
HomeDir = FindUserHomeThroughUID();
|
||||
auto UIDHome = FindUserHomeThroughUID();
|
||||
if (!UIDHome.empty() && FHU::Filesystem::Exists(UIDHome)) {
|
||||
return UIDHome;
|
||||
}
|
||||
}
|
||||
|
||||
// try the PWD
|
||||
@@ -522,7 +573,7 @@ const char* GetHomeDirectory() {
|
||||
return HomeDir;
|
||||
}
|
||||
#else
|
||||
const char* GetHomeDirectory() {
|
||||
fextl::string GetHomeDirectory() {
|
||||
const char* HomeDir = getenv("WINEHOMEDIR");
|
||||
if (HomeDir) {
|
||||
// Skip over the \??\ prefix in the NT path since we want a DOS path
|
||||
@@ -555,20 +606,29 @@ fextl::string GetDataDirectory(bool Global, const PortableInformation& PortableI
|
||||
return fextl::fmt::format("{}/fex-emu/", PortableInfo.InterpreterPath);
|
||||
}
|
||||
|
||||
fextl::string DataDir {};
|
||||
if (Global) {
|
||||
DataDir = GLOBAL_DATA_DIRECTORY;
|
||||
} else {
|
||||
const char* HomeDir = GetHomeDirectory();
|
||||
const char* DataXDG = getenv("XDG_DATA_HOME");
|
||||
if (DataOverride) {
|
||||
// Data override will override the complete directory
|
||||
DataDir = DataOverride;
|
||||
} else {
|
||||
DataDir = DataXDG ?: HomeDir;
|
||||
DataDir += "/.fex-emu/";
|
||||
}
|
||||
return GLOBAL_DATA_DIRECTORY;
|
||||
}
|
||||
|
||||
auto HomeDir = GetHomeDirectory();
|
||||
const char* DataXDG = getenv("XDG_DATA_HOME");
|
||||
const fextl::string LegacyDir = fextl::string {HomeDir} + "/.fex-emu/";
|
||||
|
||||
// If $HOME/.fex-emu exists, use that
|
||||
if (FHU::Filesystem::Exists(LegacyDir)) {
|
||||
return LegacyDir;
|
||||
}
|
||||
|
||||
fextl::string DataDir {};
|
||||
if (DataOverride) {
|
||||
// Data override will override the complete directory
|
||||
DataDir = DataOverride;
|
||||
} else {
|
||||
// use ~/.local/share if XDG_DATA_HOME is unset
|
||||
DataDir = DataXDG ? DataXDG : fmt::format("{}/.local/share", HomeDir);
|
||||
DataDir += "/fex-emu/";
|
||||
}
|
||||
|
||||
return DataDir;
|
||||
}
|
||||
|
||||
@@ -594,25 +654,29 @@ fextl::string GetConfigDirectory(bool Global, const PortableInformation& Portabl
|
||||
|
||||
fextl::string ConfigDir;
|
||||
if (Global) {
|
||||
ConfigDir = GLOBAL_DATA_DIRECTORY;
|
||||
} else {
|
||||
const char* HomeDir = GetHomeDirectory();
|
||||
const char* ConfigXDG = getenv("XDG_CONFIG_HOME");
|
||||
if (ConfigOverride) {
|
||||
// Config override completely overrides the config directory
|
||||
ConfigDir = ConfigOverride;
|
||||
} else {
|
||||
ConfigDir = ConfigXDG ? ConfigXDG : HomeDir;
|
||||
ConfigDir += "/.fex-emu/";
|
||||
}
|
||||
|
||||
// Ensure the folder structure is created for our configuration
|
||||
if (!FHU::Filesystem::Exists(ConfigDir) && !FHU::Filesystem::CreateDirectories(ConfigDir)) {
|
||||
// Let's go local in this case
|
||||
return "./";
|
||||
}
|
||||
return GLOBAL_DATA_DIRECTORY;
|
||||
}
|
||||
|
||||
auto HomeDir = GetHomeDirectory();
|
||||
const char* ConfigXDG = getenv("XDG_CONFIG_HOME");
|
||||
|
||||
const fextl::string LegacyDir = fextl::string {HomeDir} + "/.fex-emu/";
|
||||
|
||||
// If $HOME/.fex-emu exists, use that
|
||||
if (FHU::Filesystem::Exists(LegacyDir)) {
|
||||
return LegacyDir;
|
||||
}
|
||||
|
||||
if (ConfigOverride) {
|
||||
// Config override will override the complete directory
|
||||
ConfigDir = ConfigOverride;
|
||||
} else {
|
||||
// use ~/.config if XDG_CONFIG_HOME is unset
|
||||
ConfigDir = ConfigXDG ? ConfigXDG : fmt::format("{}/.config", HomeDir);
|
||||
ConfigDir += "/fex-emu/";
|
||||
}
|
||||
|
||||
|
||||
return ConfigDir;
|
||||
}
|
||||
|
||||
@@ -630,7 +694,7 @@ fextl::string GetCacheDirectory() {
|
||||
}
|
||||
#endif
|
||||
|
||||
const char* HomeDir = GetHomeDirectory();
|
||||
auto HomeDir = GetHomeDirectory();
|
||||
const char* CacheXDG = getenv("XDG_CACHE_HOME");
|
||||
return (CacheXDG ? fextl::string {CacheXDG} : (fextl::string {HomeDir} + "/.cache")) + "/fex-emu/";
|
||||
#else
|
||||
|
||||
@@ -57,7 +57,7 @@ ApplicationNames GetApplicationNames(const fextl::vector<fextl::string>& Args, b
|
||||
*/
|
||||
void LoadConfig(fextl::string ProgramName = {}, char** const envp = nullptr, const PortableInformation& PortableInfo = {});
|
||||
|
||||
const char* GetHomeDirectory();
|
||||
fextl::string GetHomeDirectory();
|
||||
|
||||
fextl::string GetDataDirectory(const PortableInformation& PortableInfo);
|
||||
fextl::string GetConfigDirectory(bool Global, const PortableInformation& PortableInfo);
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <FEXCore/fextl/fmt.h>
|
||||
#include <FEXCore/Utils/CompilerDefs.h>
|
||||
#include <FEXCore/Utils/LogManager.h>
|
||||
#include <FEXCore/Utils/MathUtils.h>
|
||||
#include <FEXCore/Utils/TypeDefines.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
namespace FEX::SBRKAllocations {
|
||||
// This function disables glibc's ability to allocate memory through the `sbrk` interface.
|
||||
// This is run early in the lifecycle of FEX in order to make sure no 64-bit pointers can make it to the guest 32-bit application.
|
||||
//
|
||||
// How this works is that this allocates a single page at the current sbrk pointer (aligned upward to page size). This makes it
|
||||
// so that when the sbrk syscall is used to allocate more memory, it fails with an ENOMEM since it runs in to the allocated guard page.
|
||||
//
|
||||
// glibc notices the sbrk failure and falls back to regular mmap based allocations when this occurs. Ensuring that memory can still be allocated.
|
||||
void* DisableSBRKAllocations() {
|
||||
void* INVALID_PTR = reinterpret_cast<void*>(~0ULL);
|
||||
// Get the starting sbrk pointer.
|
||||
void* StartingSBRK = sbrk(0);
|
||||
if (StartingSBRK == INVALID_PTR) {
|
||||
// If sbrk is already returning invalid pointers then nothing to do here.
|
||||
return INVALID_PTR;
|
||||
}
|
||||
|
||||
// Now allocate the next page after the sbrk address to ensure it can't grow.
|
||||
// In most cases at the start of `main` this will already be page aligned, which means subsequent `sbrk`
|
||||
// calls won't allocate any memory through that.
|
||||
void* AlignedBRK = reinterpret_cast<void*>(FEXCore::AlignUp(reinterpret_cast<uintptr_t>(StartingSBRK), FEXCore::Utils::FEX_PAGE_SIZE));
|
||||
void* AfterBRK =
|
||||
::mmap(AlignedBRK, FEXCore::Utils::FEX_PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE | MAP_NORESERVE, -1, 0);
|
||||
if (AfterBRK == INVALID_PTR) {
|
||||
// Couldn't allocate the page after the aligned brk? This should never happen.
|
||||
// FEXCore::LogMan isn't configured yet so we just need to print the message.
|
||||
fextl::fmt::print("Couldn't allocate page after SBRK.\n");
|
||||
FEX_TRAP_EXECUTION;
|
||||
return INVALID_PTR;
|
||||
}
|
||||
|
||||
// Now that the page after sbrk is allocated, FEX needs to consume the remaining sbrk space.
|
||||
// This will be anywhere from [0, 4096) bytes.
|
||||
// Start allocating from 1024 byte increments just to make any steps a bit faster.
|
||||
intptr_t IncrementAmount = 1024;
|
||||
for (; IncrementAmount != 0; IncrementAmount >>= 1) {
|
||||
while (sbrk(IncrementAmount) != INVALID_PTR)
|
||||
;
|
||||
}
|
||||
return AlignedBRK;
|
||||
}
|
||||
|
||||
void ReenableSBRKAllocations(void* Ptr) {
|
||||
const void* INVALID_PTR = reinterpret_cast<void*>(~0ULL);
|
||||
if (Ptr != INVALID_PTR) {
|
||||
munmap(Ptr, FEXCore::Utils::FEX_PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
} // namespace FEX::SBRKAllocations
|
||||
@@ -0,0 +1,11 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#pragma once
|
||||
|
||||
namespace FEX::SBRKAllocations {
|
||||
// Disable allocations through glibc's sbrk allocation method.
|
||||
// Returns a pointer at the end of the sbrk region.
|
||||
void* DisableSBRKAllocations();
|
||||
|
||||
// Allow sbrk again. Pass in the pointer returned by `DisableSBRKAllocations`
|
||||
void ReenableSBRKAllocations(void* Ptr);
|
||||
} // namespace FEX::SBRKAllocations
|
||||
@@ -16,13 +16,12 @@ install(TARGETS FEXServerManager RUNTIME
|
||||
DESTINATION bin
|
||||
COMPONENT Runtime)
|
||||
|
||||
# Description json gets installed into root of depot
|
||||
install(FILES emulator.json
|
||||
DESTINATION /
|
||||
COMPONENT Runtime)
|
||||
install(FILES ConfigTemplate.json
|
||||
DESTINATION /
|
||||
COMPONENT Runtime)
|
||||
install(FILES toolmanifest.vdf
|
||||
# Description json and VERSION files are installed into the depot root
|
||||
configure_file(VERSIONS.txt.in ${CMAKE_CURRENT_BINARY_DIR}/VERSIONS.txt)
|
||||
install(FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/VERSIONS.txt
|
||||
ConfigTemplate.json
|
||||
emulator.json
|
||||
toolmanifest.vdf
|
||||
DESTINATION /
|
||||
COMPONENT Runtime)
|
||||
@@ -0,0 +1,2 @@
|
||||
FEX describe @GIT_DESCRIBE_STRING@
|
||||
FEX bash @GIT_HASH@
|
||||
@@ -1,6 +1,6 @@
|
||||
"manifest"
|
||||
{
|
||||
"commandline" "/FEXCompatTool %verb%"
|
||||
"commandline" "/fex-compat-tool %verb% --"
|
||||
"filter_exclusive_priority" "2"
|
||||
"version" "2"
|
||||
"use_tool_subprocess_reaper" "1"
|
||||
|
||||
@@ -44,6 +44,8 @@ class ELFCodeLoader final : public FEX::CodeLoader {
|
||||
|
||||
bool ElfValid {false};
|
||||
bool ExecutableStack {false};
|
||||
bool ExecuteAll {false};
|
||||
bool HasStackHeader {false};
|
||||
uintptr_t MainElfBase {};
|
||||
uintptr_t InterpeterElfBase {};
|
||||
uintptr_t MainElfEntrypoint {};
|
||||
@@ -304,7 +306,7 @@ public:
|
||||
}
|
||||
|
||||
// Append any additional arguments from config
|
||||
const auto AdditionalArgs = AdditionalArguments.All();
|
||||
const auto& AdditionalArgs = AdditionalArguments.All();
|
||||
ApplicationArgs.insert(ApplicationArgs.end(), AdditionalArgs.begin(), AdditionalArgs.end());
|
||||
|
||||
if (!MainElf.InterpreterElf.empty() && !SkipInterpreter) {
|
||||
@@ -334,7 +336,7 @@ public:
|
||||
}
|
||||
|
||||
if (AdditionalEnvp) {
|
||||
const auto EnvpList = AdditionalEnvp->All();
|
||||
const auto& EnvpList = AdditionalEnvp->All();
|
||||
EnvironmentVariables.insert(EnvironmentVariables.end(), EnvpList.begin(), EnvpList.end());
|
||||
}
|
||||
|
||||
@@ -391,6 +393,7 @@ public:
|
||||
bool MapMemory(FEX::HLE::SyscallMmapInterface* const Handler, FEXCore::Core::InternalThreadState* Thread) {
|
||||
for (const auto& Header : MainElf.phdrs) {
|
||||
if (Header.p_type == PT_GNU_STACK) {
|
||||
HasStackHeader = true;
|
||||
if (Header.p_flags & PF_X) {
|
||||
ExecutableStack = true;
|
||||
}
|
||||
@@ -400,11 +403,17 @@ public:
|
||||
// Both for the main and the interpreter elf
|
||||
}
|
||||
|
||||
if (!HasStackHeader && !Is64BitMode()) {
|
||||
// 32-bit behavior
|
||||
ExecutableStack = true;
|
||||
ExecuteAll = true;
|
||||
}
|
||||
|
||||
// Set the process personality here
|
||||
// This needs some more investigation
|
||||
// READ_IMPLIES_EXEC might be default for 32-bit elfs
|
||||
// Also, what about ADDR_LIMIT_3GB & co ?
|
||||
if (-1 == personality(PER_LINUX | (ExecutableStack ? READ_IMPLIES_EXEC : 0))) {
|
||||
uint32_t Personality = personality(~0ULL);
|
||||
Personality |= ExecuteAll ? READ_IMPLIES_EXEC : 0;
|
||||
if (-1 == personality(Personality)) {
|
||||
LogMan::Msg::EFmt("Setting personality failed");
|
||||
return false;
|
||||
}
|
||||
@@ -412,7 +421,7 @@ public:
|
||||
if (Thread) {
|
||||
// Update the thread persona.
|
||||
auto ThreadObject = static_cast<FEX::HLE::ThreadStateObject*>(Thread->FrontendPtr);
|
||||
ThreadObject->persona = ::personality(0xffffffff);
|
||||
ThreadObject->persona = Personality;
|
||||
}
|
||||
|
||||
// What about ASLR and such ?
|
||||
@@ -446,12 +455,31 @@ public:
|
||||
// On the upside, this more accurately emulates how the kernel allocates stack space for the application when hinting at the location.
|
||||
//
|
||||
void* StackPointerBase {};
|
||||
uint64_t StackHint = Is64BitMode() ? STACK_HINT_64 : STACK_HINT_32;
|
||||
auto VASize = FEXCore::Allocator::DetermineVASize();
|
||||
uint64_t StackHint {};
|
||||
if (Is64BitMode()) {
|
||||
if (VASize > 47) {
|
||||
// If VA size is at least as large as minimum x86 specification, then set to max.
|
||||
VASize = 47;
|
||||
}
|
||||
|
||||
// Allocate the base of the full 128MB stack range.
|
||||
StackPointerBase = Handler->GuestMmap(Thread, reinterpret_cast<void*>(StackHint), FULL_STACK_SIZE, PROT_NONE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK | MAP_GROWSDOWN | MAP_NORESERVE, -1, 0);
|
||||
// Calculate the highest point the stack could go.
|
||||
StackHint = (1ULL << VASize) - FULL_STACK_SIZE;
|
||||
} else {
|
||||
// Needs to be under the 4GB VA space.
|
||||
StackHint = 0x1'0000'0000ULL - FULL_STACK_SIZE;
|
||||
}
|
||||
|
||||
auto PageSize = sysconf(_SC_PAGESIZE);
|
||||
PageSize = PageSize > 0 ? PageSize : FEXCore::Utils::FEX_PAGE_SIZE;
|
||||
|
||||
do {
|
||||
// Allocate the base of the full 128MB stack range.
|
||||
StackPointerBase = Handler->GuestMmap(Thread, reinterpret_cast<void*>(StackHint), FULL_STACK_SIZE, PROT_NONE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK | MAP_GROWSDOWN | MAP_NORESERVE | MAP_FIXED_NOREPLACE, -1, 0);
|
||||
// Scan-downward until we fit.
|
||||
StackHint -= PageSize;
|
||||
} while (FEX::HLE::HasSyscallError(StackPointerBase) && static_cast<int64_t>(StackHint) > 0);
|
||||
|
||||
if (FEX::HLE::HasSyscallError(StackPointerBase)) {
|
||||
LogMan::Msg::EFmt("Allocating stack failed");
|
||||
@@ -459,9 +487,9 @@ public:
|
||||
}
|
||||
|
||||
// Allocate with permissions the 8MB of regular stack size.
|
||||
StackPointer = reinterpret_cast<uintptr_t>(
|
||||
Handler->GuestMmap(Thread, reinterpret_cast<void*>(reinterpret_cast<uint64_t>(StackPointerBase) + FULL_STACK_SIZE - StackSize()),
|
||||
StackSize(), PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK | MAP_GROWSDOWN, -1, 0));
|
||||
StackPointer = reinterpret_cast<uintptr_t>(Handler->GuestMmap(
|
||||
Thread, reinterpret_cast<void*>(reinterpret_cast<uint64_t>(StackPointerBase) + FULL_STACK_SIZE - StackSize()), StackSize(),
|
||||
PROT_READ | PROT_WRITE | (ExecutableStack ? PROT_EXEC : 0), MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK | MAP_GROWSDOWN, -1, 0));
|
||||
|
||||
if (FEX::HLE::HasSyscallError(StackPointer)) {
|
||||
LogMan::Msg::EFmt("Allocating stack failed");
|
||||
@@ -538,7 +566,6 @@ public:
|
||||
#define ASLR_LOAD
|
||||
#ifdef ASLR_LOAD
|
||||
// Only enable ASLR randomization if the personality has it enabled.
|
||||
uint32_t Personality = personality(~0ULL);
|
||||
bool NoRandomize = (Personality & ADDR_NO_RANDOMIZE) == ADDR_NO_RANDOMIZE;
|
||||
|
||||
if (!NoRandomize) {
|
||||
@@ -859,7 +886,8 @@ public:
|
||||
|
||||
// Setup ExecFN aux
|
||||
AuxExecFN->val = StackPointer + ExecFNLocation;
|
||||
strncpy(reinterpret_cast<char*>(AuxExecFN->val), ApplicationArgs[0].c_str(), ApplicationArgs[0].size() + 1);
|
||||
const auto InvocationName = reinterpret_cast<char*>(AuxExecFN->val);
|
||||
strncpy(InvocationName, ApplicationArgs[0].c_str(), ApplicationArgs[0].size() + 1);
|
||||
|
||||
// Stack setup
|
||||
// [0, 8): Argument Count
|
||||
@@ -884,6 +912,21 @@ public:
|
||||
}
|
||||
|
||||
RemapArgumentData(StackPointer + ArgumentOffset, ArgumentBackingSize);
|
||||
#if defined(HAS_PROGRAM_INVOCATION_NAME) && HAS_PROGRAM_INVOCATION_NAME
|
||||
// Set the glibc invocation names to the process name.
|
||||
// Mesa uses this to determine application profiles.
|
||||
// Necessary when thunking is enabled otherwise mesa would only see FEX.
|
||||
|
||||
std::string_view INV = std::string_view(InvocationName, ApplicationArgs[0].size());
|
||||
auto short_name = InvocationName;
|
||||
auto iter = INV.rfind('/');
|
||||
if (iter != INV.npos) {
|
||||
short_name = &InvocationName[iter + 1];
|
||||
}
|
||||
|
||||
program_invocation_name = InvocationName;
|
||||
program_invocation_short_name = short_name;
|
||||
#endif
|
||||
}
|
||||
|
||||
fextl::vector<const char*> GetExecveArguments() const override {
|
||||
@@ -986,8 +1029,6 @@ public:
|
||||
constexpr static uint64_t BRK_SIZE = 8 * 1024 * 1024;
|
||||
constexpr static uint64_t STACK_SIZE = 8 * 1024 * 1024;
|
||||
constexpr static uint64_t FULL_STACK_SIZE = 128 * 1024 * 1024;
|
||||
constexpr static uint64_t STACK_HINT_32 = 0xFFFFE000 - FULL_STACK_SIZE;
|
||||
constexpr static uint64_t STACK_HINT_64 = 0x7FFFFFFFF000 - FULL_STACK_SIZE;
|
||||
|
||||
fextl::vector<fextl::string> EnvironmentVariables;
|
||||
fextl::vector<const char*> LoaderArgs;
|
||||
|
||||
@@ -10,6 +10,7 @@ $end_info$
|
||||
#include "Common/FEXServerClient.h"
|
||||
#include "Common/Config.h"
|
||||
#include "Common/HostFeatures.h"
|
||||
#include "Common/Linux/SBRKAllocations.h"
|
||||
#include "PortabilityInfo.h"
|
||||
#include "ELFCodeLoader.h"
|
||||
#include "VDSO_Emulation.h"
|
||||
@@ -142,40 +143,49 @@ void Init() {
|
||||
} // namespace FEX::Logging
|
||||
|
||||
namespace FEX::Allocator {
|
||||
static fextl::unique_ptr<FEX::HLE::MemAllocator> Allocator;
|
||||
static fextl::vector<FEXCore::Allocator::MemoryRegion> Base48Bit;
|
||||
static fextl::vector<FEXCore::Allocator::MemoryRegion> Low4GB;
|
||||
|
||||
void Init(bool Is64Bit) {
|
||||
fextl::vector<FEXCore::Allocator::MemoryRegion> InitMemoryRegions(bool Is64Bit) {
|
||||
const auto PageSize = sysconf(_SC_PAGESIZE);
|
||||
if (Is64Bit) {
|
||||
// Destroy the 48th bit if it exists
|
||||
Base48Bit = FEXCore::Allocator::Setup48BitAllocatorIfExists();
|
||||
} else {
|
||||
// Reserve [0x1_0000_0000, 0x2_0000_0000).
|
||||
// Safety net if 32-bit address calculation overflows in to 64-bit range.
|
||||
constexpr uint64_t First64BitAddr = 0x1'0000'0000ULL;
|
||||
Low4GB = FEXCore::Allocator::StealMemoryRegion(First64BitAddr, First64BitAddr + First64BitAddr);
|
||||
|
||||
// Setup our userspace allocator
|
||||
FEXCore::Allocator::SetupHooks();
|
||||
Allocator = FEX::HLE::CreatePassthroughAllocator();
|
||||
|
||||
// Now that the upper 32-bit address space is blocked for future allocations,
|
||||
// exhaust all of jemalloc's remaining internal allocations that it reserved before.
|
||||
// TODO: It's unclear how reliably this exhausts those reserves
|
||||
FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc;
|
||||
void* data;
|
||||
do {
|
||||
data = malloc(0x1);
|
||||
} while (reinterpret_cast<uintptr_t>(data) >> 32 != 0);
|
||||
free(data);
|
||||
return FEXCore::Allocator::Setup48BitAllocatorIfExists(PageSize > 0 ? PageSize : FEXCore::Utils::FEX_PAGE_SIZE);
|
||||
}
|
||||
|
||||
// Reserve [0x1_0000_0000, 0x2_0000_0000).
|
||||
// Safety net if 32-bit address calculation overflows in to 64-bit range.
|
||||
constexpr uint64_t First64BitAddr = 0x1'0000'0000ULL;
|
||||
return FEXCore::Allocator::StealMemoryRegion(First64BitAddr, First64BitAddr + First64BitAddr);
|
||||
}
|
||||
|
||||
void Shutdown() {
|
||||
fextl::unique_ptr<FEX::HLE::MemAllocator> InitAllocator(bool Is64Bit) {
|
||||
if (Is64Bit) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto PageSize = sysconf(_SC_PAGESIZE);
|
||||
|
||||
// Setup our userspace allocator
|
||||
FEXCore::Allocator::SetupHooks(PageSize > 0 ? PageSize : FEXCore::Utils::FEX_PAGE_SIZE);
|
||||
auto Allocator = FEX::HLE::CreatePassthroughAllocator();
|
||||
|
||||
// Now that the upper 32-bit address space is blocked for future allocations,
|
||||
// exhaust all of jemalloc's remaining internal allocations that it reserved before.
|
||||
// TODO: It's unclear how reliably this exhausts those reserves
|
||||
// TODO: This will likely consume one arena inside the 32-bit VA space.
|
||||
// - (HdkR): I've noticed jemalloc consuming an 8MB arena commonly.
|
||||
FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc;
|
||||
void* data;
|
||||
do {
|
||||
data = malloc(0x1);
|
||||
} while (reinterpret_cast<uintptr_t>(data) >> 32 != 0);
|
||||
free(data);
|
||||
|
||||
return Allocator;
|
||||
}
|
||||
|
||||
void Shutdown(fextl::vector<FEXCore::Allocator::MemoryRegion>&& MemoryRegions) {
|
||||
FEXCore::Allocator::ClearHooks();
|
||||
FEXCore::Allocator::ReclaimMemoryRegion(Base48Bit);
|
||||
FEXCore::Allocator::ReclaimMemoryRegion(Low4GB);
|
||||
FEXCore::Allocator::ReclaimMemoryRegion(MemoryRegions);
|
||||
}
|
||||
} // namespace FEX::Allocator
|
||||
|
||||
@@ -360,7 +370,7 @@ static int StealFEXFDFromEnv(const char* Env) {
|
||||
}
|
||||
|
||||
int main(int argc, char** argv, char** const envp) {
|
||||
auto SBRKPointer = FEXCore::Allocator::DisableSBRKAllocations();
|
||||
auto SBRKPointer = FEX::SBRKAllocations::DisableSBRKAllocations();
|
||||
FEXCore::Allocator::GLIBCScopedFault GLIBFaultScope;
|
||||
|
||||
const bool ExecutedWithFD = getauxval(AT_EXECFD) != 0;
|
||||
@@ -395,6 +405,11 @@ int main(int argc, char** argv, char** const envp) {
|
||||
FEXCore::Config::Set(FEXCore::Config::CONFIG_DISABLE_VIXL_INDIRECT_RUNTIME_CALLS, "0");
|
||||
#endif
|
||||
|
||||
if (FEXSeccompFD != -1) {
|
||||
// seccomp inheritance happens unconditionally.
|
||||
FEXCore::Config::Set(FEXCore::Config::CONFIG_NEEDSSECCOMP, "1");
|
||||
}
|
||||
|
||||
// Early check for process stall
|
||||
// Doesn't use CONFIG_ROOTFS and we don't want it to spin up a squashfs instance
|
||||
FEX_CONFIG_OPT(StallProcess, STALLPROCESS);
|
||||
@@ -503,7 +518,8 @@ int main(int argc, char** argv, char** const envp) {
|
||||
// Setup Thread handlers, so FEXCore can create threads.
|
||||
auto StackTracker = FEX::LinuxEmulation::Threads::SetupThreadHandlers();
|
||||
|
||||
FEX::Allocator::Init(Loader.Is64BitMode());
|
||||
auto MemoryRegions = FEX::Allocator::InitMemoryRegions(Loader.Is64BitMode());
|
||||
auto Allocator = FEX::Allocator::InitAllocator(Loader.Is64BitMode());
|
||||
|
||||
FEXCore::Profiler::Init(Program.ProgramName, Program.ProgramPath);
|
||||
|
||||
@@ -520,9 +536,9 @@ int main(int argc, char** argv, char** const envp) {
|
||||
auto SignalDelegation = FEX::HLE::CreateSignalDelegator(CTX.get(), Program.ProgramName, SupportsAVX);
|
||||
auto ThunkHandler = FEX::HLE::CreateThunkHandler();
|
||||
|
||||
auto SyscallHandler = Loader.Is64BitMode() ? FEX::HLE::x64::CreateHandler(CTX.get(), SignalDelegation.get(), ThunkHandler.get()) :
|
||||
FEX::HLE::x32::CreateHandler(CTX.get(), SignalDelegation.get(), ThunkHandler.get(),
|
||||
std::move(FEX::Allocator::Allocator));
|
||||
auto SyscallHandler = Loader.Is64BitMode() ?
|
||||
FEX::HLE::x64::CreateHandler(CTX.get(), SignalDelegation.get(), ThunkHandler.get()) :
|
||||
FEX::HLE::x32::CreateHandler(CTX.get(), SignalDelegation.get(), ThunkHandler.get(), std::move(Allocator));
|
||||
SyscallHandler->SetCodeLoader(&Loader);
|
||||
CTX->SetSignalDelegator(SignalDelegation.get());
|
||||
CTX->SetSyscallHandler(SyscallHandler.get());
|
||||
@@ -618,13 +634,13 @@ int main(int argc, char** argv, char** const envp) {
|
||||
LogMan::Throw::UnInstallHandler();
|
||||
LogMan::Msg::UnInstallHandler();
|
||||
|
||||
FEX::Allocator::Shutdown();
|
||||
FEX::Allocator::Shutdown(std::move(MemoryRegions));
|
||||
|
||||
// Allocator is now original system allocator
|
||||
FEXCore::Telemetry::Shutdown(Program.ProgramName);
|
||||
FEXCore::Profiler::Shutdown();
|
||||
|
||||
FEXCore::Allocator::ReenableSBRKAllocations(SBRKPointer);
|
||||
FEX::SBRKAllocations::ReenableSBRKAllocations(SBRKPointer);
|
||||
|
||||
return ProgramStatus;
|
||||
}
|
||||
@@ -154,8 +154,9 @@ GenerateSingleCache(const FEXCore::ExecutableFileInfo& Binary, fextl::set<uintpt
|
||||
}
|
||||
|
||||
if (!Is64Bit) {
|
||||
const auto PageSize = sysconf(_SC_PAGESIZE);
|
||||
// Block upper address space
|
||||
FEXCore::Allocator::SetupHooks();
|
||||
FEXCore::Allocator::SetupHooks(PageSize > 0 ? PageSize : FEXCore::Utils::FEX_PAGE_SIZE);
|
||||
}
|
||||
|
||||
auto Thread = SetupCompileThread(*CTX, Is64Bit);
|
||||
|
||||
@@ -35,7 +35,8 @@ namespace x86_64 {
|
||||
* context area.
|
||||
*/
|
||||
struct FEX_PACKED fpx_sw_bytes {
|
||||
static constexpr uint32_t FP_XSTATE_MAGIC = 0x46505853;
|
||||
static constexpr uint32_t FP_XSTATE_MAGIC_1 = 0x46505853;
|
||||
static constexpr uint32_t FP_XSTATE_MAGIC_2 = 0x46505845;
|
||||
|
||||
enum FeatureFlag : uint32_t {
|
||||
FEATURE_FP = 1U << 0,
|
||||
@@ -60,20 +61,20 @@ namespace x86_64 {
|
||||
};
|
||||
|
||||
bool HasExtendedContext() const {
|
||||
return magic1 == FP_XSTATE_MAGIC;
|
||||
return magic1 == FP_XSTATE_MAGIC_1;
|
||||
}
|
||||
|
||||
bool HasYMMH() const {
|
||||
return (xfeatures & FEATURE_YMM) != 0;
|
||||
}
|
||||
|
||||
// If magic1 is set to FP_XSTATE_MAGIC, then the encompassing
|
||||
// If magic1 is set to FP_XSTATE_MAGIC_1, then the encompassing
|
||||
// frame is an xstate frame. If 0, then it's a legacy frame.
|
||||
uint32_t magic1;
|
||||
|
||||
// Total size of the fpstate area
|
||||
// - magic1 = 0 -> sizeof(fpstate)
|
||||
// - magic1 = FP_XSTATE_MAGIC -> sizeof(xstate) + extensions (if any)
|
||||
// - magic1 = 0 -> sizeof(fpstate)
|
||||
// - magic1 = FP_XSTATE_MAGIC_1 -> sizeof(xstate) + extensions (if any)
|
||||
uint32_t extended_size;
|
||||
|
||||
// Feature bitmask describing supported features.
|
||||
@@ -119,6 +120,12 @@ namespace x86_64 {
|
||||
};
|
||||
static_assert(sizeof(ymmh_state) == 256);
|
||||
|
||||
struct FEX_PACKED magic2 {
|
||||
uint32_t pad;
|
||||
uint32_t magic;
|
||||
};
|
||||
static_assert(sizeof(magic2) == sizeof(uint64_t));
|
||||
|
||||
/**
|
||||
* Extended state that includes both the main fpstate
|
||||
* and the extended state.
|
||||
@@ -127,8 +134,9 @@ namespace x86_64 {
|
||||
_libc_fpstate fpstate;
|
||||
xstate_header xstate_hdr;
|
||||
ymmh_state ymmh;
|
||||
magic2 magic2 {};
|
||||
};
|
||||
static_assert(sizeof(xstate) == 832);
|
||||
static_assert(sizeof(xstate) == 840);
|
||||
|
||||
///< The order of these must match the GNU ordering
|
||||
enum ContextRegs {
|
||||
@@ -386,8 +394,9 @@ namespace x86 {
|
||||
_libc_fpstate fpstate;
|
||||
xstate_header xstate_hdr;
|
||||
ymmh_state ymmh;
|
||||
x86_64::magic2 magic2 {};
|
||||
};
|
||||
static_assert(sizeof(xstate) == 944);
|
||||
static_assert(sizeof(xstate) == 952);
|
||||
|
||||
struct FEX_PACKED ucontext_t {
|
||||
uint32_t uc_flags;
|
||||
|
||||
@@ -106,7 +106,7 @@ void FileManager::LoadThunkDatabase(fextl::unordered_map<fextl::string, ThunkDBO
|
||||
return;
|
||||
}
|
||||
|
||||
std::string_view HomeDirectory = FEX::Config::GetHomeDirectory();
|
||||
auto HomeDirectory = FEX::Config::GetHomeDirectory();
|
||||
|
||||
for (const json_t* Library = json_getChild(DB); Library != nullptr; Library = json_getSibling(Library)) {
|
||||
// Get the user defined name for the library
|
||||
|
||||
Loaded 100 of 218 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user