Skip to content

Commit b625535

Browse files
committed
[CIR][CIRGen] Exceptions: support free'ing allocated exception resources
1 parent bc78797 commit b625535

File tree

4 files changed

+101
-5
lines changed

4 files changed

+101
-5
lines changed

clang/include/clang/CIR/Dialect/IR/CIROps.td

+34-1
Original file line numberDiff line numberDiff line change
@@ -4092,7 +4092,7 @@ def VAArgOp : CIR_Op<"va.arg">,
40924092
}
40934093

40944094
//===----------------------------------------------------------------------===//
4095-
// AllocExceptionOp
4095+
// AllocExceptionOp & FreeExceptionOp
40964096
//===----------------------------------------------------------------------===//
40974097

40984098
def AllocExceptionOp : CIR_Op<"alloc.exception"> {
@@ -4129,6 +4129,39 @@ def AllocExceptionOp : CIR_Op<"alloc.exception"> {
41294129
let hasVerifier = 0;
41304130
}
41314131

4132+
def FreeExceptionOp : CIR_Op<"free.exception"> {
4133+
let summary = "Frees an exception according to Itanium ABI";
4134+
let description = [{
4135+
Implements a slightly higher level version of:
4136+
`void __cxa_free_exception(void *thrown_exception);`
4137+
4138+
Example:
4139+
4140+
```mlir
4141+
%0 = cir.alloc.exception 16 -> !cir.ptr<!some_struct>
4142+
%1 = cir.get_global @d2 : !cir.ptr<!some_struct>
4143+
cir.try synthetic cleanup {
4144+
cir.call exception @_ZN7test2_DC1ERKS_(%0, %1) : (!cir.ptr<!some_struct>, !cir.ptr<!some_struct>) -> () cleanup {
4145+
%2 = cir.cast(bitcast, %0 : !cir.ptr<!some_struct>), !cir.ptr<!void>
4146+
cir.free.exception %2
4147+
cir.yield
4148+
}
4149+
...
4150+
}
4151+
```
4152+
}];
4153+
4154+
let arguments = (ins VoidPtr:$ptr);
4155+
let results = (outs);
4156+
4157+
let assemblyFormat = [{
4158+
$ptr attr-dict
4159+
}];
4160+
4161+
// Constraints already described.
4162+
let hasVerifier = 0;
4163+
}
4164+
41324165
//===----------------------------------------------------------------------===//
41334166
// ThrowOp
41344167
//===----------------------------------------------------------------------===//

clang/lib/CIR/CodeGen/CIRGenException.cpp

+6-1
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,12 @@ struct FreeException final : EHScopeStack::Cleanup {
214214
mlir::Value exn;
215215
FreeException(mlir::Value exn) : exn(exn) {}
216216
void Emit(CIRGenFunction &CGF, Flags flags) override {
217-
llvm_unreachable("call to cxa_free or equivalent op NYI");
217+
// OG LLVM codegen emits a no unwind call, CIR emits an operation.
218+
cir::CIRGenBuilderTy &builder = CGF.getBuilder();
219+
mlir::Location loc =
220+
CGF.currSrcLoc ? *CGF.currSrcLoc : builder.getUnknownLoc();
221+
builder.create<mlir::cir::FreeExceptionOp>(
222+
loc, builder.createBitcast(exn, builder.getVoidPtrTy()));
218223
}
219224
};
220225
} // end anonymous namespace

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp

+23-2
Original file line numberDiff line numberDiff line change
@@ -3788,6 +3788,27 @@ class CIRAllocExceptionOpLowering
37883788
}
37893789
};
37903790

