tentzen updated this revision to Diff 265812.
tentzen retitled this revision from "[Windows SEH]: HARDWARE EXCEPTION HANDLING 
(MSVC option -EHa)" to "[Windows SEH]: HARDWARE EXCEPTION HANDLING (MSVC -EHa) 
- Part 1".
tentzen edited the summary of this revision.
tentzen added a reviewer: lebedev.ri.
tentzen added a comment.

Per Roman Lebedev's feedback, divide the patch into Clang and LLVM.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D80344/new/

https://reviews.llvm.org/D80344

Files:
  clang/include/clang/AST/Stmt.h
  clang/include/clang/Basic/LangOptions.def
  clang/include/clang/Driver/Options.td
  clang/lib/CodeGen/CGCleanup.cpp
  clang/lib/CodeGen/CGDecl.cpp
  clang/lib/CodeGen/CGException.cpp
  clang/lib/CodeGen/CGStmt.cpp
  clang/lib/CodeGen/CodeGenFunction.h
  clang/lib/CodeGen/CodeGenModule.cpp
  clang/lib/Driver/ToolChains/Clang.cpp
  clang/lib/Frontend/CompilerInvocation.cpp
  clang/lib/Sema/JumpDiagnostics.cpp
  clang/test/CodeGen/windows-seh-EHa-CppCatchDotDotDot.cpp
  clang/test/CodeGen/windows-seh-EHa-CppDtors01.cpp
  clang/test/CodeGen/windows-seh-EHa-TryInFinally.cpp
  llvm/include/llvm/IR/Intrinsics.td
  llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
  llvm/lib/IR/Verifier.cpp

