Skip to content

Commit 84e87d5

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 8655b5a commit 84e87d5

File tree

4 files changed

+61
-33
lines changed

4 files changed

+61
-33
lines changed

clang/lib/CodeGen/Targets/AArch64.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,39 @@ 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+
std::function<bool(QualType Ty)> ContainsOnlyPointers = [&](QualType Ty) {
492+
if (isEmptyRecord(getContext(), Ty, true))
493+
return false;
494+
const RecordType *RT = Ty->getAs<RecordType>();
495+
if (!RT)
496+
return false;
497+
const RecordDecl *RD = RT->getDecl();
498+
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
499+
for (const auto &I : CXXRD->bases())
500+
if (!ContainsOnlyPointers(I.getType()))
501+
return false;
502+
}
503+
return all_of(RD->fields(), [&](FieldDecl *FD) {
504+
QualType FDTy = FD->getType();
505+
if (FDTy->isArrayType())
506+
FDTy = getContext().getBaseElementType(FDTy);
507+
return (FDTy->isPointerOrReferenceType() &&
508+
getContext().getTypeSize(FDTy) == 64) ||
509+
ContainsOnlyPointers(FDTy);
510+
});
511+
};
512+
if (Alignment <= 64 && ContainsOnlyPointers(Ty)) {
513+
assert((Size == 64 || Size == 128) &&
514+
"Expected a 64 or 128bit struct containing pointers");
515+
llvm::Type *PtrTy = llvm::PointerType::getUnqual(getVMContext());
516+
if (Size == 128)
517+
PtrTy = llvm::ArrayType::get(PtrTy, 2);
518+
return ABIArgInfo::getDirect(PtrTy);
519+
}
520+
488521
// We use a pair of i64 for 16-byte aggregate with 8-byte alignment.
489522
// For aggregates with 16-byte alignment, we use i128.
490523
llvm::Type *BaseTy = llvm::Type::getIntNTy(getVMContext(), Alignment);

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

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,11 @@ struct Sp {
2929
int *x;
3030
};
3131
// CHECK-A64-LABEL: define dso_local void @_Z2Tp2Sp(
32-
// CHECK-A64-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] {
32+
// CHECK-A64-SAME: ptr [[S_COERCE:%.*]]) #[[ATTR0]] {
3333
// CHECK-A64-NEXT: [[ENTRY:.*:]]
3434
// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SP:%.*]], align 8
3535
// CHECK-A64-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SP]], ptr [[S]], i32 0, i32 0
36-
// CHECK-A64-NEXT: [[COERCE_VAL_IP:%.*]] = inttoptr i64 [[S_COERCE]] to ptr
37-
// CHECK-A64-NEXT: store ptr [[COERCE_VAL_IP]], ptr [[COERCE_DIVE]], align 8
36+
// CHECK-A64-NEXT: store ptr [[S_COERCE]], ptr [[COERCE_DIVE]], align 8
3837
// CHECK-A64-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SP]], ptr [[S]], i32 0, i32 0
3938
// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
4039
// CHECK-A64-NEXT: store i32 1, ptr [[TMP0]], align 4
@@ -58,10 +57,10 @@ struct Spp {
5857
int *x, *y;
5958
};
6059
// CHECK-A64-LABEL: define dso_local void @_Z3Tpp3Spp(
61-
// CHECK-A64-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
60+
// CHECK-A64-SAME: [2 x ptr] [[S_COERCE:%.*]]) #[[ATTR0]] {
6261
// CHECK-A64-NEXT: [[ENTRY:.*:]]
6362
// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SPP:%.*]], align 8
64-
// CHECK-A64-NEXT: store [2 x i64] [[S_COERCE]], ptr [[S]], align 8
63+
// CHECK-A64-NEXT: store [2 x ptr] [[S_COERCE]], ptr [[S]], align 8
6564
// CHECK-A64-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPP]], ptr [[S]], i32 0, i32 0
6665
// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
6766
// CHECK-A64-NEXT: store i32 1, ptr [[TMP0]], align 4
@@ -135,10 +134,10 @@ struct Srp {
135134
int &x, *y;
136135
};
137136
// CHECK-A64-LABEL: define dso_local void @_Z3Trp3Srp(
138-
// CHECK-A64-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
137+
// CHECK-A64-SAME: [2 x ptr] [[S_COERCE:%.*]]) #[[ATTR0]] {
139138
// CHECK-A64-NEXT: [[ENTRY:.*:]]
140139
// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SRP:%.*]], align 8
141-
// CHECK-A64-NEXT: store [2 x i64] [[S_COERCE]], ptr [[S]], align 8
140+
// CHECK-A64-NEXT: store [2 x ptr] [[S_COERCE]], ptr [[S]], align 8
142141
// CHECK-A64-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SRP]], ptr [[S]], i32 0, i32 0
143142
// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
144143
// CHECK-A64-NEXT: store i32 1, ptr [[TMP0]], align 4
@@ -160,10 +159,10 @@ struct __attribute__((__packed__)) Spp_packed {
160159
int *x, *y;
161160
};
162161
// CHECK-A64-LABEL: define dso_local void @_Z10Tpp_packed10Spp_packed(
163-
// CHECK-A64-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
162+
// CHECK-A64-SAME: [2 x ptr] [[S_COERCE:%.*]]) #[[ATTR0]] {
164163
// CHECK-A64-NEXT: [[ENTRY:.*:]]
165164
// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SPP_PACKED:%.*]], align 1
166-
// CHECK-A64-NEXT: store [2 x i64] [[S_COERCE]], ptr [[S]], align 1
165+
// CHECK-A64-NEXT: store [2 x ptr] [[S_COERCE]], ptr [[S]], align 1
167166
// CHECK-A64-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPP_PACKED]], ptr [[S]], i32 0, i32 0
168167
// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 1
169168
// CHECK-A64-NEXT: store i32 1, ptr [[TMP0]], align 4
@@ -186,12 +185,11 @@ union Upp {
186185
long long *y;
187186
};
188187
// CHECK-A64-LABEL: define dso_local void @_Z11Tupp_packed3Upp(
189-
// CHECK-A64-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] {
188+
// CHECK-A64-SAME: ptr [[S_COERCE:%.*]]) #[[ATTR0]] {
190189
// CHECK-A64-NEXT: [[ENTRY:.*:]]
191190
// CHECK-A64-NEXT: [[S:%.*]] = alloca [[UNION_UPP:%.*]], align 8
192191
// CHECK-A64-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[UNION_UPP]], ptr [[S]], i32 0, i32 0
193-
// CHECK-A64-NEXT: [[COERCE_VAL_IP:%.*]] = inttoptr i64 [[S_COERCE]] to ptr
194-
// CHECK-A64-NEXT: store ptr [[COERCE_VAL_IP]], ptr [[COERCE_DIVE]], align 8
192+
// CHECK-A64-NEXT: store ptr [[S_COERCE]], ptr [[COERCE_DIVE]], align 8
195193
// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S]], align 8
196194
// CHECK-A64-NEXT: store i32 1, ptr [[TMP0]], align 4
197195
// CHECK-A64-NEXT: ret void
@@ -297,10 +295,10 @@ struct SSpSp {
297295
struct Sp a, b;
298296
};
299297
// CHECK-A64-LABEL: define dso_local void @_Z5TSpSp5SSpSp(
300-
// CHECK-A64-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
298+
// CHECK-A64-SAME: [2 x ptr] [[S_COERCE:%.*]]) #[[ATTR0]] {
301299
// CHECK-A64-NEXT: [[ENTRY:.*:]]
302300
// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SSPSP:%.*]], align 8
303-
// CHECK-A64-NEXT: store [2 x i64] [[S_COERCE]], ptr [[S]], align 8
301+
// CHECK-A64-NEXT: store [2 x ptr] [[S_COERCE]], ptr [[S]], align 8
304302
// CHECK-A64-NEXT: [[A:%.*]] = getelementptr inbounds nuw [[STRUCT_SSPSP]], ptr [[S]], i32 0, i32 0
305303
// CHECK-A64-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SP:%.*]], ptr [[A]], i32 0, i32 0
306304
// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
@@ -324,11 +322,11 @@ struct SSpp {
324322
Spp a;
325323
};
326324
// CHECK-A64-LABEL: define dso_local void @_Z4TSpp4SSpp(
327-
// CHECK-A64-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
325+
// CHECK-A64-SAME: [2 x ptr] [[S_COERCE:%.*]]) #[[ATTR0]] {
328326
// CHECK-A64-NEXT: [[ENTRY:.*:]]
329327
// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SSPP:%.*]], align 8
330328
// CHECK-A64-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SSPP]], ptr [[S]], i32 0, i32 0
331-
// CHECK-A64-NEXT: store [2 x i64] [[S_COERCE]], ptr [[COERCE_DIVE]], align 8
329+
// CHECK-A64-NEXT: store [2 x ptr] [[S_COERCE]], ptr [[COERCE_DIVE]], align 8
332330
// CHECK-A64-NEXT: [[A:%.*]] = getelementptr inbounds nuw [[STRUCT_SSPP]], ptr [[S]], i32 0, i32 0
333331
// CHECK-A64-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPP:%.*]], ptr [[A]], i32 0, i32 0
334332
// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
@@ -353,10 +351,10 @@ struct SSp : public Sp {
353351
int* b;
354352
};
355353
// CHECK-A64-LABEL: define dso_local void @_Z3TSp3SSp(
356-
// CHECK-A64-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
354+
// CHECK-A64-SAME: [2 x ptr] [[S_COERCE:%.*]]) #[[ATTR0]] {
357355
// CHECK-A64-NEXT: [[ENTRY:.*:]]
358356
// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SSP:%.*]], align 8
359-
// CHECK-A64-NEXT: store [2 x i64] [[S_COERCE]], ptr [[S]], align 8
357+
// CHECK-A64-NEXT: store [2 x ptr] [[S_COERCE]], ptr [[S]], align 8
360358
// CHECK-A64-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SP:%.*]], ptr [[S]], i32 0, i32 0
361359
// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
362360
// CHECK-A64-NEXT: store i32 1, ptr [[TMP0]], align 4
@@ -404,11 +402,11 @@ struct Spa {
404402
int* xs[1];
405403
};
406404
// CHECK-A64-LABEL: define dso_local void @_Z3Tpa3Spa(
407-
// CHECK-A64-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] {
405+
// CHECK-A64-SAME: ptr [[S_COERCE:%.*]]) #[[ATTR0]] {
408406
// CHECK-A64-NEXT: [[ENTRY:.*:]]
409407
// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SPA:%.*]], align 8
410408
// CHECK-A64-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SPA]], ptr [[S]], i32 0, i32 0
411-
// CHECK-A64-NEXT: store i64 [[S_COERCE]], ptr [[COERCE_DIVE]], align 8
409+
// CHECK-A64-NEXT: store ptr [[S_COERCE]], ptr [[COERCE_DIVE]], align 8
412410
// CHECK-A64-NEXT: [[XS:%.*]] = getelementptr inbounds nuw [[STRUCT_SPA]], ptr [[S]], i32 0, i32 0
413411
// CHECK-A64-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [1 x ptr], ptr [[XS]], i64 0, i64 0
414412
// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARRAYIDX]], align 8
@@ -434,11 +432,11 @@ struct Spa2 {
434432
int* xs[2];
435433
};
436434
// CHECK-A64-LABEL: define dso_local void @_Z4Tpa24Spa2(
437-
// CHECK-A64-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
435+
// CHECK-A64-SAME: [2 x ptr] [[S_COERCE:%.*]]) #[[ATTR0]] {
438436
// CHECK-A64-NEXT: [[ENTRY:.*:]]
439437
// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SPA2:%.*]], align 8
440438
// CHECK-A64-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SPA2]], ptr [[S]], i32 0, i32 0
441-
// CHECK-A64-NEXT: store [2 x i64] [[S_COERCE]], ptr [[COERCE_DIVE]], align 8
439+
// CHECK-A64-NEXT: store [2 x ptr] [[S_COERCE]], ptr [[COERCE_DIVE]], align 8
442440
// CHECK-A64-NEXT: [[XS:%.*]] = getelementptr inbounds nuw [[STRUCT_SPA2]], ptr [[S]], i32 0, i32 0
443441
// CHECK-A64-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x ptr], ptr [[XS]], i64 0, i64 0
444442
// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARRAYIDX]], align 8
@@ -494,10 +492,10 @@ struct __attribute__((aligned(16))) Spp_align16 {
494492
int *x, *y;
495493
};
496494
// CHECK-A64-LABEL: define dso_local void @_Z11Tpp_align1611Spp_align16(
497-
// CHECK-A64-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
495+
// CHECK-A64-SAME: [2 x ptr] [[S_COERCE:%.*]]) #[[ATTR0]] {
498496
// CHECK-A64-NEXT: [[ENTRY:.*:]]
499497
// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SPP_ALIGN16:%.*]], align 16
500-
// CHECK-A64-NEXT: store [2 x i64] [[S_COERCE]], ptr [[S]], align 16
498+
// CHECK-A64-NEXT: store [2 x ptr] [[S_COERCE]], ptr [[S]], align 16
501499
// CHECK-A64-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPP_ALIGN16]], ptr [[S]], i32 0, i32 0
502500
// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 16
503501
// CHECK-A64-NEXT: store i32 1, ptr [[TMP0]], align 4

clang/test/CodeGenCXX/ptrauth-qualifier-struct.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ void testMoveAssignment(SA a) {
9999
t = static_cast<SA &&>(a);
100100
}
101101

102-
// CHECK: define {{.*}}void @_Z19testCopyConstructor2SI(i
102+
// CHECK: define {{.*}}void @_Z19testCopyConstructor2SI(
103103
// CHECK: call void @llvm.memcpy.p0.p0.i64(
104104

105105
void testCopyConstructor(SI a) {

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)