Skip to content

Commit 681e660

Browse files
authored
[CIR][ABI][AArch64][Lowering] support for passing struct types > 128 bits (#1068)
This PR adds a partial support for so-called indirect function arguments for struct types with size > 128 bits for aarch64. #### Couple words about the implementation The hard part is that it's not one-to-one copy from the original codegen, but the code is inspired by it of course. In the original codegen there is no much job is done for the indirect arguments inside the loop in the `EmitFunctionProlog`, and additional alloca is added in the end, in the call for `EmitParamDecl` function. In our case, for the indirect argument (which is a pointer) we replace the original alloca with a new one, and store the pointer in there. And replace all the uses of the old alloca with the load from the new one, i.e. in both cases users works with the pointer to a structure. Also, I added several missed features in the `constructAttributeList` for indirect arguments, but didn't preserve the original code structure, so let me know if I need to do it.
1 parent 4a60357 commit 681e660

File tree

7 files changed

+84
-1
lines changed

7 files changed

+84
-1
lines changed

clang/include/clang/CIR/ABIArgInfo.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,11 +215,21 @@ class ABIArgInfo {
215215
IndirectAttr.Align = align;
216216
}
217217

218+
bool getIndirectByVal() const {
219+
assert(isIndirect() && "Invalid kind!");
220+
return IndirectByVal;
221+
}
222+
218223
void setIndirectByVal(bool IBV) {
219224
assert(isIndirect() && "Invalid kind!");
220225
IndirectByVal = IBV;
221226
}
222227

228+
bool getIndirectRealign() const {
229+
assert((isIndirect() || isIndirectAliased()) && "Invalid kind!");
230+
return IndirectRealign;
231+
}
232+
223233
void setIndirectRealign(bool IR) {
224234
assert((isIndirect() || isIndirectAliased()) && "Invalid kind!");
225235
IndirectRealign = IR;

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,9 @@ struct MissingFeatures {
269269
static bool ABIPointerParameterAttrs() { return false; }
270270
static bool ABITransparentUnionHandling() { return false; }
271271
static bool ABIPotentialArgAccess() { return false; }
272+
static bool ABIByValAttribute() { return false; }
273+
static bool ABIAlignmentAttribute() { return false; }
274+
static bool ABINoAliasAttribute() { return false; }
272275

273276
//-- Missing AST queries
274277

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,14 @@ void LowerModule::constructAttributeList(StringRef Name,
226226
// Attrs.addStackAlignmentAttr(llvm::MaybeAlign(AI.getDirectAlign()));
227227
cir_cconv_assert(!::cir::MissingFeatures::noFPClass());
228228
break;
229+
case ABIArgInfo::Indirect: {
230+
cir_cconv_assert(!::cir::MissingFeatures::ABIInRegAttribute());
231+
cir_cconv_assert(!::cir::MissingFeatures::ABIByValAttribute());
232+
cir_cconv_assert(!::cir::MissingFeatures::ABINoAliasAttribute());
233+
cir_cconv_assert(!::cir::MissingFeatures::ABIAlignmentAttribute());
234+
cir_cconv_assert(!::cir::MissingFeatures::ABIPotentialArgAccess());
235+
break;
236+
}
229237
default:
230238
cir_cconv_unreachable("Missing ABIArgInfo::Kind");
231239
}

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

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,51 @@ LowerFunction::buildFunctionProlog(const LowerFunctionInfo &FI, FuncOp Fn,
558558
rewriter.eraseOp(argAlloca.getDefiningOp());
559559
break;
560560
}
561+
case ABIArgInfo::Indirect: {
562+
auto AI = Fn.getArgument(FirstIRArg);
563+
if (!hasScalarEvaluationKind(Ty)) {
564+
// Aggregates and complex variables are accessed by reference. All we
565+
// need to do is realign the value, if requested. Also, if the address
566+
// may be aliased, copy it to ensure that the parameter variable is
567+
// mutable and has a unique adress, as C requires.
568+
if (ArgI.getIndirectRealign() || ArgI.isIndirectAliased()) {
569+
cir_cconv_unreachable("NYI");
570+
} else {
571+
// Inspired by EmitParamDecl, which is called in the end of
572+
// EmitFunctionProlog in the original codegen
573+
cir_cconv_assert(!ArgI.getIndirectByVal() &&
574+
"For truly ABI indirect arguments");
575+
576+
auto ptrTy = rewriter.getType<PointerType>(Arg.getType());
577+
Value arg = SrcFn.getArgument(ArgNo);
578+
cir_cconv_assert(arg.hasOneUse());
579+
auto *firstStore = *arg.user_begin();
580+
auto argAlloca = cast<StoreOp>(firstStore).getAddr();
581+
582+
rewriter.setInsertionPoint(argAlloca.getDefiningOp());
583+
auto align = LM.getDataLayout().getABITypeAlign(ptrTy);
584+
auto alignAttr = rewriter.getI64IntegerAttr(align.value());
585+
auto newAlloca = rewriter.create<AllocaOp>(
586+
Fn.getLoc(), rewriter.getType<PointerType>(ptrTy), ptrTy,
587+
/*name=*/StringRef(""),
588+
/*alignment=*/alignAttr);
589+
590+
rewriter.create<StoreOp>(newAlloca.getLoc(), AI,
591+
newAlloca.getResult());
592+
auto load = rewriter.create<LoadOp>(newAlloca.getLoc(),
593+
newAlloca.getResult());
594+
595+
rewriter.replaceAllUsesWith(argAlloca, load);
596+
rewriter.eraseOp(firstStore);
597+
rewriter.eraseOp(argAlloca.getDefiningOp());
598+
599+
ArgVals.push_back(AI);
600+
}
601+
} else {
602+
cir_cconv_unreachable("NYI");
603+
}
604+
break;
605+
}
561606
default:
562607
cir_cconv_unreachable("Unhandled ABIArgInfo::Kind");
563608
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,12 @@ FuncType LowerTypes::getFunctionType(const LowerFunctionInfo &FI) {
9999
}
100100
break;
101101
}
102+
case ABIArgInfo::Indirect: {
103+
mlir::Type argType = (FI.arg_begin() + ArgNo)->type;
104+
ArgTypes[FirstIRArg] =
105+
mlir::cir::PointerType::get(getMLIRContext(), argType);
106+
break;
107+
}
102108
default:
103109
cir_cconv_unreachable("Missing ABIArgInfo::Kind");
104110
}

clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/AArch64.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ AArch64ABIInfo::classifyArgumentType(Type Ty, bool IsVariadic,
188188
return ABIArgInfo::getDirect(argTy);
189189
}
190190

191-
cir_cconv_unreachable("NYI");
191+
return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
192192
}
193193

