@@ -232,6 +232,30 @@ void CIRGenFunction::emitAnyExprToExn(const Expr *e, Address addr) {
232232 assert (!cir::MissingFeatures::ehCleanupScope ());
233233}
234234
235+ void CIRGenFunction::populateUnwindResumeBlock (bool isCleanup,
236+ cir::TryOp tryOp) {
237+ const EHPersonality &personality = EHPersonality::get (*this );
238+ // This can always be a call because we necessarily didn't find
239+ // anything on the EH stack which needs our help.
240+ const char *rethrowName = personality.catchallRethrowFn ;
241+ if (rethrowName != nullptr && !isCleanup) {
242+ cgm.errorNYI (" populateUnwindResumeBlock CatchallRethrowFn" );
243+ return ;
244+ }
245+
246+ unsigned regionsNum = tryOp->getNumRegions ();
247+ mlir::Region *unwindRegion = &tryOp->getRegion (regionsNum - 1 );
248+ mlir::Block *unwindResumeBlock = &unwindRegion->front ();
249+ if (!unwindResumeBlock->empty ())
250+ return ;
251+
252+ // Emit cir.resume into the unwind region last block
253+ cir::CIRBaseBuilderTy::InsertPoint ip = builder.saveInsertionPoint ();
254+ builder.setInsertionPointToStart (unwindResumeBlock);
255+ cir::ResumeOp::create (builder, tryOp.getLoc ());
256+ builder.restoreInsertionPoint (ip);
257+ }
258+
235259mlir::LogicalResult CIRGenFunction::emitCXXTryStmt (const CXXTryStmt &s) {
236260 if (s.getTryBlock ()->body_empty ())
237261 return mlir::LogicalResult::success ();
@@ -332,21 +356,88 @@ CIRGenFunction::emitCXXTryStmtUnderScope(const CXXTryStmt &s) {
332356 return mlir::success ();
333357}
334358
359+ // / Emit the structure of the dispatch block for the given catch scope.
360+ // / It is an invariant that the dispatch block already exists.
361+ static void emitCatchDispatchBlock (CIRGenFunction &cgf,
362+ EHCatchScope &catchScope, cir::TryOp tryOp) {
363+ if (EHPersonality::get (cgf).isWasmPersonality ()) {
364+ cgf.cgm .errorNYI (" emitCatchDispatchBlock: WasmPersonality" );
365+ return ;
366+ }
367+
368+ if (EHPersonality::get (cgf).usesFuncletPads ()) {
369+ cgf.cgm .errorNYI (" emitCatchDispatchBlock: usesFuncletPads" );
370+ return ;
371+ }
372+
373+ unsigned int numHandlers = catchScope.getNumHandlers ();
374+ if (numHandlers == 1 && catchScope.getHandler (0 ).isCatchAll ()) {
375+ return ;
376+ }
377+
378+ // In traditional LLVM codegen, the right handler is selected (with
379+ // calls to eh_typeid_for) and the selector value is loaded. After that,
380+ // blocks get connected for later codegen. In CIR, these are all
381+ // implicit behaviors of cir.catch - not a lot of work to do.
382+ //
383+ // Test against each of the exception types we claim to catch.
384+ for (unsigned i = 0 ;; ++i) {
385+ assert (i < numHandlers && " ran off end of handlers!" );
386+ const EHCatchScope::Handler &handler = catchScope.getHandler (i);
387+
388+ [[maybe_unused]] mlir::TypedAttr typeValue = handler.type .rtti ;
389+ assert (handler.Type .Flags == 0 && " catch handler flags not supported" );
390+ assert (typeValue && " fell into catch-all case!" );
391+
392+ // Check for address space mismatch
393+ assert (!cir::MissingFeatures::addressSpace ());
394+
395+ // If this is the last handler, we're at the end, and the next
396+ // block is the block for the enclosing EH scope. Make sure to call
397+ // populateEHCatchRegions for caching it.
398+ if (i + 1 == numHandlers) {
399+ cgf.populateEHCatchRegions (catchScope.getEnclosingEHScope (), tryOp);
400+ return ;
401+ }
402+
403+ // If the next handler is a catch-all, we're at the end, and the
404+ // next block is that handler.
405+ if (catchScope.getHandler (i + 1 ).isCatchAll ())
406+ return ;
407+ }
408+ }
409+
335410void CIRGenFunction::enterCXXTryStmt (const CXXTryStmt &s, cir::TryOp tryOp,
336411 bool isFnTryBlock) {
337412 unsigned numHandlers = s.getNumHandlers ();
338413 EHCatchScope *catchScope = ehStack.pushCatch (numHandlers);
339414 for (unsigned i = 0 ; i != numHandlers; ++i) {
340415 const CXXCatchStmt *catchStmt = s.getHandler (i);
416+ mlir::Region *handler = &tryOp.getHandlerRegions ()[i];
341417 if (catchStmt->getExceptionDecl ()) {
342- cgm.errorNYI (" enterCXXTryStmt: CatchStmt with ExceptionDecl" );
343- return ;
344- }
418+ // FIXME: Dropping the reference type on the type into makes it
419+ // impossible to correctly implement catch-by-reference
420+ // semantics for pointers. Unfortunately, this is what all
421+ // existing compilers do, and it's not clear that the standard
422+ // personality routine is capable of doing this right. See C++ DR 388:
423+ // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#388
424+ Qualifiers caughtTypeQuals;
425+ QualType caughtType = cgm.getASTContext ().getUnqualifiedArrayType (
426+ catchStmt->getCaughtType ().getNonReferenceType (), caughtTypeQuals);
427+ if (caughtType->isObjCObjectPointerType ()) {
428+ cgm.errorNYI (" enterCXXTryStmt: caughtType ObjCObjectPointerType" );
429+ return ;
430+ }
345431
346- // No exception decl indicates '...', a catch-all.
347- mlir::Region *handler = &tryOp.getHandlerRegions ()[i];
348- catchScope->setHandler (i, cgm.getCXXABI ().getCatchAllTypeInfo (), handler,
349- s.getHandler (i));
432+ CatchTypeInfo typeInfo = cgm.getCXXABI ().getAddrOfCXXCatchHandlerType (
433+ getLoc (catchStmt->getSourceRange ()), caughtType,
434+ catchStmt->getCaughtType ());
435+ catchScope->setHandler (i, typeInfo, handler, catchStmt);
436+ } else {
437+ // No exception decl indicates '...', a catch-all.
438+ catchScope->setHandler (i, cgm.getCXXABI ().getCatchAllTypeInfo (), handler,
439+ s.getHandler (i));
440+ }
350441
351442 // Under async exceptions, catch(...) needs to catch HW exception too
352443 // Mark scope with SehTryBegin as a SEH __try scope
@@ -385,6 +476,9 @@ void CIRGenFunction::exitCXXTryStmt(const CXXTryStmt &s, bool isFnTryBlock) {
385476 return ;
386477 }
387478
479+ // Emit the structure of the EH dispatch for this catch.
480+ emitCatchDispatchBlock (*this , catchScope, tryOp);
481+
388482 // Copy the handler blocks off before we pop the EH stack. Emitting
389483 // the handlers might scribble on this memory.
390484 SmallVector<EHCatchScope::Handler> handlers (catchScope.begin (),
@@ -487,9 +581,11 @@ void CIRGenFunction::populateCatchHandlers(cir::TryOp tryOp) {
487581 // with function local static initializers).
488582 mlir::ArrayAttr handlerTypesAttr = tryOp.getHandlerTypesAttr ();
489583 if (!handlerTypesAttr || handlerTypesAttr.empty ()) {
584+ // Accumulate all the handlers in scope.
490585 // Accumulate all the handlers in scope.
491586 bool hasCatchAll = false ;
492- llvm::SmallVector<mlir::Attribute, 4 > handlerAttrs;
587+ llvm::SmallPtrSet<mlir::Attribute, 4 > catchTypes;
588+ llvm::SmallVector<mlir::Attribute> handlerAttrs;
493589 for (EHScopeStack::iterator i = ehStack.begin (), e = ehStack.end (); i != e;
494590 ++i) {
495591 switch (i->getKind ()) {
@@ -522,8 +618,10 @@ void CIRGenFunction::populateCatchHandlers(cir::TryOp tryOp) {
522618 break ;
523619 }
524620
525- cgm.errorNYI (" emitLandingPad: non catch-all" );
526- return ;
621+ // Check whether we already have a handler for this type.
622+ // If not, keep track to later add to catch op.
623+ if (catchTypes.insert (handler.type .rtti ).second )
624+ handlerAttrs.push_back (handler.type .rtti );
527625 }
528626
529627 if (hasCatchAll)
@@ -532,9 +630,12 @@ void CIRGenFunction::populateCatchHandlers(cir::TryOp tryOp) {
532630
533631 if (hasCatchAll) {
534632 handlerAttrs.push_back (cir::CatchAllAttr::get (&getMLIRContext ()));
535- } else {
536- cgm.errorNYI (" emitLandingPad: non catch-all" );
537- return ;
633+ }
634+
635+ // If there's no catch_all, attach the unwind region. This needs to be the
636+ // last region in the TryOp catch list.
637+ if (!hasCatchAll) {
638+ handlerAttrs.push_back (cir::UnwindAttr::get (&getMLIRContext ()));
538639 }
539640
540641 // Add final array of clauses into TryOp.
@@ -559,6 +660,13 @@ void CIRGenFunction::populateEHCatchRegions(EHScopeStack::stable_iterator scope,
559660 return ;
560661 }
561662
663+ // The dispatch block for the end of the scope chain is a block that
664+ // just resumes unwinding.
665+ if (scope == ehStack.stable_end ()) {
666+ populateUnwindResumeBlock (/* isCleanup=*/ true , tryOp);
667+ return ;
668+ }
669+
562670 // Otherwise, we should look at the actual scope.
563671 EHScope &ehScope = *ehStack.find (scope);
564672 bool mayThrow = ehScope.mayThrow ();
@@ -576,16 +684,25 @@ void CIRGenFunction::populateEHCatchRegions(EHScopeStack::stable_iterator scope,
576684 if (!mayThrow) {
577685 switch (ehScope.getKind ()) {
578686 case EHScope::Catch: {
687+ mayThrow = true ;
688+
579689 // LLVM does some optimization with branches here, CIR just keep track of
580690 // the corresponding calls.
581691 EHCatchScope &catchScope = cast<EHCatchScope>(ehScope);
582692 if (catchScope.getNumHandlers () == 1 &&
583693 catchScope.getHandler (0 ).isCatchAll ()) {
584- mayThrow = true ;
585694 break ;
586695 }
587- cgm.errorNYI (" getEHDispatchBlock: mayThrow non-catch all" );
588- return ;
696+
697+ assert (callWithExceptionCtx && " expected call information" );
698+ {
699+ mlir::OpBuilder::InsertionGuard guard (builder);
700+ assert (callWithExceptionCtx.getCleanup ().empty () &&
701+ " one per call: expected empty region at this point" );
702+ builder.createBlock (&callWithExceptionCtx.getCleanup ());
703+ builder.createYield (callWithExceptionCtx.getLoc ());
704+ }
705+ break ;
589706 }
590707 case EHScope::Cleanup: {
591708 cgm.errorNYI (" getEHDispatchBlock: mayThrow & cleanup" );
0 commit comments