Index: llvm/lib/IR/Verifier.cpp
===================================================================
--- llvm/lib/IR/Verifier.cpp
+++ llvm/lib/IR/Verifier.cpp
@@ -4223,6 +4223,10 @@
       Assert(
           !F->isIntrinsic() || isa<CallInst>(I) ||
               F->getIntrinsicID() == Intrinsic::donothing ||
+              F->getIntrinsicID() == Intrinsic::seh_try_begin ||
+              F->getIntrinsicID() == Intrinsic::seh_try_end ||
+              F->getIntrinsicID() == Intrinsic::eha_scope_begin ||
+              F->getIntrinsicID() == Intrinsic::eha_scope_end ||
               F->getIntrinsicID() == Intrinsic::coro_resume ||
               F->getIntrinsicID() == Intrinsic::coro_destroy ||
               F->getIntrinsicID() == Intrinsic::experimental_patchpoint_void ||
Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
===================================================================
--- llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -2789,6 +2789,10 @@
       llvm_unreachable("Cannot invoke this intrinsic");
     case Intrinsic::donothing:
       // Ignore invokes to @llvm.donothing: jump directly to the next BB.
+    case Intrinsic::seh_try_begin:
+    case Intrinsic::eha_scope_begin:
+    case Intrinsic::seh_try_end:
+    case Intrinsic::eha_scope_end:
       break;
     case Intrinsic::experimental_patchpoint_void:
     case Intrinsic::experimental_patchpoint_i64:
@@ -6583,6 +6587,10 @@
       lowerCallToExternalSymbol(I, FunctionName);
     return;
   case Intrinsic::donothing:
+  case Intrinsic::seh_try_begin:
+  case Intrinsic::eha_scope_begin:
+  case Intrinsic::seh_try_end:
+  case Intrinsic::eha_scope_end:
     // ignore
     return;
   case Intrinsic::experimental_stackmap:
Index: llvm/include/llvm/IR/Intrinsics.td
===================================================================
--- llvm/include/llvm/IR/Intrinsics.td
+++ llvm/include/llvm/IR/Intrinsics.td
@@ -456,6 +456,16 @@
                                  [llvm_ptr_ty, llvm_ptr_ty],
                                  [IntrNoMem]>;
 
+// To mark the beginning/end of a try-scope for Windows SEH -EHa
+//  calls/invokes to these intrinsics are placed to model control flows
+//    caused by HW exceptions under option -EHa.
+//  calls/invokes to these intrinsics will be discarded during a codegen pass
+//   after EH tables are generated
+def int_seh_try_begin : Intrinsic<[], [], [IntrReadMem, IntrWriteMem, IntrWillReturn]>;
+def int_seh_try_end : Intrinsic<[], [], [IntrReadMem, IntrWriteMem, IntrWillReturn]>;
+def int_eha_scope_begin : Intrinsic<[], [], [IntrNoMem]>;
+def int_eha_scope_end : Intrinsic<[], [], [IntrNoMem]>;
+
 // Note: we treat stacksave/stackrestore as writemem because we don't otherwise
 // model their dependencies on allocas.
 def int_stacksave     : Intrinsic<[llvm_ptr_ty]>,
Index: clang/test/CodeGen/windows-seh-EHa-TryInFinally.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGen/windows-seh-EHa-TryInFinally.cpp
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -triple x86_64-windows -feh-asynch -fcxx-exceptions -fexceptions -fms-extensions -x c++ -Wno-implicit-function-declaration -S -emit-llvm %s -o - | FileCheck %s
+
+// CHECK: invoke void @llvm.seh.try.begin()
+// CHECK: invoke void @llvm.seh.try.begin()
+// CHECK: %[[src:[0-9-]+]] = load volatile i32, i32* %i
+// CHECK-NEXT: i32 %[[src]]
+// CHECK: invoke void @llvm.seh.try.end()
+// CHECK: invoke void @llvm.seh.try.end()
+
+// CHECK: define internal void @"?fin$0@0@main@@"(i8 %abnormal_termination
+// CHECK: invoke void @llvm.seh.try.begin()
+// CHECK: invoke void @llvm.seh.try.end()
+
+// *****************************************************************************
+// Abstract:     Test __Try in __finally under SEH -EHa option
+void printf(...);
+int volatile *NullPtr = 0;
+int main() {
+  for (int i = 0; i < 3; i++) {
+    printf(" --- Test _Try in _finally --- i = %d \n", i);
+    __try {
+      __try {
+        printf("  In outer _try i = %d \n", i);
+        if (i == 0)
+          *NullPtr = 0;
+      } __finally {
+        __try {
+          printf("  In outer _finally i = %d \n", i);
+          if (i == 1)
+            *NullPtr = 0;
+        } __finally {
+          printf("  In Inner _finally i = %d \n", i);
+          if (i == 2)
+            *NullPtr = 0;
+        }
+      }
+    } __except (1) {
+      printf(" --- In outer except handler i = %d \n", i);
+    }
+  }
+  return 0;
+}
Index: clang/test/CodeGen/windows-seh-EHa-CppDtors01.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGen/windows-seh-EHa-CppDtors01.cpp
@@ -0,0 +1,60 @@
+// RUN: %clang_cc1 -triple x86_64-windows -feh-asynch -fcxx-exceptions -fexceptions -fms-extensions -x c++ -Wno-implicit-function-declaration -S -emit-llvm %s -o - | FileCheck %s
+
+// CHECK: invoke void @llvm.eha.scope.begin()
+// CHECK: invoke void @llvm.eha.scope.begin()
+// CHECK: invoke void @llvm.eha.scope.begin()
+// CHECK: invoke void @llvm.eha.scope.end()
+// CHECK: invoke void @llvm.eha.scope.end()
+// CHECK: invoke void @llvm.eha.scope.end()
+
+// CHECK: invoke void @llvm.seh.try.begin()
+// CHECK: %[[src:[0-9-]+]] = load volatile i32, i32* %i
+// CHECK-NEXT: invoke void @"?crash@@YAXH@Z"(i32 %[[src]])
+// CHECK: invoke void @llvm.seh.try.end()
+
+// ****************************************************************************
+// Abstract:     Test CPP unwind Dtoring under SEH -EHa option
+
+void printf(...);
+int volatile *NullPtr = 0;
+void crash(int i) {
+  struct A {
+    ~A() {
+      printf(" in A dtor \n");
+    }
+  } ObjA;
+  if (i == 0)
+    *NullPtr = 0;
+
+  struct B {
+    ~B() {
+      printf(" in B dtor \n");
+    }
+  } ObjB;
+  if (i == 1)
+    *NullPtr = 0;
+
+  struct C {
+    ~C() {
+      printf(" in C dtor \n");
+    }
+  } ObjC;
+  if (i == 2)
+    *NullPtr = 0;
+}
+
+#define TRY __try
+#define CATCH_ALL __except (1)
+
+int g;
+int main() {
+  for (int i = 0; i < 3; i++) {
+    TRY {
+      crash(i);
+    }
+    CATCH_ALL {
+      printf(" Test CPP unwind: in catch handler i = %d \n", i);
+    }
+  }
+  return 0;
+}
Index: clang/test/CodeGen/windows-seh-EHa-CppCatchDotDotDot.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGen/windows-seh-EHa-CppCatchDotDotDot.cpp
@@ -0,0 +1,58 @@
+// RUN: %clang_cc1 -triple x86_64-windows -feh-asynch -fcxx-exceptions -fexceptions -fms-extensions -x c++ -Wno-implicit-function-declaration -S -emit-llvm %s -o - | FileCheck %s
+
+// CHECK: define dso_local void @"?crash@@YAXH@Z
+// CHECK: invoke void @llvm.seh.try.begin()
+// CHECK: invoke void @llvm.eha.scope.begin()
+// CHECK: invoke void @llvm.eha.scope.end()
+
+// CHECK: %[[dst:[0-9-]+]] = catchswitch within none [label %catch] unwind to caller
+// CHECK: %[[dst1:[0-9-]+]] = catchpad within %[[dst]] [i8* null, i32 0, i8* null]
+// CHECK: "funclet"(token %[[dst1]])
+
+// CHECK: invoke void @llvm.seh.try.begin()
+// CHECK: %[[src:[0-9-]+]] = load volatile i32, i32* %i
+// CHECK-NEXT: invoke void @"?crash@@YAXH@Z"(i32 %[[src]])
+// CHECK: invoke void @llvm.seh.try.end()
+
+// *****************************************************************************
+// Abstract:     Test CPP catch(...) under SEH -EHa option
+
+void printf(...);
+int volatile *NullPtr = 0;
+void foo() {
+  *NullPtr = 0;
+}
+int *pt1, *pt2, *pt3;
+int g;
+void crash(int i) {
+  g = i;
+  try {
+    struct A {
+      A() {
+        printf(" in A ctor \n");
+        if (g == 0)
+          *NullPtr = 0;
+      }
+      ~A() {
+        printf(" in A dtor \n");
+      }
+    } ObjA;
+    if (i == 1)
+      *NullPtr = 0;
+  } catch (...) {
+    printf(" in catch(...) funclet \n");
+    if (i == 1)
+      throw(i);
+  }
+}
+
+int main() {
+  for (int i = 0; i < 2; i++) {
+    __try {
+      crash(i);
+    } __except (1) {
+      printf(" Test CPP unwind: in except handler i = %d \n", i);
+    }
+  }
+  return 0;
+}
Index: clang/lib/Sema/JumpDiagnostics.cpp
===================================================================
--- clang/lib/Sema/JumpDiagnostics.cpp
+++ clang/lib/Sema/JumpDiagnostics.cpp
@@ -930,6 +930,9 @@
   if (!ToScopesWarning.empty()) {
     S.Diag(DiagLoc, JumpDiagWarning);
     NoteJumpIntoScopes(ToScopesWarning);
+    assert(isa<LabelStmt>(To));
+    LabelStmt *Label = cast<LabelStmt>(To);
+    Label->setSideEntry();
   }
 
   // Handle errors.
Index: clang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- clang/lib/Frontend/CompilerInvocation.cpp
+++ clang/lib/Frontend/CompilerInvocation.cpp
@@ -2783,6 +2783,7 @@
   Opts.IgnoreExceptions = Args.hasArg(OPT_fignore_exceptions);
   Opts.ObjCExceptions = Args.hasArg(OPT_fobjc_exceptions);
   Opts.CXXExceptions = Args.hasArg(OPT_fcxx_exceptions);
+  Opts.EHAsynch = Args.hasArg(OPT_feh_asynch);
 
   // -ffixed-point
   Opts.FixedPoint =
Index: clang/lib/Driver/ToolChains/Clang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Clang.cpp
+++ clang/lib/Driver/ToolChains/Clang.cpp
@@ -426,6 +426,7 @@
     Args.ClaimAllArgs(options::OPT_fobjc_exceptions);
     Args.ClaimAllArgs(options::OPT_fno_objc_exceptions);
     Args.ClaimAllArgs(options::OPT_fcxx_exceptions);
+    Args.ClaimAllArgs(options::OPT_feh_asynch);
     Args.ClaimAllArgs(options::OPT_fno_cxx_exceptions);
     return;
   }
