================
@@ -382,5 +383,274 @@ void CIRGenFunction::exitCXXTryStmt(const CXXTryStmt &s, 
bool isFnTryBlock) {
     return;
   }
 
-  cgm.errorNYI("exitCXXTryStmt: Required catch");
+  // Copy the handler blocks off before we pop the EH stack.  Emitting
+  // the handlers might scribble on this memory.
+  SmallVector<EHCatchScope::Handler, 8> handlers(
+      catchScope.begin(), catchScope.begin() + numHandlers);
+
+  ehStack.popCatch();
+
+  // Determine if we need an implicit rethrow for all these catch handlers;
+  // see the comment below.
+  bool doImplicitRethrow =
+      isFnTryBlock && isa<CXXDestructorDecl, CXXConstructorDecl>(curCodeDecl);
+
+  // Wasm uses Windows-style EH instructions, but merges all catch clauses into
+  // one big catchpad. So we save the old funclet pad here before we traverse
+  // each catch handler.
+  if (EHPersonality::get(*this).isWasmPersonality()) {
+    cgm.errorNYI("exitCXXTryStmt: WASM personality");
+    return;
+  }
+
+  bool hasCatchAll = false;
+  for (unsigned i = numHandlers; i != 0; --i) {
+    hasCatchAll |= handlers[i - 1].isCatchAll();
+    mlir::Region *catchRegion = handlers[i - 1].region;
+
+    mlir::OpBuilder::InsertionGuard guard(builder);
+    builder.setInsertionPointToStart(&catchRegion->front());
+
+    const CXXCatchStmt *catchStmt = s.getHandler(i - 1);
+
+    // Enter a cleanup scope, including the catch variable and the
+    // end-catch.
+    RunCleanupsScope catchScope(*this);
+
+    // Initialize the catch variable and set up the cleanups.
+    // TODO: emitBeginCatch
+
+    // Emit the PGO counter increment.
+    assert(!cir::MissingFeatures::incrementProfileCounter());
+
+    // Perform the body of the catch.
+    mlir::LogicalResult emitResult =
+        emitStmt(catchStmt->getHandlerBlock(), /*useCurrentScope=*/true);
+    assert(emitResult.succeeded() && "failed to emit catch handler block");
+
+    // TODO(cir): This yeild should replaced by CatchParamOp once it upstreamed
+    cir::YieldOp::create(builder, tryOp->getLoc());
+
+    // [except.handle]p11:
+    //   The currently handled exception is rethrown if control
+    //   reaches the end of a handler of the function-try-block of a
+    //   constructor or destructor.
+
+    // It is important that we only do this on fallthrough and not on
+    // return.  Note that it's illegal to put a return in a
+    // constructor function-try-block's catch handler (p14), so this
+    // really only applies to destructors.
+    if (doImplicitRethrow) {
+      cgm.errorNYI("exitCXXTryStmt: doImplicitRethrow");
+      return;
+    }
+
+    // Fall out through the catch cleanups.
+    catchScope.forceCleanup();
+  }
+
+  // Because in wasm we merge all catch clauses into one big catchpad, in case
+  // none of the types in catch handlers matches after we test against each of
+  // them, we should unwind to the next EH enclosing scope. We generate a call
+  // to rethrow function here to do that.
+  if (EHPersonality::get(*this).isWasmPersonality() && !hasCatchAll) {
+    cgm.errorNYI("exitCXXTryStmt: WASM personality without catch all");
+  }
+
+  assert(!cir::MissingFeatures::incrementProfileCounter());
+}
+
+void CIRGenFunction::populateCatchHandlers(cir::TryOp tryOp) {
+  assert(ehStack.requiresCatchOrCleanup());
+  assert(!cgm.getLangOpts().IgnoreExceptions &&
+         "LandingPad should not be emitted when -fignore-exceptions are in "
+         "effect.");
+
+  EHScope &innermostEHScope = *ehStack.find(ehStack.getInnermostEHScope());
+  switch (innermostEHScope.getKind()) {
+  case EHScope::Terminate:
+    cgm.errorNYI("emitLandingPad: terminate");
+    return;
+
+  case EHScope::Catch:
+  case EHScope::Cleanup:
+  case EHScope::Filter:
+    // CIR does not cache landing pads.
+    break;
+  }
+
+  // If there's an existing TryOp, it means we got a `cir.try` scope
+  // that leads to this "landing pad" creation site. Otherwise, exceptions
+  // are enabled but a throwing function is called anyways (common pattern
+  // with function local static initializers).
+  mlir::ArrayAttr handlerTypesAttr = tryOp.getHandlerTypesAttr();
+  if (!handlerTypesAttr || handlerTypesAttr.empty()) {
+    // Accumulate all the handlers in scope.
+    bool hasCatchAll = false;
+    llvm::SmallVector<mlir::Attribute, 4> handlerAttrs;
+    for (EHScopeStack::iterator i = ehStack.begin(), e = ehStack.end(); i != e;
+         ++i) {
+      switch (i->getKind()) {
+      case EHScope::Cleanup: {
+        cgm.errorNYI("emitLandingPad: Cleanup");
+        return;
+      }
+
+      case EHScope::Filter: {
+        cgm.errorNYI("emitLandingPad: Filter");
+        return;
+      }
+
+      case EHScope::Terminate: {
+        cgm.errorNYI("emitLandingPad: Terminate");
+        return;
+      }
+
+      case EHScope::Catch:
+        break;
+      }
+
+      EHCatchScope &catchScope = cast<EHCatchScope>(*i);
+      for (unsigned handlerIdx = 0, he = catchScope.getNumHandlers();
+           handlerIdx != he; ++handlerIdx) {
+        EHCatchScope::Handler handler = catchScope.getHandler(handlerIdx);
+        assert(handler.type.flags == 0 &&
+               "landingpads do not support catch handler flags");
+
+        // If this is a catch-all, register that and abort.
+        if (handler.isCatchAll()) {
+          assert(!hasCatchAll);
+          hasCatchAll = true;
+          break;
+        }
+
+        cgm.errorNYI("emitLandingPad: non catch-all");
+        return;
+      }
+
+      if (hasCatchAll)
+        break;
+    }
+
+    if (hasCatchAll) {
+      handlerAttrs.push_back(cir::CatchAllAttr::get(&getMLIRContext()));
+    } else {
+      cgm.errorNYI("emitLandingPad: non catch-all");
+      return;
+    }
+
+    // Add final array of clauses into TryOp.
+    tryOp.setHandlerTypesAttr(
+        mlir::ArrayAttr::get(&getMLIRContext(), handlerAttrs));
+  }
+
+  // In traditional LLVM codegen. this tells the backend how to generate the
+  // landing pad by generating a branch to the dispatch block. In CIR,
+  // this is used to populate blocks for later filing during
+  // cleanup handling.
+  populateEHCatchRegions(ehStack.getInnermostEHScope(), tryOp);
+}
+
+// Differently from LLVM traditional codegen, there are no dispatch blocks
+// to look at given cir.try_call does not jump to blocks like invoke does.
+// However.
+void CIRGenFunction::populateEHCatchRegions(EHScopeStack::stable_iterator 
scope,
+                                            cir::TryOp tryOp) {
+  if (EHPersonality::get(*this).usesFuncletPads()) {
+    cgm.errorNYI("getEHDispatchBlock: usesFuncletPads");
+    return;
+  }
+
+  // Otherwise, we should look at the actual scope.
+  EHScope &ehScope = *ehStack.find(scope);
+  bool mayThrow = ehScope.mayThrow();
+
+  mlir::Block *originalBlock = nullptr;
+  if (mayThrow && tryOp) {
+    // If the dispatch is cached but comes from a different tryOp, make sure:
+    // - Populate current `tryOp` with a new dispatch block regardless.
+    // - Update the map to enqueue new dispatchBlock to also get a cleanup. See
+    // code at the end of the function.
+    cgm.errorNYI("getEHDispatchBlock: mayThrow & tryOp");
+    return;
+  }
+
+  if (!mayThrow) {
+    switch (ehScope.getKind()) {
+    case EHScope::Catch: {
+      // LLVM does some optimization with branches here, CIR just keep track of
+      // the corresponding calls.
+      EHCatchScope &catchScope = cast<EHCatchScope>(ehScope);
+      if (catchScope.getNumHandlers() == 1 &&
+          catchScope.getHandler(0).isCatchAll()) {
+        mayThrow = true;
+        break;
+      }
+      cgm.errorNYI("getEHDispatchBlock: mayThrow non-catch all");
+      return;
+    }
+    case EHScope::Cleanup: {
+      cgm.errorNYI("getEHDispatchBlock: mayThrow & cleanup");
+      return;
+    }
+    case EHScope::Filter: {
+      cgm.errorNYI("getEHDispatchBlock: mayThrow & Filter");
+      return;
+    }
+    case EHScope::Terminate: {
+      cgm.errorNYI("getEHDispatchBlock: mayThrow & Terminate");
+      return;
+    }
+    }
+  }
+
+  if (originalBlock) {
+    cgm.errorNYI("getEHDispatchBlock: originalBlock");
+    return;
+  }
+
+  ehScope.setMayThrow(mayThrow);
+}
+
+// in classic codegen this function is mapping to `isInvokeDest` previously and
+// currently it's mapping to the conditions that performs early returns in
+// `getInvokeDestImpl`, in CIR we need the condition to know if the EH scope 
may
+// throw exception or now.
+bool CIRGenFunction::isCatchOrCleanupRequired() {
+  if (!ehStack.requiresCatchOrCleanup())
+    return false;
----------------
andykaylor wrote:

Can you sink this below the other two checks, which may be much faster?

https://github.com/llvm/llvm-project/pull/165158
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to