Skip to content

Commit 9d5846b

Browse files
dcharkescommit-bot@chromium.org
authored andcommitted
[vm/ffi] Support Unions backend
This Splits the NativeCompoundType into NativeStructType and NativeUnionType. The calling conventions themselves did not have to be updated at all, they rely on the 'queries' on NativeTypes. Some interesting corner cases in the native calling conventions are: 1. Arm64 and arm hardfp still regard unions as homogeneous floats, even if the union members are different sizes. 2. Unions can be larger than their members if their largest member has a smaller alignment than a smaller member. 3. When a specific range in a struct contains floating points in one member, but integers in another, the integers take precedence. Bug: #38491 tools/build.py run_ffi_unit_tests && tools/test.py ffi_unit TEST=runtime/vm/compiler/ffi/native_calling_convention_test.cc TEST=runtime/vm/compiler/ffi/native_type_test.cc These tests are exercised on vm-precomp-ffi-qemu-linux-release-arm-try. Change-Id: Ib97769457d1ad0fce47601e9e4a3008bd837167f Cq-Include-Trybots: luci.dart.try:vm-precomp-ffi-qemu-linux-release-arm-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/194422 Commit-Queue: Daco Harkes <[email protected]> Reviewed-by: Aske Simon Christensen <[email protected]>
1 parent 2f327a6 commit 9d5846b

File tree

199 files changed

+1477
-834
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

199 files changed

+1477
-834
lines changed

runtime/vm/compiler/ffi/native_calling_convention_test.cc

