From 93ebde18e1bed49d2c0e13560f29534e67cf216a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Wed, 10 Jun 2026 21:54:05 +0300 Subject: [PATCH] checkasm: Trim out unused upstream files We only need the source files themselves; keep them and the LICENSE file. --- tests/checkasm/ext/.clang-format | 23 - .../checkasm/ext/.github/workflows/build.yml | 228 ------ tests/checkasm/ext/.gitignore | 3 - tests/checkasm/ext/.gitlab-ci.yml | 441 ---------- tests/checkasm/ext/README.md | 172 ---- .../ext/crossfiles/aarch64-android.meson | 15 - .../ext/crossfiles/aarch64-linux-clang.meson | 16 - .../ext/crossfiles/aarch64-linux.meson | 12 - .../ext/crossfiles/aarch64-w64-mingw32.meson | 16 - .../checkasm/ext/crossfiles/arm-android.meson | 15 - .../ext/crossfiles/armv7-w64-mingw32.meson | 16 - .../ext/crossfiles/i686-linux32.meson | 15 - .../ext/crossfiles/i686-w64-mingw32.meson | 16 - .../ext/crossfiles/loongarch64-linux.meson | 13 - .../ext/crossfiles/riscv64-linux-clang.meson | 16 - .../ext/crossfiles/riscv64-linux.meson | 12 - tests/checkasm/ext/crossfiles/wasm32.meson | 15 - tests/checkasm/ext/crossfiles/wasm64.meson | 15 - .../ext/crossfiles/x86_64-w64-mingw32.meson | 16 - tests/checkasm/ext/docs/Doxyfile.in | 20 - tests/checkasm/ext/docs/DoxygenLayout.xml | 49 -- tests/checkasm/ext/docs/benchmarking.md | 492 ------------ tests/checkasm/ext/docs/getting-started.md | 280 ------- tests/checkasm/ext/docs/integration.md | 274 ------- tests/checkasm/ext/docs/introduction.md | 148 ---- tests/checkasm/ext/docs/meson.build | 77 -- tests/checkasm/ext/docs/writing-tests.md | 753 ------------------ tests/checkasm/ext/ext-build-test.make | 64 -- tests/checkasm/ext/gen-arm-core-table.sh | 63 -- .../checkasm/ext/include/checkasm/meson.build | 65 -- tests/checkasm/ext/meson.build | 134 ---- tests/checkasm/ext/meson_options.txt | 35 - tests/checkasm/ext/src/meson.build | 261 ------ tests/checkasm/ext/tests/arm/32/tests.c | 222 ------ tests/checkasm/ext/tests/arm/32/tests_asm.S | 108 --- tests/checkasm/ext/tests/arm/64/tests.c | 387 --------- tests/checkasm/ext/tests/arm/64/tests_asm.S | 247 ------ tests/checkasm/ext/tests/generic.c | 319 -------- tests/checkasm/ext/tests/meson.build | 93 --- tests/checkasm/ext/tests/riscv/tests.c | 222 ------ tests/checkasm/ext/tests/riscv/tests_asm.S | 96 --- tests/checkasm/ext/tests/selftest.c | 62 -- tests/checkasm/ext/tests/tests.h | 114 --- tests/checkasm/ext/tests/x86/tests.c | 220 ----- tests/checkasm/ext/tests/x86/tests_asm.asm | 113 --- 45 files changed, 5993 deletions(-) delete mode 100644 tests/checkasm/ext/.clang-format delete mode 100644 tests/checkasm/ext/.github/workflows/build.yml delete mode 100644 tests/checkasm/ext/.gitignore delete mode 100644 tests/checkasm/ext/.gitlab-ci.yml delete mode 100644 tests/checkasm/ext/README.md delete mode 100644 tests/checkasm/ext/crossfiles/aarch64-android.meson delete mode 100644 tests/checkasm/ext/crossfiles/aarch64-linux-clang.meson delete mode 100644 tests/checkasm/ext/crossfiles/aarch64-linux.meson delete mode 100644 tests/checkasm/ext/crossfiles/aarch64-w64-mingw32.meson delete mode 100644 tests/checkasm/ext/crossfiles/arm-android.meson delete mode 100644 tests/checkasm/ext/crossfiles/armv7-w64-mingw32.meson delete mode 100644 tests/checkasm/ext/crossfiles/i686-linux32.meson delete mode 100644 tests/checkasm/ext/crossfiles/i686-w64-mingw32.meson delete mode 100644 tests/checkasm/ext/crossfiles/loongarch64-linux.meson delete mode 100644 tests/checkasm/ext/crossfiles/riscv64-linux-clang.meson delete mode 100644 tests/checkasm/ext/crossfiles/riscv64-linux.meson delete mode 100644 tests/checkasm/ext/crossfiles/wasm32.meson delete mode 100644 tests/checkasm/ext/crossfiles/wasm64.meson delete mode 100644 tests/checkasm/ext/crossfiles/x86_64-w64-mingw32.meson delete mode 100644 tests/checkasm/ext/docs/Doxyfile.in delete mode 100644 tests/checkasm/ext/docs/DoxygenLayout.xml delete mode 100644 tests/checkasm/ext/docs/benchmarking.md delete mode 100644 tests/checkasm/ext/docs/getting-started.md delete mode 100644 tests/checkasm/ext/docs/integration.md delete mode 100644 tests/checkasm/ext/docs/introduction.md delete mode 100644 tests/checkasm/ext/docs/meson.build delete mode 100644 tests/checkasm/ext/docs/writing-tests.md delete mode 100644 tests/checkasm/ext/ext-build-test.make delete mode 100755 tests/checkasm/ext/gen-arm-core-table.sh delete mode 100644 tests/checkasm/ext/include/checkasm/meson.build delete mode 100644 tests/checkasm/ext/meson.build delete mode 100644 tests/checkasm/ext/meson_options.txt delete mode 100644 tests/checkasm/ext/src/meson.build delete mode 100644 tests/checkasm/ext/tests/arm/32/tests.c delete mode 100644 tests/checkasm/ext/tests/arm/32/tests_asm.S delete mode 100644 tests/checkasm/ext/tests/arm/64/tests.c delete mode 100644 tests/checkasm/ext/tests/arm/64/tests_asm.S delete mode 100644 tests/checkasm/ext/tests/generic.c delete mode 100644 tests/checkasm/ext/tests/meson.build delete mode 100644 tests/checkasm/ext/tests/riscv/tests.c delete mode 100644 tests/checkasm/ext/tests/riscv/tests_asm.S delete mode 100644 tests/checkasm/ext/tests/selftest.c delete mode 100644 tests/checkasm/ext/tests/tests.h delete mode 100644 tests/checkasm/ext/tests/x86/tests.c delete mode 100644 tests/checkasm/ext/tests/x86/tests_asm.asm diff --git a/tests/checkasm/ext/.clang-format b/tests/checkasm/ext/.clang-format deleted file mode 100644 index 5ffa89314b..0000000000 --- a/tests/checkasm/ext/.clang-format +++ /dev/null @@ -1,23 +0,0 @@ ---- -BasedOnStyle: WebKit -IndentWidth: 4 -IndentPPDirectives: BeforeHash -PPIndentWidth: 2 -ColumnLimit: 90 -AllowShortFunctionsOnASingleLine: false -AllowShortLoopsOnASingleLine: false -AllowShortCaseLabelsOnASingleLine: true -AlignConsecutiveDeclarations: true -AlignConsecutiveAssignments: true -AlignConsecutiveMacros: true -AlignOperands: AlignAfterOperator -AlignEscapedNewlines: Right -AlignAfterOpenBracket: Align -AlignArrayOfStructures: Left -AlignTrailingComments: true -AlignConsecutiveBitFields: true -AlignConsecutiveShortCaseStatements: - Enabled: true -PointerAlignment: Right -SpaceAfterCStyleCast: true -QualifierAlignment: Left diff --git a/tests/checkasm/ext/.github/workflows/build.yml b/tests/checkasm/ext/.github/workflows/build.yml deleted file mode 100644 index fd0b93edac..0000000000 --- a/tests/checkasm/ext/.github/workflows/build.yml +++ /dev/null @@ -1,228 +0,0 @@ -name: Run tests with MSVC - -on: - push: - -jobs: - msvc-x86: - runs-on: windows-latest - strategy: - fail-fast: false - matrix: - arch: - - x86 - - x64 - steps: - - name: Install prerequisites - run: | - pip install meson - choco install nasm - echo "C:\Program Files\NASM" | Out-File -FilePath $Env:GITHUB_PATH -Encoding utf8 -Append - - name: Set up the MSVC environment - uses: ilammy/msvc-dev-cmd@v1 - with: - arch: ${{matrix.arch}} - - uses: actions/checkout@v6 - - name: Build and test - run: | - meson setup build --buildtype release ` - --werror ` - -Ddefault_library=both - cd build - ninja - meson test -v - - msvc-cross-arm64: - # Test cross compilation with MSVC; here, we don't have any working - # host compiler available, as the only compiler in $PATH is a cross - # compiler. - runs-on: windows-latest - steps: - - name: Install prerequisites - run: | - pip install meson - - name: Set up the MSVC environment - uses: ilammy/msvc-dev-cmd@v1 - with: - arch: amd64_arm64 - - uses: actions/checkout@v6 - - name: Checkout gas-preprocessor - uses: actions/checkout@v6 - with: - repository: ffmpeg/gas-preprocessor - ref: f85b94087d168564b777877dfb3a0eeea3d57678 - path: gas-preprocessor - - name: Add gas-preprocessor to path - run: | - echo "$PWD\gas-preprocessor" | Out-File -FilePath $Env:GITHUB_PATH -Encoding utf8 -Append - - name: Create cross file - shell: bash - run: | - cat >cross.txt <cross.txt < /dev/null || true - - git remote add upstream https://code.videolan.org/videolan/checkasm.git - - git fetch -q upstream master - - for i in $(git rev-list HEAD ^upstream/master); do - echo "Checking commit message of $i"; - msg="$(git log --format=%B -n 1 $i)"; - if [ -n "$(echo "$msg" | awk "NR==2")" ]; then - echo "Malformed commit message in $i, second line must be empty"; - exit 1; - fi; - if echo "$msg" | head -1 | grep -q '\.$'; then - echo "Malformed commit message in $i, trailing period in subject line"; - exit 1; - fi; - done - -x86inc-check: - extends: .debian-amd64-common - stage: style - script: - - git remote rm x86inc 2> /dev/null || true - - git remote add x86inc https://code.videolan.org/videolan/x86inc.asm.git - - git fetch -q x86inc master - - git diff --exit-code x86inc/master:x86inc.asm src/x86/x86inc.asm - allow_failure: true - -build-docs: - extends: .debian-amd64-common - stage: build - artifacts: - paths: - - build/docs/html - expire_in: 1 day - script: - - meson setup build -Ddocs=enabled - - cd build && meson compile docs - -.test-common: - script: - - meson setup build --buildtype release - --default-library both - --werror - - cd build && ninja - - meson test -v - - time meson test --bench -v - -test-debian: - extends: - - .test-common - - .debian-amd64-common - tags: - - docker - - avx2 - - amd64 - artifacts: - paths: - - build/ - expire_in: 1 day - -test-debian-static: - extends: .debian-amd64-common - script: - - meson setup build --buildtype release - --default-library static - --werror - - cd build && ninja - - meson test -v - - time meson test --bench -v - - nm -A -g src/libcheckasm.a | grep " [ABCDGRST] " | (! grep -v " _*checkasm_") - -test-debian-notests: - extends: .debian-amd64-common - script: - - meson setup build --buildtype release - --default-library shared - -Dtests=disabled - --werror - - cd build && ninja - - meson test -v - -test-debian32: - extends: .debian-amd64-common - script: - - meson setup build --buildtype release - --werror - --cross-file crossfiles/i686-linux32.meson - - cd build && ninja - - meson test -v - - time meson test --bench -v - artifacts: - paths: - - build/ - expire_in: 1 day - -test-debian-avx: - extends: - - .test-common - - .debian-amd64-common - tags: - - docker - - avx2 - - amd64 - variables: - CFLAGS: '-mavx' - -test-debian-avx512: - extends: - - .test-common - - .debian-amd64-common - tags: - - docker - - amd64-avx512 - variables: - CFLAGS: '-mavx' - -test-debian-clang: - extends: - - .test-common - - .debian-amd64-common - variables: - CC: clang - CC_LD: mold - -test-debian-qemu: - extends: .debian-amd64-common - tags: - - docker - - avx2 - - amd64 - script: - - meson setup build --buildtype debug - - cd build && ninja - - exit_code=0 - - meson test -v --wrapper 'qemu-x86_64 -cpu Conroe' || exit_code=$((exit_code + $?)) - - meson test -v --wrapper 'qemu-x86_64 -cpu Penryn' || exit_code=$((exit_code + $?)) - - time meson test --bench -v --wrapper 'qemu-x86_64 -cpu Conroe' || exit_code=$((exit_code + $?)) - - time meson test --bench -v --wrapper 'qemu-x86_64 -cpu Penryn' || exit_code=$((exit_code + $?)) - - if [ $exit_code -ne 0 ]; then exit $exit_code; fi - -test-win: - extends: .debian-amd64-common - script: - - wineserver -p && wine wineboot - - meson setup build --buildtype release - --werror - --libdir lib - --prefix "$(pwd)/build/checkasm_install" - --cross-file crossfiles/${CROSSFILE}.meson - --default-library both - - cd build && ninja install - - meson test -v - - time meson test --bench -v - - ${CROSSFILE}-nm -A -g src/libcheckasm.a | grep " [ABCDGRST] " | (! grep -E -v " \.| _*checkasm_") - artifacts: - name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG" - paths: - - build/checkasm_install/ - expire_in: 1 week - parallel: - matrix: - - CROSSFILE: [i686-w64-mingw32, x86_64-w64-mingw32] - -build-win-arm: - extends: .debian-llvm-mingw-common - stage: build - script: - - meson setup build --buildtype release - --werror - --libdir lib - --prefix "$(pwd)/build/checkasm_install" - --cross-file crossfiles/${CROSSFILE}.meson - --default-library both - - cd build && ninja install - - ${CROSSFILE}-nm -A -g src/libcheckasm.a | grep " [ABCDGRST] " | (! grep -E -v " \.| _*checkasm_") - artifacts: - name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG" - paths: - - build/checkasm_install/ - expire_in: 1 week - parallel: - matrix: - - CROSSFILE: [armv7-w64-mingw32, aarch64-w64-mingw32] - -.build-android-common: - extends: .android-common - stage: build - script: - - meson setup build --buildtype release - --werror - --libdir lib - --prefix "$(pwd)/build/checkasm_install" - --cross-file $CROSSFILE - --default-library both - - cd build && ninja install - -build-android-armv7: - extends: .build-android-common - variables: - CROSSFILE: crossfiles/arm-android.meson - rules: - - if: '$CI_COMMIT_BRANCH' - -build-android-aarch64: - extends: .build-android-common - variables: - CROSSFILE: crossfiles/aarch64-android.meson - rules: - - if: '$CI_COMMIT_BRANCH' - -test-debian-aarch64: - extends: - - .test-common - - .debian-aarch64-common - -test-debian-aarch64-clang-5: - extends: - - .test-common - - .debian-aarch64-common - variables: - CC: clang-5.0 - CFLAGS: '-integrated-as' - -test-debian-aarch64-clang-18: - extends: .debian-amd64-common - variables: - QEMU_LD_PREFIX: /usr/aarch64-linux-gnu/ - script: - - meson setup build --buildtype release - --werror - --cross-file crossfiles/aarch64-linux-clang.meson - - cd build && ninja - - meson test -v - - time meson test --bench -v - -.test-macos-common: - stage: test - script: - - meson setup build --buildtype release - --default-library both - --werror - - cd build && ninja - - meson test -v - - time meson test --bench -v - -test-macos-x86_64: - extends: .test-macos-common - tags: - - amd64 - - macos - -test-macos-arm64: - extends: .test-macos-common - tags: - - macos-xcode26 - -test-debian-armv7: - extends: .debian-armv7-common - script: - - linux32 meson setup build --buildtype release - --werror - - cd build && ninja - - meson test -v - - time meson test --bench -v - -test-debian-armv7-clang-5: - extends: .debian-armv7-common - variables: - CC: clang-5.0 - CFLAGS: '-integrated-as' - script: - - linux32 meson setup build --buildtype release - - cd build && ninja - - meson test -v - - time meson test --bench -v - -test-debian-ppc64le: - extends: - - .test-common - - .debian-ppc64le-common - variables: - CC: gcc-13 - -test-debian-riscv64: - extends: .debian-amd64-common - variables: - QEMU_LD_PREFIX: /usr/riscv64-linux-gnu/ - script: - - meson setup build --buildtype release - --default-library both - --werror - --cross-file crossfiles/${CROSSFILE}.meson - - cd build && ninja - - meson test -v - - time meson test --bench -v - parallel: - matrix: - - CROSSFILE: [ riscv64-linux, riscv64-linux-clang ] - QEMU_CPU: - - rv64,v=true,vext_spec=v1.0,vlen=128,elen=64 - - rv64,v=true,vext_spec=v1.0,vlen=256,elen=64 - -test-debian-loongarch64: - extends: - - .debian-amd64-common - variables: - QEMU_CPU: max-loongarch-cpu - QEMU_LD_PREFIX: /opt/cross-tools/target/ - script: - - meson setup build --buildtype release - --default-library both - --werror - --cross-file crossfiles/loongarch64-linux.meson - - cd build && ninja - - meson test -v - - time meson test --bench -v - -test-debian-asan: - extends: .debian-amd64-common - variables: - ASAN_OPTIONS: 'detect_leaks=0' - script: - - meson setup build --buildtype debugoptimized - -Db_sanitize=address - - cd build && ninja - - exit_code=0 - - meson test -v || exit_code=$((exit_code + $?)) - - time meson test --bench -v || exit_code=$((exit_code + $?)) - - if [ $exit_code -ne 0 ]; then exit $exit_code; fi - -test-ext-build: - extends: .debian-amd64-common - script: - - mkdir -p build && cd build - - make -f ../ext-build-test.make NASM_FMT=elf64 -j$(getconf _NPROCESSORS_ONLN) EXTRA_CFLAGS=-Werror - - ./checkasm-selftest - -test-dav1d: - extends: .debian-amd64-common - script: - - git clone --depth 1 --branch master https://code.videolan.org/videolan/dav1d.git - - cd dav1d - - ln -s ../.. subprojects/checkasm - - meson setup build --buildtype debugoptimized - --werror - -Dtrim_dsp=false - - cd build && ninja - - meson test -v checkasm - -test-dav2d: - extends: .debian-amd64-common - script: - - git clone --depth 1 --branch main https://code.videolan.org/videolan/dav2d.git - - cd dav2d - - ln -s ../.. subprojects/checkasm - - meson setup build --buildtype debugoptimized - --werror - -Dtrim_dsp=false - - cd build && ninja - - meson test -v checkasm - -test-ffmpeg: - extends: .debian-amd64-common - script: - - git clone --depth 1 --branch master https://code.ffmpeg.org/ffmpeg/ffmpeg - - cd ffmpeg - - rm -rf tests/checkasm/ext - - ln -s ../../.. tests/checkasm/ext - - ./configure --enable-gpl - - make -j$(getconf _NPROCESSORS_ONLN) run-checkasm - -deploy-docs: - extends: .debian-amd64-common - stage: deploy - needs: ["build-docs"] - rules: - - if: '$CI_COMMIT_BRANCH == "master"' - script: - - mv build/docs/html public - pages: - publish: public diff --git a/tests/checkasm/ext/README.md b/tests/checkasm/ext/README.md deleted file mode 100644 index 356b22c1d8..0000000000 --- a/tests/checkasm/ext/README.md +++ /dev/null @@ -1,172 +0,0 @@ -# checkasm - for all your asm checking needs - -**checkasm** is a tool for verifying the correctness of assembly code, as well as performance benchmarking. - -## Usage - -For a complete guide on getting started with checkasm, see the -[Getting Started](https://checkasm.videolan.me/getting_started.html) page. - -``` -Usage: checkasm [options...] - Use fixed value to seed the PRNG -Options: - --affinity= Run the process on CPU - --bench -b Benchmark the tested functions - --csv, --tsv, --json, Choose output format for benchmarks - --html - --function= -f Test only the functions matching - --help -h Print this usage info - --list-cpu-flags List available cpu flags - --list-functions List available functions - --list-tests List available tests - --duration=<μs> Benchmark duration (per function) in μs - --repeat[=] Repeat tests N times, on successive seeds - --test= -t Test only - --verbose -v Print verbose timing info and failure data -``` - -## Supported platforms - -The following architectures are explicitly supported for asm verification, with the listed detection mechanisms for typical asm mistakes: - -- **x86, x86-64**: registers, stack, AVX2, MMX/FPU state -- **ARM, ARM64 (aarch64)**: registers, stack, VFP state -- **RISC-V**: registers, stack, vector state -- **LoongArch (32, 64)**: registers -- **PowerPC (64le)**: *none* - -In addition, hardware timers are available for benchmarking purposes on all of the listed platforms (except RISCV-V), with fall-backs to generic OS-specific APIs. - -## Integration into your project - -You can either load checkasm as a library (e.g. via `pkg-config`), or include -it directly in your project's build system. See the -[Getting Started: Installation](https://checkasm.videolan.me/getting_started.html#installation) -and [Integration Guide](https://checkasm.videolan.me/integration.html) for more information. - -### Code example - -Here is what short example test demonstrating the public API. Check the -[Quick Start Example](https://checkasm.videolan.me/getting_started.html#quick_start) -for a full example. - -```c -static void test_add8(const CheckasmCpu cpu) -{ - #define WIDTH 1024 - - // Declare aligned buffers for testing - CHECKASM_ALIGN(uint8_t src1[WIDTH]); - CHECKASM_ALIGN(uint8_t src2[WIDTH]); - CHECKASM_ALIGN(uint16_t dst_c[WIDTH]); - CHECKASM_ALIGN(uint16_t dst_a[WIDTH]); - - // Declare the function signature - checkasm_declare(void, uint16_t *, const uint8_t *, const uint8_t *, size_t); - - if (checkasm_check_func(get_add8_func(cpu), "add_8")) { - // Initialize source buffers with quasi-random test vectors - INITIALIZE_BUF(src1); - INITIALIZE_BUF(src2); - - // Test with various buffer sizes - for (int w = 1; w <= WIDTH; w <<= 1) { - // Clear destination buffers before each test - CLEAR_BUF(dst_c); - CLEAR_BUF(dst_a); - - // Call reference and optimized implementations - checkasm_call_ref(dst_c, src1, src2, w); - checkasm_call_new(dst_a, src1, src2, w); - - // Compare results - checkasm_check1d will report any mismatches - checkasm_check1d(uint16_t, dst_c, dst_a, w, "sum"); - } - - // Benchmark the optimized version on the largest buffer size - checkasm_bench_new(checkasm_alternate(dst_c, dst_a), src1, src2, WIDTH); - } -} -``` - -For a complete tutorial on writing tests, read the -[Writing Tests](https://checkasm.videolan.me/writing_tests.html) page. - -### Example outputs - -This is what the output looks like, when using `--verbose` mode to print all -timing data (on a pretty noisy/busy system). For more information about the -interpretation and usefulness of these results, refer to the -[Benchmarking](https://checkasm.videolan.me/benchmarking.html) guide. - -``` -checkasm: - - CPU: AMD Ryzen 9 9950X3D 16-Core Processor (00B40F40) - - Timing source: x86 (rdtsc) - - Timing overhead: 79.3 +/- 17.01 cycles per iteration - - Timing resolution: 0.2326 +/- 0.023 ns/cycle (4300 +/- 423.1 MHz) - - Bench duration: 2000 µs per function (8620136 cycles) - - Random seed: 3173025505 -SSE2: - - msac.decode_symbol [OK] - - msac.decode_bool [OK] - - msac.decode_hi_tok [OK] -AVX2: - - msac.decode_symbol [OK] -checkasm: all 8 tests passed -Benchmark results: - name cycles +/- stddev time (nanoseconds) (vs ref) - msac_decode_bool_c: 7.3 +/- 0.5 2 ns +/- 0 - msac_decode_bool_sse2: 5.4 +/- 0.6 1 ns +/- 0 ( 1.35x) - msac_decode_bool_adapt_c: 7.1 +/- 0.6 2 ns +/- 0 - msac_decode_bool_adapt_sse2: 7.4 +/- 0.6 2 ns +/- 0 ( 0.97x) - msac_decode_bool_equi_c: 5.9 +/- 0.6 1 ns +/- 0 - msac_decode_bool_equi_sse2: 4.0 +/- 0.6 1 ns +/- 0 ( 1.48x) - msac_decode_hi_tok_c: 92.9 +/- 19.7 22 ns +/- 5 - msac_decode_hi_tok_sse2: 52.3 +/- 7.1 12 ns +/- 2 ( 1.78x) - msac_decode_symbol_adapt4_c: 19.3 +/- 1.2 4 ns +/- 1 - msac_decode_symbol_adapt4_sse2: 12.8 +/- 0.6 3 ns +/- 0 ( 1.51x) - msac_decode_symbol_adapt8_c: 27.6 +/- 1.1 6 ns +/- 1 - msac_decode_symbol_adapt8_sse2: 13.2 +/- 0.6 3 ns +/- 0 ( 2.10x) - msac_decode_symbol_adapt16_c: 44.1 +/- 1.2 10 ns +/- 1 - msac_decode_symbol_adapt16_sse2: 14.6 +/- 0.6 3 ns +/- 0 ( 3.03x) - msac_decode_symbol_adapt16_avx2: 12.8 +/- 0.6 3 ns +/- 0 ( 3.45x) -``` - -And this is what a failure could look like: - -``` -checkasm: - - CPU: AMD Ryzen 9 9950X3D 16-Core Processor (00B40F40) - - Random seed: 3689286425 -x86: - - x86.copy [OK] -FAILURE: sigill_x86 (illegal instruction) - - x86.sigill [FAILED] -FAILURE: corrupt_stack_x86 (stack corruption) - - x86.corrupt_stack [FAILED] -FAILURE: clobber_r9_x86 (failed to preserve register: r9) -FAILURE: clobber_r10_x86 (failed to preserve register: r10) -FAILURE: clobber_r11_x86 (failed to preserve register: r11) -FAILURE: clobber_r12_x86 (failed to preserve register: r12) -FAILURE: clobber_r13_x86 (failed to preserve register: r13) -FAILURE: clobber_r14_x86 (failed to preserve register: r14) - - x86.clobber [FAILED] -FAILURE: underwrite_64_x86 (../tests/generic.c:56) -dst data (64x1): - 0: 45 b3 dc aa 68 90 a4 5d cf d9 d9 9b d0 34 45 b3 dc aa 68 90 a4 5d cf d9 d9 9b d0 34 .............. - 1b 88 37 0f 14 f1 77 f4 94 bf 53 a3 21 3f 1b 88 37 0f 14 f1 77 f4 94 bf 53 a3 21 3f .............. - b5 64 77 fc 75 6b a9 2a 38 8a c7 e8 f9 1d b5 64 77 fc 75 6b a9 2a 38 8a c7 e8 f9 1d .............. - b4 80 d6 f4 34 1d c6 2b fd a8 e5 83 51 bb b4 80 d6 f4 34 1d c6 2b fd a8 e5 83 51 bb .............. - 72 f6 e5 c1 47 80 63 f2 72 f6 e5 c1 aa aa aa aa ....xxxx - - generic.underwrite [FAILED] -``` - -## History and authors - -This project was forked from [dav1d's](https://code.videolan.org/videolan/dav1d) internal copy of checkasm, which was itself a more-or-less up-to-date version of the various checkasm versions that existed in FFmpeg, x264 and so on. - -This choice was made because dav1d was the closest to being feature complete, while also being permissively licensed and using a modern CI and build system. Some changes have been ported over from FFmpeg's copy of checkasm, with permission to relicense. - -checkasm's original authors include Henrik Gramner, Loren Merritt, Fiona Glaser and others. This fork is maintained by Niklas Haas and Martin Storsjö. diff --git a/tests/checkasm/ext/crossfiles/aarch64-android.meson b/tests/checkasm/ext/crossfiles/aarch64-android.meson deleted file mode 100644 index abb64e662f..0000000000 --- a/tests/checkasm/ext/crossfiles/aarch64-android.meson +++ /dev/null @@ -1,15 +0,0 @@ -[binaries] -c = 'aarch64-linux-android21-clang' -cpp = 'aarch64-linux-android21-clang++' -ar = 'llvm-ar' -strip = 'llvm-strip' -pkgconfig = 'pkg-config' - -[properties] -needs_exe_wrapper = true - -[host_machine] -system = 'android' -cpu_family = 'aarch64' -cpu = 'aarch64' -endian = 'little' diff --git a/tests/checkasm/ext/crossfiles/aarch64-linux-clang.meson b/tests/checkasm/ext/crossfiles/aarch64-linux-clang.meson deleted file mode 100644 index 2d218c7cb4..0000000000 --- a/tests/checkasm/ext/crossfiles/aarch64-linux-clang.meson +++ /dev/null @@ -1,16 +0,0 @@ -[binaries] -c = 'clang' -cpp = 'clang++' -ar = 'aarch64-linux-gnu-ar' -strip = 'aarch64-linux-gnu-strip' -exe_wrapper = 'qemu-aarch64' - -[properties] -c_args = '-target aarch64-linux-gnu' -c_link_args = '-target aarch64-linux-gnu' - -[host_machine] -system = 'linux' -cpu_family = 'aarch64' -cpu = 'aarch64' -endian = 'little' diff --git a/tests/checkasm/ext/crossfiles/aarch64-linux.meson b/tests/checkasm/ext/crossfiles/aarch64-linux.meson deleted file mode 100644 index 7dae0fc874..0000000000 --- a/tests/checkasm/ext/crossfiles/aarch64-linux.meson +++ /dev/null @@ -1,12 +0,0 @@ -[binaries] -c = 'aarch64-linux-gnu-gcc' -cpp = 'aarch64-linux-gnu-g++' -ar = 'aarch64-linux-gnu-ar' -strip = 'aarch64-linux-gnu-strip' -exe_wrapper = 'qemu-aarch64' - -[host_machine] -system = 'linux' -cpu_family = 'aarch64' -cpu = 'aarch64' -endian = 'little' diff --git a/tests/checkasm/ext/crossfiles/aarch64-w64-mingw32.meson b/tests/checkasm/ext/crossfiles/aarch64-w64-mingw32.meson deleted file mode 100644 index 23927cc634..0000000000 --- a/tests/checkasm/ext/crossfiles/aarch64-w64-mingw32.meson +++ /dev/null @@ -1,16 +0,0 @@ -[binaries] -c = 'aarch64-w64-mingw32-clang' -cpp = 'aarch64-w64-mingw32-clang++' -ar = 'aarch64-w64-mingw32-ar' -strip = 'aarch64-w64-mingw32-strip' -pkgconfig = 'pkg-config' -windres = 'aarch64-w64-mingw32-windres' - -[properties] -c_link_args = ['-static-libgcc'] - -[host_machine] -system = 'windows' -cpu_family = 'aarch64' -cpu = 'aarch64' -endian = 'little' diff --git a/tests/checkasm/ext/crossfiles/arm-android.meson b/tests/checkasm/ext/crossfiles/arm-android.meson deleted file mode 100644 index ed94f698ec..0000000000 --- a/tests/checkasm/ext/crossfiles/arm-android.meson +++ /dev/null @@ -1,15 +0,0 @@ -[binaries] -c = 'armv7a-linux-androideabi21-clang' -cpp = 'armv7a-linux-androideabi21-clang++' -ar = 'llvm-ar' -strip = 'llvm-strip' -pkgconfig = 'pkg-config' - -[properties] -needs_exe_wrapper = true - -[host_machine] -system = 'android' -cpu_family = 'arm' -cpu = 'arm' -endian = 'little' diff --git a/tests/checkasm/ext/crossfiles/armv7-w64-mingw32.meson b/tests/checkasm/ext/crossfiles/armv7-w64-mingw32.meson deleted file mode 100644 index 191aa2efd3..0000000000 --- a/tests/checkasm/ext/crossfiles/armv7-w64-mingw32.meson +++ /dev/null @@ -1,16 +0,0 @@ -[binaries] -c = 'armv7-w64-mingw32-clang' -cpp = 'armv7-w64-mingw32-clang++' -ar = 'armv7-w64-mingw32-ar' -strip = 'armv7-w64-mingw32-strip' -pkgconfig = 'pkg-config' -windres = 'armv7-w64-mingw32-windres' - -[properties] -c_link_args = ['-static-libgcc'] - -[host_machine] -system = 'windows' -cpu_family = 'arm' -cpu = 'armv7' -endian = 'little' diff --git a/tests/checkasm/ext/crossfiles/i686-linux32.meson b/tests/checkasm/ext/crossfiles/i686-linux32.meson deleted file mode 100644 index 09bbde3a6c..0000000000 --- a/tests/checkasm/ext/crossfiles/i686-linux32.meson +++ /dev/null @@ -1,15 +0,0 @@ -[binaries] -c = 'gcc' -cpp = 'g++' -ar = 'ar' -strip = 'strip' - -[host_machine] -system = 'linux' -cpu_family = 'x86' -cpu = 'i686' -endian = 'little' - -[built-in options] -c_link_args = ['-m32', '-Wl,-z,text'] -c_args = ['-m32'] diff --git a/tests/checkasm/ext/crossfiles/i686-w64-mingw32.meson b/tests/checkasm/ext/crossfiles/i686-w64-mingw32.meson deleted file mode 100644 index 3de8afaa0d..0000000000 --- a/tests/checkasm/ext/crossfiles/i686-w64-mingw32.meson +++ /dev/null @@ -1,16 +0,0 @@ -[binaries] -c = 'i686-w64-mingw32-gcc' -cpp = 'i686-w64-mingw32-g++' -ar = 'i686-w64-mingw32-ar' -strip = 'i686-w64-mingw32-strip' -windres = 'i686-w64-mingw32-windres' -exe_wrapper = 'wine' - -[properties] -c_link_args = ['-static-libgcc'] - -[host_machine] -system = 'windows' -cpu_family = 'x86' -cpu = 'i686' -endian = 'little' diff --git a/tests/checkasm/ext/crossfiles/loongarch64-linux.meson b/tests/checkasm/ext/crossfiles/loongarch64-linux.meson deleted file mode 100644 index 04c29acf1c..0000000000 --- a/tests/checkasm/ext/crossfiles/loongarch64-linux.meson +++ /dev/null @@ -1,13 +0,0 @@ -[binaries] -c = 'loongarch64-unknown-linux-gnu-gcc' -cpp = 'loongarch64-unknown-linux-gnu-c++' -ar = 'loongarch64-unknown-linux-gnu-ar' -strip = 'loongarch64-unknown-linux-gnu-strip' -pkgconfig = 'pkg-config' -exe_wrapper = 'qemu-loongarch64' - -[host_machine] -system = 'linux' -cpu_family = 'loongarch64' -cpu = 'loongarch64' -endian = 'little' diff --git a/tests/checkasm/ext/crossfiles/riscv64-linux-clang.meson b/tests/checkasm/ext/crossfiles/riscv64-linux-clang.meson deleted file mode 100644 index c16d74d0ca..0000000000 --- a/tests/checkasm/ext/crossfiles/riscv64-linux-clang.meson +++ /dev/null @@ -1,16 +0,0 @@ -[binaries] -c = 'clang' -cpp = 'clang++' -ar = 'riscv64-linux-gnu-ar' -strip = 'riscv64-linux-gnu-strip' -exe_wrapper = 'qemu-riscv64' - -[properties] -c_args = '-target riscv64-linux-gnu' -c_link_args = '-target riscv64-linux-gnu' - -[host_machine] -system = 'linux' -cpu_family = 'riscv64' -cpu = 'riscv64' -endian = 'little' diff --git a/tests/checkasm/ext/crossfiles/riscv64-linux.meson b/tests/checkasm/ext/crossfiles/riscv64-linux.meson deleted file mode 100644 index e3eda5e8bb..0000000000 --- a/tests/checkasm/ext/crossfiles/riscv64-linux.meson +++ /dev/null @@ -1,12 +0,0 @@ -[binaries] -c = 'riscv64-linux-gnu-gcc' -cpp = 'riscv64-linux-gnu-g++' -ar = 'riscv64-linux-gnu-ar' -strip = 'riscv64-linux-gnu-strip' -exe_wrapper = 'qemu-riscv64' - -[host_machine] -system = 'linux' -cpu_family = 'riscv64' -cpu = 'riscv64' -endian = 'little' diff --git a/tests/checkasm/ext/crossfiles/wasm32.meson b/tests/checkasm/ext/crossfiles/wasm32.meson deleted file mode 100644 index a34a8a14bd..0000000000 --- a/tests/checkasm/ext/crossfiles/wasm32.meson +++ /dev/null @@ -1,15 +0,0 @@ -[binaries] -c = 'emcc' -cpp = 'em++' -ar = 'emar' -strip = 'emstrip' -exe_wrapper = 'node' - -[properties] -c_link_args = ['-sEXPORT_ALL=1'] - -[host_machine] -system = 'emscripten' -cpu_family = 'wasm32' -cpu = 'wasm32' -endian = 'little' diff --git a/tests/checkasm/ext/crossfiles/wasm64.meson b/tests/checkasm/ext/crossfiles/wasm64.meson deleted file mode 100644 index 2ababd9b4b..0000000000 --- a/tests/checkasm/ext/crossfiles/wasm64.meson +++ /dev/null @@ -1,15 +0,0 @@ -[binaries] -c = 'emcc' -cpp = 'em++' -ar = 'emar' -strip = 'emstrip' -exe_wrapper = 'node' - -[properties] -c_link_args = ['-sEXPORT_ALL=1'] - -[host_machine] -system = 'emscripten' -cpu_family = 'wasm64' -cpu = 'wasm64' -endian = 'little' diff --git a/tests/checkasm/ext/crossfiles/x86_64-w64-mingw32.meson b/tests/checkasm/ext/crossfiles/x86_64-w64-mingw32.meson deleted file mode 100644 index a7b901f7ed..0000000000 --- a/tests/checkasm/ext/crossfiles/x86_64-w64-mingw32.meson +++ /dev/null @@ -1,16 +0,0 @@ -[binaries] -c = 'x86_64-w64-mingw32-gcc' -cpp = 'x86_64-w64-mingw32-g++' -ar = 'x86_64-w64-mingw32-ar' -strip = 'x86_64-w64-mingw32-strip' -windres = 'x86_64-w64-mingw32-windres' -exe_wrapper = 'wine' - -[properties] -c_link_args = ['-static-libgcc'] - -[host_machine] -system = 'windows' -cpu_family = 'x86_64' -cpu = 'x86_64' -endian = 'little' diff --git a/tests/checkasm/ext/docs/Doxyfile.in b/tests/checkasm/ext/docs/Doxyfile.in deleted file mode 100644 index f668cfd2fc..0000000000 --- a/tests/checkasm/ext/docs/Doxyfile.in +++ /dev/null @@ -1,20 +0,0 @@ -# Project information -PROJECT_NAME = "checkasm" -PROJECT_BRIEF = "Assembly testing and benchmarking framework" -PROJECT_NUMBER = @VERSION@ - -# Input / output settings -INPUT = @INPUT@ -LAYOUT_FILE = @LAYOUT_FILE@ -EXCLUDE_SYMBOLS = internal -EXTRACT_STATIC = YES -MARKDOWN_SUPPORT = YES - -OUTPUT_DIRECTORY = @BUILDDIR@ -GENERATE_LATEX = NO - -# Misc settings -OPTIMIZE_OUTPUT_FOR_C = YES -TYPEDEF_HIDES_STRUCT = YES -WARN_IF_UNDOCUMENTED = NO -STRIP_FROM_PATH = @INCDIR@ diff --git a/tests/checkasm/ext/docs/DoxygenLayout.xml b/tests/checkasm/ext/docs/DoxygenLayout.xml deleted file mode 100644 index 856dd90576..0000000000 --- a/tests/checkasm/ext/docs/DoxygenLayout.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/checkasm/ext/docs/benchmarking.md b/tests/checkasm/ext/docs/benchmarking.md deleted file mode 100644 index f6292db311..0000000000 --- a/tests/checkasm/ext/docs/benchmarking.md +++ /dev/null @@ -1,492 +0,0 @@ -@page benchmarking Benchmarking - -This guide explains how to use checkasm's benchmarking capabilities to accurately measure -and compare the performance of optimized assembly implementations against reference code. - -@tableofcontents - -@section bench_basic Basics - -@subsection bench_workflow Benchmark Workflow - -Benchmarking in checkasm follows the same structure as correctness testing, with -an additional call to checkasm_bench_new(): - -@code{.c} -BUF_RECT(uint8_t, src, 64, 64); -BUF_RECT(uint8_t, dst_c, 64, 64); -BUF_RECT(uint8_t, dst_a, 64, 64); - -checkasm_declare(void, uint8_t *dst, ptrdiff_t dst_stride, - const uint8_t *src, ptrdiff_t src_stride, - int w, int h); - -if (checkasm_check_func(dsp->filter, "filter_64x64")) { - INITIALIZE_BUF_RECT(src); - CLEAR_BUF_RECT(dst_c); - CLEAR_BUF_RECT(dst_a); - - // Correctness testing - checkasm_call_ref(dst_c, dst_c_stride, src, src_stride, 64, 64); - checkasm_call_new(dst_a, dst_a_stride, src, src_stride, 64, 64); - checkasm_check_rect_padded(dst_c, dst_c_stride, - dst_a, dst_a_stride, 64, 64, "dst"); - - // Benchmarking - checkasm_bench_new(checkasm_alternate(dst_a, dst_c), dst_a_stride, - src, src_stride, 64, 64); -} - -checkasm_report("filter"); -@endcode - -@subsection bench_cli Running Benchmarks - -Enable benchmarking with the `--bench` flag: - -@code{.bash} -# Quick benchmark (uses default duration) -./checkasm --bench - -# Longer benchmark for more accurate results (10ms per function) -./checkasm --bench --duration=10000 - -# Benchmark specific functions only -./checkasm --bench --function='filter_*' - -# Verbose output showing all timing measurements -./checkasm --bench --verbose -@endcode - -The `--duration` parameter controls how long (in microseconds) each function is -benchmarked. Longer durations provide more accurate results but take more time. -The default is typically sufficient for most cases. - -@subsection bench_export Exporting Results - -checkasm can export benchmark results in multiple formats: - -@code{.bash} -# CSV format (suitable for spreadsheets) -./checkasm --bench --csv > results.csv # without column headers -./checkasm --bench --csv --verbose > results.csv # with column headers - -# JSON format (for programmatic analysis, includes all data) -./checkasm --bench --json > results.json - -# HTML format (interactive visualizations) -./checkasm --bench --html > results.html -@endcode - -The JSON output format includes all measurement data and detailed statistical -parameters, including kernel density estimates, regression parameters, and confidence -intervals. The HTML output displays this same data in the form of interactive charts. - -@section bench_methodology Statistical Methodology - -@subsection bench_lognormal Log-Normal Distribution Modeling - -checkasm models execution time as a log-normal distribution, which is well-suited -for performance measurements because: - -1. Execution time is always positive -2. Performance variations tend to be multiplicative (e.g. power states) rather than additive -3. Outliers (e.g., from cache misses or interrupts) naturally fall into the long tail - -The statistical estimator tracks two parameters: -- **Log mean** (μ): the logarithm of the median execution time -- **Log variance** (σ²): the variance of log(execution time) - -From these, checkasm computes: -- **Mode**: most likely execution time = exp(μ - σ²) -- **Median**: middle execution time = exp(μ) -- **Mean**: average execution time = exp(μ + σ²/2) -- **Standard deviation**: sqrt(exp(2μ + σ²) × (exp(σ²) - 1)) -- **Upper/Lower 95% confidence intervals**: exp(μ ± 1.96 × σ) - -@subsection bench_regression Linear Regression - -checkasm performs linear regression in log-space on the relationship between -iteration count and total execution time: - -@code{.plaintext} -log(per_call_time) = log(total_time) - log(iterations) -@endcode - -This approach: -- Automatically handles the multiplicative nature of timing variations -- Provides robust outlier rejection through regression residuals -- Separates per-call time from measurement overhead -- Computes confidence intervals for the estimates - -@subsection bench_geometric Geometric Mean for Multiple Runs - -When checkasm_bench_new() is called multiple times for the same function -(e.g., testing different block sizes), the final reported value is the -**geometric mean** of all measurements: - -@code{.plaintext} -geometric_mean = (x₁ × x₂ × ... × xₙ)^(1/n) -@endcode - -The geometric mean is appropriate for performance measurements because it: -- Is not skewed by outliers as heavily as arithmetic mean -- Properly handles ratios and speedups across multiple orders of magnitude -- Provides a representative "typical" performance across configurations - -@subsection bench_overhead Overhead Correction - -checkasm measures and subtracts the overhead of: -1. The benchmarking loop itself -2. The function call mechanism -3. The timer read operation - -This is done by measuring a no-op function and subtracting its measured time -from all benchmark results. The no-op overhead is reported at startup: - -@code{.plaintext} - - No-op overhead: 2.41 +/- 0.093 cycles per call (provisional) -@endcode - -For accuracy, this is re-estimated periodically throughout the benchmarking -process to account for any drift. The final value is reported again at the end -if `--verbose` is enabled. - -@section bench_best_practices Best Practices - -@subsection bp_system_state System State - -Despite all of the statistical techniques employed by checkasm to combat -short- and medium-term noise, there is an unavoidable dependence on long-term -changes in system state. For reliable benchmarking, consider: - -**Power Management:** -- Disable CPU frequency scaling if possible: - @code{.bash} - # Linux: set CPU governor to performance mode - sudo cpupower frequency-set --governor performance - - # Or for all CPUs - for cpu in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do - echo performance | sudo tee $cpu - done - @endcode - -- Disable turbo boost for consistent results: - @code{.bash} - # Intel - echo 1 | sudo tee /sys/devices/system/cpu/intel_pstate/no_turbo - - # AMD - echo 0 | sudo tee /sys/devices/system/cpu/cpufreq/boost - @endcode - -**System Load:** -- Close unnecessary applications -- Avoid running benchmarks on heavily loaded systems -- Consider using `nice` to prioritize the benchmark process: - @code{.bash} - nice -n -20 ./checkasm --bench - @endcode - -**Thermal Throttling:** -- Ensure adequate cooling to prevent thermal throttling -- Allow sufficient cool-down time between benchmark runs -- Monitor CPU temperature during long benchmark sessions - -@subsection bp_alignment Cache Alignment - -checkasm automatically warms up caches before taking measurements, but you -should be aware of cache effects: - -- **L1/L2 Cache**: Most optimized functions should fit in L2 cache -- **Data Working Set**: Buffers allocated with BUF_RECT() are properly aligned - and sized to avoid cache conflicts. Failure to do so may lead to performance - hits from unaligned memory accesses or cache thrashing. - -For functions with large working sets that don't fit in cache, benchmark results -may reflect cache miss behavior, which is often realistic for real-world usage. - -@subsection bp_alternating Buffer Alternation - -Use checkasm_alternate() when benchmarking to prevent cache pollution: - -@code{.c} -// Good: alternates between dst_a and dst_c to prevent cache hits from -// previous iterations -checkasm_bench_new(checkasm_alternate(dst_a, dst_c), dst_a_stride, - src, src_stride, w, h); - -// Acceptable: always writes to dst_a -checkasm_bench_new(dst_a, dst_a_stride, src, src_stride, w, h); -@endcode - -Alternating buffers ensures that benchmarks are not stalled by previous -access to the same data buffer from the prior loop iteration. - -@subsection bp_realistic Realistic Test Data - -Use realistic input data for benchmarks: - -@code{.c} -// For general data processing: use INITIALIZE_BUF() which includes common edge cases -INITIALIZE_BUF_RECT(src); - -// For specific patterns: use domain-appropriate data -checkasm_randomize_normf(audio_buf, len); // Audio: normal distribution - -// For worst-case analysis: test pathological inputs -generate_worst_case_pattern(buf, len); -@endcode - -The input data can significantly affect performance due to: -- Data-dependent branches in the implementation -- SIMD instruction efficiency varying with data patterns -- Cache behavior depending on data values - -If your function's performance varies significantly with the input data or -configuration, consider looping over all such configurations and running -checkasm_bench_new() for each, to measure an overall average. - -@subsection bp_configurations Choosing Configurations - -When benchmarking functions that support multiple sizes or configurations: - -**Option 1: Benchmark all configurations** -@code{.c} -for (int w = 4; w <= 128; w <<= 1) { - if (checkasm_check_func(dsp->filter, "filter_w%d", w)) { - for (int h = 4; h <= 128; h <<= 1) { - // Test for correctness - // ... - - // Benchmark each configuration - checkasm_bench_new(dst, dst_stride, src, src_stride, w, h); - } - // Reports geometric mean of all configurations - } -} -@endcode - -**Option 2: Benchmark representative sizes separately** -@code{.c} -const int sizes[][2] = { {16, 16}, {16, 32}, {64, 16}, {64, 32} }; - -for (int i = 0; i < sizeof(sizes) / sizeof(sizes[0]); i++) { - int w = sizes[i][0], h = sizes[i][1]; - - // Separate check_func call = separate benchmark report - if (checkasm_check_func(dsp->filter, "filter_%dx%d", w, h)) { - // Test for correctness - // ... - - checkasm_bench_new(dst, dst_stride, src, src_stride, w, h); - } -} -@endcode - -**Option 3: Benchmark only the limiting case** -@code{.c} -for (int w = 4; w <= 128; w <<= 1) { - if (checkasm_check_func(dsp->filter, "filter_w%d", w)) { - for (int h = 4; h <= 128; h <<= 1) { - // Test all for correctness - // ... - } - - // Benchmark only the largest size - checkasm_bench_new(dst, dst_stride, src, src_stride, w, 128); - } -} -@endcode - -Choose based on your needs: -- Option 1: General performance across all sizes -- Option 2: Specific performance for important sizes -- Option 3: Best-case or worst-case performance - -@section bench_interpreting Interpreting Results - -@subsection interp_output Understanding Output - -checkasm's benchmark output provides several pieces of information. Pass -`--verbose` to see all timing measurements. - -@code{.plaintext} -Benchmark results: - name cycles +/- stddev time (nanoseconds) (vs ref) - nop: 2.4 +/- 0.0 1.2 ns +/- 0.1 - filter_c: 64.9 +/- 75.4 33.8 ns +/- 40.8 - filter_sse2: 46.9 +/- 13.3 24.4 ns +/- 7.8 ( 1.22x) - filter_avx2: 20.6 +/- 1.2 10.7 ns +/- 1.4 ( 3.15x) -@endcode - -**Columns:** -- **name**: Function name (with ISA suffix for optimized versions) -- **cycles**: Estimated CPU cycles per call (mean ± standard deviation) -- **time**: Estimated nanoseconds per call (mean ± standard deviation) -- **(vs ref)**: Speedup relative to the reference (C) implementation - -**What to look for:** -- Lower cycle counts indicate better performance -- Standard deviation shows measurement reliability -- Speedup factors show optimization effectiveness - -@subsection interp_variance High Variance - -High standard deviation (large ± values) can indicate: - -1. **System noise**: Background processes, interrupts, frequency scaling - - Solution: Follow best practices in @ref bp_system_state - -2. **Data-dependent performance**: Function runs faster/slower on different inputs - - This may be legitimate behavior (e.g., early exit conditions) - - Consider whether benchmark input is representative - -3. **Cache effects**: Function doesn't fit in cache or has cache conflicts - - May be realistic for large working sets - - Ensure buffers are properly aligned - -The benchmark summary reports average timing error: -@code{.plaintext} - - average timing error: 17.371% across 15 benchmarks (maximum 65.404%) -@endcode - -High maximum error typically indicates at least one very noisy measurement. - -@subsection interp_comparison Comparing Implementations - -When comparing optimized implementations: - -**Absolute speedup:** -@code{.plaintext} -filter_avx2: 20.6 cycles ( 3.15x) -@endcode -This implementation is 3.15× faster than the C reference. - -**Relative comparison:** -@code{.plaintext} -filter_sse2: 46.9 cycles ( 1.22x) -filter_avx2: 20.6 cycles ( 3.15x) -@endcode -AVX2 is 46.9 / 20.6 = 2.28× faster than SSE2. - -@subsection interp_regression Regression Detection - -Use benchmark results to detect performance regressions: - -1. **Baseline measurements**: Save benchmark results for your codebase: - @code{.bash} - ./checkasm --bench --json > baseline.json - @endcode - -2. **After changes**: Run benchmarks again: - @code{.bash} - ./checkasm --bench --json > current.json - @endcode - -3. **Compare**: Look for functions that got slower - - Small variations (< 5%) are typically noise - - Changes > 10% warrant investigation - - Changes > 20% are likely real regressions or improvements - -@section bench_advanced Advanced Topics - -@subsection adv_microbench Microbenchmarking Pitfalls - -Be aware of common microbenchmarking issues: - -- **Dead Code Elimination:** If the optimized function's results aren't used, the compiler might optimize - it away, especially when compiling with link time optimization. This would - usually be seen as unrealistically low cycle counts. -- **Constant Folding:** Always use INITIALIZE_BUF() or RANDOMIZE_BUF() to ensure inputs aren't - compile-time constants that could be folded away. -- **Branch Prediction:** Running the same code path repeatedly (as benchmarks do) leads to perfect - branch prediction, which may not reflect real-world performance that involve - mixed function calls (e.g. varying block sizes). This is generally acceptable - since you're comparing implementations under the same conditions, but may hide - performance gains from e.g. branchless implementations. -- **Memory Hierarchy:** Benchmarks often measure L1/L2 cache performance, not DRAM performance. - For functions with large working sets, real-world performance may be lower - than benchmarks suggest, which puts a bound on the realistically achievable - speedup from SIMD optimizations. - -@subsection adv_platform Platform Considerations - -@subsubsection adv_timer Timer Resolution -checkasm reports timer resolution at startup: -@code{.plaintext} - - Timing source: x86 (rdtsc) - - Timing resolution: 0.5976 +/- 0.057 ns/cycle (1644 +/- 156.8 MHz) (provisional) -@endcode - -- x86/x86_64: rdtsc (cycle counter) - very high resolution -- ARM/AArch64: pmccntr (cycle counter) - high resolution -- LoongArch: rdtime (tick counter) - high resolution -- PowerPC 64le: mfspr (tick counter) - medium resolution -- Other/Fallback: OS-provided timers - lower resolution - -Lower resolution timers may require longer `--duration` for accurate results. - -@subsubsection adv_freq_scaling Frequency Scaling -The timer resolution includes clock frequency estimation. If CPU frequency -scaling is enabled, this estimate may be inaccurate. However, this affects -only the conversion to nanoseconds, not cycle counts. For most accurate results, -disable frequency scaling, or compare only raw cycle counts (for platforms with -access to high-resolution cycle counters). - -@subsubsection adv_cross_platform Cross-Platform Comparison -Comparing cycle counts across different CPUs is meaningful when: -- Both CPUs are from the same architecture family -- Both run at similar clock speeds -- You account for microarchitectural differences - -For cross-platform comparison, use relative speedup (optimized vs C) rather -than absolute cycle counts. - -@subsection adv_html HTML Report Overview - -The HTML report provides detailed statistical visualizations: - -@subsubsection adv_kde_regression Kernel Density Estimate (left chart) -- Shows the probability distribution of execution times -- Peak indicates most likely execution time (mode) -- Wider distribution = higher variance -- Derived from log-normal distribution fit - -@subsubsection adv_raw_measurements Raw Measurements (right chart) -- X-axis: iteration count (how many times function was called in one measurement) -- Y-axis: total time for all iterations in one measurement -- Line: linear regression fit -- Shaded area: 95% confidence interval -- Points far from line: potential outliers - -@subsubsection adv_metrics Metrics Table -- **Adjusted cycles/time**: After overhead subtraction (use this for comparisons) -- **Raw cycles/time**: Before overhead subtraction (may be more reliable for sub-10-cycle functions) - -@section bench_tips Tips and Tricks - -@subsection tips_reproducible Reproducible Benchmarks - -For reproducible results: - -1. **Use fixed random seed**: - @code{.bash} - ./checkasm --bench 12345 # Use seed 12345 - @endcode - This ensures the same test data patterns across runs. - -2. **Document system state**: - - CPU model and frequency settings - - Compiler version and flags - - Operating system and kernel version - - checkasm version/commit - -3. **Multiple runs**: - Run benchmarks multiple times and verify consistency: - @code{.bash} - for i in {1..5}; do - ./checkasm --bench --function='filter_*' | tee run_$i.txt - done - @endcode diff --git a/tests/checkasm/ext/docs/getting-started.md b/tests/checkasm/ext/docs/getting-started.md deleted file mode 100644 index 9e7c45cbf2..0000000000 --- a/tests/checkasm/ext/docs/getting-started.md +++ /dev/null @@ -1,280 +0,0 @@ -@page getting_started Getting Started - -This guide will walk you through installing checkasm and writing your first test. - -@tableofcontents - -@section installation Installation - -You can either load checkasm as a library (e.g. via `pkg-config`), or include it directly in your project's build system. - -@subsection meson_submodules Meson using wrap files (recommended) - -First, create `subprojects/checkasm.wrap`: - -@code{.ini} -[wrap-git] -url = https://code.videolan.org/videolan/checkasm.git -revision = release # or a specific tag/release -directory = checkasm -@endcode - -Then integrate it into your build system: - -@code{.meson} -# This first attempts loading checkasm as an external dependency using the -# appropriate platform-specific method (e.g. pkg-config on POSIX systems), -# and falls back to using the bundled version inside `subprojects/checkasm` -# otherwise. -checkasm_dependency = dependency('checkasm', - # Extracts the `checkasm_dep` variable from the `checkasm` subproject. - fallback: ['checkasm', 'checkasm_dep'], - required: false -) - -# Alternatively, you can directly force use of the bundled version: -# checkasm_dependency = subproject('checkasm').get_variable('checkasm_dep') - -if checkasm_dependency.found() - checkasm = executable('checkasm', - checkasm_sources, - dependencies: checkasm_dependency, - ) - - test('checkasm', checkasm, suite: 'checkasm') - benchmark('checkasm', checkasm, suite: 'checkasm', args: '--bench') -endif -@endcode - -@subsection meson_wrap Meson using submodules (alternative) - -As an alternative, you may use git submodules to include checkasm as a subproject. -This may be preferred in some environments where the build system cannot access -the internet during configuration time, or if you're already using submodules -in your project. - -@code{.bash} -git submodule init -git submodule add -b release https://code.videolan.org/videolan/checkasm subprojects/checkasm -# or checkout a specific tag/release -@endcode - -Then declare the dependency in your `meson.build` as usual. (See the previous section) - -@subsection manual_installation Manual Installation - -You can also build and install checkasm manually: - -@code{.bash} -git clone https://github.com/videolan/checkasm.git && cd checkasm -meson setup builddir -Dprefix=$PREFIX # (set optional build prefix) -meson compile -C builddir -meson install -C builddir -@endcode - -This is discouraged in favor of using Meson subprojects or distribution packages, -but may be useful inside containerized environments, CI systems or custom -build roots. - -@section quick_start Quick Start Example - -Let's create a simple test for a vector addition function that operates on buffers. - -@subsection quick_start1 1. Prerequisites - -Let's assume you have a reference implementation and an optimized version, -alongside a way of detecting CPU features and choosing the implementation -based on that: - -@code{.h} -// my_dsp.h -#include - -enum { - CPU_FLAG_AVX = 1 << 0, -}; - -unsigned detect_cpu_flags(void); - -typedef void (*add8_func_t)(uint16_t *dst, const uint8_t *src1, - const uint8_t *src2, size_t len); - -add8_func_t get_add8_func(unsigned cpu_flags); -@endcode - -@code{.c} -// my_dsp.c - -#include "my_cpu.h" - -// Reference implementation (pure C) -static void add8_c(uint16_t *dst, const uint8_t *src1, - const uint8_t *src2, size_t len) -{ - for (size_t i = 0; i < len; i++) - dst[i] = src1[i] + src2[i]; -} - -// Optimized implementation (pretend this is assembly) -static void add8_avx(uint16_t *dst, const uint8_t *src1, - const uint8_t *src2, size_t len) -{ - // Assembly optimized version would go here - add8_c(dst, src1, src2, len); -} - -add8_func_t get_add8_func(unsigned cpu_flags) -{ - if (cpu_flags & CPU_FLAG_AVX) - return add8_avx; - return add8_c; -} -@endcode - -@subsection quick_start2 2. Write the Test - -Create your test file: - -@code{.c} -// check_dsp.c - -#include -#include - -#include "my_dsp.h" - -#define WIDTH 1024 - -static void test_add8(const CheckasmCpu cpu) -{ - // Declare aligned buffers for testing - CHECKASM_ALIGN(uint8_t src1[WIDTH]); - CHECKASM_ALIGN(uint8_t src2[WIDTH]); - CHECKASM_ALIGN(uint16_t dst_c[WIDTH]); - CHECKASM_ALIGN(uint16_t dst_a[WIDTH]); - - // Declare the function signature - checkasm_declare(void, uint16_t *, const uint8_t *, const uint8_t *, size_t); - - if (checkasm_check_func(get_add8_func(cpu), "add_8")) { - // Initialize source buffers with quasi-random test vectors - INITIALIZE_BUF(src1); - INITIALIZE_BUF(src2); - - // Test with various buffer sizes - for (int w = 1; w <= WIDTH; w <<= 1) { - // Clear destination buffers before each test - CLEAR_BUF(dst_c); - CLEAR_BUF(dst_a); - - // Call reference and optimized implementations - checkasm_call_ref(dst_c, src1, src2, w); - checkasm_call_new(dst_a, src1, src2, w); - - // Compare results - checkasm_check1d will report any mismatches - checkasm_check1d(uint16_t, dst_c, dst_a, w, "sum"); - } - - // Benchmark the optimized version on the largest buffer size - checkasm_bench_new(checkasm_alternate(dst_c, dst_a), src1, src2, WIDTH); - } -} - -static void check_dsp(void) -{ - const CheckasmCpu cpu = checkasm_get_cpu_flags(); - - // Test all related functions and report as a single function group - test_add8(cpu); - // test_add16(cpu); - // ... - checkasm_report("add"); - - // Check more function groups - // ... -} - -// Test registry -static const CheckasmTest tests[] = { - { "dsp", check_dsp }, - {0} // array terminator -}; - -// CPU flag registry -static const CheckasmCpuInfo cpu_flags[] = { - { "AVX", "avx", CPU_FLAG_AVX }, - {0} // array terminator -}; - -int main(int argc, const char *argv[]) { - CheckasmConfig config = { - .tests = tests, - .cpu_flags = cpu_flags, - .cpu = detect_cpu_flags(), - }; - - return checkasm_main(&config, argc, argv); -} -@endcode - -@subsection quick_start3 3. Build and Run - -@code{.bash} -# Compile (example using gcc directly) -gcc -o check_dsp my_dsp.c check_dsp.c $(pkg-config --cflags --libs checkasm) -# or use `meson compile` if using Meson - -# Run all tests -./check_dsp -@endcode - -@section options Command-Line Options - -checkasm provides several useful command-line options: - -@code{.bash} -# List all available functions -./checkasm --list-functions - -# Run specific functions (supports wildcards) -./checkasm --function=add_*_8bpc - -# Run benchmarks -./checkasm --bench - -# Run specified test with higher benchmark duration (here: 10 ms) -./checkasm --test=pixel --bench --duration=10000 - -# Enable verbose output -./checkasm --verbose -@endcode - -The `--help` output shows all available options: - -@code{.txt} -Usage: checkasm [options...] - Use fixed value to seed the PRNG -Options: - --affinity= Run the process on CPU - --bench -b Benchmark the tested functions - --csv, --tsv, --json, Choose output format for benchmarks - --html - --function= -f Test only the functions matching - --help -h Print this usage info - --list-cpu-flags List available cpu flags - --list-functions List available functions - --list-tests List available tests - --duration=<μs> Benchmark duration (per function) in μs - --repeat[=] Repeat tests N times, on successive seeds - --test= -t Test only - --verbose -v Print verbose timing info and failure data -@endcode - ---- - -@section getting_started_next_steps Next Steps - -Now that you've set up checkasm and written your first test, learn how to -integrate it properly with your project's CPU detection and dispatch mechanisms. - -**Next:** @ref integration diff --git a/tests/checkasm/ext/docs/integration.md b/tests/checkasm/ext/docs/integration.md deleted file mode 100644 index 7918331e9c..0000000000 --- a/tests/checkasm/ext/docs/integration.md +++ /dev/null @@ -1,274 +0,0 @@ -@page integration Integration Guide - -This guide covers how to integrate checkasm into existing or new projects. - -@tableofcontents - -@section config_options Configuration Options - -Checkasm uses optional C11 features inside public header files. For safety, these are only enabled -conservatively based on the C11 standard version signaled by the compiler. Sometimes, these checks -could be relaxed, such as when the target project is explicitly compiled with `-std=c99` or older, -but using a modern compiler that would still understand and accept C11 features. In this case, -these feature checks may be checked by the user and defined before including checkasm.h. See -@ref config for a list of such options. - -@section cpu_flags CPU Flags - -CPU flags represent instruction set extensions and features that your optimized implementations -depend on (e.g., SSE2, AVX2, NEON). You must define an array of these flags, so checkasm can -systematically test each implementation variant. - -@note checkasm does not provide CPU detection or runtime dispatch functionality on its own. -It is a pure testing framework, and as such, should not be used as a runtime dependency of your -project. This means that your project must implement its own CPU feature detection and dispatch -mechanisms for production use. checkasm plugs into these existing mechanisms during testing. - -@subsection defining_cpu_flags Defining CPU Flags - -Assuming you have a set of CPU flags defined in your project, e.g., - -@code{.h} -// my_cpu.h - -enum { - CPU_FLAG_SSE2 = 1 << 0, - CPU_FLAG_SSSE3 = 1 << 1, - CPU_FLAG_SSE41 = 1 << 2, - CPU_FLAG_AVX2 = 1 << 3, - CPU_FLAG_AVX512 = 1 << 4, - // ... -}; - -typedef uint64_t MyCpuFlags; -MyCpuFlags detect_cpu_flags(void); -@endcode - -Then create a CheckasmCpuInfo array describing each flag, terminated by `{0}`: - -@code{.c} -// checkasm.c - -static const CheckasmCpuInfo cpu_flags[] = { - { "SSE2", "sse2", CPU_FLAG_SSE2 }, - { "SSSE3", "ssse3", CPU_FLAG_SSSE3 }, - { "SSE4.1", "sse41", CPU_FLAG_SSE41 }, - { "AVX2", "avx2", CPU_FLAG_AVX2 }, - { "AVX512", "avx512", CPU_FLAG_AVX512 }, - {0} // array terminator -}; - -// This ordering means: -// - SSE2 functions are tested with just CPU_FLAG_SSE2 -// - SSSE3 functions are tested with CPU_FLAG_SSE2 | CPU_FLAG_SSSE3 -// - SSE4.1 functions are tested with CPU_FLAG_SSE2 | CPU_FLAG_SSSE3 | CPU_FLAG_SSE41 -// - And so on... -@endcode - -Each entry contains: -- **name**: Human-readable name displayed in output (e.g., "SSE4.1") -- **suffix**: Short suffix used in function names and filtering (e.g., "sse41") -- **flag**: The bitfield value from your CPU flag enum - -@note Flags are tested in the order defined in the array. Each test inherits -flags from all previous entries, allowing checkasm to test progressively more -advanced instruction sets. - -Register the CPU flags with checkasm via the CheckasmConfig structure: - -@code{.c} -// checkasm.c - -static const CheckasmCpuInfo cpu_flags[] = { - // ... - {0} -}; - -int main(int argc, const char *argv[]) -{ - CheckasmConfig config = { - .cpu_flags = cpu_flags, - // ... - }; - - // Set initial CPU flags using your own runtime detection function - config.cpu = detect_cpu_flags(); - - return checkasm_main(&config, argc, argv); -} -@endcode - -@subsection extra_cpu_flags Extra CPU Flags - -You can include additional flags in CheckasmConfig.cpu that aren't in CheckasmConfig.cpu_flags. -These are transparently passed through to checkasm_get_cpu_flags() and can be used for -modifier flags like `CPU_FLAG_FAST_*` that don't require separate testing, but should -instead always be assumed to be available when matching function implementations. - -@section selecting_functions Selecting Functions - -There are two common strategies for selecting the correct function implementation during tests, -depending on how your project structures its dispatch mechanism: - -@note Choose the strategy that matches your project's existing architecture. If you are -developing a new library, we recommend the first approach. - -@subsection mask_callback Strategy 1: Mask Callback - -If your project has a `mask_cpu_flags` (or `cpu_flags_override`) function that -updates an internal static bitmask used internally by dispatch table getters, e.g.: - -@code{.c} -// my_cpu.c -static unsigned cpu_flags = 0; -static unsigned cpu_flags_mask = -1; - -unsigned get_cpu_flags(void) -{ - return cpu_flags & cpu_flags_mask; -} - -void mask_cpu_flags(unsigned flags) -{ - cpu_flags_mask = flags; -} -@endcode - -@code{.c} -// my_foo_dsp.c -void foo_dsp_init(foo_dsp *dsp) -{ - const unsigned cpu_flags = get_cpu_flags(); - - // Initialize with C implementations - dsp->add = add_c; - dsp->sub = sub_c; - - // Override with optimized versions based on cpu_flags - if (cpu_flags & CPU_FLAG_SSE2) { - dsp->add = add_sse2; - } - - if (cpu_flags & CPU_FLAG_AVX2) { - dsp->add = add_avx2; - dsp->sub = sub_avx2; - } - - // ... -} -@endcode - -Then, in your checkasm main file, you can set that directly as a callback in CheckasmConfig.set_cpu_flags: - -@code{.c} -// You may need a wrapper to fix the function signature -static void set_cpu_flags(CheckasmCpu cpu) -{ - mask_cpu_flags((unsigned) cpu); -} - -CheckasmConfig config = { - // ... - .set_cpu_flags = set_cpu_flags, -}; -@endcode - -With this approach, checkasm will automatically call your `set_cpu_flags()` function whenever -it changes the active CPU feature set during testing. - -@note This will always be a subset of the initially detected CPU flags provided in CheckasmConfig.cpu, -so there is no meaningful distinction between a `mask_cpu_flags` (that masks out real CPU -flags) and a `cpu_flags_override` (that overrides them wholesale). Both can be used -as a callback. - -@subsection direct_getters Strategy 2: Direct Getters - -If your project uses dispatch functions that directly accept a CPU mask parameter (e.g., -`void foo_dsp_init(foo_dsp *dsp, unsigned cpu_flags)`), you can call them within -each test using checkasm_get_cpu_flags(): - -@code{.c} -// my_foo_dsp.c -void foo_dsp_init(foo_dsp *dsp, unsigned cpu_flags) -{ - // Initialize *dsp based on the provided CPU flags -} -@endcode - -Then, in your checkasm test files: - -@code{.c} -// check_foo_dsp.c -void check_foo_dsp(void) -{ - foo_dsp dsp; - foo_dsp_init(&dsp, checkasm_get_cpu_flags()); // Get current test flags - - // Now test dsp.add, dsp.sub, etc. - // ... -} -@endcode - -The same applies if your project uses individual function getters like -`add_func_t get_add_func(unsigned cpu_flags)` instead of dispatch tables / dsp structs. - -@section organizing_tests Organizing Multiple Tests - -For larger projects, organize tests by module: - -@code{.c} -// Test module declarations -void checkasm_check_mc(void); -void checkasm_check_pixel(void); -void checkasm_check_filmgrain(void); -// ... - -static const CheckasmTest tests[] = { - { "mc", checkasm_check_mc }, - { "pixel", checkasm_check_pixel }, - { "filmgrain", checkasm_check_filmgrain }, - // ... - {0} -}; -@endcode - -Then implement each test in separate files: - -@code{.c} -// check_mc.c -#include -#include "mc_dsp.h" - -static void test_mc_func1(const mc_dsp *dsp); -static void test_mc_func2(const mc_dsp *dsp); -static void test_mc_func3(const mc_dsp *dsp); -// ... - -void checkasm_check_mc(void) -{ - mc_dsp dsp; - mc_dsp_init(&dsp, checkasm_get_cpu_flags()); - - test_func1(&dsp); - test_func2(&dsp); - test_func3(&dsp); - checkasm_report("group1"); - - test_func4(&dsp); - test_func5(&dsp); - test_func6(&dsp); - checkasm_report("group2"); - - // ... -} -@endcode - ---- - -@section integration_next_steps Next Steps - -Now that you know how to integrate checkasm with your project's architecture, -dive deeper into best practices and advanced patterns for writing comprehensive -tests. - -**Next:** @ref writing_tests diff --git a/tests/checkasm/ext/docs/introduction.md b/tests/checkasm/ext/docs/introduction.md deleted file mode 100644 index 8dd917b31e..0000000000 --- a/tests/checkasm/ext/docs/introduction.md +++ /dev/null @@ -1,148 +0,0 @@ -@mainpage Introduction - -**checkasm** is a robust, portable testing and benchmarking framework specifically designed for -validating optimized assembly implementations against reference C code. Originally developed for the -x264 encoder project, checkasm has grown considerably while in use by FFmpeg and dav1d, -and now provides comprehensive correctness verification, crash detection, -and accurate performance measurements across multiple architectures. - -This project in particular stems from an effort to combine and improve upon multiple diverging -checkasm forks in the wild (x264, FFmpeg, dav1d, etc.). It is a direct descendent of the dav1d -variant, with all relevant enhancements from the FFmpeg fork merged in. It has since evolved -into a fully fledged cross-platform standalone library and benchmarking framework. - -@tableofcontents - -@section features Key Features - -@subsection features_correctness Correctness Verification -- **Automated comparison** between reference (C) and optimized (assembly) implementations, including - support for fuzzing implementations over multiple seeds and data patterns. -- **Detection of ABI violations** such as register misuse, illegal opcodes, - or missing state cleanup. -- **Extensive data handling utilities** for defining, initializing, and comparing - input/output buffers of various types, sizes and dimensionalities. -- **Crash resilience** including signal handling and stack smashing detection. - -@subsection features_benchmarking Performance Benchmarking -- **Accurate cycle counting** using platform-specific high-resolution timers. -- **Statistical analysis** with robust outlier rejection, logarithmic regression and confidence intervals. -- **Comparative measurements** showing speedup of optimized code including comprehensive HTML reports. -- **Minimal overhead** to ensure realistic performance data, and high throughput. - -@subsection features_platform Platform Support - -The following architectures are explicitly supported for asm verification, with -the listed detection mechanisms for typical asm mistakes: - -- **x86, x86-64**: registers, stack, AVX2, MMX/FPU state -- **ARM, ARM64 (aarch64)**: registers, stack, VFP state -- **RISC-V**: registers, stack, vector state -- **LoongArch (32, 64)**: registers -- **PowerPC (64le)**: *none* - -In addition, hardware timers are available for benchmarking purposes on all of -the listed platforms (except RISCV-V), with fall-backs to generic OS-specific APIs. - -@section links Project Links - -- [**GitLab Repository**](https://code.videolan.org/videolan/checkasm) -- [**Issue Tracker**](https://code.videolan.org/videolan/checkasm/issues) -- [VideoLAN Homepage](https://www.videolan.org/) - -@subsection intro_next_steps Next Steps - -Continue learning about checkasm through the following guides: - -- @ref getting_started for a quick start guide -- @ref integration for a guide on how to integrate checkasm into your project -- @ref writing_tests for an in-depth explanation of writing tests -- @ref benchmarking for tips and tricks on benchmarking with checkasm - -Or explore the full API reference: - -- @ref checkasm.h -- @copybrief checkasm.h -- @ref test.h -- @copybrief test.h -- @ref utils.h -- @copybrief utils.h - -@section example_outputs Example Outputs - -@subsection example_benchmark Benchmark Output - -This is what the output looks like, when using `--verbose` mode to print all -timing data (on a pretty noisy/busy system): - -@code{.plaintext} -checkasm: - - CPU: Intel(R) Core(TM) Ultra 7 258V (000B06D1) - - Timing source: x86 (rdtsc) - - Timing resolution: 0.5976 +/- 0.057 ns/cycle (1644 +/- 156.8 MHz) (provisional) - - No-op overhead: 2.41 +/- 0.093 cycles per call (provisional) - - Bench duration: 10000 µs per function (18221161 cycles) - - Random seed: 3203178780 -C: - - msac.decode_symbol [OK] - - msac.decode_bool [OK] - - msac.decode_hi_tok [OK] -SSE2: - - msac.decode_symbol [OK] - - msac.decode_bool [OK] - - msac.decode_hi_tok [OK] -AVX2: - - msac.decode_symbol [OK] -checkasm: all 15 tests passed -Benchmark results: - name cycles +/- stddev time (nanoseconds) (vs ref) - nop: 2.4 +/- 0.0 1.2 ns +/- 0.1 - msac_decode_bool_c: 6.3 +/- 0.2 3.3 ns +/- 0.4 - msac_decode_bool_sse2: 5.7 +/- 0.2 3.0 ns +/- 0.4 ( 1.10x) - msac_decode_bool_adapt_c: 5.9 +/- 0.6 3.1 ns +/- 0.5 - msac_decode_bool_adapt_sse2: 6.3 +/- 0.2 3.3 ns +/- 0.4 ( 0.94x) - msac_decode_bool_equi_c: 5.1 +/- 0.2 2.6 ns +/- 0.3 - msac_decode_bool_equi_sse2: 2.8 +/- 0.1 1.4 ns +/- 0.2 ( 1.84x) - msac_decode_hi_tok_c: 64.9 +/- 75.4 33.8 ns +/- 40.8 - msac_decode_hi_tok_sse2: 46.9 +/- 13.3 24.4 ns +/- 7.8 ( 1.22x) - msac_decode_symbol_adapt4_c: 12.6 +/- 0.7 6.5 ns +/- 0.9 - msac_decode_symbol_adapt4_sse2: 12.3 +/- 0.8 6.4 ns +/- 0.9 ( 1.02x) - msac_decode_symbol_adapt8_c: 20.5 +/- 2.3 10.7 ns +/- 1.8 - msac_decode_symbol_adapt8_sse2: 12.1 +/- 0.8 6.3 ns +/- 0.8 ( 1.68x) - msac_decode_symbol_adapt16_c: 33.6 +/- 1.2 17.5 ns +/- 2.1 - msac_decode_symbol_adapt16_sse2: 13.8 +/- 0.6 7.2 ns +/- 0.9 ( 2.42x) - msac_decode_symbol_adapt16_avx2: 20.6 +/- 1.2 10.7 ns +/- 1.4 ( 1.62x) - - average timing error: 17.371% across 15 benchmarks (maximum 65.404%) -@endcode - -@subsection example_errors Error Reporting - -This is what various failures could look like: - -@code{.plaintext} -checkasm: - - CPU: AMD Ryzen 9 9950X3D 16-Core Processor (00B40F40) - - Random seed: 3689286425 -x86: - - x86.copy [OK] -FAILURE: sigill_x86 (illegal instruction) - - x86.sigill [FAILED] -FAILURE: corrupt_stack_x86 (stack corruption) - - x86.corrupt_stack [FAILED] -FAILURE: clobber_r9_x86 (failed to preserve register: r9) -FAILURE: clobber_r10_x86 (failed to preserve register: r10) -FAILURE: clobber_r11_x86 (failed to preserve register: r11) -FAILURE: clobber_r12_x86 (failed to preserve register: r12) -FAILURE: clobber_r13_x86 (failed to preserve register: r13) -FAILURE: clobber_r14_x86 (failed to preserve register: r14) - - x86.clobber [FAILED] -FAILURE: underwrite_64_x86 (../tests/generic.c:56) -dst data (64x1): - 0: 45 b3 dc aa 68 90 a4 5d cf d9 d9 9b d0 34 45 b3 dc aa 68 90 a4 5d cf d9 d9 9b d0 34 .............. - 1b 88 37 0f 14 f1 77 f4 94 bf 53 a3 21 3f 1b 88 37 0f 14 f1 77 f4 94 bf 53 a3 21 3f .............. - b5 64 77 fc 75 6b a9 2a 38 8a c7 e8 f9 1d b5 64 77 fc 75 6b a9 2a 38 8a c7 e8 f9 1d .............. - b4 80 d6 f4 34 1d c6 2b fd a8 e5 83 51 bb b4 80 d6 f4 34 1d c6 2b fd a8 e5 83 51 bb .............. - 72 f6 e5 c1 47 80 63 f2 72 f6 e5 c1 aa aa aa aa ....xxxx - - generic.underwrite [FAILED] -@endcode - -@section license License - -checkasm is licensed under the **2-clause BSD license**. See the LICENSE file in the repository for full details. diff --git a/tests/checkasm/ext/docs/meson.build b/tests/checkasm/ext/docs/meson.build deleted file mode 100644 index 4b05189176..0000000000 --- a/tests/checkasm/ext/docs/meson.build +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright © 2025 Niklas Haas -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -doxygen = find_program('doxygen', required: build_docs) -if not doxygen.found() - subdir_done() -endif - -doxygen_file_names = [ - 'introduction.md', - 'getting-started.md', - 'integration.md', - 'writing-tests.md', - 'benchmarking.md', -] - -doxygen_paths = checkasm_api_header_paths -foreach file_name : doxygen_file_names - doxygen_paths += meson.current_source_dir() / file_name -endforeach - -# Escape input files for "INPUT" option in Doxyfile -doxygen_inputs = [] -foreach path : doxygen_paths - path = path.replace('\\', '\\\\') - path = path.replace('"', '\\"') - doxygen_inputs += ['"' + path + '"'] -endforeach - -docs_conf = configuration_data() -docs_conf.set('INPUT', ' '.join(doxygen_inputs)) -docs_conf.set('VERSION', meson.project_version()) -docs_conf.set_quoted('BUILDDIR', meson.current_build_dir()) -docs_conf.set_quoted('INCDIR', checkasm_include_dir) - -doxygen_layout = meson.current_source_dir() / 'DoxygenLayout.xml' -docs_conf.set_quoted('LAYOUT_FILE', doxygen_layout) - -doxyfile = configure_file( - input: 'Doxyfile.in', - output: 'Doxyfile', - configuration: docs_conf, - install: false -) - -custom_target('docs', - input: doxyfile, - output: 'html', - command: [doxygen, '@INPUT@'], - depend_files: files(doxygen_paths, doxygen_layout), - build_by_default: false, - install: false, - console: true, -) - -message('Run "meson compile docs" to build HTML documentation') diff --git a/tests/checkasm/ext/docs/writing-tests.md b/tests/checkasm/ext/docs/writing-tests.md deleted file mode 100644 index 62daedd348..0000000000 --- a/tests/checkasm/ext/docs/writing-tests.md +++ /dev/null @@ -1,753 +0,0 @@ -@page writing_tests Writing Tests - -This guide covers best practices and common patterns for writing checkasm tests. - -@tableofcontents - -@section test_structure Basic Test Structure - -Before diving into advanced patterns and best practices, familiarize yourself -with the basic test structure by reading the @ref quick_start. - -The typical test workflow is: -1. Allocate (aligned) buffers for test data -2. Declare the function signature with checkasm_declare() -3. Check if the function should be tested with checkasm_check_func() -4. Initialize test inputs and clear output buffers -5. Call both reference (checkasm_call_ref()) and new (checkasm_call_new()) implementations -6. Compare results with checkasm_check2d() or similar -7. Benchmark the new implementation with checkasm_bench_new() -8. Report results with checkasm_report() (optional) - -@section naming_conventions API Naming Conventions - -checkasm supports two API naming styles: - -@subsection modern_api Modern API (Recommended) - -The modern API uses the `checkasm_` prefix for all functions: - -@code{.c} -checkasm_declare(void, uint8_t *dst, const uint8_t *src, int len); -checkasm_check_func(dsp->func, "func_name") -checkasm_call_ref(dst_c, src, len); -checkasm_call_new(dst_a, src, len); -checkasm_check1d(uint8_t, dst_c, dst_a, len, "dst"); -checkasm_bench_new(dst_a, src, len); -checkasm_report("func_name"); -checkasm_fail() -checkasm_alternate(buf0, buf1) -// ... -@endcode - -@subsection legacy_api Legacy/Short API - -For convenience and backwards compatibility, shorter aliases are available: - -@code{.c} -declare_func(void, uint8_t *dst, const uint8_t *src, int len); -check_func(dsp->func, "func_name") -call_ref(dst_c, src, len); -call_new(dst_a, src, len); -// checkasm_check1d() has no short alias -bench_new(dst_a, src, len); -report("func_name"); -fail() -alternate(buf0, buf1) -@endcode - -@note Both naming styles are fully supported and can be mixed within the same -test file. However, for consistency and readability in documentation and new -code, we recommend using the modern `checkasm_` prefixed names. - -@section best_practices Best Practices - -The remainder of this guide focuses on best practices, common patterns, and advanced testing scenarios. - -@subsection bp_buffer_allocation Buffer Allocation - -Always use properly aligned buffers for testing: - -@code{.c} -// For simple arrays -CHECKASM_ALIGN(uint8_t buf[1024]); - -// For 2D buffers with automatic padding and stride calculation -// - Defines `dst` as a pointer to a 64x32 area, and `dst_stride` (in bytes) -BUF_RECT(uint8_t, dst, 64, 32); -@endcode - -**Important:** Apply CHECKASM_ALIGN() to each buffer individually: - -@code{.c} -// Correct -CHECKASM_ALIGN(uint8_t buf1[32]); -CHECKASM_ALIGN(uint8_t buf2[32]); - -// Wrong - only buf1 will be aligned -CHECKASM_ALIGN(uint8_t buf1[32], buf2[32]); -@endcode - -@subsection bp_buffer_init Buffer Initialization - -checkasm provides several buffer initialization functions: - -@code{.c} -// Random data (uniformly distributed) -RANDOMIZE_BUF(buf); -checkasm_randomize(buf, sizeof(buf)); // Equivalent to the above macro -checkasm_randomize_mask8 (buf8, width, 0x0F); // Constrain value range -checkasm_randomize_mask16(buf16, width, 1023); // Random 10-bit values - -// Pathological test patterns (mix of edge cases and random bytes) -INITIALIZE_BUF(buf); -checkasm_init(buf, sizeof(buf)); // Equivalent to the above macro -checkasm_init_mask16(buf16, width, (1 << 12) - 1); // Constrain to 12-bit range - -// Clear to a constant value -CLEAR_BUF(buf); -checkasm_clear(buf, sizeof(buf)); // Equivalent to the above macro -checkasm_clear16(buf16, width, 0x1234); -@endcode - -For 2D buffers created with BUF_RECT(): - -@code{.c} -BUF_RECT(uint8_t, src, 64, 32); -INITIALIZE_BUF_RECT(src); // Initialize with pathological test bytes -RANDOMIZE_BUF_RECT(tmp); // Fill with random data -CLEAR_BUF_RECT(dst); // Clear to constant data (currently 0xAA) -@endcode - -See @ref memory for a full list of buffer initialization functions. - -@subsection bp_test_loops Testing Multiple Configurations - -Test functions across multiple configurations (e.g. block sizes) to ensure -comprehensive coverage: - -@code{.c} -BUF_RECT(uint8_t, src, 128, 128); -BUF_RECT(uint8_t, dst_c, 128, 128); -BUF_RECT(uint8_t, dst_a, 128, 128); - -checkasm_declare(void, uint8_t *dst, ptrdiff_t dst_stride, - const uint8_t *src, ptrdiff_t src_stride, - int w, int h); - -// Test various power-of-two block sizes, from 4x4 to 128x128 -for (int h = 4; h <= 128; h <<= 1) { - for (int w = 4; w <= 128; w <<= 1) { - if (checkasm_check_func(get_func(w), "func_%dx%d", w, h)) { - // Initialize test data - doing this inside the loop picks a - // different data pattern for each test - INITIALIZE_BUF(src); - CLEAR_BUF(dst_c); - CLEAR_BUF(dst_a); - - // Test this configuration - checkasm_call_ref(dst_c, dst_c_stride, src, src_stride, w, h); - checkasm_call_new(dst_a, dst_a_stride, src, src_stride, w, h); - - checkasm_check_rect_padded(dst_c, dst_c_stride, - dst_a, dst_a_stride, w, h, "dst"); - - // Benchmark this configuration - checkasm_bench_new(checkasm_alternate(dst_a, dst_c), dst_a_stride, - src, src_stride, w, h); - } - } -} - -checkasm_report("func"); -@endcode - -@subsection bp_random_params Using Random Parameters - -Use checkasm_rand() and related functions to generate diverse test inputs: - -@code{.c} -// Random integers -int byte = checkasm_rand() & 0xFF; -uint32_t flags = checkasm_rand_uint32(); - -// Random floats -double d = checkasm_randf(); // [0.0, 1.0) -float f = (float) checkasm_randf() * 100.0f; // [0.0, 100.0) - -// Normal distribution -double normal = checkasm_rand_norm(); // mean=0, stddev=1 -checkasm_randomize_normf(buf, len); // Fill buffer with N(0,1) -@endcode - -See @ref rng for a full list of random number generation functions. - -@subsection bp_reporting Organizing Reports - -Group related functions and use checkasm_report() strategically: - -@code{.c} -static void check_add_functions(const DSPContext *dsp) -{ - // Test multiple related functions - for (int bpc = 8; bpc <= 12; bpc += 2) { - if (checkasm_check_func(get_add8(bpc), "add8_%dbpc", bpc)) { - // Test add8 - } - - if (checkasm_check_func(get_add16(bpc), "add16_%dbpc", bpc)) { - // Test add16 - } - } - - // Report once for the whole group - checkasm_report("add"); -} -@endcode - -For very simple tests with only a few functions, for which there is no -logical grouping, or for miscellaneous functions, this can be left out. -Any functions without a checkasm_report() call after them will be implicitly -reported under the name of the test itself. Note that this only makes sense -if such functions are the last functions being tested in a given test, since -any later checkasm_report() call would otherwise include all prior functions. - -@section common_patterns Common Test Patterns - -@subsection pattern_2d 2D Buffer Processing - -For functions operating on 2D buffers with stride: - -@code{.c} -static void check_filter(const DSPContext *dsp) -{ - // Define padded 64x64 buffers - BUF_RECT(uint8_t, src, 64, 64); - BUF_RECT(uint8_t, dst_c, 64, 64); - BUF_RECT(uint8_t, dst_a, 64, 64); - - checkasm_declare(void, uint8_t *dst, ptrdiff_t dst_stride, - const uint8_t *src, ptrdiff_t src_stride, - int w, int h); - - for (int w = 4; w <= 64; w <<= 1) { - if (checkasm_check_func(dsp->filter, "filter_w%d", w)) { - // Check multiple heights - for (int h = 4; h <= 64; h <<= 1) { - INITIALIZE_BUF_RECT(src); - CLEAR_BUF_RECT(dst_c); - CLEAR_BUF_RECT(dst_a); - - checkasm_call_ref(dst_c, dst_c_stride, src, src_stride, w, h); - checkasm_call_new(dst_a, dst_a_stride, src, src_stride, w, h); - - // Check buffers including padding - checkasm_check_rect_padded(dst_c, dst_c_stride, - dst_a, dst_a_stride, - w, h, "dst"); - } - - // Benchmark only the full height configuration - checkasm_bench_new(checkasm_alternate(dst_a, dst_c), dst_a_stride, - src, src_stride, w, 64); - } - } - - checkasm_report("filter"); -} -@endcode - -@subsection pattern_state State-Based Functions - -For functions that modify internal state or have side effects: - -@code{.c} -static void check_decoder(const DecoderContext *dec) -{ - DecoderState state_c, state_a; - uint8_t bitstream[128]; - - // Initialize bitstream with random data - RANDOMIZE_BUF(bitstream); - - checkasm_declare(int, DecoderState *state, const uint8_t *data, int len); - - if (checkasm_check_func(dec->decode, "decode")) { - // Initialize both states identically - init_decoder_state(&state_c, bitstream, 128); - init_decoder_state(&state_a, bitstream, 128); - - // Decode and compare - int result_c = checkasm_call_ref(&state_c, bitstream, 128); - int result_a = checkasm_call_new(&state_a, bitstream, 128); - - // Compare return values - if (result_c != result_a) { - if (checkasm_fail()) { - fprintf(stderr, "return value mismatch: %d vs %d\n", - result_c, result_a); - } - } - - // Compare final states (optional) - // - // The validity of this check depends on whether or not `DecoderState` - // has padding bytes or non-deterministic internal state. - checkasm_check1d(uint8_t, &state_c, &state_a, sizeof(DecoderState), - "decoder state"); - - checkasm_bench_new(&state_a, bitstream, 128); - } - - checkasm_report("decode"); -} -@endcode - -@subsection pattern_multi_output Multiple Outputs - -For functions that produce multiple output values: - -@code{.c} -static void check_stats(const DSPContext *dsp) -{ - CHECKASM_ALIGN(uint8_t buf[64 * 64]); - - checkasm_declare(int, const uint8_t *buf, int len, - unsigned *variance, unsigned *sum); - - if (checkasm_check_func(dsp->compute_stats, "compute_stats")) { - unsigned var_c, var_a, sum_c, sum_a; - - INITIALIZE_BUF(buf); - - int result_c = checkasm_call_ref(buf, 64*64, &var_c, &sum_c); - int result_a = checkasm_call_new(buf, 64*64, &var_a, &sum_a); - - // Compare all outputs - if (result_c != result_a || var_c != var_a || sum_c != sum_a) { - if (checkasm_fail()) { - fprintf(stderr, "result: %d vs %d, var: %u vs %u, sum: %u vs %u\n", - result_c, result_a, var_c, var_a, sum_c, sum_a); - } - } - - checkasm_bench_new(buf, 64*64, &var_a, &sum_a); - } - - checkasm_report("compute_stats"); -} -@endcode - -@subsection pattern_custom_input Custom Input Generation - -For functions requiring specific test patterns: - -@code{.c} -// Generate worst-case inputs to stress the implementation -static void generate_worst_case(uint16_t *buf, int len, int bitdepth_max) -{ - // Create reverse sorted sequence of input values - for (int i = 0; i < len; i++) - buf[i] = (len - 1 - i) & bitdepth_max; -} - -static void check_transform(const DSPContext *dsp) -{ - #define WIDTH 64 - CHECKASM_ALIGN(int16_t src [WIDTH]); - CHECKASM_ALIGN(int16_t dst_c[WIDTH]); - CHECKASM_ALIGN(int16_t dst_a[WIDTH]); - - checkasm_declare(void, int16_t *dst, const int16_t *src, int width); - - if (checkasm_check_func(dsp->transform, "transform")) { - // Test with both random and worst-case inputs - for (int pattern = 0; pattern < 2; pattern++) { - if (pattern == 0) { - INITIALIZE_BUF(src); // Random input - } else { - generate_worst_case(src, WIDTH, 32767); // Worst case pattern - } - - CLEAR_BUF(dst_c); - CLEAR_BUF(dst_a); - - checkasm_call_ref(dst_c, src, WIDTH); - checkasm_call_new(dst_a, src, WIDTH); - - checkasm_check1d(int16_t, dst_c, dst_a, WIDTH, "dst"); - } - - checkasm_bench_new(checkasm_alternate(dst_a, dst_c), src, WIDTH); - } - - checkasm_report("transform"); -} -@endcode - -@section advanced_topics Advanced Topics - -@subsection adv_float Floating-Point Comparison - -For functions producing floating-point results, use tolerance-based comparison: - -@code{.c} -static void check_float_func(const DSPContext *dsp) -{ - #define WIDTH 128 - CHECKASM_ALIGN(float src [WIDTH]); - CHECKASM_ALIGN(float dst_c[WIDTH]); - CHECKASM_ALIGN(float dst_a[WIDTH]); - - checkasm_declare(void, float *dst, const float *src, int len); - - if (checkasm_check_func(dsp->process_float, "process_float")) { - checkasm_randomize_normf(src, WIDTH); - - checkasm_call_ref(dst_c, src, WIDTH); - checkasm_call_new(dst_a, src, WIDTH); - - // Compare with ULP (Units in Last Place) tolerance - // Note: cannot use checkasm_check1d() here - const int max_ulp = 1; - checkasm_check2d(float_ulp, dst_c, 0, dst_a, 0, WIDTH, 1, "dst", max_ulp); - - // Or use absolute epsilon tolerance - // if (!checkasm_float_near_abs_eps_array(dst_c, dst_a, 1e-6f, WIDTH)) { - // checkasm_fail(); - // } - - checkasm_bench_new(checkasm_alternate(dst_a, dst_c), src, WIDTH); - } - - checkasm_report("process_float"); -} -@endcode - -@subsection adv_padding Padding and Over-Write Detection - -Detect when functions write beyond their intended boundaries: - -@code{.c} -static void check_bounds(const DSPContext *dsp) -{ - BUF_RECT(uint8_t, dst_c, 64, 64); - BUF_RECT(uint8_t, dst_a, 64, 64); - - checkasm_declare(void, uint8_t *dst, ptrdiff_t stride, int w, int h); - - if (checkasm_check_func(dsp->fill, "fill")) { - const int w = 64, h = 64; - - CLEAR_BUF_RECT(dst_c); - CLEAR_BUF_RECT(dst_a); - - checkasm_call_ref(dst_c, dst_c_stride, w, h); - checkasm_call_new(dst_a, dst_a_stride, w, h); - - // Standard check (no padding) - checkasm_check2d(uint8_t, dst_c, dst_c_stride, - dst_a, dst_a_stride, w, h, "dst"); - - // Check with padding detection (detects writes outside w×h) - checkasm_check_rect_padded(dst_c, dst_c_stride, - dst_a, dst_a_stride, w, h, "dst"); - - // Allow over-write up to 16-element alignment on right edge - checkasm_check_rect_padded_align(dst_c, dst_c_stride, - dst_a, dst_a_stride, - w, h, "dst", 16, 1); - - checkasm_bench_new(checkasm_alternate(dst_a, dst_c), dst_a_stride, w, h); - } - - checkasm_report("fill"); -} -@endcode - -@subsection bench_multiple Benchmarking Multiple Configurations - -For functions that can be benchmarked at multiple configurations: - -@code{.c} -if (checkasm_check_func(dsp->filter, "filter_w%d", w)) { - for (int h = 4; h <= 64; h <<= 1) { - // Test all heights for correctness - checkasm_call_ref(dst_c, dst_c_stride, src, src_stride, w, h); - checkasm_call_new(dst_a, dst_a_stride, src, src_stride, w, h); - checkasm_check2d(uint8_t, dst_c, dst_c_stride, - dst_a, dst_a_stride, w, h, "dst"); - - // Benchmark each configuration - checkasm_bench_new(checkasm_alternate(dst_a, dst_c), dst_a_stride, - src, src_stride, w, h); - } - - // The framework will report the geometric mean of all benchmark runs for - // the same checkasm_check_func() call -} - -checkasm_report("filter_w%d", w); -@endcode - -Alternatively, you could call checkasm_check_func() on each configuration -to get a separate benchmark report for each size, or call checkasm_bench_new() -only on the largest input size to test the limiting behavior. - -@subsection adv_bitdepth Multi-Bitdepth Testing - -For codecs supporting multiple bit depths: - -@code{.c} -static void check_pixfunc(void) -{ - DSPContext dsp; - - #define WIDTH 64 - CHECKASM_ALIGN(uint16_t src [WIDTH]); - CHECKASM_ALIGN(uint16_t dst_c[WIDTH]); - CHECKASM_ALIGN(uint16_t dst_a[WIDTH]); - - checkasm_declare(void, uint16_t *dst, const uint16_t *src, int len); - - for (int bpc = 10; bpc <= 12; bpc += 2) { - const int bitdepth_max = (1 << bpc) - 1; - dsp_context_init(&dsp, checkasm_get_cpu_flags(), bpc); - - if (checkasm_check_func(dsp->process, "process_%dbpc", bpc)) { - // Randomize within valid bit depth range - checkasm_randomize_mask16(src, WIDTH, bitdepth_max); - - checkasm_call_ref(dst_c, src, WIDTH); - checkasm_call_new(dst_a, src, WIDTH); - checkasm_check1d(uint16_t, dst_c, dst_a, WIDTH, "dst"); - checkasm_bench_new(checkasm_alternate(dst_a, dst_c), src, WIDTH); - } - } - - checkasm_report("process"); -} -@endcode - -Alternatively, you may prefer to compile the test file itself multiple times, -using preprocessor definitions like `-DBITDEPTH=10` etc. - -@subsection adv_failure Custom Failure Reporting - -Provide detailed diagnostics when tests fail: - -@code{.c} -static void check_complex(const DSPContext *dsp) -{ - // ... - - if (checkasm_check_func(dsp->complex, "complex")) { - for (int param = 0; param < 16; param++) { - int result_c = checkasm_call_ref(param); - int result_a = checkasm_call_new(param); - - // Check return value - if (result_c != result_a) { - if (checkasm_fail()) { - // This branch is only executed if verbose error diagnostics - // are requested by the user - fprintf(stderr, "return mismatch for param=%d: %d vs %d\n", - param, result_c, result_a); - } - } - } - } - - checkasm_report("complex"); -} -@endcode - -@subsection adv_indirect Calling Functions Through Wrappers - -When the function being tested must be called indirectly through a wrapper, -you may use checkasm_call() and checkasm_call_checked() to invoke an arbitrary -helper function. - -In this case, the declared function type must be the type of the wrapper, not -the inner function passed to checkasm_check_func(). You may then access the -untyped reference/tested function pointers via @ref checkasm_key_ref and -@ref checkasm_key_new "": - -@code{.c} -typedef int (my_func)(int); - -// Wrapper that invokes the actual function -static int sum_upto_n(my_func *func, int count) -{ - int sum = 0; - for (int i = 0; i < count; i++) - sum += func(i); - return sum; -} - -static void check_wrapper(void) -{ - // Declare the signature of the wrapper, not the inner function - checkasm_declare(int, my_func *, int); - - if (checkasm_check_func(get_my_func(), "my_wrapped_func")) { - const int count = checkasm_rand() % 100; - - // Cast checkasm_key_new to the appropriate type and pass to wrapper - const my_func *my_ref = (my_func *) checkasm_key_ref; - const my_func *my_new = (my_func *) checkasm_key_new; - int sum_c = checkasm_call(sum_upto_n, my_ref, count); - int sum_a = checkasm_call_checked(sum_upto_n, my_new, count); - - if (sum_c != sum_a) - checkasm_fail(); - } -} -@endcode - -@note When using a pattern like this, the value passed to checkasm_check_func() -may not even need to be a function pointer. It could be an arbitrary pointer -or pointer-sized integer, such as a configuration struct or index into a dispatch -table, so long as it uniquely identifies the underlying implementation being -tested. - -@subsection adv_mmx MMX Functions (x86) - -MMX functions on x86 often omit the `emms` instruction before returning, expecting -the caller to execute it manually after a loop. The `emms` instruction is necessary -to clear MMX state before any floating-point code can execute, but it can be very -slow, so optimized loops that call into MMX kernels usually defer it to the loop -end to minimize overhead. - -Use checkasm_declare_emms() for such (non-ABI-compliant) functions: - -@code{.c} -static void check_sad_mmx(const DSPContext *dsp) -{ - #define SIZE 16 - CHECKASM_ALIGN(uint8_t src [SIZE * SIZE]); - CHECKASM_ALIGN(uint8_t ref [SIZE * SIZE]); - - // Declaring with CPU_FLAG_MMX enables an automatic emms after calling - // this function whenever CPU_FLAG_MMX is active - checkasm_declare_emms(CPU_FLAG_MMX, int, const uint8_t *src, - const uint8_t *ref, ptrdiff_t stride); - - if (checkasm_check_func(dsp->sad_16x16, "sad_16x16")) { - INITIALIZE_BUF(src); - INITIALIZE_BUF(ref); - - // checkasm will automatically call emms after checkasm_call_new() - int result_c = checkasm_call_ref(src, ref, SIZE); - int result_a = checkasm_call_new(src, ref, SIZE); - - if (result_c != result_a) { - if (checkasm_fail()) { - fprintf(stderr, "sad mismatch: %d vs %d\n", result_c, result_a); - } - } - - // checkasm will also call emms after benchmarking iterations - checkasm_bench_new(src, ref, SIZE); - } - - checkasm_report("sad"); -} -@endcode - -The first parameter is a CPU flag mask (e.g., `CPU_FLAG_MMX | CPU_FLAG_MMXEXT`). -When any of the specified CPU flags are active, checkasm will call `emms` after -each checkasm_call_new() and benchmark run. On non-x86 platforms, checkasm_declare_emms() -is equivalent to checkasm_declare(). - -@note Modern SIMD instruction sets (SSE and later) do not use MMX registers and - therefore don't require `emms`. Only use checkasm_declare_emms() for legacy - MMX-only code or MMXEXT functions that explicitly use MMX registers. - -@section tips_tricks Tips and Tricks - -@subsection tips_deterministic Deterministic Testing - -checkasm uses a seeded PRNG for reproducible tests. To test with a specific seed: - -@code{.bash} -./checkasm 12345 # Use seed 12345 -@endcode - -Failed tests will print the seed used, allowing you to reproduce failures: - -@code{.txt} -checkasm: using random seed 987654321 -... -sad_16x16: FAILED (ref:1234 new:1235) -@endcode - -@subsection tips_selective Selective Testing - -Test specific functions or groups: - -@code{.bash} -# Test only functions matching pattern -./checkasm --function='add_*' - -# Test only a specific test module -./checkasm --test=math - -# Combine both -./checkasm --test=dsp --function='blend_*' -@endcode - -@subsection tips_verbose Verbose Output - -Enable verbose mode for detailed failure information: - -@code{.bash} -./checkasm --verbose -@endcode - -This shows hexdumps of differing buffer regions automatically, when using -the built-in checkasm_check*() series of buffer comparison helpers. - -@subsection tips_bench Benchmarking Tips - -Run benchmarks with appropriate duration: - -@code{.bash} -# Quick benchmark (default) -./checkasm --bench - -# Longer benchmark for more accurate results (10ms per function) -./checkasm --bench --duration=10000 - -# Export results in different formats -./checkasm --bench --csv > results.csv -./checkasm --bench --json > results.json -./checkasm --bench --html > results.html -@endcode - -@subsection tips_helpers Helper Macros - -Create helper macros to reduce repetition in your tests: - -@code{.c} -#define TEST_FILTER(name, w, h) \ - if (checkasm_check_func(dsp->name, #name "_%dx%d", w, h)) { \ - test_filter_##name(dsp, w, h); \ - checkasm_bench_new(dst, dst_stride, src, src_stride, w, h); \ - } - -// Usage: -TEST_FILTER(blur, 16, 16); -TEST_FILTER(blur, 32, 32); -TEST_FILTER(sharpen, 16, 16); -@endcode - ---- - -@section tests_next_steps Next Steps - -Now that you've mastered writing tests, learn how to accurately measure and -compare the performance of your optimized implementations using checkasm's -benchmarking capabilities. - -**Next:** @ref benchmarking diff --git a/tests/checkasm/ext/ext-build-test.make b/tests/checkasm/ext/ext-build-test.make deleted file mode 100644 index 3bea491490..0000000000 --- a/tests/checkasm/ext/ext-build-test.make +++ /dev/null @@ -1,64 +0,0 @@ -# A simple makefile for testing building the files in a foreign build -# system. This is not intended as the user facing way of building the library. - -SRC_PATH = $(word 1, $(dir $(MAKEFILE_LIST))) -vpath %.c $(SRC_PATH) -vpath %.S $(SRC_PATH) -vpath %.asm $(SRC_PATH) - -CPPFLAGS = -I$(SRC_PATH) -I$(SRC_PATH)include -I$(SRC_PATH)src -I$(SRC_PATH)tests -CFLAGS = -std=gnu11 -Wundef $(EXTRA_CFLAGS) -LIBS = -lm -EXE = checkasm-selftest -OBJS = \ - src/arm/checkasm_32.o \ - src/arm/checkasm_64.o \ - src/arm/cpu.o \ - src/loongarch/checkasm.o \ - src/riscv/callcheck.o \ - src/riscv/cpu.o \ - src/x86/cpu.o \ - src/perf/arm.o \ - src/perf/linux.o \ - src/perf/macos_kperf.o \ - src/checkasm.o \ - src/cpu.o \ - src/function.o \ - src/perf.o \ - src/signal.o \ - src/stackguard.o \ - src/stats.o \ - src/utils.o \ - tests/selftest.o \ - tests/generic.o \ - tests/arm/32/tests.o \ - tests/arm/32/tests_asm.o \ - tests/arm/64/tests.o \ - tests/arm/64/tests_asm.o \ - tests/riscv/tests.o \ - tests/riscv/tests_asm.o \ - tests/x86/tests.o -NASM_OBJS = \ - src/x86/checkasm.o \ - tests/x86/tests_asm.o - -NASM_FMT ?= -ifdef NASM_FMT -OBJS += $(NASM_OBJS) -endif - -$(EXE): $(OBJS) - $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) - -%.o: %.asm - nasm -f $(NASM_FMT) $(CPPFLAGS) -o $@ $< - -OBJDIRS = $(sort $(dir $(OBJS))) - -$(OBJDIRS): - mkdir -p $@ - -$(OBJS): | $(OBJDIRS) - -clean: - $(RM) $(EXE) $(OBJS) $(NASM_OBJS) diff --git a/tests/checkasm/ext/gen-arm-core-table.sh b/tests/checkasm/ext/gen-arm-core-table.sh deleted file mode 100755 index 8b2b80f638..0000000000 --- a/tests/checkasm/ext/gen-arm-core-table.sh +++ /dev/null @@ -1,63 +0,0 @@ -#!/bin/sh - -# Copyright © 2026, Martin Storsjo -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -set -e - -LSCPU="$1" - -if [ -z "$LSCPU" ]; then - echo $0 lscpu-binary - exit 1 -fi - -make_symbol() { - echo "$1" | sed 's/[^A-Za-z_]/_/g' | tr A-Z a-z -} - -echo "/* Autogenerated with gen-arm-core-table.sh */" -echo "/* clang-format off */" -"$LSCPU" --arm-id | tail -n +2 | while read line; do - id=$(echo $line | cut -f 1 -d " ") - name=$(echo $line | cut -f 2- -d " ") - echo "static const struct arm_core cores_$(make_symbol "$name")[] = {" - "$LSCPU" --arm-id=$id | tail -n +2 | while read line; do - core_id=$(echo $line | cut -f 1 -d " ") - core_name=$(echo $line | cut -f 2- -d " ") - echo " { $core_id, \"$core_name\" }," - done - echo " { 0, NULL }," - echo "};" - echo "" -done - -echo "static const struct arm_implementer arm_implementers[] = {" -"$LSCPU" --arm-id | tail -n +2 | while read line; do - id=$(echo $line | cut -f 1 -d " ") - name=$(echo $line | cut -f 2- -d " ") - echo " { $id, cores_$(make_symbol "$name"), \"$name\" }," -done -echo " { 0, NULL, NULL }," -echo "};" diff --git a/tests/checkasm/ext/include/checkasm/meson.build b/tests/checkasm/ext/include/checkasm/meson.build deleted file mode 100644 index 3c9b4250eb..0000000000 --- a/tests/checkasm/ext/include/checkasm/meson.build +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright © 2025 Niklas Haas -# Copyright © 2018, VideoLAN and dav1d authors -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -api_header_file_names = [ - 'attributes.h', - 'checkasm.h', - 'test.h', - 'utils.h', -] - -extra_header_names = [ - 'header_config.h', - - 'perf.h', - 'perf/aarch64.h', - 'perf/arm.h', - 'perf/loongarch32.h', - 'perf/loongarch64.h', - 'perf/ppc64le.h', - 'perf/x86.h', - - 'platform.h', - 'platform/aarch64.h', - 'platform/arm.h', - 'platform/loongarch.h', - 'platform/ppc64le.h', - 'platform/riscv.h', - 'platform/x86_32.h', - 'platform/x86_64.h', -] - -checkasm_api_headers = files(api_header_file_names + extra_header_names) - -# Export these for the Doxygen build process (see docs/meson.build) -checkasm_include_dir = meson.current_source_dir() -checkasm_api_header_paths = [] -foreach file_name : api_header_file_names - checkasm_api_header_paths += checkasm_include_dir / file_name -endforeach - -if not meson.is_subproject() - install_headers(checkasm_api_headers, subdir: meson.project_name(), preserve_path: true) -endif diff --git a/tests/checkasm/ext/meson.build b/tests/checkasm/ext/meson.build deleted file mode 100644 index 6f5f9eef77..0000000000 --- a/tests/checkasm/ext/meson.build +++ /dev/null @@ -1,134 +0,0 @@ -# Copyright © 2025 Niklas Haas -# Copyright © 2024, Marvin Scholz -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -project('checkasm', 'c', - version: '1.3.0', - default_options: ['c_std=c11', - 'buildtype=debugoptimized', - 'default_library=static', - 'b_ndebug=if-release', - 'warning_level=2'], - meson_version : '>=0.64.0') - -# Project arguments and basic checks -cc = meson.get_compiler('c') - -optional_arguments = [] - -if cc.get_argument_syntax() != 'msvc' - optional_arguments += [ - '-Wundef', - '-Werror=vla', - '-Wno-maybe-uninitialized', - '-Wno-missing-field-initializers', - '-Wno-unused-parameter', - '-Wstrict-prototypes', - '-Werror=missing-prototypes', - '-Wshorten-64-to-32', - '-Wtype-limits', - '-Wredundant-decls', - '-Wimplicit-fallthrough=5', - ] -else - optional_arguments += [ - '-wd4028', # parameter different from declaration - '-wd4996', # use of POSIX functions - ] -endif - -add_project_arguments(cc.get_supported_arguments(optional_arguments), language : 'c') - -test_args = [] -if host_machine.system() in ['linux', 'gnu'] - add_project_arguments(['-D_POSIX_C_SOURCE=200112', '-D_XOPEN_SOURCE=600'], language: 'c') - test_args += ['-D_POSIX_C_SOURCE=200112', '-D_XOPEN_SOURCE=600'] -endif -if host_machine.system() in ['emscripten', 'os/2'] - add_project_arguments('-D_GNU_SOURCE', language: 'c') - test_args += '-D_GNU_SOURCE' -endif - -if get_option('b_sanitize') == 'memory' - error('asm causes false positives with the memory sanitizer.') -endif - -if host_machine.system() not in ['windows', 'os/2'] - if cc.has_argument('-fvisibility=hidden') - add_project_arguments('-fvisibility=hidden', language: 'c') - else - warning('Compiler does not support -fvisibility=hidden, all symbols will be public!') - endif -endif - -# Global paths -checkasm_src_root = meson.current_source_dir() -checkasm_inc_dirs = include_directories('.', 'include') - -# Global platform flags -arch_aarch64 = host_machine.cpu_family() == 'aarch64' or host_machine.cpu() == 'arm64' -arch_arm = host_machine.cpu_family().startswith('arm') and host_machine.cpu() != 'arm64' -arch_x86 = host_machine.cpu_family().startswith('x86') -arch_x86_64 = host_machine.cpu_family() == 'x86_64' -arch_x86_32 = host_machine.cpu_family() == 'x86' -arch_ppc64le = host_machine.cpu() == 'ppc64le' -arch_riscv = host_machine.cpu_family().startswith('riscv') -arch_rv32 = host_machine.cpu_family() == 'riscv32' -arch_rv64 = host_machine.cpu_family() == 'riscv64' -arch_loongarch = host_machine.cpu_family().startswith('loongarch') -arch_loongarch32 = host_machine.cpu_family() == 'loongarch32' -arch_loongarch64 = host_machine.cpu_family() == 'loongarch64' - -use_gaspp = false -if ((arch_aarch64 or arch_arm) and - cc.get_argument_syntax() == 'msvc' and cc.get_id() != 'clang-cl') - gaspp = find_program('gas-preprocessor.pl') - use_gaspp = true - gaspp_args = [ - '-as-type', 'armasm', - '-arch', host_machine.cpu_family(), - '--', - arch_aarch64 ? 'armasm64' : 'armasm', - '-nologo', - ] - gaspp_gen = generator(gaspp, - output: '@BASENAME@.obj', - arguments: gaspp_args + [ - '@EXTRA_ARGS@', - '@INPUT@', - '-c', - '-o', '@OUTPUT@' - ]) -endif - -# Global component configuration -build_tests = get_option('tests').disable_auto_if(meson.is_subproject()) -build_docs = get_option('docs' ).disable_auto_if(meson.is_subproject()) - -subdir('include/checkasm') -subdir('src') -subdir('docs') -subdir('tests') - -meson.override_dependency(meson.project_name(), checkasm_dep) diff --git a/tests/checkasm/ext/meson_options.txt b/tests/checkasm/ext/meson_options.txt deleted file mode 100644 index aab2d84b83..0000000000 --- a/tests/checkasm/ext/meson_options.txt +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright © 2025 Niklas Haas -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -option('docs', - type: 'feature', - value: 'auto', - description: 'Build API documentation with Doxygen' -) - -option('tests', - type: 'feature', - value: 'auto', - description: 'Build internal self-tests' -) diff --git a/tests/checkasm/ext/src/meson.build b/tests/checkasm/ext/src/meson.build deleted file mode 100644 index e81aa0288e..0000000000 --- a/tests/checkasm/ext/src/meson.build +++ /dev/null @@ -1,261 +0,0 @@ -# Copyright © 2018, VideoLAN and dav1d authors -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -# Dependencies -libm_dependency = cc.find_library('m', required: false) -rt_dependency = cc.find_library('rt', required: false) -libdl_dependency = cc.find_library('dl', required: false) -thread_dependency = dependency('threads') - -have_pthread_np = cc.check_header('pthread_np.h') -if have_pthread_np - test_args += '-DHAVE_PTHREAD_NP_H' -endif - -have_pthread_setaffinity_np = cc.has_function('pthread_setaffinity_np', - prefix: ''' - #include - #ifdef HAVE_PTHREAD_NP_H - #include - #endif - ''', - args: test_args + '-D_GNU_SOURCE', - dependencies: thread_dependency, -) -if not have_pthread_setaffinity_np - thread_dependency = [] -endif - - -have_clock_gettime = cc.has_function('clock_gettime', prefix : '#include ', args : test_args, dependencies : rt_dependency) -have_ioctl = cc.has_function('ioctl', prefix : '#include ', args : test_args) -have_isatty = cc.has_function('isatty', prefix : '#include ', args : test_args) -have_prctl = cc.has_function('prctl', prefix : '#include ', args : test_args) -have_sigaction = cc.has_function('sigaction', prefix : '#include ', args : test_args) -have_siglongjmp = cc.has_function('siglongjmp', prefix : '#include ', args : test_args) - -have_getauxval = false -have_elf_aux_info = false -if (arch_aarch64 or arch_arm or arch_loongarch or arch_ppc64le or arch_riscv) - have_getauxval = cc.has_function('getauxval', prefix : '#include ', args : test_args) - have_elf_aux_info = cc.has_function('elf_aux_info', prefix : '#include ', args : test_args) -endif - -have_stdbit_h = cc.check_header('stdbit.h') - -have_sys_hwprobe_h = false -have_asm_hwprobe_h = false -if arch_riscv - have_sys_hwprobe_h = cc.check_header('sys/hwprobe.h') - have_asm_hwprobe_h = cc.check_header('asm/hwprobe.h') -endif - -api_export_flags = [] -api_export_flags_asm = [] -if host_machine.system() == 'windows' - if get_option('default_library') != 'static' - # nasm's dllexport doesn't match the mingw conventions on x86_32, - # so don't do explicit dllexport at all, just let it export all symbols. - if cc.get_argument_syntax() == 'msvc' or not arch_x86_32 - api_export_flags = ['-DCHECKASM_BUILDING_DLL', '-DBUILDING_DLL'] - api_export_flags_asm = ['-DBUILDING_DLL'] - endif - endif -endif - -if build_tests.allowed() - api_export_flags += '-DCHECKASM_BUILDING_TESTS' - api_export_flags_asm += '-DCHECKASM_BUILDING_TESTS' -endif - -have_linux_perf = false -if host_machine.system() == 'linux' - have_linux_perf = cc.has_header_symbol('linux/perf_event.h', 'PERF_COUNT_HW_CPU_CYCLES', args: test_args) -endif - -# Build configuration -cdata = configuration_data() -cdata.set('PREFIX', cc.symbols_have_underscore_prefix()) -cdata.set_quoted('CHECKASM_VERSION', meson.project_version()) -cdata.set10('ARCH_AARCH64', arch_aarch64) -cdata.set10('ARCH_ARM', arch_arm) -cdata.set10('ARCH_X86', arch_x86) -cdata.set10('ARCH_X86_64', arch_x86_64) -cdata.set10('ARCH_X86_32', arch_x86_32) -cdata.set10('ARCH_PPC64LE', arch_ppc64le) -cdata.set10('ARCH_RISCV', arch_riscv) -cdata.set10('ARCH_RV32', arch_rv32) -cdata.set10('ARCH_RV64', arch_rv64) -cdata.set10('ARCH_LOONGARCH', arch_loongarch) -cdata.set10('ARCH_LOONGARCH32', arch_loongarch32) -cdata.set10('ARCH_LOONGARCH64', arch_loongarch64) -cdata.set10('HAVE_PTHREAD_NP_H', have_pthread_np) -cdata.set10('HAVE_PTHREAD_SETAFFINITY_NP', have_pthread_setaffinity_np) -cdata.set10('HAVE_CLOCK_GETTIME', have_clock_gettime) -cdata.set10('HAVE_IOCTL', have_ioctl) -cdata.set10('HAVE_ISATTY', have_isatty) -cdata.set10('HAVE_SIGACTION', have_sigaction) -cdata.set10('HAVE_SIGLONGJMP', have_siglongjmp) -cdata.set10('HAVE_GETAUXVAL', have_getauxval) -cdata.set10('HAVE_ELF_AUX_INFO', have_elf_aux_info) -cdata.set10('HAVE_LINUX_PERF', have_linux_perf) -cdata.set10('HAVE_STDBIT_H', have_stdbit_h) -cdata.set10('HAVE_PRCTL', have_prctl) - -if arch_x86 - cdata_asm = configuration_data() - cdata_asm.set('PREFIX', cc.symbols_have_underscore_prefix()) - cdata_asm.set10('ARCH_X86_64', arch_x86_64) - cdata_asm.set10('ARCH_X86_32', arch_x86_32) - cdata_asm.set10('PIC', true) - cdata_asm.set10('FORCE_VEX_ENCODING', cc.get_define('__AVX__').strip() != '') -endif - -if arch_aarch64 - if use_gaspp - python3 = import('python').find_installation() - endif - aarch64_extensions = { - 'sve': ['whilelt p0.s, x0, x1'], - 'sme': ['smstart', 'cntb x0'], - } - foreach name, instrs : aarch64_extensions - if use_gaspp - instr = '\n'.join(instrs) - f = configure_file( - command: [python3, '-c', 'import sys; print(sys.argv[1])', '@0@'.format(instr)], - output: 'test-@0@.S'.format(name), - capture: true) - r = run_command(gaspp, gaspp_args, f, '-c', '-o', meson.current_build_dir() / 'test-' + name + '.obj', check: false) - message('Checking for gaspp/armasm64 ' + name.to_upper() + ': ' + (r.returncode() == 0 ? 'YES' : 'NO')) - archext_supported = false - supported = r.returncode() == 0 - else - instr = '\\n'.join(instrs) - code = f'__asm__ (".arch_extension @name@\\n@instr@\\n");' - supported = cc.compiles(code, name: name.to_upper()) - archext_supported = supported - endif - cdata.set10('HAVE_AS_ARCHEXT_' + name.to_upper() + '_DIRECTIVE', archext_supported) - cdata.set10('HAVE_' + name.to_upper(), supported) - endforeach -endif - -if arch_riscv - cdata.set10('HAVE_SYS_HWPROBE_H', have_sys_hwprobe_h) - cdata.set10('HAVE_ASM_HWPROBE_H', have_asm_hwprobe_h) -endif - -checkasm_config = [] -checkasm_config += configure_file( - output: 'checkasm_config_generated.h', - configuration: cdata, - install: false, -) - -# Build definition -checkasm_asm_objs = [] -checkasm_sources = files( - 'arm/cpu.c', - 'checkasm.c', - 'cpu.c', - 'function.c', - 'perf.c', - 'perf/arm.c', - 'perf/linux.c', - 'perf/macos_kperf.c', - 'riscv/cpu.c', - 'signal.c', - 'stackguard.c', - 'stats.c', - 'utils.c', - 'x86/cpu.c', -) - -checkasm_asm_sources = [] -if arch_aarch64 - checkasm_asm_sources = files('arm/checkasm_64.S') -elif arch_arm - checkasm_asm_sources = files('arm/checkasm_32.S') -elif arch_loongarch - checkasm_sources += files('loongarch/checkasm.S') -elif arch_riscv - checkasm_sources += files('riscv/callcheck.S') -elif arch_x86 - add_languages('nasm', native: false) - configure_file( - output: 'checkasm_config_generated.asm', - output_format: 'nasm', - configuration: cdata_asm, - install: false, - ) - checkasm_sources += files( - 'x86/checkasm.asm', - ) -endif - -if use_gaspp - gaspp_args = api_export_flags_asm + [ - '-I@0@'.format(meson.project_source_root() + '/include'), - '-I@0@'.format(meson.current_source_dir()), - '-I@0@'.format(meson.current_build_dir()), - '-DCHECKASM_HAVE_GENERATED_H', - ] - checkasm_asm_objs += gaspp_gen.process(checkasm_asm_sources, extra_args: gaspp_args) -else - checkasm_sources += checkasm_asm_sources -endif - -checkasm_dependencies = [ - thread_dependency, - rt_dependency, - libdl_dependency, - libm_dependency, -] - -checkasm_library = library(meson.project_name(), - checkasm_sources, - checkasm_config, - checkasm_asm_objs, - c_args : [api_export_flags, '-DCHECKASM_HAVE_GENERATED_H'], - nasm_args : [api_export_flags_asm, '-DCHECKASM_HAVE_GENERATED_H'], - include_directories: checkasm_inc_dirs, - dependencies: checkasm_dependencies, - install: not meson.is_subproject(), -) - -checkasm_dep = declare_dependency( - link_with: checkasm_library, - include_directories: checkasm_inc_dirs, -) - -if not meson.is_subproject() - pkg = import('pkgconfig') - pkg.generate( - name: meson.project_name(), - description: 'checkasm for all your asm checking needs', - libraries: checkasm_library, - version: meson.project_version(), - ) -endif diff --git a/tests/checkasm/ext/tests/arm/32/tests.c b/tests/checkasm/ext/tests/arm/32/tests.c deleted file mode 100644 index eff47114d3..0000000000 --- a/tests/checkasm/ext/tests/arm/32/tests.c +++ /dev/null @@ -1,222 +0,0 @@ -#include "tests.h" - -#if ARCH_ARM - -/* Re-use helpers from main checkasm library */ -#include "src/cpu.h" - -uint64_t selftest_get_cpu_flags_arm(void) -{ - uint64_t flags = SELFTEST_CPU_FLAG_ARM; - if (checkasm_has_vfp()) - flags |= SELFTEST_CPU_FLAG_VFP; - if (checkasm_has_vfpd32()) - flags |= SELFTEST_CPU_FLAG_VFPD32; - return flags; -} - -DEF_NOOP_FUNC(clobber_r0); -DEF_NOOP_FUNC(clobber_r1); -DEF_NOOP_FUNC(clobber_r2); -DEF_NOOP_FUNC(clobber_r3); -DEF_NOOP_FUNC(clobber_r4); -DEF_NOOP_FUNC(clobber_r5); -DEF_NOOP_FUNC(clobber_r6); -DEF_NOOP_FUNC(clobber_r7); -DEF_NOOP_FUNC(clobber_r8); -DEF_NOOP_FUNC(clobber_r9); -DEF_NOOP_FUNC(clobber_r10); -DEF_NOOP_FUNC(clobber_r11); -DEF_NOOP_FUNC(clobber_r12); -DEF_NOOP_FUNC(clobber_d0); -DEF_NOOP_FUNC(clobber_d1); -DEF_NOOP_FUNC(clobber_d2); -DEF_NOOP_FUNC(clobber_d3); -DEF_NOOP_FUNC(clobber_d4); -DEF_NOOP_FUNC(clobber_d5); -DEF_NOOP_FUNC(clobber_d6); -DEF_NOOP_FUNC(clobber_d7); -DEF_NOOP_FUNC(clobber_d8); -DEF_NOOP_FUNC(clobber_d9); -DEF_NOOP_FUNC(clobber_d10); -DEF_NOOP_FUNC(clobber_d11); -DEF_NOOP_FUNC(clobber_d12); -DEF_NOOP_FUNC(clobber_d13); -DEF_NOOP_FUNC(clobber_d14); -DEF_NOOP_FUNC(clobber_d15); -DEF_NOOP_FUNC(clobber_d16); -DEF_NOOP_FUNC(clobber_d17); -DEF_NOOP_FUNC(clobber_d18); -DEF_NOOP_FUNC(clobber_d19); -DEF_NOOP_FUNC(clobber_d20); -DEF_NOOP_FUNC(clobber_d21); -DEF_NOOP_FUNC(clobber_d22); -DEF_NOOP_FUNC(clobber_d23); -DEF_NOOP_FUNC(clobber_d24); -DEF_NOOP_FUNC(clobber_d25); -DEF_NOOP_FUNC(clobber_d26); -DEF_NOOP_FUNC(clobber_d27); -DEF_NOOP_FUNC(clobber_d28); -DEF_NOOP_FUNC(clobber_d29); -DEF_NOOP_FUNC(clobber_d30); -DEF_NOOP_FUNC(clobber_d31); - -DEF_NOOP_FUNC(sigill_arm); -DEF_NOOP_FUNC(clobber_fpscr_vfp); - -// A function with 4 parameters in registers and 1 on the stack. -typedef void(many_args_func)(int, int, int, int, int); - -#define DEF_MANY_ARGS_FUNC(NAME) void selftest_##NAME(int, int, int, int, int) -#define DEF_MANY_ARGS_GETTER(FLAG, NAME) DEF_GETTER(FLAG, NAME, many_args_func, NULL) - -DEF_MANY_ARGS_FUNC(clobber_stack_args_arm); -DEF_MANY_ARGS_FUNC(clobber_stack_arm); - -static noop_func *get_clobber_r(int reg) -{ - if (!(checkasm_get_cpu_flags() & SELFTEST_CPU_FLAG_ARM)) - return NULL; - - switch (reg) { - case 0: return selftest_clobber_r0; - case 1: return selftest_clobber_r1; - case 2: return selftest_clobber_r2; - case 3: return selftest_clobber_r3; - case 4: return selftest_clobber_r4; - case 5: return selftest_clobber_r5; - case 6: return selftest_clobber_r6; - case 7: return selftest_clobber_r7; - case 8: return selftest_clobber_r8; - case 9: return selftest_clobber_r9; - case 10: return selftest_clobber_r10; - case 11: return selftest_clobber_r11; - case 12: return selftest_clobber_r12; - case 13: return NULL; /* Shouldn't try to clobber SP */ - case 14: return NULL; /* Shouldn't try to clobber LR */ - case 15: return NULL; /* Shouldn't try to clobber PC */ - default: return NULL; - } -} - -static noop_func *get_clobber_d(int reg) -{ - if (!(checkasm_get_cpu_flags() & SELFTEST_CPU_FLAG_VFP)) - return NULL; - if (reg >= 16 && !(checkasm_get_cpu_flags() & SELFTEST_CPU_FLAG_VFPD32)) - return NULL; - - switch (reg) { - case 0: return selftest_clobber_d0; - case 1: return selftest_clobber_d1; - case 2: return selftest_clobber_d2; - case 3: return selftest_clobber_d3; - case 4: return selftest_clobber_d4; - case 5: return selftest_clobber_d5; - case 6: return selftest_clobber_d6; - case 7: return selftest_clobber_d7; - case 8: return selftest_clobber_d8; - case 9: return selftest_clobber_d9; - case 10: return selftest_clobber_d10; - case 11: return selftest_clobber_d11; - case 12: return selftest_clobber_d12; - case 13: return selftest_clobber_d13; - case 14: return selftest_clobber_d14; - case 15: return selftest_clobber_d15; - case 16: return selftest_clobber_d16; - case 17: return selftest_clobber_d17; - case 18: return selftest_clobber_d18; - case 19: return selftest_clobber_d19; - case 20: return selftest_clobber_d20; - case 21: return selftest_clobber_d21; - case 22: return selftest_clobber_d22; - case 23: return selftest_clobber_d23; - case 24: return selftest_clobber_d24; - case 25: return selftest_clobber_d25; - case 26: return selftest_clobber_d26; - case 27: return selftest_clobber_d27; - case 28: return selftest_clobber_d28; - case 29: return selftest_clobber_d29; - case 30: return selftest_clobber_d30; - case 31: return selftest_clobber_d31; - default: return NULL; - } -} - -DEF_NOOP_GETTER(SELFTEST_CPU_FLAG_ARM, sigill_arm) -DEF_NOOP_GETTER(SELFTEST_CPU_FLAG_VFP, clobber_fpscr_vfp) -DEF_MANY_ARGS_GETTER(SELFTEST_CPU_FLAG_ARM, clobber_stack_args_arm) -DEF_MANY_ARGS_GETTER(SELFTEST_CPU_FLAG_ARM, clobber_stack_arm) - -static void check_clobber_r(int from, int to) -{ - checkasm_declare(void, int); - - for (int reg = from; reg < to; reg++) { - noop_func *clobber = get_clobber_r(reg); - if (!clobber) - break; - - if (checkasm_check_func(clobber, "clobber_r%d", reg)) { - checkasm_call_new(0); - } - } - - checkasm_report("clobber_r"); -} - -static void check_clobber_d(int from, int to) -{ - checkasm_declare(void, int); - - for (int reg = from; reg < to; reg++) { - noop_func *clobber = get_clobber_d(reg); - if (!clobber) - break; - - if (checkasm_check_func(clobber, "clobber_d%d", reg)) { - checkasm_call_new(0); - } - } - - checkasm_report("clobber_d"); -} - -static void selftest_test_many_args(many_args_func fun, const char *name) -{ - checkasm_declare(void, int, int, int, int, int); - - if (checkasm_check_func(fun, "%s", name)) { - /* don't call unchecked because that one is called without wrapping, - * and we try to cloober the stack here. */ - (void) func_ref; - checkasm_call_new(1, 2, 3, 4, 5); - } - - checkasm_report("%s", name); -} - -void selftest_check_arm(void) -{ - check_clobber_r(0, 4); - check_clobber_r(12, 13); - check_clobber_d(0, 8); - check_clobber_d(16, 32); - selftest_test_many_args(get_clobber_stack_args_arm(), "clobber_stack_args"); - - if (!checkasm_should_fail(SELFTEST_CPU_FLAG_ARM)) - return; - selftest_test_noop(get_sigill_arm(), "sigill"); - selftest_test_many_args(get_clobber_stack_arm(), "clobber_stack"); - selftest_test_noop(get_clobber_fpscr_vfp(), "clobber_fpscr"); - check_clobber_r(4, 9); -#ifndef __APPLE__ - // In the iOS ABI, r9 is a volatile register, so we don't check if it is - // clobbered in the checked_call wrapper. - check_clobber_r(9, 10); -#endif - check_clobber_r(10, 11); - check_clobber_d(8, 16); -} - -#endif diff --git a/tests/checkasm/ext/tests/arm/32/tests_asm.S b/tests/checkasm/ext/tests/arm/32/tests_asm.S deleted file mode 100644 index 38e6ebcdc1..0000000000 --- a/tests/checkasm/ext/tests/arm/32/tests_asm.S +++ /dev/null @@ -1,108 +0,0 @@ -/****************************************************************************** - * Copyright © 2025 Martin Storsjo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - -#define PRIVATE_PREFIX selftest_ - -#include "src/checkasm_config.h" - -#if ARCH_ARM - -#include "src/arm/asm.S" - -#ifndef __ARM_ARCH -#ifdef _M_ARM -#define __ARM_ARCH _M_ARM -#else -#define __ARM_ARCH 0 -#endif -#endif - -.macro v4bx rd -#if __ARM_ARCH >= 5 || defined(__ARM_ARCH_4T__) - bx \rd -#else - mov pc, \rd -#endif -.endm - -function sigill_arm, export=1 - udf #0 - v4bx lr -endfunc - -.macro clobber_r reg -function clobber_\reg, export=1 - mov \reg, #0x42 - v4bx lr -endfunc -.endm - -.macro clobber_d reg -function clobber_\reg, export=1 - mov r0, #0x42 - mov r1, #0x42 - vmov \reg, r0, r1 - v4bx lr -endfunc -.endm - -.irp r, r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12 -clobber_r \r -.endr - -.irp r, d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15, d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31 -clobber_d \r -.endr - -// void clobber_stack_args_arm(int, int, int, int, int); -// -// Write into the stack of the caller, overwriting the arguments that are on -// the stack. This is legal to do. -function clobber_stack_args_arm, export=1 - mov r0, #0x42 - str r0, [sp, #0] - v4bx lr -endfunc - -// void clobber_stack_arm(int, int, int, int, int); -// -// Write into the stack of the caller, writing past the arguments on the stack -// that we are allowed to touch. -function clobber_stack_arm, export=1 - mov r0, #0x42 - str r0, [sp, #0] - str r0, [sp, #4] - v4bx lr -endfunc - -function clobber_fpscr_vfp, export=1 - // Flush to zero, default NaN mode, round towards zero - ldr r12, =0x3C00000 - fmxr fpscr, r12 - v4bx lr -endfunc - -#endif diff --git a/tests/checkasm/ext/tests/arm/64/tests.c b/tests/checkasm/ext/tests/arm/64/tests.c deleted file mode 100644 index 44fbeb14c5..0000000000 --- a/tests/checkasm/ext/tests/arm/64/tests.c +++ /dev/null @@ -1,387 +0,0 @@ -#include "tests.h" - -#if ARCH_AARCH64 - -uint64_t selftest_get_cpu_flags_aarch64(void) -{ - return SELFTEST_CPU_FLAG_AARCH64; -} - -DEF_NOOP_FUNC(clobber_x0); -DEF_NOOP_FUNC(clobber_x1); -DEF_NOOP_FUNC(clobber_x2); -DEF_NOOP_FUNC(clobber_x3); -DEF_NOOP_FUNC(clobber_x4); -DEF_NOOP_FUNC(clobber_x5); -DEF_NOOP_FUNC(clobber_x6); -DEF_NOOP_FUNC(clobber_x7); -DEF_NOOP_FUNC(clobber_x8); -DEF_NOOP_FUNC(clobber_x9); -DEF_NOOP_FUNC(clobber_x10); -DEF_NOOP_FUNC(clobber_x11); -DEF_NOOP_FUNC(clobber_x12); -DEF_NOOP_FUNC(clobber_x13); -DEF_NOOP_FUNC(clobber_x14); -DEF_NOOP_FUNC(clobber_x15); -DEF_NOOP_FUNC(clobber_x16); -DEF_NOOP_FUNC(clobber_x17); -// x18 skipped -DEF_NOOP_FUNC(clobber_x19); -DEF_NOOP_FUNC(clobber_x20); -DEF_NOOP_FUNC(clobber_x21); -DEF_NOOP_FUNC(clobber_x22); -DEF_NOOP_FUNC(clobber_x23); -DEF_NOOP_FUNC(clobber_x24); -DEF_NOOP_FUNC(clobber_x25); -DEF_NOOP_FUNC(clobber_x26); -DEF_NOOP_FUNC(clobber_x27); -DEF_NOOP_FUNC(clobber_x28); -DEF_NOOP_FUNC(clobber_x29); - -DEF_NOOP_FUNC(clobber_d0); -DEF_NOOP_FUNC(clobber_d1); -DEF_NOOP_FUNC(clobber_d2); -DEF_NOOP_FUNC(clobber_d3); -DEF_NOOP_FUNC(clobber_d4); -DEF_NOOP_FUNC(clobber_d5); -DEF_NOOP_FUNC(clobber_d6); -DEF_NOOP_FUNC(clobber_d7); -DEF_NOOP_FUNC(clobber_d8); -DEF_NOOP_FUNC(clobber_d9); -DEF_NOOP_FUNC(clobber_d10); -DEF_NOOP_FUNC(clobber_d11); -DEF_NOOP_FUNC(clobber_d12); -DEF_NOOP_FUNC(clobber_d13); -DEF_NOOP_FUNC(clobber_d14); -DEF_NOOP_FUNC(clobber_d15); -DEF_NOOP_FUNC(clobber_d16); -DEF_NOOP_FUNC(clobber_d17); -DEF_NOOP_FUNC(clobber_d18); -DEF_NOOP_FUNC(clobber_d19); -DEF_NOOP_FUNC(clobber_d20); -DEF_NOOP_FUNC(clobber_d21); -DEF_NOOP_FUNC(clobber_d22); -DEF_NOOP_FUNC(clobber_d23); -DEF_NOOP_FUNC(clobber_d24); -DEF_NOOP_FUNC(clobber_d25); -DEF_NOOP_FUNC(clobber_d26); -DEF_NOOP_FUNC(clobber_d27); -DEF_NOOP_FUNC(clobber_d28); -DEF_NOOP_FUNC(clobber_d29); -DEF_NOOP_FUNC(clobber_d30); -DEF_NOOP_FUNC(clobber_d31); - -DEF_NOOP_FUNC(clobber_v8_upper); -DEF_NOOP_FUNC(clobber_v9_upper); -DEF_NOOP_FUNC(clobber_v10_upper); -DEF_NOOP_FUNC(clobber_v11_upper); -DEF_NOOP_FUNC(clobber_v12_upper); -DEF_NOOP_FUNC(clobber_v13_upper); -DEF_NOOP_FUNC(clobber_v14_upper); -DEF_NOOP_FUNC(clobber_v15_upper); - -DEF_NOOP_FUNC(sigill_aarch64); - -// A function with 8 parameters in registers and 3 on the stack. -typedef void(many_args_func)(int, int, int, int, int, int, int, int, int, int, int); - -#define DEF_MANY_ARGS_FUNC(NAME) \ - void selftest_##NAME(int, int, int, int, int, int, int, int, int, int, int) -#define DEF_MANY_ARGS_GETTER(FLAG, NAME) DEF_GETTER(FLAG, NAME, many_args_func, NULL) - -DEF_MANY_ARGS_FUNC(clobber_stack_args_aarch64); -DEF_MANY_ARGS_FUNC(clobber_stack_aarch64); -DEF_MANY_ARGS_FUNC(check_clobber_upper_x0_aarch64); -DEF_MANY_ARGS_FUNC(check_clobber_upper_x1_aarch64); -DEF_MANY_ARGS_FUNC(check_clobber_upper_x2_aarch64); -DEF_MANY_ARGS_FUNC(check_clobber_upper_x3_aarch64); -DEF_MANY_ARGS_FUNC(check_clobber_upper_x4_aarch64); -DEF_MANY_ARGS_FUNC(check_clobber_upper_x5_aarch64); -DEF_MANY_ARGS_FUNC(check_clobber_upper_x6_aarch64); -DEF_MANY_ARGS_FUNC(check_clobber_upper_x7_aarch64); -DEF_MANY_ARGS_FUNC(check_clobber_upper_stack0_aarch64); -DEF_MANY_ARGS_FUNC(check_clobber_upper_stack1_aarch64); -DEF_MANY_ARGS_FUNC(check_clobber_upper_stack2_aarch64); - -// A function with MAX_ARGS (15) arguments -typedef void(max_int_args_func)(int, int, int, int, int, int, int, int, int, int, int, - int, int, int, int); -typedef void(max_int64_args_func)(int64_t, int64_t, int64_t, int64_t, int64_t, int64_t, - int64_t, int64_t, int64_t, int64_t, int64_t, int64_t, - int64_t, int64_t, int64_t); - -#define DEF_MAX_INT_ARGS_FUNC(NAME) \ - void selftest_##NAME(int, int, int, int, int, int, int, int, int, int, int, int, \ - int, int, int) -#define DEF_MAX_INT_ARGS_GETTER(FLAG, NAME) \ - DEF_GETTER(FLAG, NAME, max_int_args_func, NULL) -#define DEF_MAX_INT64_ARGS_FUNC(NAME) \ - void selftest_##NAME(int64_t, int64_t, int64_t, int64_t, int64_t, int64_t, int64_t, \ - int64_t, int64_t, int64_t, int64_t, int64_t, int64_t, int64_t, \ - int64_t) -#define DEF_MAX_INT64_ARGS_GETTER(FLAG, NAME) \ - DEF_GETTER(FLAG, NAME, max_int64_args_func, NULL) - -DEF_MAX_INT_ARGS_FUNC(check_max_int_args_aarch64); -DEF_MAX_INT64_ARGS_FUNC(check_max_int64_args_aarch64); - -static noop_func *get_clobber_x(int reg) -{ - if (!(checkasm_get_cpu_flags() & SELFTEST_CPU_FLAG_AARCH64)) - return NULL; - - switch (reg) { - case 0: return selftest_clobber_x0; - case 1: return selftest_clobber_x1; - case 2: return selftest_clobber_x2; - case 3: return selftest_clobber_x3; - case 4: return selftest_clobber_x4; - case 5: return selftest_clobber_x5; - case 6: return selftest_clobber_x6; - case 7: return selftest_clobber_x7; - case 8: return selftest_clobber_x8; - case 9: return selftest_clobber_x9; - case 10: return selftest_clobber_x10; - case 11: return selftest_clobber_x11; - case 12: return selftest_clobber_x12; - case 13: return selftest_clobber_x13; - case 14: return selftest_clobber_x14; - case 15: return selftest_clobber_x15; - case 16: return selftest_clobber_x16; - case 17: return selftest_clobber_x17; - // x18 skipped - case 19: return selftest_clobber_x19; - case 20: return selftest_clobber_x20; - case 21: return selftest_clobber_x21; - case 22: return selftest_clobber_x22; - case 23: return selftest_clobber_x23; - case 24: return selftest_clobber_x24; - case 25: return selftest_clobber_x25; - case 26: return selftest_clobber_x26; - case 27: return selftest_clobber_x27; - case 28: return selftest_clobber_x28; - case 29: return selftest_clobber_x29; - default: return NULL; - } -} - -static noop_func *get_clobber_d(int reg) -{ - if (!(checkasm_get_cpu_flags() & SELFTEST_CPU_FLAG_AARCH64)) - return NULL; - - switch (reg) { - case 0: return selftest_clobber_d0; - case 1: return selftest_clobber_d1; - case 2: return selftest_clobber_d2; - case 3: return selftest_clobber_d3; - case 4: return selftest_clobber_d4; - case 5: return selftest_clobber_d5; - case 6: return selftest_clobber_d6; - case 7: return selftest_clobber_d7; - case 8: return selftest_clobber_d8; - case 9: return selftest_clobber_d9; - case 10: return selftest_clobber_d10; - case 11: return selftest_clobber_d11; - case 12: return selftest_clobber_d12; - case 13: return selftest_clobber_d13; - case 14: return selftest_clobber_d14; - case 15: return selftest_clobber_d15; - case 16: return selftest_clobber_d16; - case 17: return selftest_clobber_d17; - case 18: return selftest_clobber_d18; - case 19: return selftest_clobber_d19; - case 20: return selftest_clobber_d20; - case 21: return selftest_clobber_d21; - case 22: return selftest_clobber_d22; - case 23: return selftest_clobber_d23; - case 24: return selftest_clobber_d24; - case 25: return selftest_clobber_d25; - case 26: return selftest_clobber_d26; - case 27: return selftest_clobber_d27; - case 28: return selftest_clobber_d28; - case 29: return selftest_clobber_d29; - case 30: return selftest_clobber_d30; - case 31: return selftest_clobber_d31; - default: return NULL; - } -} - -static noop_func *get_clobber_v_upper(int reg) -{ - if (!(checkasm_get_cpu_flags() & SELFTEST_CPU_FLAG_AARCH64)) - return NULL; - - switch (reg) { - case 8: return selftest_clobber_v8_upper; - case 9: return selftest_clobber_v9_upper; - case 10: return selftest_clobber_v10_upper; - case 11: return selftest_clobber_v11_upper; - case 12: return selftest_clobber_v12_upper; - case 13: return selftest_clobber_v13_upper; - case 14: return selftest_clobber_v14_upper; - case 15: return selftest_clobber_v15_upper; - default: return NULL; - } -} - -static many_args_func *get_check_clobber_upper(int arg) -{ - if (!(checkasm_get_cpu_flags() & SELFTEST_CPU_FLAG_AARCH64)) - return NULL; - - switch (arg) { - case 0: return selftest_check_clobber_upper_x0_aarch64; - case 1: return selftest_check_clobber_upper_x1_aarch64; - case 2: return selftest_check_clobber_upper_x2_aarch64; - case 3: return selftest_check_clobber_upper_x3_aarch64; - case 4: return selftest_check_clobber_upper_x4_aarch64; - case 5: return selftest_check_clobber_upper_x5_aarch64; - case 6: return selftest_check_clobber_upper_x6_aarch64; - case 7: return selftest_check_clobber_upper_x7_aarch64; - case 8: return selftest_check_clobber_upper_stack0_aarch64; - case 9: return selftest_check_clobber_upper_stack1_aarch64; - case 10: return selftest_check_clobber_upper_stack2_aarch64; - default: return NULL; - } -} - -DEF_NOOP_GETTER(SELFTEST_CPU_FLAG_AARCH64, sigill_aarch64) -DEF_MANY_ARGS_GETTER(SELFTEST_CPU_FLAG_AARCH64, clobber_stack_args_aarch64) -DEF_MANY_ARGS_GETTER(SELFTEST_CPU_FLAG_AARCH64, clobber_stack_aarch64) - -DEF_MAX_INT_ARGS_GETTER(SELFTEST_CPU_FLAG_AARCH64, check_max_int_args_aarch64) -DEF_MAX_INT64_ARGS_GETTER(SELFTEST_CPU_FLAG_AARCH64, check_max_int64_args_aarch64) - -static void check_clobber_x(int from, int to) -{ - checkasm_declare(void, int); - - for (int reg = from; reg < to; reg++) { - noop_func *clobber = get_clobber_x(reg); - if (!clobber) - break; - - if (checkasm_check_func(clobber, "clobber_x%d", reg)) { - checkasm_call_new(0); - } - } - - checkasm_report("clobber_x"); -} - -static void check_clobber_d(int from, int to) -{ - checkasm_declare(void, int); - - for (int reg = from; reg < to; reg++) { - noop_func *clobber = get_clobber_d(reg); - if (!clobber) - break; - - if (checkasm_check_func(clobber, "clobber_d%d", reg)) { - checkasm_call_new(0); - } - } - - checkasm_report("clobber_d"); -} - -static void check_clobber_v_upper(int from, int to) -{ - checkasm_declare(void, int); - - for (int reg = from; reg < to; reg++) { - noop_func *clobber = get_clobber_v_upper(reg); - if (!clobber) - break; - - if (checkasm_check_func(clobber, "clobber_v%d_upper", reg)) { - checkasm_call_new(0); - } - } - - checkasm_report("clobber_v_upper"); -} - -static void check_clobber_arg_upper(void) -{ - checkasm_declare(void, int, int, int, int, int, int, int, int, int, int, int); - - for (int arg = 0; arg < 11; arg++) { - many_args_func *check_clobber = get_check_clobber_upper(arg); - if (!check_clobber) - break; - - if (checkasm_check_func(check_clobber, "check_clobber_arg_upper_%d", arg)) { - checkasm_call_new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11); - } - } - - checkasm_report("check_clobber_arg_upper"); -} - -static void selftest_test_many_args(many_args_func fun, const char *name) -{ - checkasm_declare(void, int, int, int, int, int, int, int, int, int, int, int); - - if (checkasm_check_func(fun, "%s", name)) { - /* don't call unchecked because that one is called without wrapping, - * and we try to cloober the stack here. */ - (void) func_ref; - checkasm_call_new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11); - } - - checkasm_report("%s", name); -} - -static void selftest_test_max_int_args(max_int_args_func fun, const char *name) -{ - checkasm_declare(void, int, int, int, int, int, int, int, int, int, int, int, int, - int, int, int); - - if (checkasm_check_func(fun, "%s", name)) { - (void) func_ref; - checkasm_call_new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - } - - checkasm_report("%s", name); -} - -static void selftest_test_max_int64_args(max_int64_args_func fun, const char *name) -{ - checkasm_declare(void, int64_t, int64_t, int64_t, int64_t, int64_t, int64_t, int64_t, - int64_t, int64_t, int64_t, int64_t, int64_t, int64_t, int64_t, - int64_t); - - if (checkasm_check_func(fun, "%s", name)) { - (void) func_ref; - checkasm_call_new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - } - - checkasm_report("%s", name); -} - -void selftest_check_aarch64(void) -{ - check_clobber_x(0, 18); - // Don't try testing x18 - it has platform specific behaviour. - check_clobber_d(0, 8); - check_clobber_d(16, 32); - check_clobber_v_upper(8, 16); - selftest_test_many_args(get_clobber_stack_args_aarch64(), "clobber_stack_args"); - - selftest_test_max_int_args(get_check_max_int_args_aarch64(), "check_max_int_args"); - selftest_test_max_int64_args(get_check_max_int64_args_aarch64(), - "check_max_int64_args"); - check_clobber_arg_upper(); - - if (!checkasm_should_fail(SELFTEST_CPU_FLAG_AARCH64)) - return; - selftest_test_noop(get_sigill_aarch64(), "sigill"); - selftest_test_many_args(get_clobber_stack_aarch64(), "clobber_stack"); - check_clobber_x(19, 30); - check_clobber_d(8, 16); -} - -#endif diff --git a/tests/checkasm/ext/tests/arm/64/tests_asm.S b/tests/checkasm/ext/tests/arm/64/tests_asm.S deleted file mode 100644 index 7ddf270e9d..0000000000 --- a/tests/checkasm/ext/tests/arm/64/tests_asm.S +++ /dev/null @@ -1,247 +0,0 @@ -/****************************************************************************** - * Copyright © 2025 Martin Storsjo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - -#define PRIVATE_PREFIX selftest_ - -#include "src/checkasm_config.h" - -#if ARCH_AARCH64 - -#include "src/arm/asm.S" - -function sigill_aarch64, export=1 - .inst 0 // udf #0 - ret -endfunc - -.macro clobber_x reg -function clobber_\reg, export=1 - mov \reg, #0x42 - ret -endfunc -.endm - -.macro clobber_d reg -function clobber_d\reg, export=1 - movi v\reg\().8b, #0x42 - ret -endfunc -.endm - -.macro clobber_v_upper reg -function clobber_v\reg\()_upper, export=1 - str d\reg, [sp, #-16]! - movi v\reg\().16b, #0x42 - ldr d\reg, [sp], #16 - ret -endfunc -.endm - -.irp r, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17 -clobber_x \r -.endr -// x18 skipped -.irp r, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29 -clobber_x \r -.endr - -.irp r, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 -clobber_d \r -.endr - -.irp r, 8, 9, 10, 11, 12, 13, 14, 15 -clobber_v_upper \r -.endr - -// void clobber_stack_args_aarch64(int, int, int, int, int, int, int, int, int, int, int); -// -// Write into the stack of the caller, overwriting the arguments that are on -// the stack. This is legal to do. -function clobber_stack_args_aarch64, export=1 - mov w0, #0x42 -#ifdef __APPLE__ - str w0, [sp, #0] - str w0, [sp, #4] - str w0, [sp, #8] -#else - str w0, [sp, #0] - str w0, [sp, #8] - str w0, [sp, #16] -#endif - ret -endfunc - -// void clobber_stack_aarch64(int, int, int, int, int, int, int, int, int, int, int); -// -// Write into the stack of the caller, writing past the arguments on the stack -// that we are allowed to touch. -function clobber_stack_aarch64, export=1 - mov w0, #0x42 -#ifdef __APPLE__ - str w0, [sp, #0] - str w0, [sp, #4] - str w0, [sp, #8] - // This write on its own falls within the 8 byte stack slot of - // the third stack argument (above), which we are allowed to clobber, - // so the wrapper won't notice it; we need to write past it for it to - // be noticed. - str w0, [sp, #12] - // Write past the 8 byte stack slot of the third/fourth argument, to - // allow checked_call to catch it. - str w0, [sp, #16] -#else - str w0, [sp, #0] - str w0, [sp, #8] - str w0, [sp, #16] - str w0, [sp, #24] -#endif - ret -endfunc - -// void check_max_int_args_aarch64(int, int, int, int, int, int, int, int, int, int, int, int, int, int, int); -function check_max_int_args_aarch64, export=1 -#ifdef __APPLE__ - ldr w8, [sp, #0] - ldr w9, [sp, #4] - ldr w10, [sp, #8] - ldr w11, [sp, #12] - ldr w12, [sp, #16] - ldr w13, [sp, #20] - ldr w14, [sp, #24] -#else - ldr w8, [sp, #0] - ldr w9, [sp, #8] - ldr w10, [sp, #16] - ldr w11, [sp, #24] - ldr w12, [sp, #32] - ldr w13, [sp, #40] - ldr w14, [sp, #48] -#endif -.macro check_reg reg, val - cmp \reg, #\val - bne 9f -.endm - check_reg w0, 1 - check_reg w1, 2 - check_reg w2, 3 - check_reg w3, 4 - check_reg w4, 5 - check_reg w5, 6 - check_reg w6, 7 - check_reg w7, 8 - check_reg w8, 9 - check_reg w9, 10 - check_reg w10, 11 - check_reg w11, 12 - check_reg w12, 13 - check_reg w13, 14 - check_reg w14, 15 - ret -9: - .inst 0 // udf #0 - ret -.purgem check_reg -endfunc - -// void check_max_int64_args_aarch64(int64_t, int64_t, int64_t, int64_t, int64_t, int64_t, int64_t, int64_t, int64_t, int64_t, int64_t, int64_t, int64_t, int64_t, int64_t); -function check_max_int64_args_aarch64, export=1 - ldr x8, [sp, #0] - ldr x9, [sp, #8] - ldr x10, [sp, #16] - ldr x11, [sp, #24] - ldr x12, [sp, #32] - ldr x13, [sp, #40] - ldr x14, [sp, #48] -.macro check_reg reg, val - cmp \reg, #\val - bne 9f -.endm - check_reg x0, 1 - check_reg x1, 2 - check_reg x2, 3 - check_reg x3, 4 - check_reg x4, 5 - check_reg x5, 6 - check_reg x6, 7 - check_reg x7, 8 - check_reg x8, 9 - check_reg x9, 10 - check_reg x10, 11 - check_reg x11, 12 - check_reg x12, 13 - check_reg x13, 14 - check_reg x14, 15 - ret -9: - .inst 0 // udf #0 - ret -.purgem check_reg -endfunc - -// void check_clobber_upper_aarch64(int, int, int, int, int, int, int, int, int, int, int); -// -// Check that the upper half of parameters that are passed as int actually -// are filled with garbage. -// -// This test has a bit of an inverted role; this test tries to verify the -// actions of the checked_call wrapper. If it finds a fault, it triggers -// a crash, to indicate a fault. -.macro check_clobber_reg reg -function check_clobber_upper_\reg\()_aarch64, export=1 - lsr \reg, \reg, #32 - cbnz \reg, 9f - .inst 0 // udf #0 -9: - ret -endfunc -.endm - -.macro check_clobber_stack arg -function check_clobber_upper_stack\arg\()_aarch64, export=1 -#ifndef __APPLE__ - // This assumes the stack argument layout that isn't used on Apple - // platforms. On Apple platforms, 32 bit arguments are packed tightly, - // on the stack, so there's nothing that can be clobbered - just - // return success. - ldr x0, [sp, #8*\arg] - lsr x0, x0, #32 - cbnz x0, 9f - .inst 0 // udf #0 -9: -#endif - ret -endfunc -.endm - -.irpc r, 01234567 -check_clobber_reg x\r -.endr - -.irpc r, 012 -check_clobber_stack \r -.endr - -#endif diff --git a/tests/checkasm/ext/tests/generic.c b/tests/checkasm/ext/tests/generic.c deleted file mode 100644 index 407a288c0d..0000000000 --- a/tests/checkasm/ext/tests/generic.c +++ /dev/null @@ -1,319 +0,0 @@ -/* - * Copyright © 2024, Marvin Scholz - * Copyright © 2019, VideoLAN and dav1d authors - * Copyright © 2019, Two Orioles, LLC - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include - -#include "tests.h" - -void selftest_test_copy(copy_func fun, const char *name, const int min_width) -{ -#define WIDTH 256 - BUF_RECT(uint8_t, c_dst, WIDTH, 1); - BUF_RECT(uint8_t, a_dst, WIDTH, 1); - - CHECKASM_ALIGN(uint8_t src[WIDTH]); - INITIALIZE_BUF(src); - - checkasm_declare(void, uint8_t *dest, const uint8_t *src, size_t n); - - for (int w = min_width; w <= WIDTH; w *= 2) { - if (checkasm_check_func(fun, "%s_%d", name, w)) { - CLEAR_BUF_RECT(c_dst); - CLEAR_BUF_RECT(a_dst); - - /* Make sure that the destination buffer actually differs from - * the source buffer, to make sure that a skipped write does - * trigger a failure. */ - for (int i = 0; i < w; i++) - c_dst[i] = a_dst[i] = ~src[i]; - checkasm_call_ref(c_dst, src, w); - checkasm_call_new(a_dst, src, w); - - /* Test all checkasm_check() variants */ - checkasm_check1d(uint8_t, c_dst, a_dst, w, "1d"); - checkasm_check2d(uint8_t, c_dst, 0, a_dst, 0, w, 1, "2d"); - checkasm_check_rect(c_dst, c_dst_stride, a_dst, a_dst_stride, w, 1, "rect"); - - checkasm_check1d_padded(uint8_t, c_dst, a_dst, w, "1d_padded", 1, 64); - checkasm_check2d_padded(uint8_t, c_dst, 0, a_dst, 0, w, 1, - "2d_padded", 1, 1, 16); - checkasm_check_rect_padded(c_dst, c_dst_stride, a_dst, a_dst_stride, w, 1, - "rect_padded"); - - checkasm_check_rect_padded_align(c_dst, c_dst_stride, a_dst, a_dst_stride, w, 1, - "rect_align", 1, 1); - - checkasm_bench_new(a_dst, src, w); - } - } - - checkasm_report("%s", name); -#undef WIDTH -} - -void selftest_test_noop(noop_func fun, const char *name) -{ - checkasm_declare(void, int); - - if (checkasm_check_func(fun, "%s", name)) { - /* don't call unchecked because some of these functions are designed to - * e.g. intentionally corrupt the stack */ - (void) checkasm_func_ref; - checkasm_call_new(0); - } - - checkasm_report("%s", name); -} - -void selftest_test_float(float_func fun, const char *name, const float input) -{ - checkasm_declare(float, float); - - if (checkasm_check_func(fun, "%s", name)) { - float x = checkasm_call_ref(input); - float y = checkasm_call_new(input); - if (!checkasm_float_near_abs_eps(x, y, FLT_EPSILON)) { - if (checkasm_fail()) - fprintf(stderr, "expected %f, got %f\n", x, y); - } - } - - checkasm_report("%s", name); -} - -static void selftest_test_double(double_func fun, const char *name, - const double input) -{ - checkasm_declare(double, double); - - if (checkasm_check_func(fun, "%s", name)) { - double x = checkasm_call_ref(input); - double y = checkasm_call_new(input); - - if (!checkasm_double_near_abs_eps(x, y, DBL_EPSILON)) { - if (checkasm_fail()) - fprintf(stderr, "expected %f, got %f\n", x, y); - } - } - - checkasm_report("%s", name); -} - -static DEF_COPY_FUNC(overwrite_left) -{ - memcpy(dst, src, size); - dst[-1] = dst[-2] = dst[-3] = dst[-4] = 0xAC; -} - -static DEF_COPY_FUNC(overwrite_right) -{ - memcpy(dst, src, size); - dst[size] = dst[size + 1] = dst[size + 2] = dst[size + 3] = 0xAC; -} - -static DEF_COPY_FUNC(underwrite) -{ - if (size < 4) - return; - memcpy(dst, src, size - 4); -} - -static DEF_NOOP_FUNC(segfault) -{ - volatile int *bad = NULL; - *bad = 0; -} - -static DEF_FLOAT_FUNC(sqrt) -{ - return sqrtf(input); -} - -static int identity_ref(const int x) -{ - return x; -} - -/* Just make this a separate function to test the checked wrappers */ -static int identity_new(const int x) -{ - return x; -} - -static void selftest_test_retval(void) -{ - const uint64_t flags = checkasm_get_cpu_flags(); - - checkasm_declare(int, int); - - if (checkasm_check_func(flags ? identity_new : identity_ref, "identity")) { - for (int i = 0; i < 10; i++) { - int x = checkasm_call_ref(i); - int y = checkasm_call_new(i); - if (x != y) { - if (checkasm_fail()) - fprintf(stderr, "expected %d, got %d\n", x, y); - } - } - } - - checkasm_report("identity"); -} - -static int truncate_c(const float x) -{ - return (int) x; -} - -static void selftest_test_float_arg(void) -{ - checkasm_declare(int, float); - - if (checkasm_check_func(truncate_c, "truncate")) { - for (float f = 0.0f; f <= 10.0f; f += 0.5f) { - int x = checkasm_call_ref(f); - int y = checkasm_call_new(f); - if (x != y) { - if (checkasm_fail()) - fprintf(stderr, "expected %d, got %d\n", x, y); - } - } - } - - checkasm_report("truncate"); -} - -static void selftest_test_double_arg(void) -{ - checkasm_declare(long, double); - - if (checkasm_check_func(lrint, "lrint")) { - for (float f = 0.0f; f <= 10.0f; f += 0.5f) { - long x = checkasm_call_ref(f); - long y = checkasm_call_new(f); - - if (x != y) { - if (checkasm_fail()) - fprintf(stderr, "expected %ld, got %ld\n", x, y); - } - } - } - - checkasm_report("lrint"); -} - -DEF_COPY_GETTER(SELFTEST_CPU_FLAG_BAD_C, overwrite_left) -DEF_COPY_GETTER(SELFTEST_CPU_FLAG_BAD_C, overwrite_right) -DEF_COPY_GETTER(SELFTEST_CPU_FLAG_BAD_C, underwrite) -DEF_NOOP_GETTER(SELFTEST_CPU_FLAG_BAD_C, segfault) - -/* Ensure we can call declare_func() inside check_func() */ -static void selftest_test_check_declare(void) -{ - /* Pick a function that will actually crash, to ensure the error - * handling still works in this case */ - noop_func *func = get_segfault(); - - if (checkasm_check_func(func, "check_declare")) { - checkasm_declare(void, int); - - checkasm_call_ref(0); - checkasm_call_new(0); - } - - checkasm_report("check_declare"); -} - -typedef int (int_func)(int); -static int wrapper(int_func *func, int arg) -{ - return func(arg); -} - -static void selftest_test_wrappers(void) -{ - if (checkasm_check_func(identity_ref, "override_funcs")) { - checkasm_declare(int, int); - int x = checkasm_call(identity_ref, 12345); - int y = checkasm_call_checked(identity_new, 12345); - if (x != y) - checkasm_fail(); - } - - if (checkasm_check_func(identity_ref, "wrapper_func")) { - checkasm_declare(int, int_func *, int); // type of wrapper - int x = checkasm_call(wrapper, (int_func *) checkasm_key_ref, 12345); - int y = checkasm_call_checked(wrapper, (int_func *) checkasm_key_new, 12345); - if (x != y) - checkasm_fail(); - } - - checkasm_report("wrappers"); -} - -static void selftest_test_variants(void) -{ - for (int i = 0; i < 2; i++) { - checkasm_set_func_variant(i ? "new" : "ref"); - if (checkasm_check_func(i ? identity_new : identity_ref, "func_id")) { - checkasm_declare(int, int); - int x = checkasm_call_ref(12345); - int y = checkasm_call_new(12345); - if (x != y) - checkasm_fail(); - checkasm_bench_new(12345); - } - } - - checkasm_report("func_id"); -} - -void selftest_check_generic(void) -{ - selftest_test_copy(selftest_copy_c, "copy_generic", 1); - selftest_test_float(selftest_sqrt, "sqrt_generic", 2.0f); - selftest_test_float_arg(); - selftest_test_double(sqrt, "sqrt", 2.); - selftest_test_double_arg(); - selftest_test_retval(); - selftest_test_wrappers(); - selftest_test_variants(); - - if (!checkasm_should_fail(SELFTEST_CPU_FLAG_BAD_C)) - return; - - selftest_test_copy(get_overwrite_left(), "overwrite_left", 1); - selftest_test_copy(get_overwrite_right(), "overwrite_right", 1); - selftest_test_copy(get_underwrite(), "underwrite", 1); - selftest_test_noop(get_segfault(), "segfault"); - selftest_test_check_declare(); -} diff --git a/tests/checkasm/ext/tests/meson.build b/tests/checkasm/ext/tests/meson.build deleted file mode 100644 index 384e54e6ae..0000000000 --- a/tests/checkasm/ext/tests/meson.build +++ /dev/null @@ -1,93 +0,0 @@ -# Copyright © 2025 Niklas Haas -# Copyright © 2024, Marvin Scholz -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -if build_tests.disabled() - subdir_done() -endif - -libm_dependency = cc.find_library('m', required: false) - -optional_arguments = [] -if cc.get_argument_syntax() != 'msvc' - optional_arguments += [ - '-Wno-unused-parameter', - ] -endif -extra_arguments = cc.get_supported_arguments(optional_arguments) - -checkasm_asm_objs = [] -checkasm_asm_sources = [] -checkasm_test_sources = files( - 'selftest.c', - 'generic.c', - 'arm/32/tests.c', - 'arm/64/tests.c', - 'riscv/tests.c', - 'x86/tests.c', -) - -if arch_x86 - checkasm_test_sources += files( - 'x86/tests_asm.asm', - ) -elif arch_riscv - checkasm_test_sources += files( - 'riscv/tests_asm.S', - ) -elif arch_aarch64 - checkasm_asm_sources = files('arm/64/tests_asm.S') -elif arch_arm - checkasm_asm_sources = files('arm/32/tests_asm.S') -else - warning('There are no assembly functions to test on the current platform.') -endif - -if use_gaspp and checkasm_asm_sources.length() > 0 - gaspp_args = [ - '-I@0@'.format(meson.project_source_root() + '/include'), - '-I@0@'.format(meson.project_source_root()), - '-I@0@'.format(meson.project_build_root()), - '-I@0@'.format(meson.project_build_root() + '/src'), - '-DCHECKASM_HAVE_GENERATED_H', - ] - checkasm_asm_objs += gaspp_gen.process(checkasm_asm_sources, extra_args: gaspp_args) -else - checkasm_test_sources += checkasm_asm_sources -endif - -checkasm_test = executable('checkasm-selftest', - checkasm_test_sources, - checkasm_asm_objs, - checkasm_config, - c_args: [extra_arguments, '-DCHECKASM_HAVE_GENERATED_H'], - nasm_args: '-DCHECKASM_HAVE_GENERATED_H', - dependencies: [checkasm_dep, libm_dependency], - include_directories: include_directories('../src'), - build_by_default: false, - install: false, -) - -test('selftest', checkasm_test, suite: 'checkasm', args: ['--verbose']) -benchmark('selftest', checkasm_test, suite: 'checkasm', args: ['--bench', '--verbose']) diff --git a/tests/checkasm/ext/tests/riscv/tests.c b/tests/checkasm/ext/tests/riscv/tests.c deleted file mode 100644 index c408013073..0000000000 --- a/tests/checkasm/ext/tests/riscv/tests.c +++ /dev/null @@ -1,222 +0,0 @@ -#include "tests.h" - -#if ARCH_RISCV - -/* Re-use helpers from main checkasm library */ -#include "src/cpu.h" - -uint64_t selftest_get_cpu_flags_riscv(void) -{ - uint64_t flags = SELFTEST_CPU_FLAG_RVI; - if (checkasm_has_float()) - flags |= SELFTEST_CPU_FLAG_RVF; - if (checkasm_has_vector()) - flags |= SELFTEST_CPU_FLAG_RVV; - return flags; -} - -DEF_COPY_FUNC(copy_rvv); -DEF_COPY_GETTER(SELFTEST_CPU_FLAG_RVV, copy_rvv) - -DEF_NOOP_FUNC(clobber_ra); -DEF_NOOP_FUNC(clobber_sp); -DEF_NOOP_FUNC(clobber_gp); -DEF_NOOP_FUNC(clobber_t0); -DEF_NOOP_FUNC(clobber_t1); -DEF_NOOP_FUNC(clobber_t2); -DEF_NOOP_FUNC(clobber_s0); -DEF_NOOP_FUNC(clobber_s1); -DEF_NOOP_FUNC(clobber_a0); -DEF_NOOP_FUNC(clobber_a1); -DEF_NOOP_FUNC(clobber_a2); -DEF_NOOP_FUNC(clobber_a3); -DEF_NOOP_FUNC(clobber_a4); -DEF_NOOP_FUNC(clobber_a5); -DEF_NOOP_FUNC(clobber_a6); -DEF_NOOP_FUNC(clobber_a7); -DEF_NOOP_FUNC(clobber_s2); -DEF_NOOP_FUNC(clobber_s3); -DEF_NOOP_FUNC(clobber_s4); -DEF_NOOP_FUNC(clobber_s5); -DEF_NOOP_FUNC(clobber_s6); -DEF_NOOP_FUNC(clobber_s7); -DEF_NOOP_FUNC(clobber_s8); -DEF_NOOP_FUNC(clobber_s9); -DEF_NOOP_FUNC(clobber_s10); -DEF_NOOP_FUNC(clobber_s11); -DEF_NOOP_FUNC(clobber_t3); -DEF_NOOP_FUNC(clobber_t4); -DEF_NOOP_FUNC(clobber_t5); -DEF_NOOP_FUNC(clobber_t6); - -DEF_NOOP_FUNC(clobber_ft0); -DEF_NOOP_FUNC(clobber_ft1); -DEF_NOOP_FUNC(clobber_ft2); -DEF_NOOP_FUNC(clobber_ft3); -DEF_NOOP_FUNC(clobber_ft4); -DEF_NOOP_FUNC(clobber_ft5); -DEF_NOOP_FUNC(clobber_ft6); -DEF_NOOP_FUNC(clobber_ft7); -DEF_NOOP_FUNC(clobber_fs0); -DEF_NOOP_FUNC(clobber_fs1); -DEF_NOOP_FUNC(clobber_fa0); -DEF_NOOP_FUNC(clobber_fa1); -DEF_NOOP_FUNC(clobber_fa2); -DEF_NOOP_FUNC(clobber_fa3); -DEF_NOOP_FUNC(clobber_fa4); -DEF_NOOP_FUNC(clobber_fa5); -DEF_NOOP_FUNC(clobber_fa6); -DEF_NOOP_FUNC(clobber_fa7); -DEF_NOOP_FUNC(clobber_fs2); -DEF_NOOP_FUNC(clobber_fs3); -DEF_NOOP_FUNC(clobber_fs4); -DEF_NOOP_FUNC(clobber_fs5); -DEF_NOOP_FUNC(clobber_fs6); -DEF_NOOP_FUNC(clobber_fs7); -DEF_NOOP_FUNC(clobber_fs8); -DEF_NOOP_FUNC(clobber_fs9); -DEF_NOOP_FUNC(clobber_fs10); -DEF_NOOP_FUNC(clobber_fs11); -DEF_NOOP_FUNC(clobber_ft8); -DEF_NOOP_FUNC(clobber_ft9); -DEF_NOOP_FUNC(clobber_ft10); -DEF_NOOP_FUNC(clobber_ft11); - -DEF_NOOP_FUNC(sigill_riscv); -DEF_NOOP_FUNC(corrupt_stack_riscv); -DEF_NOOP_GETTER(SELFTEST_CPU_FLAG_RVI, sigill_riscv) -DEF_NOOP_GETTER(SELFTEST_CPU_FLAG_RVI, corrupt_stack_riscv) - -typedef struct RiscvRegister { - const char *name; - noop_func *clobber; -} RiscvRegister; - -static const RiscvRegister registers_safe[] = { - { "ra", selftest_clobber_ra }, - { "t0", selftest_clobber_t0 }, - { "t1", selftest_clobber_t1 }, - { "t2", selftest_clobber_t2 }, - { "t3", selftest_clobber_t3 }, - { "t4", selftest_clobber_t4 }, - { "t5", selftest_clobber_t5 }, - { "t6", selftest_clobber_t6 }, - { "a0", selftest_clobber_a0 }, - { "a1", selftest_clobber_a1 }, - { "a2", selftest_clobber_a2 }, - { "a3", selftest_clobber_a3 }, - { "a4", selftest_clobber_a4 }, - { "a5", selftest_clobber_a5 }, - { "a6", selftest_clobber_a6 }, - { "a7", selftest_clobber_a7 }, - { NULL, NULL } -}; - -static const RiscvRegister float_registers_safe[] = { - { "ft0", selftest_clobber_ft0 }, - { "ft1", selftest_clobber_ft1 }, - { "ft2", selftest_clobber_ft2 }, - { "ft3", selftest_clobber_ft3 }, - { "ft4", selftest_clobber_ft4 }, - { "ft5", selftest_clobber_ft5 }, - { "ft6", selftest_clobber_ft6 }, - { "ft7", selftest_clobber_ft7 }, -#ifdef __riscv_float_abi_soft - { "fs0", selftest_clobber_fs0 }, - { "fs1", selftest_clobber_fs1 }, -#endif - { "fa0", selftest_clobber_fa0 }, - { "fa1", selftest_clobber_fa1 }, - { "fa2", selftest_clobber_fa2 }, - { "fa3", selftest_clobber_fa3 }, - { "fa4", selftest_clobber_fa4 }, - { "fa5", selftest_clobber_fa5 }, - { "fa6", selftest_clobber_fa6 }, - { "fa7", selftest_clobber_fa7 }, -#ifdef __riscv_float_abi_soft - { "fs2", selftest_clobber_fs2 }, - { "fs3", selftest_clobber_fs3 }, - { "fs4", selftest_clobber_fs4 }, - { "fs5", selftest_clobber_fs5 }, - { "fs6", selftest_clobber_fs6 }, - { "fs7", selftest_clobber_fs7 }, - { "fs8", selftest_clobber_fs8 }, - { "fs9", selftest_clobber_fs9 }, - { "fs10", selftest_clobber_fs10 }, - { "fs11", selftest_clobber_fs11 }, -#endif - { "ft8", selftest_clobber_ft8 }, - { "ft9", selftest_clobber_ft9 }, - { "ft10", selftest_clobber_ft10 }, - { "ft11", selftest_clobber_ft11 }, - { NULL, NULL }, -}; - -static const RiscvRegister registers_unsafe[] = { - { "s0", selftest_clobber_s0 }, - { "s1", selftest_clobber_s1 }, - { "s2", selftest_clobber_s2 }, - { "s3", selftest_clobber_s3 }, - { "s4", selftest_clobber_s4 }, - { "s5", selftest_clobber_s5 }, - { "s6", selftest_clobber_s6 }, - { "s7", selftest_clobber_s7 }, - { "s8", selftest_clobber_s8 }, - { "s9", selftest_clobber_s9 }, - { "s10", selftest_clobber_s10 }, - { "s11", selftest_clobber_s11 }, - { "sp", selftest_clobber_sp }, - { "gp", selftest_clobber_gp }, - /* Can't clobber tp because checkasm.S saves registers in TLS */ - { NULL, NULL } -}; - -static const RiscvRegister float_registers_unsafe[] = { -#ifndef __riscv_float_abi_soft - { "fs0", selftest_clobber_fs0 }, - { "fs1", selftest_clobber_fs1 }, - { "fs2", selftest_clobber_fs2 }, - { "fs3", selftest_clobber_fs3 }, - { "fs4", selftest_clobber_fs4 }, - { "fs5", selftest_clobber_fs5 }, - { "fs6", selftest_clobber_fs6 }, - { "fs7", selftest_clobber_fs7 }, - { "fs8", selftest_clobber_fs8 }, - { "fs9", selftest_clobber_fs9 }, - { "fs10", selftest_clobber_fs10 }, - { "fs11", selftest_clobber_fs11 }, -#endif - { NULL, NULL } -}; - -static void check_clobber(uint64_t mask, unsigned char letter, - const RiscvRegister *registers) -{ - const uint64_t flag = checkasm_get_cpu_flags() & mask; - checkasm_declare(void, int); - - for (int i = 0; registers[i].name; i++) { - noop_func *const func = flag ? registers[i].clobber : NULL; - if (checkasm_check_func(func, "clobber_%s", registers[i].name)) { - checkasm_call_new(0); - } - } - - checkasm_report("clobber_%c", letter); -} - -void selftest_check_riscv(void) -{ - selftest_test_copy(get_copy_rvv(), "copy_rvv", 1); - check_clobber(SELFTEST_CPU_FLAG_RVI, 'x', registers_safe); - check_clobber(SELFTEST_CPU_FLAG_RVF, 'f', float_registers_safe); - - if (!checkasm_should_fail(1)) - return; - selftest_test_noop(get_sigill_riscv(), "sigill"); - selftest_test_noop(get_corrupt_stack_riscv(), "corrupt_stack"); - check_clobber(SELFTEST_CPU_FLAG_RVI, 'x', registers_unsafe); - check_clobber(SELFTEST_CPU_FLAG_RVF, 'f', float_registers_unsafe); -} - -#endif diff --git a/tests/checkasm/ext/tests/riscv/tests_asm.S b/tests/checkasm/ext/tests/riscv/tests_asm.S deleted file mode 100644 index 1e91e094c3..0000000000 --- a/tests/checkasm/ext/tests/riscv/tests_asm.S +++ /dev/null @@ -1,96 +0,0 @@ -/****************************************************************************** - * Copyright © 2018, VideoLAN and dav1d authors - * Copyright © 2023, Nathan Egge - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - -#define PRIVATE_PREFIX selftest_ - -#include "src/checkasm_config.h" - -#if ARCH_RISCV - -#include "src/riscv/asm.S" - -function copy_rvv, export=1, ext=zve32x - vsetvli t0, a2, e8, m8, ta, ma - vle8.v v0, (a1) - add a1, a1, t0 - sub a2, a2, t0 - vse8.v v0, (a0) - add a0, a0, t0 - bnez a2, copy_rvv - ret -endfunc - -.macro clobber_fn reg -function clobber_\reg, export=1 - not \reg, \reg - ret -endfunc -.endm - -.irp reg, sp, gp, t0, t1, t2, s0, s1, a0, a1, a2, a3, a4, a5, a6, a7, \ - s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, t3, t4, t5, t6 -clobber_fn \reg -.endr - -function clobber_ra, export=1 - mv t0, ra - not ra, ra - jr t0 -endfunc - -.macro clobber_f_fn reg -function clobber_\reg, export=1, ext=f - fmv.x.w t0, \reg - not t0, t0 - fmv.w.x \reg, zero - ret -endfunc -.endm - -.irp reg, ft0, ft1, ft2, ft3, ft4, ft5, ft6, ft7, fs0, fs1, \ - fa0, fa1, fa2, fa3, fa4, fa5, fa6, fa7, fs2, fs3, \ - fs4, fs5, fs6, fs7, fs8, fs9, fs10, fs11, ft8, ft9, ft10, ft11 -clobber_f_fn \reg -.endr - -function sigill_riscv, export=1 - .word 0 -endfunc - -function corrupt_stack_riscv, export=1 - mv t0, sp - li t1, (__riscv_xlen / 2) -1: - addi t1, t1, -1 - sw zero, (t0) - addi t0, t0, 4 - bnez t1, 1b - - ret -endfunc - -#endif diff --git a/tests/checkasm/ext/tests/selftest.c b/tests/checkasm/ext/tests/selftest.c deleted file mode 100644 index 7ac52d7a1b..0000000000 --- a/tests/checkasm/ext/tests/selftest.c +++ /dev/null @@ -1,62 +0,0 @@ -#include "tests.h" -#include - -static const CheckasmCpuInfo cpus[] = { - { "Bad C", "badc", SELFTEST_CPU_FLAG_BAD_C }, -#if ARCH_X86 - { "Generic x86", "x86", SELFTEST_CPU_FLAG_X86 }, - { "MMX", "mmx", SELFTEST_CPU_FLAG_MMX }, - { "SSE2", "sse2", SELFTEST_CPU_FLAG_SSE2 }, - { "AVX-2", "avx2", SELFTEST_CPU_FLAG_AVX2 }, - { "AVX-512", "avx512", SELFTEST_CPU_FLAG_AVX512 }, -#endif -#if ARCH_RISCV - { "Generic RISC-V", "rvi", SELFTEST_CPU_FLAG_RVI }, - { "Floating point", "rvf", SELFTEST_CPU_FLAG_RVF }, - { "Vector", "rvv", SELFTEST_CPU_FLAG_RVV }, -#endif -#if ARCH_AARCH64 - { "Generic aarch64", "aarch64", SELFTEST_CPU_FLAG_AARCH64 }, -#endif -#if ARCH_ARM - { "Generic ARM", "arm", SELFTEST_CPU_FLAG_ARM }, - { "VFP", "vfp", SELFTEST_CPU_FLAG_VFP }, - { "VFP D32", "vfpd32", SELFTEST_CPU_FLAG_VFPD32 }, -#endif - {0} -}; - -static const CheckasmTest tests[] = { - { "generic", selftest_check_generic }, -#if ARCH_X86 - { "x86", selftest_check_x86 }, -#elif ARCH_RISCV - { "riscv", selftest_check_riscv }, -#elif ARCH_AARCH64 - { "aarch64", selftest_check_aarch64 }, -#elif ARCH_ARM - { "arm", selftest_check_arm }, -#endif - {0} -}; - -int main(int argc, const char *argv[]) -{ - CheckasmConfig cfg = { - .cpu_flags = cpus, - .tests = tests, - .cpu = SELFTEST_CPU_FLAG_BAD_C, - }; - -#if ARCH_X86 - cfg.cpu |= selftest_get_cpu_flags_x86(); -#elif ARCH_RISCV - cfg.cpu |= selftest_get_cpu_flags_riscv(); -#elif ARCH_AARCH64 - cfg.cpu |= selftest_get_cpu_flags_aarch64(); -#elif ARCH_ARM - cfg.cpu |= selftest_get_cpu_flags_arm(); -#endif - - return checkasm_main(&cfg, argc, argv); -} diff --git a/tests/checkasm/ext/tests/tests.h b/tests/checkasm/ext/tests/tests.h deleted file mode 100644 index f3f9c04635..0000000000 --- a/tests/checkasm/ext/tests/tests.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright © 2025, Niklas Haas - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef CHECKASM_TESTS_H -#define CHECKASM_TESTS_H - -#include -#include -#include - -#include "src/checkasm_config.h" - -#include -#include - -enum { - SELFTEST_CPU_FLAG_BAD_C = 1 << 0, // dummy flag for "bad" C implementations -#if ARCH_X86 - SELFTEST_CPU_FLAG_X86 = 1 << 1, - SELFTEST_CPU_FLAG_MMX = 1 << 2, - SELFTEST_CPU_FLAG_SSE2 = 1 << 3, - SELFTEST_CPU_FLAG_AVX2 = 1 << 4, - SELFTEST_CPU_FLAG_AVX512 = 1 << 5, -#elif ARCH_RISCV - SELFTEST_CPU_FLAG_RVI = 1 << 1, - SELFTEST_CPU_FLAG_RVF = 1 << 2, - SELFTEST_CPU_FLAG_RVV = 1 << 3, -#elif ARCH_AARCH64 - SELFTEST_CPU_FLAG_AARCH64 = 1 << 1, -#elif ARCH_ARM - SELFTEST_CPU_FLAG_ARM = 1 << 1, - SELFTEST_CPU_FLAG_VFP = 1 << 2, - SELFTEST_CPU_FLAG_VFPD32 = 1 << 3, -#endif -}; - -#define DEF_GETTER(FLAG, NAME, func_type, fallback) \ - static func_type *get_##NAME(void) \ - { \ - return (checkasm_get_cpu_flags() & FLAG) ? selftest_##NAME : fallback; \ - } - -/* Should return the arch-specific flags */ -uint64_t selftest_get_cpu_flags_x86(void); -uint64_t selftest_get_cpu_flags_riscv(void); -uint64_t selftest_get_cpu_flags_aarch64(void); -uint64_t selftest_get_cpu_flags_arm(void); - -/** - * Copy `size` (power-of-two) bytes from aligned buffers `src` to `dst`. - */ -typedef void(copy_func)(uint8_t *dst, const uint8_t *src, size_t size); -void selftest_test_copy(copy_func *func, const char *name, int min_width); - -#define DEF_COPY_FUNC(NAME) \ - void selftest_##NAME(uint8_t *dst, const uint8_t *src, size_t size) - -#define DEF_COPY_GETTER(FLAG, NAME) DEF_GETTER(FLAG, NAME, copy_func, selftest_copy_c) - -/* Reference function for copy routines */ -static inline DEF_COPY_FUNC(copy_c) -{ - memcpy(dst, src, size); -} - -/** - * Do nothing. Used to test side effects, stack corruption etc. - * The singular int parameter is just to have at least one parameter, - * which is required by `declare_func`. - */ -typedef void(noop_func)(int unused); -void selftest_test_noop(noop_func *func, const char *name); - -#define DEF_NOOP_FUNC(NAME) void selftest_##NAME(int unused) -#define DEF_NOOP_GETTER(FLAG, NAME) DEF_GETTER(FLAG, NAME, noop_func, NULL) - -/* Used for testing floating point operations */ -typedef float(float_func)(float input); -typedef double(double_func)(double input); -void selftest_test_float(float_func *func, const char *name, float input); - -#define DEF_FLOAT_FUNC(NAME) float selftest_##NAME(float input) - -/* Platform-specific tests */ -void selftest_check_generic(void); -void selftest_check_x86(void); -void selftest_check_riscv(void); -void selftest_check_aarch64(void); -void selftest_check_arm(void); - -#endif /* CHECKASM_TESTS_H */ diff --git a/tests/checkasm/ext/tests/x86/tests.c b/tests/checkasm/ext/tests/x86/tests.c deleted file mode 100644 index 7c7277d9d5..0000000000 --- a/tests/checkasm/ext/tests/x86/tests.c +++ /dev/null @@ -1,220 +0,0 @@ -#include -#include - -#include "tests.h" - -#if ARCH_X86 - -/* Re-use helpers from main checkasm library */ -#include "src/cpu.h" - -uint64_t selftest_get_cpu_flags_x86(void) -{ - uint64_t flags = SELFTEST_CPU_FLAG_X86; - CpuidRegisters r; - checkasm_cpu_cpuid(&r, 0, 0); - const uint32_t max_leaf = r.eax; - if (max_leaf < 1) - return flags; - - checkasm_cpu_cpuid(&r, 1, 0); - if (r.edx & 0x00800000) /* MMX */ - flags |= SELFTEST_CPU_FLAG_MMX; - if (r.edx & 0x02000000) /* SSE2 */ - flags |= SELFTEST_CPU_FLAG_SSE2; - if (~r.ecx & 0x18000000) /* OSXSAVE/AVX */ - return flags; - - const uint64_t xcr0 = checkasm_cpu_xgetbv(0); - if (max_leaf < 7 || ~xcr0 & 0x6) /* XMM/YMM */ - return flags; - - checkasm_cpu_cpuid(&r, 7, 0); - if (r.ebx & 0x00000020) /* AVX2 */ - flags |= SELFTEST_CPU_FLAG_AVX2; - - if (~xcr0 & 0xe0) /* ZMM/OPMASK */ - return flags; - - if (r.ebx & 0x00000020) /* AVX512F */ - flags |= SELFTEST_CPU_FLAG_AVX512; - return flags; -} - -DEF_COPY_FUNC(copy_x86); -DEF_COPY_FUNC(copy_mmx); -DEF_COPY_FUNC(copy_sse2); -DEF_COPY_FUNC(copy_avx2); -DEF_COPY_FUNC(copy_avx512); - -DEF_NOOP_FUNC(clobber_r0); -DEF_NOOP_FUNC(clobber_r1); -DEF_NOOP_FUNC(clobber_r2); -DEF_NOOP_FUNC(clobber_r3); -DEF_NOOP_FUNC(clobber_r4); -DEF_NOOP_FUNC(clobber_r5); -DEF_NOOP_FUNC(clobber_r6); -#if ARCH_X86_64 -DEF_NOOP_FUNC(clobber_r7); -DEF_NOOP_FUNC(clobber_r8); -DEF_NOOP_FUNC(clobber_r9); -DEF_NOOP_FUNC(clobber_r10); -DEF_NOOP_FUNC(clobber_r11); -DEF_NOOP_FUNC(clobber_r12); -DEF_NOOP_FUNC(clobber_r13); -DEF_NOOP_FUNC(clobber_r14); -#endif - -DEF_NOOP_FUNC(sigill_x86); -DEF_NOOP_FUNC(corrupt_stack_x86); - -DEF_COPY_FUNC(copy_noemms_mmx); -DEF_COPY_FUNC(copy_novzeroupper_avx2); - -static copy_func *get_copy_x86(void) -{ - const uint64_t flags = checkasm_get_cpu_flags(); -#if ARCH_X86 - if (flags & SELFTEST_CPU_FLAG_AVX512) - return selftest_copy_avx512; - if (flags & SELFTEST_CPU_FLAG_AVX2) - return selftest_copy_avx2; - if (flags & SELFTEST_CPU_FLAG_SSE2) - return selftest_copy_sse2; - if (flags & SELFTEST_CPU_FLAG_MMX) - return selftest_copy_mmx; - if (flags & SELFTEST_CPU_FLAG_X86) - return selftest_copy_x86; -#endif - return selftest_copy_c; -} - -#if ARCH_X86_64 - #ifdef _WIN32 - #define NUM_SAFE 7 - #else - #define NUM_SAFE 9 - #endif - #define NUM_REGS 15 - #define STACK_ALIGN 16 -#else - #define NUM_SAFE 3 - #define NUM_REGS 7 - #define STACK_ALIGN 4 -#endif - -static noop_func *get_clobber(int reg) -{ - if (!(checkasm_get_cpu_flags() & SELFTEST_CPU_FLAG_X86)) - return NULL; - - switch (reg) { - case 0: return selftest_clobber_r0; - case 1: return selftest_clobber_r1; - case 2: return selftest_clobber_r2; - case 3: return selftest_clobber_r3; - case 4: return selftest_clobber_r4; - case 5: return selftest_clobber_r5; - case 6: return selftest_clobber_r6; -#if ARCH_X86_64 - case 7: return selftest_clobber_r7; - case 8: return selftest_clobber_r8; - case 9: return selftest_clobber_r9; - case 10: return selftest_clobber_r10; - case 11: return selftest_clobber_r11; - case 12: return selftest_clobber_r12; - case 13: return selftest_clobber_r13; - case 14: return selftest_clobber_r14; -#endif - /* can't clobber rsp without completely crashing the program */ - default: return NULL; - } -} - -DEF_NOOP_GETTER(SELFTEST_CPU_FLAG_X86, sigill_x86) -DEF_NOOP_GETTER(SELFTEST_CPU_FLAG_X86, corrupt_stack_x86) -DEF_COPY_GETTER(SELFTEST_CPU_FLAG_MMX, copy_noemms_mmx) -DEF_COPY_GETTER(SELFTEST_CPU_FLAG_AVX2, copy_novzeroupper_avx2) - -uintptr_t selftest_get_stack_pointer_x86(int unused); - -static void check_stack_alignment(void) -{ - checkasm_declare(uintptr_t, int); - - if (checkasm_check_func(selftest_get_stack_pointer_x86, "stack_alignment")) { - uintptr_t sp = checkasm_call_new(0); - - /* Subtract return address */ - sp -= sizeof(sp); - if (sp & (STACK_ALIGN - 1)) { - if (checkasm_fail()) { - fprintf(stderr, "stack pointer not %d-byte aligned: 0x%" PRIxPTR "\n", - STACK_ALIGN, sp); - } - } - } -} - -static void check_clobber(int from, int to) -{ - checkasm_declare(void, int); - - for (int reg = from; reg < to; reg++) { - noop_func *clobber = get_clobber(reg); - if (!clobber) - break; - - if (checkasm_check_func(clobber, "clobber_r%d", reg)) { - checkasm_call_new(0); - } - } - - checkasm_report("clobber"); -} - -static void test_copy_emms(copy_func fun, const char *name) -{ - CHECKASM_ALIGN(uint8_t c_dst[256]); - CHECKASM_ALIGN(uint8_t a_dst[256]); - CHECKASM_ALIGN(uint8_t src[256]); - INITIALIZE_BUF(src); - - checkasm_declare_emms(SELFTEST_CPU_FLAG_MMX, void, uint8_t *dest, - const uint8_t *src, size_t n); - - for (size_t w = 8; w <= 256; w *= 2) { - if (checkasm_check_func(fun, "%s_%zu", name, w)) { - CLEAR_BUF(c_dst); - CLEAR_BUF(a_dst); - - checkasm_call_ref(c_dst, src, w); - checkasm_call_new(a_dst, src, w); - checkasm_check(uint8_t, c_dst, 0, a_dst, 0, 256, 1, "dst data"); - checkasm_bench_new(a_dst, src, w); - } - } - - checkasm_report("%s", name); -} - -void selftest_check_x86(void) -{ - selftest_test_copy(get_copy_x86(), "copy", 1); - test_copy_emms(get_copy_noemms_mmx(), "copy_noemms"); - check_stack_alignment(); - check_clobber(0, NUM_SAFE); - - if (!checkasm_should_fail(SELFTEST_CPU_FLAG_X86)) - return; - - selftest_test_noop(get_sigill_x86(), "sigill"); - selftest_test_noop(get_corrupt_stack_x86(), "corrupt_stack"); - selftest_test_copy(get_copy_noemms_mmx(), "noemms", 8); - check_clobber(NUM_SAFE, NUM_REGS); - - if (checkasm_get_check_vzeroupper()) - selftest_test_copy(get_copy_novzeroupper_avx2(), "novzeroupper", 32); -} - -#endif diff --git a/tests/checkasm/ext/tests/x86/tests_asm.asm b/tests/checkasm/ext/tests/x86/tests_asm.asm deleted file mode 100644 index 1af9e12dae..0000000000 --- a/tests/checkasm/ext/tests/x86/tests_asm.asm +++ /dev/null @@ -1,113 +0,0 @@ -%undef private_prefix -%define private_prefix selftest - -%include "src/checkasm_config.asm" -%include "src/x86/x86inc.asm" - -SECTION .text - -%macro copy_mm 0-1 ; suffix -cglobal copy%1, 3, 3, 1, dst, src, size - cmp sizeq, mmsize - jl copy_x86 - - add dstq, sizeq - add srcq, sizeq - neg sizeq -.loop: - mova m0, [srcq + sizeq] - mova [dstq + sizeq], m0 - add sizeq, mmsize - jl .loop - - ; emit emms after all MMX functions unless suffix is _noemms -%if mmsize == 8 - %ifnidn %1, _noemms - emms - %endif -%endif - - ; skip vzeroupper if suffix is _novzeroupper -%ifidn %1, _novzeroupper - ret -%else - RET -%endif -%endmacro - -; Generic x86 functions -cglobal copy_x86, 3, 3, 0, dst, src, size -%if ARCH_X86_32 || WIN64 - push rdi - push rsi - mov rdi, dstq - mov rsi, srcq -%endif - mov rcx, sizeq - rep movsb -%if ARCH_X86_32 || WIN64 - pop rsi - pop rdi -%endif - RET - -cglobal sigill_x86 - ud2 - -%macro clobber 2 ; register, suffix -cglobal clobber%2 - xor %1, %1 - RET -%endmacro - -clobber r0, _r0 -clobber r1, _r1 -clobber r2, _r2 -clobber r3, _r3 -clobber r4, _r4 -clobber r5, _r5 -clobber r6, _r6 -%if ARCH_X86_64 -clobber r7, _r7 -clobber r8, _r8 -clobber r9, _r9 -clobber r10, _r10 -clobber r11, _r11 -clobber r12, _r12 -clobber r13, _r13 -clobber r14, _r14 -%endif - -cglobal corrupt_stack_x86 - xor rax, rax -%if WIN64 - mov [rsp+32+8], rax ; account for shadow space -%else - mov [rsp+8], rax -%endif - RET - -cglobal get_stack_pointer_x86 - mov rax, rsp - RET - -; MMX functions -INIT_MMX mmx -copy_mm -copy_mm _noemms - -cglobal noemms, 3, 3, 0, dst, src, size - RET - -; SSE2 functions -INIT_XMM sse2 -copy_mm - -; AVX2 functions -INIT_YMM avx2 -copy_mm -copy_mm _novzeroupper - -; AVX512 functions -INIT_YMM avx512 -copy_mm