Skip to content

Commit 7837cc3

Browse files
committed
[CIR] Upstream CIR Dialect TryOp with Catch Attrs
1 parent c89d721 commit 7837cc3

File tree

4 files changed

+292
-2
lines changed

4 files changed

+292
-2
lines changed

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -968,4 +968,19 @@ def CIR_TypeInfoAttr : CIR_Attr<"TypeInfo", "typeinfo", [TypedAttrInterface]> {
968968
}];
969969
}
970970

971+
//===----------------------------------------------------------------------===//
972+
// CatchAllAttr & CatchUnwindAttr
973+
//===----------------------------------------------------------------------===//
974+
975+
// Represents the unwind region where unwind continues or
976+
// the program std::terminate's.
977+
def CIR_CatchUnwindAttr : CIR_UnitAttr<"CatchUnwind", "unwind"> {
978+
let storageType = [{ CatchUnwind }];
979+
}
980+
981+
// Represents the catch_all region.
982+
def CIR_CatchAllAttr : CIR_UnitAttr<"CatchAll", "all"> {
983+
let storageType = [{ CatchAllAttr }];
984+
}
985+
971986
#endif // CLANG_CIR_DIALECT_IR_CIRATTRS_TD

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

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -644,7 +644,7 @@ def CIR_StoreOp : CIR_Op<"store", [
644644

645645
defvar CIR_ReturnableScopes = [
646646
"FuncOp", "ScopeOp", "IfOp", "SwitchOp", "CaseOp",
647-
"DoWhileOp", "WhileOp", "ForOp"
647+
"DoWhileOp", "WhileOp", "ForOp", "TryOp"
648648
];
649649

650650
def CIR_ReturnOp : CIR_Op<"return", [
@@ -791,7 +791,7 @@ def CIR_ConditionOp : CIR_Op<"condition", [
791791

792792
defvar CIR_YieldableScopes = [
793793
"ArrayCtor", "ArrayDtor", "CaseOp", "DoWhileOp", "ForOp", "GlobalOp", "IfOp",
794-
"ScopeOp", "SwitchOp", "TernaryOp", "WhileOp"
794+
"ScopeOp", "SwitchOp", "TernaryOp", "WhileOp", "TryOp"
795795
];
796796

797797
def CIR_YieldOp : CIR_Op<"yield", [
@@ -4325,6 +4325,65 @@ def CIR_AllocExceptionOp : CIR_Op<"alloc.exception"> {
43254325
}];
43264326
}
43274327

4328+
//===----------------------------------------------------------------------===//
4329+
// TryOp
4330+
//===----------------------------------------------------------------------===//
4331+
4332+
def CIR_TryOp : CIR_Op<"try",[
4333+
DeclareOpInterfaceMethods<RegionBranchOpInterface>,
4334+
RecursivelySpeculatable, AutomaticAllocationScope, NoRegionArguments
4335+
]> {
4336+
let summary = "C++ try block";
4337+
let description = [{
4338+
Holds the lexical scope of `try {}`. Note that resources used on catch
4339+
clauses are usually allocated in the same parent as `cir.try`.
4340+
4341+
`synthetic`: use `cir.try` to represent try/catches not originally
4342+
present in the source code (e.g. `g = new Class` under `-fexceptions`).
4343+
4344+
`cleanup`: signal to targets (LLVM for now) that this try/catch, needs
4345+
to specially tag their landing pads as needing "cleanup".
4346+
4347+
Example:
4348+
4349+
```mlir
4350+
%0 = cir.alloc.exception 16 -> !cir.ptr<!some_record>
4351+
%1 = cir.get_global @d2 : !cir.ptr<!some_record>
4352+
cir.try synthetic cleanup {
4353+
cir.call exception @_ZN7test2_DC1ERKS_(%0, %1)
4354+
: (!cir.ptr<!some_record>, !cir.ptr<!some_record>) -> () cleanup {
4355+
%2 = cir.cast bitcast %0 : !cir.ptr<!some_record> -> !cir.ptr<!void>
4356+
cir.free.exception %2
4357+
cir.yield
4358+
}
4359+
...
4360+
}
4361+
```
4362+
}];
4363+
4364+
let arguments = (ins UnitAttr:$synthetic, UnitAttr:$cleanup,
4365+
OptionalAttr<ArrayAttr>:$catch_types);
4366+
let regions = (region AnyRegion:$try_region,
4367+
VariadicRegion<AnyRegion>:$catch_regions);
4368+
4369+
let assemblyFormat = [{
4370+
(`synthetic` $synthetic^)?
4371+
(`cleanup` $cleanup^)?
4372+
$try_region
4373+
custom<CatchRegions>($catch_regions, $catch_types)
4374+
attr-dict
4375+
}];
4376+
4377+
// Everything already covered elsewhere.
4378+
let builders = [OpBuilder<(ins
4379+
"llvm::function_ref<void(mlir::OpBuilder &, "
4380+
"mlir::Location)>":$tryBuilder,
4381+
"llvm::function_ref<void(mlir::OpBuilder &, mlir::Location, "
4382+
"mlir::OperationState &)>":$catchBuilder)>];
4383+
4384+
let hasLLVMLowering = false;
4385+
}
4386+
43284387
//===----------------------------------------------------------------------===//
43294388
// Atomic operations
43304389
//===----------------------------------------------------------------------===//

clang/lib/CIR/Dialect/IR/CIRDialect.cpp

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2914,6 +2914,138 @@ LogicalResult cir::TypeInfoAttr::verify(
29142914
return success();
29152915
}
29162916

2917+
//===----------------------------------------------------------------------===//
2918+
// TryOp
2919+
//===----------------------------------------------------------------------===//
2920+
2921+
void cir::TryOp::build(
2922+
OpBuilder &builder, OperationState &result,
2923+
function_ref<void(OpBuilder &, Location)> tryBuilder,
2924+
function_ref<void(OpBuilder &, Location, OperationState &)> catchBuilder) {
2925+
assert(tryBuilder && "expected builder callback for 'cir.try' body");
2926+
assert(catchBuilder && "expected builder callback for 'catch' body");
2927+
2928+
OpBuilder::InsertionGuard guard(builder);
2929+
2930+
// Try body region
2931+
Region *tryBodyRegion = result.addRegion();
2932+
2933+
// Create try body region and set insertion point
2934+
builder.createBlock(tryBodyRegion);
2935+
tryBuilder(builder, result.location);
2936+
catchBuilder(builder, result.location, result);
2937+
}
2938+
2939+
void cir::TryOp::getSuccessorRegions(
2940+
mlir::RegionBranchPoint point, SmallVectorImpl<RegionSuccessor> &regions) {
2941+
// If any index all the underlying regions branch back to the parent
2942+
// operation.
2943+
if (!point.isParent()) {
2944+
regions.push_back(RegionSuccessor());
2945+
return;
2946+
}
2947+
2948+
// If the condition isn't constant, both regions may be executed.
2949+
regions.push_back(RegionSuccessor(&getTryRegion()));
2950+
2951+
// FIXME: optimize, ideas include:
2952+
// - If we know a target function never throws a specific type, we can
2953+
// remove the catch handler.
2954+
for (mlir::Region &r : this->getCatchRegions())
2955+
regions.push_back(RegionSuccessor(&r));
2956+
}
2957+
2958+
static void printCatchRegions(OpAsmPrinter &printer, cir::TryOp op,
2959+
mlir::MutableArrayRef<::mlir::Region> regions,
2960+
mlir::ArrayAttr catchersAttr) {
2961+
if (!catchersAttr)
2962+
return;
2963+
2964+
int currCatchIdx = 0;
2965+
printer << "catch [";
2966+
llvm::interleaveComma(catchersAttr, printer, [&](const Attribute &a) {
2967+
if (mlir::isa<cir::CatchUnwindAttr>(a)) {
2968+
printer.printAttribute(a);
2969+
printer << " ";
2970+
} else if (!a) {
2971+
printer << "all";
2972+
} else {
2973+
printer << "type ";
2974+
printer.printAttribute(a);
2975+
printer << " ";
2976+
}
2977+
printer.printRegion(regions[currCatchIdx], /*printEntryBLockArgs=*/false,
2978+
/*printBlockTerminators=*/true);
2979+
currCatchIdx++;
2980+
});
2981+
2982+
printer << "]";
2983+
}
2984+
2985+
static ParseResult parseCatchRegions(
2986+
OpAsmParser &parser,
2987+
llvm::SmallVectorImpl<std::unique_ptr<::mlir::Region>> &regions,
2988+
::mlir::ArrayAttr &catchersAttr) {
2989+
if (parser.parseKeyword("catch").failed())
2990+
return parser.emitError(parser.getCurrentLocation(),
2991+
"expected 'catch' keyword here");
2992+
2993+
auto parseAndCheckRegion = [&]() -> ParseResult {
2994+
// Parse region attached to catch
2995+
regions.emplace_back(new Region);
2996+
Region &currRegion = *regions.back();
2997+
SMLoc parserLoc = parser.getCurrentLocation();
2998+
if (parser.parseRegion(currRegion)) {
2999+
regions.clear();
3000+
return failure();
3001+
}
3002+
3003+
if (currRegion.empty()) {
3004+
return parser.emitError(parser.getCurrentLocation(),
3005+
"catch region shall not be empty");
3006+
}
3007+
3008+
if (!(currRegion.back().mightHaveTerminator() &&
3009+
currRegion.back().getTerminator()))
3010+
return parser.emitError(
3011+
parserLoc, "blocks are expected to be explicitly terminated");
3012+
3013+
return success();
3014+
};
3015+
3016+
llvm::SmallVector<mlir::Attribute, 4> catchList;
3017+
auto parseCatchEntry = [&]() -> ParseResult {
3018+
mlir::Attribute exceptionTypeInfo;
3019+
3020+
if (parser.parseOptionalAttribute(exceptionTypeInfo).has_value()) {
3021+
catchList.push_back(exceptionTypeInfo);
3022+
} else {
3023+
::llvm::StringRef attrStr;
3024+
if (parser.parseOptionalKeyword(&attrStr, {"all"}).succeeded()) {
3025+
// "all" keyword found, exceptionTypeInfo remains null
3026+
} else if (parser.parseOptionalKeyword("type").succeeded()) {
3027+
if (parser.parseAttribute(exceptionTypeInfo).failed())
3028+
return parser.emitError(parser.getCurrentLocation(),
3029+
"expected valid RTTI info attribute");
3030+
} else {
3031+
return parser.emitError(parser.getCurrentLocation(),
3032+
"expected attribute, 'all', or 'type' keyword");
3033+
}
3034+
catchList.push_back(exceptionTypeInfo);
3035+
}
3036+
return parseAndCheckRegion();
3037+
};
3038+
3039+
if (parser
3040+
.parseCommaSeparatedList(OpAsmParser::Delimiter::Square,
3041+
parseCatchEntry, " in catch list")
3042+
.failed())
3043+
return failure();
3044+
3045+
catchersAttr = parser.getBuilder().getArrayAttr(catchList);
3046+
return ::mlir::success();
3047+
}
3048+
29173049
//===----------------------------------------------------------------------===//
29183050
// TableGen'd op method definitions
29193051
//===----------------------------------------------------------------------===//

clang/test/CIR/IR/try-catch.cir

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// RUN: cir-opt %s --verify-roundtrip | FileCheck %s
2+
3+
!u8i = !cir.int<u, 8>
4+
5+
module {
6+
7+
cir.global "private" constant external @_ZTIi : !cir.ptr<!u8i>
8+
cir.global "private" constant external @_ZTIPKc : !cir.ptr<!u8i>
9+
10+
cir.func dso_local @empty_try_block_with_catch_all() {
11+
cir.scope {
12+
cir.try {
13+
cir.yield
14+
} catch [type #cir.all {
15+
cir.yield
16+
}]
17+
}
18+
cir.return
19+
}
20+
21+
// CHECK: cir.func dso_local @empty_try_block_with_catch_all() {
22+
// CHECK: cir.scope {
23+
// CHECK: cir.try {
24+
// CHECK: cir.yield
25+
// CHECK: } catch [type #cir.all {
26+
// CHECK: cir.yield
27+
// CHECK: }]
28+
// CHECK: }
29+
// CHECK: cir.return
30+
// CHECK: }
31+
32+
cir.func dso_local @empty_try_block_with_catch_unwind() {
33+
cir.scope {
34+
cir.try {
35+
cir.yield
36+
} catch [#cir.unwind {
37+
cir.yield
38+
}]
39+
}
40+
cir.return
41+
}
42+
43+
// CHECK: cir.func dso_local @empty_try_block_with_catch_unwind() {
44+
// CHECK: cir.scope {
45+
// CHECK: cir.try {
46+
// CHECK: cir.yield
47+
// CHECK: } catch [#cir.unwind {
48+
// CHECK: cir.yield
49+
// CHECK: }]
50+
// CHECK: }
51+
// CHECK: cir.return
52+
// CHECK: }
53+
54+
cir.func dso_local @empty_try_block_with_catch_ist() {
55+
cir.scope {
56+
cir.try {
57+
cir.yield
58+
} catch [type #cir.global_view<@_ZTIi> : !cir.ptr<!u8i> {
59+
cir.yield
60+
}, type #cir.global_view<@_ZTIPKc> : !cir.ptr<!u8i> {
61+
cir.yield
62+
}, #cir.unwind {
63+
cir.yield
64+
}]
65+
}
66+
cir.return
67+
}
68+
69+
// CHECK: cir.func dso_local @empty_try_block_with_catch_ist() {
70+
// CHECK: cir.scope {
71+
// CHECK: cir.try {
72+
// CHECK: cir.yield
73+
// CHECK: } catch [type #cir.global_view<@_ZTIi> : !cir.ptr<!u8i> {
74+
// CHECK: cir.yield
75+
// CHECK: }, type #cir.global_view<@_ZTIPKc> : !cir.ptr<!u8i> {
76+
// CHECK: cir.yield
77+
// CHECK: }, #cir.unwind {
78+
// CHECK: cir.yield
79+
// CHECK: }]
80+
// CHECK: }
81+
// CHECK: cir.return
82+
// CHECK: }
83+
84+
}

0 commit comments

Comments
 (0)