[vm/ffi] Fix variadic arguments on MacOS Arm64

Non-variadic arguments on the stack on MacOS Arm64 are aligned to
the value size (which can be smaller than word size). However, for
varargs, the arguments on the stack seem to be aligned to the word
size.

This CL introduces an alignment strategy constant for primitives on
the stack in varargs and uses it in the native calling convention
calculation.

TEST=runtime/vm/compiler/ffi/native_calling_convention_test.cc with
runtime/vm/compiler/ffi/unit_tests/variadic_less_than_word/arm64_macos.expect

TEST=tests/ffi/function_varargs_generated_native_leaf_test.dart

Closes: https://github.com/dart-lang/sdk/issues/55471
Change-Id: I51d20c3933a2cea9b110954ddec92fb91b9c3ecd
Cq-Include-Trybots: dart/try:vm-aot-android-release-arm64c-try,vm-aot-linux-debug-x64-try,vm-aot-linux-debug-x64c-try,vm-aot-mac-release-arm64-try,vm-aot-mac-release-x64-try,vm-aot-obfuscate-linux-release-x64-try,vm-aot-optimization-level-linux-release-x64-try,vm-aot-win-debug-arm64-try,vm-aot-win-debug-x64-try,vm-aot-win-debug-x64c-try,vm-appjit-linux-debug-x64-try,vm-asan-linux-release-x64-try,vm-checked-mac-release-arm64-try,vm-eager-optimization-linux-release-ia32-try,vm-eager-optimization-linux-release-x64-try,vm-ffi-android-debug-arm-try,vm-ffi-android-debug-arm64c-try,vm-ffi-qemu-linux-release-arm-try,vm-ffi-qemu-linux-release-riscv64-try,vm-fuchsia-release-x64-try,vm-linux-debug-ia32-try,vm-linux-debug-x64-try,vm-linux-debug-x64c-try,vm-mac-debug-arm64-try,vm-mac-debug-x64-try,vm-msan-linux-release-x64-try,vm-reload-linux-debug-x64-try,vm-reload-rollback-linux-debug-x64-try,vm-ubsan-linux-release-x64-try,vm-win-debug-arm64-try,vm-win-debug-x64-try,vm-win-debug-x64c-try,vm-win-release-ia32-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/362762
Commit-Queue: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Tess Strickland <sstrickl@google.com>
This commit is contained in:
Daco Harkes 2024-04-17 15:42:16 +00:00 committed by Commit Queue
parent 4bb644ce3e
commit c0b938c228
35 changed files with 685 additions and 2 deletions

View file

@ -22996,6 +22996,38 @@ DART_EXPORT int64_t VariadicAt1Int64x7Struct12BytesHomogeneousInt32(int64_t a0,
return result;
}
// Used for testing structs and unions by value.
// Variadic arguments test on macos_arm64.
DART_EXPORT int32_t VariadicAt1Struct12BytesHomogeneousInt32Int32x4(
Struct12BytesHomogeneousInt32 a0,
...) {
va_list var_args;
va_start(var_args, a0);
int32_t a1 = va_arg(var_args, int32_t);
int32_t a2 = va_arg(var_args, int32_t);
int32_t a3 = va_arg(var_args, int32_t);
int32_t a4 = va_arg(var_args, int32_t);
va_end(var_args);
std::cout << "VariadicAt1Struct12BytesHomogeneousInt32Int32x4" << "(("
<< a0.a0 << ", " << a0.a1 << ", " << a0.a2 << "), " << a1 << ", "
<< a2 << ", " << a3 << ", " << a4 << ")" << "\n";
int32_t result = 0;
result += a0.a0;
result += a0.a1;
result += a0.a2;
result += a1;
result += a2;
result += a3;
result += a4;
std::cout << "result = " << result << "\n";
return result;
}
// Used for testing structs and unions by value.
// Single variadic argument.
DART_EXPORT intptr_t TestVariadicAt1Int64x2(
@ -23897,4 +23929,50 @@ DART_EXPORT intptr_t TestVariadicAt1Int64x7Struct12BytesHomogeneousInt32(
return 0;
}
// Used for testing structs and unions by value.
// Variadic arguments test on macos_arm64.
DART_EXPORT intptr_t TestVariadicAt1Struct12BytesHomogeneousInt32Int32x4(
// NOLINTNEXTLINE(whitespace/parens)
int32_t (*f)(Struct12BytesHomogeneousInt32 a0, ...)) {
Struct12BytesHomogeneousInt32 a0 = {};
int32_t a1;
int32_t a2;
int32_t a3;
int32_t a4;
a0.a0 = -1;
a0.a1 = 2;
a0.a2 = -3;
a1 = 4;
a2 = -5;
a3 = 6;
a4 = -7;
std::cout << "Calling TestVariadicAt1Struct12BytesHomogeneousInt32Int32x4("
<< "((" << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << "), " << a1
<< ", " << a2 << ", " << a3 << ", " << a4 << ")" << ")\n";
int32_t result = f(a0, a1, a2, a3, a4);
std::cout << "result = " << result << "\n";
CHECK_EQ(-4, result);
// Pass argument that will make the Dart callback throw.
a0.a0 = 42;
result = f(a0, a1, a2, a3, a4);
CHECK_EQ(0, result);
// Pass argument that will make the Dart callback return null.
a0.a0 = 84;
result = f(a0, a1, a2, a3, a4);
CHECK_EQ(0, result);
return 0;
}
} // namespace dart

