Skip to content

Commit 7fc592a

Browse files
committed
[CIR][CIRGen][NFC] Exceptions: redesign cir.catch in terms of cir.try
Simplify things a bit and remove the propagation of exception in terms of a returned exception value. This also merges cir.catch as part of cir.try and remove the former. Everything that didn't work still doesn't work, nothing new added here. The CatchOp parsing was wrong even before this commit, so for now add an XFAIL with the complete testcase we want to be able to parse soon (incremental work will fix this) in clang/test/CIR/IR/exceptions.cir. More cleanups to come as well, this is just the first part.
1 parent 4ea2ec3 commit 7fc592a

File tree

11 files changed

+276
-347
lines changed

11 files changed

+276
-347
lines changed

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

Lines changed: 24 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -780,8 +780,8 @@ def ConditionOp : CIR_Op<"condition", [
780780

781781
def YieldOp : CIR_Op<"yield", [ReturnLike, Terminator,
782782
ParentOneOf<["IfOp", "ScopeOp", "SwitchOp", "WhileOp", "ForOp", "AwaitOp",
783-
"TernaryOp", "GlobalOp", "DoWhileOp", "CatchOp", "TryOp",
784-
"ArrayCtor", "ArrayDtor"]>]> {
783+
"TernaryOp", "GlobalOp", "DoWhileOp", "TryOp", "ArrayCtor",
784+
"ArrayDtor"]>]> {
785785
let summary = "Represents the default branching behaviour of a region";
786786
let description = [{
787787
The `cir.yield` operation terminates regions on different CIR operations,
@@ -871,7 +871,7 @@ def ContinueOp : CIR_Op<"continue", [Terminator]> {
871871
//===----------------------------------------------------------------------===//
872872

873873
def ResumeOp : CIR_Op<"resume", [ReturnLike, Terminator,
874-
ParentOneOf<["CatchOp"]>]> {
874+
ParentOneOf<["TryOp"]>]> {
875875
let summary = "Resumes execution after not catching exceptions";
876876
let description = [{
877877
The `cir.resume` operation terminates a region on `cir.catch`, "resuming"
@@ -3205,6 +3205,17 @@ def AwaitOp : CIR_Op<"await",
32053205
// TryOp
32063206
//===----------------------------------------------------------------------===//
32073207

3208+
// Represents the unwind region where unwind continues or
3209+
// the program std::terminate's.
3210+
def CatchUnwind : CIRUnitAttr<"CatchUnwind", "unwind"> {
3211+
let storageType = [{ CatchUnwind }];
3212+
}
3213+
3214+
// Represents the catch_all region.
3215+
def CatchAllAttr : CIRUnitAttr<"CatchAll", "all"> {
3216+
let storageType = [{ CatchAllAttr }];
3217+
}
3218+
32083219
def TryOp : CIR_Op<"try",
32093220
[DeclareOpInterfaceMethods<RegionBranchOpInterface>,
32103221
RecursivelySpeculatable, AutomaticAllocationScope,
@@ -3228,67 +3239,26 @@ def TryOp : CIR_Op<"try",
32283239
```
32293240
}];
32303241

3231-
let regions = (region AnyRegion:$body);
3232-
let results = (outs ExceptionInfoPtr:$result);
3242+
let arguments = (ins OptionalAttr<ArrayAttr>:$catch_types);
3243+
let regions = (region AnyRegion:$try_region,
3244+
VariadicRegion<AnyRegion>:$catch_regions);
32333245

32343246
let assemblyFormat = [{
3235-
$body `:` functional-type(operands, results) attr-dict
3247+
$try_region
3248+
custom<CatchRegions>($catch_regions, $catch_types)
3249+
attr-dict
32363250
}];
32373251

32383252
// Everything already covered elsewhere.
32393253
let hasVerifier = 0;
32403254
let builders = [
32413255
OpBuilder<(ins
3242-
"function_ref<void(OpBuilder &, Type &, Location)>":$tryBuilder)>,
3256+
"function_ref<void(OpBuilder &, Location)>":$tryBuilder,
3257+
"function_ref<void(OpBuilder &, Location, OperationState &)>"
3258+
:$catchBuilder)>,
32433259
];
32443260
}
32453261

3246-
//===----------------------------------------------------------------------===//
3247-
// CatchOp
3248-
//===----------------------------------------------------------------------===//
3249-
3250-
// Represents the unwind region where unwind continues or
3251-
// the program std::terminate's.
3252-
def CatchUnwind : CIRUnitAttr<"CatchUnwind", "unwind"> {
3253-
let storageType = [{ CatchUnwind }];
3254-
}
3255-
3256-
// Represents the catch_all region.
3257-
def CatchAllAttr : CIRUnitAttr<"CatchAll", "all"> {
3258-
let storageType = [{ CatchAllAttr }];
3259-
}
3260-
3261-
def CatchOp : CIR_Op<"catch",
3262-
[SameVariadicOperandSize,
3263-
DeclareOpInterfaceMethods<RegionBranchOpInterface>,
3264-
RecursivelySpeculatable, NoRegionArguments]> {
3265-
let summary = "Catch operation";
3266-
let description = [{
3267-
}];
3268-
3269-
let arguments = (ins CIR_AnyType:$exception_info,
3270-
OptionalAttr<ArrayAttr>:$catchers);
3271-
let regions = (region VariadicRegion<AnyRegion>:$regions);
3272-
3273-
// Already verified elsewhere
3274-
let hasVerifier = 0;
3275-
3276-
let skipDefaultBuilders = 1;
3277-
let builders = [
3278-
OpBuilder<(ins
3279-
"Value":$exception_info,
3280-
"function_ref<void(OpBuilder &, Location, OperationState &)>"
3281-
:$catchBuilder)>
3282-
];
3283-
3284-
let assemblyFormat = [{
3285-
`(`
3286-
$exception_info `:` type($exception_info) `,`
3287-
custom<CatchOp>($regions, $catchers)
3288-
`)` attr-dict
3289-
}];
3290-
}
3291-
32923262
//===----------------------------------------------------------------------===//
32933263
// CatchParamOp
32943264
//===----------------------------------------------------------------------===//
@@ -3306,10 +3276,9 @@ def CatchParamOp : CIR_Op<"catch_param"> {
33063276
```
33073277
}];
33083278

3309-
let arguments = (ins ExceptionInfoPtr:$exception_info);
33103279
let results = (outs CIR_AnyType:$param);
33113280
let assemblyFormat = [{
3312-
`(` $exception_info `)` `->` qualified(type($param)) attr-dict
3281+
`->` qualified(type($param)) attr-dict
33133282
}];
33143283

33153284
let hasVerifier = 0;

clang/lib/CIR/CodeGen/CIRGenCleanup.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ class EHCatchScope : public EHScope {
206206
// 'takeHandler' or some such function which removes ownership from the
207207
// EHCatchScope object if the handlers should live longer than EHCatchScope.
208208
void clearHandlerBlocks() {
209-
// The blocks are owned by CatchOp, nothing to delete.
209+
// The blocks are owned by TryOp, nothing to delete.
210210
}
211211

212212
typedef const Handler *iterator;

clang/lib/CIR/CodeGen/CIRGenException.cpp

Lines changed: 44 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -257,8 +257,9 @@ mlir::Block *CIRGenFunction::getEHResumeBlock(bool isCleanup) {
257257
// pointer but only use it to denote we're tracking things, but there
258258
// shouldn't be any changes to that block after work done in this function.
259259
auto catchOp = currLexScope->getExceptionInfo().catchOp;
260-
assert(catchOp && catchOp.getNumRegions() && "expected at least one region");
261-
auto &fallbackRegion = catchOp.getRegion(catchOp.getNumRegions() - 1);
260+
unsigned numCatchRegions = catchOp.getCatchRegions().size();
261+
assert(catchOp && numCatchRegions && "expected at least one region");
262+
auto &fallbackRegion = catchOp.getCatchRegions()[numCatchRegions - 1];
262263

263264
auto *resumeBlock = &fallbackRegion.getBlocks().back();
264265
if (!resumeBlock->empty())
@@ -322,7 +323,6 @@ CIRGenFunction::buildCXXTryStmtUnderScope(const CXXTryStmt &S) {
322323

323324
auto numHandlers = S.getNumHandlers();
324325
auto tryLoc = getLoc(S.getBeginLoc());
325-
auto scopeLoc = getLoc(S.getSourceRange());
326326

327327
mlir::OpBuilder::InsertPoint beginInsertTryBody;
328328
auto ehPtrTy = mlir::cir::PointerType::get(
@@ -335,28 +335,21 @@ CIRGenFunction::buildCXXTryStmtUnderScope(const CXXTryStmt &S) {
335335
// info but don't emit the bulk right away, for now only make sure the
336336
// scope returns the exception information.
337337
auto tryScope = builder.create<mlir::cir::TryOp>(
338-
scopeLoc, /*scopeBuilder=*/
339-
[&](mlir::OpBuilder &b, mlir::Type &yieldTy, mlir::Location loc) {
338+
tryLoc, /*scopeBuilder=*/
339+
[&](mlir::OpBuilder &b, mlir::Location loc) {
340340
// Allocate space for our exception info that might be passed down
341341
// to `cir.try_call` everytime a call happens.
342-
yieldTy = ehPtrTy;
343342
exceptionInfoInsideTry = b.create<mlir::cir::AllocaOp>(
344-
loc, /*addr type*/ getBuilder().getPointerTo(yieldTy),
345-
/*var type*/ yieldTy, "__exception_ptr",
343+
loc, /*addr type*/ getBuilder().getPointerTo(ehPtrTy),
344+
/*var type*/ ehPtrTy, "__exception_ptr",
346345
CGM.getSize(CharUnits::One()), nullptr);
347346

348347
beginInsertTryBody = getBuilder().saveInsertionPoint();
349-
});
350-
351-
// The catch {} parts consume the exception information provided by a
352-
// try scope. Also don't emit the code right away for catch clauses, for
353-
// now create the regions and consume the try scope result.
354-
// Note that clauses are later populated in
355-
// CIRGenFunction::buildLandingPad.
356-
auto catchOp = builder.create<mlir::cir::CatchOp>(
357-
tryLoc,
358-
tryScope->getResult(
359-
0), // FIXME(cir): we can do better source location here.
348+
},
349+
// Don't emit the code right away for catch clauses, for
350+
// now create the regions and consume the try scope result.
351+
// Note that clauses are later populated in
352+
// CIRGenFunction::buildLandingPad.
360353
[&](mlir::OpBuilder &b, mlir::Location loc,
361354
mlir::OperationState &result) {
362355
mlir::OpBuilder::InsertionGuard guard(b);
@@ -372,28 +365,24 @@ CIRGenFunction::buildCXXTryStmtUnderScope(const CXXTryStmt &S) {
372365

373366
// Finally emit the body for try/catch.
374367
auto emitTryCatchBody = [&]() -> mlir::LogicalResult {
375-
auto loc = catchOp.getLoc();
368+
auto loc = tryScope.getLoc();
376369
mlir::OpBuilder::InsertionGuard guard(getBuilder());
377370
getBuilder().restoreInsertionPoint(beginInsertTryBody);
378371
CIRGenFunction::LexicalScope lexScope{*this, loc,
379372
getBuilder().getInsertionBlock()};
380373

381374
{
382-
lexScope.setExceptionInfo({exceptionInfoInsideTry, catchOp});
383-
// Attach the basic blocks for the catchOp regions into ScopeCatch
384-
// info.
385-
enterCXXTryStmt(S, catchOp);
375+
lexScope.setExceptionInfo({exceptionInfoInsideTry, tryScope});
376+
// Attach the basic blocks for the catch regions.
377+
enterCXXTryStmt(S, tryScope);
386378
// Emit the body for the `try {}` part.
387379
if (buildStmt(S.getTryBlock(), /*useCurrentScope=*/true).failed())
388380
return mlir::failure();
389-
390-
auto v = getBuilder().create<mlir::cir::LoadOp>(loc, ehPtrTy,
391-
exceptionInfoInsideTry);
392-
getBuilder().create<mlir::cir::YieldOp>(loc, v.getResult());
381+
getBuilder().create<mlir::cir::YieldOp>(loc);
393382
}
394383

395384
{
396-
lexScope.setExceptionInfo({tryScope->getResult(0), catchOp});
385+
lexScope.setExceptionInfo({nullptr, tryScope});
397386
// Emit catch clauses.
398387
exitCXXTryStmt(S);
399388
}
@@ -452,7 +441,7 @@ static void buildCatchDispatchBlock(CIRGenFunction &CGF,
452441
// If the next handler is a catch-all, we're at the end, and the
453442
// next block is that handler.
454443
} else if (catchScope.getHandler(i + 1).isCatchAll()) {
455-
// Block already created when creating CatchOp, just mark this
444+
// Block already created when creating catch regions, just mark this
456445
// is the end.
457446
nextIsEnd = true;
458447
}
@@ -464,14 +453,14 @@ static void buildCatchDispatchBlock(CIRGenFunction &CGF,
464453
}
465454

466455
void CIRGenFunction::enterCXXTryStmt(const CXXTryStmt &S,
467-
mlir::cir::CatchOp catchOp,
456+
mlir::cir::TryOp catchOp,
468457
bool IsFnTryBlock) {
469458
unsigned NumHandlers = S.getNumHandlers();
470459
EHCatchScope *CatchScope = EHStack.pushCatch(NumHandlers);
471460
for (unsigned I = 0; I != NumHandlers; ++I) {
472461
const CXXCatchStmt *C = S.getHandler(I);
473462

474-
mlir::Block *Handler = &catchOp.getRegion(I).getBlocks().front();
463+
mlir::Block *Handler = &catchOp.getCatchRegions()[I].getBlocks().front();
475464
if (C->getExceptionDecl()) {
476465
// FIXME: Dropping the reference type on the type into makes it
477466
// impossible to correctly implement catch-by-reference
@@ -510,7 +499,18 @@ void CIRGenFunction::exitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) {
510499
if (!CatchScope.hasEHBranches()) {
511500
CatchScope.clearHandlerBlocks();
512501
EHStack.popCatch();
513-
currLexScope->getExceptionInfo().catchOp->erase();
502+
// Drop all basic block from all catch regions.
503+
auto tryOp = currLexScope->getExceptionInfo().catchOp;
504+
SmallVector<mlir::Block *> eraseBlocks;
505+
for (mlir::Region &r : tryOp.getCatchRegions()) {
506+
if (r.empty())
507+
continue;
508+
for (mlir::Block &b : r.getBlocks())
509+
eraseBlocks.push_back(&b);
510+
}
511+
for (mlir::Block *b : eraseBlocks)
512+
b->erase();
513+
tryOp.setCatchTypesAttr({});
514514
return;
515515
}
516516

@@ -630,43 +630,13 @@ mlir::Operation *CIRGenFunction::buildLandingPad() {
630630
return lpad;
631631
}
632632

633-
// If there's an existing CatchOp, it means we got a `cir.try` scope
633+
// If there's an existing TryOp, it means we got a `cir.try` scope
634634
// that leads to this "landing pad" creation site. Otherwise, exceptions
635-
// are enabled but a throwing function is called anyways.
636-
auto catchOp = currLexScope->getExceptionInfo().catchOp;
637-
if (!catchOp) {
638-
auto loc = *currSrcLoc;
639-
auto ehPtrTy = mlir::cir::PointerType::get(
640-
getBuilder().getContext(),
641-
getBuilder().getType<::mlir::cir::ExceptionInfoType>());
642-
643-
mlir::Value exceptionAddr;
644-
{
645-
// Get a new alloca within the current scope.
646-
mlir::OpBuilder::InsertionGuard guard(builder);
647-
exceptionAddr = buildAlloca(
648-
"__exception_ptr", ehPtrTy, loc, CharUnits::One(),
649-
builder.getBestAllocaInsertPoint(builder.getInsertionBlock()));
650-
}
651-
652-
{
653-
// Insert catch at the end of the block, and place the insert pointer
654-
// back to where it was.
655-
mlir::OpBuilder::InsertionGuard guard(builder);
656-
auto exceptionPtr =
657-
builder.create<mlir::cir::LoadOp>(loc, ehPtrTy, exceptionAddr);
658-
catchOp = builder.create<mlir::cir::CatchOp>(
659-
loc, exceptionPtr,
660-
[&](mlir::OpBuilder &b, mlir::Location loc,
661-
mlir::OperationState &result) {
662-
// There's no source code level catch here, create one region for
663-
// the resume block.
664-
mlir::OpBuilder::InsertionGuard guard(b);
665-
auto *r = result.addRegion();
666-
builder.createBlock(r);
667-
});
668-
}
669-
currLexScope->setExceptionInfo({exceptionAddr, catchOp});
635+
// are enabled but a throwing function is called anyways (common pattern
636+
// with function local static initializers).
637+
auto tryOp = currLexScope->getExceptionInfo().catchOp;
638+
if (!tryOp) {
639+
llvm_unreachable("NYI");
670640
}
671641

672642
{
@@ -752,17 +722,17 @@ mlir::Operation *CIRGenFunction::buildLandingPad() {
752722
assert(!MissingFeatures::setLandingPadCleanup());
753723
}
754724

755-
assert((clauses.size() > 0 || hasCleanup) && "CatchOp has no clauses!");
725+
assert((clauses.size() > 0 || hasCleanup) && "no catch clauses!");
756726

757727
// If there's no catch_all, attach the unwind region. This needs to be the
758-
// last region in the CatchOp operation.
728+
// last region in the TryOp operation catch list.
759729
if (!hasCatchAll) {
760730
auto catchUnwind = mlir::cir::CatchUnwindAttr::get(builder.getContext());
761731
clauses.push_back(catchUnwind);
762732
}
763733

764-
// Add final array of clauses into catchOp.
765-
catchOp.setCatchersAttr(
734+
// Add final array of clauses into TryOp.
735+
tryOp.setCatchTypesAttr(
766736
mlir::ArrayAttr::get(builder.getContext(), clauses));
767737

768738
// In traditional LLVM codegen. this tells the backend how to generate the
@@ -772,7 +742,7 @@ mlir::Operation *CIRGenFunction::buildLandingPad() {
772742
(void)getEHDispatchBlock(EHStack.getInnermostEHScope());
773743
}
774744

775-
return catchOp;
745+
return tryOp;
776746
}
777747

778748
// Differently from LLVM traditional codegen, there are no dispatch blocks

clang/lib/CIR/CodeGen/CIRGenFunction.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ class CIRGenFunction : public CIRGenTypeCache {
316316
/// allocas for the exception info
317317
struct CIRExceptionInfo {
318318
mlir::Value addr{};
319-
mlir::cir::CatchOp catchOp{};
319+
mlir::cir::TryOp catchOp{};
320320
};
321321

322322
enum class EvaluationOrder {
@@ -940,7 +940,7 @@ class CIRGenFunction : public CIRGenTypeCache {
940940

941941
mlir::LogicalResult buildCXXTryStmtUnderScope(const clang::CXXTryStmt &S);
942942
mlir::LogicalResult buildCXXTryStmt(const clang::CXXTryStmt &S);
943-
void enterCXXTryStmt(const CXXTryStmt &S, mlir::cir::CatchOp catchOp,
943+
void enterCXXTryStmt(const CXXTryStmt &S, mlir::cir::TryOp catchOp,
944944
bool IsFnTryBlock = false);
945945
void exitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock = false);
946946

0 commit comments

Comments
 (0)