@@ -434,6 +435,13 @@
   bool EH = Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions,
                          false);
 
+  bool EHa =
+      Args.hasFlag(options::OPT_feh_asynch, options::OPT_fno_eh_asynch, false);
+  if (EHa) {
+    CmdArgs.push_back("-feh-asynch");
+    EH = true;
+  }
+
   // Obj-C exceptions are enabled by default, regardless of -fexceptions. This
   // is not necessarily sensible, but follows GCC.
   if (types::isObjC(InputType) &&
@@ -6572,7 +6580,10 @@
     if (types::isCXX(InputType))
       CmdArgs.push_back("-fcxx-exceptions");
     CmdArgs.push_back("-fexceptions");
+    if (EH.Asynch)
+      CmdArgs.push_back("-feh-asynch");
   }
+
   if (types::isCXX(InputType) && EH.Synch && EH.NoUnwindC)
     CmdArgs.push_back("-fexternc-nounwind");
 
Index: clang/lib/CodeGen/CodeGenModule.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenModule.cpp
+++ clang/lib/CodeGen/CodeGenModule.cpp
@@ -597,6 +597,9 @@
                                   llvm::DenormalMode::IEEE);
   }
 
+  if (LangOpts.EHAsynch)
+    getModule().addModuleFlag(llvm::Module::Warning, "eh-asynch", 1);
+
   // Emit OpenCL specific module metadata: OpenCL/SPIR version.
   if (LangOpts.OpenCL) {
     EmitOpenCLMetadata();
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -2687,6 +2687,11 @@
   void EmitCXXTemporary(const CXXTemporary *Temporary, QualType TempType,
                         Address Ptr);
 
+  void EmitSehCppScopeBegin();
+  void EmitSehCppScopeEnd();
+  void EmitSehTryScopeBegin();
+  void EmitSehTryScopeEnd();
+
   llvm::Value *EmitLifetimeStart(uint64_t Size, llvm::Value *Addr);
   void EmitLifetimeEnd(llvm::Value *Size, llvm::Value *Addr);
 
@@ -3037,6 +3042,8 @@
   void EmitSEHLeaveStmt(const SEHLeaveStmt &S);
   void EnterSEHTryStmt(const SEHTryStmt &S);
   void ExitSEHTryStmt(const SEHTryStmt &S);
+  void VolatilizeTryBlocks(llvm::BasicBlock *BB,
+                           llvm::SmallPtrSet<llvm::BasicBlock *, 10> &V);
 
   void pushSEHCleanup(CleanupKind kind,
                       llvm::Function *FinallyFunc);
Index: clang/lib/CodeGen/CGStmt.cpp
===================================================================
--- clang/lib/CodeGen/CGStmt.cpp
+++ clang/lib/CodeGen/CGStmt.cpp
@@ -604,6 +604,11 @@
 
 void CodeGenFunction::EmitLabelStmt(const LabelStmt &S) {
   EmitLabel(S.getDecl());
+
+  // IsEHa - emit eha.scope.begin if it's a side entry of a scope
+  if (getLangOpts().EHAsynch && S.IsSideEntry())
+    EmitSehCppScopeBegin();
+
   EmitStmt(S.getSubStmt());
 }
 
Index: clang/lib/CodeGen/CGException.cpp
===================================================================
--- clang/lib/CodeGen/CGException.cpp
+++ clang/lib/CodeGen/CGException.cpp
@@ -38,6 +38,18 @@
   return CGM.CreateRuntimeFunction(FTy, "__cxa_free_exception");
 }
 
