Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 84e87d5

Browse filesBrowse 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
Copy full SHA for 84e87d5

File tree

Expand file treeCollapse file tree

4 files changed

+61
-33
lines changed
Filter options
Expand file treeCollapse file tree

4 files changed

+61
-33
lines changed

‎clang/lib/CodeGen/Targets/AArch64.cpp

Copy file name to clipboardExpand all lines: clang/lib/CodeGen/Targets/AArch64.cpp
+33Lines 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

Copy file name to clipboardExpand all lines: clang/test/CodeGen/AArch64/struct-coerce-using-ptr.cpp
+22-24Lines 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

Copy file name to clipboardExpand all lines: clang/test/CodeGenCXX/ptrauth-qualifier-struct.cpp
+1-1Lines 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

Copy file name to clipboardExpand all lines: clang/test/CodeGenCXX/trivial_abi.cpp
+5-8Lines 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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.