When preparing arguments for a function call, the JIT must detect and
resolve dependencies (cycles) between registers. This occurs when,
for example, the value for the first argument is currently in the
register that should hold the second argument, and vice-versa.
The logic incorrectly used the register's 'kind' (the register class)
instead of its 'abi' (the specific data type/width) to identify the
source operand. This caused the dependency solver to fail or emit
incorrect moves on 64-bit platforms where floating-point arguments
are passed in registers.
This issue is "masked" on 32-bit x86 (IA32) because it primarily
uses the stack for passing double-precision arguments, avoiding
register-to-register swaps for the ABI registers.
The fix has been verified by adjusting 'tests/call_10_2.c' to force
a register swap (F0/F1). Formerly the modified test failed on:
- Linux x86_64 (System V ABI)
- Linux aarch64
- Windows 64-bit (Microsoft x64 ABI) via Cygwin, MINGW64, UCRT64,
and CLANG64.
* lightening/lightening.c (prepare_args): Use 'src[j].abi' instead of
'src[j].kind' when resolving register-to-register dependencies.
* tests/call_10_2.c (run_test_double): Swap the order in which dargs[0]
and dargs[1] are loaded into registers F0 and F1. This forces a
register cycle during the call, exposing the dependency resolution bug.
Fix register dependency resolution in JIT calls #2
h-c-mueller/lightening:fix_move_one into main
The command `make -C tests test-native' now runs successfully on MSYS2 for MSYS (a Cygwin clone), MINGW32, MINGW64, and UCRT64. The command `make -C tests CC=clang test-native' passed on CLANG64. Finally, the command: 'make -C tests check TARGETS="native ia32 aarch64" \ CC_IA32=i686-linux-gnu-gcc \ CC_AARCH64=aarch64-linux-gnu-gcc' passes on Linux x86_64. All without warnings. Patch regarding __ffs is based on ideas from Michael Gran. * lightening.h (JIT_API): Update copyright year. Disable visibility attributes on Cygwin and Windows, as they are not supported the same way as on ELF platforms. * lightening/aarch64.c: Update copyright year. Add `maybe_unused' attributes to instruction helpers generated by the `DEFINE_PATCHABLE_INSTRUCTION' macro to suppress warnings. * lightening/lightening.c: Update copyright year. Remove inclusion of `<sys/mman.h>' since it is no longer required. Fix warnings from -Wundef. * lightening/lightening.c (jit_address): Cast ternary operator results to `(jit_pointer_t)' and wrap in parentheses to avoid pointer type mismatch warnings in Clang. * lightening/x86-cpu.c (__ffs): Update copyright year. New static helper to wrap `__builtin_ffs' on Windows/MinGW where the standard `ffs' function is missing. * lightening/x86-cpu.c (ffsw): Use the new `__ffs' helper. * lightening/x86.c (reset_abi_arg_iterator): Update copyright year. Simplify Cygwin 64-bit and Windows 64-bit detection logic without changing any code path. * tests/Makefile: Add `EXEEXT' support for Windows. Update `PROGS' and `clean' rules. Refactor test targets to correctly use dependencies with extensions. Update Debian package installation instructions and dependencies. Add -Wundef since related warnings have been found. * tests/call_10_2.c (run_test_double): Adjust register usage for the Microsoft x64 ABI. Only use `JIT_F0' through `JIT_F4' as scratch registers to comply with the MS ABI. * tests/test.h (main_helper): Use `uint8_t *' for arena_base instead of `char *'. Implement Windows-specific JIT memory allocation using `CreateFileMapping' and `MapViewOfFile'. Add proper cleanup using `UnmapViewOfFile' and `CloseHandle'.
When preparing arguments for a function call, the JIT must detect and resolve dependencies (cycles) between registers. This occurs when, for example, the value for the first argument is currently in the register that should hold the second argument, and vice-versa. The logic incorrectly used the register's 'kind' (the register class) instead of its 'abi' (the specific data type/width) to identify the source operand. This caused the dependency solver to fail or emit incorrect moves on 64-bit platforms where floating-point arguments are passed in registers. This issue is "masked" on 32-bit x86 (IA32) because it primarily uses the stack for passing double-precision arguments, avoiding register-to-register swaps for the ABI registers. The fix has been verified by adjusting 'tests/call_10_2.c' to force a register swap (F0/F1). Formerly the modified test failed on: - Linux x86_64 (System V ABI) - Linux aarch64 - Windows 64-bit (Microsoft x64 ABI) via Cygwin, MINGW64, UCRT64, and CLANG64. * lightening/lightening.c (prepare_args): Use 'src[j].abi' instead of 'src[j].kind' when resolving register-to-register dependencies. * tests/call_10_2.c (run_test_double): Swap the order in which dargs[0] and dargs[1] are loaded into registers F0 and F1. This forces a register cycle during the call, exposing the dependency resolution bug.
The change of parameter to is_fpr_arg looks absolutely correct to me. I don't know how this doesn't cause more havoc 😱
Edit: note that this currently includes the commit from #1, maybe it would make sense to separate the two PRs more strictly?
Hi, could you please rebase on top of main so I can tell the CI to test the changes?
When the PR was proposed the CI was broken... but has been fixed now.
Thank you!
- tests/Makefile
View command line instructions
Manual merge helper
Use this merge commit message when completing the merge manually.
Checkout
From your project repository, check out a new branch and test the changes.Merge
Merge the changes and update on Forgejo.Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.
No due date set.
No dependencies set.
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?