Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions clang/include/clang/CIR/MissingFeatures.h
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,8 @@ struct MissingFeatures {
static bool itaniumRecordLayoutBuilderFinishLayout() { return false; }

static bool mustProgress() { return false; }

static bool skipTempCopy() { return false; }
};

} // namespace cir
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,14 @@ LowerFunction::buildFunctionEpilog(const LowerFunctionInfo &FI) {
if (auto al = findAlloca(ret)) {
rewriter.replaceAllUsesWith(al.getResult(), RVAddr);
rewriter.eraseOp(al);
rewriter.setInsertionPoint(ret);

auto retInputs = ret.getInput();
assert(retInputs.size() == 1 && "return should only have one input");
if (auto load = mlir::dyn_cast<LoadOp>(retInputs[0].getDefiningOp()))
if (load.getResult().use_empty())
rewriter.eraseOp(load);

rewriter.replaceOpWithNewOp<ReturnOp>(ret);
}
});
Expand Down Expand Up @@ -933,6 +941,15 @@ mlir::Value LowerFunction::rewriteCallOp(FuncType calleeTy, FuncOp origCallee,
return CallResult;
}

mlir::Value createAlloca(mlir::Location loc, mlir::Type type,
LowerFunction &CGF) {
auto align = CGF.LM.getDataLayout().getABITypeAlign(type);
auto alignAttr = CGF.getRewriter().getI64IntegerAttr(align.value());
return CGF.getRewriter().create<AllocaOp>(
loc, CGF.getRewriter().getType<PointerType>(type), type,
/*name=*/llvm::StringRef(""), alignAttr);
}

