From 88b80011e434aa92043892d682c3a472881a576b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 21 Sep 2026 15:36:49 -0600 Subject: [PATCH] Run pspautotests under qemu for loongarch64 and riscv64 Only the IR JIT: it's the sole native backend these two have and the one thing here that isn't shared code, and the x86-64 and arm64 runners already cover all four backends. Every run costs emulated wall clock, so the timeout goes up to match. test.py grows a per-architecture known-failure list, selected with --known-failures=, so this can guard against new breakage while the four outstanding ones stay outstanding. Each entry carries its reason. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/build.yml | 15 +++++++++++++++ test.py | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7af3817375..02c5d524fa 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -409,6 +409,21 @@ jobs: qemu-${{ matrix.extra }} -L /usr/${{ matrix.extra }}-linux-gnu \ build-${{ matrix.extra }}/PPSSPPUnitTest all + # Only the IR JIT - it's the sole native backend these two have, and the only thing here that + # isn't shared code. The interpreters are portable C++ that the x86-64 and arm64 runners + # already cover on all four backends, and every run costs emulated wall clock. + - name: Execute headless tests under qemu + if: matrix.extra == 'loongarch64' || matrix.extra == 'riscv64' + run: | + # test.py takes the newest build*/PPSSPPHeadless, so hand it one that runs the cross build + # under emulation. The wall clock is raised because everything is slower under qemu. + mkdir -p build-qemu + printf '#!/bin/bash\nexec qemu-%s -L /usr/%s-linux-gnu "$(dirname "$0")/../build-%s/PPSSPPHeadless" "$@"\n' \ + '${{ matrix.extra }}' '${{ matrix.extra }}' '${{ matrix.extra }}' > build-qemu/PPSSPPHeadless + chmod +x build-qemu/PPSSPPHeadless + python3 test.py -g --graphics=software --cpu=jit-ir --timeout=60 \ + --known-failures=${{ matrix.extra }} + - name: Package build if: matrix.extra == 'test' || matrix.id == 'ios' run: | diff --git a/test.py b/test.py index 80f3291f41..da2e69aedd 100755 --- a/test.py +++ b/test.py @@ -432,6 +432,30 @@ tests_good = [ # Broken tests # -b flag runs these. + +# Tests that don't pass yet on an architecture we can only reach through emulation. Pass +# --known-failures= to drop them from the run, so CI can still catch anything *new* breaking +# while these stay outstanding. Keep a reason next to each one, and delete entries as they're fixed +# rather than letting the list rot. +known_failures = { + "riscv64": [ + # No flush-to-zero: the ISA has no control for it, so a denormal result survives where the + # PSP would have flushed it. Everything else in this test passes. + "cpu/fpu/fpu", + # The software renderer's output differs from the reference by the same amount on both of + # these architectures, despite them using completely different SIMD paths. Unexplained. + "gpu/clipping/homogeneous", + "gpu/commands/cull", + "gpu/primitives/triangles", + ], + "loongarch64": [ + "cpu/fpu/fpu", + "gpu/clipping/homogeneous", + "gpu/commands/cull", + "gpu/primitives/triangles", + ], +} + tests_next = [ # These are the next tests up for fixing. These run by default. "cpu/fpu/fcr", @@ -628,10 +652,17 @@ def main(): tests = [] args = [] teamcity = False + skip_arch = None for arg in sys.argv[1:]: if arg == '--teamcity': args.append(arg) teamcity = True + elif arg.startswith('--known-failures='): + # Ours, not headless's - don't pass it through. + skip_arch = arg[len('--known-failures='):] + if skip_arch not in known_failures: + print("Unknown architecture for --known-failures: " + skip_arch) + sys.exit(1) elif arg[0] == '-': args.append(arg) else: @@ -651,6 +682,12 @@ def main(): elif '-m' in args: tests = [i for i in tests_next + tests_good if i.startswith(tests[0])] + if skip_arch: + skipped = [t for t in tests if t in known_failures[skip_arch]] + tests = [t for t in tests if t not in known_failures[skip_arch]] + if skipped: + print("Skipping %d known failures on %s: %s" % (len(skipped), skip_arch, ", ".join(skipped))) + returncode = run_tests(tests, args) if teamcity: return 0