Skip to content

Commit c53b6c1

Browse files
bruteforceboylanza
authored andcommitted
[CIR][AArch64][Lowering] Support fields with structs containing constant arrays or pointers (#1136)
This PR adds support for function arguments with structs that contain constant arrays or pointers for AArch64. For example, ``` typedef struct { int a[42]; } CAT; void pass_cat(CAT a) {} ``` As usual, the main ideas are gotten from the original [CodeGen](https://github.com/llvm/clangir/blob/3aed38cf52e72cb51a907fad9dd53802f6505b81/clang/lib/AST/ASTContext.cpp#L1823), and I have added a couple of tests.
1 parent c302703 commit c53b6c1

File tree

3 files changed

+91
-1
lines changed

3 files changed

+91
-1
lines changed

clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRLowerContext.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@ clang::TypeInfo CIRLowerContext::getTypeInfoImpl(const mlir::Type T) const {
9494
Align = Target->getDoubleAlign();
9595
break;
9696
}
97+
if (mlir::isa<PointerType>(T)) {
98+
Width = Target->getPointerWidth(clang::LangAS::Default);
99+
Align = Target->getPointerAlign(clang::LangAS::Default);
100+
break;
101+
}
97102
cir_cconv_unreachable("Unknown builtin type!");
98103
break;
99104
}
@@ -167,9 +172,28 @@ int64_t CIRLowerContext::toBits(clang::CharUnits CharSize) const {
167172
return CharSize.getQuantity() * getCharWidth();
168173
}
169174

175+
/// Performing the computation in CharUnits
176+
/// instead of in bits prevents overflowing the uint64_t for some large arrays.
177+
clang::TypeInfoChars getConstantArrayInfoInChars(const CIRLowerContext &ctx,
178+
cir::ArrayType arrTy) {
179+
clang::TypeInfoChars eltInfo = ctx.getTypeInfoInChars(arrTy.getEltType());
180+
uint64_t tySize = arrTy.getSize();
181+
assert((tySize == 0 || static_cast<uint64_t>(eltInfo.Width.getQuantity()) <=
182+
(uint64_t)(-1) / tySize) &&
183+
"Overflow in array type char size evaluation");
184+
uint64_t width = eltInfo.Width.getQuantity() * tySize;
185+
unsigned align = eltInfo.Align.getQuantity();
186+
if (!ctx.getTargetInfo().getCXXABI().isMicrosoft() ||
187+
ctx.getTargetInfo().getPointerWidth(clang::LangAS::Default) == 64)
188+
width = llvm::alignTo(width, align);
189+
return clang::TypeInfoChars(clang::CharUnits::fromQuantity(width),
190+
clang::CharUnits::fromQuantity(align),
191+
eltInfo.AlignRequirement);
192+
}
193+
170194
clang::TypeInfoChars CIRLowerContext::getTypeInfoInChars(mlir::Type T) const {
171195
if (auto arrTy = mlir::dyn_cast<ArrayType>(T))
172-
cir_cconv_unreachable("NYI");
196+
return getConstantArrayInfoInChars(*this, arrTy);
173197
clang::TypeInfo Info = getTypeInfo(T);
174198
return clang::TypeInfoChars(toCharUnitsFromBits(Info.Width),
175199
toCharUnitsFromBits(Info.Align),

clang/test/CIR/CallConvLowering/AArch64/aarch64-cc-structs.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,3 +234,20 @@ S_PAD ret_s_pad() {
234234
S_PAD s;
235235
return s;
236236
}
237+
238+
typedef struct {
239+
int a[42];
240+
} CAT;
241+
242+
// CHECK: cir.func @pass_cat(%arg0: !cir.ptr<!ty_CAT>
243+
// CHECK: %[[#V0:]] = cir.alloca !cir.ptr<!ty_CAT>, !cir.ptr<!cir.ptr<!ty_CAT>>, [""] {alignment = 8 : i64}
244+
// CHECK: cir.store %arg0, %[[#V0]] : !cir.ptr<!ty_CAT>, !cir.ptr<!cir.ptr<!ty_CAT>>
245+
// CHECK: %[[#V1:]] = cir.load %[[#V0]] : !cir.ptr<!cir.ptr<!ty_CAT>>, !cir.ptr<!ty_CAT>
246+
// CHECK: cir.return
247+
248+
// LLVM: void @pass_cat(ptr %[[#V0:]])
249+
// LLVM: %[[#V2:]] = alloca ptr, i64 1, align 8
250+
// LLVM: store ptr %[[#V0]], ptr %[[#V2]], align 8
251+
// LLVM: %[[#V3:]] = load ptr, ptr %[[#V2]], align 8
252+
// LLVM: ret void
253+
void pass_cat(CAT a) {}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// RUN: %clang_cc1 -triple aarch64-unknown-linux-gnu -fclangir -fclangir-call-conv-lowering -emit-cir-flat -mmlir --mlir-print-ir-after=cir-call-conv-lowering %s -o %t.cir
2+
// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
3+
// RUN: %clang_cc1 -triple aarch64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll -fclangir-call-conv-lowering
4+
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
5+
6+
typedef int (*myfptr)(int);
7+
8+
typedef struct {
9+
myfptr f;
10+
} A;
11+
12+
int foo(int x) { return x; }
13+
14+
// CIR: cir.func @passA(%arg0: !u64i
15+
// CIR: %[[#V0:]] = cir.alloca !ty_A, !cir.ptr<!ty_A>, [""] {alignment = 4 : i64}
16+
// CIR: %[[#V1:]] = cir.cast(bitcast, %[[#V0]] : !cir.ptr<!ty_A>), !cir.ptr<!u64i>
17+
// CIR: cir.store %arg0, %[[#V1]] : !u64i, !cir.ptr<!u64i>
18+
// CIR: %[[#V2:]] = cir.get_global @foo : !cir.ptr<!cir.func<!s32i (!s32i)>>
19+
// CIR: %[[#V3:]] = cir.get_member %[[#V0]][0] {name = "f"} : !cir.ptr<!ty_A> -> !cir.ptr<!cir.ptr<!cir.func<!s32i (!s32i)>>>
20+
// CIR: cir.store %[[#V2]], %[[#V3]] : !cir.ptr<!cir.func<!s32i (!s32i)>>, !cir.ptr<!cir.ptr<!cir.func<!s32i (!s32i)>>>
21+
// CIR: cir.return
22+
23+
// LLVM: void @passA(i64 %[[#V0:]])
24+
// LLVM: %[[#V2:]] = alloca %struct.A, i64 1, align 4
25+
// LLVM: store i64 %[[#V0]], ptr %[[#V2]], align 8
26+
// LLVM: %[[#V3:]] = getelementptr %struct.A, ptr %[[#V2]], i32 0, i32 0
27+
// LLVM: store ptr @foo, ptr %[[#V3]], align 8
28+
// LLVM: ret void
29+
void passA(A a) { a.f = foo; }
30+
31+
typedef struct {
32+
int a;
33+
} S_1;
34+
35+
typedef struct {
36+
S_1* s;
37+
} S_2;
38+
39+
// CIR: cir.func @passB(%arg0: !u64i
40+
// CIR: %[[#V0:]] = cir.alloca !ty_S_2_, !cir.ptr<!ty_S_2_>, [""] {alignment = 4 : i64}
41+
// CIR: %[[#V1:]] = cir.cast(bitcast, %[[#V0]] : !cir.ptr<!ty_S_2_>), !cir.ptr<!u64i>
42+
// CIR: cir.store %arg0, %[[#V1]] : !u64i, !cir.ptr<!u64i>
43+
// CIR: cir.return
44+
45+
// LLVM: void @passB(i64 %[[#V0:]])
46+
// LLVM: %[[#V2:]] = alloca %struct.S_2, i64 1, align 4
47+
// LLVM: store i64 %[[#V0]], ptr %[[#V2]], align 8
48+
// LLVM: ret void
49+
void passB(S_2 s) {}

0 commit comments

Comments
 (0)