View file

@ -242,7 +242,7 @@ class ArgumentAllocator : public ValueObject {
zone_, payload_type, container_type, AllocateCpuRegister());
}
}
return AllocateStack(payload_type);
return AllocateStack(payload_type, is_vararg);
}
// Constructs a container type.

View file

@ -969,6 +969,28 @@ UNIT_TEST_CASE_WITH_ZONE(
RunSignatureTest(Z, "variadic_stradle_last_register", native_signature);
}
// Struct parameter that potentially is partially allocated to a register and
// partially to the stack. Mainly interesting on ARM64 and RISC-V.
//
// See the *.expect in ./unit_tests for this behavior.
UNIT_TEST_CASE_WITH_ZONE(NativeCallingConvention_variadic_less_than_word) {
#if defined(TARGET_ARCH_IS_32_BIT)
const auto& halfptr_type = *new (Z) NativePrimitiveType(kInt16);
#elif defined(TARGET_ARCH_IS_64_BIT)
const auto& halfptr_type = *new (Z) NativePrimitiveType(kInt32);
#endif
auto& arguments = *new (Z) NativeTypes(Z, 12);
for (intptr_t i = 0; i < 12; i++) {
arguments.Add(&halfptr_type);
}
const auto& native_signature = *new (Z) NativeFunctionType(
arguments, halfptr_type, /*variadic_arguments_index=*/1);
RunSignatureTest(Z, "variadic_less_than_word", native_signature);
}
} // namespace ffi
} // namespace compiler
} // namespace dart

View file

