Skip to content

Commit 009ec6f

Browse files
authored
[CIR] Upstream Exception EhInflight op (#165621)
Upstream Exception EhInflight op as a prerequisite for full catch handlers implementation Issue #154992
1 parent 36cbcec commit 009ec6f

File tree

4 files changed

+215
-0
lines changed

4 files changed

+215
-0
lines changed

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

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4658,6 +4658,44 @@ def CIR_TryOp : CIR_Op<"try",[
46584658
let hasLLVMLowering = false;
46594659
}
46604660

4661+
//===----------------------------------------------------------------------===//
4662+
// Exception related: EhInflightOp
4663+
//===----------------------------------------------------------------------===//
4664+
4665+
def CIR_EhInflightOp : CIR_Op<"eh.inflight_exception"> {
4666+
let summary = "Materialize the catch clause formal parameter";
4667+
let description = [{
4668+
`cir.eh.inflight_exception` returns two values:
4669+
- `exception_ptr`: The exception pointer for the inflight exception
4670+
- `type_id`: the type info index for the exception type
4671+
This operation is expected to be the first operation in the unwind
4672+
destination basic blocks of a `cir.try_call` operation.
4673+
4674+
The `cleanup` attribute indicates that clean up code must be run before the
4675+
values produced by this operation are used to dispatch the exception. This
4676+
cleanup code must be executed even if the exception is not caught.
4677+
This helps CIR to pass down more accurate information for LLVM lowering
4678+
to landingpads.
4679+
4680+
Example:
4681+
4682+
```mlir
4683+
%exception_ptr, %type_id = cir.eh.inflight_exception
4684+
%exception_ptr, %type_id = cir.eh.inflight_exception [@_ZTIi, @_ZTIPKc]
4685+
%exception_ptr, %type_id = cir.eh.inflight_exception cleanup
4686+
``
4687+
}];
4688+
4689+
let arguments = (ins UnitAttr:$cleanup,
4690+
OptionalAttr<FlatSymbolRefArrayAttr>:$catch_type_list);
4691+
let results = (outs CIR_VoidPtrType:$exception_ptr, CIR_UInt32:$type_id);
4692+
let assemblyFormat = [{
4693+
(`cleanup` $cleanup^)?
4694+
($catch_type_list^)?
4695+
attr-dict
4696+
}];
4697+
}
4698+
46614699
//===----------------------------------------------------------------------===//
46624700
// Atomic operations
46634701
//===----------------------------------------------------------------------===//

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

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3104,6 +3104,90 @@ mlir::LogicalResult CIRToLLVMAllocExceptionOpLowering::matchAndRewrite(
31043104
return mlir::success();
31053105
}
31063106

3107+
static mlir::LLVM::LLVMStructType
3108+
getLLVMLandingPadStructTy(mlir::ConversionPatternRewriter &rewriter) {
3109+
// Create the landing pad type: struct { ptr, i32 }
3110+
mlir::MLIRContext *ctx = rewriter.getContext();
3111+
auto llvmPtr = mlir::LLVM::LLVMPointerType::get(ctx);
3112+
llvm::SmallVector<mlir::Type> structFields = {llvmPtr, rewriter.getI32Type()};
3113+
return mlir::LLVM::LLVMStructType::getLiteral(ctx, structFields);
3114+
}
3115+
3116+
mlir::LogicalResult CIRToLLVMEhInflightOpLowering::matchAndRewrite(
3117+
cir::EhInflightOp op, OpAdaptor adaptor,
3118+
mlir::ConversionPatternRewriter &rewriter) const {
3119+
auto llvmFn = op->getParentOfType<mlir::LLVM::LLVMFuncOp>();
3120+
assert(llvmFn && "expected LLVM function parent");
3121+
mlir::Block *entryBlock = &llvmFn.getRegion().front();
3122+
assert(entryBlock->isEntryBlock());
3123+
3124+
mlir::ArrayAttr catchListAttr = op.getCatchTypeListAttr();
3125+
mlir::SmallVector<mlir::Value> catchSymAddrs;
3126+
3127+
auto llvmPtrTy = mlir::LLVM::LLVMPointerType::get(rewriter.getContext());
3128+
mlir::Location loc = op.getLoc();
3129+
3130+
// %landingpad = landingpad { ptr, i32 }
3131+
// Note that since llvm.landingpad has to be the first operation on the
3132+
// block, any needed value for its operands has to be added somewhere else.
3133+
if (catchListAttr) {
3134+
// catch ptr @_ZTIi
3135+
// catch ptr @_ZTIPKc
3136+
for (mlir::Attribute catchAttr : catchListAttr) {
3137+
auto symAttr = cast<mlir::FlatSymbolRefAttr>(catchAttr);
3138+
// Generate `llvm.mlir.addressof` for each symbol, and place those
3139+
// operations in the LLVM function entry basic block.
3140+
mlir::OpBuilder::InsertionGuard guard(rewriter);
3141+
rewriter.setInsertionPointToStart(entryBlock);
3142+
mlir::Value addrOp = mlir::LLVM::AddressOfOp::create(
3143+
rewriter, loc, llvmPtrTy, symAttr.getValue());
3144+
catchSymAddrs.push_back(addrOp);
3145+
}
3146+
} else if (!op.getCleanup()) {
3147+
// We need to emit catch-all only if cleanup is not set, because when we
3148+
// have catch-all handler, there is no case when we set would unwind past
3149+
// the handler
3150+
mlir::OpBuilder::InsertionGuard guard(rewriter);
3151+
rewriter.setInsertionPointToStart(entryBlock);
3152+
mlir::Value nullOp = mlir::LLVM::ZeroOp::create(rewriter, loc, llvmPtrTy);
3153+
catchSymAddrs.push_back(nullOp);
3154+
}
3155+
3156+
// %slot = extractvalue { ptr, i32 } %x, 0
3157+
// %selector = extractvalue { ptr, i32 } %x, 1
3158+
mlir::LLVM::LLVMStructType llvmLandingPadStructTy =
3159+
getLLVMLandingPadStructTy(rewriter);
3160+
auto landingPadOp = mlir::LLVM::LandingpadOp::create(
3161+
rewriter, loc, llvmLandingPadStructTy, catchSymAddrs);
3162+
3163+
if (op.getCleanup())
3164+
landingPadOp.setCleanup(true);
3165+
3166+
mlir::Value slot =
3167+
mlir::LLVM::ExtractValueOp::create(rewriter, loc, landingPadOp, 0);
3168+
mlir::Value selector =
3169+
mlir::LLVM::ExtractValueOp::create(rewriter, loc, landingPadOp, 1);
3170+
rewriter.replaceOp(op, mlir::ValueRange{slot, selector});
3171+
3172+
// Landing pads are required to be in LLVM functions with personality
3173+
// attribute.
3174+
// TODO(cir): for now hardcode personality creation in order to start
3175+
// adding exception tests, once we annotate CIR with such information,
3176+
// change it to be in FuncOp lowering instead.
3177+
mlir::OpBuilder::InsertionGuard guard(rewriter);
3178+
// Insert personality decl before the current function.
3179+
rewriter.setInsertionPoint(llvmFn);
3180+
auto personalityFnTy =
3181+
mlir::LLVM::LLVMFunctionType::get(rewriter.getI32Type(), {},
3182+
/*isVarArg=*/true);
3183+
3184+
const StringRef fnName = "__gxx_personality_v0";
3185+
createLLVMFuncOpIfNotExist(rewriter, op, fnName, personalityFnTy);
3186+
llvmFn.setPersonality(fnName);
3187+
3188+
return mlir::success();
3189+
}
3190+
31073191
mlir::LogicalResult CIRToLLVMTrapOpLowering::matchAndRewrite(
31083192
cir::TrapOp op, OpAdaptor adaptor,
31093193
mlir::ConversionPatternRewriter &rewriter) const {

clang/test/CIR/IR/eh-inflight.cir

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// RUN: cir-opt %s --verify-roundtrip | FileCheck %s
2+
3+
!u8i = !cir.int<u, 8>
4+
5+
module {
6+
7+
cir.func dso_local @inflight_exception() {
8+
%exception_ptr, %type_id = cir.eh.inflight_exception
9+
cir.return
10+
}
11+
12+
// CHECK: cir.func dso_local @inflight_exception() {
13+
// CHECK: %exception_ptr, %type_id = cir.eh.inflight_exception
14+
// CHECK: cir.return
15+
// CHECK: }
16+
17+
cir.func dso_local @inflight_exception_with_cleanup() {
18+
%exception_ptr, %type_id = cir.eh.inflight_exception cleanup
19+
cir.return
20+
}
21+
22+
// CHECK: cir.func dso_local @inflight_exception_with_cleanup() {
23+
// CHECK: %exception_ptr, %type_id = cir.eh.inflight_exception cleanup
24+
// CHECK: cir.return
25+
// CHECK: }
26+
27+
cir.global "private" constant external @_ZTIi : !cir.ptr<!u8i>
28+
cir.global "private" constant external @_ZTIPKc : !cir.ptr<!u8i>
29+
30+
cir.func dso_local @inflight_exception_with_catch_type_list() {
31+
%exception_ptr, %type_id = cir.eh.inflight_exception [@_ZTIi, @_ZTIPKc]
32+
cir.return
33+
}
34+
35+
// CHECK: cir.func dso_local @inflight_exception_with_catch_type_list() {
36+
// CHECK: %exception_ptr, %type_id = cir.eh.inflight_exception [@_ZTIi, @_ZTIPKc]
37+
// CHECK: cir.return
38+
// CHECK:}
39+
40+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// RUN: cir-opt %s -cir-to-llvm -o %t.cir
2+
3+
!u8i = !cir.int<u, 8>
4+
5+
module {
6+
7+
// CHECK: llvm.func @__gxx_personality_v0(...) -> i32
8+
9+
cir.func @inflight_exception() {
10+
%exception_ptr, %type_id = cir.eh.inflight_exception
11+
cir.return
12+
}
13+
14+
// CHECK: llvm.func @inflight_exception() attributes {personality = @__gxx_personality_v0} {
15+
// CHECK: %[[CONST_0:.*]] = llvm.mlir.zero : !llvm.ptr
16+
// CHECK: %[[LP:.*]] = llvm.landingpad (catch %[[CONST_0]] : !llvm.ptr) : !llvm.struct<(ptr, i32)>
17+
// CHECK: %[[EXCEPTION_PTR:.*]] = llvm.extractvalue %[[LP]][0] : !llvm.struct<(ptr, i32)>
18+
// CHECK: %[[TYPE_ID:.*]] = llvm.extractvalue %[[LP]][1] : !llvm.struct<(ptr, i32)>
19+
// CHECK: llvm.return
20+
// CHECK: }
21+
22+
cir.func @inflight_exception_with_cleanup() {
23+
%exception_ptr, %type_id = cir.eh.inflight_exception cleanup
24+
cir.return
25+
}
26+
27+
// CHECK: llvm.func @inflight_exception_with_cleanup() attributes {personality = @__gxx_personality_v0} {
28+
// CHECK: %[[LP:.*]] = llvm.landingpad cleanup : !llvm.struct<(ptr, i32)>
29+
// CHECK: %[[EXCEPTION_PTR:.*]] = llvm.extractvalue %[[LP]][0] : !llvm.struct<(ptr, i32)>
30+
// CHECK: %[[TYPE_ID:.*]] = llvm.extractvalue %[[LP]][1] : !llvm.struct<(ptr, i32)>
31+
// CHECK: llvm.return
32+
// CHECK: }
33+
34+
35+
cir.global "private" constant external @_ZTIi : !cir.ptr<!u8i>
36+
cir.global "private" constant external @_ZTIPKc : !cir.ptr<!u8i>
37+
38+
cir.func @inflight_exception_with_catch_type_list() {
39+
%exception_ptr, %type_id = cir.eh.inflight_exception [@_ZTIi, @_ZTIPKc]
40+
cir.return
41+
}
42+
43+
// CHECK: llvm.func @inflight_exception_with_catch_type_list() attributes {personality = @__gxx_personality_v0} {
44+
// CHECK: %[[TI_1_ADDR:.*]] = llvm.mlir.addressof @_ZTIPKc : !llvm.ptr
45+
// CHECK: %[[TI_2_ADDR:.*]] = llvm.mlir.addressof @_ZTIi : !llvm.ptr
46+
// CHECK: %[[LP:.*]] = llvm.landingpad (catch %[[TI_2_ADDR]] : !llvm.ptr) (catch %[[TI_1_ADDR]] : !llvm.ptr) : !llvm.struct<(ptr, i32)>
47+
// CHECK: %[[EXCEPTION_PTR:.*]] = llvm.extractvalue %[[LP]][0] : !llvm.struct<(ptr, i32)>
48+
// CHECK: %[[TYPE_ID:.*]] = llvm.extractvalue %[[LP]][1] : !llvm.struct<(ptr, i32)>
49+
// CHECK: llvm.return
50+
// CHECK: }
51+
52+
53+
}

0 commit comments

Comments
 (0)