// NOTE(cir): This method has partial parity to CodeGenFunction's EmitCall
// method in CGCall.cpp. When incrementing it, use the original codegen as a
// reference: add ABI-specific stuff and skip codegen stuff.
Expand Down Expand Up @@ -965,10 +982,12 @@ mlir::Value LowerFunction::rewriteCallOp(const LowerFunctionInfo &CallInfo,
CIRToCIRArgMapping IRFunctionArgs(LM.getContext(), CallInfo);
llvm::SmallVector<mlir::Value, 16> IRCallArgs(IRFunctionArgs.totalIRArgs());

mlir::Value sRetPtr;
// If the call returns a temporary with struct return, create a temporary
// alloca to hold the result, unless one is given to us.
if (RetAI.isIndirect() || RetAI.isCoerceAndExpand() || RetAI.isInAlloca()) {
cir_cconv_unreachable("NYI");
sRetPtr = createAlloca(loc, RetTy, *this);
IRCallArgs[IRFunctionArgs.getSRetArgNo()] = sRetPtr;
}

cir_cconv_assert(!cir::MissingFeatures::swift());
Expand Down Expand Up @@ -1063,6 +1082,32 @@ mlir::Value LowerFunction::rewriteCallOp(const LowerFunctionInfo &CallInfo,

break;
}
case ABIArgInfo::Indirect:
case ABIArgInfo::IndirectAliased: {
assert(NumIRArgs == 1);
// TODO(cir): For aggregate types
// We want to avoid creating an unnecessary temporary+copy here;
// however, we need one in three cases:
// 1. If the argument is not byval, and we are required to copy the
// 2. If the argument is byval, RV is not sufficiently aligned, and
// source. (This case doesn't occur on any common architecture.)
// we cannot force it to be sufficiently aligned.
// 3. If the argument is byval, but RV is not located in default
// or alloca address space.
cir_cconv_assert(!::cir::MissingFeatures::skipTempCopy());

mlir::Value alloca = findAlloca(I->getDefiningOp());

// since they are a ARM-specific feature.
if (::cir::MissingFeatures::undef())
cir_cconv_unreachable("NYI");

IRCallArgs[FirstIRArg] = alloca;

// NOTE(cir): Skipping Emissions, lifetime markers.

break;
}
default:
llvm::outs() << "Missing ABIArgInfo::Kind: " << ArgInfo.getKind() << "\n";
cir_cconv_unreachable("NYI");
Expand Down Expand Up @@ -1198,6 +1243,10 @@ mlir::Value LowerFunction::rewriteCallOp(const LowerFunctionInfo &CallInfo,
// done in CIRGen
return RetVal;
}
case ABIArgInfo::Indirect: {
auto load = rewriter.create<LoadOp>(loc, sRetPtr);
return load.getResult();
}
default:
llvm::errs() << "Unhandled ABIArgInfo kind: " << RetAI.getKind() << "\n";
cir_cconv_unreachable("NYI");
Expand Down
37 changes: 37 additions & 0 deletions clang/test/CIR/CallConvLowering/AArch64/aarch64-cc-structs.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,43 @@ void pass_eq_128(EQ_128 s) {}
// LLVM: %[[#V2:]] = load ptr, ptr %[[#V1]], align 8
void pass_gt_128(GT_128 s) {}

// CHECK: cir.func @get_gt_128(%arg0: !cir.ptr<!ty_GT_128_> {{.*}}, %arg1: !cir.ptr<!ty_GT_128_>
// CHECK: %[[#V0:]] = cir.alloca !cir.ptr<!ty_GT_128_>, !cir.ptr<!cir.ptr<!ty_GT_128_>>, [""] {alignment = 8 : i64}
// CHECK: cir.store %arg1, %[[#V0]] : !cir.ptr<!ty_GT_128_>, !cir.ptr<!cir.ptr<!ty_GT_128_>>
// CHECK: %[[#V1:]] = cir.load %[[#V0]] : !cir.ptr<!cir.ptr<!ty_GT_128_>>, !cir.ptr<!ty_GT_128_>
// CHECK: cir.copy %[[#V1]] to %arg0 : !cir.ptr<!ty_GT_128_>
// CHECK: cir.return

// LLVM: void @get_gt_128(ptr %[[#V0:]], ptr %[[#V1:]])
// LLVM: %[[#V3:]] = alloca ptr, i64 1, align 8
// LLVM: store ptr %[[#V1]], ptr %[[#V3]], align 8
// LLVM: %[[#V4:]] = load ptr, ptr %[[#V3]], align 8
// LLVM: call void @llvm.memcpy.p0.p0.i32(ptr %[[#V0]], ptr %[[#V4]], i32 24, i1 false)
// LLVM: ret void
GT_128 get_gt_128(GT_128 s) {
return s;
}

// CHECK: cir.func no_proto @call_and_get_gt_128(%arg0: !cir.ptr<!ty_GT_128_>
// CHECK: %[[#V0:]] = cir.alloca !ty_GT_128_, !cir.ptr<!ty_GT_128_>, {{.*}} {alignment = 8 : i64}
// CHECK: %[[#V1:]] = cir.alloca !ty_GT_128_, !cir.ptr<!ty_GT_128_>, {{.*}} {alignment = 8 : i64}
// CHECK: cir.call @get_gt_128(%[[#V1]], %arg0) : (!cir.ptr<!ty_GT_128_>, !cir.ptr<!ty_GT_128_>) -> ()
// CHECK: %[[#V2:]] = cir.load %[[#V1]] : !cir.ptr<!ty_GT_128_>, !ty_GT_128_
// CHECK: cir.store %[[#V2]], %[[#V0]] : !ty_GT_128_, !cir.ptr<!ty_GT_128_>
// CHECK: cir.return

// LLVM: void @call_and_get_gt_128(ptr %[[#V0:]])
// LLVM: %[[#V2:]] = alloca %struct.GT_128, i64 1, align 8
// LLVM: %[[#V3:]] = alloca %struct.GT_128, i64 1, align 8
// LLVM: call void @get_gt_128(ptr %[[#V3]], ptr %[[#V0]])
// LLVM: %[[#V4:]] = load %struct.GT_128, ptr %[[#V3]], align 8
// LLVM: store %struct.GT_128 %[[#V4]], ptr %[[#V2]], align 8
// LLVM: ret void
GT_128 call_and_get_gt_128() {
GT_128 s;
s = get_gt_128(s);
return s;
}
// CHECK: cir.func @passS(%arg0: !cir.array<!u64i x 2>
// CHECK: %[[#V0:]] = cir.alloca !ty_S, !cir.ptr<!ty_S>, [""] {alignment = 4 : i64}
// CHECK: %[[#V1:]] = cir.alloca !cir.array<!u64i x 2>, !cir.ptr<!cir.array<!u64i x 2>>, ["tmp"] {alignment = 8 : i64}
Expand Down