diff --git a/clang/include/clang/CIR/ABIArgInfo.h b/clang/include/clang/CIR/ABIArgInfo.h index 582feae157b2..818d3b62f13f 100644 --- a/clang/include/clang/CIR/ABIArgInfo.h +++ b/clang/include/clang/CIR/ABIArgInfo.h @@ -215,11 +215,21 @@ class ABIArgInfo { IndirectAttr.Align = align; } + bool getIndirectByVal() const { + assert(isIndirect() && "Invalid kind!"); + return IndirectByVal; + } + void setIndirectByVal(bool IBV) { assert(isIndirect() && "Invalid kind!"); IndirectByVal = IBV; } + bool getIndirectRealign() const { + assert((isIndirect() || isIndirectAliased()) && "Invalid kind!"); + return IndirectRealign; + } + void setIndirectRealign(bool IR) { assert((isIndirect() || isIndirectAliased()) && "Invalid kind!"); IndirectRealign = IR; diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index 9b1eb419f3e0..412ac4385f4b 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -269,6 +269,9 @@ struct MissingFeatures { static bool ABIPointerParameterAttrs() { return false; } static bool ABITransparentUnionHandling() { return false; } static bool ABIPotentialArgAccess() { return false; } + static bool ABIByValAttribute() { return false; } + static bool ABIAlignmentAttribute() { return false; } + static bool ABINoAliasAttribute() { return false; } //-- Missing AST queries diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerCall.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerCall.cpp index 54fe89838e82..23c6c85a9723 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerCall.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerCall.cpp @@ -226,6 +226,14 @@ void LowerModule::constructAttributeList(StringRef Name, // Attrs.addStackAlignmentAttr(llvm::MaybeAlign(AI.getDirectAlign())); cir_cconv_assert(!::cir::MissingFeatures::noFPClass()); break; + case ABIArgInfo::Indirect: { + cir_cconv_assert(!::cir::MissingFeatures::ABIInRegAttribute()); + cir_cconv_assert(!::cir::MissingFeatures::ABIByValAttribute()); + cir_cconv_assert(!::cir::MissingFeatures::ABINoAliasAttribute()); + cir_cconv_assert(!::cir::MissingFeatures::ABIAlignmentAttribute()); + cir_cconv_assert(!::cir::MissingFeatures::ABIPotentialArgAccess()); + break; + } default: cir_cconv_unreachable("Missing ABIArgInfo::Kind"); } diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerFunction.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerFunction.cpp index 1b638411cc59..67e5a012cb6e 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerFunction.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerFunction.cpp @@ -516,6 +516,51 @@ LowerFunction::buildFunctionProlog(const LowerFunctionInfo &FI, FuncOp Fn, rewriter.eraseOp(argAlloca.getDefiningOp()); break; } + case ABIArgInfo::Indirect: { + auto AI = Fn.getArgument(FirstIRArg); + if (!hasScalarEvaluationKind(Ty)) { + // Aggregates and complex variables are accessed by reference. All we + // need to do is realign the value, if requested. Also, if the address + // may be aliased, copy it to ensure that the parameter variable is + // mutable and has a unique adress, as C requires. + if (ArgI.getIndirectRealign() || ArgI.isIndirectAliased()) { + cir_cconv_unreachable("NYI"); + } else { + // Inspired by EmitParamDecl, which is called in the end of + // EmitFunctionProlog in the original codegen + cir_cconv_assert(!ArgI.getIndirectByVal() && + "For truly ABI indirect arguments"); + + auto ptrTy = rewriter.getType(Arg.getType()); + Value arg = SrcFn.getArgument(ArgNo); + cir_cconv_assert(arg.hasOneUse()); + auto *firstStore = *arg.user_begin(); + auto argAlloca = cast(firstStore).getAddr(); + + rewriter.setInsertionPoint(argAlloca.getDefiningOp()); + auto align = LM.getDataLayout().getABITypeAlign(ptrTy); + auto alignAttr = rewriter.getI64IntegerAttr(align.value()); + auto newAlloca = rewriter.create( + Fn.getLoc(), rewriter.getType(ptrTy), ptrTy, + /*name=*/StringRef(""), + /*alignment=*/alignAttr); + + rewriter.create(newAlloca.getLoc(), AI, + newAlloca.getResult()); + auto load = rewriter.create(newAlloca.getLoc(), + newAlloca.getResult()); + + rewriter.replaceAllUsesWith(argAlloca, load); + rewriter.eraseOp(firstStore); + rewriter.eraseOp(argAlloca.getDefiningOp()); + + ArgVals.push_back(AI); + } + } else { + cir_cconv_unreachable("NYI"); + } + break; + } default: cir_cconv_unreachable("Unhandled ABIArgInfo::Kind"); } diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerTypes.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerTypes.cpp index 8ed553a8f7d2..5a3382dc40e6 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerTypes.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerTypes.cpp @@ -99,6 +99,12 @@ FuncType LowerTypes::getFunctionType(const LowerFunctionInfo &FI) { } break; } + case ABIArgInfo::Indirect: { + mlir::Type argType = (FI.arg_begin() + ArgNo)->type; + ArgTypes[FirstIRArg] = + mlir::cir::PointerType::get(getMLIRContext(), argType); + break; + } default: cir_cconv_unreachable("Missing ABIArgInfo::Kind"); } diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/AArch64.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/AArch64.cpp index e28766985995..74de795ed622 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/AArch64.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/AArch64.cpp @@ -188,7 +188,7 @@ AArch64ABIInfo::classifyArgumentType(Type Ty, bool IsVariadic, return ABIArgInfo::getDirect(argTy); } - cir_cconv_unreachable("NYI"); + return getNaturalAlignIndirect(Ty, /*ByVal=*/false); } std::unique_ptr diff --git a/clang/test/CIR/CallConvLowering/AArch64/aarch64-cc-structs.c b/clang/test/CIR/CallConvLowering/AArch64/aarch64-cc-structs.c index bc2f1d37d729..7847ad8b684b 100644 --- a/clang/test/CIR/CallConvLowering/AArch64/aarch64-cc-structs.c +++ b/clang/test/CIR/CallConvLowering/AArch64/aarch64-cc-structs.c @@ -115,3 +115,14 @@ void pass_lt_128(LT_128 s) {} // LLVM: %[[#V1]] = alloca %struct.EQ_128, i64 1, align 4 // LLVM: store [2 x i64] %0, ptr %[[#V1]], align 8 void pass_eq_128(EQ_128 s) {} + +// CHECK: cir.func @pass_gt_128(%arg0: !cir.ptr +// CHECK: %[[#V0:]] = cir.alloca !cir.ptr, !cir.ptr>, [""] {alignment = 8 : i64} +// CHECK: cir.store %arg0, %[[#V0]] : !cir.ptr, !cir.ptr> +// CHECK: %[[#V1:]] = cir.load %[[#V0]] : !cir.ptr>, !cir.ptr + +// LLVM: void @pass_gt_128(ptr %0) +// LLVM: %[[#V1:]] = alloca ptr, i64 1, align 8 +// LLVM: store ptr %0, ptr %[[#V1]], align 8 +// LLVM: %[[#V2:]] = load ptr, ptr %[[#V1]], align 8 +void pass_gt_128(GT_128 s) {}