194194
std::unique_ptr<TargetLoweringInfo>

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,3 +141,14 @@ void pass_lt_128(LT_128 s) {}
141141
// LLVM: %[[#V1]] = alloca %struct.EQ_128, i64 1, align 4
142142
// LLVM: store [2 x i64] %0, ptr %[[#V1]], align 8
143143
void pass_eq_128(EQ_128 s) {}
144+
145+
// CHECK: cir.func @pass_gt_128(%arg0: !cir.ptr<!ty_GT_128_>
146+
// CHECK: %[[#V0:]] = cir.alloca !cir.ptr<!ty_GT_128_>, !cir.ptr<!cir.ptr<!ty_GT_128_>>, [""] {alignment = 8 : i64}
147+
// CHECK: cir.store %arg0, %[[#V0]] : !cir.ptr<!ty_GT_128_>, !cir.ptr<!cir.ptr<!ty_GT_128_>>
148+
// CHECK: %[[#V1:]] = cir.load %[[#V0]] : !cir.ptr<!cir.ptr<!ty_GT_128_>>, !cir.ptr<!ty_GT_128_>
149+
150+
// LLVM: void @pass_gt_128(ptr %0)
151+
// LLVM: %[[#V1:]] = alloca ptr, i64 1, align 8
152+
// LLVM: store ptr %0, ptr %[[#V1]], align 8
153+
// LLVM: %[[#V2:]] = load ptr, ptr %[[#V1]], align 8
154+
void pass_gt_128(GT_128 s) {}

0 commit comments

Comments
 (0)