aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/CIR/CodeGen/CIRGenException.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/CIR/CodeGen/CIRGenException.cpp')
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenException.cpp151
1 files changed, 149 insertions, 2 deletions
diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp b/clang/lib/CIR/CodeGen/CIRGenException.cpp
index f9ff37b..717a3e0 100644
--- a/clang/lib/CIR/CodeGen/CIRGenException.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp
@@ -69,6 +69,153 @@ mlir::LogicalResult CIRGenFunction::emitCXXTryStmt(const CXXTryStmt &s) {
if (s.getTryBlock()->body_empty())
return mlir::LogicalResult::success();
- cgm.errorNYI("exitCXXTryStmt: CXXTryStmt with non-empty body");
- return mlir::LogicalResult::success();
+ mlir::Location loc = getLoc(s.getSourceRange());
+ // Create a scope to hold try local storage for catch params.
+
+ mlir::OpBuilder::InsertPoint scopeIP;
+ cir::ScopeOp::create(
+ builder, loc,
+ /*scopeBuilder=*/[&](mlir::OpBuilder &b, mlir::Location loc) {
+ scopeIP = builder.saveInsertionPoint();
+ });
+
+ mlir::OpBuilder::InsertionGuard guard(builder);
+ builder.restoreInsertionPoint(scopeIP);
+ mlir::LogicalResult result = emitCXXTryStmtUnderScope(s);
+ cir::YieldOp::create(builder, loc);
+ return result;
+}
+
+mlir::LogicalResult
+CIRGenFunction::emitCXXTryStmtUnderScope(const CXXTryStmt &s) {
+ const llvm::Triple &t = getTarget().getTriple();
+ // If we encounter a try statement on in an OpenMP target region offloaded to
+ // a GPU, we treat it as a basic block.
+ const bool isTargetDevice =
+ (cgm.getLangOpts().OpenMPIsTargetDevice && (t.isNVPTX() || t.isAMDGCN()));
+ if (isTargetDevice) {
+ cgm.errorNYI(
+ "emitCXXTryStmtUnderScope: OpenMP target region offloaded to GPU");
+ return mlir::success();
+ }
+
+ unsigned numHandlers = s.getNumHandlers();
+ mlir::Location tryLoc = getLoc(s.getBeginLoc());
+ mlir::OpBuilder::InsertPoint beginInsertTryBody;
+
+ bool hasCatchAll = false;
+ for (unsigned i = 0; i != numHandlers; ++i) {
+ hasCatchAll |= s.getHandler(i)->getExceptionDecl() == nullptr;
+ if (hasCatchAll)
+ break;
+ }
+
+ // Create the scope to represent only the C/C++ `try {}` part. However,
+ // don't populate right away. Create regions for the catch handlers,
+ // but don't emit the handler bodies yet. For now, only make sure the
+ // scope returns the exception information.
+ auto tryOp = cir::TryOp::create(
+ builder, tryLoc,
+ /*tryBuilder=*/
+ [&](mlir::OpBuilder &b, mlir::Location loc) {
+ beginInsertTryBody = builder.saveInsertionPoint();
+ },
+ /*handlersBuilder=*/
+ [&](mlir::OpBuilder &b, mlir::Location loc,
+ mlir::OperationState &result) {
+ mlir::OpBuilder::InsertionGuard guard(b);
+
+ // We create an extra region for an unwind catch handler in case the
+ // catch-all handler doesn't exists
+ unsigned numRegionsToCreate =
+ hasCatchAll ? numHandlers : numHandlers + 1;
+
+ for (unsigned i = 0; i != numRegionsToCreate; ++i) {
+ mlir::Region *region = result.addRegion();
+ builder.createBlock(region);
+ }
+ });
+
+ // Finally emit the body for try/catch.
+ {
+ mlir::Location loc = tryOp.getLoc();
+ mlir::OpBuilder::InsertionGuard guard(builder);
+ builder.restoreInsertionPoint(beginInsertTryBody);
+ CIRGenFunction::LexicalScope tryScope{*this, loc,
+ builder.getInsertionBlock()};
+
+ tryScope.setAsTry(tryOp);
+
+ // Attach the basic blocks for the catch regions.
+ enterCXXTryStmt(s, tryOp);
+
+ // Emit the body for the `try {}` part.
+ {
+ mlir::OpBuilder::InsertionGuard guard(builder);
+ CIRGenFunction::LexicalScope tryBodyScope{*this, loc,
+ builder.getInsertionBlock()};
+ if (emitStmt(s.getTryBlock(), /*useCurrentScope=*/true).failed())
+ return mlir::failure();
+ }
+
+ // Emit catch clauses.
+ exitCXXTryStmt(s);
+ }
+
+ return mlir::success();
+}
+
+void CIRGenFunction::enterCXXTryStmt(const CXXTryStmt &s, cir::TryOp tryOp,
+ bool isFnTryBlock) {
+ unsigned numHandlers = s.getNumHandlers();
+ EHCatchScope *catchScope = ehStack.pushCatch(numHandlers);
+ for (unsigned i = 0; i != numHandlers; ++i) {
+ const CXXCatchStmt *catchStmt = s.getHandler(i);
+ if (catchStmt->getExceptionDecl()) {
+ cgm.errorNYI("enterCXXTryStmt: CatchStmt with ExceptionDecl");
+ return;
+ }
+
+ // No exception decl indicates '...', a catch-all.
+ mlir::Region *handler = &tryOp.getHandlerRegions()[i];
+ catchScope->setHandler(i, cgm.getCXXABI().getCatchAllTypeInfo(), handler);
+
+ // Under async exceptions, catch(...) needs to catch HW exception too
+ // Mark scope with SehTryBegin as a SEH __try scope
+ if (getLangOpts().EHAsynch) {
+ cgm.errorNYI("enterCXXTryStmt: EHAsynch");
+ return;
+ }
+ }
+}
+
+void CIRGenFunction::exitCXXTryStmt(const CXXTryStmt &s, bool isFnTryBlock) {
+ unsigned numHandlers = s.getNumHandlers();
+ EHCatchScope &catchScope = cast<EHCatchScope>(*ehStack.begin());
+ assert(catchScope.getNumHandlers() == numHandlers);
+ cir::TryOp tryOp = curLexScope->getTry();
+
+ // If the catch was not required, bail out now.
+ if (!catchScope.mayThrow()) {
+ catchScope.clearHandlerBlocks();
+ ehStack.popCatch();
+
+ // Drop all basic block from all catch regions.
+ SmallVector<mlir::Block *> eraseBlocks;
+ for (mlir::Region &handlerRegion : tryOp.getHandlerRegions()) {
+ if (handlerRegion.empty())
+ continue;
+
+ for (mlir::Block &b : handlerRegion.getBlocks())
+ eraseBlocks.push_back(&b);
+ }
+
+ for (mlir::Block *b : eraseBlocks)
+ b->erase();
+
+ tryOp.setHandlerTypesAttr({});
+ return;
+ }
+
+ cgm.errorNYI("exitCXXTryStmt: Required catch");
}