Skip to content

Commit 6d0fa9f

Browse files
committed
Update to recursive check fields, check bases, exclude aarch64_32, more tests.
1 parent 4277570 commit 6d0fa9f

File tree

2 files changed

+55
-45
lines changed

2 files changed

+55
-45
lines changed

clang/lib/CodeGen/Targets/AArch64.cpp

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -488,19 +488,32 @@ ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty, bool IsVariadicFn,
488488
// If the Aggregate is made up of pointers, use an array of pointers for the
489489
// coerced type. This prevents having to convert ptr2int->int2ptr through
490490
// 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-
}
491+
std::function<bool(QualType Ty)> ContainsOnlyPointers = [&](QualType Ty) {
492+
const RecordType *RT = Ty->getAs<RecordType>();
493+
if (!RT)
494+
return false;
495+
const RecordDecl *RD = RT->getDecl();
496+
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
497+
for (const auto &I : CXXRD->bases())
498+
if (!ContainsOnlyPointers(I.getType()))
499+
return false;
503500
}
501+
return all_of(RD->fields(), [&](FieldDecl *FD) {
502+
QualType FDTy = FD->getType();
503+
return FDTy->isPointerOrReferenceType() ||
504+
(FDTy->isArrayType() &&
505+
FDTy->getBaseElementTypeUnsafe()->isPointerOrReferenceType()) ||
506+
ContainsOnlyPointers(FDTy);
507+
});
508+
};
509+
if (getTarget().getTriple().getArch() != llvm::Triple::aarch64_32 &&
510+
ContainsOnlyPointers(Ty)) {
511+
assert((Size == 64 || Size == 128) &&
512+
"Expected a 64 or 128bit struct containing pointers");
513+
llvm::Type *PtrTy = llvm::PointerType::getUnqual(getVMContext());
514+
if (Size == 128)
515+
PtrTy = llvm::ArrayType::get(PtrTy, 2);
516+
return ABIArgInfo::getDirect(PtrTy);
504517
}
505518

506519
// We use a pair of i64 for 16-byte aggregate with 8-byte alignment.

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

