Skip to content

Commit c116767

Browse files
committed
[AArch64] Change the coercion type of structs with pointer members.
The aim here is to avoid a ptrtoint->inttoptr round-trip throught the function argument whilst keeping the calling convention the same. Given a struct which is <= 128bits in size, which can only contain either 1 or 2 pointers, we convert to a ptr or [2 x ptr] as opposed to the old coercion that uses i64 or [2 x i64].
1 parent 6825a7d commit c116767

File tree

3 files changed

+31
-17
lines changed

3 files changed

+31
-17
lines changed

clang/lib/CodeGen/Targets/AArch64.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,24 @@ ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty, bool IsVariadicFn,
485485
}
486486
Size = llvm::alignTo(Size, Alignment);
487487

488+
// If the Aggregate is made up of pointers, use an array of pointers for the
489+
// coerced type. This prevents having to convert ptr2int->int2ptr through
490+
// the call, allowing alias analysis to produce better code.
491+
if (const RecordType *RT = Ty->getAs<RecordType>()) {
492+
if (const RecordDecl *RD = RT->getDecl()) {
493+
if (all_of(RD->fields(), [](FieldDecl *FD) {
494+
return FD->getType()->isPointerOrReferenceType();
495+
})) {
496+
assert((Size == 64 || Size == 128) &&
497+
"Expected a 64 or 128bit struct containing pointers");
498+
llvm::Type *PtrTy = llvm::PointerType::getUnqual(getVMContext());
499+
if (Size == 128)
500+
PtrTy = llvm::ArrayType::get(PtrTy, 2);
501+
return ABIArgInfo::getDirect(PtrTy);
502+
}
503+
}
504+
}
505+
488506
// We use a pair of i64 for 16-byte aggregate with 8-byte alignment.
489507
// For aggregates with 16-byte alignment, we use i128.
490508
llvm::Type *BaseTy = llvm::Type::getIntNTy(getVMContext(), Alignment);

clang/test/CodeGen/AArch64/struct-coerce-using-ptr.cpp

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@ struct Sp {
55
int *x;
66
};
77
// CHECK-LABEL: define dso_local void @_Z2Tp2Sp(
8-
// CHECK-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0:[0-9]+]] {
8+
// CHECK-SAME: ptr [[S_COERCE:%.*]]) #[[ATTR0:[0-9]+]] {
99
// CHECK-NEXT: [[ENTRY:.*:]]
1010
// CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_SP:%.*]], align 8
1111
// CHECK-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SP]], ptr [[S]], i32 0, i32 0
12-
// CHECK-NEXT: [[COERCE_VAL_IP:%.*]] = inttoptr i64 [[S_COERCE]] to ptr
13-
// CHECK-NEXT: store ptr [[COERCE_VAL_IP]], ptr [[COERCE_DIVE]], align 8
12+
// CHECK-NEXT: store ptr [[S_COERCE]], ptr [[COERCE_DIVE]], align 8
1413
// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SP]], ptr [[S]], i32 0, i32 0
1514
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
1615
// CHECK-NEXT: store i32 1, ptr [[TMP0]], align 4
@@ -22,10 +21,10 @@ struct Spp {
2221
int *x, *y;
2322
};
2423
// CHECK-LABEL: define dso_local void @_Z3Tpp3Spp(
25-
// CHECK-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
24+
// CHECK-SAME: [2 x ptr] [[S_COERCE:%.*]]) #[[ATTR0]] {
2625
// CHECK-NEXT: [[ENTRY:.*:]]
2726
// CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_SPP:%.*]], align 8
28-
// CHECK-NEXT: store [2 x i64] [[S_COERCE]], ptr [[S]], align 8
27+
// CHECK-NEXT: store [2 x ptr] [[S_COERCE]], ptr [[S]], align 8
2928
// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPP]], ptr [[S]], i32 0, i32 0
3029
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
3130
// CHECK-NEXT: store i32 1, ptr [[TMP0]], align 4
@@ -67,10 +66,10 @@ struct Srp {
6766
int &x, *y;
6867
};
6968
// CHECK-LABEL: define dso_local void @_Z3Trp3Srp(
70-
// CHECK-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
69+
// CHECK-SAME: [2 x ptr] [[S_COERCE:%.*]]) #[[ATTR0]] {
7170
// CHECK-NEXT: [[ENTRY:.*:]]
7271
// CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_SRP:%.*]], align 8
73-
// CHECK-NEXT: store [2 x i64] [[S_COERCE]], ptr [[S]], align 8
72+
// CHECK-NEXT: store [2 x ptr] [[S_COERCE]], ptr [[S]], align 8
7473
// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SRP]], ptr [[S]], i32 0, i32 0
7574
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
7675
// CHECK-NEXT: store i32 1, ptr [[TMP0]], align 4
@@ -82,10 +81,10 @@ struct __attribute__((__packed__)) Spp_packed {
8281
int *x, *y;
8382
};
8483
// CHECK-LABEL: define dso_local void @_Z10Tpp_packed10Spp_packed(
85-
// CHECK-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
84+
// CHECK-SAME: [2 x ptr] [[S_COERCE:%.*]]) #[[ATTR0]] {
8685
// CHECK-NEXT: [[ENTRY:.*:]]
8786
// CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_SPP_PACKED:%.*]], align 1
88-
// CHECK-NEXT: store [2 x i64] [[S_COERCE]], ptr [[S]], align 1
87+
// CHECK-NEXT: store [2 x ptr] [[S_COERCE]], ptr [[S]], align 1
8988
// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPP_PACKED]], ptr [[S]], i32 0, i32 0
9089
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 1
9190
// CHECK-NEXT: store i32 1, ptr [[TMP0]], align 4

