Skip to content

Commit 40be77f

Browse files
gitoleglanza
authored andcommitted
[CIR][CIRGen] Fixes function calls with return values and cleanup stage (#1214)
#### The Problem Let's take a look at the following code: ``` struct A { ~A() {} }; int foo() { return 42; } void bar() { A a; int b = foo(); } ``` The call to `foo` guarded by the synthetic `tryOp` looks approximately like the following: ``` cir.try synthetic cleanup { %2 = cir.call exception @_Z3foov() : () -> !s32i cleanup { cir.call @_ZN1AD1Ev(%0) : (!cir.ptr<!ty_A>) -> () extra(#fn_attr1) // call to destructor of 'A' cir.yield } cir.yield } catch [#cir.unwind { cir.resume }] cir.store %2, %1: !s32i, !cir.ptr<!s32i> // CIR verification error ``` The result of the `foo` call is in the `try` region - and is not accessible from the outside, so the code generation fails with `operand #0 does not dominate its use` . #### Solution So we have several options how to handle this properly. 1. We may intpoduce a new operation here, like `TryCall` but probably more high level one, e.g. introduce the `InvokeOp`. 2. Also, we may add the result to `TryOp`. 3. The fast fix that is implemented in this PR is a temporary `alloca` where we store the call result right in the try region. And the result of the whole `emitCall` is a `load` from the temp `alloca`. So this PR is both the request for changes and an open discussion as well - how to handle this properly. So far I choose the third approach. If it's ok - I will need to create one more PR with a similar fix for the aggregated results or update this one.
1 parent c8ade18 commit 40be77f

File tree

2 files changed

+54
-0
lines changed

2 files changed

+54
-0
lines changed

clang/lib/CIR/CodeGen/CIRGenCall.cpp

+23
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,17 @@ static cir::CIRCallOpInterface emitCallLikeOp(
552552
extraFnAttrs);
553553
}
554554

555+
static RValue getRValueThroughMemory(mlir::Location loc,
556+
CIRGenBuilderTy &builder, mlir::Value val,
557+
Address addr) {
558+
auto ip = builder.saveInsertionPoint();
559+
builder.setInsertionPointAfterValue(val);
560+
builder.createStore(loc, val, addr);
561+
builder.restoreInsertionPoint(ip);
562+
auto load = builder.createLoad(loc, addr);
563+
return RValue::get(load);
564+
}
565+
555566
RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &CallInfo,
556567
const CIRGenCallee &Callee,
557568
ReturnValueSlot ReturnValue,
@@ -890,6 +901,18 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &CallInfo,
890901
auto Results = theCall->getOpResults();
891902
assert(Results.size() <= 1 && "multiple returns NYI");
892903
assert(Results[0].getType() == RetCIRTy && "Bitcast support NYI");
904+
905+
mlir::Region *region = builder.getBlock()->getParent();
906+
if (region != theCall->getParentRegion()) {
907+
Address DestPtr = ReturnValue.getValue();
908+
909+
if (!DestPtr.isValid())
910+
DestPtr = CreateMemTemp(RetTy, callLoc, "tmp.try.call.res");
911+
912+
return getRValueThroughMemory(callLoc, builder, Results[0],
913+
DestPtr);
914+
}
915+
893916
return RValue::get(Results[0]);
894917
}
895918
default:

clang/test/CIR/CodeGen/try-catch-dtors.cpp

+31
Original file line numberDiff line numberDiff line change
@@ -308,3 +308,34 @@ void yo2(bool x) {
308308
// CIR: } catch [type #cir.all {
309309
// CIR: cir.catch_param -> !cir.ptr<!void>
310310
// CIR: }]
311+
312+
313+
int foo() { return 42; }
314+
315+
struct A {
316+
~A() {}
317+
};
318+
319+
void bar() {
320+
A a;
321+
int b = foo();
322+
}
323+
324+
// CIR-LABEL: @_Z3barv
325+
// CIR: %[[V0:.*]] = cir.alloca !ty_A, !cir.ptr<!ty_A>, ["a"] {alignment = 1 : i64}
326+
// CIR: %[[V1:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["b", init] {alignment = 4 : i64}
327+
// CIR: %[[V2:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["tmp.try.call.res"] {alignment = 4 : i64}
328+
// CIR: cir.try synthetic cleanup {
329+
// CIR: %[[V4:.*]] = cir.call exception @_Z3foov() : () -> !s32i cleanup {
330+
// CIR: cir.call @_ZN1AD2Ev(%[[V0]]) : (!cir.ptr<!ty_A>) -> () extra(#fn_attr)
331+
// CIR: cir.yield
332+
// CIR: }
333+
// CIR: cir.store %[[V4]], %[[V2]] : !s32i, !cir.ptr<!s32i>
334+
// CIR: cir.yield
335+
// CIR: } catch [#cir.unwind {
336+
// CIR: cir.resume
337+
// CIR: }]
338+
// CIR: %[[V3:.*]] = cir.load %[[V2]] : !cir.ptr<!s32i>, !s32i
339+
// CIR: cir.store %[[V3]], %[[V1]] : !s32i, !cir.ptr<!s32i>
340+
// CIR: cir.call @_ZN1AD2Ev(%[[V0]]) : (!cir.ptr<!ty_A>) -> () extra(#fn_attr)
341+
// CIR: cir.return

0 commit comments

Comments
 (0)