@ -152,7 +152,10 @@ intptr_t NativePrimitiveType::SizeInBytes() const {
}
intptr_t NativePrimitiveType::AlignmentInBytesStack(bool is_vararg) const {
switch (CallingConventions::kArgumentStackAlignment) {
const auto alignment =
is_vararg ? CallingConventions::kArgumentStackAlignmentVarArgs
: CallingConventions::kArgumentStackAlignment;
switch (alignment) {
case kAlignedToWordSize:
// The default is to align stack arguments to word size.
return compiler::target::kWordSize;

View file

@ -0,0 +1,14 @@
r0 int32
r1 int32
r2 int32
r3 int32
r4 int32
r5 int32
r6 int32
r7 int32
S+0 int32
S+8 int32
S+16 int32
S+24 int32
=>
r0 int32

View file

@ -0,0 +1,14 @@
r0 int32
r1 int32
r2 int32
r3 int32
r4 int32
r5 int32
r6 int32
r7 int32
S+0 int32
S+8 int32
S+16 int32
S+24 int32
=>
r0 int32

View file

@ -0,0 +1,14 @@
r0 int32
S+0 int32
S+8 int32
S+16 int32
S+24 int32
S+32 int32
S+40 int32
S+48 int32
S+56 int32
S+64 int32
S+72 int32
S+80 int32
=>
r0 int32

View file

@ -0,0 +1,14 @@
r0 int32
r1 int32
r2 int32
r3 int32
r4 int32
r5 int32
r6 int32
r7 int32
S+0 int32
S+8 int32
S+16 int32
S+24 int32
=>
r0 int32

View file

@ -0,0 +1,14 @@
r0 int32
S+0 int32
S+8 int32
S+16 int32
S+24 int32
S+32 int32
S+40 int32
S+48 int32
S+56 int32
S+64 int32
S+72 int32
S+80 int32
=>
r0 int32

View file

@ -0,0 +1,14 @@
r0 int32
r1 int32
r2 int32
r3 int32
r4 int32
r5 int32
r6 int32
r7 int32
S+0 int32
S+8 int32
S+16 int32
S+24 int32
=>
r0 int32

View file

@ -0,0 +1,14 @@
r0 int32[int16]
r1 int32[int16]
r2 int32[int16]
r3 int32[int16]
S+0 int32[int16]
S+4 int32[int16]
S+8 int32[int16]
S+12 int32[int16]
S+16 int32[int16]
S+20 int32[int16]
S+24 int32[int16]
S+28 int32[int16]
=>
r0 int32[int16]

View file

@ -0,0 +1,14 @@
r0 int32[int16]
r1 int32[int16]
r2 int32[int16]
r3 int32[int16]
S+0 int32[int16]
S+4 int32[int16]
S+8 int32[int16]
S+12 int32[int16]
S+16 int32[int16]
S+20 int32[int16]
S+24 int32[int16]
S+28 int32[int16]
=>
r0 int32[int16]

View file

@ -0,0 +1,14 @@
r0 int32[int16]
r1 int32[int16]
r2 int32[int16]
r3 int32[int16]
S+0 int32[int16]
S+4 int32[int16]
S+8 int32[int16]
S+12 int32[int16]
S+16 int32[int16]
S+20 int32[int16]
S+24 int32[int16]
S+28 int32[int16]
=>
r0 int32[int16]

View file

@ -0,0 +1,14 @@
S+0 int32[int16]
S+4 int32[int16]
S+8 int32[int16]
S+12 int32[int16]
S+16 int32[int16]
S+20 int32[int16]
S+24 int32[int16]
S+28 int32[int16]
S+32 int32[int16]
S+36 int32[int16]
S+40 int32[int16]
S+44 int32[int16]
=>
eax int16

View file

@ -0,0 +1,14 @@
S+0 int32[int16]
S+4 int32[int16]
S+8 int32[int16]
S+12 int32[int16]
S+16 int32[int16]
S+20 int32[int16]
S+24 int32[int16]
S+28 int32[int16]
S+32 int32[int16]
S+36 int32[int16]
S+40 int32[int16]
S+44 int32[int16]
=>
eax int16

View file

@ -0,0 +1,14 @@
S+0 int32[int16]
S+4 int32[int16]
S+8 int32[int16]
S+12 int32[int16]
S+16 int32[int16]
S+20 int32[int16]
S+24 int32[int16]
S+28 int32[int16]
S+32 int32[int16]
S+36 int32[int16]
S+40 int32[int16]
S+44 int32[int16]
=>
eax int16

View file

@ -0,0 +1,14 @@
a0 int32[int16]
a1 int32[int16]
a2 int32[int16]
t3 int32[int16]
t4 int32[int16]
t5 int32[int16]
a6 int32[int16]
a7 int32[int16]
S+0 int32[int16]
S+4 int32[int16]
S+8 int32[int16]
S+12 int32[int16]
=>
a0 int32[int16]

View file

@ -0,0 +1,14 @@
a0 int64[int32]
a1 int64[int32]
a2 int64[int32]
t3 int64[int32]
t4 int64[int32]
t5 int64[int32]
a6 int64[int32]
a7 int64[int32]
S+0 int64[int32]
S+8 int64[int32]
S+16 int64[int32]
S+24 int64[int32]
=>
a0 int64[int32]

View file

@ -0,0 +1,14 @@
rdi int32
rsi int32
rdx int32
rcx int32
r8 int32
r9 int32
S+0 int32
S+8 int32
S+16 int32
S+24 int32
S+32 int32
S+40 int32
=>
rax int32

View file

@ -0,0 +1,14 @@
rdi int32
rsi int32
rdx int32
rcx int32
r8 int32
r9 int32
S+0 int32
S+8 int32
S+16 int32
S+24 int32
S+32 int32
S+40 int32
=>
rax int32

View file

@ -0,0 +1,14 @@
rdi int32
rsi int32
rdx int32
rcx int32
r8 int32
r9 int32
S+0 int32
S+8 int32
S+16 int32
S+24 int32
S+32 int32
S+40 int32
=>
rax int32

View file

@ -0,0 +1,14 @@
rdi int32
rsi int32
rdx int32
rcx int32
r8 int32
r9 int32
S+0 int32
S+8 int32
S+16 int32
S+24 int32
S+32 int32
S+40 int32
=>
rax int32

View file

@ -0,0 +1,14 @@
rcx int32
rdx int32
r8 int32
r9 int32
S+0 int32
S+8 int32
S+16 int32
S+24 int32
S+32 int32
S+40 int32
S+48 int32
S+56 int32
=>
rax int32

View file

@ -718,6 +718,8 @@ class CallingConventions {
// How stack arguments are aligned.
static constexpr AlignmentStrategy kArgumentStackAlignment =
kAlignedToWordSizeAndValueSize;
static constexpr AlignmentStrategy kArgumentStackAlignmentVarArgs =
kArgumentStackAlignment;
// How fields in compounds are aligned.
#if defined(DART_TARGET_OS_MACOS_IOS)

View file

@ -584,9 +584,14 @@ class CallingConventions {
// https://developer.apple.com/documentation/xcode/writing_arm64_code_for_apple_platforms
static constexpr AlignmentStrategy kArgumentStackAlignment =
kAlignedToValueSize;
// Varargs are aligned to wordsize.
static constexpr AlignmentStrategy kArgumentStackAlignmentVarArgs =
kAlignedToWordSize;
#else
static constexpr AlignmentStrategy kArgumentStackAlignment =
kAlignedToWordSize;
static constexpr AlignmentStrategy kArgumentStackAlignmentVarArgs =
kArgumentStackAlignment;
#endif
// How fields in compounds are aligned.

View file

@ -503,6 +503,8 @@ class CallingConventions {
// How stack arguments are aligned.
static constexpr AlignmentStrategy kArgumentStackAlignment =
kAlignedToWordSize;
static constexpr AlignmentStrategy kArgumentStackAlignmentVarArgs =
kArgumentStackAlignment;
// How fields in compounds are aligned.
#if defined(DART_TARGET_OS_WINDOWS)

View file

@ -557,6 +557,8 @@ class CallingConventions {
// How stack arguments are aligned.
static constexpr AlignmentStrategy kArgumentStackAlignment =
kAlignedToWordSizeAndValueSize;
static constexpr AlignmentStrategy kArgumentStackAlignmentVarArgs =
kArgumentStackAlignment;
// How fields in compounds are aligned.
static constexpr AlignmentStrategy kFieldAlignment = kAlignedToValueSize;

View file

@ -571,6 +571,8 @@ class CallingConventions {
// How stack arguments are aligned.
static constexpr AlignmentStrategy kArgumentStackAlignment =
kAlignedToWordSize;
static constexpr AlignmentStrategy kArgumentStackAlignmentVarArgs =
kArgumentStackAlignment;
// How fields in compounds are aligned.
static constexpr AlignmentStrategy kFieldAlignment = kAlignedToValueSize;
@ -641,6 +643,8 @@ class CallingConventions {
// How stack arguments are aligned.
static constexpr AlignmentStrategy kArgumentStackAlignment =
kAlignedToWordSize;
static constexpr AlignmentStrategy kArgumentStackAlignmentVarArgs =
kArgumentStackAlignment;
// How fields in compounds are aligned.
static constexpr AlignmentStrategy kFieldAlignment = kAlignedToValueSize;

View file

@ -124,6 +124,11 @@ final testCases = [
Pointer.fromFunction<VariadicAt1Int64x7Struct12BytesHomogeneousInt32Type>(
variadicAt1Int64x7Struct12BytesHomogeneousInt32, 0),
variadicAt1Int64x7Struct12BytesHomogeneousInt32AfterCallback),
CallbackTest.withCheck(
"VariadicAt1Struct12BytesHomogeneousInt32Int32x4",
Pointer.fromFunction<VariadicAt1Struct12BytesHomogeneousInt32Int32x4Type>(
variadicAt1Struct12BytesHomogeneousInt32Int32x4, 0),
variadicAt1Struct12BytesHomogeneousInt32Int32x4AfterCallback),
];
typedef VariadicAt1Int64x2Type = Int64 Function(Int64, VarArgs<(Int64,)>);
@ -1488,3 +1493,70 @@ void variadicAt1Int64x7Struct12BytesHomogeneousInt32AfterCallback() {
Expect.equals(5, result);
}
typedef VariadicAt1Struct12BytesHomogeneousInt32Int32x4Type = Int32 Function(
Struct12BytesHomogeneousInt32, VarArgs<(Int32, Int32, Int32, Int32)>);
// Global variables to be able to test inputs after callback returned.
Struct12BytesHomogeneousInt32
variadicAt1Struct12BytesHomogeneousInt32Int32x4_a0 =
Pointer<Struct12BytesHomogeneousInt32>.fromAddress(0).ref;
int variadicAt1Struct12BytesHomogeneousInt32Int32x4_a1 = 0;
int variadicAt1Struct12BytesHomogeneousInt32Int32x4_a2 = 0;
int variadicAt1Struct12BytesHomogeneousInt32Int32x4_a3 = 0;
int variadicAt1Struct12BytesHomogeneousInt32Int32x4_a4 = 0;
// Result variable also global, so we can delete it after the callback.
int variadicAt1Struct12BytesHomogeneousInt32Int32x4Result = 0;
int variadicAt1Struct12BytesHomogeneousInt32Int32x4CalculateResult() {
int result = 0;
result += variadicAt1Struct12BytesHomogeneousInt32Int32x4_a0.a0;
result += variadicAt1Struct12BytesHomogeneousInt32Int32x4_a0.a1;
result += variadicAt1Struct12BytesHomogeneousInt32Int32x4_a0.a2;
result += variadicAt1Struct12BytesHomogeneousInt32Int32x4_a1;
result += variadicAt1Struct12BytesHomogeneousInt32Int32x4_a2;
result += variadicAt1Struct12BytesHomogeneousInt32Int32x4_a3;
result += variadicAt1Struct12BytesHomogeneousInt32Int32x4_a4;
variadicAt1Struct12BytesHomogeneousInt32Int32x4Result = result;
return result;
}
/// Variadic arguments test on macos_arm64.
int variadicAt1Struct12BytesHomogeneousInt32Int32x4(
Struct12BytesHomogeneousInt32 a0, int a1, int a2, int a3, int a4) {
print(
"variadicAt1Struct12BytesHomogeneousInt32Int32x4(${a0}, ${a1}, ${a2}, ${a3}, ${a4})");
// Possibly throw.
if (a0.a0 == 42 || a0.a0 == 84) {
print("throwing!");
throw Exception(
"VariadicAt1Struct12BytesHomogeneousInt32Int32x4 throwing on purpose!");
}
variadicAt1Struct12BytesHomogeneousInt32Int32x4_a0 = a0;
variadicAt1Struct12BytesHomogeneousInt32Int32x4_a1 = a1;
variadicAt1Struct12BytesHomogeneousInt32Int32x4_a2 = a2;
variadicAt1Struct12BytesHomogeneousInt32Int32x4_a3 = a3;
variadicAt1Struct12BytesHomogeneousInt32Int32x4_a4 = a4;
final result =
variadicAt1Struct12BytesHomogeneousInt32Int32x4CalculateResult();
print("result = $result");
return result;
}
void variadicAt1Struct12BytesHomogeneousInt32Int32x4AfterCallback() {
final result =
variadicAt1Struct12BytesHomogeneousInt32Int32x4CalculateResult();
print("after callback result = $result");
Expect.equals(-4, result);
}

View file

@ -145,6 +145,13 @@ final testCases = [
variadicAt1Int64x7Struct12BytesHomogeneousInt32,
exceptionalReturn: 0),
variadicAt1Int64x7Struct12BytesHomogeneousInt32AfterCallback),
CallbackTest.withCheck(
"VariadicAt1Struct12BytesHomogeneousInt32Int32x4",
NativeCallable<
VariadicAt1Struct12BytesHomogeneousInt32Int32x4Type>.isolateLocal(
variadicAt1Struct12BytesHomogeneousInt32Int32x4,
exceptionalReturn: 0),
variadicAt1Struct12BytesHomogeneousInt32Int32x4AfterCallback),
];
typedef VariadicAt1Int64x2Type = Int64 Function(Int64, VarArgs<(Int64,)>);
@ -1509,3 +1516,70 @@ void variadicAt1Int64x7Struct12BytesHomogeneousInt32AfterCallback() {
Expect.equals(5, result);
}
typedef VariadicAt1Struct12BytesHomogeneousInt32Int32x4Type = Int32 Function(
Struct12BytesHomogeneousInt32, VarArgs<(Int32, Int32, Int32, Int32)>);
// Global variables to be able to test inputs after callback returned.
Struct12BytesHomogeneousInt32
variadicAt1Struct12BytesHomogeneousInt32Int32x4_a0 =
Pointer<Struct12BytesHomogeneousInt32>.fromAddress(0).ref;
int variadicAt1Struct12BytesHomogeneousInt32Int32x4_a1 = 0;
int variadicAt1Struct12BytesHomogeneousInt32Int32x4_a2 = 0;
int variadicAt1Struct12BytesHomogeneousInt32Int32x4_a3 = 0;
int variadicAt1Struct12BytesHomogeneousInt32Int32x4_a4 = 0;
// Result variable also global, so we can delete it after the callback.
int variadicAt1Struct12BytesHomogeneousInt32Int32x4Result = 0;
int variadicAt1Struct12BytesHomogeneousInt32Int32x4CalculateResult() {
int result = 0;
result += variadicAt1Struct12BytesHomogeneousInt32Int32x4_a0.a0;
result += variadicAt1Struct12BytesHomogeneousInt32Int32x4_a0.a1;
result += variadicAt1Struct12BytesHomogeneousInt32Int32x4_a0.a2;
result += variadicAt1Struct12BytesHomogeneousInt32Int32x4_a1;
result += variadicAt1Struct12BytesHomogeneousInt32Int32x4_a2;
result += variadicAt1Struct12BytesHomogeneousInt32Int32x4_a3;
result += variadicAt1Struct12BytesHomogeneousInt32Int32x4_a4;
variadicAt1Struct12BytesHomogeneousInt32Int32x4Result = result;
return result;
}
/// Variadic arguments test on macos_arm64.
int variadicAt1Struct12BytesHomogeneousInt32Int32x4(
Struct12BytesHomogeneousInt32 a0, int a1, int a2, int a3, int a4) {
print(
"variadicAt1Struct12BytesHomogeneousInt32Int32x4(${a0}, ${a1}, ${a2}, ${a3}, ${a4})");
// Possibly throw.
if (a0.a0 == 42 || a0.a0 == 84) {
print("throwing!");
throw Exception(
"VariadicAt1Struct12BytesHomogeneousInt32Int32x4 throwing on purpose!");
}
variadicAt1Struct12BytesHomogeneousInt32Int32x4_a0 = a0;
variadicAt1Struct12BytesHomogeneousInt32Int32x4_a1 = a1;
variadicAt1Struct12BytesHomogeneousInt32Int32x4_a2 = a2;
variadicAt1Struct12BytesHomogeneousInt32Int32x4_a3 = a3;
variadicAt1Struct12BytesHomogeneousInt32Int32x4_a4 = a4;
final result =
variadicAt1Struct12BytesHomogeneousInt32Int32x4CalculateResult();
print("result = $result");
return result;
}
void variadicAt1Struct12BytesHomogeneousInt32Int32x4AfterCallback() {
final result =
variadicAt1Struct12BytesHomogeneousInt32Int32x4CalculateResult();
print("after callback result = $result");
Expect.equals(-4, result);
}

View file

@ -43,6 +43,7 @@ void main() {
testVariadicAt1DoubleInt64Int32Struct20BytesHomogeneouLeaf();
testVariadicAt5Doublex5Leaf();
testVariadicAt1Int64x7Struct12BytesHomogeneousInt32Leaf();
testVariadicAt1Struct12BytesHomogeneousInt32Int32x4Leaf();
}
}
@ -804,3 +805,38 @@ void testVariadicAt1Int64x7Struct12BytesHomogeneousInt32Leaf() {
calloc.free(a7Pointer);
}
final variadicAt1Struct12BytesHomogeneousInt32Int32x4Leaf =
ffiTestFunctions.lookupFunction<
Int32 Function(Struct12BytesHomogeneousInt32,
VarArgs<(Int32, Int32, Int32, Int32)>),
int Function(Struct12BytesHomogeneousInt32, int, int, int, int)>(
"VariadicAt1Struct12BytesHomogeneousInt32Int32x4",
isLeaf: true);
/// Variadic arguments test on macos_arm64.
void testVariadicAt1Struct12BytesHomogeneousInt32Int32x4Leaf() {
final a0Pointer = calloc<Struct12BytesHomogeneousInt32>();
final Struct12BytesHomogeneousInt32 a0 = a0Pointer.ref;
int a1;
int a2;
int a3;
int a4;
a0.a0 = -1;
a0.a1 = 2;
a0.a2 = -3;
a1 = 4;
a2 = -5;
a3 = 6;
a4 = -7;
final result =
variadicAt1Struct12BytesHomogeneousInt32Int32x4Leaf(a0, a1, a2, a3, a4);
print("result = $result");
Expect.equals(-4, result);
calloc.free(a0Pointer);
}

View file

@ -46,6 +46,7 @@ void main() {
testVariadicAt1DoubleInt64Int32Struct20BytesHomogeneouNativeLeaf();
testVariadicAt5Doublex5NativeLeaf();
testVariadicAt1Int64x7Struct12BytesHomogeneousInt32NativeLeaf();
testVariadicAt1Struct12BytesHomogeneousInt32Int32x4NativeLeaf();
}
}
@ -799,3 +800,37 @@ void testVariadicAt1Int64x7Struct12BytesHomogeneousInt32NativeLeaf() {
calloc.free(a7Pointer);
}
@Native<
Int32 Function(Struct12BytesHomogeneousInt32,
VarArgs<(Int32, Int32, Int32, Int32)>)>(
symbol: 'VariadicAt1Struct12BytesHomogeneousInt32Int32x4', isLeaf: true)
external int variadicAt1Struct12BytesHomogeneousInt32Int32x4NativeLeaf(
Struct12BytesHomogeneousInt32 a0, int a1, int a2, int a3, int a4);
/// Variadic arguments test on macos_arm64.
void testVariadicAt1Struct12BytesHomogeneousInt32Int32x4NativeLeaf() {
final a0Pointer = calloc<Struct12BytesHomogeneousInt32>();
final Struct12BytesHomogeneousInt32 a0 = a0Pointer.ref;
int a1;
int a2;
int a3;
int a4;
a0.a0 = -1;
a0.a1 = 2;
a0.a2 = -3;
a1 = 4;
a2 = -5;
a3 = 6;
a4 = -7;
final result = variadicAt1Struct12BytesHomogeneousInt32Int32x4NativeLeaf(
a0, a1, a2, a3, a4);
print("result = $result");
Expect.equals(-4, result);
calloc.free(a0Pointer);
}

View file

@ -46,6 +46,7 @@ void main() {
testVariadicAt1DoubleInt64Int32Struct20BytesHomogeneouNative();
testVariadicAt5Doublex5Native();
testVariadicAt1Int64x7Struct12BytesHomogeneousInt32Native();
testVariadicAt1Struct12BytesHomogeneousInt32Int32x4Native();
}
}
@ -794,3 +795,37 @@ void testVariadicAt1Int64x7Struct12BytesHomogeneousInt32Native() {
calloc.free(a7Pointer);
}
@Native<
Int32 Function(Struct12BytesHomogeneousInt32,
VarArgs<(Int32, Int32, Int32, Int32)>)>(
symbol: 'VariadicAt1Struct12BytesHomogeneousInt32Int32x4')
external int variadicAt1Struct12BytesHomogeneousInt32Int32x4Native(
Struct12BytesHomogeneousInt32 a0, int a1, int a2, int a3, int a4);
/// Variadic arguments test on macos_arm64.
void testVariadicAt1Struct12BytesHomogeneousInt32Int32x4Native() {
final a0Pointer = calloc<Struct12BytesHomogeneousInt32>();
final Struct12BytesHomogeneousInt32 a0 = a0Pointer.ref;
int a1;
int a2;
int a3;
int a4;
a0.a0 = -1;
a0.a1 = 2;
a0.a2 = -3;
a1 = 4;
a2 = -5;
a3 = 6;
a4 = -7;
final result =
variadicAt1Struct12BytesHomogeneousInt32Int32x4Native(a0, a1, a2, a3, a4);
print("result = $result");
Expect.equals(-4, result);
calloc.free(a0Pointer);
}

View file

@ -43,6 +43,7 @@ void main() {
testVariadicAt1DoubleInt64Int32Struct20BytesHomogeneou();
testVariadicAt5Doublex5();
testVariadicAt1Int64x7Struct12BytesHomogeneousInt32();
testVariadicAt1Struct12BytesHomogeneousInt32Int32x4();
}
}
@ -769,3 +770,37 @@ void testVariadicAt1Int64x7Struct12BytesHomogeneousInt32() {
calloc.free(a7Pointer);
}
final variadicAt1Struct12BytesHomogeneousInt32Int32x4 =
ffiTestFunctions.lookupFunction<
Int32 Function(Struct12BytesHomogeneousInt32,
VarArgs<(Int32, Int32, Int32, Int32)>),
int Function(Struct12BytesHomogeneousInt32, int, int, int,
int)>("VariadicAt1Struct12BytesHomogeneousInt32Int32x4");
/// Variadic arguments test on macos_arm64.
void testVariadicAt1Struct12BytesHomogeneousInt32Int32x4() {
final a0Pointer = calloc<Struct12BytesHomogeneousInt32>();
final Struct12BytesHomogeneousInt32 a0 = a0Pointer.ref;
int a1;
int a2;
int a3;
int a4;
a0.a0 = -1;
a0.a1 = 2;
a0.a2 = -3;
a1 = 4;
a2 = -5;
a3 = 6;
a4 = -7;
final result =
variadicAt1Struct12BytesHomogeneousInt32Int32x4(a0, a1, a2, a3, a4);
print("result = $result");
Expect.equals(-4, result);
calloc.free(a0Pointer);
}

View file

@ -847,6 +847,18 @@ https://github.com/dart-lang/sdk/issues/49460""",
int64,
"Struct stradles last argument register, variadic",
),
FunctionType(
varArgsIndex: 1,
[
struct12bytesInt,
int32,
int32,
int32,
int32,
],
int32,
"Variadic arguments test on macos_arm64.",
),
];
final struct1byteBool = StructType([bool_]);