@@ -69,6 +69,153 @@ mlir::LogicalResult CIRGenFunction::emitCXXTryStmt(const CXXTryStmt &s) {
6969 if (s.getTryBlock ()->body_empty ())
7070 return mlir::LogicalResult::success ();
7171
72- cgm.errorNYI (" exitCXXTryStmt: CXXTryStmt with non-empty body" );
73- return mlir::LogicalResult::success ();
72+ mlir::Location loc = getLoc (s.getSourceRange ());
73+ // Create a scope to hold try local storage for catch params.
74+
75+ mlir::OpBuilder::InsertPoint scopeIP;
76+ cir::ScopeOp::create (
77+ builder, loc,
78+ /* scopeBuilder=*/ [&](mlir::OpBuilder &b, mlir::Location loc) {
79+ scopeIP = builder.saveInsertionPoint ();
80+ });
81+
82+ mlir::OpBuilder::InsertionGuard guard (builder);
83+ builder.restoreInsertionPoint (scopeIP);
84+ mlir::LogicalResult result = emitCXXTryStmtUnderScope (s);
85+ cir::YieldOp::create (builder, loc);
86+ return result;
87+ }
88+
89+ mlir::LogicalResult
90+ CIRGenFunction::emitCXXTryStmtUnderScope (const CXXTryStmt &s) {
91+ const llvm::Triple &t = getTarget ().getTriple ();
92+ // If we encounter a try statement on in an OpenMP target region offloaded to
93+ // a GPU, we treat it as a basic block.
94+ const bool isTargetDevice =
95+ (cgm.getLangOpts ().OpenMPIsTargetDevice && (t.isNVPTX () || t.isAMDGCN ()));
96+ if (isTargetDevice) {
97+ cgm.errorNYI (
98+ " emitCXXTryStmtUnderScope: OpenMP target region offloaded to GPU" );
99+ return mlir::success ();
100+ }
101+
102+ unsigned numHandlers = s.getNumHandlers ();
103+ mlir::Location tryLoc = getLoc (s.getBeginLoc ());
104+ mlir::OpBuilder::InsertPoint beginInsertTryBody;
105+
106+ bool hasCatchAll = false ;
107+ for (unsigned i = 0 ; i != numHandlers; ++i) {
108+ hasCatchAll |= s.getHandler (i)->getExceptionDecl () == nullptr ;
109+ if (hasCatchAll)
110+ break ;
111+ }
112+
113+ // Create the scope to represent only the C/C++ `try {}` part. However,
114+ // don't populate right away. Create regions for the catch handlers,
115+ // but don't emit the handler bodies yet. For now, only make sure the
116+ // scope returns the exception information.
117+ auto tryOp = cir::TryOp::create (
118+ builder, tryLoc,
119+ /* tryBuilder=*/
120+ [&](mlir::OpBuilder &b, mlir::Location loc) {
121+ beginInsertTryBody = builder.saveInsertionPoint ();
122+ },
123+ /* handlersBuilder=*/
124+ [&](mlir::OpBuilder &b, mlir::Location loc,
125+ mlir::OperationState &result) {
126+ mlir::OpBuilder::InsertionGuard guard (b);
127+
128+ // We create an extra region for an unwind catch handler in case the
129+ // catch-all handler doesn't exists
130+ unsigned numRegionsToCreate =
131+ hasCatchAll ? numHandlers : numHandlers + 1 ;
132+
133+ for (unsigned i = 0 ; i != numRegionsToCreate; ++i) {
134+ mlir::Region *region = result.addRegion ();
135+ builder.createBlock (region);
136+ }
137+ });
138+
139+ // Finally emit the body for try/catch.
140+ {
141+ mlir::Location loc = tryOp.getLoc ();
142+ mlir::OpBuilder::InsertionGuard guard (builder);
143+ builder.restoreInsertionPoint (beginInsertTryBody);
144+ CIRGenFunction::LexicalScope tryScope{*this , loc,
145+ builder.getInsertionBlock ()};
146+
147+ tryScope.setAsTry (tryOp);
148+
149+ // Attach the basic blocks for the catch regions.
150+ enterCXXTryStmt (s, tryOp);
151+
152+ // Emit the body for the `try {}` part.
153+ {
154+ mlir::OpBuilder::InsertionGuard guard (builder);
155+ CIRGenFunction::LexicalScope tryBodyScope{*this , loc,
156+ builder.getInsertionBlock ()};
157+ if (emitStmt (s.getTryBlock (), /* useCurrentScope=*/ true ).failed ())
158+ return mlir::failure ();
159+ }
160+
161+ // Emit catch clauses.
162+ exitCXXTryStmt (s);
163+ }
164+
165+ return mlir::success ();
166+ }
167+
168+ void CIRGenFunction::enterCXXTryStmt (const CXXTryStmt &s, cir::TryOp tryOp,
169+ bool isFnTryBlock) {
170+ unsigned numHandlers = s.getNumHandlers ();
171+ EHCatchScope *catchScope = ehStack.pushCatch (numHandlers);
172+ for (unsigned i = 0 ; i != numHandlers; ++i) {
173+ const CXXCatchStmt *catchStmt = s.getHandler (i);
174+ if (catchStmt->getExceptionDecl ()) {
175+ cgm.errorNYI (" enterCXXTryStmt: CatchStmt with ExceptionDecl" );
176+ return ;
177+ }
178+
179+ // No exception decl indicates '...', a catch-all.
180+ mlir::Region *handler = &tryOp.getHandlerRegions ()[i];
181+ catchScope->setHandler (i, cgm.getCXXABI ().getCatchAllTypeInfo (), handler);
182+
183+ // Under async exceptions, catch(...) needs to catch HW exception too
184+ // Mark scope with SehTryBegin as a SEH __try scope
185+ if (getLangOpts ().EHAsynch ) {
186+ cgm.errorNYI (" enterCXXTryStmt: EHAsynch" );
187+ return ;
188+ }
189+ }
190+ }
191+
192+ void CIRGenFunction::exitCXXTryStmt (const CXXTryStmt &s, bool isFnTryBlock) {
193+ unsigned numHandlers = s.getNumHandlers ();
194+ EHCatchScope &catchScope = cast<EHCatchScope>(*ehStack.begin ());
195+ assert (catchScope.getNumHandlers () == numHandlers);
196+ cir::TryOp tryOp = curLexScope->getTry ();
197+
198+ // If the catch was not required, bail out now.
199+ if (!catchScope.mayThrow ()) {
200+ catchScope.clearHandlerBlocks ();
201+ ehStack.popCatch ();
202+
203+ // Drop all basic block from all catch regions.
204+ SmallVector<mlir::Block *> eraseBlocks;
205+ for (mlir::Region &handlerRegion : tryOp.getHandlerRegions ()) {
206+ if (handlerRegion.empty ())
207+ continue ;
208+
209+ for (mlir::Block &b : handlerRegion.getBlocks ())
210+ eraseBlocks.push_back (&b);
211+ }
212+
213+ for (mlir::Block *b : eraseBlocks)
214+ b->erase ();
215+
216+ tryOp.setHandlerTypesAttr ({});
217+ return ;
218+ }
219+
220+ cgm.errorNYI (" exitCXXTryStmt: Required catch" );
74221}
0 commit comments