Files
NX2navi/tests/check_isa_test.py
chrg6 6b051eea58 List kern_ap_stub_ymm as dispatched in check_isa.py, so that a --cpu v2 build passes its instruction check again.
kernel.c's preemption stub has two bodies since 00f06e66: kern_ap_stub_ymm saves YMM0-15 with vmovdqa and is chosen only when ap_init's cpu_keeps_ymm() finds AVX, OSXSAVE and XCR0 bits 1 and 2, and kern_ap_stub_xmm serves every other processor. tools/check_isa.py's DISPATCHED listed only sha256.c's blocks_ni, so it took the YMM body for an undispatched AVX function and stopped every tools/build_game.py --cpu v2 build. The entry names that check. Players' builds (make_game.py) run no such check and were not affected.

Reproduced before the change: kernel.c built with the ucrt64 clang at -march=x86-64-v2 failed tools/check_isa.py with "kern_ap_stub_ymm ...: vmovdqa x32, vzeroupper x1", and passes now. Checks that passed: the new tests/check_isa_test.py (kernel.c and sha256.c built with -march=x86-64-v2 and without -march pass; an AVX function not in DISPATCHED still fails; it fails before the change) and tools/check_content.py --staged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-13 18:43:30 -05:00

54 lines
2.2 KiB
Python

"""tools/check_isa.py on the runtime files that hold instructions above x86-64-v2 behind a runtime CPU check
(runtime/kernel.c kern_ap_stub_ymm, runtime/sha256.c blocks_ni): built as tools/build_game.py --cpu v2 builds the
runtime (-march=x86-64-v2) and as players' builds do (no -march), they pass, and a function with such an instruction
and no entry in DISPATCHED still fails. Needs the MSYS2 UCRT64 clang and an objdump (skipped without them); no game
files.
Run: python tests/check_isa_test.py
"""
import shutil
import subprocess
import sys
import tempfile
import unittest
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT / 'tools'))
import check_isa # noqa: E402
UCRT = Path(r'C:\msys64\ucrt64\bin')
CC = next((str(c) for c in (UCRT / 'clang.exe', shutil.which('clang')) if c and Path(c).is_file()), None)
OBJDUMP = check_isa.find_objdump(str(UCRT / 'objdump.exe') if (UCRT / 'objdump.exe').is_file() else None)
FLAGS = ['-O2', '-g', '-fno-strict-aliasing', '-w'] # tools/build_game.py RT_FLAGS, without its warnings
@unittest.skipUnless(CC and OBJDUMP, 'needs clang and objdump')
class CheckIsaTest(unittest.TestCase):
def setUp(self):
td = tempfile.TemporaryDirectory()
self.addCleanup(td.cleanup)
self.tmp = Path(td.name)
def compile(self, src, march, name=None):
out = self.tmp / f'{name or Path(src).stem}{march or ""}.o'
subprocess.run([CC, *FLAGS, *([march] if march else []), '-I', str(ROOT / 'runtime'), '-c', str(src),
'-o', str(out)], check=True, capture_output=True, timeout=600)
return out
def test_the_dispatched_functions_pass(self):
for march in ('-march=x86-64-v2', None):
objs = [self.compile(ROOT / 'runtime' / f, march) for f in ('kernel.c', 'sha256.c')]
self.assertEqual(check_isa.scan(objs, OBJDUMP), {}, march)
def test_an_undispatched_avx_function_fails(self):
src = self.tmp / 'wide.c'
src.write_text('void wide(void) { __asm__ volatile("vzeroupper"); }\n', encoding='utf-8')
hits = check_isa.scan([self.compile(src, '-march=x86-64-v2')], OBJDUMP)
self.assertEqual([f for _, f in hits], ['wide'])
if __name__ == '__main__':
unittest.main(verbosity=2)