diff --git a/.github/workflows/build-recompile-dataset.yml b/.github/workflows/build-recompile-dataset.yml new file mode 100644 index 00000000..7a64c761 --- /dev/null +++ b/.github/workflows/build-recompile-dataset.yml @@ -0,0 +1,114 @@ +# Build recompile-dataset binaries with MSVC on Windows. +# +# Triggers on changes to the dataset sources. Compiles each source file +# with cl.exe at multiple optimisation levels for both x86 and x64, +# then commits the PE binaries back to the repository. +# +name: Build recompile-dataset (MSVC) + +on: + push: + paths: + - 'tests_src/recompile_dataset/**' + workflow_dispatch: # manual trigger + +permissions: + contents: write + +jobs: + build-msvc: + runs-on: windows-latest + strategy: + matrix: + include: + - arch: x64 + outdir: tests/x86_64/recompile_dataset_pe + - arch: x86 + outdir: tests/i386/recompile_dataset_pe + steps: + - uses: actions/checkout@v4 + + - name: Setup MSVC + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: ${{ matrix.arch }} + + - name: Build binaries + shell: cmd + env: + OUTDIR: ${{ matrix.outdir }} + run: | + setlocal enabledelayedexpansion + mkdir "%OUTDIR%" 2>nul + + set SRCS=t1_control_flow t2_types t3_memory t4_calling t5_patterns + set OPTS=/O1 /O2 /Os /Ox + set COUNT=0 + set FAIL=0 + + for %%S in (!SRCS!) do ( + for %%O in (!OPTS!) do ( + set "TAG=%%O" + set "TAG=!TAG:/=!" + set "NAME=%%S_msvc_!TAG!.exe" + echo Building !NAME! ... + + cl.exe /nologo %%O /Zi /Fe:"!OUTDIR!\!NAME!" ^ + tests_src\recompile_dataset\%%S.c ^ + tests_src\recompile_dataset\dummy_main.c ^ + /link /DEBUG /PDB:"!OUTDIR!\%%S_msvc_!TAG!.pdb" + if !errorlevel! equ 0 ( + set /a COUNT+=1 + ) else ( + echo FAILED: !NAME! + set FAIL=1 + ) + ) + ) + + rem Clean up intermediate files in working directory + del /q *.obj 2>nul + del /q "!OUTDIR!\*.ilk" 2>nul + + echo. + echo Built !COUNT! binaries. + if !FAIL! neq 0 ( + echo Some builds failed. + exit /b 1 + ) + + - name: Upload binaries + uses: actions/upload-artifact@v4 + with: + name: recompile-dataset-pe-${{ matrix.arch }} + path: ${{ matrix.outdir }}/ + + commit-binaries: + needs: build-msvc + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Download x64 binaries + uses: actions/download-artifact@v4 + with: + name: recompile-dataset-pe-x64 + path: tests/x86_64/recompile_dataset_pe/ + + - name: Download x86 binaries + uses: actions/download-artifact@v4 + with: + name: recompile-dataset-pe-x86 + path: tests/i386/recompile_dataset_pe/ + + - name: Commit binaries + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add tests/x86_64/recompile_dataset_pe/ tests/i386/recompile_dataset_pe/ + if git diff --cached --quiet; then + echo "No changes to commit." + else + git commit -m "ci: rebuild MSVC recompile-dataset binaries [skip ci]" + git push + fi diff --git a/tests/aarch64/ccop_triggers/ccop_arm_adc_sbb_O1 b/tests/aarch64/ccop_triggers/ccop_arm_adc_sbb_O1 new file mode 100755 index 00000000..df6f2586 Binary files /dev/null and b/tests/aarch64/ccop_triggers/ccop_arm_adc_sbb_O1 differ diff --git a/tests/aarch64/ccop_triggers/ccop_arm_adc_sbb_O2 b/tests/aarch64/ccop_triggers/ccop_arm_adc_sbb_O2 new file mode 100755 index 00000000..d3d62eef Binary files /dev/null and b/tests/aarch64/ccop_triggers/ccop_arm_adc_sbb_O2 differ diff --git a/tests/aarch64/ccop_triggers/ccop_arm_adc_sbb_Os b/tests/aarch64/ccop_triggers/ccop_arm_adc_sbb_Os new file mode 100755 index 00000000..a374d0a2 Binary files /dev/null and b/tests/aarch64/ccop_triggers/ccop_arm_adc_sbb_Os differ diff --git a/tests/aarch64/ccop_triggers/ccop_arm_add_O1 b/tests/aarch64/ccop_triggers/ccop_arm_add_O1 new file mode 100755 index 00000000..4dc03c09 Binary files /dev/null and b/tests/aarch64/ccop_triggers/ccop_arm_add_O1 differ diff --git a/tests/aarch64/ccop_triggers/ccop_arm_add_O2 b/tests/aarch64/ccop_triggers/ccop_arm_add_O2 new file mode 100755 index 00000000..6cc1d85e Binary files /dev/null and b/tests/aarch64/ccop_triggers/ccop_arm_add_O2 differ diff --git a/tests/aarch64/ccop_triggers/ccop_arm_add_Os b/tests/aarch64/ccop_triggers/ccop_arm_add_Os new file mode 100755 index 00000000..f7b4bd85 Binary files /dev/null and b/tests/aarch64/ccop_triggers/ccop_arm_add_Os differ diff --git a/tests/aarch64/ccop_triggers/ccop_arm_logic_O1 b/tests/aarch64/ccop_triggers/ccop_arm_logic_O1 new file mode 100755 index 00000000..409f7a15 Binary files /dev/null and b/tests/aarch64/ccop_triggers/ccop_arm_logic_O1 differ diff --git a/tests/aarch64/ccop_triggers/ccop_arm_logic_O2 b/tests/aarch64/ccop_triggers/ccop_arm_logic_O2 new file mode 100755 index 00000000..35c81d3f Binary files /dev/null and b/tests/aarch64/ccop_triggers/ccop_arm_logic_O2 differ diff --git a/tests/aarch64/ccop_triggers/ccop_arm_logic_Os b/tests/aarch64/ccop_triggers/ccop_arm_logic_Os new file mode 100755 index 00000000..e9ad9f61 Binary files /dev/null and b/tests/aarch64/ccop_triggers/ccop_arm_logic_Os differ diff --git a/tests/aarch64/ccop_triggers/ccop_arm_sub_O1 b/tests/aarch64/ccop_triggers/ccop_arm_sub_O1 new file mode 100755 index 00000000..9d356f17 Binary files /dev/null and b/tests/aarch64/ccop_triggers/ccop_arm_sub_O1 differ diff --git a/tests/aarch64/ccop_triggers/ccop_arm_sub_O2 b/tests/aarch64/ccop_triggers/ccop_arm_sub_O2 new file mode 100755 index 00000000..d188c785 Binary files /dev/null and b/tests/aarch64/ccop_triggers/ccop_arm_sub_O2 differ diff --git a/tests/aarch64/ccop_triggers/ccop_arm_sub_Os b/tests/aarch64/ccop_triggers/ccop_arm_sub_Os new file mode 100755 index 00000000..cee18efb Binary files /dev/null and b/tests/aarch64/ccop_triggers/ccop_arm_sub_Os differ diff --git a/tests/armhf/ccop_triggers/ccop_arm_adc_sbb_O1 b/tests/armhf/ccop_triggers/ccop_arm_adc_sbb_O1 new file mode 100755 index 00000000..9ad04b65 Binary files /dev/null and b/tests/armhf/ccop_triggers/ccop_arm_adc_sbb_O1 differ diff --git a/tests/armhf/ccop_triggers/ccop_arm_adc_sbb_O2 b/tests/armhf/ccop_triggers/ccop_arm_adc_sbb_O2 new file mode 100755 index 00000000..c0c7bf84 Binary files /dev/null and b/tests/armhf/ccop_triggers/ccop_arm_adc_sbb_O2 differ diff --git a/tests/armhf/ccop_triggers/ccop_arm_adc_sbb_Os b/tests/armhf/ccop_triggers/ccop_arm_adc_sbb_Os new file mode 100755 index 00000000..32d7b123 Binary files /dev/null and b/tests/armhf/ccop_triggers/ccop_arm_adc_sbb_Os differ diff --git a/tests/armhf/ccop_triggers/ccop_arm_add_O1 b/tests/armhf/ccop_triggers/ccop_arm_add_O1 new file mode 100755 index 00000000..b42fd691 Binary files /dev/null and b/tests/armhf/ccop_triggers/ccop_arm_add_O1 differ diff --git a/tests/armhf/ccop_triggers/ccop_arm_add_O2 b/tests/armhf/ccop_triggers/ccop_arm_add_O2 new file mode 100755 index 00000000..f5c0a427 Binary files /dev/null and b/tests/armhf/ccop_triggers/ccop_arm_add_O2 differ diff --git a/tests/armhf/ccop_triggers/ccop_arm_add_Os b/tests/armhf/ccop_triggers/ccop_arm_add_Os new file mode 100755 index 00000000..e13d0048 Binary files /dev/null and b/tests/armhf/ccop_triggers/ccop_arm_add_Os differ diff --git a/tests/armhf/ccop_triggers/ccop_arm_logic_O1 b/tests/armhf/ccop_triggers/ccop_arm_logic_O1 new file mode 100755 index 00000000..f9441b78 Binary files /dev/null and b/tests/armhf/ccop_triggers/ccop_arm_logic_O1 differ diff --git a/tests/armhf/ccop_triggers/ccop_arm_logic_O2 b/tests/armhf/ccop_triggers/ccop_arm_logic_O2 new file mode 100755 index 00000000..09a90b50 Binary files /dev/null and b/tests/armhf/ccop_triggers/ccop_arm_logic_O2 differ diff --git a/tests/armhf/ccop_triggers/ccop_arm_logic_Os b/tests/armhf/ccop_triggers/ccop_arm_logic_Os new file mode 100755 index 00000000..f24a3bce Binary files /dev/null and b/tests/armhf/ccop_triggers/ccop_arm_logic_Os differ diff --git a/tests/armhf/ccop_triggers/ccop_arm_sub_O1 b/tests/armhf/ccop_triggers/ccop_arm_sub_O1 new file mode 100755 index 00000000..fee0f1fe Binary files /dev/null and b/tests/armhf/ccop_triggers/ccop_arm_sub_O1 differ diff --git a/tests/armhf/ccop_triggers/ccop_arm_sub_O2 b/tests/armhf/ccop_triggers/ccop_arm_sub_O2 new file mode 100755 index 00000000..d5f0acf9 Binary files /dev/null and b/tests/armhf/ccop_triggers/ccop_arm_sub_O2 differ diff --git a/tests/armhf/ccop_triggers/ccop_arm_sub_Os b/tests/armhf/ccop_triggers/ccop_arm_sub_Os new file mode 100755 index 00000000..5aa08fcc Binary files /dev/null and b/tests/armhf/ccop_triggers/ccop_arm_sub_Os differ diff --git a/tests/i386/ccop_triggers/ccop_adc_sbb_O1 b/tests/i386/ccop_triggers/ccop_adc_sbb_O1 new file mode 100755 index 00000000..c3e3c66e Binary files /dev/null and b/tests/i386/ccop_triggers/ccop_adc_sbb_O1 differ diff --git a/tests/i386/ccop_triggers/ccop_adc_sbb_O2 b/tests/i386/ccop_triggers/ccop_adc_sbb_O2 new file mode 100755 index 00000000..d374a100 Binary files /dev/null and b/tests/i386/ccop_triggers/ccop_adc_sbb_O2 differ diff --git a/tests/i386/ccop_triggers/ccop_adc_sbb_Os b/tests/i386/ccop_triggers/ccop_adc_sbb_Os new file mode 100755 index 00000000..1fa06386 Binary files /dev/null and b/tests/i386/ccop_triggers/ccop_adc_sbb_Os differ diff --git a/tests/i386/ccop_triggers/ccop_add_O1 b/tests/i386/ccop_triggers/ccop_add_O1 new file mode 100755 index 00000000..e64a9d58 Binary files /dev/null and b/tests/i386/ccop_triggers/ccop_add_O1 differ diff --git a/tests/i386/ccop_triggers/ccop_add_O2 b/tests/i386/ccop_triggers/ccop_add_O2 new file mode 100755 index 00000000..c534cba5 Binary files /dev/null and b/tests/i386/ccop_triggers/ccop_add_O2 differ diff --git a/tests/i386/ccop_triggers/ccop_add_Os b/tests/i386/ccop_triggers/ccop_add_Os new file mode 100755 index 00000000..9329677f Binary files /dev/null and b/tests/i386/ccop_triggers/ccop_add_Os differ diff --git a/tests/i386/ccop_triggers/ccop_copy_O1 b/tests/i386/ccop_triggers/ccop_copy_O1 new file mode 100755 index 00000000..ef133ab6 Binary files /dev/null and b/tests/i386/ccop_triggers/ccop_copy_O1 differ diff --git a/tests/i386/ccop_triggers/ccop_copy_O2 b/tests/i386/ccop_triggers/ccop_copy_O2 new file mode 100755 index 00000000..e0b5a77b Binary files /dev/null and b/tests/i386/ccop_triggers/ccop_copy_O2 differ diff --git a/tests/i386/ccop_triggers/ccop_copy_Os b/tests/i386/ccop_triggers/ccop_copy_Os new file mode 100755 index 00000000..b8980e08 Binary files /dev/null and b/tests/i386/ccop_triggers/ccop_copy_Os differ diff --git a/tests/i386/ccop_triggers/ccop_inc_dec_O1_incdec b/tests/i386/ccop_triggers/ccop_inc_dec_O1_incdec new file mode 100755 index 00000000..83f636e2 Binary files /dev/null and b/tests/i386/ccop_triggers/ccop_inc_dec_O1_incdec differ diff --git a/tests/i386/ccop_triggers/ccop_inc_dec_O2_haswell b/tests/i386/ccop_triggers/ccop_inc_dec_O2_haswell new file mode 100755 index 00000000..dd5a0a92 Binary files /dev/null and b/tests/i386/ccop_triggers/ccop_inc_dec_O2_haswell differ diff --git a/tests/i386/ccop_triggers/ccop_inc_dec_Os_incdec b/tests/i386/ccop_triggers/ccop_inc_dec_Os_incdec new file mode 100755 index 00000000..38c67757 Binary files /dev/null and b/tests/i386/ccop_triggers/ccop_inc_dec_Os_incdec differ diff --git a/tests/i386/ccop_triggers/ccop_logic_O1 b/tests/i386/ccop_triggers/ccop_logic_O1 new file mode 100755 index 00000000..455e199f Binary files /dev/null and b/tests/i386/ccop_triggers/ccop_logic_O1 differ diff --git a/tests/i386/ccop_triggers/ccop_logic_O2 b/tests/i386/ccop_triggers/ccop_logic_O2 new file mode 100755 index 00000000..9689c30c Binary files /dev/null and b/tests/i386/ccop_triggers/ccop_logic_O2 differ diff --git a/tests/i386/ccop_triggers/ccop_logic_Os b/tests/i386/ccop_triggers/ccop_logic_Os new file mode 100755 index 00000000..56c62681 Binary files /dev/null and b/tests/i386/ccop_triggers/ccop_logic_Os differ diff --git a/tests/i386/ccop_triggers/ccop_rflags_c_O1 b/tests/i386/ccop_triggers/ccop_rflags_c_O1 new file mode 100755 index 00000000..47c35550 Binary files /dev/null and b/tests/i386/ccop_triggers/ccop_rflags_c_O1 differ diff --git a/tests/i386/ccop_triggers/ccop_rflags_c_O2 b/tests/i386/ccop_triggers/ccop_rflags_c_O2 new file mode 100755 index 00000000..677a5949 Binary files /dev/null and b/tests/i386/ccop_triggers/ccop_rflags_c_O2 differ diff --git a/tests/i386/ccop_triggers/ccop_rflags_c_Os b/tests/i386/ccop_triggers/ccop_rflags_c_Os new file mode 100755 index 00000000..7af80bcb Binary files /dev/null and b/tests/i386/ccop_triggers/ccop_rflags_c_Os differ diff --git a/tests/i386/ccop_triggers/ccop_shl_shr_O1 b/tests/i386/ccop_triggers/ccop_shl_shr_O1 new file mode 100755 index 00000000..0d93a6af Binary files /dev/null and b/tests/i386/ccop_triggers/ccop_shl_shr_O1 differ diff --git a/tests/i386/ccop_triggers/ccop_shl_shr_O2 b/tests/i386/ccop_triggers/ccop_shl_shr_O2 new file mode 100755 index 00000000..50c46740 Binary files /dev/null and b/tests/i386/ccop_triggers/ccop_shl_shr_O2 differ diff --git a/tests/i386/ccop_triggers/ccop_shl_shr_Os b/tests/i386/ccop_triggers/ccop_shl_shr_Os new file mode 100755 index 00000000..208e7e87 Binary files /dev/null and b/tests/i386/ccop_triggers/ccop_shl_shr_Os differ diff --git a/tests/i386/ccop_triggers/ccop_sub_O1 b/tests/i386/ccop_triggers/ccop_sub_O1 new file mode 100755 index 00000000..495b4693 Binary files /dev/null and b/tests/i386/ccop_triggers/ccop_sub_O1 differ diff --git a/tests/i386/ccop_triggers/ccop_sub_O2 b/tests/i386/ccop_triggers/ccop_sub_O2 new file mode 100755 index 00000000..88b60fe3 Binary files /dev/null and b/tests/i386/ccop_triggers/ccop_sub_O2 differ diff --git a/tests/i386/ccop_triggers/ccop_sub_Os b/tests/i386/ccop_triggers/ccop_sub_Os new file mode 100755 index 00000000..3b96d996 Binary files /dev/null and b/tests/i386/ccop_triggers/ccop_sub_Os differ diff --git a/tests/i386/ccop_triggers/ccop_umul_smul_O1 b/tests/i386/ccop_triggers/ccop_umul_smul_O1 new file mode 100755 index 00000000..e24a8023 Binary files /dev/null and b/tests/i386/ccop_triggers/ccop_umul_smul_O1 differ diff --git a/tests/i386/ccop_triggers/ccop_umul_smul_O2 b/tests/i386/ccop_triggers/ccop_umul_smul_O2 new file mode 100755 index 00000000..8d1c0553 Binary files /dev/null and b/tests/i386/ccop_triggers/ccop_umul_smul_O2 differ diff --git a/tests/i386/ccop_triggers/ccop_umul_smul_Os b/tests/i386/ccop_triggers/ccop_umul_smul_Os new file mode 100755 index 00000000..bc44030c Binary files /dev/null and b/tests/i386/ccop_triggers/ccop_umul_smul_Os differ diff --git a/tests/i386/recompile_dataset_pe/t1_control_flow_msvc_O1.exe b/tests/i386/recompile_dataset_pe/t1_control_flow_msvc_O1.exe new file mode 100644 index 00000000..d89f9d43 Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t1_control_flow_msvc_O1.exe differ diff --git a/tests/i386/recompile_dataset_pe/t1_control_flow_msvc_O1.pdb b/tests/i386/recompile_dataset_pe/t1_control_flow_msvc_O1.pdb new file mode 100644 index 00000000..6a8d3d27 Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t1_control_flow_msvc_O1.pdb differ diff --git a/tests/i386/recompile_dataset_pe/t1_control_flow_msvc_O2.exe b/tests/i386/recompile_dataset_pe/t1_control_flow_msvc_O2.exe new file mode 100644 index 00000000..5afcc521 Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t1_control_flow_msvc_O2.exe differ diff --git a/tests/i386/recompile_dataset_pe/t1_control_flow_msvc_O2.pdb b/tests/i386/recompile_dataset_pe/t1_control_flow_msvc_O2.pdb new file mode 100644 index 00000000..c2796634 Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t1_control_flow_msvc_O2.pdb differ diff --git a/tests/i386/recompile_dataset_pe/t1_control_flow_msvc_Os.exe b/tests/i386/recompile_dataset_pe/t1_control_flow_msvc_Os.exe new file mode 100644 index 00000000..20b79ed6 Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t1_control_flow_msvc_Os.exe differ diff --git a/tests/i386/recompile_dataset_pe/t1_control_flow_msvc_Os.pdb b/tests/i386/recompile_dataset_pe/t1_control_flow_msvc_Os.pdb new file mode 100644 index 00000000..25108f66 Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t1_control_flow_msvc_Os.pdb differ diff --git a/tests/i386/recompile_dataset_pe/t1_control_flow_msvc_Ox.exe b/tests/i386/recompile_dataset_pe/t1_control_flow_msvc_Ox.exe new file mode 100644 index 00000000..e81f8ce0 Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t1_control_flow_msvc_Ox.exe differ diff --git a/tests/i386/recompile_dataset_pe/t1_control_flow_msvc_Ox.pdb b/tests/i386/recompile_dataset_pe/t1_control_flow_msvc_Ox.pdb new file mode 100644 index 00000000..6d39254f Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t1_control_flow_msvc_Ox.pdb differ diff --git a/tests/i386/recompile_dataset_pe/t2_types_msvc_O1.exe b/tests/i386/recompile_dataset_pe/t2_types_msvc_O1.exe new file mode 100644 index 00000000..8763c0f3 Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t2_types_msvc_O1.exe differ diff --git a/tests/i386/recompile_dataset_pe/t2_types_msvc_O1.pdb b/tests/i386/recompile_dataset_pe/t2_types_msvc_O1.pdb new file mode 100644 index 00000000..384c2f9d Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t2_types_msvc_O1.pdb differ diff --git a/tests/i386/recompile_dataset_pe/t2_types_msvc_O2.exe b/tests/i386/recompile_dataset_pe/t2_types_msvc_O2.exe new file mode 100644 index 00000000..d4308f4a Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t2_types_msvc_O2.exe differ diff --git a/tests/i386/recompile_dataset_pe/t2_types_msvc_O2.pdb b/tests/i386/recompile_dataset_pe/t2_types_msvc_O2.pdb new file mode 100644 index 00000000..9633f984 Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t2_types_msvc_O2.pdb differ diff --git a/tests/i386/recompile_dataset_pe/t2_types_msvc_Os.exe b/tests/i386/recompile_dataset_pe/t2_types_msvc_Os.exe new file mode 100644 index 00000000..5646567f Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t2_types_msvc_Os.exe differ diff --git a/tests/i386/recompile_dataset_pe/t2_types_msvc_Os.pdb b/tests/i386/recompile_dataset_pe/t2_types_msvc_Os.pdb new file mode 100644 index 00000000..d329b742 Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t2_types_msvc_Os.pdb differ diff --git a/tests/i386/recompile_dataset_pe/t2_types_msvc_Ox.exe b/tests/i386/recompile_dataset_pe/t2_types_msvc_Ox.exe new file mode 100644 index 00000000..1e04e481 Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t2_types_msvc_Ox.exe differ diff --git a/tests/i386/recompile_dataset_pe/t2_types_msvc_Ox.pdb b/tests/i386/recompile_dataset_pe/t2_types_msvc_Ox.pdb new file mode 100644 index 00000000..ce0ca61c Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t2_types_msvc_Ox.pdb differ diff --git a/tests/i386/recompile_dataset_pe/t3_memory_msvc_O1.exe b/tests/i386/recompile_dataset_pe/t3_memory_msvc_O1.exe new file mode 100644 index 00000000..1bd20937 Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t3_memory_msvc_O1.exe differ diff --git a/tests/i386/recompile_dataset_pe/t3_memory_msvc_O1.pdb b/tests/i386/recompile_dataset_pe/t3_memory_msvc_O1.pdb new file mode 100644 index 00000000..6e2763ad Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t3_memory_msvc_O1.pdb differ diff --git a/tests/i386/recompile_dataset_pe/t3_memory_msvc_O2.exe b/tests/i386/recompile_dataset_pe/t3_memory_msvc_O2.exe new file mode 100644 index 00000000..c74890f5 Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t3_memory_msvc_O2.exe differ diff --git a/tests/i386/recompile_dataset_pe/t3_memory_msvc_O2.pdb b/tests/i386/recompile_dataset_pe/t3_memory_msvc_O2.pdb new file mode 100644 index 00000000..7214bbd9 Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t3_memory_msvc_O2.pdb differ diff --git a/tests/i386/recompile_dataset_pe/t3_memory_msvc_Os.exe b/tests/i386/recompile_dataset_pe/t3_memory_msvc_Os.exe new file mode 100644 index 00000000..1e54bf90 Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t3_memory_msvc_Os.exe differ diff --git a/tests/i386/recompile_dataset_pe/t3_memory_msvc_Os.pdb b/tests/i386/recompile_dataset_pe/t3_memory_msvc_Os.pdb new file mode 100644 index 00000000..8b218e7e Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t3_memory_msvc_Os.pdb differ diff --git a/tests/i386/recompile_dataset_pe/t3_memory_msvc_Ox.exe b/tests/i386/recompile_dataset_pe/t3_memory_msvc_Ox.exe new file mode 100644 index 00000000..bcc82bbc Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t3_memory_msvc_Ox.exe differ diff --git a/tests/i386/recompile_dataset_pe/t3_memory_msvc_Ox.pdb b/tests/i386/recompile_dataset_pe/t3_memory_msvc_Ox.pdb new file mode 100644 index 00000000..dc9120f7 Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t3_memory_msvc_Ox.pdb differ diff --git a/tests/i386/recompile_dataset_pe/t4_calling_msvc_O1.exe b/tests/i386/recompile_dataset_pe/t4_calling_msvc_O1.exe new file mode 100644 index 00000000..1c88abdc Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t4_calling_msvc_O1.exe differ diff --git a/tests/i386/recompile_dataset_pe/t4_calling_msvc_O1.pdb b/tests/i386/recompile_dataset_pe/t4_calling_msvc_O1.pdb new file mode 100644 index 00000000..1d6a6cd8 Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t4_calling_msvc_O1.pdb differ diff --git a/tests/i386/recompile_dataset_pe/t4_calling_msvc_O2.exe b/tests/i386/recompile_dataset_pe/t4_calling_msvc_O2.exe new file mode 100644 index 00000000..38ea4fe1 Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t4_calling_msvc_O2.exe differ diff --git a/tests/i386/recompile_dataset_pe/t4_calling_msvc_O2.pdb b/tests/i386/recompile_dataset_pe/t4_calling_msvc_O2.pdb new file mode 100644 index 00000000..7f635ece Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t4_calling_msvc_O2.pdb differ diff --git a/tests/i386/recompile_dataset_pe/t4_calling_msvc_Os.exe b/tests/i386/recompile_dataset_pe/t4_calling_msvc_Os.exe new file mode 100644 index 00000000..77bdf751 Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t4_calling_msvc_Os.exe differ diff --git a/tests/i386/recompile_dataset_pe/t4_calling_msvc_Os.pdb b/tests/i386/recompile_dataset_pe/t4_calling_msvc_Os.pdb new file mode 100644 index 00000000..050bcb49 Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t4_calling_msvc_Os.pdb differ diff --git a/tests/i386/recompile_dataset_pe/t4_calling_msvc_Ox.exe b/tests/i386/recompile_dataset_pe/t4_calling_msvc_Ox.exe new file mode 100644 index 00000000..c30de162 Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t4_calling_msvc_Ox.exe differ diff --git a/tests/i386/recompile_dataset_pe/t4_calling_msvc_Ox.pdb b/tests/i386/recompile_dataset_pe/t4_calling_msvc_Ox.pdb new file mode 100644 index 00000000..cf888559 Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t4_calling_msvc_Ox.pdb differ diff --git a/tests/i386/recompile_dataset_pe/t5_patterns_msvc_O1.exe b/tests/i386/recompile_dataset_pe/t5_patterns_msvc_O1.exe new file mode 100644 index 00000000..d7ce983e Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t5_patterns_msvc_O1.exe differ diff --git a/tests/i386/recompile_dataset_pe/t5_patterns_msvc_O1.pdb b/tests/i386/recompile_dataset_pe/t5_patterns_msvc_O1.pdb new file mode 100644 index 00000000..012cb437 Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t5_patterns_msvc_O1.pdb differ diff --git a/tests/i386/recompile_dataset_pe/t5_patterns_msvc_O2.exe b/tests/i386/recompile_dataset_pe/t5_patterns_msvc_O2.exe new file mode 100644 index 00000000..2b7ff51e Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t5_patterns_msvc_O2.exe differ diff --git a/tests/i386/recompile_dataset_pe/t5_patterns_msvc_O2.pdb b/tests/i386/recompile_dataset_pe/t5_patterns_msvc_O2.pdb new file mode 100644 index 00000000..d0b696cf Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t5_patterns_msvc_O2.pdb differ diff --git a/tests/i386/recompile_dataset_pe/t5_patterns_msvc_Os.exe b/tests/i386/recompile_dataset_pe/t5_patterns_msvc_Os.exe new file mode 100644 index 00000000..bcf7cca8 Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t5_patterns_msvc_Os.exe differ diff --git a/tests/i386/recompile_dataset_pe/t5_patterns_msvc_Os.pdb b/tests/i386/recompile_dataset_pe/t5_patterns_msvc_Os.pdb new file mode 100644 index 00000000..22a3cbab Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t5_patterns_msvc_Os.pdb differ diff --git a/tests/i386/recompile_dataset_pe/t5_patterns_msvc_Ox.exe b/tests/i386/recompile_dataset_pe/t5_patterns_msvc_Ox.exe new file mode 100644 index 00000000..86e9bc64 Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t5_patterns_msvc_Ox.exe differ diff --git a/tests/i386/recompile_dataset_pe/t5_patterns_msvc_Ox.pdb b/tests/i386/recompile_dataset_pe/t5_patterns_msvc_Ox.pdb new file mode 100644 index 00000000..99fd7b27 Binary files /dev/null and b/tests/i386/recompile_dataset_pe/t5_patterns_msvc_Ox.pdb differ diff --git a/tests/x86_64/ccop_triggers/ccop_adc_sbb_O1 b/tests/x86_64/ccop_triggers/ccop_adc_sbb_O1 new file mode 100755 index 00000000..d2740880 Binary files /dev/null and b/tests/x86_64/ccop_triggers/ccop_adc_sbb_O1 differ diff --git a/tests/x86_64/ccop_triggers/ccop_adc_sbb_O2 b/tests/x86_64/ccop_triggers/ccop_adc_sbb_O2 new file mode 100755 index 00000000..f1195ec5 Binary files /dev/null and b/tests/x86_64/ccop_triggers/ccop_adc_sbb_O2 differ diff --git a/tests/x86_64/ccop_triggers/ccop_adc_sbb_Os b/tests/x86_64/ccop_triggers/ccop_adc_sbb_Os new file mode 100755 index 00000000..061a6ed4 Binary files /dev/null and b/tests/x86_64/ccop_triggers/ccop_adc_sbb_Os differ diff --git a/tests/x86_64/ccop_triggers/ccop_add_O1 b/tests/x86_64/ccop_triggers/ccop_add_O1 new file mode 100755 index 00000000..9df78f4c Binary files /dev/null and b/tests/x86_64/ccop_triggers/ccop_add_O1 differ diff --git a/tests/x86_64/ccop_triggers/ccop_add_O2 b/tests/x86_64/ccop_triggers/ccop_add_O2 new file mode 100755 index 00000000..12d89166 Binary files /dev/null and b/tests/x86_64/ccop_triggers/ccop_add_O2 differ diff --git a/tests/x86_64/ccop_triggers/ccop_add_Os b/tests/x86_64/ccop_triggers/ccop_add_Os new file mode 100755 index 00000000..ec4ef9c1 Binary files /dev/null and b/tests/x86_64/ccop_triggers/ccop_add_Os differ diff --git a/tests/x86_64/ccop_triggers/ccop_copy_O1 b/tests/x86_64/ccop_triggers/ccop_copy_O1 new file mode 100755 index 00000000..40e0320d Binary files /dev/null and b/tests/x86_64/ccop_triggers/ccop_copy_O1 differ diff --git a/tests/x86_64/ccop_triggers/ccop_copy_O2 b/tests/x86_64/ccop_triggers/ccop_copy_O2 new file mode 100755 index 00000000..72fd4549 Binary files /dev/null and b/tests/x86_64/ccop_triggers/ccop_copy_O2 differ diff --git a/tests/x86_64/ccop_triggers/ccop_copy_Os b/tests/x86_64/ccop_triggers/ccop_copy_Os new file mode 100755 index 00000000..2ad60c18 Binary files /dev/null and b/tests/x86_64/ccop_triggers/ccop_copy_Os differ diff --git a/tests/x86_64/ccop_triggers/ccop_inc_dec_O1_incdec b/tests/x86_64/ccop_triggers/ccop_inc_dec_O1_incdec new file mode 100755 index 00000000..c6e4c9f0 Binary files /dev/null and b/tests/x86_64/ccop_triggers/ccop_inc_dec_O1_incdec differ diff --git a/tests/x86_64/ccop_triggers/ccop_inc_dec_O2_haswell b/tests/x86_64/ccop_triggers/ccop_inc_dec_O2_haswell new file mode 100755 index 00000000..cf145739 Binary files /dev/null and b/tests/x86_64/ccop_triggers/ccop_inc_dec_O2_haswell differ diff --git a/tests/x86_64/ccop_triggers/ccop_inc_dec_Os_incdec b/tests/x86_64/ccop_triggers/ccop_inc_dec_Os_incdec new file mode 100755 index 00000000..3bc7c62c Binary files /dev/null and b/tests/x86_64/ccop_triggers/ccop_inc_dec_Os_incdec differ diff --git a/tests/x86_64/ccop_triggers/ccop_logic_O1 b/tests/x86_64/ccop_triggers/ccop_logic_O1 new file mode 100755 index 00000000..e149ba84 Binary files /dev/null and b/tests/x86_64/ccop_triggers/ccop_logic_O1 differ diff --git a/tests/x86_64/ccop_triggers/ccop_logic_O2 b/tests/x86_64/ccop_triggers/ccop_logic_O2 new file mode 100755 index 00000000..4f3a7b14 Binary files /dev/null and b/tests/x86_64/ccop_triggers/ccop_logic_O2 differ diff --git a/tests/x86_64/ccop_triggers/ccop_logic_Os b/tests/x86_64/ccop_triggers/ccop_logic_Os new file mode 100755 index 00000000..5b855878 Binary files /dev/null and b/tests/x86_64/ccop_triggers/ccop_logic_Os differ diff --git a/tests/x86_64/ccop_triggers/ccop_rflags_c_O1 b/tests/x86_64/ccop_triggers/ccop_rflags_c_O1 new file mode 100755 index 00000000..655327db Binary files /dev/null and b/tests/x86_64/ccop_triggers/ccop_rflags_c_O1 differ diff --git a/tests/x86_64/ccop_triggers/ccop_rflags_c_O2 b/tests/x86_64/ccop_triggers/ccop_rflags_c_O2 new file mode 100755 index 00000000..8716c06d Binary files /dev/null and b/tests/x86_64/ccop_triggers/ccop_rflags_c_O2 differ diff --git a/tests/x86_64/ccop_triggers/ccop_rflags_c_Os b/tests/x86_64/ccop_triggers/ccop_rflags_c_Os new file mode 100755 index 00000000..b9c6c51e Binary files /dev/null and b/tests/x86_64/ccop_triggers/ccop_rflags_c_Os differ diff --git a/tests/x86_64/ccop_triggers/ccop_shl_shr_O1 b/tests/x86_64/ccop_triggers/ccop_shl_shr_O1 new file mode 100755 index 00000000..c106e13b Binary files /dev/null and b/tests/x86_64/ccop_triggers/ccop_shl_shr_O1 differ diff --git a/tests/x86_64/ccop_triggers/ccop_shl_shr_O2 b/tests/x86_64/ccop_triggers/ccop_shl_shr_O2 new file mode 100755 index 00000000..b941f7a0 Binary files /dev/null and b/tests/x86_64/ccop_triggers/ccop_shl_shr_O2 differ diff --git a/tests/x86_64/ccop_triggers/ccop_shl_shr_Os b/tests/x86_64/ccop_triggers/ccop_shl_shr_Os new file mode 100755 index 00000000..2124046d Binary files /dev/null and b/tests/x86_64/ccop_triggers/ccop_shl_shr_Os differ diff --git a/tests/x86_64/ccop_triggers/ccop_sub_O1 b/tests/x86_64/ccop_triggers/ccop_sub_O1 new file mode 100755 index 00000000..481bba31 Binary files /dev/null and b/tests/x86_64/ccop_triggers/ccop_sub_O1 differ diff --git a/tests/x86_64/ccop_triggers/ccop_sub_O2 b/tests/x86_64/ccop_triggers/ccop_sub_O2 new file mode 100755 index 00000000..b1673a51 Binary files /dev/null and b/tests/x86_64/ccop_triggers/ccop_sub_O2 differ diff --git a/tests/x86_64/ccop_triggers/ccop_sub_Os b/tests/x86_64/ccop_triggers/ccop_sub_Os new file mode 100755 index 00000000..da0aa346 Binary files /dev/null and b/tests/x86_64/ccop_triggers/ccop_sub_Os differ diff --git a/tests/x86_64/ccop_triggers/ccop_umul_smul_O1 b/tests/x86_64/ccop_triggers/ccop_umul_smul_O1 new file mode 100755 index 00000000..a20b14f5 Binary files /dev/null and b/tests/x86_64/ccop_triggers/ccop_umul_smul_O1 differ diff --git a/tests/x86_64/ccop_triggers/ccop_umul_smul_O2 b/tests/x86_64/ccop_triggers/ccop_umul_smul_O2 new file mode 100755 index 00000000..a511fa71 Binary files /dev/null and b/tests/x86_64/ccop_triggers/ccop_umul_smul_O2 differ diff --git a/tests/x86_64/ccop_triggers/ccop_umul_smul_Os b/tests/x86_64/ccop_triggers/ccop_umul_smul_Os new file mode 100755 index 00000000..9c2e299e Binary files /dev/null and b/tests/x86_64/ccop_triggers/ccop_umul_smul_Os differ diff --git a/tests/x86_64/recompile_dataset/t1_control_flow_clang_O0 b/tests/x86_64/recompile_dataset/t1_control_flow_clang_O0 new file mode 100755 index 00000000..dcbaa8fc Binary files /dev/null and b/tests/x86_64/recompile_dataset/t1_control_flow_clang_O0 differ diff --git a/tests/x86_64/recompile_dataset/t1_control_flow_clang_O1 b/tests/x86_64/recompile_dataset/t1_control_flow_clang_O1 new file mode 100755 index 00000000..7cfd3cc5 Binary files /dev/null and b/tests/x86_64/recompile_dataset/t1_control_flow_clang_O1 differ diff --git a/tests/x86_64/recompile_dataset/t1_control_flow_clang_O2 b/tests/x86_64/recompile_dataset/t1_control_flow_clang_O2 new file mode 100755 index 00000000..59a7374b Binary files /dev/null and b/tests/x86_64/recompile_dataset/t1_control_flow_clang_O2 differ diff --git a/tests/x86_64/recompile_dataset/t1_control_flow_clang_O3 b/tests/x86_64/recompile_dataset/t1_control_flow_clang_O3 new file mode 100755 index 00000000..6e37f88f Binary files /dev/null and b/tests/x86_64/recompile_dataset/t1_control_flow_clang_O3 differ diff --git a/tests/x86_64/recompile_dataset/t1_control_flow_clang_Os b/tests/x86_64/recompile_dataset/t1_control_flow_clang_Os new file mode 100755 index 00000000..27d55c01 Binary files /dev/null and b/tests/x86_64/recompile_dataset/t1_control_flow_clang_Os differ diff --git a/tests/x86_64/recompile_dataset/t1_control_flow_gcc_O0 b/tests/x86_64/recompile_dataset/t1_control_flow_gcc_O0 new file mode 100755 index 00000000..49fff028 Binary files /dev/null and b/tests/x86_64/recompile_dataset/t1_control_flow_gcc_O0 differ diff --git a/tests/x86_64/recompile_dataset/t1_control_flow_gcc_O1 b/tests/x86_64/recompile_dataset/t1_control_flow_gcc_O1 new file mode 100755 index 00000000..76e870ca Binary files /dev/null and b/tests/x86_64/recompile_dataset/t1_control_flow_gcc_O1 differ diff --git a/tests/x86_64/recompile_dataset/t1_control_flow_gcc_O2 b/tests/x86_64/recompile_dataset/t1_control_flow_gcc_O2 new file mode 100755 index 00000000..d8f73a54 Binary files /dev/null and b/tests/x86_64/recompile_dataset/t1_control_flow_gcc_O2 differ diff --git a/tests/x86_64/recompile_dataset/t1_control_flow_gcc_O3 b/tests/x86_64/recompile_dataset/t1_control_flow_gcc_O3 new file mode 100755 index 00000000..a0f52bbe Binary files /dev/null and b/tests/x86_64/recompile_dataset/t1_control_flow_gcc_O3 differ diff --git a/tests/x86_64/recompile_dataset/t1_control_flow_gcc_Os b/tests/x86_64/recompile_dataset/t1_control_flow_gcc_Os new file mode 100755 index 00000000..74bca42b Binary files /dev/null and b/tests/x86_64/recompile_dataset/t1_control_flow_gcc_Os differ diff --git a/tests/x86_64/recompile_dataset/t2_types_clang_O0 b/tests/x86_64/recompile_dataset/t2_types_clang_O0 new file mode 100755 index 00000000..cb5a256f Binary files /dev/null and b/tests/x86_64/recompile_dataset/t2_types_clang_O0 differ diff --git a/tests/x86_64/recompile_dataset/t2_types_clang_O1 b/tests/x86_64/recompile_dataset/t2_types_clang_O1 new file mode 100755 index 00000000..69a8b997 Binary files /dev/null and b/tests/x86_64/recompile_dataset/t2_types_clang_O1 differ diff --git a/tests/x86_64/recompile_dataset/t2_types_clang_O2 b/tests/x86_64/recompile_dataset/t2_types_clang_O2 new file mode 100755 index 00000000..69a8b997 Binary files /dev/null and b/tests/x86_64/recompile_dataset/t2_types_clang_O2 differ diff --git a/tests/x86_64/recompile_dataset/t2_types_clang_O3 b/tests/x86_64/recompile_dataset/t2_types_clang_O3 new file mode 100755 index 00000000..69a8b997 Binary files /dev/null and b/tests/x86_64/recompile_dataset/t2_types_clang_O3 differ diff --git a/tests/x86_64/recompile_dataset/t2_types_clang_Os b/tests/x86_64/recompile_dataset/t2_types_clang_Os new file mode 100755 index 00000000..496a040e Binary files /dev/null and b/tests/x86_64/recompile_dataset/t2_types_clang_Os differ diff --git a/tests/x86_64/recompile_dataset/t2_types_gcc_O0 b/tests/x86_64/recompile_dataset/t2_types_gcc_O0 new file mode 100755 index 00000000..8c4d0f2b Binary files /dev/null and b/tests/x86_64/recompile_dataset/t2_types_gcc_O0 differ diff --git a/tests/x86_64/recompile_dataset/t2_types_gcc_O1 b/tests/x86_64/recompile_dataset/t2_types_gcc_O1 new file mode 100755 index 00000000..e8caf73a Binary files /dev/null and b/tests/x86_64/recompile_dataset/t2_types_gcc_O1 differ diff --git a/tests/x86_64/recompile_dataset/t2_types_gcc_O2 b/tests/x86_64/recompile_dataset/t2_types_gcc_O2 new file mode 100755 index 00000000..af9b470b Binary files /dev/null and b/tests/x86_64/recompile_dataset/t2_types_gcc_O2 differ diff --git a/tests/x86_64/recompile_dataset/t2_types_gcc_O3 b/tests/x86_64/recompile_dataset/t2_types_gcc_O3 new file mode 100755 index 00000000..fad93231 Binary files /dev/null and b/tests/x86_64/recompile_dataset/t2_types_gcc_O3 differ diff --git a/tests/x86_64/recompile_dataset/t2_types_gcc_Os b/tests/x86_64/recompile_dataset/t2_types_gcc_Os new file mode 100755 index 00000000..b25bc9f7 Binary files /dev/null and b/tests/x86_64/recompile_dataset/t2_types_gcc_Os differ diff --git a/tests/x86_64/recompile_dataset/t3_memory_clang_O0 b/tests/x86_64/recompile_dataset/t3_memory_clang_O0 new file mode 100755 index 00000000..bd234d1d Binary files /dev/null and b/tests/x86_64/recompile_dataset/t3_memory_clang_O0 differ diff --git a/tests/x86_64/recompile_dataset/t3_memory_clang_O1 b/tests/x86_64/recompile_dataset/t3_memory_clang_O1 new file mode 100755 index 00000000..39649f7d Binary files /dev/null and b/tests/x86_64/recompile_dataset/t3_memory_clang_O1 differ diff --git a/tests/x86_64/recompile_dataset/t3_memory_clang_O2 b/tests/x86_64/recompile_dataset/t3_memory_clang_O2 new file mode 100755 index 00000000..73c41875 Binary files /dev/null and b/tests/x86_64/recompile_dataset/t3_memory_clang_O2 differ diff --git a/tests/x86_64/recompile_dataset/t3_memory_clang_O3 b/tests/x86_64/recompile_dataset/t3_memory_clang_O3 new file mode 100755 index 00000000..73c41875 Binary files /dev/null and b/tests/x86_64/recompile_dataset/t3_memory_clang_O3 differ diff --git a/tests/x86_64/recompile_dataset/t3_memory_clang_Os b/tests/x86_64/recompile_dataset/t3_memory_clang_Os new file mode 100755 index 00000000..3de71666 Binary files /dev/null and b/tests/x86_64/recompile_dataset/t3_memory_clang_Os differ diff --git a/tests/x86_64/recompile_dataset/t3_memory_gcc_O0 b/tests/x86_64/recompile_dataset/t3_memory_gcc_O0 new file mode 100755 index 00000000..9f1d8d0f Binary files /dev/null and b/tests/x86_64/recompile_dataset/t3_memory_gcc_O0 differ diff --git a/tests/x86_64/recompile_dataset/t3_memory_gcc_O1 b/tests/x86_64/recompile_dataset/t3_memory_gcc_O1 new file mode 100755 index 00000000..3b9c7786 Binary files /dev/null and b/tests/x86_64/recompile_dataset/t3_memory_gcc_O1 differ diff --git a/tests/x86_64/recompile_dataset/t3_memory_gcc_O2 b/tests/x86_64/recompile_dataset/t3_memory_gcc_O2 new file mode 100755 index 00000000..b829a69f Binary files /dev/null and b/tests/x86_64/recompile_dataset/t3_memory_gcc_O2 differ diff --git a/tests/x86_64/recompile_dataset/t3_memory_gcc_O3 b/tests/x86_64/recompile_dataset/t3_memory_gcc_O3 new file mode 100755 index 00000000..1c295cf5 Binary files /dev/null and b/tests/x86_64/recompile_dataset/t3_memory_gcc_O3 differ diff --git a/tests/x86_64/recompile_dataset/t3_memory_gcc_Os b/tests/x86_64/recompile_dataset/t3_memory_gcc_Os new file mode 100755 index 00000000..7258cd9c Binary files /dev/null and b/tests/x86_64/recompile_dataset/t3_memory_gcc_Os differ diff --git a/tests/x86_64/recompile_dataset/t4_calling_clang_O0 b/tests/x86_64/recompile_dataset/t4_calling_clang_O0 new file mode 100755 index 00000000..b84f45c0 Binary files /dev/null and b/tests/x86_64/recompile_dataset/t4_calling_clang_O0 differ diff --git a/tests/x86_64/recompile_dataset/t4_calling_clang_O1 b/tests/x86_64/recompile_dataset/t4_calling_clang_O1 new file mode 100755 index 00000000..0c1a734c Binary files /dev/null and b/tests/x86_64/recompile_dataset/t4_calling_clang_O1 differ diff --git a/tests/x86_64/recompile_dataset/t4_calling_clang_O2 b/tests/x86_64/recompile_dataset/t4_calling_clang_O2 new file mode 100755 index 00000000..ef5bee02 Binary files /dev/null and b/tests/x86_64/recompile_dataset/t4_calling_clang_O2 differ diff --git a/tests/x86_64/recompile_dataset/t4_calling_clang_O3 b/tests/x86_64/recompile_dataset/t4_calling_clang_O3 new file mode 100755 index 00000000..ef5bee02 Binary files /dev/null and b/tests/x86_64/recompile_dataset/t4_calling_clang_O3 differ diff --git a/tests/x86_64/recompile_dataset/t4_calling_clang_Os b/tests/x86_64/recompile_dataset/t4_calling_clang_Os new file mode 100755 index 00000000..2b085740 Binary files /dev/null and b/tests/x86_64/recompile_dataset/t4_calling_clang_Os differ diff --git a/tests/x86_64/recompile_dataset/t4_calling_gcc_O0 b/tests/x86_64/recompile_dataset/t4_calling_gcc_O0 new file mode 100755 index 00000000..edee931e Binary files /dev/null and b/tests/x86_64/recompile_dataset/t4_calling_gcc_O0 differ diff --git a/tests/x86_64/recompile_dataset/t4_calling_gcc_O1 b/tests/x86_64/recompile_dataset/t4_calling_gcc_O1 new file mode 100755 index 00000000..895cc825 Binary files /dev/null and b/tests/x86_64/recompile_dataset/t4_calling_gcc_O1 differ diff --git a/tests/x86_64/recompile_dataset/t4_calling_gcc_O2 b/tests/x86_64/recompile_dataset/t4_calling_gcc_O2 new file mode 100755 index 00000000..f6245440 Binary files /dev/null and b/tests/x86_64/recompile_dataset/t4_calling_gcc_O2 differ diff --git a/tests/x86_64/recompile_dataset/t4_calling_gcc_O3 b/tests/x86_64/recompile_dataset/t4_calling_gcc_O3 new file mode 100755 index 00000000..7585197a Binary files /dev/null and b/tests/x86_64/recompile_dataset/t4_calling_gcc_O3 differ diff --git a/tests/x86_64/recompile_dataset/t4_calling_gcc_Os b/tests/x86_64/recompile_dataset/t4_calling_gcc_Os new file mode 100755 index 00000000..d071ba33 Binary files /dev/null and b/tests/x86_64/recompile_dataset/t4_calling_gcc_Os differ diff --git a/tests/x86_64/recompile_dataset/t5_patterns_clang_O0 b/tests/x86_64/recompile_dataset/t5_patterns_clang_O0 new file mode 100755 index 00000000..4a341b18 Binary files /dev/null and b/tests/x86_64/recompile_dataset/t5_patterns_clang_O0 differ diff --git a/tests/x86_64/recompile_dataset/t5_patterns_clang_O1 b/tests/x86_64/recompile_dataset/t5_patterns_clang_O1 new file mode 100755 index 00000000..f6155c10 Binary files /dev/null and b/tests/x86_64/recompile_dataset/t5_patterns_clang_O1 differ diff --git a/tests/x86_64/recompile_dataset/t5_patterns_clang_O2 b/tests/x86_64/recompile_dataset/t5_patterns_clang_O2 new file mode 100755 index 00000000..bc04aea4 Binary files /dev/null and b/tests/x86_64/recompile_dataset/t5_patterns_clang_O2 differ diff --git a/tests/x86_64/recompile_dataset/t5_patterns_clang_O3 b/tests/x86_64/recompile_dataset/t5_patterns_clang_O3 new file mode 100755 index 00000000..fc60d40c Binary files /dev/null and b/tests/x86_64/recompile_dataset/t5_patterns_clang_O3 differ diff --git a/tests/x86_64/recompile_dataset/t5_patterns_clang_Os b/tests/x86_64/recompile_dataset/t5_patterns_clang_Os new file mode 100755 index 00000000..bf8ef7eb Binary files /dev/null and b/tests/x86_64/recompile_dataset/t5_patterns_clang_Os differ diff --git a/tests/x86_64/recompile_dataset/t5_patterns_gcc_O0 b/tests/x86_64/recompile_dataset/t5_patterns_gcc_O0 new file mode 100755 index 00000000..3629d633 Binary files /dev/null and b/tests/x86_64/recompile_dataset/t5_patterns_gcc_O0 differ diff --git a/tests/x86_64/recompile_dataset/t5_patterns_gcc_O1 b/tests/x86_64/recompile_dataset/t5_patterns_gcc_O1 new file mode 100755 index 00000000..b9684864 Binary files /dev/null and b/tests/x86_64/recompile_dataset/t5_patterns_gcc_O1 differ diff --git a/tests/x86_64/recompile_dataset/t5_patterns_gcc_O2 b/tests/x86_64/recompile_dataset/t5_patterns_gcc_O2 new file mode 100755 index 00000000..936a5fd8 Binary files /dev/null and b/tests/x86_64/recompile_dataset/t5_patterns_gcc_O2 differ diff --git a/tests/x86_64/recompile_dataset/t5_patterns_gcc_O3 b/tests/x86_64/recompile_dataset/t5_patterns_gcc_O3 new file mode 100755 index 00000000..f6eced4c Binary files /dev/null and b/tests/x86_64/recompile_dataset/t5_patterns_gcc_O3 differ diff --git a/tests/x86_64/recompile_dataset/t5_patterns_gcc_Os b/tests/x86_64/recompile_dataset/t5_patterns_gcc_Os new file mode 100755 index 00000000..92ac90c3 Binary files /dev/null and b/tests/x86_64/recompile_dataset/t5_patterns_gcc_Os differ diff --git a/tests/x86_64/recompile_dataset_pe/t1_control_flow_msvc_O1.exe b/tests/x86_64/recompile_dataset_pe/t1_control_flow_msvc_O1.exe new file mode 100644 index 00000000..1fc14247 Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t1_control_flow_msvc_O1.exe differ diff --git a/tests/x86_64/recompile_dataset_pe/t1_control_flow_msvc_O1.pdb b/tests/x86_64/recompile_dataset_pe/t1_control_flow_msvc_O1.pdb new file mode 100644 index 00000000..1ff99958 Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t1_control_flow_msvc_O1.pdb differ diff --git a/tests/x86_64/recompile_dataset_pe/t1_control_flow_msvc_O2.exe b/tests/x86_64/recompile_dataset_pe/t1_control_flow_msvc_O2.exe new file mode 100644 index 00000000..eb6258d0 Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t1_control_flow_msvc_O2.exe differ diff --git a/tests/x86_64/recompile_dataset_pe/t1_control_flow_msvc_O2.pdb b/tests/x86_64/recompile_dataset_pe/t1_control_flow_msvc_O2.pdb new file mode 100644 index 00000000..1c4f27bf Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t1_control_flow_msvc_O2.pdb differ diff --git a/tests/x86_64/recompile_dataset_pe/t1_control_flow_msvc_Os.exe b/tests/x86_64/recompile_dataset_pe/t1_control_flow_msvc_Os.exe new file mode 100644 index 00000000..f99c6ecc Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t1_control_flow_msvc_Os.exe differ diff --git a/tests/x86_64/recompile_dataset_pe/t1_control_flow_msvc_Os.pdb b/tests/x86_64/recompile_dataset_pe/t1_control_flow_msvc_Os.pdb new file mode 100644 index 00000000..04c561fe Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t1_control_flow_msvc_Os.pdb differ diff --git a/tests/x86_64/recompile_dataset_pe/t1_control_flow_msvc_Ox.exe b/tests/x86_64/recompile_dataset_pe/t1_control_flow_msvc_Ox.exe new file mode 100644 index 00000000..6c388c86 Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t1_control_flow_msvc_Ox.exe differ diff --git a/tests/x86_64/recompile_dataset_pe/t1_control_flow_msvc_Ox.pdb b/tests/x86_64/recompile_dataset_pe/t1_control_flow_msvc_Ox.pdb new file mode 100644 index 00000000..df194857 Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t1_control_flow_msvc_Ox.pdb differ diff --git a/tests/x86_64/recompile_dataset_pe/t2_types_msvc_O1.exe b/tests/x86_64/recompile_dataset_pe/t2_types_msvc_O1.exe new file mode 100644 index 00000000..26c37f42 Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t2_types_msvc_O1.exe differ diff --git a/tests/x86_64/recompile_dataset_pe/t2_types_msvc_O1.pdb b/tests/x86_64/recompile_dataset_pe/t2_types_msvc_O1.pdb new file mode 100644 index 00000000..ea3eba6e Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t2_types_msvc_O1.pdb differ diff --git a/tests/x86_64/recompile_dataset_pe/t2_types_msvc_O2.exe b/tests/x86_64/recompile_dataset_pe/t2_types_msvc_O2.exe new file mode 100644 index 00000000..0b7e0a05 Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t2_types_msvc_O2.exe differ diff --git a/tests/x86_64/recompile_dataset_pe/t2_types_msvc_O2.pdb b/tests/x86_64/recompile_dataset_pe/t2_types_msvc_O2.pdb new file mode 100644 index 00000000..37ef274b Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t2_types_msvc_O2.pdb differ diff --git a/tests/x86_64/recompile_dataset_pe/t2_types_msvc_Os.exe b/tests/x86_64/recompile_dataset_pe/t2_types_msvc_Os.exe new file mode 100644 index 00000000..7553010b Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t2_types_msvc_Os.exe differ diff --git a/tests/x86_64/recompile_dataset_pe/t2_types_msvc_Os.pdb b/tests/x86_64/recompile_dataset_pe/t2_types_msvc_Os.pdb new file mode 100644 index 00000000..37e150fd Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t2_types_msvc_Os.pdb differ diff --git a/tests/x86_64/recompile_dataset_pe/t2_types_msvc_Ox.exe b/tests/x86_64/recompile_dataset_pe/t2_types_msvc_Ox.exe new file mode 100644 index 00000000..a5d567a7 Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t2_types_msvc_Ox.exe differ diff --git a/tests/x86_64/recompile_dataset_pe/t2_types_msvc_Ox.pdb b/tests/x86_64/recompile_dataset_pe/t2_types_msvc_Ox.pdb new file mode 100644 index 00000000..ecd44d17 Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t2_types_msvc_Ox.pdb differ diff --git a/tests/x86_64/recompile_dataset_pe/t3_memory_msvc_O1.exe b/tests/x86_64/recompile_dataset_pe/t3_memory_msvc_O1.exe new file mode 100644 index 00000000..7809e992 Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t3_memory_msvc_O1.exe differ diff --git a/tests/x86_64/recompile_dataset_pe/t3_memory_msvc_O1.pdb b/tests/x86_64/recompile_dataset_pe/t3_memory_msvc_O1.pdb new file mode 100644 index 00000000..df008b32 Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t3_memory_msvc_O1.pdb differ diff --git a/tests/x86_64/recompile_dataset_pe/t3_memory_msvc_O2.exe b/tests/x86_64/recompile_dataset_pe/t3_memory_msvc_O2.exe new file mode 100644 index 00000000..c3b6e9b8 Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t3_memory_msvc_O2.exe differ diff --git a/tests/x86_64/recompile_dataset_pe/t3_memory_msvc_O2.pdb b/tests/x86_64/recompile_dataset_pe/t3_memory_msvc_O2.pdb new file mode 100644 index 00000000..951f2897 Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t3_memory_msvc_O2.pdb differ diff --git a/tests/x86_64/recompile_dataset_pe/t3_memory_msvc_Os.exe b/tests/x86_64/recompile_dataset_pe/t3_memory_msvc_Os.exe new file mode 100644 index 00000000..d31c587c Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t3_memory_msvc_Os.exe differ diff --git a/tests/x86_64/recompile_dataset_pe/t3_memory_msvc_Os.pdb b/tests/x86_64/recompile_dataset_pe/t3_memory_msvc_Os.pdb new file mode 100644 index 00000000..ac3f09f0 Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t3_memory_msvc_Os.pdb differ diff --git a/tests/x86_64/recompile_dataset_pe/t3_memory_msvc_Ox.exe b/tests/x86_64/recompile_dataset_pe/t3_memory_msvc_Ox.exe new file mode 100644 index 00000000..2a4afec2 Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t3_memory_msvc_Ox.exe differ diff --git a/tests/x86_64/recompile_dataset_pe/t3_memory_msvc_Ox.pdb b/tests/x86_64/recompile_dataset_pe/t3_memory_msvc_Ox.pdb new file mode 100644 index 00000000..5b5a3b1d Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t3_memory_msvc_Ox.pdb differ diff --git a/tests/x86_64/recompile_dataset_pe/t4_calling_msvc_O1.exe b/tests/x86_64/recompile_dataset_pe/t4_calling_msvc_O1.exe new file mode 100644 index 00000000..e8feda33 Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t4_calling_msvc_O1.exe differ diff --git a/tests/x86_64/recompile_dataset_pe/t4_calling_msvc_O1.pdb b/tests/x86_64/recompile_dataset_pe/t4_calling_msvc_O1.pdb new file mode 100644 index 00000000..2968578c Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t4_calling_msvc_O1.pdb differ diff --git a/tests/x86_64/recompile_dataset_pe/t4_calling_msvc_O2.exe b/tests/x86_64/recompile_dataset_pe/t4_calling_msvc_O2.exe new file mode 100644 index 00000000..3b5594f3 Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t4_calling_msvc_O2.exe differ diff --git a/tests/x86_64/recompile_dataset_pe/t4_calling_msvc_O2.pdb b/tests/x86_64/recompile_dataset_pe/t4_calling_msvc_O2.pdb new file mode 100644 index 00000000..afae6644 Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t4_calling_msvc_O2.pdb differ diff --git a/tests/x86_64/recompile_dataset_pe/t4_calling_msvc_Os.exe b/tests/x86_64/recompile_dataset_pe/t4_calling_msvc_Os.exe new file mode 100644 index 00000000..7a41f242 Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t4_calling_msvc_Os.exe differ diff --git a/tests/x86_64/recompile_dataset_pe/t4_calling_msvc_Os.pdb b/tests/x86_64/recompile_dataset_pe/t4_calling_msvc_Os.pdb new file mode 100644 index 00000000..412bc67a Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t4_calling_msvc_Os.pdb differ diff --git a/tests/x86_64/recompile_dataset_pe/t4_calling_msvc_Ox.exe b/tests/x86_64/recompile_dataset_pe/t4_calling_msvc_Ox.exe new file mode 100644 index 00000000..08935003 Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t4_calling_msvc_Ox.exe differ diff --git a/tests/x86_64/recompile_dataset_pe/t4_calling_msvc_Ox.pdb b/tests/x86_64/recompile_dataset_pe/t4_calling_msvc_Ox.pdb new file mode 100644 index 00000000..5b14cc17 Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t4_calling_msvc_Ox.pdb differ diff --git a/tests/x86_64/recompile_dataset_pe/t5_patterns_msvc_O1.exe b/tests/x86_64/recompile_dataset_pe/t5_patterns_msvc_O1.exe new file mode 100644 index 00000000..7083e0eb Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t5_patterns_msvc_O1.exe differ diff --git a/tests/x86_64/recompile_dataset_pe/t5_patterns_msvc_O1.pdb b/tests/x86_64/recompile_dataset_pe/t5_patterns_msvc_O1.pdb new file mode 100644 index 00000000..6ce6bef1 Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t5_patterns_msvc_O1.pdb differ diff --git a/tests/x86_64/recompile_dataset_pe/t5_patterns_msvc_O2.exe b/tests/x86_64/recompile_dataset_pe/t5_patterns_msvc_O2.exe new file mode 100644 index 00000000..af8c3452 Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t5_patterns_msvc_O2.exe differ diff --git a/tests/x86_64/recompile_dataset_pe/t5_patterns_msvc_O2.pdb b/tests/x86_64/recompile_dataset_pe/t5_patterns_msvc_O2.pdb new file mode 100644 index 00000000..e94dde0a Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t5_patterns_msvc_O2.pdb differ diff --git a/tests/x86_64/recompile_dataset_pe/t5_patterns_msvc_Os.exe b/tests/x86_64/recompile_dataset_pe/t5_patterns_msvc_Os.exe new file mode 100644 index 00000000..7a20c535 Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t5_patterns_msvc_Os.exe differ diff --git a/tests/x86_64/recompile_dataset_pe/t5_patterns_msvc_Os.pdb b/tests/x86_64/recompile_dataset_pe/t5_patterns_msvc_Os.pdb new file mode 100644 index 00000000..f42cd310 Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t5_patterns_msvc_Os.pdb differ diff --git a/tests/x86_64/recompile_dataset_pe/t5_patterns_msvc_Ox.exe b/tests/x86_64/recompile_dataset_pe/t5_patterns_msvc_Ox.exe new file mode 100644 index 00000000..04c052de Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t5_patterns_msvc_Ox.exe differ diff --git a/tests/x86_64/recompile_dataset_pe/t5_patterns_msvc_Ox.pdb b/tests/x86_64/recompile_dataset_pe/t5_patterns_msvc_Ox.pdb new file mode 100644 index 00000000..6a87d206 Binary files /dev/null and b/tests/x86_64/recompile_dataset_pe/t5_patterns_msvc_Ox.pdb differ diff --git a/tests_src/ccop_triggers/STATUS.md b/tests_src/ccop_triggers/STATUS.md new file mode 100644 index 00000000..8ae41c75 --- /dev/null +++ b/tests_src/ccop_triggers/STATUS.md @@ -0,0 +1,259 @@ +# ccop_triggers Test Suite — Status + +## What This Is + +A set of C source files designed to trigger every VEX condition-code operation (ccop) type +handled by angr's decompiler ccall rewriters (`amd64_ccalls.py`, `x86_ccalls.py`). Each +function is `noinline`, uses a volatile sink to prevent dead-code elimination, and is compiled +with `-fno-if-conversion` to force real branches (not cmov). + +Built binaries go into `bin/amd64/` and `bin/i386/` (gitignored). Run `bash build.sh` to +rebuild. + +## Current State: All 9 source files complete, all P0/P1 gaps filled + +### Complete — ~285 functions across 54 binaries (all build cleanly, all tests pass) + +| File | Functions | Notes | +|------|-----------|-------| +| `ccop_sub.c` | 48 | SUB/CMP: CondZ/NZ/L/NL/LE/NLE/B/NB/BE/NBE/S/NS all at 8,16,32,64. Pure C comparisons. | +| `ccop_add.c` | 39 | ADD: CondZ/NZ/S/NS/O/NO/B (8,16,32,64), CondLE/NLE (8,16,32,64), CondBE (8,16,32). Uses `__builtin_add_overflow` for CondO; `asm goto` for CondLE/NLE/BE. 64-bit CondLE/NLE guarded by `__x86_64__`. | +| `ccop_logic.c` | 38 | LOGIC (test/and): CondZ/NZ/S/NS/L/NL (8,16,32,64), CondLE/NLE (8,16,32,64), CondB/BE (8,16,32 x86 only via `asm goto`). | +| `ccop_inc_dec.c` | 48 | INC: CondZ/NZ/S/NS (8,16,32,64), CondO/NO (8,16,32 via asm goto), CondLE/NLE (32 fallback). DEC: CondZ/NZ/S/NS/LE/NLE (8,16,32,64). All inline asm; built with `-mtune-ctrl=use_incdec`. | +| `ccop_shl_shr.c` | 32 | SHL: CondZ/NZ/S/NS (8,16,32,64). SHR: CondZ/NZ/S/NS (8,16,32,64). Pure C shifts; narrow widths use volatile + explicit casts. | +| `ccop_umul_smul.c` | 16 | UMUL/SMUL: CondO/NO (8,16,32,64). Uses `__builtin_*_overflow`. 64-bit UMUL CondNO guarded by `__x86_64__`. | +| `ccop_adc_sbb.c` | ~59 | ADC/SBB: comprehensive coverage. amd64 section (11 funcs via `__int128`), i386 section (48 funcs via pure C + asm goto). Covers CondZ/NZ/S/B/O/NO for ADC; CondZ/B/NB/BE/NBE/L/NL/S/O/NO for SBB at 8,16,32 widths. | +| `ccop_copy.c` | 4 | COPY: CondZ/NZ via `pushf`/`popf` + `asm goto`. amd64 uses `pushfq`/`popfq` (64-bit), i386 uses `pushfl`/`popfl` (32-bit). | +| `ccop_rflags_c.c` | 6 | rflags_c: carry flag extraction for ADD (32,64), SUB (32,64), DEC (32,64). amd64-only (`#ifdef __x86_64__`). Uses `adc $0` / `sbb $0` carry chains. | + +### Python Test Harness + +`tests/analyses/decompiler/test_ccop_triggers.py` — parametrized pytest (54 test cases) +that decompiles every `ccop_*` function in every binary and asserts: + +1. Decompilation succeeds (codegen is not None) +2. For rewriter-handled (op, cond, width) combos: no raw `calculate_condition` or + `calculate_rflags_c` in the output +3. For fallback-only combos (no rewriter): just checks decompilation doesn't crash + +Run: `python -m pytest tests/analyses/decompiler/test_ccop_triggers.py -v` + +--- + +## Comprehensive Rewriter Coverage vs Test Coverage + +The tables below map every (ccop, condition) combination handled by the rewriters against +what the test suite covers. This was generated by reading every code path in +`amd64_ccalls.py` and `x86_ccalls.py`. + +### Legend + +- **A** = amd64 rewriter handles this (B/W/L/Q widths) +- **X** = x86 rewriter handles this (B/W/L widths) +- All listed conditions now have full width coverage + +### SUB — `ccop_sub.c` (48 functions) + +| Condition | Rewriter | Tested Widths | +|-----------|----------|---------------| +| CondZ | A, X | 8, 16, 32, 64 | +| CondNZ | A, X | 8, 16, 32, 64 | +| CondL | A, X | 8, 16, 32, 64 | +| CondNL | A, X | 8, 16, 32, 64 | +| CondLE | A, X | 8, 16, 32, 64 | +| CondNLE | A, X | 8, 16, 32, 64 | +| CondB | A, X | 8, 16, 32, 64 | +| CondNB | A, X | 8, 16, 32, 64 | +| CondBE | A, X | 8, 16, 32, 64 | +| CondNBE | A, X | 8, 16, 32, 64 | +| CondS | A, X | 8, 16, 32, 64 | +| CondNS | A, X | 8, 16, 32, 64 | + +### ADD — `ccop_add.c` (39 functions) + +| Condition | Rewriter | Tested Widths | +|-----------|----------|---------------| +| CondZ | A, X | 8, 16, 32, 64 | +| CondNZ | A, X | 8, 16, 32, 64 | +| CondS | A, X | 8, 16, 32, 64 | +| CondNS | A, X | 8, 16, 32, 64 | +| CondO | A, X | 8, 16, 32, 64 | +| CondNO | A, X | 8, 16, 32, 64 | +| CondB | A, X | 8, 16, 32, 64 | +| CondLE | X only | 8, 16, 32, 64 | +| CondNLE | X only | 8, 16, 32, 64 | +| CondBE | X only | 8, 16, 32 | + +### LOGIC — `ccop_logic.c` (38 functions) + +| Condition | Rewriter | Tested Widths | +|-----------|----------|---------------| +| CondZ | A, X | 8, 16, 32, 64 | +| CondNZ | A, X | 8, 16, 32, 64 | +| CondS | A, X | 8, 16, 32, 64 | +| CondNS | A, X | 8, 16, 32, 64 | +| CondL | A, X | 8, 16, 32, 64 | +| CondNL | A, X | 8, 16, 32, 64 | +| CondLE | A, X | 8, 16, 32, 64 | +| CondNLE | A, X | 8, 16, 32, 64 | +| CondB | X only | 8, 16, 32 | +| CondBE | X only | 8, 16, 32 | + +### INC — `ccop_inc_dec.c` (24 INC functions) + +| Condition | Rewriter | Tested Widths | +|-----------|----------|---------------| +| CondZ | A, X | 8, 16, 32, 64 | +| CondNZ | A, X | 8, 16, 32, 64 | +| CondS | A | 8, 16, 32, 64 | +| CondNS | A | 8, 16, 32, 64 | +| CondO | X only | 8, 16, 32 | +| CondNO | X only | 8, 16, 32 | + +Note: INC CondLE/CondNLE (32) are in the test but neither rewriter handles this — those +test fallback behavior only. + +### DEC — `ccop_inc_dec.c` (24 DEC functions) + +| Condition | Rewriter | Tested Widths | +|-----------|----------|---------------| +| CondZ | A, X | 8, 16, 32, 64 | +| CondNZ | A, X | 8, 16, 32, 64 | +| CondS | A | 8, 16, 32, 64 | +| CondNS | A | 8, 16, 32, 64 | +| CondLE | A, X | 8, 16, 32, 64 | +| CondNLE | A, X | 8, 16, 32, 64 | + +### SHL — `ccop_shl_shr.c` (16 SHL functions) + +| Condition | Rewriter | Tested Widths | +|-----------|----------|---------------| +| CondZ | A, X | 8, 16, 32, 64 | +| CondNZ | A, X | 8, 16, 32, 64 | +| CondS | A, X | 8, 16, 32, 64 | +| CondNS | A, X | 8, 16, 32, 64 | + +### SHR — `ccop_shl_shr.c` (16 SHR functions) + +| Condition | Rewriter | Tested Widths | +|-----------|----------|---------------| +| CondZ | A, X | 8, 16, 32, 64 | +| CondNZ | A, X | 8, 16, 32, 64 | +| CondS | A, X | 8, 16, 32, 64 | +| CondNS | A, X | 8, 16, 32, 64 | + +### UMUL — `ccop_umul_smul.c` (8 UMUL functions) + +| Condition | Rewriter | Tested Widths | +|-----------|----------|---------------| +| CondO | A, X | 8, 16, 32, 64 | +| CondNO | A, X | 8, 16, 32, 64 | + +### SMUL — `ccop_umul_smul.c` (8 SMUL functions) + +| Condition | Rewriter | Tested Widths | +|-----------|----------|---------------| +| CondO | A (B/W/L/Q), X (L only) | 8, 16, 32, 64 | +| CondNO | A (B/W/L/Q), X (L only) | 8, 16, 32, 64 | + +### ADC — `ccop_adc_sbb.c` + +The AMD64 rewriter does NOT handle ADC at all. Only x86 handles ADC. + +| Condition | Rewriter | Tested Widths | +|-----------|----------|---------------| +| CondO | X only | 8, 16, 32 | +| CondNO | X only | 8, 16, 32 | +| CondB | X only | 8, 16, 32 | + +ADC CondZ/NZ/S are tested but NOT handled by any rewriter — they exercise fallback only. + +### SBB — `ccop_adc_sbb.c` + +AMD64 rewriter only handles SBB+CondB. x86 handles more conditions. + +| Condition | Rewriter | Tested Widths | +|-----------|----------|---------------| +| CondB | A, X | 8, 16, 32, 64 | +| CondBE | X only | 8, 16, 32 | +| CondNB | X only | 8, 16, 32 | +| CondNBE | X only | 8, 16, 32 | +| CondL | X only | 8, 16, 32 | +| CondNL | X only | 8, 16, 32 | +| CondO | X only | 8, 16, 32 | +| CondNO | X only | 8, 16, 32 | + +SBB CondZ/S are tested but NOT handled by any rewriter — they exercise fallback only. + +### COPY — `ccop_copy.c` (4 functions) + +| Condition | Rewriter | Tested Widths | +|-----------|----------|---------------| +| CondZ | A, X | 32, 64 | +| CondNZ | A, X | 32, 64 | + +### `amd64g_calculate_rflags_c` — `ccop_rflags_c.c` (6 functions, amd64-only) + +| CCOP | Rewriter | Tested Widths | +|------|----------|---------------| +| ADD | A only | 32, 64 | +| SUB | A only | 32, 64 | +| DEC | A only | 32, 64 | + +--- + +## Remaining Gaps (P2 — fallback-only, no rewriter exists) + +These ccop+condition combos are NOT handled by either rewriter. Tests would only verify +the decompiler doesn't crash (produces a raw `_ccall`). Not urgent. + +| Gap | Notes | +|-----|-------| +| ADC + CondZ/NZ/S | Tested already, no rewriter path exists | +| SBB + CondZ/S | Tested already, no rewriter path exists | +| INC + CondLE/NLE | Tested already, no rewriter path exists | +| CondP/CondNP (parity) | Not in any rewriter | +| ROL/ROR | Op types defined but no rewriter code | +| ANDN/BLSI/BLSMSK/BLSR | AMD64 BMI ops, no rewriter | +| ADCX/ADOX | AMD64 ADX ops, no rewriter | + +--- + +## Build System + +``` +bash build.sh # builds 54 binaries (27 amd64, 27 i386) +``` + +Produces 3 optimization variants per source file x 2 arches: +- Standard sources: `-O1`, `-O2`, `-Os` +- INC/DEC: `-O1 -mtune-ctrl=use_incdec`, `-O2 -mtune=haswell`, `-Os -mtune-ctrl=use_incdec` +- ADC/SBB: same as standard + +All with base flags: `-fno-if-conversion -fno-if-conversion2 -fno-tree-loop-if-convert -g` + +Requires `gcc` and `gcc-multilib` (both installed on this system). + +## File Layout + +``` +ccop_triggers/ +├── build.sh # Build script +├── ccop_common.h # NOINLINE macro, volatile g_sink, sized typedefs +├── ccop_sub.c # 48 funcs — SUB/CMP conditions +├── ccop_add.c # 39 funcs — ADD conditions +├── ccop_logic.c # 38 funcs — LOGIC (test/and) conditions +├── ccop_inc_dec.c # 48 funcs — INC/DEC conditions (inline asm) +├── ccop_shl_shr.c # 32 funcs — SHL/SHR conditions +├── ccop_umul_smul.c # 16 funcs — multiply overflow +├── ccop_adc_sbb.c # ~59 funcs — ADC/SBB multi-precision (inline asm) +├── ccop_copy.c # 4 funcs — COPY (pushf/popf) +├── ccop_rflags_c.c # 6 funcs — rflags_c carry extraction (amd64) +├── .gitignore # Ignores bin/ +├── STATUS.md # This file +└── bin/ # Compiled output (gitignored) + ├── amd64/ # 27 binaries + └── i386/ # 27 binaries + +../test_ccop_triggers.py # Pytest harness (54 parametrized test cases) +``` diff --git a/tests_src/ccop_triggers/build.sh b/tests_src/ccop_triggers/build.sh new file mode 100644 index 00000000..a70cccf8 --- /dev/null +++ b/tests_src/ccop_triggers/build.sh @@ -0,0 +1,139 @@ +#!/bin/bash +# +# Build all ccop trigger binaries for amd64, i386, armhf, and aarch64. +# Usage: cd tests_src/ccop_triggers && bash build.sh +# +# Produces multiple variants per source file using different optimization +# levels, tuning targets, and feature flags to maximize the variety of +# ccop patterns the compiler emits. +# +# Requires: +# gcc, gcc-multilib (for -m32 builds) +# arm-linux-gnueabihf-gcc (for armhf builds) +# aarch64-linux-gnu-gcc (for aarch64 builds) +# +set -e + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +cd "$SCRIPT_DIR" + +# Base flags: suppress conditional moves so branches stay as branches, +# keep debug info for decompiler friendliness +BASE="-fno-if-conversion -fno-if-conversion2 -fno-tree-loop-if-convert -g" + +# ─── x86/amd64: Standard sources ───────────────────────────────── +STD_SRCS=( + ccop_sub + ccop_add + ccop_logic + ccop_shl_shr + ccop_umul_smul + ccop_copy + ccop_rflags_c +) + +# ─── x86/amd64: INC/DEC source ─────────────────────────────────── +INCDEC_SRCS=( + ccop_inc_dec +) + +# ─── x86/amd64: ADC/SBB source ─────────────────────────────────── +ADCSBB_SRCS=( + ccop_adc_sbb +) + +# ─── ARM: Sources that work on both armhf and aarch64 ──────────── +ARM_SRCS=( + ccop_arm_sub + ccop_arm_add + ccop_arm_logic + ccop_arm_adc_sbb +) + +# Standard optimization variants +STD_VARIANTS=( + "O1::-O1" + "O2::-O2" + "Os::-Os" +) + +# INC/DEC variants: force inc/dec emission via tuning control +INCDEC_VARIANTS=( + "O1_incdec::-O1 -mtune-ctrl=use_incdec" + "O2_haswell::-O2 -mtune=haswell" + "Os_incdec::-Os -mtune-ctrl=use_incdec" +) + +mkdir -p bin/amd64 bin/i386 bin/armhf bin/aarch64 + +FAIL=0 +COUNT=0 + +build_one() { + local compiler="$1" src="$2" name="$3" extra_flags="$4" outdir="$5" + if $compiler $BASE $extra_flags -o "${outdir}/${name}" "${src}.c" 2>&1; then + COUNT=$((COUNT + 1)) + else + echo " FAILED: $name ($outdir)" + FAIL=1 + fi +} + +# ═══════════════════════════════════════════════════════════════════ +# x86 / amd64 builds +# ═══════════════════════════════════════════════════════════════════ + +# Build standard sources with standard variants +for src in "${STD_SRCS[@]}"; do + for variant in "${STD_VARIANTS[@]}"; do + IFS=':' read -r tag _ flags <<< "$variant" + name="${src}_${tag}" + echo "Building $name ..." + build_one "gcc" "$src" "$name" "$flags" "bin/amd64" + build_one "gcc -m32" "$src" "$name" "$flags" "bin/i386" + done +done + +# Build INC/DEC sources with inc/dec-forcing variants +for src in "${INCDEC_SRCS[@]}"; do + for variant in "${INCDEC_VARIANTS[@]}"; do + IFS=':' read -r tag _ flags <<< "$variant" + name="${src}_${tag}" + echo "Building $name ..." + build_one "gcc" "$src" "$name" "$flags" "bin/amd64" + build_one "gcc -m32" "$src" "$name" "$flags" "bin/i386" + done +done + +# Build ADC/SBB sources with standard variants +for src in "${ADCSBB_SRCS[@]}"; do + for variant in "${STD_VARIANTS[@]}"; do + IFS=':' read -r tag _ flags <<< "$variant" + name="${src}_${tag}" + echo "Building $name ..." + build_one "gcc" "$src" "$name" "$flags" "bin/amd64" + build_one "gcc -m32" "$src" "$name" "$flags" "bin/i386" + done +done + +# ═══════════════════════════════════════════════════════════════════ +# ARM builds (armhf + aarch64) +# ═══════════════════════════════════════════════════════════════════ + +for src in "${ARM_SRCS[@]}"; do + for variant in "${STD_VARIANTS[@]}"; do + IFS=':' read -r tag _ flags <<< "$variant" + name="${src}_${tag}" + echo "Building $name ..." + build_one "arm-linux-gnueabihf-gcc" "$src" "$name" "$flags" "bin/armhf" + build_one "aarch64-linux-gnu-gcc" "$src" "$name" "$flags" "bin/aarch64" + done +done + +echo "" +if [ $FAIL -eq 0 ]; then + echo "Done. Built $COUNT binaries." +else + echo "Done with errors ($COUNT succeeded). Check output above." + exit 1 +fi diff --git a/tests_src/ccop_triggers/ccop_adc_sbb.c b/tests_src/ccop_triggers/ccop_adc_sbb.c new file mode 100644 index 00000000..54b88324 --- /dev/null +++ b/tests_src/ccop_triggers/ccop_adc_sbb.c @@ -0,0 +1,440 @@ +/* + * ccop_adc_sbb.c — ADC/SBB condition code triggers (pure C) + * + * VEX models add-with-carry as CC_OP_ADCx and subtract-with-borrow as + * CC_OP_SBBx. These arise in multi-precision arithmetic. + * + * Strategy: + * - amd64: __int128 addition/subtraction compiles to add+adc / sub+sbb + * - i386: uint64_t addition/subtraction compiles to add+adc / sub+sbb + * + * Branching on the wide result after the operation triggers condition + * code evaluation on the ADC/SBB instruction's flags. + */ + +#include "ccop_common.h" + +volatile int g_sink; + +#ifdef __x86_64__ + +/* + * On amd64, __int128 is natively supported. The compiler breaks it into + * two 64-bit operations: add+adc for addition, sub+sbb for subtraction. + * The flags from the adc/sbb instruction become CC_OP_ADCQ / CC_OP_SBBQ. + */ + +typedef unsigned __int128 u128; +typedef __int128 s128; + +/* ═══════════════════════════════════════════════════════════════════ + * ADC — from __int128 addition + * ═══════════════════════════════════════════════════════════════════ */ + +/* ADC + CondZ: 128-bit add result == 0 */ +NOINLINE int ccop_adc_condz_64(u64 a_lo, u64 a_hi, u64 b_lo, u64 b_hi) { + u128 a = ((u128)a_hi << 64) | a_lo; + u128 b = ((u128)b_hi << 64) | b_lo; + u128 r = a + b; + if (r == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ADC + CondNZ: 128-bit add result != 0 */ +NOINLINE int ccop_adc_condnz_64(u64 a_lo, u64 a_hi, u64 b_lo, u64 b_hi) { + u128 a = ((u128)a_hi << 64) | a_lo; + u128 b = ((u128)b_hi << 64) | b_lo; + u128 r = a + b; + if (r != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ADC + CondS: 128-bit signed add result < 0 */ +NOINLINE int ccop_adc_conds_64(s64 a_lo, s64 a_hi, s64 b_lo, s64 b_hi) { + s128 a = ((s128)a_hi << 64) | (u64)a_lo; + s128 b = ((s128)b_hi << 64) | (u64)b_lo; + s128 r = a + b; + if (r < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ADC + CondB: 128-bit unsigned add carry (a + b < a) */ +NOINLINE int ccop_adc_condb_64(u64 a_lo, u64 a_hi, u64 b_lo, u64 b_hi) { + u128 a = ((u128)a_hi << 64) | a_lo; + u128 b = ((u128)b_hi << 64) | b_lo; + u128 r = a + b; + if (r < a) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ═══════════════════════════════════════════════════════════════════ + * SBB — from __int128 subtraction + * ═══════════════════════════════════════════════════════════════════ */ + +/* SBB + CondZ: 128-bit sub result == 0 */ +NOINLINE int ccop_sbb_condz_64(u64 a_lo, u64 a_hi, u64 b_lo, u64 b_hi) { + u128 a = ((u128)a_hi << 64) | a_lo; + u128 b = ((u128)b_hi << 64) | b_lo; + u128 r = a - b; + if (r == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* SBB + CondB: 128-bit unsigned a < b */ +NOINLINE int ccop_sbb_condb_64(u64 a_lo, u64 a_hi, u64 b_lo, u64 b_hi) { + u128 a = ((u128)a_hi << 64) | a_lo; + u128 b = ((u128)b_hi << 64) | b_lo; + if (a < b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* SBB + CondNB: 128-bit unsigned a >= b */ +NOINLINE int ccop_sbb_condnb_64(u64 a_lo, u64 a_hi, u64 b_lo, u64 b_hi) { + u128 a = ((u128)a_hi << 64) | a_lo; + u128 b = ((u128)b_hi << 64) | b_lo; + if (a >= b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* SBB + CondBE: 128-bit unsigned a <= b */ +NOINLINE int ccop_sbb_condbe_64(u64 a_lo, u64 a_hi, u64 b_lo, u64 b_hi) { + u128 a = ((u128)a_hi << 64) | a_lo; + u128 b = ((u128)b_hi << 64) | b_lo; + if (a <= b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* SBB + CondNBE: 128-bit unsigned a > b */ +NOINLINE int ccop_sbb_condnbe_64(u64 a_lo, u64 a_hi, u64 b_lo, u64 b_hi) { + u128 a = ((u128)a_hi << 64) | a_lo; + u128 b = ((u128)b_hi << 64) | b_lo; + if (a > b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* SBB + CondL: 128-bit signed a < b */ +NOINLINE int ccop_sbb_condl_64(s64 a_lo, s64 a_hi, s64 b_lo, s64 b_hi) { + s128 a = ((s128)a_hi << 64) | (u64)a_lo; + s128 b = ((s128)b_hi << 64) | (u64)b_lo; + if (a < b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* SBB + CondS: 128-bit signed sub result sign */ +NOINLINE int ccop_sbb_conds_64(s64 a_lo, s64 a_hi, s64 b_lo, s64 b_hi) { + s128 a = ((s128)a_hi << 64) | (u64)a_lo; + s128 b = ((s128)b_hi << 64) | (u64)b_lo; + s128 r = a - b; + if (r < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +#else /* i386 */ + +/* + * On i386, uint64_t / int64_t are handled as pairs of 32-bit registers. + * Addition compiles to add+adc, subtraction to sub+sbb. + * Flags from the adc/sbb become CC_OP_ADCL / CC_OP_SBBL. + */ + +/* ── Helper macros for narrow asm goto ADC/SBB ────────────────────── */ + +#define ADC_ASM_GOTO_8(fname, jcc) \ +NOINLINE int fname(u8 a_lo, u8 a_hi, u8 b_lo, u8 b_hi) { \ + u8 lo = a_lo, hi = a_hi; \ + asm goto ( \ + "addb %[blo], %[lo]\n\t" \ + "adcb %[bhi], %[hi]\n\t" \ + jcc " %l[taken]" \ + : [lo] "+q"(lo), [hi] "+q"(hi) \ + : [blo] "q"(b_lo), [bhi] "q"(b_hi) \ + : "cc" : taken); \ + g_sink = 0; return g_sink; \ +taken: g_sink = 1; return g_sink; \ +} + +#define ADC_ASM_GOTO_16(fname, jcc) \ +NOINLINE int fname(u16 a_lo, u16 a_hi, u16 b_lo, u16 b_hi) { \ + u16 lo = a_lo, hi = a_hi; \ + asm goto ( \ + "addw %[blo], %[lo]\n\t" \ + "adcw %[bhi], %[hi]\n\t" \ + jcc " %l[taken]" \ + : [lo] "+r"(lo), [hi] "+r"(hi) \ + : [blo] "r"(b_lo), [bhi] "r"(b_hi) \ + : "cc" : taken); \ + g_sink = 0; return g_sink; \ +taken: g_sink = 1; return g_sink; \ +} + +#define ADC_ASM_GOTO_32(fname, jcc) \ +NOINLINE int fname(u32 a_lo, u32 a_hi, u32 b_lo, u32 b_hi) { \ + u32 lo = a_lo, hi = a_hi; \ + asm goto ( \ + "addl %[blo], %[lo]\n\t" \ + "adcl %[bhi], %[hi]\n\t" \ + jcc " %l[taken]" \ + : [lo] "+r"(lo), [hi] "+r"(hi) \ + : [blo] "r"(b_lo), [bhi] "r"(b_hi) \ + : "cc" : taken); \ + g_sink = 0; return g_sink; \ +taken: g_sink = 1; return g_sink; \ +} + +#define SBB_ASM_GOTO_8(fname, jcc) \ +NOINLINE int fname(u8 a_lo, u8 a_hi, u8 b_lo, u8 b_hi) { \ + u8 lo = a_lo, hi = a_hi; \ + asm goto ( \ + "subb %[blo], %[lo]\n\t" \ + "sbbb %[bhi], %[hi]\n\t" \ + jcc " %l[taken]" \ + : [lo] "+q"(lo), [hi] "+q"(hi) \ + : [blo] "q"(b_lo), [bhi] "q"(b_hi) \ + : "cc" : taken); \ + g_sink = 0; return g_sink; \ +taken: g_sink = 1; return g_sink; \ +} + +#define SBB_ASM_GOTO_16(fname, jcc) \ +NOINLINE int fname(u16 a_lo, u16 a_hi, u16 b_lo, u16 b_hi) { \ + u16 lo = a_lo, hi = a_hi; \ + asm goto ( \ + "subw %[blo], %[lo]\n\t" \ + "sbbw %[bhi], %[hi]\n\t" \ + jcc " %l[taken]" \ + : [lo] "+r"(lo), [hi] "+r"(hi) \ + : [blo] "r"(b_lo), [bhi] "r"(b_hi) \ + : "cc" : taken); \ + g_sink = 0; return g_sink; \ +taken: g_sink = 1; return g_sink; \ +} + +#define SBB_ASM_GOTO_32(fname, jcc) \ +NOINLINE int fname(u32 a_lo, u32 a_hi, u32 b_lo, u32 b_hi) { \ + u32 lo = a_lo, hi = a_hi; \ + asm goto ( \ + "subl %[blo], %[lo]\n\t" \ + "sbbl %[bhi], %[hi]\n\t" \ + jcc " %l[taken]" \ + : [lo] "+r"(lo), [hi] "+r"(hi) \ + : [blo] "r"(b_lo), [bhi] "r"(b_hi) \ + : "cc" : taken); \ + g_sink = 0; return g_sink; \ +taken: g_sink = 1; return g_sink; \ +} + +/* ═══════════════════════════════════════════════════════════════════ + * ADC — from uint64_t addition on i386 (pure C, 32-bit pair) + * ═══════════════════════════════════════════════════════════════════ */ + +/* ADC + CondZ: 64-bit add result == 0 */ +NOINLINE int ccop_adc_condz_32(u64 a, u64 b) { + u64 r = a + b; + if (r == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ADC + CondNZ: 64-bit add result != 0 */ +NOINLINE int ccop_adc_condnz_32(u64 a, u64 b) { + u64 r = a + b; + if (r != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ADC + CondS: 64-bit signed add < 0 */ +NOINLINE int ccop_adc_conds_32(s64 a, s64 b) { + s64 r = a + b; + if (r < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ADC + CondB: 64-bit unsigned add carry */ +NOINLINE int ccop_adc_condb_32(u64 a, u64 b) { + u64 r = a + b; + if (r < a) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ═══════════════════════════════════════════════════════════════════ + * SBB — from uint64_t subtraction on i386 (pure C, 32-bit pair) + * ═══════════════════════════════════════════════════════════════════ */ + +/* SBB + CondZ: 64-bit sub result == 0 */ +NOINLINE int ccop_sbb_condz_32(u64 a, u64 b) { + u64 r = a - b; + if (r == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* SBB + CondB: 64-bit unsigned a < b */ +NOINLINE int ccop_sbb_condb_32(u64 a, u64 b) { + if (a < b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* SBB + CondNB: 64-bit unsigned a >= b */ +NOINLINE int ccop_sbb_condnb_32(u64 a, u64 b) { + if (a >= b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* SBB + CondBE: 64-bit unsigned a <= b */ +NOINLINE int ccop_sbb_condbe_32(u64 a, u64 b) { + if (a <= b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* SBB + CondNBE: 64-bit unsigned a > b */ +NOINLINE int ccop_sbb_condnbe_32(u64 a, u64 b) { + if (a > b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* SBB + CondL: 64-bit signed a < b */ +NOINLINE int ccop_sbb_condl_32(s64 a, s64 b) { + if (a < b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* SBB + CondS: 64-bit signed sub result sign */ +NOINLINE int ccop_sbb_conds_32(s64 a, s64 b) { + s64 r = a - b; + if (r < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ═══════════════════════════════════════════════════════════════════ + * P0: New conditions at 32-bit (asm goto) + * ═══════════════════════════════════════════════════════════════════ */ + +ADC_ASM_GOTO_32(ccop_adc_condo_32, "jo") +ADC_ASM_GOTO_32(ccop_adc_condno_32, "jno") +SBB_ASM_GOTO_32(ccop_sbb_condo_32, "jo") +SBB_ASM_GOTO_32(ccop_sbb_condno_32, "jno") +SBB_ASM_GOTO_32(ccop_sbb_condnl_32, "jge") + +/* ═══════════════════════════════════════════════════════════════════ + * P1: Narrow ADC 8-bit and 16-bit (asm goto) + * ═══════════════════════════════════════════════════════════════════ */ + +ADC_ASM_GOTO_8(ccop_adc_condz_8, "je") +ADC_ASM_GOTO_16(ccop_adc_condz_16, "je") +ADC_ASM_GOTO_8(ccop_adc_condnz_8, "jne") +ADC_ASM_GOTO_16(ccop_adc_condnz_16, "jne") +ADC_ASM_GOTO_8(ccop_adc_conds_8, "js") +ADC_ASM_GOTO_16(ccop_adc_conds_16, "js") +ADC_ASM_GOTO_8(ccop_adc_condb_8, "jb") +ADC_ASM_GOTO_16(ccop_adc_condb_16, "jb") +ADC_ASM_GOTO_8(ccop_adc_condo_8, "jo") +ADC_ASM_GOTO_16(ccop_adc_condo_16, "jo") +ADC_ASM_GOTO_8(ccop_adc_condno_8, "jno") +ADC_ASM_GOTO_16(ccop_adc_condno_16, "jno") + +/* ═══════════════════════════════════════════════════════════════════ + * P1: Narrow SBB 8-bit and 16-bit (asm goto) + * ═══════════════════════════════════════════════════════════════════ */ + +SBB_ASM_GOTO_8(ccop_sbb_condz_8, "je") +SBB_ASM_GOTO_16(ccop_sbb_condz_16, "je") +SBB_ASM_GOTO_8(ccop_sbb_condb_8, "jb") +SBB_ASM_GOTO_16(ccop_sbb_condb_16, "jb") +SBB_ASM_GOTO_8(ccop_sbb_condnb_8, "jae") +SBB_ASM_GOTO_16(ccop_sbb_condnb_16, "jae") +SBB_ASM_GOTO_8(ccop_sbb_condbe_8, "jbe") +SBB_ASM_GOTO_16(ccop_sbb_condbe_16, "jbe") +SBB_ASM_GOTO_8(ccop_sbb_condnbe_8, "ja") +SBB_ASM_GOTO_16(ccop_sbb_condnbe_16, "ja") +SBB_ASM_GOTO_8(ccop_sbb_condl_8, "jl") +SBB_ASM_GOTO_16(ccop_sbb_condl_16, "jl") +SBB_ASM_GOTO_8(ccop_sbb_conds_8, "js") +SBB_ASM_GOTO_16(ccop_sbb_conds_16, "js") +SBB_ASM_GOTO_8(ccop_sbb_condo_8, "jo") +SBB_ASM_GOTO_16(ccop_sbb_condo_16, "jo") +SBB_ASM_GOTO_8(ccop_sbb_condno_8, "jno") +SBB_ASM_GOTO_16(ccop_sbb_condno_16, "jno") +SBB_ASM_GOTO_8(ccop_sbb_condnl_8, "jge") +SBB_ASM_GOTO_16(ccop_sbb_condnl_16, "jge") + +#endif /* __x86_64__ */ + +int main(void) { + g_sink = 0; + +#ifdef __x86_64__ + ccop_adc_condz_64(0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL, 1, 0); + ccop_adc_condnz_64(1, 0, 2, 0); + ccop_adc_conds_64(0, 0x7FFFFFFFFFFFFFFFLL, 0, 1); + ccop_adc_condb_64(0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL, 1, 0); + + ccop_sbb_condz_64(5, 0, 5, 0); + ccop_sbb_condb_64(1, 0, 2, 0); + ccop_sbb_condnb_64(2, 0, 1, 0); + ccop_sbb_condbe_64(1, 0, 1, 0); + ccop_sbb_condnbe_64(2, 0, 1, 0); + ccop_sbb_condl_64(0, -1, 0, 1); + ccop_sbb_conds_64(0, 0, 0, 1); +#else + /* Existing pure C 32-bit pair calls */ + ccop_adc_condz_32(0xFFFFFFFFFFFFFFFFULL, 1); + ccop_adc_condnz_32(1, 2); + ccop_adc_conds_32(0x7FFFFFFFFFFFFFFFLL, 1); + ccop_adc_condb_32(0xFFFFFFFFFFFFFFFFULL, 1); + + ccop_sbb_condz_32(5, 5); + ccop_sbb_condb_32(1, 2); + ccop_sbb_condnb_32(2, 1); + ccop_sbb_condbe_32(1, 1); + ccop_sbb_condnbe_32(2, 1); + ccop_sbb_condl_32(-1, 1); + ccop_sbb_conds_32(0, 1); + + /* P0: New 32-bit asm goto conditions */ + ccop_adc_condo_32(0, 0x7FFFFFFF, 0, 1); + ccop_adc_condno_32(1, 0, 2, 0); + ccop_sbb_condo_32(0, 0x80000000U, 0, 1); + ccop_sbb_condno_32(0, 0, 0, 0); + ccop_sbb_condnl_32(0, 2, 0, 1); + + /* P1: Narrow ADC 8-bit */ + ccop_adc_condz_8(0xFF, 0xFF, 1, 0); + ccop_adc_condnz_8(1, 0, 2, 0); + ccop_adc_conds_8(0, 0x7F, 0, 1); + ccop_adc_condb_8(0, 0xFF, 0, 1); + ccop_adc_condo_8(0, 0x7F, 0, 1); + ccop_adc_condno_8(1, 0, 2, 0); + + /* P1: Narrow ADC 16-bit */ + ccop_adc_condz_16(0xFFFF, 0xFFFF, 1, 0); + ccop_adc_condnz_16(1, 0, 2, 0); + ccop_adc_conds_16(0, 0x7FFF, 0, 1); + ccop_adc_condb_16(0, 0xFFFF, 0, 1); + ccop_adc_condo_16(0, 0x7F, 0, 1); + ccop_adc_condno_16(1, 0, 2, 0); + + /* P1: Narrow SBB 8-bit */ + ccop_sbb_condz_8(5, 0, 5, 0); + ccop_sbb_condb_8(0, 1, 0, 2); + ccop_sbb_condnb_8(0, 2, 0, 1); + ccop_sbb_condbe_8(0, 1, 0, 1); + ccop_sbb_condnbe_8(0, 2, 0, 1); + ccop_sbb_condl_8(0, (u8)-1, 0, 1); + ccop_sbb_conds_8(0, 0, 0, 1); + ccop_sbb_condo_8(0, 0x80, 0, 1); + ccop_sbb_condno_8(0, 0, 0, 0); + ccop_sbb_condnl_8(0, 2, 0, 1); + + /* P1: Narrow SBB 16-bit */ + ccop_sbb_condz_16(5, 0, 5, 0); + ccop_sbb_condb_16(0, 1, 0, 2); + ccop_sbb_condnb_16(0, 2, 0, 1); + ccop_sbb_condbe_16(0, 1, 0, 1); + ccop_sbb_condnbe_16(0, 2, 0, 1); + ccop_sbb_condl_16(0, (u16)-1, 0, 1); + ccop_sbb_conds_16(0, 0, 0, 1); + ccop_sbb_condo_16(0, 0x80, 0, 1); + ccop_sbb_condno_16(0, 0, 0, 0); + ccop_sbb_condnl_16(0, 2, 0, 1); +#endif + + return g_sink; +} diff --git a/tests_src/ccop_triggers/ccop_add.c b/tests_src/ccop_triggers/ccop_add.c new file mode 100644 index 00000000..b9a7e578 --- /dev/null +++ b/tests_src/ccop_triggers/ccop_add.c @@ -0,0 +1,472 @@ +/* + * ccop_add.c — ADD condition code triggers + * + * VEX models ADD flag-setting as CC_OP_ADDx. These functions trigger + * conditions on the result of addition: zero, sign, overflow. + */ + +#include "ccop_common.h" + +volatile int g_sink; + +/* ═══════════════════════════════════════════════════════════════════════ + * CondZ: (a + b) == 0 + * ═══════════════════════════════════════════════════════════════════════ */ + +/* ── CondZ 8 ──────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condz_8(s8 a, s8 b) { + volatile s8 va = a, vb = b; + s8 r = va + vb; + if (r == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondZ 16 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condz_16(s16 a, s16 b) { + volatile s16 va = a, vb = b; + s16 r = va + vb; + if (r == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondZ 32 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condz_32(s32 a, s32 b) { + s32 r = a + b; + if (r == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondZ 64 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condz_64(s64 a, s64 b) { + s64 r = a + b; + if (r == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ═══════════════════════════════════════════════════════════════════════ + * CondNZ: (a + b) != 0 + * ═══════════════════════════════════════════════════════════════════════ */ + +/* ── CondNZ 8 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condnz_8(s8 a, s8 b) { + volatile s8 va = a, vb = b; + s8 r = va + vb; + if (r != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondNZ 16 ────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condnz_16(s16 a, s16 b) { + volatile s16 va = a, vb = b; + s16 r = va + vb; + if (r != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondNZ 32 ────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condnz_32(s32 a, s32 b) { + s32 r = a + b; + if (r != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondNZ 64 ────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condnz_64(s64 a, s64 b) { + s64 r = a + b; + if (r != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ═══════════════════════════════════════════════════════════════════════ + * CondS: sign of (a + b) + * ═══════════════════════════════════════════════════════════════════════ */ + +/* ── CondS 8 ──────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_conds_8(s8 a, s8 b) { + volatile s8 va = a, vb = b; + s8 r = va + vb; + if (r < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondS 16 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_conds_16(s16 a, s16 b) { + volatile s16 va = a, vb = b; + s16 r = va + vb; + if (r < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondS 32 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_conds_32(s32 a, s32 b) { + s32 r = a + b; + if (r < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondS 64 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_conds_64(s64 a, s64 b) { + s64 r = a + b; + if (r < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ═══════════════════════════════════════════════════════════════════════ + * CondNS: not sign of (a + b) + * ═══════════════════════════════════════════════════════════════════════ */ + +/* ── CondNS 8 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condns_8(s8 a, s8 b) { + volatile s8 va = a, vb = b; + s8 r = va + vb; + if (r >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondNS 16 ────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condns_16(s16 a, s16 b) { + volatile s16 va = a, vb = b; + s16 r = va + vb; + if (r >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondNS 32 ────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condns_32(s32 a, s32 b) { + s32 r = a + b; + if (r >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondNS 64 ────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condns_64(s64 a, s64 b) { + s64 r = a + b; + if (r >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ═══════════════════════════════════════════════════════════════════════ + * CondO: signed add overflow + * ═══════════════════════════════════════════════════════════════════════ */ + +/* ── CondO 8 ──────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condo_8(s8 a, s8 b) { + s8 r; + if (__builtin_add_overflow(a, b, &r)) + g_sink = 1; + else + g_sink = 0; + return g_sink; +} + +/* ── CondO 16 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condo_16(s16 a, s16 b) { + s16 r; + if (__builtin_add_overflow(a, b, &r)) + g_sink = 1; + else + g_sink = 0; + return g_sink; +} + +/* ── CondO 32 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condo_32(s32 a, s32 b) { + s32 r; + if (__builtin_add_overflow(a, b, &r)) + g_sink = 1; + else + g_sink = 0; + return g_sink; +} + +/* ── CondO 64 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condo_64(s64 a, s64 b) { + s64 r; + if (__builtin_add_overflow(a, b, &r)) + g_sink = 1; + else + g_sink = 0; + return g_sink; +} + +/* ═══════════════════════════════════════════════════════════════════════ + * CondNO: no signed add overflow + * ═══════════════════════════════════════════════════════════════════════ */ + +/* ── CondNO 8 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condno_8(s8 a, s8 b) { + s8 r; + if (!__builtin_add_overflow(a, b, &r)) + g_sink = 1; + else + g_sink = 0; + return g_sink; +} + +/* ── CondNO 16 ────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condno_16(s16 a, s16 b) { + s16 r; + if (!__builtin_add_overflow(a, b, &r)) + g_sink = 1; + else + g_sink = 0; + return g_sink; +} + +/* ── CondNO 32 ────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condno_32(s32 a, s32 b) { + s32 r; + if (!__builtin_add_overflow(a, b, &r)) + g_sink = 1; + else + g_sink = 0; + return g_sink; +} + +/* ── CondNO 64 ────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condno_64(s64 a, s64 b) { + s64 r; + if (!__builtin_add_overflow(a, b, &r)) + g_sink = 1; + else + g_sink = 0; + return g_sink; +} + +/* ═══════════════════════════════════════════════════════════════════════ + * CondB: unsigned add carry (a + b < a) + * ═══════════════════════════════════════════════════════════════════════ */ + +/* ── CondB 8 ──────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condb_8(u8 a, u8 b) { + volatile u8 va = a, vb = b; + u8 r = va + vb; + if (r < a) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondB 16 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condb_16(u16 a, u16 b) { + volatile u16 va = a, vb = b; + u16 r = va + vb; + if (r < a) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondB 32 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condb_32(u32 a, u32 b) { + u32 r = a + b; + if (r < a) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondB 64 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condb_64(u64 a, u64 b) { + u64 r = a + b; + if (r < a) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ═══════════════════════════════════════════════════════════════════════ + * CondLE: signed (a + b) <= 0 — via asm goto (add + jle) + * ═══════════════════════════════════════════════════════════════════════ */ + +/* ── CondLE 8 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condle_8(s8 a, s8 b) { + s8 tmp = a; + asm goto ("addb %1, %0\n\t" "jle %l[taken]" : "+q"(tmp) : "q"(b) : "cc" : taken); + g_sink = 0; return g_sink; +taken: g_sink = 1; return g_sink; +} + +/* ── CondLE 16 ────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condle_16(s16 a, s16 b) { + s16 tmp = a; + asm goto ("addw %1, %0\n\t" "jle %l[taken]" : "+r"(tmp) : "r"(b) : "cc" : taken); + g_sink = 0; return g_sink; +taken: g_sink = 1; return g_sink; +} + +/* ── CondLE 32 ────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condle_32(s32 a, s32 b) { + s32 tmp = a; + asm goto ("addl %1, %0\n\t" "jle %l[taken]" : "+r"(tmp) : "r"(b) : "cc" : taken); + g_sink = 0; return g_sink; +taken: g_sink = 1; return g_sink; +} + +/* ── CondLE 64 ────────────────────────────────────────────────────────── */ + +#ifdef __x86_64__ +NOINLINE int ccop_add_condle_64(s64 a, s64 b) { + s64 tmp = a; + asm goto ("addq %1, %0\n\t" "jle %l[taken]" : "+r"(tmp) : "r"(b) : "cc" : taken); + g_sink = 0; return g_sink; +taken: g_sink = 1; return g_sink; +} +#endif + +/* ═══════════════════════════════════════════════════════════════════════ + * CondNLE: signed (a + b) > 0 — via asm goto (add + jg) + * ═══════════════════════════════════════════════════════════════════════ */ + +/* ── CondNLE 8 ────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condnle_8(s8 a, s8 b) { + s8 tmp = a; + asm goto ("addb %1, %0\n\t" "jg %l[taken]" : "+q"(tmp) : "q"(b) : "cc" : taken); + g_sink = 0; return g_sink; +taken: g_sink = 1; return g_sink; +} + +/* ── CondNLE 16 ───────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condnle_16(s16 a, s16 b) { + s16 tmp = a; + asm goto ("addw %1, %0\n\t" "jg %l[taken]" : "+r"(tmp) : "r"(b) : "cc" : taken); + g_sink = 0; return g_sink; +taken: g_sink = 1; return g_sink; +} + +/* ── CondNLE 32 ───────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condnle_32(s32 a, s32 b) { + s32 tmp = a; + asm goto ("addl %1, %0\n\t" "jg %l[taken]" : "+r"(tmp) : "r"(b) : "cc" : taken); + g_sink = 0; return g_sink; +taken: g_sink = 1; return g_sink; +} + +/* ── CondNLE 64 ───────────────────────────────────────────────────────── */ + +#ifdef __x86_64__ +NOINLINE int ccop_add_condnle_64(s64 a, s64 b) { + s64 tmp = a; + asm goto ("addq %1, %0\n\t" "jg %l[taken]" : "+r"(tmp) : "r"(b) : "cc" : taken); + g_sink = 0; return g_sink; +taken: g_sink = 1; return g_sink; +} +#endif + +/* ═══════════════════════════════════════════════════════════════════════ + * CondBE: unsigned (a + b) below-or-equal — via asm goto (add + jbe) + * ═══════════════════════════════════════════════════════════════════════ */ + +/* ── CondBE 8 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condbe_8(u8 a, u8 b) { + u8 tmp = a; + asm goto ("addb %1, %0\n\t" "jbe %l[taken]" : "+q"(tmp) : "q"(b) : "cc" : taken); + g_sink = 0; return g_sink; +taken: g_sink = 1; return g_sink; +} + +/* ── CondBE 16 ────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condbe_16(u16 a, u16 b) { + u16 tmp = a; + asm goto ("addw %1, %0\n\t" "jbe %l[taken]" : "+r"(tmp) : "r"(b) : "cc" : taken); + g_sink = 0; return g_sink; +taken: g_sink = 1; return g_sink; +} + +/* ── CondBE 32 ────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_add_condbe_32(u32 a, u32 b) { + u32 tmp = a; + asm goto ("addl %1, %0\n\t" "jbe %l[taken]" : "+r"(tmp) : "r"(b) : "cc" : taken); + g_sink = 0; return g_sink; +taken: g_sink = 1; return g_sink; +} + +/* ═══════════════════════════════════════════════════════════════════════ */ + +int main(void) { + g_sink = 0; + + ccop_add_condz_8(1, -1); + ccop_add_condz_16(1, -1); + ccop_add_condz_32(1, -1); + ccop_add_condz_64(1, -1); + + ccop_add_condnz_8(1, 2); + ccop_add_condnz_16(1, 2); + ccop_add_condnz_32(1, 2); + ccop_add_condnz_64(1, 2); + + ccop_add_conds_8(1, -5); + ccop_add_conds_16(1, -5); + ccop_add_conds_32(1, -5); + ccop_add_conds_64(1, -5); + + ccop_add_condns_8(1, 2); + ccop_add_condns_16(1, 2); + ccop_add_condns_32(1, 2); + ccop_add_condns_64(1, 2); + + ccop_add_condo_8(127, 1); + ccop_add_condo_16(0x7FFF, 1); + ccop_add_condo_32(0x7FFFFFFF, 1); + ccop_add_condo_64(0x7FFFFFFFFFFFFFFFLL, 1); + + ccop_add_condno_8(1, 2); + ccop_add_condno_16(1, 2); + ccop_add_condno_32(1, 2); + ccop_add_condno_64(1, 2); + + ccop_add_condb_8(0xFF, 1); + ccop_add_condb_16(0xFFFF, 1); + ccop_add_condb_32(0xFFFFFFFFU, 1); + ccop_add_condb_64(0xFFFFFFFFFFFFFFFFULL, 1); + + ccop_add_condle_8(-5, 1); + ccop_add_condle_16(-5, 1); + ccop_add_condle_32(-5, 1); +#ifdef __x86_64__ + ccop_add_condle_64(-5, 1); +#endif + + ccop_add_condnle_8(5, 1); + ccop_add_condnle_16(5, 1); + ccop_add_condnle_32(5, 1); +#ifdef __x86_64__ + ccop_add_condnle_64(5, 1); +#endif + + ccop_add_condbe_8(0x80, 0x80); + ccop_add_condbe_16(0x8000, 0x8000); + ccop_add_condbe_32(0x80000000U, 0x80000000U); + + return g_sink; +} diff --git a/tests_src/ccop_triggers/ccop_arm_adc_sbb.c b/tests_src/ccop_triggers/ccop_arm_adc_sbb.c new file mode 100644 index 00000000..8fdee9c3 --- /dev/null +++ b/tests_src/ccop_triggers/ccop_arm_adc_sbb.c @@ -0,0 +1,484 @@ +/* + * ccop_arm_adc_sbb.c -- ADC/SBC condition code triggers for ARM32 and AArch64 + * + * VEX models add-with-carry and subtract-with-carry as: + * ARM32: ARMG_CC_OP_ADC (dep1 = argL, dep2 = argR, dep3 = oldC) + * ARMG_CC_OP_SBB (dep1 = argL, dep2 = argR, dep3 = oldC) + * ARM64: ARM64G_CC_OP_ADC32 / ARM64G_CC_OP_ADC64 + * ARM64G_CC_OP_SBC32 / ARM64G_CC_OP_SBC64 + * + * Strategy: + * ARM32: 64-bit arithmetic on a 32-bit target compiles to + * adds+adc / subs+sbc pairs. Alternatively, use inline asm + * to directly emit ADCS/SBCS with known carry-in. + * ARM64: 128-bit arithmetic (unsigned __int128) compiles to + * adds+adc / subs+sbc pairs for the high 64 bits. + * For 32-bit ADC/SBC on ARM64, we need inline asm. + * + * The flags from the ADC/SBC instruction are what VEX captures. + */ + +#include "ccop_common.h" + +volatile int g_sink; + +/* =================================================================== + * ARM32: 64-bit arithmetic generates add+adc / sub+sbc + * + * On a 32-bit ARM target, uint64_t/int64_t operations are split + * into pairs of 32-bit operations. The second half uses ADC/SBC. + * =================================================================== */ + +#ifndef __aarch64__ + +/* -- ADC conditions from uint64_t addition -- */ + +/* ADC + EQ: 64-bit add result == 0 */ +NOINLINE int ccop_adc_eq_32(u64 a, u64 b) { + u64 r = a + b; + if (r == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ADC + NE: 64-bit add result != 0 */ +NOINLINE int ccop_adc_ne_32(u64 a, u64 b) { + u64 r = a + b; + if (r != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ADC + MI: 64-bit signed add result < 0 */ +NOINLINE int ccop_adc_mi_32(s64 a, s64 b) { + s64 r = a + b; + if (r < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ADC + PL: 64-bit signed add result >= 0 */ +NOINLINE int ccop_adc_pl_32(s64 a, s64 b) { + s64 r = a + b; + if (r >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ADC + HS: 64-bit unsigned add carry (result < a) */ +NOINLINE int ccop_adc_hs_32(u64 a, u64 b) { + u64 r = a + b; + if (r < a) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* -- SBC conditions from uint64_t subtraction -- */ + +/* SBC + EQ: 64-bit sub result == 0 */ +NOINLINE int ccop_sbc_eq_32(u64 a, u64 b) { + u64 r = a - b; + if (r == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* SBC + NE: 64-bit sub result != 0 */ +NOINLINE int ccop_sbc_ne_32(u64 a, u64 b) { + u64 r = a - b; + if (r != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* SBC + LO: 64-bit unsigned a < b */ +NOINLINE int ccop_sbc_lo_32(u64 a, u64 b) { + if (a < b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* SBC + HS: 64-bit unsigned a >= b */ +NOINLINE int ccop_sbc_hs_32(u64 a, u64 b) { + if (a >= b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* SBC + HI: 64-bit unsigned a > b */ +NOINLINE int ccop_sbc_hi_32(u64 a, u64 b) { + if (a > b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* SBC + LS: 64-bit unsigned a <= b */ +NOINLINE int ccop_sbc_ls_32(u64 a, u64 b) { + if (a <= b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* SBC + LT: 64-bit signed a < b */ +NOINLINE int ccop_sbc_lt_32(s64 a, s64 b) { + if (a < b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* SBC + GE: 64-bit signed a >= b */ +NOINLINE int ccop_sbc_ge_32(s64 a, s64 b) { + if (a >= b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* SBC + GT: 64-bit signed a > b */ +NOINLINE int ccop_sbc_gt_32(s64 a, s64 b) { + if (a > b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* SBC + LE: 64-bit signed a <= b */ +NOINLINE int ccop_sbc_le_32(s64 a, s64 b) { + if (a <= b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* SBC + MI: 64-bit signed sub result < 0 */ +NOINLINE int ccop_sbc_mi_32(s64 a, s64 b) { + s64 r = a - b; + if (r < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* -- Inline asm ADC/SBC with explicit carry-in -- */ + +/* ADCS with carry-in=1: r = a + b + 1, test EQ */ +NOINLINE int ccop_adc_carry_eq_32(u32 a, u32 b) { + u32 result; + int cond; + /* Set carry, then ADCS */ + asm volatile ( + "cmp %[z], #0\n\t" /* sets C=1 (0 >= 0 unsigned) */ + "adcs %[r], %[a], %[b]\n\t" + "ite eq\n\t" + "moveq %[c], #1\n\t" + "movne %[c], #0" + : [r] "=r"(result), [c] "=r"(cond) + : [a] "r"(a), [b] "r"(b), [z] "r"(0) + : "cc" + ); + g_sink = cond; + return g_sink; +} + +/* SBCS with carry-in=1: r = a - b, test LO (borrow) */ +NOINLINE int ccop_sbc_carry_lo_32(u32 a, u32 b) { + u32 result; + int cond; + /* Set carry (no borrow), then SBCS */ + asm volatile ( + "cmp %[z], #0\n\t" /* sets C=1 */ + "sbcs %[r], %[a], %[b]\n\t" + "ite cc\n\t" + "movcc %[c], #1\n\t" + "movcs %[c], #0" + : [r] "=r"(result), [c] "=r"(cond) + : [a] "r"(a), [b] "r"(b), [z] "r"(0) + : "cc" + ); + g_sink = cond; + return g_sink; +} + +/* ADCS with carry-in=0: r = a + b + 0 (same as ADDS, but VEX sees ADC) */ +NOINLINE int ccop_adc_nocarry_vs_32(s32 a, s32 b) { + s32 result; + int cond; + asm volatile ( + "adds %[r], %[z], #0\n\t" /* clears C */ + "adcs %[r], %[a], %[b]\n\t" + "ite vs\n\t" + "movvs %[c], #1\n\t" + "movvc %[c], #0" + : [r] "=r"(result), [c] "=r"(cond) + : [a] "r"(a), [b] "r"(b), [z] "r"(0) + : "cc" + ); + g_sink = cond; + return g_sink; +} + +#else /* __aarch64__ */ + +/* =================================================================== + * AArch64: __int128 arithmetic generates adds+adc / subs+sbc + * =================================================================== */ + +typedef unsigned __int128 u128; +typedef __int128 s128; + +/* -- ADC conditions from __int128 addition -- */ + +/* ADC + EQ: 128-bit add result == 0 */ +NOINLINE int ccop_adc_eq_64(u64 a_lo, u64 a_hi, u64 b_lo, u64 b_hi) { + u128 a = ((u128)a_hi << 64) | a_lo; + u128 b = ((u128)b_hi << 64) | b_lo; + u128 r = a + b; + if (r == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ADC + NE: 128-bit add result != 0 */ +NOINLINE int ccop_adc_ne_64(u64 a_lo, u64 a_hi, u64 b_lo, u64 b_hi) { + u128 a = ((u128)a_hi << 64) | a_lo; + u128 b = ((u128)b_hi << 64) | b_lo; + u128 r = a + b; + if (r != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ADC + MI: 128-bit signed add result < 0 */ +NOINLINE int ccop_adc_mi_64(s64 a_lo, s64 a_hi, s64 b_lo, s64 b_hi) { + s128 a = ((s128)a_hi << 64) | (u64)a_lo; + s128 b = ((s128)b_hi << 64) | (u64)b_lo; + s128 r = a + b; + if (r < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ADC + PL: 128-bit signed add result >= 0 */ +NOINLINE int ccop_adc_pl_64(s64 a_lo, s64 a_hi, s64 b_lo, s64 b_hi) { + s128 a = ((s128)a_hi << 64) | (u64)a_lo; + s128 b = ((s128)b_hi << 64) | (u64)b_lo; + s128 r = a + b; + if (r >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ADC + HS: 128-bit unsigned add carry */ +NOINLINE int ccop_adc_hs_64(u64 a_lo, u64 a_hi, u64 b_lo, u64 b_hi) { + u128 a = ((u128)a_hi << 64) | a_lo; + u128 b = ((u128)b_hi << 64) | b_lo; + u128 r = a + b; + if (r < a) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* -- SBC conditions from __int128 subtraction -- */ + +/* SBC + EQ: 128-bit sub result == 0 */ +NOINLINE int ccop_sbc_eq_64(u64 a_lo, u64 a_hi, u64 b_lo, u64 b_hi) { + u128 a = ((u128)a_hi << 64) | a_lo; + u128 b = ((u128)b_hi << 64) | b_lo; + u128 r = a - b; + if (r == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* SBC + LO: 128-bit unsigned a < b */ +NOINLINE int ccop_sbc_lo_64(u64 a_lo, u64 a_hi, u64 b_lo, u64 b_hi) { + u128 a = ((u128)a_hi << 64) | a_lo; + u128 b = ((u128)b_hi << 64) | b_lo; + if (a < b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* SBC + HS: 128-bit unsigned a >= b */ +NOINLINE int ccop_sbc_hs_64(u64 a_lo, u64 a_hi, u64 b_lo, u64 b_hi) { + u128 a = ((u128)a_hi << 64) | a_lo; + u128 b = ((u128)b_hi << 64) | b_lo; + if (a >= b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* SBC + HI: 128-bit unsigned a > b */ +NOINLINE int ccop_sbc_hi_64(u64 a_lo, u64 a_hi, u64 b_lo, u64 b_hi) { + u128 a = ((u128)a_hi << 64) | a_lo; + u128 b = ((u128)b_hi << 64) | b_lo; + if (a > b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* SBC + LS: 128-bit unsigned a <= b */ +NOINLINE int ccop_sbc_ls_64(u64 a_lo, u64 a_hi, u64 b_lo, u64 b_hi) { + u128 a = ((u128)a_hi << 64) | a_lo; + u128 b = ((u128)b_hi << 64) | b_lo; + if (a <= b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* SBC + LT: 128-bit signed a < b */ +NOINLINE int ccop_sbc_lt_64(s64 a_lo, s64 a_hi, s64 b_lo, s64 b_hi) { + s128 a = ((s128)a_hi << 64) | (u64)a_lo; + s128 b = ((s128)b_hi << 64) | (u64)b_lo; + if (a < b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* SBC + GE: 128-bit signed a >= b */ +NOINLINE int ccop_sbc_ge_64(s64 a_lo, s64 a_hi, s64 b_lo, s64 b_hi) { + s128 a = ((s128)a_hi << 64) | (u64)a_lo; + s128 b = ((s128)b_hi << 64) | (u64)b_lo; + if (a >= b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* SBC + MI: 128-bit signed sub result < 0 */ +NOINLINE int ccop_sbc_mi_64(s64 a_lo, s64 a_hi, s64 b_lo, s64 b_hi) { + s128 a = ((s128)a_hi << 64) | (u64)a_lo; + s128 b = ((s128)b_hi << 64) | (u64)b_lo; + s128 r = a - b; + if (r < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* -- Inline asm ADCS/SBCS for 32-bit width on AArch64 -- */ + +/* ADCS 32-bit with carry-in=1: test EQ */ +NOINLINE int ccop_adc_carry_eq_32(u32 a, u32 b) { + int cond; + asm volatile ( + "cmp wzr, wzr\n\t" /* sets C=1, Z=1 */ + "adcs %w[r], %w[a], %w[b]\n\t" + "cset %w[c], eq" + : [r] "=r"(cond), [c] "=r"(cond) + : [a] "r"(a), [b] "r"(b) + : "cc" + ); + g_sink = cond; + return g_sink; +} + +/* ADCS 64-bit with carry-in=1: test EQ */ +NOINLINE int ccop_adc_carry_eq_asm_64(u64 a, u64 b) { + int cond; + asm volatile ( + "cmp xzr, xzr\n\t" /* sets C=1 */ + "adcs %x[r], %x[a], %x[b]\n\t" + "cset %w[c], eq" + : [r] "=r"(cond), [c] "=r"(cond) + : [a] "r"(a), [b] "r"(b) + : "cc" + ); + g_sink = cond; + return g_sink; +} + +/* SBCS 32-bit with carry-in=1 (no borrow): test LO */ +NOINLINE int ccop_sbc_carry_lo_32(u32 a, u32 b) { + int cond; + asm volatile ( + "cmp wzr, wzr\n\t" /* sets C=1 */ + "sbcs %w[r], %w[a], %w[b]\n\t" + "cset %w[c], lo" + : [r] "=r"(cond), [c] "=r"(cond) + : [a] "r"(a), [b] "r"(b) + : "cc" + ); + g_sink = cond; + return g_sink; +} + +/* SBCS 64-bit with carry-in=1: test LO */ +NOINLINE int ccop_sbc_carry_lo_asm_64(u64 a, u64 b) { + int cond; + asm volatile ( + "cmp xzr, xzr\n\t" /* sets C=1 */ + "sbcs %x[r], %x[a], %x[b]\n\t" + "cset %w[c], lo" + : [r] "=r"(cond), [c] "=r"(cond) + : [a] "r"(a), [b] "r"(b) + : "cc" + ); + g_sink = cond; + return g_sink; +} + +/* ADCS 32-bit with carry-in=0: test VS (signed overflow) */ +NOINLINE int ccop_adc_nocarry_vs_32(s32 a, s32 b) { + int cond; + asm volatile ( + "msr nzcv, xzr\n\t" /* NZCV = 0000 (all clear, C=0) */ + "adcs %w[r], %w[a], %w[b]\n\t" + "cset %w[c], vs" + : [r] "=r"(cond), [c] "=r"(cond) + : [a] "r"(a), [b] "r"(b) + : "cc" + ); + g_sink = cond; + return g_sink; +} + +/* ADCS 64-bit with carry-in=0: test VS */ +NOINLINE int ccop_adc_nocarry_vs_64(s64 a, s64 b) { + int cond; + asm volatile ( + "msr nzcv, xzr\n\t" /* NZCV = 0000 (all clear, C=0) */ + "adcs %x[r], %x[a], %x[b]\n\t" + "cset %w[c], vs" + : [r] "=r"(cond), [c] "=r"(cond) + : [a] "r"(a), [b] "r"(b) + : "cc" + ); + g_sink = cond; + return g_sink; +} + +#endif /* __aarch64__ */ + +/* =================================================================== */ + +int main(void) { + g_sink = 0; + +#ifndef __aarch64__ + /* ARM32: 64-bit pair generates adds+adc / subs+sbc */ + + /* ADC conditions */ + ccop_adc_eq_32(0xFFFFFFFFFFFFFFFFULL, 1); + ccop_adc_ne_32(1, 2); + ccop_adc_mi_32(0x7FFFFFFFFFFFFFFFLL, 1); + ccop_adc_pl_32(1, 2); + ccop_adc_hs_32(0xFFFFFFFFFFFFFFFFULL, 1); + + /* SBC conditions */ + ccop_sbc_eq_32(5, 5); + ccop_sbc_ne_32(5, 3); + ccop_sbc_lo_32(1, 2); + ccop_sbc_hs_32(2, 1); + ccop_sbc_hi_32(2, 1); + ccop_sbc_ls_32(1, 1); + ccop_sbc_lt_32(-1, 1); + ccop_sbc_ge_32(1, -1); + ccop_sbc_gt_32(2, 1); + ccop_sbc_le_32(1, 2); + ccop_sbc_mi_32(0, 1); + + /* Inline asm with explicit carry */ + ccop_adc_carry_eq_32(0xFFFFFFFF, 0); + ccop_sbc_carry_lo_32(1, 5); + ccop_adc_nocarry_vs_32(0x7FFFFFFF, 1); + +#else + /* AArch64: __int128 generates adds+adc / subs+sbc */ + + /* ADC conditions */ + ccop_adc_eq_64(0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL, 1, 0); + ccop_adc_ne_64(1, 0, 2, 0); + ccop_adc_mi_64(0, 0x7FFFFFFFFFFFFFFFLL, 0, 1); + ccop_adc_pl_64(1, 0, 2, 0); + ccop_adc_hs_64(0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL, 1, 0); + + /* SBC conditions */ + ccop_sbc_eq_64(5, 0, 5, 0); + ccop_sbc_lo_64(1, 0, 2, 0); + ccop_sbc_hs_64(2, 0, 1, 0); + ccop_sbc_hi_64(2, 0, 1, 0); + ccop_sbc_ls_64(1, 0, 1, 0); + ccop_sbc_lt_64(0, -1, 0, 1); + ccop_sbc_ge_64(0, 1, 0, -1); + ccop_sbc_mi_64(0, 0, 0, 1); + + /* Inline asm with explicit carry -- 32-bit */ + ccop_adc_carry_eq_32(0xFFFFFFFF, 0); + ccop_sbc_carry_lo_32(1, 5); + ccop_adc_nocarry_vs_32(0x7FFFFFFF, 1); + + /* Inline asm with explicit carry -- 64-bit */ + ccop_adc_carry_eq_asm_64(0xFFFFFFFFFFFFFFFFULL, 0); + ccop_sbc_carry_lo_asm_64(1, 5); + ccop_adc_nocarry_vs_64(0x7FFFFFFFFFFFFFFFLL, 1); + +#endif + + return g_sink; +} diff --git a/tests_src/ccop_triggers/ccop_arm_add.c b/tests_src/ccop_triggers/ccop_arm_add.c new file mode 100644 index 00000000..c50a33b2 --- /dev/null +++ b/tests_src/ccop_triggers/ccop_arm_add.c @@ -0,0 +1,523 @@ +/* + * ccop_arm_add.c -- ADD condition code triggers for ARM32 and AArch64 + * + * The ADDS instruction sets NZCV flags from addition. + * VEX models this as: + * ARM32: ARMG_CC_OP_ADD (dep1 = argL, dep2 = argR) + * ARM64: ARM64G_CC_OP_ADD32 / ARM64G_CC_OP_ADD64 + * + * To get the compiler to emit ADDS (flag-setting add) followed by + * a conditional branch, we compute a sum and test its properties. + * For conditions that depend on the add flags directly (not just the + * result value), we need volatile or inline asm to prevent the + * compiler from optimizing into a CMP. + */ + +#include "ccop_common.h" + +volatile int g_sink; + +/* =================================================================== + * EQ (Z=1): (a + b) == 0 + * =================================================================== */ + +NOINLINE int ccop_add_eq_32(s32 a, s32 b) { + volatile s32 va = a, vb = b; + s32 r = va + vb; + if (r == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_add_eq_64(s64 a, s64 b) { + volatile s64 va = a, vb = b; + s64 r = va + vb; + if (r == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== + * NE (Z=0): (a + b) != 0 + * =================================================================== */ + +NOINLINE int ccop_add_ne_32(s32 a, s32 b) { + volatile s32 va = a, vb = b; + s32 r = va + vb; + if (r != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_add_ne_64(s64 a, s64 b) { + volatile s64 va = a, vb = b; + s64 r = va + vb; + if (r != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== + * MI (N=1): (a + b) < 0 (sign of sum) + * =================================================================== */ + +NOINLINE int ccop_add_mi_32(s32 a, s32 b) { + volatile s32 va = a, vb = b; + s32 r = va + vb; + if (r < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_add_mi_64(s64 a, s64 b) { + volatile s64 va = a, vb = b; + s64 r = va + vb; + if (r < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== + * PL (N=0): (a + b) >= 0 + * =================================================================== */ + +NOINLINE int ccop_add_pl_32(s32 a, s32 b) { + volatile s32 va = a, vb = b; + s32 r = va + vb; + if (r >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_add_pl_64(s64 a, s64 b) { + volatile s64 va = a, vb = b; + s64 r = va + vb; + if (r >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== + * VS (V=1): signed add overflow + * =================================================================== */ + +NOINLINE int ccop_add_vs_32(s32 a, s32 b) { + s32 r; + if (__builtin_add_overflow(a, b, &r)) + g_sink = 1; + else + g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_add_vs_64(s64 a, s64 b) { + s64 r; + if (__builtin_add_overflow(a, b, &r)) + g_sink = 1; + else + g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== + * VC (V=0): no signed add overflow + * =================================================================== */ + +NOINLINE int ccop_add_vc_32(s32 a, s32 b) { + s32 r; + if (!__builtin_add_overflow(a, b, &r)) + g_sink = 1; + else + g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_add_vc_64(s64 a, s64 b) { + s64 r; + if (!__builtin_add_overflow(a, b, &r)) + g_sink = 1; + else + g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== + * HS (C=1): unsigned add carry (a + b wraps, i.e. result < a) + * =================================================================== */ + +NOINLINE int ccop_add_hs_32(u32 a, u32 b) { + volatile u32 va = a, vb = b; + u32 r = va + vb; + if (r < va) g_sink = 1; else g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_add_hs_64(u64 a, u64 b) { + volatile u64 va = a, vb = b; + u64 r = va + vb; + if (r < va) g_sink = 1; else g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== + * LO (C=0): no unsigned add carry (result >= a) + * =================================================================== */ + +NOINLINE int ccop_add_lo_32(u32 a, u32 b) { + volatile u32 va = a, vb = b; + u32 r = va + vb; + if (r >= va) g_sink = 1; else g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_add_lo_64(u64 a, u64 b) { + volatile u64 va = a, vb = b; + u64 r = va + vb; + if (r >= va) g_sink = 1; else g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== + * GE (N=V): sum >= 0 in signed interpretation (after adds) + * + * Use inline asm to force ADDS + B.GE so the compiler cannot + * transform this into a CMP-based pattern. + * =================================================================== */ + +#ifndef __aarch64__ +NOINLINE int ccop_add_ge_32(s32 a, s32 b) { + int result; + asm volatile ( + "adds %[r], %[a], %[b]\n\t" + "ite ge\n\t" + "movge %[out], #1\n\t" + "movlt %[out], #0" + : [r] "=r"(result), [out] "=r"(result) + : [a] "r"(a), [b] "r"(b) + : "cc" + ); + g_sink = result; + return g_sink; +} +#else +NOINLINE int ccop_add_ge_32(s32 a, s32 b) { + int result; + asm volatile ( + "adds %w[r], %w[a], %w[b]\n\t" + "cset %w[out], ge" + : [r] "=r"(result), [out] "=r"(result) + : [a] "r"(a), [b] "r"(b) + : "cc" + ); + g_sink = result; + return g_sink; +} + +NOINLINE int ccop_add_ge_64(s64 a, s64 b) { + int result; + asm volatile ( + "adds %x[r], %x[a], %x[b]\n\t" + "cset %w[out], ge" + : [r] "=r"(result), [out] "=r"(result) + : [a] "r"(a), [b] "r"(b) + : "cc" + ); + g_sink = result; + return g_sink; +} +#endif + +/* =================================================================== + * LT (N!=V): sum < 0 in signed interpretation (after adds) + * =================================================================== */ + +#ifndef __aarch64__ +NOINLINE int ccop_add_lt_32(s32 a, s32 b) { + int result; + asm volatile ( + "adds %[r], %[a], %[b]\n\t" + "ite lt\n\t" + "movlt %[out], #1\n\t" + "movge %[out], #0" + : [r] "=r"(result), [out] "=r"(result) + : [a] "r"(a), [b] "r"(b) + : "cc" + ); + g_sink = result; + return g_sink; +} +#else +NOINLINE int ccop_add_lt_32(s32 a, s32 b) { + int result; + asm volatile ( + "adds %w[r], %w[a], %w[b]\n\t" + "cset %w[out], lt" + : [r] "=r"(result), [out] "=r"(result) + : [a] "r"(a), [b] "r"(b) + : "cc" + ); + g_sink = result; + return g_sink; +} + +NOINLINE int ccop_add_lt_64(s64 a, s64 b) { + int result; + asm volatile ( + "adds %x[r], %x[a], %x[b]\n\t" + "cset %w[out], lt" + : [r] "=r"(result), [out] "=r"(result) + : [a] "r"(a), [b] "r"(b) + : "cc" + ); + g_sink = result; + return g_sink; +} +#endif + +/* =================================================================== + * GT (Z=0 && N=V): sum > 0 (after adds) + * =================================================================== */ + +#ifndef __aarch64__ +NOINLINE int ccop_add_gt_32(s32 a, s32 b) { + int result; + asm volatile ( + "adds %[r], %[a], %[b]\n\t" + "ite gt\n\t" + "movgt %[out], #1\n\t" + "movle %[out], #0" + : [r] "=r"(result), [out] "=r"(result) + : [a] "r"(a), [b] "r"(b) + : "cc" + ); + g_sink = result; + return g_sink; +} +#else +NOINLINE int ccop_add_gt_32(s32 a, s32 b) { + int result; + asm volatile ( + "adds %w[r], %w[a], %w[b]\n\t" + "cset %w[out], gt" + : [r] "=r"(result), [out] "=r"(result) + : [a] "r"(a), [b] "r"(b) + : "cc" + ); + g_sink = result; + return g_sink; +} + +NOINLINE int ccop_add_gt_64(s64 a, s64 b) { + int result; + asm volatile ( + "adds %x[r], %x[a], %x[b]\n\t" + "cset %w[out], gt" + : [r] "=r"(result), [out] "=r"(result) + : [a] "r"(a), [b] "r"(b) + : "cc" + ); + g_sink = result; + return g_sink; +} +#endif + +/* =================================================================== + * LE (Z=1 || N!=V): sum <= 0 (after adds) + * =================================================================== */ + +#ifndef __aarch64__ +NOINLINE int ccop_add_le_32(s32 a, s32 b) { + int result; + asm volatile ( + "adds %[r], %[a], %[b]\n\t" + "ite le\n\t" + "movle %[out], #1\n\t" + "movgt %[out], #0" + : [r] "=r"(result), [out] "=r"(result) + : [a] "r"(a), [b] "r"(b) + : "cc" + ); + g_sink = result; + return g_sink; +} +#else +NOINLINE int ccop_add_le_32(s32 a, s32 b) { + int result; + asm volatile ( + "adds %w[r], %w[a], %w[b]\n\t" + "cset %w[out], le" + : [r] "=r"(result), [out] "=r"(result) + : [a] "r"(a), [b] "r"(b) + : "cc" + ); + g_sink = result; + return g_sink; +} + +NOINLINE int ccop_add_le_64(s64 a, s64 b) { + int result; + asm volatile ( + "adds %x[r], %x[a], %x[b]\n\t" + "cset %w[out], le" + : [r] "=r"(result), [out] "=r"(result) + : [a] "r"(a), [b] "r"(b) + : "cc" + ); + g_sink = result; + return g_sink; +} +#endif + +/* =================================================================== + * HI (C=1 && Z=0) after ADDS -- via inline asm + * =================================================================== */ + +#ifndef __aarch64__ +NOINLINE int ccop_add_hi_32(u32 a, u32 b) { + int result; + asm volatile ( + "adds %[r], %[a], %[b]\n\t" + "ite hi\n\t" + "movhi %[out], #1\n\t" + "movls %[out], #0" + : [r] "=r"(result), [out] "=r"(result) + : [a] "r"(a), [b] "r"(b) + : "cc" + ); + g_sink = result; + return g_sink; +} +#else +NOINLINE int ccop_add_hi_32(u32 a, u32 b) { + int result; + asm volatile ( + "adds %w[r], %w[a], %w[b]\n\t" + "cset %w[out], hi" + : [r] "=r"(result), [out] "=r"(result) + : [a] "r"(a), [b] "r"(b) + : "cc" + ); + g_sink = result; + return g_sink; +} + +NOINLINE int ccop_add_hi_64(u64 a, u64 b) { + int result; + asm volatile ( + "adds %x[r], %x[a], %x[b]\n\t" + "cset %w[out], hi" + : [r] "=r"(result), [out] "=r"(result) + : [a] "r"(a), [b] "r"(b) + : "cc" + ); + g_sink = result; + return g_sink; +} +#endif + +/* =================================================================== + * LS (C=0 || Z=1) after ADDS -- via inline asm + * =================================================================== */ + +#ifndef __aarch64__ +NOINLINE int ccop_add_ls_32(u32 a, u32 b) { + int result; + asm volatile ( + "adds %[r], %[a], %[b]\n\t" + "ite ls\n\t" + "movls %[out], #1\n\t" + "movhi %[out], #0" + : [r] "=r"(result), [out] "=r"(result) + : [a] "r"(a), [b] "r"(b) + : "cc" + ); + g_sink = result; + return g_sink; +} +#else +NOINLINE int ccop_add_ls_32(u32 a, u32 b) { + int result; + asm volatile ( + "adds %w[r], %w[a], %w[b]\n\t" + "cset %w[out], ls" + : [r] "=r"(result), [out] "=r"(result) + : [a] "r"(a), [b] "r"(b) + : "cc" + ); + g_sink = result; + return g_sink; +} + +NOINLINE int ccop_add_ls_64(u64 a, u64 b) { + int result; + asm volatile ( + "adds %x[r], %x[a], %x[b]\n\t" + "cset %w[out], ls" + : [r] "=r"(result), [out] "=r"(result) + : [a] "r"(a), [b] "r"(b) + : "cc" + ); + g_sink = result; + return g_sink; +} +#endif + +/* =================================================================== */ + +int main(void) { + g_sink = 0; + + /* EQ / NE */ + ccop_add_eq_32(1, -1); + ccop_add_ne_32(1, 2); + + /* MI / PL (sign of sum) */ + ccop_add_mi_32(1, -5); + ccop_add_pl_32(1, 2); + + /* VS / VC (signed overflow) */ + ccop_add_vs_32(0x7FFFFFFF, 1); + ccop_add_vc_32(1, 2); + + /* HS / LO (unsigned carry) */ + ccop_add_hs_32(0xFFFFFFFFU, 1); + ccop_add_lo_32(1, 2); + + /* GE / LT / GT / LE (after adds, via asm) */ + ccop_add_ge_32(1, 2); + ccop_add_lt_32(-5, 1); + ccop_add_gt_32(5, 1); + ccop_add_le_32(-5, 1); + + /* HI / LS (after adds, via asm) */ + ccop_add_hi_32(0x80000000U, 0x80000000U); + ccop_add_ls_32(1, 2); + +#ifdef __aarch64__ + /* 64-bit variants */ + ccop_add_eq_64(1, -1); + ccop_add_ne_64(1, 2); + ccop_add_mi_64(1, -5); + ccop_add_pl_64(1, 2); + ccop_add_vs_64(0x7FFFFFFFFFFFFFFFLL, 1); + ccop_add_vc_64(1, 2); + ccop_add_hs_64(0xFFFFFFFFFFFFFFFFULL, 1); + ccop_add_lo_64(1, 2); + ccop_add_ge_64(1, 2); + ccop_add_lt_64(-5, 1); + ccop_add_gt_64(5, 1); + ccop_add_le_64(-5, 1); + ccop_add_hi_64(0x8000000000000000ULL, 0x8000000000000000ULL); + ccop_add_ls_64(1, 2); +#endif + + return g_sink; +} diff --git a/tests_src/ccop_triggers/ccop_arm_logic.c b/tests_src/ccop_triggers/ccop_arm_logic.c new file mode 100644 index 00000000..7d6d0dac --- /dev/null +++ b/tests_src/ccop_triggers/ccop_arm_logic.c @@ -0,0 +1,391 @@ +/* + * ccop_arm_logic.c -- LOGIC (AND/ORR/EOR/TST/TEQ) condition code triggers + * for ARM32 and AArch64 + * + * VEX models flag-setting from bitwise operations as: + * ARM32: ARMG_CC_OP_LOGIC (dep1 = result, dep2 = shifter_carry_out) + * ARM64: ARM64G_CC_OP_LOGIC32 / ARM64G_CC_OP_LOGIC64 + * + * The TST instruction (ANDS with result discarded) is the most common + * trigger. For ARM LOGIC: + * N = sign bit of result + * Z = (result == 0) + * C = shifter carry out (dep2) -- ARM32 specific + * V = 0 (always cleared) + * + * Because V=0 for LOGIC: + * GE (N=V) is equivalent to PL (N=0) + * LT (N!=V) is equivalent to MI (N=1) + * GT (Z=0 && N=V) is equivalent to (result > 0, signed) + * LE (Z=1 || N!=V) is equivalent to (result <= 0, signed) + * VS is always false, VC is always true + * + * For HS/LO on ARM32, they depend on the shifter carry out (dep2), + * which is ARM-architecture-specific. We use inline asm for those. + */ + +#include "ccop_common.h" + +volatile int g_sink; + +/* =================================================================== + * EQ (Z=1): (a & b) == 0 -- TST a, b + * =================================================================== */ + +NOINLINE int ccop_logic_eq_32(u32 a, u32 b) { + volatile u32 va = a, vb = b; + if ((va & vb) == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_logic_eq_64(u64 a, u64 b) { + volatile u64 va = a, vb = b; + if ((va & vb) == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== + * NE (Z=0): (a & b) != 0 or test reg,reg (if (a)) + * =================================================================== */ + +NOINLINE int ccop_logic_ne_32(u32 a, u32 b) { + volatile u32 va = a, vb = b; + if ((va & vb) != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* Single-operand variant: test reg,reg -- "if (a)" */ +NOINLINE int ccop_logic_ne_self_32(s32 a) { + if (a) g_sink = 1; else g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_logic_ne_64(u64 a, u64 b) { + volatile u64 va = a, vb = b; + if ((va & vb) != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_logic_ne_self_64(s64 a) { + if (a) g_sink = 1; else g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== + * MI (N=1): sign bit of (a & b) is set, or sign of single value + * =================================================================== */ + +NOINLINE int ccop_logic_mi_32(s32 a) { + /* "tst a, a; bmi" or "cmp a, #0; blt" -- compiler picks */ + if (a < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_logic_mi_64(s64 a) { + if (a < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== + * PL (N=0): sign bit clear + * =================================================================== */ + +NOINLINE int ccop_logic_pl_32(s32 a) { + if (a >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_logic_pl_64(s64 a) { + if (a >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== + * GE (N=V): since V=0 for LOGIC, this is N=0, same as PL + * We include it as a distinct function because the VEX condition + * code is different (CondGE vs CondPL), even though the semantic + * result is the same for LOGIC. + * =================================================================== */ + +NOINLINE int ccop_logic_ge_32(s32 a) { + volatile s32 va = a; + volatile s32 zero = 0; + if (va >= zero) g_sink = 1; else g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_logic_ge_64(s64 a) { + volatile s64 va = a; + volatile s64 zero = 0; + if (va >= zero) g_sink = 1; else g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== + * LT (N!=V): since V=0 for LOGIC, this is N=1, same as MI + * =================================================================== */ + +NOINLINE int ccop_logic_lt_32(s32 a) { + volatile s32 va = a; + volatile s32 zero = 0; + if (va < zero) g_sink = 1; else g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_logic_lt_64(s64 a) { + volatile s64 va = a; + volatile s64 zero = 0; + if (va < zero) g_sink = 1; else g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== + * GT (Z=0 && N=V): since V=0 for LOGIC, this is (Z=0 && N=0) + * i.e. result > 0 (signed) + * =================================================================== */ + +NOINLINE int ccop_logic_gt_32(s32 a) { + volatile s32 va = a; + volatile s32 zero = 0; + if (va > zero) g_sink = 1; else g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_logic_gt_64(s64 a) { + volatile s64 va = a; + volatile s64 zero = 0; + if (va > zero) g_sink = 1; else g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== + * LE (Z=1 || N!=V): since V=0, this is (Z=1 || N=1) + * i.e. result <= 0 (signed) + * =================================================================== */ + +NOINLINE int ccop_logic_le_32(s32 a) { + volatile s32 va = a; + volatile s32 zero = 0; + if (va <= zero) g_sink = 1; else g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_logic_le_64(s64 a) { + volatile s64 va = a; + volatile s64 zero = 0; + if (va <= zero) g_sink = 1; else g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== + * AND with two operands -- TST mask pattern + * These ensure the compiler emits TST (ANDS) rather than CMP. + * =================================================================== */ + +NOINLINE int ccop_logic_and_eq_32(u32 val, u32 mask) { + if ((val & mask) == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_logic_and_ne_32(u32 val, u32 mask) { + if ((val & mask) != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_logic_and_mi_32(s32 val, s32 mask) { + volatile s32 r = val & mask; + if (r < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_logic_and_eq_64(u64 val, u64 mask) { + if ((val & mask) == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_logic_and_ne_64(u64 val, u64 mask) { + if ((val & mask) != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_logic_and_mi_64(s64 val, s64 mask) { + volatile s64 r = val & mask; + if (r < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== + * ORR result tests -- compiler may emit ORRS or ORR+TST + * =================================================================== */ + +NOINLINE int ccop_logic_orr_eq_32(u32 a, u32 b) { + volatile u32 r = a | b; + if (r == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_logic_orr_ne_32(u32 a, u32 b) { + volatile u32 r = a | b; + if (r != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_logic_orr_eq_64(u64 a, u64 b) { + volatile u64 r = a | b; + if (r == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== + * EOR (XOR) result tests + * =================================================================== */ + +NOINLINE int ccop_logic_eor_eq_32(u32 a, u32 b) { + volatile u32 r = a ^ b; + if (r == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_logic_eor_ne_32(u32 a, u32 b) { + volatile u32 r = a ^ b; + if (r != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_logic_eor_eq_64(u64 a, u64 b) { + volatile u64 r = a ^ b; + if (r == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== + * ARM32-only: HS/LO with shifter carry out + * + * On ARM32, the LOGIC C flag comes from the barrel shifter carry out. + * A shifted operand in TST/AND can produce a non-zero C flag. + * This is unique to ARM32 (dep2 = shifter_carry_out). + * + * We use inline asm to force TST with a shifted operand so the + * carry out is meaningful. + * =================================================================== */ + +#ifndef __aarch64__ +/* TST with LSL -- carry out is the last bit shifted out */ +NOINLINE int ccop_logic_shift_hs_32(u32 a, u32 b) { + int result; + /* + * "tst a, b, lsl #1" -- the barrel shifter produces a carry out + * from bit 31 of b. Then BHS checks C=1. + */ + asm volatile ( + "tst %[a], %[b], lsl #1\n\t" + "ite cs\n\t" + "movcs %[out], #1\n\t" + "movcc %[out], #0" + : [out] "=r"(result) + : [a] "r"(a), [b] "r"(b) + : "cc" + ); + g_sink = result; + return g_sink; +} + +NOINLINE int ccop_logic_shift_lo_32(u32 a, u32 b) { + int result; + asm volatile ( + "tst %[a], %[b], lsl #1\n\t" + "ite cc\n\t" + "movcc %[out], #1\n\t" + "movcs %[out], #0" + : [out] "=r"(result) + : [a] "r"(a), [b] "r"(b) + : "cc" + ); + g_sink = result; + return g_sink; +} +#endif + +/* =================================================================== */ + +int main(void) { + g_sink = 0; + + /* EQ / NE with two-operand AND */ + ccop_logic_eq_32(0xAA, 0x55); + ccop_logic_ne_32(0xFF, 0x01); + ccop_logic_ne_self_32(42); + + /* MI / PL (sign bit) */ + ccop_logic_mi_32(-1); + ccop_logic_pl_32(1); + + /* GE / LT (N=V, V=0 for logic) */ + ccop_logic_ge_32(5); + ccop_logic_lt_32(-5); + + /* GT / LE */ + ccop_logic_gt_32(5); + ccop_logic_le_32(-1); + + /* AND mask patterns */ + ccop_logic_and_eq_32(0xF0, 0x0F); + ccop_logic_and_ne_32(0xFF, 0x0F); + ccop_logic_and_mi_32(-1, -1); + + /* ORR patterns */ + ccop_logic_orr_eq_32(0, 0); + ccop_logic_orr_ne_32(0, 1); + + /* EOR patterns */ + ccop_logic_eor_eq_32(42, 42); + ccop_logic_eor_ne_32(42, 0); + +#ifndef __aarch64__ + /* ARM32 shifter carry out */ + ccop_logic_shift_hs_32(0xFFFFFFFF, 0x80000000); + ccop_logic_shift_lo_32(0xFFFFFFFF, 0x7FFFFFFF); +#endif + +#ifdef __aarch64__ + /* 64-bit variants */ + ccop_logic_eq_64(0xAA, 0x55); + ccop_logic_ne_64(0xFF, 0x01); + ccop_logic_ne_self_64(42); + ccop_logic_mi_64(-1); + ccop_logic_pl_64(1); + ccop_logic_ge_64(5); + ccop_logic_lt_64(-5); + ccop_logic_gt_64(5); + ccop_logic_le_64(-1); + ccop_logic_and_eq_64(0xF0, 0x0F); + ccop_logic_and_ne_64(0xFF, 0x0F); + ccop_logic_and_mi_64(-1, -1); + ccop_logic_orr_eq_64(0, 0); + ccop_logic_eor_eq_64(42, 42); +#endif + + return g_sink; +} diff --git a/tests_src/ccop_triggers/ccop_arm_sub.c b/tests_src/ccop_triggers/ccop_arm_sub.c new file mode 100644 index 00000000..86d28ab6 --- /dev/null +++ b/tests_src/ccop_triggers/ccop_arm_sub.c @@ -0,0 +1,318 @@ +/* + * ccop_arm_sub.c -- SUB/CMP condition code triggers for ARM32 and AArch64 + * + * The ARM CMP instruction is SUB that discards the result, setting NZCV. + * VEX models this as: + * ARM32: ARMG_CC_OP_SUB (dep1 = argL, dep2 = argR) + * ARM64: ARM64G_CC_OP_SUB32 / ARM64G_CC_OP_SUB64 + * + * Each function triggers a specific ARM condition after a CMP/SUB. + * ARM condition naming: EQ, NE, HS(CS), LO(CC), MI, PL, VS, VC, + * HI, LS, GE, LT, GT, LE + */ + +#include "ccop_common.h" + +volatile int g_sink; + +/* =================================================================== + * EQ (Z=1): a == b + * =================================================================== */ + +NOINLINE int ccop_sub_eq_32(s32 a, s32 b) { + if (a == b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_sub_eq_64(s64 a, s64 b) { + if (a == b) g_sink = 1; else g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== + * NE (Z=0): a != b + * =================================================================== */ + +NOINLINE int ccop_sub_ne_32(s32 a, s32 b) { + if (a != b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_sub_ne_64(s64 a, s64 b) { + if (a != b) g_sink = 1; else g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== + * HS / CS (C=1): unsigned a >= b + * =================================================================== */ + +NOINLINE int ccop_sub_hs_32(u32 a, u32 b) { + if (a >= b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_sub_hs_64(u64 a, u64 b) { + if (a >= b) g_sink = 1; else g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== + * LO / CC (C=0): unsigned a < b + * =================================================================== */ + +NOINLINE int ccop_sub_lo_32(u32 a, u32 b) { + if (a < b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_sub_lo_64(u64 a, u64 b) { + if (a < b) g_sink = 1; else g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== + * MI (N=1): sign of (a - b), i.e. result negative + * =================================================================== */ + +NOINLINE int ccop_sub_mi_32(s32 a, s32 b) { + volatile s32 va = a, vb = b; + s32 r = va - vb; + if (r < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_sub_mi_64(s64 a, s64 b) { + volatile s64 va = a, vb = b; + s64 r = va - vb; + if (r < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== + * PL (N=0): result non-negative + * =================================================================== */ + +NOINLINE int ccop_sub_pl_32(s32 a, s32 b) { + volatile s32 va = a, vb = b; + s32 r = va - vb; + if (r >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_sub_pl_64(s64 a, s64 b) { + volatile s64 va = a, vb = b; + s64 r = va - vb; + if (r >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== + * VS (V=1): signed overflow from subtraction + * =================================================================== */ + +NOINLINE int ccop_sub_vs_32(s32 a, s32 b) { + s32 r; + if (__builtin_sub_overflow(a, b, &r)) + g_sink = 1; + else + g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_sub_vs_64(s64 a, s64 b) { + s64 r; + if (__builtin_sub_overflow(a, b, &r)) + g_sink = 1; + else + g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== + * VC (V=0): no signed overflow from subtraction + * =================================================================== */ + +NOINLINE int ccop_sub_vc_32(s32 a, s32 b) { + s32 r; + if (!__builtin_sub_overflow(a, b, &r)) + g_sink = 1; + else + g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_sub_vc_64(s64 a, s64 b) { + s64 r; + if (!__builtin_sub_overflow(a, b, &r)) + g_sink = 1; + else + g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== + * HI (C=1 && Z=0): unsigned a > b + * =================================================================== */ + +NOINLINE int ccop_sub_hi_32(u32 a, u32 b) { + if (a > b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_sub_hi_64(u64 a, u64 b) { + if (a > b) g_sink = 1; else g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== + * LS (C=0 || Z=1): unsigned a <= b + * =================================================================== */ + +NOINLINE int ccop_sub_ls_32(u32 a, u32 b) { + if (a <= b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_sub_ls_64(u64 a, u64 b) { + if (a <= b) g_sink = 1; else g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== + * GE (N=V): signed a >= b + * =================================================================== */ + +NOINLINE int ccop_sub_ge_32(s32 a, s32 b) { + if (a >= b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_sub_ge_64(s64 a, s64 b) { + if (a >= b) g_sink = 1; else g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== + * LT (N!=V): signed a < b + * =================================================================== */ + +NOINLINE int ccop_sub_lt_32(s32 a, s32 b) { + if (a < b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_sub_lt_64(s64 a, s64 b) { + if (a < b) g_sink = 1; else g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== + * GT (Z=0 && N=V): signed a > b + * =================================================================== */ + +NOINLINE int ccop_sub_gt_32(s32 a, s32 b) { + if (a > b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_sub_gt_64(s64 a, s64 b) { + if (a > b) g_sink = 1; else g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== + * LE (Z=1 || N!=V): signed a <= b + * =================================================================== */ + +NOINLINE int ccop_sub_le_32(s32 a, s32 b) { + if (a <= b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +#ifdef __aarch64__ +NOINLINE int ccop_sub_le_64(s64 a, s64 b) { + if (a <= b) g_sink = 1; else g_sink = 0; + return g_sink; +} +#endif + +/* =================================================================== */ + +int main(void) { + g_sink = 0; + + /* EQ / NE */ + ccop_sub_eq_32(3, 3); + ccop_sub_ne_32(3, 5); + + /* HS / LO (unsigned) */ + ccop_sub_hs_32(5, 3); + ccop_sub_lo_32(3, 5); + + /* MI / PL (sign) */ + ccop_sub_mi_32(1, 5); + ccop_sub_pl_32(5, 1); + + /* VS / VC (overflow) */ + ccop_sub_vs_32(0x7FFFFFFF, -1); + ccop_sub_vc_32(5, 3); + + /* HI / LS (unsigned) */ + ccop_sub_hi_32(5, 3); + ccop_sub_ls_32(3, 5); + + /* GE / LT (signed) */ + ccop_sub_ge_32(5, 3); + ccop_sub_lt_32(-1, 1); + + /* GT / LE (signed) */ + ccop_sub_gt_32(5, 3); + ccop_sub_le_32(3, 5); + +#ifdef __aarch64__ + /* 64-bit variants */ + ccop_sub_eq_64(3, 3); + ccop_sub_ne_64(3, 5); + ccop_sub_hs_64(5, 3); + ccop_sub_lo_64(3, 5); + ccop_sub_mi_64(1, 5); + ccop_sub_pl_64(5, 1); + ccop_sub_vs_64(0x7FFFFFFFFFFFFFFFLL, -1); + ccop_sub_vc_64(5, 3); + ccop_sub_hi_64(5, 3); + ccop_sub_ls_64(3, 5); + ccop_sub_ge_64(5, 3); + ccop_sub_lt_64(-1, 1); + ccop_sub_gt_64(5, 3); + ccop_sub_le_64(3, 5); +#endif + + return g_sink; +} diff --git a/tests_src/ccop_triggers/ccop_common.h b/tests_src/ccop_triggers/ccop_common.h new file mode 100644 index 00000000..f3f83e7c --- /dev/null +++ b/tests_src/ccop_triggers/ccop_common.h @@ -0,0 +1,20 @@ +#ifndef CCOP_COMMON_H +#define CCOP_COMMON_H + +#include + +#define NOINLINE __attribute__((noinline)) + +/* Declared in each .c file to prevent dead-code elimination */ +extern volatile int g_sink; + +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +#endif /* CCOP_COMMON_H */ diff --git a/tests_src/ccop_triggers/ccop_copy.c b/tests_src/ccop_triggers/ccop_copy.c new file mode 100644 index 00000000..d0025354 --- /dev/null +++ b/tests_src/ccop_triggers/ccop_copy.c @@ -0,0 +1,87 @@ +/* + * ccop_copy.c — COPY condition code triggers + * + * VEX models pushf/popf (flag save/restore) as CC_OP_COPY. + * Strategy: CMP sets flags -> pushf saves -> trash flags -> popf restores + * -> branch on restored flags exercises CC_OP_COPY + condition. + */ + +#include "ccop_common.h" + +volatile int g_sink; + +#ifdef __x86_64__ + +/* COPY + CondZ (amd64): cmp sets ZF, pushfq/popfq preserves it */ +NOINLINE int ccop_copy_condz_64(s64 a, s64 b) { + asm goto ( + "cmpq %[b], %[a]\n\t" + "pushfq\n\t" + "testq $1, %[a]\n\t" + "popfq\n\t" + "je %l[taken]" + : : [a] "r"(a), [b] "r"(b) : "cc", "memory" : taken + ); + g_sink = 0; return g_sink; +taken: g_sink = 1; return g_sink; +} + +/* COPY + CondNZ (amd64) */ +NOINLINE int ccop_copy_condnz_64(s64 a, s64 b) { + asm goto ( + "cmpq %[b], %[a]\n\t" + "pushfq\n\t" + "testq $1, %[a]\n\t" + "popfq\n\t" + "jne %l[taken]" + : : [a] "r"(a), [b] "r"(b) : "cc", "memory" : taken + ); + g_sink = 0; return g_sink; +taken: g_sink = 1; return g_sink; +} + +#else /* i386 */ + +/* COPY + CondZ (i386): cmpl + pushfl/popfl */ +NOINLINE int ccop_copy_condz_32(s32 a, s32 b) { + asm goto ( + "cmpl %[b], %[a]\n\t" + "pushfl\n\t" + "testl $1, %[a]\n\t" + "popfl\n\t" + "je %l[taken]" + : : [a] "r"(a), [b] "r"(b) : "cc", "memory" : taken + ); + g_sink = 0; return g_sink; +taken: g_sink = 1; return g_sink; +} + +/* COPY + CondNZ (i386) */ +NOINLINE int ccop_copy_condnz_32(s32 a, s32 b) { + asm goto ( + "cmpl %[b], %[a]\n\t" + "pushfl\n\t" + "testl $1, %[a]\n\t" + "popfl\n\t" + "jne %l[taken]" + : : [a] "r"(a), [b] "r"(b) : "cc", "memory" : taken + ); + g_sink = 0; return g_sink; +taken: g_sink = 1; return g_sink; +} + +#endif + +int main(void) { + g_sink = 0; + +#ifdef __x86_64__ + ccop_copy_condz_64(5, 5); + ccop_copy_condnz_64(5, 3); +#else + ccop_copy_condz_32(5, 5); + ccop_copy_condnz_32(5, 3); +#endif + + return g_sink; +} diff --git a/tests_src/ccop_triggers/ccop_inc_dec.c b/tests_src/ccop_triggers/ccop_inc_dec.c new file mode 100644 index 00000000..24920828 --- /dev/null +++ b/tests_src/ccop_triggers/ccop_inc_dec.c @@ -0,0 +1,477 @@ +/* + * ccop_inc_dec.c — INC/DEC condition code triggers (pure C + asm goto) + * + * Modern GCC with -mtune=generic prefers "add $1"/"sub $1" over inc/dec + * because of partial-flag stalls on older microarchitectures. To get real + * INC/DEC instructions, compile with: + * -mtune-ctrl=use_incdec (explicit GCC tuning override) + * -mtune=haswell (Haswell+ re-enables inc/dec) + * + * VEX models these as CC_OP_INCx / CC_OP_DECx (distinct from ADD/SUB + * because INC/DEC preserve CF via NDEP). + * + * We use volatile locals to prevent the compiler from folding the +1/-1 + * into the comparison (e.g. turning "a+1 == 0" into "a == -1" which + * would emit CMP instead of INC). + */ + +#include "ccop_common.h" + +volatile int g_sink; + +/* ═══════════════════════════════════════════════════════════════════ + * INC — triggered by (var + 1) or var++ with inc/dec tuning enabled + * + * Using volatile forces the compiler to actually perform the increment + * in a register and then test the result, rather than constant-folding. + * ═══════════════════════════════════════════════════════════════════ */ + +/* ── INC + CondZ ──────────────────────────────────────────────────── */ + +NOINLINE int ccop_inc_condz_8(s8 a) { + volatile s8 v = a; + v++; + if (v == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_inc_condz_16(s16 a) { + volatile s16 v = a; + v++; + if (v == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_inc_condz_32(s32 a) { + volatile s32 v = a; + v++; + if (v == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_inc_condz_64(s64 a) { + volatile s64 v = a; + v++; + if (v == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── INC + CondNZ ─────────────────────────────────────────────────── */ + +NOINLINE int ccop_inc_condnz_8(s8 a) { + volatile s8 v = a; + v++; + if (v != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_inc_condnz_16(s16 a) { + volatile s16 v = a; + v++; + if (v != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_inc_condnz_32(s32 a) { + volatile s32 v = a; + v++; + if (v != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_inc_condnz_64(s64 a) { + volatile s64 v = a; + v++; + if (v != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── INC + CondS ──────────────────────────────────────────────────── */ + +NOINLINE int ccop_inc_conds_8(s8 a) { + volatile s8 v = a; + v++; + if (v < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_inc_conds_16(s16 a) { + volatile s16 v = a; + v++; + if (v < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_inc_conds_32(s32 a) { + volatile s32 v = a; + v++; + if (v < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_inc_conds_64(s64 a) { + volatile s64 v = a; + v++; + if (v < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── INC + CondNS ─────────────────────────────────────────────────── */ + +NOINLINE int ccop_inc_condns_8(s8 a) { + volatile s8 v = a; + v++; + if (v >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_inc_condns_16(s16 a) { + volatile s16 v = a; + v++; + if (v >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_inc_condns_32(s32 a) { + volatile s32 v = a; + v++; + if (v >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_inc_condns_64(s64 a) { + volatile s64 v = a; + v++; + if (v >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── INC + CondLE ─────────────────────────────────────────────────── */ + +NOINLINE int ccop_inc_condle_32(s32 a) { + volatile s32 v = a; + v++; + if (v <= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── INC + CondNLE ────────────────────────────────────────────────── */ + +NOINLINE int ccop_inc_condnle_32(s32 a) { + volatile s32 v = a; + v++; + if (v > 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── INC + CondO (asm goto — x86 rewriter only) ──────────────────── */ + +NOINLINE int ccop_inc_condo_8(s8 a) { + s8 tmp = a; + asm goto ("incb %0\n\t" "jo %l[taken]" : "+q"(tmp) : : "cc" : taken); + g_sink = 0; return g_sink; +taken: g_sink = 1; return g_sink; +} + +NOINLINE int ccop_inc_condo_16(s16 a) { + s16 tmp = a; + asm goto ("incw %0\n\t" "jo %l[taken]" : "+r"(tmp) : : "cc" : taken); + g_sink = 0; return g_sink; +taken: g_sink = 1; return g_sink; +} + +NOINLINE int ccop_inc_condo_32(s32 a) { + s32 tmp = a; + asm goto ("incl %0\n\t" "jo %l[taken]" : "+r"(tmp) : : "cc" : taken); + g_sink = 0; return g_sink; +taken: g_sink = 1; return g_sink; +} + +/* ── INC + CondNO (asm goto — x86 rewriter only) ─────────────────── */ + +NOINLINE int ccop_inc_condno_8(s8 a) { + s8 tmp = a; + asm goto ("incb %0\n\t" "jno %l[taken]" : "+q"(tmp) : : "cc" : taken); + g_sink = 0; return g_sink; +taken: g_sink = 1; return g_sink; +} + +NOINLINE int ccop_inc_condno_16(s16 a) { + s16 tmp = a; + asm goto ("incw %0\n\t" "jno %l[taken]" : "+r"(tmp) : : "cc" : taken); + g_sink = 0; return g_sink; +taken: g_sink = 1; return g_sink; +} + +NOINLINE int ccop_inc_condno_32(s32 a) { + s32 tmp = a; + asm goto ("incl %0\n\t" "jno %l[taken]" : "+r"(tmp) : : "cc" : taken); + g_sink = 0; return g_sink; +taken: g_sink = 1; return g_sink; +} + +/* ═══════════════════════════════════════════════════════════════════ + * DEC — triggered by (var - 1) or var-- with inc/dec tuning enabled + * ═══════════════════════════════════════════════════════════════════ */ + +/* ── DEC + CondZ ──────────────────────────────────────────────────── */ + +NOINLINE int ccop_dec_condz_8(s8 a) { + volatile s8 v = a; + v--; + if (v == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_dec_condz_16(s16 a) { + volatile s16 v = a; + v--; + if (v == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_dec_condz_32(s32 a) { + volatile s32 v = a; + v--; + if (v == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_dec_condz_64(s64 a) { + volatile s64 v = a; + v--; + if (v == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── DEC + CondNZ ─────────────────────────────────────────────────── */ + +NOINLINE int ccop_dec_condnz_8(s8 a) { + volatile s8 v = a; + v--; + if (v != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_dec_condnz_16(s16 a) { + volatile s16 v = a; + v--; + if (v != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_dec_condnz_32(s32 a) { + volatile s32 v = a; + v--; + if (v != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_dec_condnz_64(s64 a) { + volatile s64 v = a; + v--; + if (v != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── DEC + CondS ──────────────────────────────────────────────────── */ + +NOINLINE int ccop_dec_conds_8(s8 a) { + volatile s8 v = a; + v--; + if (v < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_dec_conds_16(s16 a) { + volatile s16 v = a; + v--; + if (v < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_dec_conds_32(s32 a) { + volatile s32 v = a; + v--; + if (v < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_dec_conds_64(s64 a) { + volatile s64 v = a; + v--; + if (v < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── DEC + CondNS ─────────────────────────────────────────────────── */ + +NOINLINE int ccop_dec_condns_8(s8 a) { + volatile s8 v = a; + v--; + if (v >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_dec_condns_16(s16 a) { + volatile s16 v = a; + v--; + if (v >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_dec_condns_32(s32 a) { + volatile s32 v = a; + v--; + if (v >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_dec_condns_64(s64 a) { + volatile s64 v = a; + v--; + if (v >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── DEC + CondLE ─────────────────────────────────────────────────── */ + +NOINLINE int ccop_dec_condle_8(s8 a) { + volatile s8 v = a; + v--; + if (v <= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_dec_condle_16(s16 a) { + volatile s16 v = a; + v--; + if (v <= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_dec_condle_32(s32 a) { + volatile s32 v = a; + v--; + if (v <= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_dec_condle_64(s64 a) { + volatile s64 v = a; + v--; + if (v <= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── DEC + CondNLE ────────────────────────────────────────────────── */ + +NOINLINE int ccop_dec_condnle_8(s8 a) { + volatile s8 v = a; + v--; + if (v > 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_dec_condnle_16(s16 a) { + volatile s16 v = a; + v--; + if (v > 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_dec_condnle_32(s32 a) { + volatile s32 v = a; + v--; + if (v > 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_dec_condnle_64(s64 a) { + volatile s64 v = a; + v--; + if (v > 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +int main(void) { + g_sink = 0; + + /* INC + CondZ */ + ccop_inc_condz_8(-1); + ccop_inc_condz_16(-1); + ccop_inc_condz_32(-1); + ccop_inc_condz_64(-1); + + /* INC + CondNZ */ + ccop_inc_condnz_8(5); + ccop_inc_condnz_16(5); + ccop_inc_condnz_32(5); + ccop_inc_condnz_64(5); + + /* INC + CondS */ + ccop_inc_conds_8(127); + ccop_inc_conds_16(0x7FFF); + ccop_inc_conds_32(0x7FFFFFFF); + ccop_inc_conds_64(0x7FFFFFFFFFFFFFFFLL); + + /* INC + CondNS */ + ccop_inc_condns_8(0); + ccop_inc_condns_16(0); + ccop_inc_condns_32(0); + ccop_inc_condns_64(0); + + /* INC + CondLE */ + ccop_inc_condle_32(-2); + + /* INC + CondNLE */ + ccop_inc_condnle_32(5); + + /* INC + CondO (asm goto) */ + ccop_inc_condo_8(127); + ccop_inc_condo_16(0x7FFF); + ccop_inc_condo_32(0x7FFFFFFF); + + /* INC + CondNO (asm goto) */ + ccop_inc_condno_8(0); + ccop_inc_condno_16(0); + ccop_inc_condno_32(0); + + /* DEC + CondZ */ + ccop_dec_condz_8(1); + ccop_dec_condz_16(1); + ccop_dec_condz_32(1); + ccop_dec_condz_64(1); + + /* DEC + CondNZ */ + ccop_dec_condnz_8(5); + ccop_dec_condnz_16(5); + ccop_dec_condnz_32(5); + ccop_dec_condnz_64(5); + + /* DEC + CondS */ + ccop_dec_conds_8(0); + ccop_dec_conds_16(0); + ccop_dec_conds_32(0); + ccop_dec_conds_64(0); + + /* DEC + CondNS */ + ccop_dec_condns_8(1); + ccop_dec_condns_16(1); + ccop_dec_condns_32(1); + ccop_dec_condns_64(1); + + /* DEC + CondLE */ + ccop_dec_condle_8(1); + ccop_dec_condle_16(1); + ccop_dec_condle_32(1); + ccop_dec_condle_64(1); + + /* DEC + CondNLE */ + ccop_dec_condnle_8(5); + ccop_dec_condnle_16(5); + ccop_dec_condnle_32(5); + ccop_dec_condnle_64(5); + + return g_sink; +} diff --git a/tests_src/ccop_triggers/ccop_logic.c b/tests_src/ccop_triggers/ccop_logic.c new file mode 100644 index 00000000..e85f31b5 --- /dev/null +++ b/tests_src/ccop_triggers/ccop_logic.c @@ -0,0 +1,432 @@ +/* + * ccop_logic.c — LOGIC (AND/OR/XOR/TEST) condition code triggers + * + * VEX models flag-setting from bitwise operations as CC_OP_LOGICx. + * The TEST instruction (AND without storing result) is the most common + * trigger. SF and ZF are meaningful; OF and CF are always 0. + */ + +#include "ccop_common.h" + +volatile int g_sink; + +/* ═══════════════════════════════════════════════════════════════════════ + * CondZ: (a & b) == 0 + * ═══════════════════════════════════════════════════════════════════════ */ + +/* ── CondZ 8 ──────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condz_8(u8 a, u8 b) { + volatile u8 va = a, vb = b; + if ((va & vb) == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondZ 16 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condz_16(u16 a, u16 b) { + volatile u16 va = a, vb = b; + if ((va & vb) == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondZ 32 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condz_32(u32 a, u32 b) { + if ((a & b) == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondZ 64 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condz_64(u64 a, u64 b) { + if ((a & b) == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ═══════════════════════════════════════════════════════════════════════ + * CondNZ: test reg,reg (if (a)) + * ═══════════════════════════════════════════════════════════════════════ */ + +/* ── CondNZ 8 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condnz_8(s8 a) { + volatile s8 va = a; + if (va) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondNZ 16 ────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condnz_16(s16 a) { + volatile s16 va = a; + if (va) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondNZ 32 ────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condnz_32(s32 a) { + /* "test eax, eax; jnz" — LOGIC + CondNZ */ + if (a) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondNZ 64 ────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condnz_64(s64 a) { + if (a) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ═══════════════════════════════════════════════════════════════════════ + * CondS: sign flag via test (a < 0) + * ═══════════════════════════════════════════════════════════════════════ */ + +/* ── CondS 8 ──────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_conds_8(s8 a) { + volatile s8 va = a; + if (va < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondS 16 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_conds_16(s16 a) { + volatile s16 va = a; + if (va < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondS 32 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_conds_32(s32 a) { + /* "test eax, eax; js" — LOGIC + CondS */ + if (a < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondS 64 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_conds_64(s64 a) { + if (a < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ═══════════════════════════════════════════════════════════════════════ + * CondNS: not sign via test (a >= 0) + * ═══════════════════════════════════════════════════════════════════════ */ + +/* ── CondNS 8 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condns_8(s8 a) { + volatile s8 va = a; + if (va >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondNS 16 ────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condns_16(s16 a) { + volatile s16 va = a; + if (va >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondNS 32 ────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condns_32(s32 a) { + if (a >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondNS 64 ────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condns_64(s64 a) { + if (a >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* + * CondL/NL/LE/NLE + LOGIC: The rewriter handles these when dep_2 == 0. + * This happens with "test reg,reg" where the compiler uses signed + * comparison conditions on the result. + */ + +/* ═══════════════════════════════════════════════════════════════════════ + * CondL: a < 0 (test reg,reg + jl) + * ═══════════════════════════════════════════════════════════════════════ */ + +/* ── CondL 8 ──────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condl_8(s8 a) { + volatile s8 va = a; + volatile s8 zero = 0; + if (va < zero) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondL 16 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condl_16(s16 a) { + volatile s16 va = a; + volatile s16 zero = 0; + if (va < zero) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondL 32 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condl_32(s32 a) { + /* + * Some compilers emit "test eax,eax; jl" instead of "js" + * for signed-negative checks. Both trigger LOGIC ccop. + * Force via volatile + explicit signed comparison. + */ + volatile s32 va = a; + volatile s32 zero = 0; + if (va < zero) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondL 64 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condl_64(s64 a) { + volatile s64 va = a; + volatile s64 zero = 0; + if (va < zero) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ═══════════════════════════════════════════════════════════════════════ + * CondNL: a >= 0 (test reg,reg + jge) + * ═══════════════════════════════════════════════════════════════════════ */ + +/* ── CondNL 8 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condnl_8(s8 a) { + volatile s8 va = a; + volatile s8 zero = 0; + if (va >= zero) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondNL 16 ────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condnl_16(s16 a) { + volatile s16 va = a; + volatile s16 zero = 0; + if (va >= zero) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondNL 32 ────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condnl_32(s32 a) { + volatile s32 va = a; + volatile s32 zero = 0; + if (va >= zero) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondNL 64 ────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condnl_64(s64 a) { + volatile s64 va = a; + volatile s64 zero = 0; + if (va >= zero) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ═══════════════════════════════════════════════════════════════════════ + * CondLE: a <= 0 (test reg,reg + jle) + * ═══════════════════════════════════════════════════════════════════════ */ + +/* ── CondLE 8 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condle_8(s8 a) { + volatile s8 va = a; + volatile s8 zero = 0; + if (va <= zero) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondLE 16 ────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condle_16(s16 a) { + volatile s16 va = a; + volatile s16 zero = 0; + if (va <= zero) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondLE 32 ────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condle_32(s32 a) { + volatile s32 va = a; + volatile s32 zero = 0; + if (va <= zero) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondLE 64 ────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condle_64(s64 a) { + volatile s64 va = a; + volatile s64 zero = 0; + if (va <= zero) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ═══════════════════════════════════════════════════════════════════════ + * CondNLE: a > 0 (test reg,reg + jg) + * ═══════════════════════════════════════════════════════════════════════ */ + +/* ── CondNLE 8 ────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condnle_8(s8 a) { + volatile s8 va = a; + volatile s8 zero = 0; + if (va > zero) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondNLE 16 ───────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condnle_16(s16 a) { + volatile s16 va = a; + volatile s16 zero = 0; + if (va > zero) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondNLE 32 ───────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condnle_32(s32 a) { + volatile s32 va = a; + volatile s32 zero = 0; + if (va > zero) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondNLE 64 ───────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condnle_64(s64 a) { + volatile s64 va = a; + volatile s64 zero = 0; + if (va > zero) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ═══════════════════════════════════════════════════════════════════════ + * CondB: test + jb — x86 rewriter path (CF is always 0 for LOGIC) + * ═══════════════════════════════════════════════════════════════════════ */ + +/* ── CondB 8 ──────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condb_8(u8 a, u8 b) { + asm goto ("testb %0, %1\n\t" "jb %l[taken]" : : "q"(a), "q"(b) : "cc" : taken); + g_sink = 0; return g_sink; +taken: g_sink = 1; return g_sink; +} + +/* ── CondB 16 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condb_16(u16 a, u16 b) { + asm goto ("testw %0, %1\n\t" "jb %l[taken]" : : "r"(a), "r"(b) : "cc" : taken); + g_sink = 0; return g_sink; +taken: g_sink = 1; return g_sink; +} + +/* ── CondB 32 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condb_32(u32 a, u32 b) { + asm goto ("testl %0, %1\n\t" "jb %l[taken]" : : "r"(a), "r"(b) : "cc" : taken); + g_sink = 0; return g_sink; +taken: g_sink = 1; return g_sink; +} + +/* ═══════════════════════════════════════════════════════════════════════ + * CondBE: test + jbe — x86 rewriter path (CF is always 0 for LOGIC) + * ═══════════════════════════════════════════════════════════════════════ */ + +/* ── CondBE 8 ─────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condbe_8(u8 a, u8 b) { + asm goto ("testb %0, %1\n\t" "jbe %l[taken]" : : "q"(a), "q"(b) : "cc" : taken); + g_sink = 0; return g_sink; +taken: g_sink = 1; return g_sink; +} + +/* ── CondBE 16 ────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condbe_16(u16 a, u16 b) { + asm goto ("testw %0, %1\n\t" "jbe %l[taken]" : : "r"(a), "r"(b) : "cc" : taken); + g_sink = 0; return g_sink; +taken: g_sink = 1; return g_sink; +} + +/* ── CondBE 32 ────────────────────────────────────────────────────────── */ + +NOINLINE int ccop_logic_condbe_32(u32 a, u32 b) { + asm goto ("testl %0, %1\n\t" "jbe %l[taken]" : : "r"(a), "r"(b) : "cc" : taken); + g_sink = 0; return g_sink; +taken: g_sink = 1; return g_sink; +} + +/* ═══════════════════════════════════════════════════════════════════════ */ + +int main(void) { + g_sink = 0; + + ccop_logic_condz_8(0xAA, 0x55); + ccop_logic_condz_16(0xAA00, 0x5500); + ccop_logic_condz_32(0xAA, 0x55); + ccop_logic_condz_64(0xAA, 0x55); + + ccop_logic_condnz_8(42); + ccop_logic_condnz_16(42); + ccop_logic_condnz_32(42); + ccop_logic_condnz_64(42); + + ccop_logic_conds_8(-1); + ccop_logic_conds_16(-1); + ccop_logic_conds_32(-1); + ccop_logic_conds_64(-1); + + ccop_logic_condns_8(1); + ccop_logic_condns_16(1); + ccop_logic_condns_32(1); + ccop_logic_condns_64(1); + + ccop_logic_condl_8(-5); + ccop_logic_condl_16(-5); + ccop_logic_condl_32(-5); + ccop_logic_condl_64(-5); + + ccop_logic_condnl_8(5); + ccop_logic_condnl_16(5); + ccop_logic_condnl_32(5); + ccop_logic_condnl_64(5); + + ccop_logic_condle_8(-1); + ccop_logic_condle_16(-1); + ccop_logic_condle_32(-1); + ccop_logic_condle_64(-1); + + ccop_logic_condnle_8(5); + ccop_logic_condnle_16(5); + ccop_logic_condnle_32(5); + ccop_logic_condnle_64(5); + + ccop_logic_condb_8(0xAA, 0x55); + ccop_logic_condb_16(0xAA00, 0x5500); + ccop_logic_condb_32(0xAA, 0x55); + + ccop_logic_condbe_8(0xAA, 0x55); + ccop_logic_condbe_16(0xAA00, 0x5500); + ccop_logic_condbe_32(0xAA, 0x55); + + return g_sink; +} diff --git a/tests_src/ccop_triggers/ccop_rflags_c.c b/tests_src/ccop_triggers/ccop_rflags_c.c new file mode 100644 index 00000000..2a5169ed --- /dev/null +++ b/tests_src/ccop_triggers/ccop_rflags_c.c @@ -0,0 +1,127 @@ +/* + * ccop_rflags_c.c — rflags_c (carry flag extraction) triggers + * + * The amd64 rewriter handles amd64g_calculate_rflags_c for ADD, SUB, DEC. + * This callee extracts CF independently from the full flags calculation. + * + * Pattern: operation sets CF -> adc $0,reg captures CF into a register. + * For DEC (which preserves CF via NDEP): stc -> dec -> adc $0 captures + * the preserved carry. + * + * amd64-only (rflags_c is not used by the x86/i386 rewriter). + */ + +#include "ccop_common.h" + +volatile int g_sink; + +#ifdef __x86_64__ + +/* =================================================================== + * rflags_c + ADD: carry capture via adc $0 after add + * =================================================================== */ + +NOINLINE int ccop_rflagsc_add_32(u32 a, u32 b) { + u32 carry = 0; + asm volatile ( + "addl %[b], %[a]\n\t" + "adcl $0, %[c]" + : [a] "+r"(a), [c] "+r"(carry) + : [b] "r"(b) + : "cc" + ); + if (carry) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_rflagsc_add_64(u64 a, u64 b) { + u64 carry = 0; + asm volatile ( + "addq %[b], %[a]\n\t" + "adcq $0, %[c]" + : [a] "+r"(a), [c] "+r"(carry) + : [b] "r"(b) + : "cc" + ); + if (carry) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* =================================================================== + * rflags_c + SUB: borrow capture via sbb $0 after sub + * =================================================================== */ + +NOINLINE int ccop_rflagsc_sub_32(u32 a, u32 b) { + u32 borrow = 0; + asm volatile ( + "subl %[b], %[a]\n\t" + "sbbl $0, %[c]" + : [a] "+r"(a), [c] "+r"(borrow) + : [b] "r"(b) + : "cc" + ); + if (borrow) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_rflagsc_sub_64(u64 a, u64 b) { + u64 borrow = 0; + asm volatile ( + "subq %[b], %[a]\n\t" + "sbbq $0, %[c]" + : [a] "+r"(a), [c] "+r"(borrow) + : [b] "r"(b) + : "cc" + ); + if (borrow) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* =================================================================== + * rflags_c + DEC: DEC preserves CF (via NDEP), capture after dec + * =================================================================== */ + +NOINLINE int ccop_rflagsc_dec_32(u32 a) { + u32 carry = 0; + asm volatile ( + "stc\n\t" + "decl %[a]\n\t" + "adcl $0, %[c]" + : [a] "+r"(a), [c] "+r"(carry) + : : "cc" + ); + if (carry) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_rflagsc_dec_64(u64 a) { + u64 carry = 0; + asm volatile ( + "stc\n\t" + "decq %[a]\n\t" + "adcq $0, %[c]" + : [a] "+r"(a), [c] "+r"(carry) + : : "cc" + ); + if (carry) g_sink = 1; else g_sink = 0; + return g_sink; +} + +#endif /* __x86_64__ */ + +int main(void) { + g_sink = 0; + +#ifdef __x86_64__ + ccop_rflagsc_add_32(0xFFFFFFFFU, 1); + ccop_rflagsc_add_64(0xFFFFFFFFFFFFFFFFULL, 1); + + ccop_rflagsc_sub_32(1, 2); + ccop_rflagsc_sub_64(1, 2); + + ccop_rflagsc_dec_32(5); + ccop_rflagsc_dec_64(5); +#endif + + return g_sink; +} diff --git a/tests_src/ccop_triggers/ccop_shl_shr.c b/tests_src/ccop_triggers/ccop_shl_shr.c new file mode 100644 index 00000000..9010c47b --- /dev/null +++ b/tests_src/ccop_triggers/ccop_shl_shr.c @@ -0,0 +1,272 @@ +/* + * ccop_shl_shr.c — SHL/SHR condition code triggers + * + * VEX models shift flag-setting as CC_OP_SHLx / CC_OP_SHRx. + * Pure C shifts trigger these naturally. + */ + +#include "ccop_common.h" + +volatile int g_sink; + +/* ═══════════════════════════════════════════════════════════════════ + * SHL (left shift) + * ═══════════════════════════════════════════════════════════════════ */ + +/* ── SHL + CondZ ──────────────────────────────────────────────────── */ + +NOINLINE int ccop_shl_condz_8(u8 a, u8 n) { + volatile u8 va = a; + if ((u8)(va << n) == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_shl_condz_16(u16 a, u16 n) { + volatile u16 va = a; + if ((u16)(va << n) == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_shl_condz_32(u32 a, u32 n) { + if ((a << n) == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_shl_condz_64(u64 a, u64 n) { + if ((a << n) == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── SHL + CondNZ ─────────────────────────────────────────────────── */ + +NOINLINE int ccop_shl_condnz_8(u8 a, u8 n) { + volatile u8 va = a; + if ((u8)(va << n) != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_shl_condnz_16(u16 a, u16 n) { + volatile u16 va = a; + if ((u16)(va << n) != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_shl_condnz_32(u32 a, u32 n) { + if ((a << n) != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_shl_condnz_64(u64 a, u64 n) { + if ((a << n) != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── SHL + CondS ──────────────────────────────────────────────────── */ + +NOINLINE int ccop_shl_conds_8(s8 a, u8 n) { + volatile s8 va = a; + s8 r = (s8)(va << n); + if (r < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_shl_conds_16(s16 a, u16 n) { + volatile s16 va = a; + s16 r = (s16)(va << n); + if (r < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_shl_conds_32(s32 a, u32 n) { + s32 r = a << n; + if (r < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_shl_conds_64(s64 a, u64 n) { + s64 r = a << n; + if (r < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── SHL + CondNS ─────────────────────────────────────────────────── */ + +NOINLINE int ccop_shl_condns_8(s8 a, u8 n) { + volatile s8 va = a; + s8 r = (s8)(va << n); + if (r >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_shl_condns_16(s16 a, u16 n) { + volatile s16 va = a; + s16 r = (s16)(va << n); + if (r >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_shl_condns_32(s32 a, u32 n) { + s32 r = a << n; + if (r >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_shl_condns_64(s64 a, u64 n) { + s64 r = a << n; + if (r >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ═══════════════════════════════════════════════════════════════════ + * SHR (logical right shift) + * ═══════════════════════════════════════════════════════════════════ */ + +/* ── SHR + CondZ ──────────────────────────────────────────────────── */ + +NOINLINE int ccop_shr_condz_8(u8 a, u8 n) { + volatile u8 va = a; + if ((u8)(va >> n) == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_shr_condz_16(u16 a, u16 n) { + volatile u16 va = a; + if ((u16)(va >> n) == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_shr_condz_32(u32 a, u32 n) { + if ((a >> n) == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_shr_condz_64(u64 a, u64 n) { + if ((a >> n) == 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── SHR + CondNZ ─────────────────────────────────────────────────── */ + +NOINLINE int ccop_shr_condnz_8(u8 a, u8 n) { + volatile u8 va = a; + if ((u8)(va >> n) != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_shr_condnz_16(u16 a, u16 n) { + volatile u16 va = a; + if ((u16)(va >> n) != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_shr_condnz_32(u32 a, u32 n) { + if ((a >> n) != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_shr_condnz_64(u64 a, u64 n) { + if ((a >> n) != 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── SHR + CondS ──────────────────────────────────────────────────── */ + +NOINLINE int ccop_shr_conds_8(u8 a, u8 n) { + volatile u8 va = a; + s8 r = (s8)(va >> n); + if (r < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_shr_conds_16(u16 a, u16 n) { + volatile u16 va = a; + s16 r = (s16)(va >> n); + if (r < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_shr_conds_32(u32 a, u32 n) { + s32 r = (s32)(a >> n); + if (r < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_shr_conds_64(u64 a, u64 n) { + s64 r = (s64)(a >> n); + if (r < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── SHR + CondNS ─────────────────────────────────────────────────── */ + +NOINLINE int ccop_shr_condns_8(u8 a, u8 n) { + volatile u8 va = a; + s8 r = (s8)(va >> n); + if (r >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_shr_condns_16(u16 a, u16 n) { + volatile u16 va = a; + s16 r = (s16)(va >> n); + if (r >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_shr_condns_32(u32 a, u32 n) { + s32 r = (s32)(a >> n); + if (r >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_shr_condns_64(u64 a, u64 n) { + s64 r = (s64)(a >> n); + if (r >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +int main(void) { + g_sink = 0; + + ccop_shl_condz_8(0x80, 1); + ccop_shl_condz_16(0x8000, 1); + ccop_shl_condz_32(0x80000000U, 1); + ccop_shl_condz_64(0x8000000000000000ULL, 1); + + ccop_shl_condnz_8(1, 4); + ccop_shl_condnz_16(1, 4); + ccop_shl_condnz_32(1, 4); + ccop_shl_condnz_64(1, 4); + + ccop_shl_conds_8(1, 7); + ccop_shl_conds_16(1, 15); + ccop_shl_conds_32(1, 31); + ccop_shl_conds_64(1LL, 63); + + ccop_shl_condns_8(1, 1); + ccop_shl_condns_16(1, 1); + ccop_shl_condns_32(1, 1); + ccop_shl_condns_64(1LL, 1); + + ccop_shr_condz_8(1, 1); + ccop_shr_condz_16(1, 1); + ccop_shr_condz_32(1, 1); + ccop_shr_condz_64(1, 1); + + ccop_shr_condnz_8(0xFF, 1); + ccop_shr_condnz_16(0xFF, 1); + ccop_shr_condnz_32(0xFF, 1); + ccop_shr_condnz_64(0xFF, 1); + + ccop_shr_conds_8(0x80, 0); + ccop_shr_conds_16(0x8000, 0); + ccop_shr_conds_32(0x80000000U, 0); + ccop_shr_conds_64(0x8000000000000000ULL, 0); + + ccop_shr_condns_8(0x80, 1); + ccop_shr_condns_16(0x8000, 1); + ccop_shr_condns_32(0x80000000U, 1); + ccop_shr_condns_64(0x8000000000000000ULL, 1); + + return g_sink; +} diff --git a/tests_src/ccop_triggers/ccop_sub.c b/tests_src/ccop_triggers/ccop_sub.c new file mode 100644 index 00000000..e5680be0 --- /dev/null +++ b/tests_src/ccop_triggers/ccop_sub.c @@ -0,0 +1,373 @@ +/* + * ccop_sub.c — SUB/CMP condition code triggers + * + * The x86 CMP instruction is SUB that discards the result. + * VEX models this as CC_OP_SUBx (x = B/W/L/Q for 8/16/32/64). + * Each function triggers a specific (condition, size) pair. + */ + +#include "ccop_common.h" + +volatile int g_sink; + +/* ── CondZ: a == b ────────────────────────────────────────────────── */ + +NOINLINE int ccop_sub_condz_8(s8 a, s8 b) { + volatile s8 va = a, vb = b; + if (va == vb) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condz_16(s16 a, s16 b) { + volatile s16 va = a, vb = b; + if (va == vb) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condz_32(s32 a, s32 b) { + if (a == b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condz_64(s64 a, s64 b) { + if (a == b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondNZ: a != b ───────────────────────────────────────────────── */ + +NOINLINE int ccop_sub_condnz_8(s8 a, s8 b) { + volatile s8 va = a, vb = b; + if (va != vb) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condnz_16(s16 a, s16 b) { + volatile s16 va = a, vb = b; + if (va != vb) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condnz_32(s32 a, s32 b) { + if (a != b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condnz_64(s64 a, s64 b) { + if (a != b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondL: a < b (signed) ────────────────────────────────────────── */ + +NOINLINE int ccop_sub_condl_8(s8 a, s8 b) { + volatile s8 va = a, vb = b; + if (va < vb) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condl_16(s16 a, s16 b) { + volatile s16 va = a, vb = b; + if (va < vb) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condl_32(s32 a, s32 b) { + if (a < b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condl_64(s64 a, s64 b) { + if (a < b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondNL: a >= b (signed) ──────────────────────────────────────── */ + +NOINLINE int ccop_sub_condnl_8(s8 a, s8 b) { + volatile s8 va = a, vb = b; + if (va >= vb) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condnl_16(s16 a, s16 b) { + volatile s16 va = a, vb = b; + if (va >= vb) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condnl_32(s32 a, s32 b) { + if (a >= b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condnl_64(s64 a, s64 b) { + if (a >= b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondLE: a <= b (signed) ──────────────────────────────────────── */ + +NOINLINE int ccop_sub_condle_8(s8 a, s8 b) { + volatile s8 va = a, vb = b; + if (va <= vb) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condle_16(s16 a, s16 b) { + volatile s16 va = a, vb = b; + if (va <= vb) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condle_32(s32 a, s32 b) { + if (a <= b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condle_64(s64 a, s64 b) { + if (a <= b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondNLE: a > b (signed) ──────────────────────────────────────── */ + +NOINLINE int ccop_sub_condnle_8(s8 a, s8 b) { + volatile s8 va = a, vb = b; + if (va > vb) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condnle_16(s16 a, s16 b) { + volatile s16 va = a, vb = b; + if (va > vb) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condnle_32(s32 a, s32 b) { + if (a > b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condnle_64(s64 a, s64 b) { + if (a > b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondB: a < b (unsigned) ──────────────────────────────────────── */ + +NOINLINE int ccop_sub_condb_8(u8 a, u8 b) { + volatile u8 va = a, vb = b; + if (va < vb) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condb_16(u16 a, u16 b) { + volatile u16 va = a, vb = b; + if (va < vb) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condb_32(u32 a, u32 b) { + if (a < b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condb_64(u64 a, u64 b) { + if (a < b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondNB: a >= b (unsigned) ────────────────────────────────────── */ + +NOINLINE int ccop_sub_condnb_8(u8 a, u8 b) { + volatile u8 va = a, vb = b; + if (va >= vb) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condnb_16(u16 a, u16 b) { + volatile u16 va = a, vb = b; + if (va >= vb) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condnb_32(u32 a, u32 b) { + if (a >= b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condnb_64(u64 a, u64 b) { + if (a >= b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondBE: a <= b (unsigned) ────────────────────────────────────── */ + +NOINLINE int ccop_sub_condbe_8(u8 a, u8 b) { + volatile u8 va = a, vb = b; + if (va <= vb) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condbe_16(u16 a, u16 b) { + volatile u16 va = a, vb = b; + if (va <= vb) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condbe_32(u32 a, u32 b) { + if (a <= b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condbe_64(u64 a, u64 b) { + if (a <= b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondNBE: a > b (unsigned) ────────────────────────────────────── */ + +NOINLINE int ccop_sub_condnbe_8(u8 a, u8 b) { + volatile u8 va = a, vb = b; + if (va > vb) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condnbe_16(u16 a, u16 b) { + volatile u16 va = a, vb = b; + if (va > vb) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condnbe_32(u32 a, u32 b) { + if (a > b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condnbe_64(u64 a, u64 b) { + if (a > b) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondS: sign flag of (a - b) ──────────────────────────────────── */ + +NOINLINE int ccop_sub_conds_8(s8 a, s8 b) { + volatile s8 va = a, vb = b; + s8 r = va - vb; + if (r < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_conds_16(s16 a, s16 b) { + volatile s16 va = a, vb = b; + s16 r = va - vb; + if (r < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_conds_32(s32 a, s32 b) { + s32 r = a - b; + if (r < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_conds_64(s64 a, s64 b) { + s64 r = a - b; + if (r < 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +/* ── CondNS: not sign flag of (a - b) ─────────────────────────────── */ + +NOINLINE int ccop_sub_condns_8(s8 a, s8 b) { + volatile s8 va = a, vb = b; + s8 r = va - vb; + if (r >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condns_16(s16 a, s16 b) { + volatile s16 va = a, vb = b; + s16 r = va - vb; + if (r >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condns_32(s32 a, s32 b) { + s32 r = a - b; + if (r >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +NOINLINE int ccop_sub_condns_64(s64 a, s64 b) { + s64 r = a - b; + if (r >= 0) g_sink = 1; else g_sink = 0; + return g_sink; +} + +int main(void) { + g_sink = 0; + /* Call every function to prevent linker stripping */ + ccop_sub_condz_8(1, 1); + ccop_sub_condz_16(2, 2); + ccop_sub_condz_32(3, 3); + ccop_sub_condz_64(4, 4); + + ccop_sub_condnz_8(1, 2); + ccop_sub_condnz_16(1, 2); + ccop_sub_condnz_32(1, 2); + ccop_sub_condnz_64(1, 2); + + ccop_sub_condl_8(-1, 1); + ccop_sub_condl_16(-1, 1); + ccop_sub_condl_32(-1, 1); + ccop_sub_condl_64(-1, 1); + + ccop_sub_condnl_8(5, 3); + ccop_sub_condnl_16(5, 3); + ccop_sub_condnl_32(5, 3); + ccop_sub_condnl_64(5, 3); + + ccop_sub_condle_8(3, 5); + ccop_sub_condle_16(3, 5); + ccop_sub_condle_32(3, 5); + ccop_sub_condle_64(3, 5); + + ccop_sub_condnle_8(5, 3); + ccop_sub_condnle_16(5, 3); + ccop_sub_condnle_32(5, 3); + ccop_sub_condnle_64(5, 3); + + ccop_sub_condb_8(1, 2); + ccop_sub_condb_16(1, 2); + ccop_sub_condb_32(1, 2); + ccop_sub_condb_64(1, 2); + + ccop_sub_condnb_8(2, 1); + ccop_sub_condnb_16(2, 1); + ccop_sub_condnb_32(2, 1); + ccop_sub_condnb_64(2, 1); + + ccop_sub_condbe_8(1, 2); + ccop_sub_condbe_16(1, 2); + ccop_sub_condbe_32(1, 2); + ccop_sub_condbe_64(1, 2); + + ccop_sub_condnbe_8(2, 1); + ccop_sub_condnbe_16(2, 1); + ccop_sub_condnbe_32(2, 1); + ccop_sub_condnbe_64(2, 1); + + ccop_sub_conds_8(1, 5); + ccop_sub_conds_16(1, 5); + ccop_sub_conds_32(1, 5); + ccop_sub_conds_64(1, 5); + + ccop_sub_condns_8(5, 1); + ccop_sub_condns_16(5, 1); + ccop_sub_condns_32(5, 1); + ccop_sub_condns_64(5, 1); + + return g_sink; +} diff --git a/tests_src/ccop_triggers/ccop_umul_smul.c b/tests_src/ccop_triggers/ccop_umul_smul.c new file mode 100644 index 00000000..79126042 --- /dev/null +++ b/tests_src/ccop_triggers/ccop_umul_smul.c @@ -0,0 +1,241 @@ +/* + * ccop_umul_smul.c — UMUL/SMUL (multiply overflow) condition code triggers + * + * VEX models widening multiply overflow as CC_OP_UMULx / CC_OP_SMULx. + * The overflow flag (OF) is set when the upper half of the result is + * non-zero (unsigned) or differs from sign-extension of the lower half + * (signed). + * + * Uses __builtin_mul_overflow which GCC compiles to widening multiply + * + overflow check. + */ + +#include "ccop_common.h" + +volatile int g_sink; + +/* ═══════════════════════════════════════════════════════════════════ + * UMUL — unsigned multiply overflow + * ═══════════════════════════════════════════════════════════════════ */ + +/* ── UMUL + CondO, 8-bit ──────────────────────────────────────────── */ + +NOINLINE int ccop_umul_condo_8(u8 a, u8 b) { + u8 r; + if (__builtin_mul_overflow(a, b, &r)) + g_sink = 1; + else + g_sink = 0; + return g_sink; +} + +/* ── UMUL + CondO, 16-bit ─────────────────────────────────────────── */ + +NOINLINE int ccop_umul_condo_16(u16 a, u16 b) { + u16 r; + if (__builtin_mul_overflow(a, b, &r)) + g_sink = 1; + else + g_sink = 0; + return g_sink; +} + +/* ── UMUL + CondO, 32-bit ─────────────────────────────────────────── */ + +NOINLINE int ccop_umul_condo_32(u32 a, u32 b) { + u32 r; + if (__builtin_mul_overflow(a, b, &r)) + g_sink = 1; + else + g_sink = 0; + return g_sink; +} + +/* ── UMUL + CondO, 64-bit ─────────────────────────────────────────── */ + +#ifdef __x86_64__ +NOINLINE int ccop_umul_condo_64(u64 a, u64 b) { + u64 r; + if (__builtin_mul_overflow(a, b, &r)) + g_sink = 1; + else + g_sink = 0; + return g_sink; +} +#endif + +/* ── UMUL + CondNO, 8-bit ─────────────────────────────────────────── */ + +NOINLINE int ccop_umul_condno_8(u8 a, u8 b) { + u8 r; + if (!__builtin_mul_overflow(a, b, &r)) + g_sink = 1; + else + g_sink = 0; + return g_sink; +} + +/* ── UMUL + CondNO, 16-bit ────────────────────────────────────────── */ + +NOINLINE int ccop_umul_condno_16(u16 a, u16 b) { + u16 r; + if (!__builtin_mul_overflow(a, b, &r)) + g_sink = 1; + else + g_sink = 0; + return g_sink; +} + +/* ── UMUL + CondNO, 32-bit ────────────────────────────────────────── */ + +NOINLINE int ccop_umul_condno_32(u32 a, u32 b) { + u32 r; + if (!__builtin_mul_overflow(a, b, &r)) + g_sink = 1; + else + g_sink = 0; + return g_sink; +} + +/* ── UMUL + CondNO, 64-bit ────────────────────────────────────────── */ + +#ifdef __x86_64__ +NOINLINE int ccop_umul_condno_64(u64 a, u64 b) { + u64 r; + if (!__builtin_mul_overflow(a, b, &r)) + g_sink = 1; + else + g_sink = 0; + return g_sink; +} +#endif + +/* ═══════════════════════════════════════════════════════════════════ + * SMUL — signed multiply overflow + * ═══════════════════════════════════════════════════════════════════ */ + +/* ── SMUL + CondO, 8-bit ──────────────────────────────────────────── */ + +NOINLINE int ccop_smul_condo_8(s8 a, s8 b) { + s8 r; + if (__builtin_mul_overflow(a, b, &r)) + g_sink = 1; + else + g_sink = 0; + return g_sink; +} + +/* ── SMUL + CondO, 16-bit ─────────────────────────────────────────── */ + +NOINLINE int ccop_smul_condo_16(s16 a, s16 b) { + s16 r; + if (__builtin_mul_overflow(a, b, &r)) + g_sink = 1; + else + g_sink = 0; + return g_sink; +} + +/* ── SMUL + CondO, 32-bit ─────────────────────────────────────────── */ + +NOINLINE int ccop_smul_condo_32(s32 a, s32 b) { + s32 r; + if (__builtin_mul_overflow(a, b, &r)) + g_sink = 1; + else + g_sink = 0; + return g_sink; +} + +/* ── SMUL + CondO, 64-bit ─────────────────────────────────────────── */ + +#ifdef __x86_64__ +NOINLINE int ccop_smul_condo_64(s64 a, s64 b) { + s64 r; + if (__builtin_mul_overflow(a, b, &r)) + g_sink = 1; + else + g_sink = 0; + return g_sink; +} +#endif + +/* ── SMUL + CondNO, 8-bit ─────────────────────────────────────────── */ + +NOINLINE int ccop_smul_condno_8(s8 a, s8 b) { + s8 r; + if (!__builtin_mul_overflow(a, b, &r)) + g_sink = 1; + else + g_sink = 0; + return g_sink; +} + +/* ── SMUL + CondNO, 16-bit ────────────────────────────────────────── */ + +NOINLINE int ccop_smul_condno_16(s16 a, s16 b) { + s16 r; + if (!__builtin_mul_overflow(a, b, &r)) + g_sink = 1; + else + g_sink = 0; + return g_sink; +} + +/* ── SMUL + CondNO, 32-bit ────────────────────────────────────────── */ + +NOINLINE int ccop_smul_condno_32(s32 a, s32 b) { + s32 r; + if (!__builtin_mul_overflow(a, b, &r)) + g_sink = 1; + else + g_sink = 0; + return g_sink; +} + +/* ── SMUL + CondNO, 64-bit ────────────────────────────────────────── */ + +#ifdef __x86_64__ +NOINLINE int ccop_smul_condno_64(s64 a, s64 b) { + s64 r; + if (!__builtin_mul_overflow(a, b, &r)) + g_sink = 1; + else + g_sink = 0; + return g_sink; +} +#endif + +int main(void) { + g_sink = 0; + + ccop_umul_condo_8(16, 16); + ccop_umul_condo_16(256, 256); + ccop_umul_condo_32(0x10000U, 0x10000U); +#ifdef __x86_64__ + ccop_umul_condo_64(0x100000000ULL, 0x100000000ULL); +#endif + + ccop_umul_condno_8(2, 3); + ccop_umul_condno_16(2, 3); + ccop_umul_condno_32(2, 3); +#ifdef __x86_64__ + ccop_umul_condno_64(2, 3); +#endif + + ccop_smul_condo_8(127, 2); + ccop_smul_condo_16(0x7FFF, 2); + ccop_smul_condo_32(0x7FFFFFFF, 2); +#ifdef __x86_64__ + ccop_smul_condo_64(0x7FFFFFFFFFFFFFFFLL, 2); +#endif + + ccop_smul_condno_8(2, 3); + ccop_smul_condno_16(2, 3); + ccop_smul_condno_32(2, 3); +#ifdef __x86_64__ + ccop_smul_condno_64(2, 3); +#endif + + return g_sink; +} diff --git a/tests_src/recompile_dataset/build.sh b/tests_src/recompile_dataset/build.sh new file mode 100755 index 00000000..5a91ac92 --- /dev/null +++ b/tests_src/recompile_dataset/build.sh @@ -0,0 +1,149 @@ +#!/bin/bash +# +# Build recompile-dataset binaries for multiple architectures, compilers, +# and optimisation levels. +# +# Usage: cd tests_src/recompile_dataset && bash build.sh +# +# Requires (install missing ones with apt): +# gcc, gcc-multilib (x86_64 and i386) +# aarch64-linux-gnu-gcc (aarch64) +# arm-linux-gnueabihf-gcc (armhf) +# clang (x86_64 and i386, and cross targets) +# x86_64-w64-mingw32-gcc (optional, for mingw PE builds) +# i686-w64-mingw32-gcc (optional, for mingw PE i386 builds) +# +set -e + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +cd "$SCRIPT_DIR" + +SRCS=( + t1_control_flow + t2_types + t3_memory + t4_calling + t5_patterns +) + +# Output directories (relative to the binaries repo root) +REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +OUT_X64="$REPO_ROOT/tests/x86_64/recompile_dataset" +OUT_I386="$REPO_ROOT/tests/i386/recompile_dataset" +OUT_AARCH64="$REPO_ROOT/tests/aarch64/recompile_dataset" +OUT_ARMHF="$REPO_ROOT/tests/armhf/recompile_dataset" + +mkdir -p "$OUT_X64" "$OUT_I386" "$OUT_AARCH64" "$OUT_ARMHF" + +# Base flags: keep debug info. +# GCC supports -fno-if-conversion to keep branches; clang does not. +BASE_GCC="-g -fno-if-conversion -fno-if-conversion2" +BASE_CLANG="-g" + +OPT_LEVELS=(-O0 -O1 -O2 -O3 -Os) + +FAIL=0 +COUNT=0 +SKIP=0 + +build_one() { + local compiler="$1" + local src="$2" + local name="$3" + local flags="$4" + local outdir="$5" + local base="$6" + + if $compiler $base $flags \ + -o "${outdir}/${name}" \ + "${src}.c" dummy_main.c 2>/dev/null; then + COUNT=$((COUNT + 1)) + else + echo " FAILED: $name ($outdir)" + SKIP=$((SKIP + 1)) + fi +} + +# Check which compilers are available +has_cmd() { command -v "$1" >/dev/null 2>&1; } + +echo "=== Building recompile-dataset binaries ===" +echo "" + +# ── GCC x86_64 + i386 ──────────────────────────────────────────── +if has_cmd gcc; then + for src in "${SRCS[@]}"; do + for opt in "${OPT_LEVELS[@]}"; do + tag="${opt#-}" # O0, O1, ... + echo "gcc x86_64: ${src}_gcc_${tag}" + build_one "gcc" "$src" "${src}_gcc_${tag}" "$opt" "$OUT_X64" "$BASE_GCC" + # i386 requires gcc-multilib; skip gracefully if missing + echo "gcc i386: ${src}_gcc_${tag}" + build_one "gcc -m32" "$src" "${src}_gcc_${tag}" "$opt" "$OUT_I386" "$BASE_GCC" + done + done +else + echo "SKIP: gcc not found" +fi + +# ── Clang x86_64 + i386 ────────────────────────────────────────── +if has_cmd clang; then + for src in "${SRCS[@]}"; do + for opt in "${OPT_LEVELS[@]}"; do + tag="${opt#-}" + echo "clang x86_64: ${src}_clang_${tag}" + build_one "clang" "$src" "${src}_clang_${tag}" "$opt" "$OUT_X64" "$BASE_CLANG" + echo "clang i386: ${src}_clang_${tag}" + build_one "clang -m32" "$src" "${src}_clang_${tag}" "$opt" "$OUT_I386" "$BASE_CLANG" + done + done +else + echo "SKIP: clang not found" +fi + +# ── GCC aarch64 ────────────────────────────────────────────────── +if has_cmd aarch64-linux-gnu-gcc; then + for src in "${SRCS[@]}"; do + for opt in "${OPT_LEVELS[@]}"; do + tag="${opt#-}" + echo "aarch64-gcc: ${src}_gcc_${tag}" + build_one "aarch64-linux-gnu-gcc" "$src" "${src}_gcc_${tag}" "$opt" "$OUT_AARCH64" "$BASE_GCC" + done + done +else + echo "SKIP: aarch64-linux-gnu-gcc not found" +fi + +# ── GCC armhf ──────────────────────────────────────────────────── +if has_cmd arm-linux-gnueabihf-gcc; then + for src in "${SRCS[@]}"; do + for opt in "${OPT_LEVELS[@]}"; do + tag="${opt#-}" + echo "armhf-gcc: ${src}_gcc_${tag}" + build_one "arm-linux-gnueabihf-gcc" "$src" "${src}_gcc_${tag}" "$opt" "$OUT_ARMHF" "$BASE_GCC" + done + done +else + echo "SKIP: arm-linux-gnueabihf-gcc not found" +fi + +# ── Clang aarch64 ──────────────────────────────────────────────── +if has_cmd clang; then + if has_cmd aarch64-linux-gnu-gcc; then + for src in "${SRCS[@]}"; do + for opt in "${OPT_LEVELS[@]}"; do + tag="${opt#-}" + echo "clang aarch64: ${src}_clang_${tag}" + build_one "clang --target=aarch64-linux-gnu --sysroot=/usr/aarch64-linux-gnu" \ + "$src" "${src}_clang_${tag}" "$opt" "$OUT_AARCH64" "$BASE_CLANG" + done + done + fi +fi + +echo "" +echo "Done. Built $COUNT binaries ($SKIP skipped)." +if [ $COUNT -eq 0 ]; then + echo "ERROR: no binaries were built at all." + exit 1 +fi diff --git a/tests_src/recompile_dataset/dummy_main.c b/tests_src/recompile_dataset/dummy_main.c new file mode 100644 index 00000000..4fa58688 --- /dev/null +++ b/tests_src/recompile_dataset/dummy_main.c @@ -0,0 +1,13 @@ +/* + * dummy_main.c -- Provides main() and g_sink definition for linking. + * + * Each source file declares ``extern volatile int g_sink;`` via + * harness_common.h. This file provides the actual definition and a + * trivial main so the linker produces a valid executable. + */ + +volatile int g_sink; + +int main(void) { + return 0; +} diff --git a/tests_src/recompile_dataset/harness_common.h b/tests_src/recompile_dataset/harness_common.h new file mode 100644 index 00000000..77ff9afa --- /dev/null +++ b/tests_src/recompile_dataset/harness_common.h @@ -0,0 +1,33 @@ +/* + * harness_common.h -- Shared header for recompile-dataset test functions. + * + * Contract: + * - Every test function is NOINLINE, takes (s32 a, s32 b), writes g_sink. + * - Each .c file defines ``volatile int g_sink;`` + * - Compiles cleanly with GCC, Clang, and MSVC. + */ + +#ifndef HARNESS_COMMON_H +#define HARNESS_COMMON_H + +#include +#include + +#ifdef _MSC_VER +#define NOINLINE __declspec(noinline) +#else +#define NOINLINE __attribute__((noinline)) +#endif + +extern volatile int g_sink; + +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +#endif /* HARNESS_COMMON_H */ diff --git a/tests_src/recompile_dataset/t1_control_flow.c b/tests_src/recompile_dataset/t1_control_flow.c new file mode 100644 index 00000000..8fff4584 --- /dev/null +++ b/tests_src/recompile_dataset/t1_control_flow.c @@ -0,0 +1,185 @@ +/* + * t1_control_flow.c -- Control flow pattern triggers. + * + * Tests: switch (dense/sparse), loop variants, nested conditionals, + * early return, short-circuit, break/continue. + */ + +#include "harness_common.h" + +/* Dense switch: compiler should emit a jump table. */ +NOINLINE int t1_switch_dense(s32 a, s32 b) { + switch (a & 7) { + case 0: g_sink = b + 1; break; + case 1: g_sink = b - 1; break; + case 2: g_sink = b * 2; break; + case 3: g_sink = b >> 1; break; + case 4: g_sink = b ^ 0xFF; break; + case 5: g_sink = b & 0xF0; break; + case 6: g_sink = b | 0x0F; break; + case 7: g_sink = ~b; break; + } + return g_sink; +} + +/* Sparse switch: compiler may emit binary search or if-else chain. */ +NOINLINE int t1_switch_sparse(s32 a, s32 b) { + switch (a) { + case 1: g_sink = b + 10; break; + case 10: g_sink = b + 20; break; + case 100: g_sink = b + 30; break; + case 1000: g_sink = b + 40; break; + default: g_sink = b; break; + } + return g_sink; +} + +/* Switch with fallthrough. */ +NOINLINE int t1_switch_fallthrough(s32 a, s32 b) { + s32 r = 0; + switch (a & 3) { + case 3: r += b; /* fallthrough */ + case 2: r += b; /* fallthrough */ + case 1: r += b; /* fallthrough */ + case 0: r += 1; break; + } + g_sink = r; + return g_sink; +} + +/* For loop with accumulator. */ +NOINLINE int t1_loop_for(s32 a, s32 b) { + s32 sum = 0; + s32 n = a & 15; + for (s32 i = 0; i < n; i++) { + sum += i * b; + } + g_sink = sum; + return g_sink; +} + +/* While loop. */ +NOINLINE int t1_loop_while(s32 a, s32 b) { + s32 result = a; + s32 count = b & 15; + while (count > 0) { + result = result * 3 + 1; + count--; + } + g_sink = result; + return g_sink; +} + +/* Do-while loop. */ +NOINLINE int t1_loop_do_while(s32 a, s32 b) { + s32 val = a | 1; /* ensure nonzero start */ + s32 limit = (b & 15) + 1; + s32 i = 0; + do { + val = (val >> 1) ^ ((val & 1) ? 0xB : 0); + i++; + } while (i < limit); + g_sink = val; + return g_sink; +} + +/* Nested loops. */ +NOINLINE int t1_loop_nested(s32 a, s32 b) { + s32 sum = 0; + s32 na = a & 7; + s32 nb = b & 7; + for (s32 i = 0; i < na; i++) { + for (s32 j = 0; j < nb; j++) { + sum += i * nb + j; + } + } + g_sink = sum; + return g_sink; +} + +/* If-else chain. */ +NOINLINE int t1_if_chain(s32 a, s32 b) { + if (a < -100) + g_sink = -b; + else if (a < 0) + g_sink = b - a; + else if (a == 0) + g_sink = 0; + else if (a < 100) + g_sink = b + a; + else + g_sink = b * 2; + return g_sink; +} + +/* Deeply nested conditions. */ +NOINLINE int t1_if_nested(s32 a, s32 b) { + if (a > 0) { + if (b > 0) { + g_sink = a + b; + } else { + if (a > -b) + g_sink = a; + else + g_sink = b; + } + } else { + if (b < 0) + g_sink = -(a + b); + else + g_sink = b - a; + } + return g_sink; +} + +/* Multiple early returns. */ +NOINLINE int t1_early_return(s32 a, s32 b) { + if (a == 0) { g_sink = 0; return g_sink; } + if (b == 0) { g_sink = a; return g_sink; } + if (a == b) { g_sink = 1; return g_sink; } + if (a < 0 && b < 0) { g_sink = -a - b; return g_sink; } + g_sink = a + b; + return g_sink; +} + +/* Ternary chain. */ +NOINLINE int t1_ternary(s32 a, s32 b) { + g_sink = (a > 0) ? ((b > 0) ? a + b : a - b) + : ((b > 0) ? b - a : -(a + b)); + return g_sink; +} + +/* Short-circuit evaluation. */ +NOINLINE int t1_short_circuit(s32 a, s32 b) { + if (a > 0 && b > 0 && a < 1000 && b < 1000) + g_sink = a * b; + else if (a < 0 || b < 0) + g_sink = -(a + b); + else + g_sink = 0; + return g_sink; +} + +/* Loop with break and continue. */ +NOINLINE int t1_loop_break_continue(s32 a, s32 b) { + s32 sum = 0; + s32 stop = a & 15; + for (s32 i = 0; i < 16; i++) { + if (i == stop) break; + if ((i & 1) == 0) continue; + sum += b; + } + g_sink = sum; + return g_sink; +} + +/* Countdown loop (counts down to zero). */ +NOINLINE int t1_loop_countdown(s32 a, s32 b) { + s32 n = (a & 15) + 1; + s32 acc = b; + while (n-- > 0) { + acc ^= n; + } + g_sink = acc; + return g_sink; +} diff --git a/tests_src/recompile_dataset/t2_types.c b/tests_src/recompile_dataset/t2_types.c new file mode 100644 index 00000000..c3ac249b --- /dev/null +++ b/tests_src/recompile_dataset/t2_types.c @@ -0,0 +1,117 @@ +/* + * t2_types.c -- Type conversion and width-mixing triggers. + * + * Tests: signed/unsigned widening, truncation, sign-change casts, + * bitwise manipulation across widths, mixed-width arithmetic. + */ + +#include "harness_common.h" + +/* Widen signed 8-bit to 32-bit, operate, store. */ +NOINLINE int t2_widen_s8(s32 a, s32 b) { + s8 narrow = (s8)a; + s32 wide = (s32)narrow; + g_sink = wide + b; + return g_sink; +} + +/* Widen unsigned 8-bit to 32-bit. */ +NOINLINE int t2_widen_u8(s32 a, s32 b) { + u8 narrow = (u8)a; + u32 wide = (u32)narrow; + g_sink = (s32)(wide + (u32)b); + return g_sink; +} + +/* Widen signed 16-bit to 64-bit. */ +NOINLINE int t2_widen_s16_s64(s32 a, s32 b) { + s16 narrow = (s16)a; + s64 wide = (s64)narrow; + g_sink = (s32)(wide + (s64)b); + return g_sink; +} + +/* Truncate 32-bit to 8-bit, then widen back. */ +NOINLINE int t2_trunc_widen(s32 a, s32 b) { + s8 t = (s8)a; + s32 r = (s32)t + b; + g_sink = r; + return g_sink; +} + +/* Truncate 64-bit to 16-bit. */ +NOINLINE int t2_trunc_64_16(s32 a, s32 b) { + s64 big = (s64)a * (s64)b; + s16 small = (s16)big; + g_sink = (s32)small; + return g_sink; +} + +/* Signed <-> unsigned reinterpretation. */ +NOINLINE int t2_sign_change(s32 a, s32 b) { + u32 ua = (u32)a; + u32 ub = (u32)b; + u32 sum = ua + ub; + s32 result = (s32)sum; + g_sink = result; + return g_sink; +} + +/* Unsigned comparison after widening. */ +NOINLINE int t2_unsigned_cmp(s32 a, s32 b) { + u32 ua = (u32)a; + u32 ub = (u32)b; + if (ua > ub) + g_sink = 1; + else if (ua == ub) + g_sink = 0; + else + g_sink = -1; + return g_sink; +} + +/* Mixed-width arithmetic: 16-bit intermediates in 32-bit context. */ +NOINLINE int t2_mixed_width(s32 a, s32 b) { + s16 ha = (s16)a; + s16 hb = (s16)b; + s16 prod = ha * hb; /* 16-bit multiply, may overflow */ + s32 result = (s32)prod + a; + g_sink = result; + return g_sink; +} + +/* Bit-field style extraction using shifts and masks. */ +NOINLINE int t2_bitfield_extract(s32 a, s32 b) { + u32 val = (u32)a; + u32 field1 = (val >> 0) & 0xF; /* bits 0-3 */ + u32 field2 = (val >> 4) & 0xFF; /* bits 4-11 */ + u32 field3 = (val >> 12) & 0xFFF; /* bits 12-23 */ + g_sink = (s32)(field1 + field2 * (u32)b + field3); + return g_sink; +} + +/* Bit-field style packing. */ +NOINLINE int t2_bitfield_pack(s32 a, s32 b) { + u32 packed = 0; + packed |= ((u32)a & 0xF) << 0; + packed |= ((u32)b & 0xFF) << 4; + packed |= ((u32)(a + b) & 0xFFF) << 12; + g_sink = (s32)packed; + return g_sink; +} + +/* Bool conversion: nonzero -> 1, zero -> 0. */ +NOINLINE int t2_bool_convert(s32 a, s32 b) { + bool ba = (a != 0); + bool bb = (b != 0); + g_sink = (s32)(ba & bb) + (s32)(ba | bb) + (s32)(ba ^ bb); + return g_sink; +} + +/* Double negation and absolute value via conditional. */ +NOINLINE int t2_abs_negate(s32 a, s32 b) { + s32 abs_a = (a < 0) ? -a : a; + s32 abs_b = (b < 0) ? -b : b; + g_sink = abs_a - abs_b; + return g_sink; +} diff --git a/tests_src/recompile_dataset/t3_memory.c b/tests_src/recompile_dataset/t3_memory.c new file mode 100644 index 00000000..9f6a3e48 --- /dev/null +++ b/tests_src/recompile_dataset/t3_memory.c @@ -0,0 +1,140 @@ +/* + * t3_memory.c -- Stack memory and aggregate triggers. + * + * Tests: local array operations, struct access on stack, pointer + * arithmetic, nested structs. All data is stack-allocated so the + * functions remain self-contained (no heap, no globals beyond g_sink). + */ + +#include "harness_common.h" + +/* Sum a stack-allocated array. */ +NOINLINE int t3_array_sum(s32 a, s32 b) { + s32 arr[8]; + for (int i = 0; i < 8; i++) + arr[i] = a + i * b; + s32 sum = 0; + for (int i = 0; i < 8; i++) + sum += arr[i]; + g_sink = sum; + return g_sink; +} + +/* Reverse a stack array in place. */ +NOINLINE int t3_array_reverse(s32 a, s32 b) { + s32 arr[8]; + for (int i = 0; i < 8; i++) + arr[i] = a * (i + 1) + b; + for (int i = 0; i < 4; i++) { + s32 tmp = arr[i]; + arr[i] = arr[7 - i]; + arr[7 - i] = tmp; + } + g_sink = arr[0] + arr[7]; + return g_sink; +} + +/* Find maximum in a stack array. */ +NOINLINE int t3_array_max(s32 a, s32 b) { + s32 arr[8]; + for (int i = 0; i < 8; i++) + arr[i] = (a ^ (i * 0x9E3779B9)) + b; + s32 mx = arr[0]; + for (int i = 1; i < 8; i++) { + if (arr[i] > mx) + mx = arr[i]; + } + g_sink = mx; + return g_sink; +} + +/* Pointer arithmetic: walk array with pointer instead of index. */ +NOINLINE int t3_ptr_walk(s32 a, s32 b) { + s32 arr[8]; + s32 *p = arr; + for (int i = 0; i < 8; i++) + *p++ = a + i * b; + s32 sum = 0; + p = arr; + s32 *end = arr + 8; + while (p < end) + sum += *p++; + g_sink = sum; + return g_sink; +} + +/* Simple struct access on stack. */ +NOINLINE int t3_struct_basic(s32 a, s32 b) { + struct { s32 x; s32 y; s32 z; } pt; + pt.x = a; + pt.y = b; + pt.z = a + b; + g_sink = pt.x * pt.y + pt.z; + return g_sink; +} + +/* Nested struct access. */ +NOINLINE int t3_struct_nested(s32 a, s32 b) { + struct inner { s32 lo; s32 hi; }; + struct outer { struct inner first; struct inner second; s32 tag; }; + struct outer s; + s.first.lo = a; + s.first.hi = b; + s.second.lo = a ^ b; + s.second.hi = a & b; + s.tag = (a | b); + g_sink = s.first.lo + s.first.hi + s.second.lo + s.second.hi + s.tag; + return g_sink; +} + +/* Array of structs. */ +NOINLINE int t3_array_of_structs(s32 a, s32 b) { + struct pair { s32 key; s32 val; }; + struct pair arr[4]; + for (int i = 0; i < 4; i++) { + arr[i].key = a + i; + arr[i].val = b * (i + 1); + } + s32 sum = 0; + for (int i = 0; i < 4; i++) + sum += arr[i].key * arr[i].val; + g_sink = sum; + return g_sink; +} + +/* Two-dimensional array indexing (on stack). */ +NOINLINE int t3_matrix_trace(s32 a, s32 b) { + s32 m[4][4]; + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + m[i][j] = a * i + b * j; + s32 trace = 0; + for (int i = 0; i < 4; i++) + trace += m[i][i]; + g_sink = trace; + return g_sink; +} + +/* Union reinterpretation. */ +NOINLINE int t3_union_reinterpret(s32 a, s32 b) { + union { s32 i; u32 u; } x; + x.i = a; + u32 hi16 = x.u >> 16; + u32 lo16 = x.u & 0xFFFF; + g_sink = (s32)(hi16 ^ lo16) + b; + return g_sink; +} + +/* Copy between two stack arrays. */ +NOINLINE int t3_array_copy(s32 a, s32 b) { + s32 src[8], dst[8]; + for (int i = 0; i < 8; i++) + src[i] = a + i * b; + for (int i = 0; i < 8; i++) + dst[i] = src[7 - i]; + s32 sum = 0; + for (int i = 0; i < 8; i++) + sum += dst[i]; + g_sink = sum; + return g_sink; +} diff --git a/tests_src/recompile_dataset/t4_calling.c b/tests_src/recompile_dataset/t4_calling.c new file mode 100644 index 00000000..e99929ed --- /dev/null +++ b/tests_src/recompile_dataset/t4_calling.c @@ -0,0 +1,121 @@ +/* + * t4_calling.c -- Calling convention and indirect-call triggers. + * + * Tests: static helper calls, function pointers, recursive calls, + * multi-level call chains. Each top-level function still follows the + * (s32 a, s32 b) -> g_sink contract. + * + * Internal helpers are also NOINLINE so the decompiler sees real calls + * rather than inlined code. + */ + +#include "harness_common.h" + +/* ── Static helpers (called by the test functions below) ───────── */ + +static NOINLINE s32 _helper_add(s32 x, s32 y) { return x + y; } +static NOINLINE s32 _helper_sub(s32 x, s32 y) { return x - y; } +static NOINLINE s32 _helper_mul(s32 x, s32 y) { return x * y; } +static NOINLINE s32 _helper_xor(s32 x, s32 y) { return x ^ y; } +static NOINLINE s32 _helper_neg(s32 x) { return -x; } + +/* ── Test functions ────────────────────────────────────────────── */ + +/* Call a static helper. */ +NOINLINE int t4_static_call(s32 a, s32 b) { + g_sink = _helper_add(a, b) + _helper_mul(a, b); + return g_sink; +} + +/* Call chain: f -> g -> h. */ +NOINLINE int t4_call_chain(s32 a, s32 b) { + s32 t1 = _helper_add(a, b); + s32 t2 = _helper_mul(t1, b); + s32 t3 = _helper_sub(t2, a); + g_sink = t3; + return g_sink; +} + +/* Function pointer dispatch. */ +typedef s32 (*binop_fn)(s32, s32); + +NOINLINE int t4_funcptr(s32 a, s32 b) { + binop_fn ops[4]; + ops[0] = _helper_add; + ops[1] = _helper_sub; + ops[2] = _helper_mul; + ops[3] = _helper_xor; + s32 idx = (u32)a & 3; + g_sink = ops[idx](a, b); + return g_sink; +} + +/* Simple recursion: factorial (clamped to small inputs). */ +static NOINLINE s32 _factorial(s32 n) { + if (n <= 1) return 1; + return n * _factorial(n - 1); +} + +NOINLINE int t4_recursion(s32 a, s32 b) { + s32 n = (a & 7) + 1; /* 1..8 */ + g_sink = _factorial(n) + b; + return g_sink; +} + +/* Mutual recursion: even/odd parity check. */ +static NOINLINE s32 _is_odd(s32 n); + +static NOINLINE s32 _is_even(s32 n) { + if (n == 0) return 1; + return _is_odd(n - 1); +} + +static NOINLINE s32 _is_odd(s32 n) { + if (n == 0) return 0; + return _is_even(n - 1); +} + +NOINLINE int t4_mutual_recursion(s32 a, s32 b) { + s32 n = (u32)a & 15; + g_sink = _is_even(n) + _is_odd((u32)b & 15); + return g_sink; +} + +/* Call with many distinct live values (register pressure). */ +NOINLINE int t4_register_pressure(s32 a, s32 b) { + s32 v0 = a + 1; + s32 v1 = b - 1; + s32 v2 = a ^ b; + s32 v3 = a & b; + s32 v4 = a | b; + s32 v5 = a * 3; + s32 v6 = b * 5; + s32 v7 = v0 + v1; + /* Use all values so none are optimised away. */ + g_sink = v0 + v1 + v2 + v3 + v4 + v5 + v6 + v7; + return g_sink; +} + +/* Conditional call: call different helpers depending on input. */ +NOINLINE int t4_conditional_call(s32 a, s32 b) { + s32 r; + if (a > 0) + r = _helper_add(a, b); + else if (a < 0) + r = _helper_sub(b, _helper_neg(a)); + else + r = _helper_xor(b, b); + g_sink = r; + return g_sink; +} + +/* Loop calling a helper each iteration. */ +NOINLINE int t4_loop_with_call(s32 a, s32 b) { + s32 acc = 0; + s32 n = (a & 7) + 1; + for (s32 i = 0; i < n; i++) { + acc = _helper_add(acc, _helper_mul(i, b)); + } + g_sink = acc; + return g_sink; +} diff --git a/tests_src/recompile_dataset/t5_patterns.c b/tests_src/recompile_dataset/t5_patterns.c new file mode 100644 index 00000000..38e55659 --- /dev/null +++ b/tests_src/recompile_dataset/t5_patterns.c @@ -0,0 +1,190 @@ +/* + * t5_patterns.c -- Real-world algorithmic patterns. + * + * Tests: manual strlen/memcpy, binary search, sorting, hashing, + * popcount, checksum, ring buffer. All operate on stack-local data. + */ + +#include "harness_common.h" + +/* Manual strlen on a stack-local "string" (array of bytes). */ +NOINLINE int t5_strlen(s32 a, s32 b) { + u8 buf[16]; + /* Fill buf: length depends on a. */ + s32 len = (u32)a & 15; + for (int i = 0; i < len; i++) + buf[i] = (u8)(b + i); + buf[len] = 0; + /* Manual strlen. */ + int n = 0; + while (buf[n] != 0) + n++; + g_sink = n; + return g_sink; +} + +/* Manual memcpy between two stack buffers. */ +NOINLINE int t5_memcpy(s32 a, s32 b) { + u8 src[16], dst[16]; + s32 len = ((u32)a & 15) + 1; + for (int i = 0; i < len; i++) + src[i] = (u8)(b ^ i); + /* Byte-by-byte copy. */ + for (int i = 0; i < len; i++) + dst[i] = src[i]; + s32 sum = 0; + for (int i = 0; i < len; i++) + sum += dst[i]; + g_sink = sum; + return g_sink; +} + +/* Iterative binary search on a sorted stack array. */ +NOINLINE int t5_bsearch(s32 a, s32 b) { + s32 arr[8]; + /* Build sorted array: 0, 3, 6, 9, 12, 15, 18, 21. */ + for (int i = 0; i < 8; i++) + arr[i] = i * 3; + s32 target = (u32)a & 31; + int lo = 0, hi = 7, result = -1; + while (lo <= hi) { + int mid = lo + (hi - lo) / 2; + if (arr[mid] == target) { + result = mid; + break; + } else if (arr[mid] < target) { + lo = mid + 1; + } else { + hi = mid - 1; + } + } + g_sink = result + b; + return g_sink; +} + +/* Bubble sort on a small stack array. */ +NOINLINE int t5_bubble_sort(s32 a, s32 b) { + s32 arr[8]; + for (int i = 0; i < 8; i++) + arr[i] = (a ^ (i * 2654435761u)) + b; + for (int i = 0; i < 7; i++) { + for (int j = 0; j < 7 - i; j++) { + if (arr[j] > arr[j + 1]) { + s32 tmp = arr[j]; + arr[j] = arr[j + 1]; + arr[j + 1] = tmp; + } + } + } + g_sink = arr[0] + arr[7]; + return g_sink; +} + +/* Simple hash (djb2-style) over a stack buffer. */ +NOINLINE int t5_hash(s32 a, s32 b) { + u8 buf[8]; + for (int i = 0; i < 8; i++) + buf[i] = (u8)(a + i * b); + u32 h = 5381; + for (int i = 0; i < 8; i++) + h = h * 33 + buf[i]; + g_sink = (s32)h; + return g_sink; +} + +/* Population count (Hamming weight). */ +NOINLINE int t5_popcount(s32 a, s32 b) { + u32 v = (u32)a; + s32 count = 0; + while (v) { + count += v & 1; + v >>= 1; + } + g_sink = count + b; + return g_sink; +} + +/* Branchless absolute value via arithmetic. */ +NOINLINE int t5_abs_branchless(s32 a, s32 b) { + s32 mask = a >> 31; + s32 abs_a = (a ^ mask) - mask; + mask = b >> 31; + s32 abs_b = (b ^ mask) - mask; + g_sink = abs_a + abs_b; + return g_sink; +} + +/* Simple checksum: XOR + rotate accumulator. */ +NOINLINE int t5_checksum(s32 a, s32 b) { + u32 data[4]; + data[0] = (u32)a; + data[1] = (u32)b; + data[2] = (u32)(a ^ b); + data[3] = (u32)(a + b); + u32 acc = 0; + for (int i = 0; i < 4; i++) { + acc ^= data[i]; + /* Rotate left by 7. */ + acc = (acc << 7) | (acc >> 25); + } + g_sink = (s32)acc; + return g_sink; +} + +/* Ring buffer: write then read. */ +NOINLINE int t5_ring_buffer(s32 a, s32 b) { + s32 buf[8]; + s32 head = 0; + /* Write (a & 15) + 1 items. */ + s32 nwrites = ((u32)a & 7) + 1; + for (s32 i = 0; i < nwrites; i++) { + buf[head & 7] = b + i; + head++; + } + /* Read all written items. */ + s32 sum = 0; + for (s32 i = 0; i < nwrites; i++) { + sum += buf[i & 7]; + } + g_sink = sum; + return g_sink; +} + +/* Min and max of a stack array. */ +NOINLINE int t5_minmax(s32 a, s32 b) { + s32 arr[8]; + for (int i = 0; i < 8; i++) + arr[i] = a ^ (i * 0x45D9F3B + b); + s32 mn = arr[0], mx = arr[0]; + for (int i = 1; i < 8; i++) { + if (arr[i] < mn) mn = arr[i]; + if (arr[i] > mx) mx = arr[i]; + } + g_sink = mx - mn; + return g_sink; +} + +/* GCD via Euclidean algorithm. */ +NOINLINE int t5_gcd(s32 a, s32 b) { + u32 x = (u32)a | 1; /* ensure nonzero */ + u32 y = (u32)b | 1; + while (y != 0) { + u32 t = y; + y = x % y; + x = t; + } + g_sink = (s32)x; + return g_sink; +} + +/* Bit reversal of a 32-bit value. */ +NOINLINE int t5_bitreverse(s32 a, s32 b) { + u32 v = (u32)a; + u32 r = 0; + for (int i = 0; i < 32; i++) { + r = (r << 1) | (v & 1); + v >>= 1; + } + g_sink = (s32)r + b; + return g_sink; +}