[foreign-memaccess+abi] RFR: 8295290: Add Windows ARM64 ABI support to the Foreign Function & Memory API [v2]
Jorn Vernee
jvernee at openjdk.org
Fri Jan 6 10:15:27 UTC 2023
On Sun, 1 Jan 2023 06:16:01 GMT, Saint Wesonga <duke at openjdk.org> wrote:
>> There are 2 primary differences between the Windows ARM64 ABI and the macOS/Linux ARM64 ABI: variadic floating point arguments are passed in general purpose registers on Windows (instead of the vector registers). In addition to this, up to 64 bytes of a struct being passed to a variadic function can be placed in general purpose registers. This happens regardless of the type of struct (HFA or other generic struct). This means that a struct can be split across registers and the stack when invoking a variadic function.
>>
>> This change introduces tests that compute the sum of the fields of structs containing 1-4 ints, floats, and doubles to verify that each field is correctly assigned a register or stack location when invoking a variadic function (both when the struct can be passed entirely in registers as well as when the struct spills onto the stack).
>>
>> For details about the Foreign Function & Memory API, see JEP 434 defined at https://openjdk.org/jeps/434
>>
>> The Windows ARM64 ABI conventions are documented at https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions
>>
>> This work builds on @lewurm / Bernhard's branch at https://github.com/lewurm/openjdk/commits/foreign-windows-aarch64
>
> Saint Wesonga has updated the pull request with a new target base due to a merge or a rebase. The pull request now contains ten commits:
>
> - Merge branch 'foreign-memaccess+abi' into WindowsAArch64ABI
> - Update Windows FFM implementation to match latest Preview API
> - Merge branch 'foreign-memaccess+abi' into WindowsAArch64ABI
> - Simplify newly added tests in TestVarArgs
> - Move storage decisions into StorageCalculator
> - Remove toSessionImpl method
> - Remove unnecessary null check
> - Move Windows CallArranger tests into separate file
> - Add Windows ARM64 ABI support to the Foreign Function & Memory API
>
> There are 2 primary differences between the Windows ARM64 ABI and
> the macOS/Linux ARM64 ABI: variadic floating point arguments are passed
> in general purpose registers on Windows (instead of the vector registers).
> In addition to this, up to 64 bytes of a struct being passed to a
> variadic function can be placed in general purpose registers. This
> happens regardless of the type of struct (HFA or other generic struct).
> This means that a struct can be split across registers and the stack
> when invoking a variadic function.
>
> This change introduces tests that compute the sum of the fields of
> structs containing 1-4 ints, floats, and doubles to verify that each
> field is correctly assigned a register or stack location when invoking
> a variadic function (both when the struct can be passed entirely in
> registers as well as when the struct spills onto the stack).
>
> For details about the Foreign Function & Memory API, see JEP 434
> defined at https://openjdk.org/jeps/434
>
> The Windows ARM64 ABI conventions are documented at
> https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions
Few more comments inline.
FWIW, I think CallArranger can be cleaned up further, and I've been playing with a patch [1]. But I'll file a followup PR for that.
[1]: https://github.com/openjdk/panama-foreign/compare/pull/754/head...JornVernee:panama-foreign:Refector_CallArranger
src/java.base/share/classes/jdk/internal/foreign/abi/LinkerOptions.java line 86:
> 84: public boolean isVariadicFunction() {
> 85: FirstVariadicArg fva = getOption(FirstVariadicArg.class);
> 86: return fva != null && fva.index >= 0;
The second condition is not needed anymore, since we now validate that the index is greater than 0 already. (See `FirstVariadicArg::validateForDowncall`)
src/java.base/share/classes/jdk/internal/foreign/abi/aarch64/CallArranger.java line 263:
> 261:
> 262: VMStorage[] regAlloc(int type, MemoryLayout layout) {
> 263: boolean spillRegistersPartially = forVariadicFunction && spillsVariadicStructsPartially();
Just be sure here, this would make it so that any struct passed to a variadic function is spilled partially, even if that particular struct is not being passed as a variadic argument.
Is that correct?
src/java.base/share/classes/jdk/internal/foreign/abi/aarch64/CallArranger.java line 287:
> 285: if (type == StorageType.VECTOR) {
> 286: boolean forVariadicFunctionArgs = forArguments && forVariadicFunction;
> 287: boolean useIntRegsForFloatingPointArgs = forVariadicFunctionArgs && useIntRegsForVariadicFloatingPointArgs();
Same here I suppose. On Windows/x64 we pass vardiadic floats both in float registers and int registers, but only variadic floats. But, this seems to make it so that any float being passed to a variadic function, even as fixed argument, is passed in an int register.
test/jdk/java/foreign/valist/VaListTest.java line 136:
> 134: private static final Function<Consumer<VaList.Builder>, VaList> linuxAArch64VaListFactory
> 135: = actions -> LinuxAArch64Linker.newVaList(actions, SegmentScope.auto());
> 136: private static final Function<Consumer<VaList.Builder>, VaList> macAArch64VaListFactory
Spurious whitespace
Suggestion:
private static final Function<Consumer<VaList.Builder>, VaList> macAArch64VaListFactory
-------------
PR: https://git.openjdk.org/panama-foreign/pull/754
More information about the panama-dev
mailing list