clang/test/CodeGenCXX/trivial_abi.cpp

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,10 @@ struct D0 : B0, B1 {
6868

6969
Small D0::m0() { return {}; }
7070

71-
// CHECK: define{{.*}} void @_Z14testParamSmall5Small(i64 %[[A_COERCE:.*]])
71+
// CHECK: define{{.*}} void @_Z14testParamSmall5Small(ptr %[[A_COERCE:.*]])
7272
// CHECK: %[[A:.*]] = alloca %[[STRUCT_SMALL]], align 8
7373
// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds nuw %[[STRUCT_SMALL]], ptr %[[A]], i32 0, i32 0
74-
// CHECK: %[[COERCE_VAL_IP:.*]] = inttoptr i64 %[[A_COERCE]] to ptr
75-
// CHECK: store ptr %[[COERCE_VAL_IP]], ptr %[[COERCE_DIVE]], align 8
74+
// CHECK: store ptr %[[A_COERCE]], ptr %[[COERCE_DIVE]], align 8
7675
// CHECK: %[[CALL:.*]] = call noundef ptr @_ZN5SmallD1Ev(ptr {{[^,]*}} %[[A]])
7776
// CHECK: ret void
7877
// CHECK: }
@@ -101,8 +100,7 @@ Small testReturnSmall() {
101100
// CHECK: %[[CALL1:.*]] = call noundef ptr @_ZN5SmallC1ERKS_(ptr {{[^,]*}} %[[AGG_TMP]], ptr noundef nonnull align 8 dereferenceable(8) %[[T]])
102101
// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds nuw %[[STRUCT_SMALL]], ptr %[[AGG_TMP]], i32 0, i32 0
103102
// CHECK: %[[V0:.*]] = load ptr, ptr %[[COERCE_DIVE]], align 8
104-
// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint ptr %[[V0]] to i64
105-
// CHECK: call void @_Z14testParamSmall5Small(i64 %[[COERCE_VAL_PI]])
103+
// CHECK: call void @_Z14testParamSmall5Small(ptr %[[V0]])
106104
// CHECK: %[[CALL2:.*]] = call noundef ptr @_ZN5SmallD1Ev(ptr {{[^,]*}} %[[T]])
107105
// CHECK: ret void
108106
// CHECK: }
@@ -120,8 +118,7 @@ void testCallSmall0() {
120118
// CHECK: store ptr %[[COERCE_VAL_IP]], ptr %[[COERCE_DIVE]], align 8
121119
// CHECK: %[[COERCE_DIVE1:.*]] = getelementptr inbounds nuw %[[STRUCT_SMALL]], ptr %[[AGG_TMP]], i32 0, i32 0
122120
// CHECK: %[[V0:.*]] = load ptr, ptr %[[COERCE_DIVE1]], align 8
123-
// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint ptr %[[V0]] to i64
124-
// CHECK: call void @_Z14testParamSmall5Small(i64 %[[COERCE_VAL_PI]])
121+
// CHECK: call void @_Z14testParamSmall5Small(ptr %[[V0]])
125122
// CHECK: ret void
126123
// CHECK: }
127124

@@ -226,7 +223,7 @@ NonTrivial testReturnHasNonTrivial() {
226223
// CHECK: call noundef ptr @_ZN5SmallC1Ev(ptr {{[^,]*}} %[[AGG_TMP]])
227224
// CHECK: invoke noundef ptr @_ZN5SmallC1Ev(ptr {{[^,]*}} %[[AGG_TMP1]])
228225

229-
// CHECK: call void @_Z20calleeExceptionSmall5SmallS_(i64 %{{.*}}, i64 %{{.*}})
226+
// CHECK: call void @_Z20calleeExceptionSmall5SmallS_(ptr %{{.*}}, ptr %{{.*}})
230227
// CHECK-NEXT: ret void
231228

232229
// CHECK: landingpad { ptr, i32 }

0 commit comments

Comments
 (0)