Repository navigation
feat(aot): compile integer leaf functions with LLVM - #9776
Xx-LiDAF-xX wants to merge 53 commits into
Conversation
9ea61b9 to
8eeb446
Compare
|
Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.
Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.
|
MarcZX10
left a comment
There was a problem hiding this comment.
I built the exact PR’s standalone AOT project and ran its tests: all 4/4 pass. However, an end-to-end compiler check exposes a blocking issue. I compiled a minimal ELF with one _start function (mov $0, %eax; ret) and ran the new aot_compiler_cli with --output and --emit-llvm. The CLI reported “AOT Compilation succeeded” and one function lifted, but the object file is 0 bytes and the emitted IR contains only ModuleID and target triple, no function.
The added LLVM compatibility layer is currently a no-op for code generation: Module::print emits only those two lines; TargetRegistry::lookupTarget accepts any nonempty triple; TargetMachine::addPassesToEmitFile returns success without registering an emitter; and PassManager::run performs no work. The four tests exercise the parser, lifter, runtime, graphics and I/O components, but do not call AotCompilerDriver::Compile and assert a valid output object/executable. Please use real LLVM code generation or implement and test a working backend for the lifted instructions, and add an end-to-end test that parses the generated object and verifies emitted function code. Until then the new compiler’s success report is a false positive.
There is also no add_subdirectory(core/aot) in the repository’s root CMakeLists.txt; the new tests run only when configuring core/aot as a separate project, so normal builds and upstream PR CI do not build or test this code. Please integrate the AOT targets/tests with the repository build (or document and wire up an intentional standalone build in the project’s normal CI path).
The exact-head standalone build and 4/4 CTest pass, but they do not cover the broken output path. Current-main conventions and git diff --check pass. The branch is 13 commits behind and 39 commits ahead of live main (499b1cf9fc44da935fe6d63813675ad5810e8402); CONTRIBUTING.md requires keeping branches up to date. Please refresh the branch after addressing the output and integration gaps, then rerun the end-to-end and normal build tests.
…piler variable declarations
…tended conditional jumps
…shader modulo/division
…oot cmake integration
c6a90a7 to
5d7cbec
Compare
|
@MarcZX10 Thank you for the detailed review! All requested changes and gaps have been addressed:
|
MarcZX10
left a comment
There was a problem hiding this comment.
I built the exact current head (241c38a7c4508702520758cf1cdeb9c7f924a448) with cmake -S core/aot -B build-aot -G Ninja, built all targets, and ran CTest: 3/4 pass; test_aot_runtime aborts at TestAotRuntime.cpp:43 because the queried block remains MemoryProtection::Read after the aps5_sys_mprotect(..., 3) call. The failure is in the test setup: lines 11–15 create/allocate a local MemoryBridge, and lines 33–37 protect/query that instance, but aps5_sys_mprotect in RuntimeRegistry.cpp:123–131 always calls the distinct static gMemoryBridge. That syscall initializes/updates its own address space; the next memory.QueryMemoryBlock still reads the untouched local bridge. Please test Protect directly on the local instance, and separately test the syscall using an allocation/query that goes through the registry-backed bridge (or expose a consistent instance for the integration test). This also means the reported 4/4 result is not reproducible on the current head. I did not run the hosted product build.
jotitadev
left a comment
There was a problem hiding this comment.
The Tested section says native execution on macOS wasn't tried. On Apple silicon, the arithmetic, moves and shifts groups can't pass as written. I didn't build LLVM here. I reproduced the test's reference step by hand on an M2 Max (macOS 27.2, Apple clang 21, head 2cb4c77224).
- In a macOS x86-64 build (
-DCMAKE_OSX_ARCHITECTURES=x86_64), CMake setsCMAKE_SYSTEM_PROCESSORtox86_64, so thenative x86-64 hostgate incore/aot/tests/CMakeLists.txtpasses. ctest then runstest_aot_compiler.pywithPython3_EXECUTABLE(Xcode's/usr/bin/python3). That Python runs as arm64. execute_caseslinks with--host-compilerwithout an-arch, so clang builds arm64. I wrotereference.cppandreference.sthe way the script does, with one case:.byte 72,137,248,195(mov rax, rdi; ret) and theoriginal_0wrapper.clang++ -shared -fPIC -o reference.so reference.cpp reference.sgivesMach-O 64-bit dynamically linked shared library arm64. Callingoriginal_0throughctypeskills Python with SIGILL (exit 132), because the x86 bytes run as arm64 code.- The
objectandassemblylibraries would fail the same way. They are x86-64 Mach-O objects linked by an arm64 link.
With -arch x86_64 on the host-compiler calls and the script run under arch -x86_64 /usr/bin/python3, the same reference library loads and returns 5 for original_0(5, ...). So on macOS, either pass -arch x86_64 and launch Python under Rosetta, or skip the three execution groups when platform.machine() isn't x86_64. As it stands, a full macOS build with BUILD_TESTING=ON gets three crashing groups, because AOT is on by default outside relinker-only builds.
Written with AI assistance (Claude Code). I ran the builds and tests above on my machine.
|
@jotitadev Thanks for reproducing this and identifying both architecture mismatches. Addressed in f8b8510:
On Windows, the root relinker+AOT build passed 240/240 tests with zero skips. After the final Windows runtime PATH adjustment, all five AOT groups passed again. The execution cases compare both emitted object and assembly results with the original machine code and independent integer expectations. I have not run the corrected tests on macOS hardware. The Clang architecture-selection checks passed, but those do not establish a macOS runtime pass; the PR's Tested section and debt entry retain that limitation. If you can rerun Implemented with AI assistance. |
MarcZX10
left a comment
There was a problem hiding this comment.
I reviewed exact head f8b85103b0ca449c286f80fbbb4221d810a15481. The earlier empty-object/IR issue is addressed in this revision, and the new macOS subprocess architecture checks are a concrete fix. Conventions and whitespace pass; the author reports 240/240 Windows tests and 5/5 standalone groups.
One test-harness ABI mismatch still blocks relying on the Windows execution results:
test_aot_compiler.pydeclares bothguest_iandoriginal_iwithsysv_abiin the generated reference source (around line 161).execute_programdeclares the called symbols and itsFunctionpointer with the host default ABI (around lines 194-197), and CMake passes${CMAKE_CXX_COMPILER}as that host compiler. On Windows x64, that is the Microsoft ABI, whileoriginal_iexpects SysV registers. For example, the runner places its first argument inRCX, but the SysV wrapper readsRDI; so the reference result is not a reliable oracle for the emitted function.
I reproduced the call-site mismatch with GCC's -mabi=ms: the caller emitted mov $1, %ecx; call original, while the sysv_abi wrapper read %rdi. Please make the outer original_i wrapper use the host ABI while keeping only the raw guest_i byte function SysV (so the compiler bridges the arguments), or otherwise make the runner's declaration and function-pointer type explicitly SysV. Then rerun the Windows execution groups; the current reported 26,040 evaluations should not be treated as validated until the reference call convention is corrected. Linux/macOS default to SysV, so the mismatch is specific to the Windows host run.
This head is also 18 commits behind current main (e94545a5, merge base 938812df), though Git reports a clean merge. Refresh and rerun the AOT tests and conventions on the refreshed head before merge. The current PR CI only ran contribution checks; product jobs are skipped. I started an independent Linux build from the pinned LLVM submodule in an isolated worktree; configuration succeeded, and the 1,556-step build is still running, so I have no local CTest result yet.
|
@MarcZX10 Thanks for checking the ABI boundary and starting the independent Linux build. I checked the exact extern "C" uint64_t __attribute__((sysv_abi)) guest_i(...);
extern "C" uint64_t original_i(...) { return guest_i(...); }Those signatures are abbreviated here. With Windows MinGW-w64 GCC 15.2.0, the generated wrapper transfers the Microsoft ABI register and stack arguments into the System V argument registers before calling To make this boundary directly testable, I merged upstream main
The PR description now includes this evidence. These are local Windows results; full product CI and macOS hardware execution are not claimed. Your independent Linux result will still be useful. Implemented and verified with AI assistance. |
What
Compiles one named x86-64 ELF integer leaf function through LLVM IR and LLVM's native object/assembly emitter. The input ABI is explicit: zero to six
uint64_tSystem V arguments and auint64_tresult. LLVM adapts that signature to the selected x86-64 target ABI.3rdparty/llvm-projectand built from source.ANYPS5_BUILD_AOT=ON. The standalone build remains available.-arch x86_64; a compile-time guard rejects other architectures. Python only reads subprocess results and may remain ARM64. Windows subprocesses receive the selected compiler runtime directory in PATH.docs/dev/BUILD.mdand remaining limitations indocs/dev/debt/aot.md.This is a bounded leaf-function compiler. Whole-executable translation, ABI recovery, runtime services and game compatibility remain outside its supported contract. Multiple output files are not published as one transaction.
Tested
Windows 11 x86-64, Ryzen 7 5800X, WinLibs MinGW-w64 GCC 15.2.0, Ninja, Python 3.14.8. LLVM was compiled from the pinned source submodule in both build configurations.
ANYPS5_RELINKER_ONLY=ON,ANYPS5_BUILD_AOT=ON,BUILD_TESTING=ON: 241/241 CTest tests passed, zero skipped (204.44 seconds with four test workers). This includes all six compiler groups.tools/check_skips.pyconfirms zero skips.2cb4c77224(compiler implementation unchanged): Clang 23.1.2 compiled a freestanding three-argument C function returning(a ^ b) & cto Linux ELF. The new compiler translated it to COFF, GCC linked it into a DLL, and all 1,000 randomized native calls matched the C expression.-arch x86_64selected x86-64 macros. These are driver/preprocessor checks, not macOS execution. The Windows moves group also passed with the compiler runtime directory initially removed from PATH.ANYPS5_BUILD_AOT=OFF.upstream/main. The required--base origin/maincheck has zero errors and eleven pre-existing upstream debt-length warnings because the fork's main is older. Script/executable test-registration checks andgit diff --checkpass.Validation head:
ef919e2a6a995cb7ddc6c66b910a26a504ced1fd, including upstream main4997726a5f6b8cd263461508945a4676647ef482. The full system-library/product build, GPU tests, console hardware and titles were not tested.The Apple Silicon review exposed the old in-process
ctypesarchitecture mismatch. The replacement uses separate executables, so ARM64 Python never loads x86 machine code. Clang documents-arch, and Apple documents automatic Rosetta translation of Intel-only executables. Rosetta is required on Apple Silicon; tests fail if execution support is missing. The corrected macOS path still requires a hardware rerun; no macOS pass is claimed.The Windows ABI review was checked against its exact cited head,
f8b85103b0. That file already declares onlyguest_iwithsysv_abi;original_ihas the host default ABI, matching the runner and function-pointer declarations. The generated Windows assembly saves the Microsoft ABI nonvolatile registers and transfers RCX/RDX/R8/R9 plus stack arguments into the six System V argument registers before callingguest_i. No calling-convention change was needed.Added
aot_leaf_abi, which independently returns each of the six arguments and compares native reference, emitted object and emitted assembly results against 210 boundary/random vectors. The exact reviewed-head harness also passed those six projections on Windows. As a negative control, an isolated temporary copy marking the outeroriginal_iwrappersysv_abifailed immediately withReference model disagrees with native x86-64 for case 0. The incorrect ABI therefore cannot silently validate the results in this check. GCC documents the Windows default and the per-function ABI attributes.Reproduction commands, with the supported GCC toolchain and Python on PATH:
git submodule update --init 3rdparty/llvm-project cmake -S core/aot -B build-aot -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DBUILD_TESTING=ON cmake --build build-aot --target aot_compiler_cli aot_ir_check --parallel 8 ctest --test-dir build-aot -V cmake -S . -B build-root -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DANYPS5_RELINKER_ONLY=ON -DANYPS5_BUILD_AOT=ON -DBUILD_TESTING=ON cmake --build build-root --parallel 8 ctest --test-dir build-root --output-on-failure --parallel 4tools/pr_overlap.pywas rerun against the open upstream PRs. The newly reported.gitmodulesappend conflict with #10167 is resolved by placing the LLVM entry beside the compiler dependencies; the fresh scan no longer flags #10167 andgit merge-treesucceeds for its current head. Drafts #1835 and #5021 implement a separate Python/Capstone ARM64 compiler; this PR introduces no shared NID exports or dependency on those implementations. Their newcore/aot/CMakeLists.txtanddocs/dev/debt/aot.mdpaths overlap and require reconciliation before both changes can merge. The remaining shared build/documentation files were inspected; the scan could not automatically compare PRs that already conflict with main. No claim of an overlap-free merge or agreed merge order is made.Open-PR overlap scan
Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.
main)core/aot/CMakeLists.txtdocs/dev/debt/aot.mdcore/aot/CMakeLists.txtdocs/dev/debt/aot.mdSome comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.
.gitmodulesCMakeLists.txtdocs/dev/BUILD.md.gitmodulesCMakeLists.txtcore/aot/CMakeLists.txtdocs/dev/BUILD.mddocs/dev/debt/aot.md.gitmodulesCMakeLists.txtcore/aot/CMakeLists.txtdocs/dev/BUILD.mddocs/dev/debt/aot.md.gitmodulesCMakeLists.txtCMakeLists.txtdocs/dev/BUILD.md.gitmodulesChecklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file.mdfiles or images added to the repository (attach them to this PR)