Lines changed: 107 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,7 @@ UNIT_TEST_CASE_WITH_ZONE(NativeCallingConvention_struct3bytesx10) {
9595
member_types.Add(&int8type);
9696
member_types.Add(&int8type);
9797
member_types.Add(&int8type);
98-
const auto& struct_type =
99-
NativeCompoundType::FromNativeTypes(Z, member_types);
98+
const auto& struct_type = NativeStructType::FromNativeTypes(Z, member_types);
10099

101100
auto& arguments = *new (Z) NativeTypes(Z, 10);
102101
arguments.Add(&struct_type);
@@ -138,8 +137,7 @@ UNIT_TEST_CASE_WITH_ZONE(NativeCallingConvention_struct16bytesHomogenousx10) {
138137
member_types.Add(&float_type);
139138
member_types.Add(&float_type);
140139
member_types.Add(&float_type);
141-
const auto& struct_type =
142-
NativeCompoundType::FromNativeTypes(Z, member_types);
140+
const auto& struct_type = NativeStructType::FromNativeTypes(Z, member_types);
143141

144142
auto& arguments = *new (Z) NativeTypes(Z, 13);
145143
arguments.Add(&struct_type);
@@ -174,14 +172,13 @@ UNIT_TEST_CASE_WITH_ZONE(NativeCallingConvention_struct16bytesHomogenousx10_2) {
174172
auto& full_float_member_types = *new (Z) NativeTypes(Z, 1);
175173
full_float_member_types.Add(&float_2_array_type);
176174
const auto& float_array_struct_type =
177-
NativeCompoundType::FromNativeTypes(Z, full_float_member_types);
175+
NativeStructType::FromNativeTypes(Z, full_float_member_types);
178176

179177
auto& member_types = *new (Z) NativeTypes(Z, 3);
180178
member_types.Add(&float_1_array_type);
181179
member_types.Add(&float_array_struct_type);
182180
member_types.Add(&float_type);
183-
const auto& struct_type =
184-
NativeCompoundType::FromNativeTypes(Z, member_types);
181+
const auto& struct_type = NativeStructType::FromNativeTypes(Z, member_types);
185182

186183
auto& arguments = *new (Z) NativeTypes(Z, 13);
187184
arguments.Add(&struct_type);
@@ -203,6 +200,55 @@ UNIT_TEST_CASE_WITH_ZONE(NativeCallingConvention_struct16bytesHomogenousx10_2) {
203200
RunSignatureTest(Z, "struct16bytesHomogenousx10", arguments, struct_type);
204201
}
205202

203+
// Test with homogenous union.
204+
//
205+
// Even though the number of floats nested is different, this is still laid
206+
// out as a homogeneous aggregate in arm64 and arm hardfp.
207+
//
208+
// Even though the member sizes are different, these unions are still passed in
209+
// xmm registers on Linux/MacOS x64.
210+
//
211+
// See the *.expect in ./unit_tests for this behavior.
212+
UNIT_TEST_CASE_WITH_ZONE(NativeCallingConvention_union16bytesHomogenousx10) {
213+
const auto& float_type = *new (Z) NativePrimitiveType(kFloat);
214+
const auto& int8type = *new (Z) NativePrimitiveType(kInt8);
215+
216+
const auto& float_array_type = *new (Z) NativeArrayType(float_type, 3);
217+
218+
auto& struct_member_types = *new (Z) NativeTypes(Z, 4);
219+
struct_member_types.Add(&float_type);
220+
struct_member_types.Add(&float_type);
221+
struct_member_types.Add(&float_type);
222+
struct_member_types.Add(&float_type);
223+
const auto& struct_type =
224+
NativeStructType::FromNativeTypes(Z, struct_member_types);
225+
226+
auto& member_types = *new (Z) NativeTypes(Z, 2);
227+
member_types.Add(&float_array_type);
228+
member_types.Add(&struct_type);
229+
const auto& union_type = NativeUnionType::FromNativeTypes(Z, member_types);
230+
231+
EXPECT_EQ(16, union_type.SizeInBytes());
232+
EXPECT(union_type.ContainsHomogenuousFloats());
233+
234+
auto& arguments = *new (Z) NativeTypes(Z, 13);
235+
arguments.Add(&union_type);
236+
arguments.Add(&union_type);
237+
arguments.Add(&union_type);
238+
arguments.Add(&union_type);
239+
arguments.Add(&union_type);
240+
arguments.Add(&union_type);
241+
arguments.Add(&union_type);
242+
arguments.Add(&union_type);
243+
arguments.Add(&union_type);
244+
arguments.Add(&int8type); // Check integer register back filling, if any.
245+
arguments.Add(&union_type); // Check stack alignment of struct.
246+
247+
// Identical expectation files as previous test, struct contains the same
248+
// members, but nested in arrays and nested structs.
249+
RunSignatureTest(Z, "union16bytesHomogenousx10", arguments, union_type);
250+
}
251+
206252
// A fairly big struct.
207253
//
208254
// On arm, split up in 8-byte chunks. The first chunk goes into two registers,
@@ -237,8 +283,7 @@ UNIT_TEST_CASE_WITH_ZONE(NativeCallingConvention_struct128bytesx1) {
237283
member_types.Add(&int64_type);
238284
member_types.Add(&int64_type);
239285
member_types.Add(&int64_type);
240-
const auto& struct_type =
241-
NativeCompoundType::FromNativeTypes(Z, member_types);
286+
const auto& struct_type = NativeStructType::FromNativeTypes(Z, member_types);
242287

243288
auto& arguments = *new (Z) NativeTypes(Z, 2);
244289
arguments.Add(&struct_type);
@@ -260,8 +305,7 @@ UNIT_TEST_CASE_WITH_ZONE(NativeCallingConvention_struct16bytesMixedx10) {
260305
member_types.Add(&float_type);
261306
member_types.Add(&int32_type);
262307
member_types.Add(&int32_type);
263-
const auto& struct_type =
264-
NativeCompoundType::FromNativeTypes(Z, member_types);
308+
const auto& struct_type = NativeStructType::FromNativeTypes(Z, member_types);
265309

266310
auto& arguments = *new (Z) NativeTypes(Z, 11);
267311
arguments.Add(&struct_type);
@@ -291,8 +335,7 @@ UNIT_TEST_CASE_WITH_ZONE(NativeCallingConvention_struct16bytesMixedx10_2) {
291335
member_types.Add(&float_type);
292336
member_types.Add(&int32_type);
293337
member_types.Add(&int32_type);
294-
const auto& struct_type =
295-
NativeCompoundType::FromNativeTypes(Z, member_types);
338+
const auto& struct_type = NativeStructType::FromNativeTypes(Z, member_types);
296339

297340
auto& arguments = *new (Z) NativeTypes(Z, 15);
298341
arguments.Add(&float_type);
@@ -342,20 +385,19 @@ UNIT_TEST_CASE_WITH_ZONE(NativeCallingConvention_struct16bytesMixedx10_3) {
342385
half_float_member_types.Add(&int32_type);
343386
half_float_member_types.Add(&float_type);
344387
const auto& half_float_type =
345-
NativeCompoundType::FromNativeTypes(Z, half_float_member_types);
388+
NativeStructType::FromNativeTypes(Z, half_float_member_types);
346389

347390
const auto& float_array_type = *new (Z) NativeArrayType(float_type, 1);
348391
auto& full_float_member_types = *new (Z) NativeTypes(Z, 1);
349392
full_float_member_types.Add(&float_array_type);
350393
const auto& full_float_type =
351-
NativeCompoundType::FromNativeTypes(Z, full_float_member_types);
394+
NativeStructType::FromNativeTypes(Z, full_float_member_types);
352395

353396
auto& member_types = *new (Z) NativeTypes(Z, 3);
354397
member_types.Add(&int32_type);
355398
member_types.Add(&half_float_type);
356399
member_types.Add(&full_float_type);
357-
const auto& struct_type =
358-
NativeCompoundType::FromNativeTypes(Z, member_types);
400+
const auto& struct_type = NativeStructType::FromNativeTypes(Z, member_types);
359401

360402
auto& arguments = *new (Z) NativeTypes(Z, 11);
361403
arguments.Add(&struct_type);
@@ -389,8 +431,7 @@ UNIT_TEST_CASE_WITH_ZONE(NativeCallingConvention_struct8bytesx1) {
389431
member_types.Add(&int8type);
390432
member_types.Add(&int8type);
391433
member_types.Add(&int8type);
392-
const auto& struct_type =
393-
NativeCompoundType::FromNativeTypes(Z, member_types);
434+
const auto& struct_type = NativeStructType::FromNativeTypes(Z, member_types);
394435

395436
auto& arguments = *new (Z) NativeTypes(Z, 1);
396437
arguments.Add(&struct_type);
@@ -418,7 +459,7 @@ UNIT_TEST_CASE_WITH_ZONE(NativeCallingConvention_struct8bytesPackedx10) {
418459
member_types.Add(&int8_type);
419460
member_types.Add(&int8_type);
420461
const auto& struct_type =
421-
NativeCompoundType::FromNativeTypes(Z, member_types, /*packing=*/1);
462+
NativeStructType::FromNativeTypes(Z, member_types, /*packing=*/1);
422463
EXPECT_EQ(8, struct_type.SizeInBytes());
423464
EXPECT(struct_type.ContainsUnalignedMembers());
424465

@@ -456,7 +497,7 @@ UNIT_TEST_CASE_WITH_ZONE(NativeCallingConvention_structPacked) {
456497
member_types.Add(&int8_type);
457498
member_types.Add(&double_type);
458499
const auto& struct_type =
459-
NativeCompoundType::FromNativeTypes(Z, member_types, /*packing=*/1);
500+
NativeStructType::FromNativeTypes(Z, member_types, /*packing=*/1);
460501
EXPECT_EQ(9, struct_type.SizeInBytes());
461502
EXPECT(struct_type.ContainsUnalignedMembers());
462503

@@ -469,6 +510,51 @@ UNIT_TEST_CASE_WITH_ZONE(NativeCallingConvention_structPacked) {
469510
RunSignatureTest(Z, "structPacked", arguments, struct_type);
470511
}
471512

513+
// The union is only 5 bytes because it's members are packed.
514+
//
515+
// Many calling conventions pass this struct in single registers or less
516+
// stack slots because of this.
517+
//
518+
// Non-windows x64 passes this struct on the stack instead of in a single
519+
// CPU register, because it contains a mis-aligned member.
520+
//
521+
// See the *.expect in ./unit_tests for this behavior.
522+
UNIT_TEST_CASE_WITH_ZONE(NativeCallingConvention_union5bytesPackedx10) {
523+
const auto& uint8_type = *new (Z) NativePrimitiveType(kUint8);
524+
const auto& uint32_type = *new (Z) NativePrimitiveType(kUint32);
525+
526+
auto& inner_members = *new (Z) NativeTypes(Z, 2);
527+
inner_members.Add(&uint8_type);
528+
inner_members.Add(&uint32_type);
529+
const intptr_t packing = 1;
530+
const auto& struct_type =
531+
NativeStructType::FromNativeTypes(Z, inner_members, packing);
532+
533+
const auto& array_type = *new (Z) NativeArrayType(uint8_type, 5);
534+
535+
auto& member_types = *new (Z) NativeTypes(Z, 2);
536+
member_types.Add(&array_type);
537+
member_types.Add(&struct_type);
538+
const auto& union_type = NativeUnionType::FromNativeTypes(Z, member_types);
539+
540+
EXPECT_EQ(5, union_type.SizeInBytes());
541+
EXPECT_EQ(1, union_type.AlignmentInBytesField());
542+
543+
auto& arguments = *new (Z) NativeTypes(Z, 10);
544+
arguments.Add(&union_type);
545+
arguments.Add(&union_type);
546+
arguments.Add(&union_type);
547+
arguments.Add(&union_type);
548+
arguments.Add(&union_type);
549+
arguments.Add(&union_type);
550+
arguments.Add(&union_type);
551+
arguments.Add(&union_type);
552+
arguments.Add(&union_type);
553+
arguments.Add(&union_type);
554+
555+
RunSignatureTest(Z, "union5bytesPackedx10", arguments, union_type);
556+
}
557+
472558
} // namespace ffi
473559
} // namespace compiler
474560
} // namespace dart

0 commit comments

Comments
 (0)