+static llvm::FunctionCallee getSehTryBeginFn(CodeGenModule &CGM) {
+  llvm::FunctionType *FTy =
+      llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
+  return CGM.CreateRuntimeFunction(FTy, "llvm.seh.try.begin");
+}
+
+static llvm::FunctionCallee getSehTryEndFn(CodeGenModule &CGM) {
+  llvm::FunctionType *FTy =
+      llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
+  return CGM.CreateRuntimeFunction(FTy, "llvm.seh.try.end");
+}
+
 static llvm::FunctionCallee getUnexpectedFn(CodeGenModule &CGM) {
   // void __cxa_call_unexpected(void *thrown_exception);
 
@@ -450,7 +462,7 @@
   if (!FD) {
     // Check if CapturedDecl is nothrow and create terminate scope for it.
     if (const CapturedDecl* CD = dyn_cast_or_null<CapturedDecl>(D)) {
-      if (CD->isNothrow())
+      if (CD->isNothrow() && !getLangOpts().EHAsynch /* !IsEHa */)
         EHStack.pushTerminate();
     }
     return;
@@ -462,7 +474,8 @@
   ExceptionSpecificationType EST = Proto->getExceptionSpecType();
   if (isNoexceptExceptionSpec(EST) && Proto->canThrow() == CT_Cannot) {
     // noexcept functions are simple terminate scopes.
-    EHStack.pushTerminate();
+    if (!getLangOpts().EHAsynch) // -EHa: HW exception still can occur
+      EHStack.pushTerminate();
   } else if (EST == EST_Dynamic || EST == EST_DynamicNone) {
     // TODO: Revisit exception specifications for the MS ABI.  There is a way to
     // encode these in an object file but MSVC doesn't do anything with it.
@@ -527,7 +540,7 @@
   if (!FD) {
     // Check if CapturedDecl is nothrow and pop terminate scope for it.
     if (const CapturedDecl* CD = dyn_cast_or_null<CapturedDecl>(D)) {
-      if (CD->isNothrow())
+      if (CD->isNothrow() && !EHStack.empty())
         EHStack.popTerminate();
     }
     return;
@@ -537,7 +550,8 @@
     return;
 
   ExceptionSpecificationType EST = Proto->getExceptionSpecType();
-  if (isNoexceptExceptionSpec(EST) && Proto->canThrow() == CT_Cannot) {
+  if (isNoexceptExceptionSpec(EST) && Proto->canThrow() == CT_Cannot &&
+      !EHStack.empty() /* possible empty when -EHa */) {
     EHStack.popTerminate();
   } else if (EST == EST_Dynamic || EST == EST_DynamicNone) {
     // TODO: Revisit exception specifications for the MS ABI.  There is a way to
@@ -584,7 +598,16 @@
       CatchScope->setHandler(I, TypeInfo, Handler);
     } else {
       // No exception decl indicates '...', a catch-all.
-      CatchScope->setHandler(I, CGM.getCXXABI().getCatchAllTypeInfo(), Handler);
+      CatchTypeInfo TypeInfo = CGM.getCXXABI().getCatchAllTypeInfo();
+
+      // For IsEHa catch(...) must handle HW exception
+      // Adjective = HT_IsStdDotDot (0x40), only catch C++ exceptions
+      // Also mark scope with SehTryBegin
+      if (getLangOpts().EHAsynch) {
+        TypeInfo.Flags = 0;
+        EmitRuntimeCallOrInvoke(getSehTryBeginFn(CGM));
+      }
+      CatchScope->setHandler(I, TypeInfo, Handler);
     }
   }
 }
@@ -706,7 +729,7 @@
   // If exceptions are disabled/ignored and SEH is not in use, then there is no
   // invoke destination. SEH "works" even if exceptions are off. In practice,
   // this means that C++ destructors and other EH cleanups don't run, which is
-  // consistent with MSVC's behavior.
+  // consistent with MSVC's behavior, except in the presence of -EHa
   const LangOptions &LO = CGM.getLangOpts();
   if (!LO.Exceptions || LO.IgnoreExceptions) {
     if (!LO.Borland && !LO.MicrosoftExt)
@@ -1602,7 +1625,23 @@
     JumpDest TryExit = getJumpDestInCurrentScope("__try.__leave");
 
     SEHTryEpilogueStack.push_back(&TryExit);
+
+    llvm::BasicBlock *TryBB = nullptr;
+    // IsEHa: emit an invoke to _seh_try_begin() runtime for -EHa
+    if (getLangOpts().EHAsynch) {
+      EmitRuntimeCallOrInvoke(getSehTryBeginFn(CGM));
+      if (SEHTryEpilogueStack.size() == 1) // outermost only
+        TryBB = Builder.GetInsertBlock();
+    }
+
     EmitStmt(S.getTryBlock());
+
+    // Volatilize all blocks in Try, till current insert point
+    if (TryBB) {
+      llvm::SmallPtrSet<llvm::BasicBlock *, 10> Visited;
+      VolatilizeTryBlocks(TryBB, Visited);
+    }
+
     SEHTryEpilogueStack.pop_back();
 
     if (!TryExit.getBlock()->use_empty())
@@ -1613,6 +1652,38 @@
   ExitSEHTryStmt(S);
 }
 
+//  Recursively walk through blocks in a _try
+//      and make all memory instructions volatile
+void CodeGenFunction::VolatilizeTryBlocks(
+    llvm::BasicBlock *BB, llvm::SmallPtrSet<llvm::BasicBlock *, 10> &V) {
+  if (BB == SEHTryEpilogueStack.back()->getBlock() /* end of Try */ ||
+      !V.insert(BB).second /* already visited */ ||
+      !BB->getParent() /* not emitted */ || BB->empty())
+    return;
+
+  if (!BB->isEHPad()) {
+    for (llvm::BasicBlock::iterator J = BB->begin(), JE = BB->end(); J != JE;
+         ++J) {
+      if (isa<llvm::LoadInst>(J)) {
+        auto LI = cast<llvm::LoadInst>(J);
+        LI->setVolatile(true);
+      } else if (isa<llvm::StoreInst>(J)) {
+        auto SI = cast<llvm::StoreInst>(J);
+        SI->setVolatile(true);
+      } else if (isa<llvm::MemIntrinsic>(J)) {
+        auto *MCI = cast<llvm::MemIntrinsic>(J);
+        MCI->setVolatile(llvm::ConstantInt::get(Builder.getInt1Ty(), 1));
+      }
+    }
+  }
+  const llvm::Instruction *TI = BB->getTerminator();
+  if (TI) {
+    unsigned N = TI->getNumSuccessors();
+    for (unsigned I = 0; I < N; I++)
+      VolatilizeTryBlocks(TI->getSuccessor(I), V);
+  }
+}
+
 namespace {
 struct PerformSEHFinally final : EHScopeStack::Cleanup {
   llvm::Function *OutlinedFinally;
@@ -2050,6 +2121,12 @@
     return;
   }
 
+  // IsEHa: emit an invoke _seh_try_end() to mark end of FT flow
+  if (getLangOpts().EHAsynch && Builder.GetInsertBlock()) {
+    llvm::FunctionCallee SehTryEnd = getSehTryEndFn(CGM);
+    EmitRuntimeCallOrInvoke(SehTryEnd);
+  }
+
   // Otherwise, we must have an __except block.
   const SEHExceptStmt *Except = S.getExceptHandler();
   assert(Except && "__try must have __finally xor __except");
Index: clang/lib/CodeGen/CGDecl.cpp
===================================================================
--- clang/lib/CodeGen/CGDecl.cpp
+++ clang/lib/CodeGen/CGDecl.cpp
@@ -1997,9 +1997,16 @@
   const VarDecl &D = *emission.Variable;
 
   // Check the type for a cleanup.
-  if (QualType::DestructionKind dtorKind = D.needsDestruction(getContext()))
+  if (QualType::DestructionKind dtorKind = D.needsDestruction(getContext())) {
     emitAutoVarTypeCleanup(emission, dtorKind);
 
+    // Under -EHa, Invoke llvm.eha.scope.begin() right after
+    //   Ctor is emitted and EHStack.pushCleanup
+    bool IsEHa = getLangOpts().EHAsynch;
+    if (IsEHa && dtorKind == QualType::DK_cxx_destructor)
+      EmitSehCppScopeBegin();
+  }
+
   // In GC mode, honor objc_precise_lifetime.
   if (getLangOpts().getGC() != LangOptions::NonGC &&
       D.hasAttr<ObjCPreciseLifetimeAttr>()) {
Index: clang/lib/CodeGen/CGCleanup.cpp
===================================================================
--- clang/lib/CodeGen/CGCleanup.cpp
+++ clang/lib/CodeGen/CGCleanup.cpp
@@ -765,10 +765,21 @@
     destroyOptimisticNormalEntry(*this, Scope);
     EHStack.popCleanup();
   } else {
+    // Under -EHa, invoke eha_scope_end() to mark scope end before dtor
+    bool IsEHa = getLangOpts().EHAsynch && !Scope.isLifetimeMarker();
+    const EHPersonality &Personality = EHPersonality::get(*this);
+
     // If we have a fallthrough and no other need for the cleanup,
     // emit it directly.
-    if (HasFallthrough && !HasPrebranchedFallthrough &&
-        !HasFixups && !HasExistingBranches) {
+    if (HasFallthrough && !HasPrebranchedFallthrough && !HasFixups &&
+        !HasExistingBranches) {
+
+      // mark EHa scope end for fall-through flow
+      if (IsEHa && getInvokeDest())
+        if (Personality.isMSVCXXPersonality())
+          EmitSehCppScopeEnd();
+        else
+          EmitSehTryScopeEnd();
 
       destroyOptimisticNormalEntry(*this, Scope);
       EHStack.popCleanup();
@@ -803,6 +814,13 @@
       // should already be branched to it.
       EmitBlock(NormalEntry);
 
+      // intercept normal cleanup to mark EHa scope end
+      if (IsEHa)
+        if (Personality.isMSVCXXPersonality())
+          EmitSehCppScopeEnd();
+        else
+          EmitSehTryScopeEnd();
+
       // III.  Figure out where we're going and build the cleanup
       // epilogue.
 
@@ -1278,3 +1296,61 @@
   pushDestroy(NormalAndEHCleanup, Ptr, TempType, destroyCXXObject,
               /*useEHCleanup*/ true);
 }
+
+// Need to set "funclet" in OperandBundle properly for noThrow
+//       intrinsic (see CGCall.cpp)
+static void EmitSehEHaScope(CodeGenFunction &CGF,
+                            llvm::FunctionCallee &SehCppScope) {
+  llvm::BasicBlock *InvokeDest = CGF.getInvokeDest();
+  llvm::BasicBlock *BB = CGF.Builder.GetInsertBlock();
+  assert(BB && InvokeDest);
+  llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont");
+  SmallVector<llvm::OperandBundleDef, 1> BundleList =
+      CGF.getBundlesForFunclet(SehCppScope.getCallee());
+  if (CGF.CurrentFuncletPad)
+    BundleList.emplace_back("funclet", CGF.CurrentFuncletPad);
+  CGF.Builder.CreateInvoke(SehCppScope, Cont, InvokeDest, None, BundleList);
+  CGF.EmitBlock(Cont);
+}
+
+// Invoke a llvm.eha.scope.begin at the beginning of a CPP scope for -EHa
+void CodeGenFunction::EmitSehCppScopeBegin() {
+  assert(getLangOpts().EHAsynch);
+  llvm::FunctionType *FTy =
+      llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
+  llvm::FunctionCallee SehCppScope =
+      CGM.CreateRuntimeFunction(FTy, "llvm.eha.scope.begin");
+  EmitSehEHaScope(*this, SehCppScope);
+}
+
+// Invoke a llvm.eha.scope.end at the end of a CPP scope for -EHa
+//   llvm.eha.scope.end is emitted before popCleanup, so it's "invoked"
+void CodeGenFunction::EmitSehCppScopeEnd() {
+  assert(getLangOpts().EHAsynch);
+  llvm::FunctionType *FTy =
+      llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
+  llvm::FunctionCallee SehCppScope =
+      CGM.CreateRuntimeFunction(FTy, "llvm.eha.scope.end");
+  EmitSehEHaScope(*this, SehCppScope);
+}
+
+// Invoke a llvm.eha.scope.begin at the beginning of a CPP scope for -EHa
+void CodeGenFunction::EmitSehTryScopeBegin() {
+  assert(getLangOpts().EHAsynch);
+  llvm::FunctionType *FTy =
+      llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
+  llvm::FunctionCallee SehCppScope =
+      CGM.CreateRuntimeFunction(FTy, "llvm.seh.try.begin");
+  EmitSehEHaScope(*this, SehCppScope);
+}
+
+// Invoke a llvm.eha.scope.end at the end of a CPP scope for -EHa
+//   llvm.eha.scope.end is emitted before popCleanup, so it's "invoked"
+void CodeGenFunction::EmitSehTryScopeEnd() {
+  assert(getLangOpts().EHAsynch);
+  llvm::FunctionType *FTy =
+      llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
+  llvm::FunctionCallee SehCppScope =
+      CGM.CreateRuntimeFunction(FTy, "llvm.seh.try.end");
+  EmitSehEHaScope(*this, SehCppScope);
+}
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -883,6 +883,8 @@
 def fcreate_profile : Flag<["-"], "fcreate-profile">, Group<f_Group>;
 def fcxx_exceptions: Flag<["-"], "fcxx-exceptions">, Group<f_Group>,
   HelpText<"Enable C++ exceptions">, Flags<[CC1Option]>;
+def feh_asynch: Flag<["-"], "feh-asynch">, Group<f_Group>,
+  HelpText<"Enable EH Asynchronous exceptions">, Flags<[CC1Option]>;
 def fcxx_modules : Flag <["-"], "fcxx-modules">, Group<f_Group>,
   Flags<[DriverOption]>;
 def fdebug_pass_arguments : Flag<["-"], "fdebug-pass-arguments">, Group<f_Group>;
@@ -1526,6 +1528,7 @@
   Flags<[CC1Option]>,
   HelpText<"Disable creation of CodeFoundation-type constant strings">;
 def fno_cxx_exceptions: Flag<["-"], "fno-cxx-exceptions">, Group<f_Group>;
+def fno_eh_asynch: Flag<["-"], "fno-eh-asynch">, Group<f_Group>;
 def fno_cxx_modules : Flag <["-"], "fno-cxx-modules">, Group<f_Group>,
   Flags<[DriverOption]>;
 def fno_diagnostics_fixit_info : Flag<["-"], "fno-diagnostics-fixit-info">, Group<f_Group>,
Index: clang/include/clang/Basic/LangOptions.def
===================================================================
--- clang/include/clang/Basic/LangOptions.def
+++ clang/include/clang/Basic/LangOptions.def
@@ -128,6 +128,7 @@
 LANGOPT(Exceptions        , 1, 0, "exception handling")
 LANGOPT(ObjCExceptions    , 1, 0, "Objective-C exceptions")
 LANGOPT(CXXExceptions     , 1, 0, "C++ exceptions")
+LANGOPT(EHAsynch          , 1, 0, "C/C++ EH Asynch exceptions")
 LANGOPT(DWARFExceptions   , 1, 0, "dwarf exception handling")
 LANGOPT(SjLjExceptions    , 1, 0, "setjmp-longjump exception handling")
 LANGOPT(SEHExceptions     , 1, 0, "SEH .xdata exception handling")
Index: clang/include/clang/AST/Stmt.h
===================================================================
--- clang/include/clang/AST/Stmt.h
+++ clang/include/clang/AST/Stmt.h
@@ -1743,6 +1743,7 @@
 class LabelStmt : public ValueStmt {
   LabelDecl *TheDecl;
   Stmt *SubStmt;
+  bool SideEntry = false;
 
 public:
   /// Build a label statement.
@@ -1778,6 +1779,9 @@
   static bool classof(const Stmt *T) {
     return T->getStmtClass() == LabelStmtClass;
   }
+
+  bool IsSideEntry() const { return SideEntry; }
+  void setSideEntry() { SideEntry = true; }
 };
 
 /// Represents an attribute applied to a statement.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to