3791+
class CIRFreeExceptionOpLowering
3792+
: public mlir::OpConversionPattern<mlir::cir::FreeExceptionOp> {
3793+
public:
3794+
using OpConversionPattern<mlir::cir::FreeExceptionOp>::OpConversionPattern;
3795+
3796+
mlir::LogicalResult
3797+
matchAndRewrite(mlir::cir::FreeExceptionOp op, OpAdaptor adaptor,
3798+
mlir::ConversionPatternRewriter &rewriter) const override {
3799+
// Get or create `declare void @__cxa_free_exception(ptr)`
3800+
StringRef fnName = "__cxa_free_exception";
3801+
auto llvmPtrTy = mlir::LLVM::LLVMPointerType::get(rewriter.getContext());
3802+
auto voidTy = mlir::LLVM::LLVMVoidType::get(rewriter.getContext());
3803+
auto fnTy = mlir::LLVM::LLVMFunctionType::get(voidTy, {llvmPtrTy},
3804+
/*isVarArg=*/false);
3805+
getOrCreateLLVMFuncOp(rewriter, op, fnName, fnTy);
3806+
rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
3807+
op, mlir::TypeRange{}, fnName, mlir::ValueRange{adaptor.getPtr()});
3808+
return mlir::success();
3809+
}
3810+
};
3811+
37913812
class CIRThrowOpLowering
37923813
: public mlir::OpConversionPattern<mlir::cir::ThrowOp> {
37933814
public:
@@ -3854,8 +3875,8 @@ void populateCIRToLLVMConversionPatterns(mlir::RewritePatternSet &patterns,
38543875
CIRPrefetchLowering, CIRObjSizeOpLowering, CIRIsConstantOpLowering,
38553876
CIRCmpThreeWayOpLowering, CIRClearCacheOpLowering, CIRUndefOpLowering,
38563877
CIREhTypeIdOpLowering, CIRCatchParamOpLowering, CIRResumeOpLowering,
3857-
CIRAllocExceptionOpLowering, CIRThrowOpLowering, CIRIntrinsicCallLowering,
3858-
CIRBaseClassAddrOpLowering
3878+
CIRAllocExceptionOpLowering, CIRFreeExceptionOpLowering,
3879+
CIRThrowOpLowering, CIRIntrinsicCallLowering, CIRBaseClassAddrOpLowering
38593880
#define GET_BUILTIN_LOWERING_LIST
38603881
#include "clang/CIR/Dialect/IR/CIRBuiltinsLowering.inc"
38613882
#undef GET_BUILTIN_LOWERING_LIST

clang/test/CIR/CodeGen/eh.cpp

+38-1
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,41 @@ void test1() {
2626
// LLVM: call void @_ZN7test1_DC1ERKS_(ptr %[[ALLOC]], ptr @d1)
2727
// LLVM: call void @__cxa_throw(ptr %[[ALLOC]], ptr @_ZTI7test1_D, ptr null)
2828
// LLVM: unreachable
29-
// LLVM: }
29+
// LLVM: }
30+
31+
struct test2_D {
32+
test2_D(const test2_D&o);
33+
test2_D();
34+
virtual void bar() { }
35+
int i; int j;
36+
} d2;
37+
38+
void test2() {
39+
throw d2;
40+
}
41+
42+
// CIR-LABEL: @_Z5test2v
43+
// CIR: %[[ALLOC:.*]] = cir.alloc.exception 16 -> !cir.ptr<!ty_test2_D>
44+
// CIR: %[[G:.*]] = cir.get_global @d2 : !cir.ptr<!ty_test2_D>
45+
// CIR: cir.try synthetic cleanup {
46+
// CIR: cir.call exception @_ZN7test2_DC1ERKS_(%[[ALLOC]], %[[G]]) : (!cir.ptr<!ty_test2_D>, !cir.ptr<!ty_test2_D>) -> () cleanup {
47+
// CIR: %[[VOID_PTR:.*]] = cir.cast(bitcast, %[[ALLOC]] : !cir.ptr<!ty_test2_D>), !cir.ptr<!void>
48+
// CIR: cir.free.exception %[[VOID_PTR]]
49+
// CIR: cir.yield
50+
// CIR: }
51+
// CIR: cir.yield
52+
// CIR: } catch [#cir.unwind {
53+
// CIR: cir.resume
54+
// CIR: }]
55+
// CIR: cir.throw %[[ALLOC]] : !cir.ptr<!ty_test2_D>, @_ZTI7test2_D
56+
// CIR: cir.unreachable
57+
58+
// LLVM-LABEL: @_Z5test2v
59+
60+
// LLVM: %[[ALLOC:.*]] = call ptr @__cxa_allocate_exception(i64 16)
61+
62+
// LLVM: landingpad { ptr, i32 }
63+
// LLVM: cleanup
64+
// LLVM: extractvalue { ptr, i32 }
65+
// LLVM: extractvalue { ptr, i32 }
66+
// LLVM: call void @__cxa_free_exception(ptr %[[ALLOC]])

0 commit comments

Comments
 (0)