Lines changed: 30 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@ struct Sp {
1717
// CHECK-A64-NEXT: ret void
1818
//
1919
// CHECK-A64_32-LABEL: define void @_Z2Tp2Sp(
20-
// CHECK-A64_32-SAME: ptr [[S_COERCE:%.*]]) #[[ATTR0:[0-9]+]] {
20+
// CHECK-A64_32-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0:[0-9]+]] {
2121
// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
2222
// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SP:%.*]], align 4
2323
// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SP]], ptr [[S]], i32 0, i32 0
24-
// CHECK-A64_32-NEXT: store ptr [[S_COERCE]], ptr [[COERCE_DIVE]], align 4
24+
// CHECK-A64_32-NEXT: [[COERCE_VAL_II:%.*]] = trunc i64 [[S_COERCE]] to i32
25+
// CHECK-A64_32-NEXT: store i32 [[COERCE_VAL_II]], ptr [[COERCE_DIVE]], align 4
2526
// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SP]], ptr [[S]], i32 0, i32 0
2627
// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 4
2728
// CHECK-A64_32-NEXT: store i32 1, ptr [[TMP0]], align 4
@@ -43,11 +44,10 @@ struct Spp {
4344
// CHECK-A64-NEXT: ret void
4445
//
4546
// CHECK-A64_32-LABEL: define void @_Z3Tpp3Spp(
46-
// CHECK-A64_32-SAME: ptr [[S_COERCE:%.*]]) #[[ATTR0]] {
47+
// CHECK-A64_32-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] {
4748
// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
4849
// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SPP:%.*]], align 4
49-
// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SPP]], ptr [[S]], i32 0, i32 0
50-
// CHECK-A64_32-NEXT: store ptr [[S_COERCE]], ptr [[COERCE_DIVE]], align 4
50+
// CHECK-A64_32-NEXT: store i64 [[S_COERCE]], ptr [[S]], align 4
5151
// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPP]], ptr [[S]], i32 0, i32 0
5252
// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 4
5353
// CHECK-A64_32-NEXT: store i32 1, ptr [[TMP0]], align 4
@@ -69,10 +69,12 @@ struct Sppp {
6969
// CHECK-A64-NEXT: ret void
7070
//
7171
// CHECK-A64_32-LABEL: define void @_Z4Tppp4Sppp(
72-
// CHECK-A64_32-SAME: [2 x ptr] [[S_COERCE:%.*]]) #[[ATTR0]] {
72+
// CHECK-A64_32-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
7373
// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
7474
// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SPPP:%.*]], align 4
75-
// CHECK-A64_32-NEXT: store [2 x ptr] [[S_COERCE]], ptr [[S]], align 4
75+
// CHECK-A64_32-NEXT: [[TMP_COERCE:%.*]] = alloca [2 x i64], align 8
76+
// CHECK-A64_32-NEXT: store [2 x i64] [[S_COERCE]], ptr [[TMP_COERCE]], align 8
77+
// CHECK-A64_32-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[S]], ptr align 8 [[TMP_COERCE]], i32 12, i1 false)
7678
// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPPP]], ptr [[S]], i32 0, i32 0
7779
// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 4
7880
// CHECK-A64_32-NEXT: store i32 1, ptr [[TMP0]], align 4
@@ -119,11 +121,10 @@ struct Srp {
119121
// CHECK-A64-NEXT: ret void
120122
//
121123
// CHECK-A64_32-LABEL: define void @_Z3Trp3Srp(
122-
// CHECK-A64_32-SAME: ptr [[S_COERCE:%.*]]) #[[ATTR0]] {
124+
// CHECK-A64_32-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] {
123125
// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
124126
// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SRP:%.*]], align 4
125-
// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SRP]], ptr [[S]], i32 0, i32 0
126-
// CHECK-A64_32-NEXT: store ptr [[S_COERCE]], ptr [[COERCE_DIVE]], align 4
127+
// CHECK-A64_32-NEXT: store i64 [[S_COERCE]], ptr [[S]], align 4
127128
// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SRP]], ptr [[S]], i32 0, i32 0
128129
// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 4
129130
// CHECK-A64_32-NEXT: store i32 1, ptr [[TMP0]], align 4
@@ -145,11 +146,10 @@ struct __attribute__((__packed__)) Spp_packed {
145146
// CHECK-A64-NEXT: ret void
146147
//
147148
// CHECK-A64_32-LABEL: define void @_Z10Tpp_packed10Spp_packed(
148-
// CHECK-A64_32-SAME: ptr [[S_COERCE:%.*]]) #[[ATTR0]] {
149+
// CHECK-A64_32-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] {
149150
// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
150151
// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SPP_PACKED:%.*]], align 1
151-
// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SPP_PACKED]], ptr [[S]], i32 0, i32 0
152-
// CHECK-A64_32-NEXT: store ptr [[S_COERCE]], ptr [[COERCE_DIVE]], align 1
152+
// CHECK-A64_32-NEXT: store i64 [[S_COERCE]], ptr [[S]], align 1
153153
// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SPP_PACKED]], ptr [[S]], i32 0, i32 0
154154
// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 1
155155
// CHECK-A64_32-NEXT: store i32 1, ptr [[TMP0]], align 4
@@ -172,11 +172,12 @@ union Upp {
172172
// CHECK-A64-NEXT: ret void
173173
//
174174
// CHECK-A64_32-LABEL: define void @_Z11Tupp_packed3Upp(
175-
// CHECK-A64_32-SAME: ptr [[S_COERCE:%.*]]) #[[ATTR0]] {
175+
// CHECK-A64_32-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] {
176176
// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
177177
// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[UNION_UPP:%.*]], align 4
178178
// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[UNION_UPP]], ptr [[S]], i32 0, i32 0
179-
// CHECK-A64_32-NEXT: store ptr [[S_COERCE]], ptr [[COERCE_DIVE]], align 4
179+
// CHECK-A64_32-NEXT: [[COERCE_VAL_II:%.*]] = trunc i64 [[S_COERCE]] to i32
180+
// CHECK-A64_32-NEXT: store i32 [[COERCE_VAL_II]], ptr [[COERCE_DIVE]], align 4
180181
// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S]], align 4
181182
// CHECK-A64_32-NEXT: store i32 1, ptr [[TMP0]], align 4
182183
// CHECK-A64_32-NEXT: ret void
@@ -271,10 +272,10 @@ struct SSpSp {
271272
struct Sp a, b;
272273
};
273274
// CHECK-A64-LABEL: define dso_local void @_Z5TSpSp5SSpSp(
274-
// CHECK-A64-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
275+
// CHECK-A64-SAME: [2 x ptr] [[S_COERCE:%.*]]) #[[ATTR0]] {
275276
// CHECK-A64-NEXT: [[ENTRY:.*:]]
276277
// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SSPSP:%.*]], align 8
277-
// CHECK-A64-NEXT: store [2 x i64] [[S_COERCE]], ptr [[S]], align 8
278+
// CHECK-A64-NEXT: store [2 x ptr] [[S_COERCE]], ptr [[S]], align 8
278279
// CHECK-A64-NEXT: [[A:%.*]] = getelementptr inbounds nuw [[STRUCT_SSPSP]], ptr [[S]], i32 0, i32 0
279280
// CHECK-A64-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SP:%.*]], ptr [[A]], i32 0, i32 0
280281
// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 8
@@ -308,13 +309,11 @@ struct SSp : public Sp {
308309
// CHECK-A64-NEXT: ret void
309310
//
310311
// CHECK-A64_32-LABEL: define void @_Z3TSp3SSp(
311-
// CHECK-A64_32-SAME: ptr [[S_COERCE:%.*]]) #[[ATTR0]] {
312+
// CHECK-A64_32-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] {
312313
// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
313314
// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SSP:%.*]], align 4
314-
// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SSP]], ptr [[S]], i32 0, i32 0
315-
// CHECK-A64_32-NEXT: [[COERCE_DIVE1:%.*]] = getelementptr inbounds nuw [[STRUCT_SP:%.*]], ptr [[COERCE_DIVE]], i32 0, i32 0
316-
// CHECK-A64_32-NEXT: store ptr [[S_COERCE]], ptr [[COERCE_DIVE1]], align 4
317-
// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SP]], ptr [[S]], i32 0, i32 0
315+
// CHECK-A64_32-NEXT: store i64 [[S_COERCE]], ptr [[S]], align 4
316+
// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SP:%.*]], ptr [[S]], i32 0, i32 0
318317
// CHECK-A64_32-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X]], align 4
319318
// CHECK-A64_32-NEXT: store i32 1, ptr [[TMP0]], align 4
320319
// CHECK-A64_32-NEXT: ret void
@@ -328,22 +327,20 @@ struct SSpi : public Si {
328327
int* y;
329328
};
330329
// CHECK-A64-LABEL: define dso_local void @_Z4TSpi4SSpi(
331-
// CHECK-A64-SAME: [2 x ptr] [[S_COERCE:%.*]]) #[[ATTR0]] {
330+
// CHECK-A64-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
332331
// CHECK-A64-NEXT: [[ENTRY:.*:]]
333332
// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SSPI:%.*]], align 8
334-
// CHECK-A64-NEXT: store [2 x ptr] [[S_COERCE]], ptr [[S]], align 8
333+
// CHECK-A64-NEXT: store [2 x i64] [[S_COERCE]], ptr [[S]], align 8
335334
// CHECK-A64-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SI:%.*]], ptr [[S]], i32 0, i32 0
336335
// CHECK-A64-NEXT: store i32 1, ptr [[X]], align 8
337336
// CHECK-A64-NEXT: ret void
338337
//
339338
// CHECK-A64_32-LABEL: define void @_Z4TSpi4SSpi(
340-
// CHECK-A64_32-SAME: ptr [[S_COERCE:%.*]]) #[[ATTR0]] {
339+
// CHECK-A64_32-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] {
341340
// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
342341
// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SSPI:%.*]], align 4
343-
// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SSPI]], ptr [[S]], i32 0, i32 0
344-
// CHECK-A64_32-NEXT: [[COERCE_DIVE1:%.*]] = getelementptr inbounds nuw [[STRUCT_SI:%.*]], ptr [[COERCE_DIVE]], i32 0, i32 0
345-
// CHECK-A64_32-NEXT: store ptr [[S_COERCE]], ptr [[COERCE_DIVE1]], align 4
346-
// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SI]], ptr [[S]], i32 0, i32 0
342+
// CHECK-A64_32-NEXT: store i64 [[S_COERCE]], ptr [[S]], align 4
343+
// CHECK-A64_32-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_SI:%.*]], ptr [[S]], i32 0, i32 0
347344
// CHECK-A64_32-NEXT: store i32 1, ptr [[X]], align 4
348345
// CHECK-A64_32-NEXT: ret void
349346
//
@@ -353,11 +350,11 @@ struct Spa {
353350
int* xs[1];
354351
};
355352
// CHECK-A64-LABEL: define dso_local void @_Z3Tpa3Spa(
356-
// CHECK-A64-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] {
353+
// CHECK-A64-SAME: ptr [[S_COERCE:%.*]]) #[[ATTR0]] {
357354
// CHECK-A64-NEXT: [[ENTRY:.*:]]
358355
// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SPA:%.*]], align 8
359356
// CHECK-A64-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SPA]], ptr [[S]], i32 0, i32 0
360-
// CHECK-A64-NEXT: store i64 [[S_COERCE]], ptr [[COERCE_DIVE]], align 8
357+
// CHECK-A64-NEXT: store ptr [[S_COERCE]], ptr [[COERCE_DIVE]], align 8
361358
// CHECK-A64-NEXT: [[XS:%.*]] = getelementptr inbounds nuw [[STRUCT_SPA]], ptr [[S]], i32 0, i32 0
362359
// CHECK-A64-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [1 x ptr], ptr [[XS]], i64 0, i64 0
363360
// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARRAYIDX]], align 8
@@ -383,11 +380,11 @@ struct Spa2 {
383380
int* xs[2];
384381
};
385382
// CHECK-A64-LABEL: define dso_local void @_Z4Tpa24Spa2(
386-
// CHECK-A64-SAME: [2 x i64] [[S_COERCE:%.*]]) #[[ATTR0]] {
383+
// CHECK-A64-SAME: [2 x ptr] [[S_COERCE:%.*]]) #[[ATTR0]] {
387384
// CHECK-A64-NEXT: [[ENTRY:.*:]]
388385
// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SPA2:%.*]], align 8
389386
// CHECK-A64-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SPA2]], ptr [[S]], i32 0, i32 0
390-
// CHECK-A64-NEXT: store [2 x i64] [[S_COERCE]], ptr [[COERCE_DIVE]], align 8
387+
// CHECK-A64-NEXT: store [2 x ptr] [[S_COERCE]], ptr [[COERCE_DIVE]], align 8
391388
// CHECK-A64-NEXT: [[XS:%.*]] = getelementptr inbounds nuw [[STRUCT_SPA2]], ptr [[S]], i32 0, i32 0
392389
// CHECK-A64-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x ptr], ptr [[XS]], i64 0, i64 0
393390
// CHECK-A64-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARRAYIDX]], align 8

0 commit comments

Comments
 (0)