[clang] [CIR] Implement flattening for cleanup scopes with multiple exits (PR #180627)
Henrich Lauko via cfe-commits
cfe-commits at lists.llvm.org
Tue Feb 10 02:03:39 PST 2026
================
@@ -768,94 +862,104 @@ class CIRCleanupScopeOpFlattening
rewriter.setInsertionPointToEnd(currentBlock);
cir::BrOp::create(rewriter, loc, bodyEntry);
- // Create a block for the exit terminator (after cleanup, before continue).
+ // Create the exit/dispatch block (after cleanup, before continue).
mlir::Block *exitBlock = rewriter.createBlock(continueBlock);
// Rewrite the cleanup region's yield to branch to exit block.
rewriter.setInsertionPoint(cleanupYield);
rewriter.replaceOpWithNewOp<cir::BrOp>(cleanupYield, exitBlock);
- // Put the appropriate terminator in the exit block.
- rewriter.setInsertionPointToEnd(exitBlock);
- mlir::LogicalResult result =
- llvm::TypeSwitch<mlir::Operation *, mlir::LogicalResult>(exitOp)
- .Case<cir::YieldOp>([&](auto) {
- // Yield becomes a branch to continue block.
- cir::BrOp::create(rewriter, loc, continueBlock);
- return mlir::success();
- })
- .Case<cir::BreakOp>([&](auto) {
- // Break is preserved for later lowering by enclosing switch/loop.
- cir::BreakOp::create(rewriter, loc);
- return mlir::success();
- })
- .Case<cir::ContinueOp>([&](auto) {
- // Continue is preserved for later lowering by enclosing loop.
- cir::ContinueOp::create(rewriter, loc);
- return mlir::success();
- })
- .Case<cir::ReturnOp>([&](auto &returnOp) {
- // Return from the cleanup exit. Note, if this is a return inside
- // a nested cleanup scope, the flattening of the outer scope will
- // handle branching through the outer cleanup.
- if (returnOp.hasOperand())
- cir::ReturnOp::create(rewriter, loc, returnOp.getOperands());
- else
- cir::ReturnOp::create(rewriter, loc);
- return mlir::success();
- })
- .Case<cir::GotoOp>([&](auto &gotoOp) {
- // Correct goto handling requires determining whether the goto
- // branches out of the cleanup scope or stays within it.
- // Although the goto necessarily exits the cleanup scope in the
- // case where it is the only exit from the scope, it is left
- // as unimplemented for now so that it can be generalized when
- // multi-exit flattening is implemented.
- cir::UnreachableOp::create(rewriter, loc);
- return gotoOp.emitError(
- "goto in cleanup scope is not yet implemented");
- })
- .Default([&](mlir::Operation *op) {
- cir::UnreachableOp::create(rewriter, loc);
- return op->emitError(
- "unexpected terminator in cleanup scope body");
- });
-
- // Replace body exit with branch to cleanup entry.
- rewriter.setInsertionPoint(exitOp);
- rewriter.replaceOpWithNewOp<cir::BrOp>(exitOp, cleanupEntry);
+ mlir::LogicalResult result = mlir::success();
+ if (isMultiExit) {
+ // Build the dispatch switch in the exit block.
+ rewriter.setInsertionPointToEnd(exitBlock);
+
+ // Load the destination slot value.
+ auto slotValue = cir::LoadOp::create(
+ rewriter, loc, destSlot, /*isDeref=*/false,
+ /*isVolatile=*/false, /*alignment=*/mlir::IntegerAttr(),
+ cir::SyncScopeKindAttr(), cir::MemOrderAttr());
+
+ // Create destination blocks for each exit and collect switch case info.
+ llvm::SmallVector<mlir::APInt, 8> caseValues;
+ llvm::SmallVector<mlir::Block *, 8> caseDestinations;
+ llvm::SmallVector<mlir::ValueRange, 8> caseOperands;
+ cir::IntType s32Type =
+ cir::IntType::get(rewriter.getContext(), 32, /*isSigned=*/true);
+
+ for (const CleanupExit &exit : exits) {
+ // Create a block for this destination.
+ mlir::Block *destBlock = rewriter.createBlock(continueBlock);
+ rewriter.setInsertionPointToEnd(destBlock);
+ result =
+ createExitTerminator(exit.exitOp, loc, continueBlock, rewriter);
+
+ // Add to switch cases.
----------------
xlauko wrote:
the following code executes even on failure of createExitTerminator, shouldn;t we bail out sooner?
https://github.com/llvm/llvm-project/pull/180627
More information about the cfe-commits
mailing list