From 8bd3e41c197c4e39554d86cd92fc490d0d1c3296 Mon Sep 17 00:00:00 2001
From: Rafal Kupiec <belliash@codingworkshop.eu.org>
Date: Thu, 19 Nov 2020 21:51:59 +0100
Subject: [PATCH] Update hardware exceptions patch

---
 .../001-hardware-exception-handling.patch     | 455 ++++++++++++++----
 1 file changed, 360 insertions(+), 95 deletions(-)

diff --git a/patches/llvm/11.0.0/001-hardware-exception-handling.patch b/patches/llvm/11.0.0/001-hardware-exception-handling.patch
index 7df2fb8..3b0d37c 100644
--- a/patches/llvm/11.0.0/001-hardware-exception-handling.patch
+++ b/patches/llvm/11.0.0/001-hardware-exception-handling.patch
@@ -1,5 +1,5 @@
 diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
-index d3fad58fcf5..dccbbe2fade 100644
+index d3fad58fcf5..77153f85a93 100644
 --- a/clang/include/clang/AST/Stmt.h
 +++ b/clang/include/clang/AST/Stmt.h
 @@ -1764,6 +1764,7 @@ public:
@@ -16,7 +16,7 @@ index d3fad58fcf5..dccbbe2fade 100644
    }
 +
 +  bool isSideEntry() const { return SideEntry; }
-+  void setSideEntry() { SideEntry = true; }
++  void setSideEntry(bool SE) { SideEntry = SE; }
  };
  
  /// Represents an attribute applied to a statement.
@@ -53,18 +53,64 @@ index 966cb907b7e..dc7b38c254f 100644
  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>,
+diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp
+index 4bd00ece86a..7cc6089b711 100644
+--- a/clang/lib/AST/JSONNodeDumper.cpp
++++ b/clang/lib/AST/JSONNodeDumper.cpp
+@@ -1444,6 +1444,7 @@ void JSONNodeDumper::VisitCaseStmt(const CaseStmt *CS) {
+ void JSONNodeDumper::VisitLabelStmt(const LabelStmt *LS) {
+   JOS.attribute("name", LS->getName());
+   JOS.attribute("declId", createPointerRepresentation(LS->getDecl()));
++  attributeOnlyIfTrue("sideEntry", LS->isSideEntry());
+ }
+ void JSONNodeDumper::VisitGotoStmt(const GotoStmt *GS) {
+   JOS.attribute("targetLabelDeclId",
+diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
+index 5b0a0ac392c..0d5e9418fb7 100644
+--- a/clang/lib/AST/TextNodeDumper.cpp
++++ b/clang/lib/AST/TextNodeDumper.cpp
+@@ -916,6 +916,8 @@ void TextNodeDumper::VisitWhileStmt(const WhileStmt *Node) {
+ 
+ void TextNodeDumper::VisitLabelStmt(const LabelStmt *Node) {
+   OS << " '" << Node->getName() << "'";
++  if (Node->isSideEntry())
++    OS << " side_entry";
+ }
+ 
+ void TextNodeDumper::VisitGotoStmt(const GotoStmt *Node) {
 diff --git a/clang/lib/CodeGen/CGCleanup.cpp b/clang/lib/CodeGen/CGCleanup.cpp
-index ad543ef86c1..7c1902f080f 100644
+index ad543ef86c1..3b69bb20b06 100644
 --- a/clang/lib/CodeGen/CGCleanup.cpp
 +++ b/clang/lib/CodeGen/CGCleanup.cpp
-@@ -763,10 +763,22 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
+@@ -194,6 +194,11 @@ void *EHScopeStack::pushCleanup(CleanupKind Kind, size_t Size) {
+   if (IsLifetimeMarker)
+     Scope->setLifetimeMarker();
+ 
++  // With Windows -EHa, Invoke llvm.seh.scope.begin() for EHCleanup
++  if (CGF->getLangOpts().EHAsynch && IsEHCleanup && 
++    CGF->getTarget().getCXXABI().isMicrosoft())
++    CGF->EmitSehCppScopeBegin();
++
+   return Scope->getCleanupBuffer();
+ }
+ 
+@@ -759,14 +764,31 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
+   if (Scope.isEHCleanup())
+     cleanupFlags.setIsEHCleanupKind();
+ 
++  // Under -EHa, invoke seh.scope.end() to mark scope end before dtor
++  bool IsEHa = getLangOpts().EHAsynch && !Scope.isLifetimeMarker();
++  const EHPersonality& Personality = EHPersonality::get(*this);
+   if (!RequiresNormalCleanup) {
++    // Mark CPP scope end for passed-by-value Arg temp
++    //   per Windows ABI which is "normally" Cleanup in callee
++    if (IsEHa && getInvokeDest()) {
++      if (Personality.isMSVCXXPersonality())
++        EmitSehCppScopeEnd();
++    }
      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 &&
@@ -72,39 +118,63 @@ index ad543ef86c1..7c1902f080f 100644
 +    if (HasFallthrough && !HasPrebranchedFallthrough && !HasFixups &&
 +        !HasExistingBranches) {
 +
-+      // mark EHa scope end for fall-through flow
-+      if (IsEHa && getInvokeDest())
++      // mark SEH scope end for fall-through flow
++      if (IsEHa && getInvokeDest()) {
 +        if (Personality.isMSVCXXPersonality())
 +          EmitSehCppScopeEnd();
-+        else {
++        else
 +          EmitSehTryScopeEnd();
-+        }
++      }
  
        destroyOptimisticNormalEntry(*this, Scope);
        EHStack.popCleanup();
-@@ -801,6 +813,14 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
+@@ -801,6 +823,14 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
        // should already be branched to it.
        EmitBlock(NormalEntry);
  
-+      // intercept normal cleanup to mark EHa scope end
-+      if (IsEHa)
++      // intercept normal cleanup to mark SEH scope end
++      if (IsEHa) {
 +        if (Personality.isMSVCXXPersonality())
 +          EmitSehCppScopeEnd();
-+        else {
++        else
 +          EmitSehTryScopeEnd();
-+        }
++      }
 +
        // III.  Figure out where we're going and build the cleanup
        // epilogue.
  
-@@ -1276,3 +1296,61 @@ void CodeGenFunction::EmitCXXTemporary(const CXXTemporary *Temporary,
+@@ -1248,11 +1278,18 @@ void CodeGenFunction::DeactivateCleanupBlock(EHScopeStack::stable_iterator C,
+   // to the current RunCleanupsScope.
+   if (C == EHStack.stable_begin() &&
+       CurrentCleanupScopeDepth.strictlyEncloses(C)) {
+-    // If it's a normal cleanup, we need to pretend that the
+-    // fallthrough is unreachable.
+-    CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP();
+-    PopCleanupBlock();
+-    Builder.restoreIP(SavedIP);
++    // Per comment below, checking EHAsynch is not really necessary
++    // it's there to assure zero-impact w/o EHAsynch option
++    if (!Scope.isNormalCleanup() && getLangOpts().EHAsynch)
++      PopCleanupBlock();
++    else
++    {
++      // If it's a normal cleanup, we need to pretend that the
++      // fallthrough is unreachable.
++      CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP();
++      PopCleanupBlock();
++      Builder.restoreIP(SavedIP);
++    }
+     return;
+   }
+ 
+@@ -1276,3 +1313,60 @@ void CodeGenFunction::EmitCXXTemporary(const CXXTemporary *Temporary,
    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,
++static void EmitSehScope(CodeGenFunction &CGF,
 +                            llvm::FunctionCallee &SehCppScope) {
 +  llvm::BasicBlock *InvokeDest = CGF.getInvokeDest();
 +  llvm::BasicBlock *BB = CGF.Builder.GetInsertBlock();
@@ -118,69 +188,47 @@ index ad543ef86c1..7c1902f080f 100644
 +  CGF.EmitBlock(Cont);
 +}
 +
-+// Invoke a llvm.eha.scope.begin at the beginning of a CPP scope for -EHa
++// Invoke a llvm.seh.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);
++      CGM.CreateRuntimeFunction(FTy, "llvm.seh.scope.begin");
++  EmitSehScope(*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"
++// Invoke a llvm.seh.scope.end at the end of a CPP scope for -EHa
++//   llvm.seh.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);
++      CGM.CreateRuntimeFunction(FTy, "llvm.seh.scope.end");
++  EmitSehScope(*this, SehCppScope);
 +}
 +
-+// Invoke a llvm.eha.scope.begin at the beginning of a CPP scope for -EHa
++// Invoke a llvm.seh.try.begin at the beginning of a SEH scope for -EHa
 +void CodeGenFunction::EmitSehTryScopeBegin() {
 +  assert(getLangOpts().EHAsynch);
-+  llvm::FunctionType *FTy =
-+      llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
++  llvm::FunctionType* FTy =
++    llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
 +  llvm::FunctionCallee SehCppScope =
-+      CGM.CreateRuntimeFunction(FTy, "llvm.seh.try.begin");
-+  EmitSehEHaScope(*this, SehCppScope);
++    CGM.CreateRuntimeFunction(FTy, "llvm.seh.try.begin");
++  EmitSehScope(*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"
++// Invoke a llvm.seh.try.end at the end of a SEH scope for -EHa
 +void CodeGenFunction::EmitSehTryScopeEnd() {
 +  assert(getLangOpts().EHAsynch);
-+  llvm::FunctionType *FTy =
-+      llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
++  llvm::FunctionType* FTy =
++    llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
 +  llvm::FunctionCallee SehCppScope =
-+      CGM.CreateRuntimeFunction(FTy, "llvm.seh.try.end");
-+  EmitSehEHaScope(*this, SehCppScope);
++    CGM.CreateRuntimeFunction(FTy, "llvm.seh.try.end");
++  EmitSehScope(*this, SehCppScope);
 +}
-diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
-index 1729c7ed3c3..c9107b1296f 100644
---- a/clang/lib/CodeGen/CGDecl.cpp
-+++ b/clang/lib/CodeGen/CGDecl.cpp
-@@ -2006,9 +2006,16 @@ void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) {
-   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>()) {
+\ No newline at end of file
 diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp
 index bdf70252b5a..a4e4d7d8120 100644
 --- a/clang/lib/CodeGen/CGException.cpp
@@ -353,6 +401,18 @@ index 672909849bb..32dca08b8cf 100644
    EmitStmt(S.getSubStmt());
  }
  
+diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
+index 8ce488f35dd..4cc8304c455 100644
+--- a/clang/lib/CodeGen/CodeGenFunction.cpp
++++ b/clang/lib/CodeGen/CodeGenFunction.cpp
+@@ -71,6 +71,7 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext)
+           shouldEmitLifetimeMarkers(CGM.getCodeGenOpts(), CGM.getLangOpts())) {
+   if (!suppressNewContext)
+     CGM.getCXXABI().getMangleContext().startNewFunction();
++  EHStack.setCGF(this);
+ 
+   SetFastMathFlags(CurFPFeatures);
+   SetFPModel();
 diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
 index d794f4f0fa8..1b5892c7459 100644
 --- a/clang/lib/CodeGen/CodeGenFunction.h
@@ -392,6 +452,38 @@ index 4ae8ce7e5cc..5512c8fe88a 100644
    // Emit OpenCL specific module metadata: OpenCL/SPIR version.
    if (LangOpts.OpenCL) {
      EmitOpenCLMetadata();
+diff --git a/clang/lib/CodeGen/EHScopeStack.h b/clang/lib/CodeGen/EHScopeStack.h
+index 3a640d6117d..60fe9b3c9dd 100644
+--- a/clang/lib/CodeGen/EHScopeStack.h
++++ b/clang/lib/CodeGen/EHScopeStack.h
+@@ -236,6 +236,9 @@ private:
+   /// The innermost EH scope on the stack.
+   stable_iterator InnermostEHScope;
+ 
++  /// The CGF this Stack belong to
++  CodeGenFunction* CGF;
++
+   /// The current set of branch fixups.  A branch fixup is a jump to
+   /// an as-yet unemitted label, i.e. a label for which we don't yet
+   /// know the EH stack depth.  Whenever we pop a cleanup, we have
+@@ -263,7 +266,7 @@ private:
+ public:
+   EHScopeStack() : StartOfBuffer(nullptr), EndOfBuffer(nullptr),
+                    StartOfData(nullptr), InnermostNormalCleanup(stable_end()),
+-                   InnermostEHScope(stable_end()) {}
++                   InnermostEHScope(stable_end()), CGF(nullptr) {}
+   ~EHScopeStack() { delete[] StartOfBuffer; }
+ 
+   /// Push a lazily-created cleanup on the stack.
+@@ -311,6 +314,8 @@ public:
+     std::memcpy(Buffer, Cleanup, Size);
+   }
+ 
++  void setCGF(CodeGenFunction* inCGF) { CGF = inCGF; }
++
+   /// Pops a cleanup scope off the stack.  This is private to CGCleanup.cpp.
+   void popCleanup();
+ 
 diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
 index 45c6cb6b2e0..a080c93356a 100644
 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -460,7 +552,7 @@ index 73114c6d76c..b58af0b68e7 100644
    // -ffixed-point
    Opts.FixedPoint =
 diff --git a/clang/lib/Sema/JumpDiagnostics.cpp b/clang/lib/Sema/JumpDiagnostics.cpp
-index b34243edea3..cbc309a3d42 100644
+index b34243edea3..304f059a032 100644
 --- a/clang/lib/Sema/JumpDiagnostics.cpp
 +++ b/clang/lib/Sema/JumpDiagnostics.cpp
 @@ -930,6 +930,9 @@ void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc,
@@ -469,13 +561,43 @@ index b34243edea3..cbc309a3d42 100644
      NoteJumpIntoScopes(ToScopesWarning);
 +    assert(isa<LabelStmt>(To));
 +    LabelStmt *Label = cast<LabelStmt>(To);
-+    Label->setSideEntry();
++    Label->setSideEntry(true);
    }
  
    // Handle errors.
+diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
+index a40c5499a6d..bfed22a1252 100644
+--- a/clang/lib/Serialization/ASTReaderStmt.cpp
++++ b/clang/lib/Serialization/ASTReaderStmt.cpp
+@@ -185,11 +185,13 @@ void ASTStmtReader::VisitDefaultStmt(DefaultStmt *S) {
+ 
+ void ASTStmtReader::VisitLabelStmt(LabelStmt *S) {
+   VisitStmt(S);
++  bool IsSideEntry = Record.readInt();
+   auto *LD = readDeclAs<LabelDecl>();
+   LD->setStmt(S);
+   S->setDecl(LD);
+   S->setSubStmt(Record.readSubStmt());
+   S->setIdentLoc(readSourceLocation());
++  S->setSideEntry(IsSideEntry);
+ }
+ 
+ void ASTStmtReader::VisitAttributedStmt(AttributedStmt *S) {
+diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
+index 0767b3a24bf..614fd45d193 100644
+--- a/clang/lib/Serialization/ASTWriterStmt.cpp
++++ b/clang/lib/Serialization/ASTWriterStmt.cpp
+@@ -115,6 +115,7 @@ void ASTStmtWriter::VisitDefaultStmt(DefaultStmt *S) {
+ 
+ void ASTStmtWriter::VisitLabelStmt(LabelStmt *S) {
+   VisitStmt(S);
++  Record.push_back(S->isSideEntry());
+   Record.AddDeclRef(S->getDecl());
+   Record.AddStmt(S->getSubStmt());
+   Record.AddSourceLocation(S->getIdentLoc());
 diff --git a/clang/test/CodeGen/windows-seh-EHa-CppCatchDotDotDot.cpp b/clang/test/CodeGen/windows-seh-EHa-CppCatchDotDotDot.cpp
 new file mode 100644
-index 00000000000..4f261ab59ee
+index 00000000000..2928a610d3c
 --- /dev/null
 +++ b/clang/test/CodeGen/windows-seh-EHa-CppCatchDotDotDot.cpp
 @@ -0,0 +1,58 @@
@@ -483,8 +605,8 @@ index 00000000000..4f261ab59ee
 +
 +// 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: invoke void @llvm.seh.scope.begin()
++// CHECK: invoke void @llvm.seh.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]
@@ -537,20 +659,156 @@ index 00000000000..4f261ab59ee
 +  }
 +  return 0;
 +}
+diff --git a/clang/test/CodeGen/windows-seh-EHa-CppCondiTemps.cpp b/clang/test/CodeGen/windows-seh-EHa-CppCondiTemps.cpp
+new file mode 100644
+index 00000000000..d588d6e2292
+--- /dev/null
++++ b/clang/test/CodeGen/windows-seh-EHa-CppCondiTemps.cpp
+@@ -0,0 +1,129 @@
++// 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 i32 @"?bar@@YAHHVB1@@VB2@@@Z"
++// CHECK: %coerce.dive1 = getelementptr inbounds %class.B2
++// CHECK: %coerce.dive2 = getelementptr inbounds %class.B1
++// -----   scope begin of two passed-by-value temps  
++// CHECK: invoke void @llvm.seh.scope.begin()
++// CHECK: invoke void @llvm.seh.scope.begin()
++// CHECK: invoke void @llvm.seh.scope.end()
++// CHECK: call void @"??1B1@@QEAA@XZ"
++// CHECK: invoke void @llvm.seh.scope.end()
++// CHECK: call void @"??1B2@@QEAA@XZ"
++
++// CHECK: define linkonce_odr dso_local void @"??1B2@@QEAA@XZ"
++// CHECK: %this.addr = alloca %class.B2*
++// -----  B1 scope begin without base ctor
++// CHECK: invoke void @llvm.seh.scope.begin()
++// CHECK: invoke void @llvm.seh.scope.end()
++// CHECK: call void @"??1B1@@QEAA@XZ"
++
++// CHECK: define dso_local void @"?goo@@YA?AVB1@@H@Z"
++// CHECK: call %class.B2* @"??0B2@@QEAA@XZ"(%class.B2* %b2ingoo)
++// CHECK: invoke void @llvm.seh.scope.begin()
++// check: call void @llvm.memcpy
++// CHECK: invoke void @llvm.seh.scope.end()
++// CHECK: call void @"??1B2@@QEAA@XZ"(%class.B2* %b2ingoo)
++
++// CHECK: define linkonce_odr dso_local %class.B2* @"??0B2@@QEAA@XZ"
++// CHECK: call %class.B1* @"??0B1@@QEAA@XZ"(%class.B1*
++// -----  scope begin of base ctor 
++// CHECK: invoke void @llvm.seh.scope.begin()
++// CHECK: invoke void @llvm.seh.scope.end()
++// -----  B1 scope end without base dtor
++
++// ****************************************************************************
++// Abstract:     Test CPP Conditional-Expr & ABI Temps under SEH -EHa option
++
++void printf(...);
++
++int xxxx = 0;
++int* ptr; 
++
++int foo(int a)
++{
++  return xxxx + a;
++}
++
++class B1      {
++public:
++   int data = 90;
++   B1() { foo(data + 111); }
++    ~B1() { printf("in B1 Dtor \n"); }
++};
++class B2 : public B1 {
++public:
++  B2() { foo(data + 222); }
++  ~B2() { printf("in B2 Dtor \n");; }
++};
++class B3 : public B2 {
++public:
++  B3() { foo(data + 333); }
++  ~B3() { printf("in B3 Dtor \n");; }
++};
++
++int bar(int j, class B1 b1Bar, class B2 b2Bar)
++{
++  int ww;
++  if ( j > 0)
++    ww = b1Bar.data;
++  else
++    ww = b2Bar.data;
++  return  ww + *ptr;
++}
++
++class B1 goo(int w)
++{
++  class B2 b2ingoo;
++  b2ingoo.data += w;
++  return b2ingoo;
++}
++
++// CHECK: define dso_local i32 @main()
++// CHECK: invoke void @llvm.seh.scope.begin()
++// ---   beginning of conditional temp test
++// CHECK: invoke %class.B2* @"??0B2@@QEAA@XZ"
++// CHECK: invoke void @llvm.seh.scope.begin()
++// CHECK: invoke %class.B3* @"??0B3@@QEAA@XZ"
++// CHECK: invoke void @llvm.seh.scope.begin()
++// CHECK: invoke void @llvm.seh.scope.end()
++// CHECK: call void @"??1B3@@QEAA@XZ"
++// CHECK: invoke void @llvm.seh.scope.end()
++// CHECK: call void @"??1B2@@QEAA@XZ"
++// -----  end of conditional temp test
++
++// -----  testing caller's passed-by-value temps
++//        setting scope in case exception occurs before the call
++// check: invoke %class.B2* @"??0B2@@QEAA@XZ"
++// CHECK: invoke void @llvm.seh.scope.begin()
++// CHECK: invoke %class.B1* @"??0B1@@QEAA@XZ"
++// CHECK: invoke void @llvm.seh.scope.begin()
++// -----   end of temps' scope right before callee
++// CHECK: invoke void @llvm.seh.scope.end()
++// CHECK: invoke void @llvm.seh.scope.end()
++// CHECK: invoke i32 @"?bar@@YAHHVB1@@VB2@@@Z"
++
++// -----  testing caller's return-by-value temp
++//        scope begins right after callee which is the ctor of return temp
++// CHECK: void @"?goo@@YA?AVB1@@H@Z"
++// CHECK: invoke void @llvm.seh.scope.begin()
++// CHECK: invoke void @llvm.seh.scope.end()
++
++int main() {
++  class B3 b3inmain;
++
++  // Test conditional ctor and dtor
++  int m = (xxxx > 1) ? B2().data + foo(99) : 
++      B3().data + foo(88);
++
++  // Test: passed-in by value
++  // Per Windows ABI, ctored by caller, dtored by callee
++  int i = bar(foo(0), B1(), B2());
++
++  // Test: returned by value
++  // Per Windows ABI, caller allocate a temp in stack, then ctored by callee, 
++  //          finally dtored in caller after consumed
++  class B1 b1fromgoo = goo(i);
++
++  return m + b1fromgoo.data + b3inmain.data;
++}
+\ No newline at end of file
 diff --git a/clang/test/CodeGen/windows-seh-EHa-CppDtors01.cpp b/clang/test/CodeGen/windows-seh-EHa-CppDtors01.cpp
 new file mode 100644
-index 00000000000..d731bbb8ad2
+index 00000000000..8fdb1e889c4
 --- /dev/null
 +++ b/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.scope.begin()
++// CHECK: invoke void @llvm.seh.scope.begin()
++// CHECK: invoke void @llvm.seh.scope.begin()
++// CHECK: invoke void @llvm.seh.scope.end()
++// CHECK: invoke void @llvm.seh.scope.end()
++// CHECK: invoke void @llvm.seh.scope.end()
 +
 +// CHECK: invoke void @llvm.seh.try.begin()
 +// CHECK: %[[src:[0-9-]+]] = load volatile i32, i32* %i
@@ -652,10 +910,10 @@ index 00000000000..3efd7d6505f
 +  return 0;
 +}
 diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
-index 9b58b9dfb17..1738ccd94ee 100644
+index 9b58b9dfb17..7ba418ab7d0 100644
 --- a/llvm/docs/LangRef.rst
 +++ b/llvm/docs/LangRef.rst
-@@ -11642,6 +11642,59 @@ The '``llvm.localescape``' intrinsic blocks inlining, as inlining changes where
+@@ -11642,6 +11642,66 @@ The '``llvm.localescape``' intrinsic blocks inlining, as inlining changes where
  the escaped allocas are allocated, which would break attempts to use
  '``llvm.localrecover``'.
  
@@ -683,7 +941,7 @@ index 9b58b9dfb17..1738ccd94ee 100644
 +-feh_asynch (aka MSVC -EHa), these two intrinsics are injected to mark _try
 +boundary and to prevent from potential exceptions being moved across boundary.
 +
-+'``llvm.eha.scope.begin``' and '``llvm.eha.scope.end``' Intrinsics
++'``llvm.seh.scope.begin``' and '``llvm.seh.scope.end``' Intrinsics
 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +Syntax:
@@ -691,32 +949,39 @@ index 9b58b9dfb17..1738ccd94ee 100644
 +
 +::
 +
-+      declare void @llvm.eha.scope.begin()
-+      declare void @llvm.eha.scope.end()
++      declare void @llvm.seh.scope.begin()
++      declare void @llvm.seh.scope.end()
 +
 +Overview:
 +"""""""""
 +
-+The '``llvm.eha.scope.begin``' and '``llvm.eha.scope.end``' intrinsics mark
++The '``llvm.seh.scope.begin``' and '``llvm.seh.scope.end``' intrinsics mark
 +the boundary of a CPP object lifetime for Windows SEH Asynchrous Exception
 +Handling (MSVC option -EHa).
 +
 +Semantics:
 +""""""""""
 +
-+'``llvm.eha.scope.begin``' is added immediately after an object constructor is
-+called, i.e., EHStack is not empty. So it will be an invoke, not a call.
-+With that it's also guaranteed that an associated EH-cleanup-pad is
-+created in IR regardless whether there exists a call in this object lifetime.
-+'``llvm.eha.scope.end``' is added before the object destructor.
-+These intrinsics make Block-level State computation possible in downstream
-+LLVM code gen pass, even in the presence of ctor/dtor inlining.
++LLVM's ordinary exception-handling representation associates EH cleanups and
++handlers only with ``invoke``s, which normally correspond only to call sites.  To
++support arbitrary faulting instructions, it must be possible to recover the current
++EH scope for any instruction.  Turning every operation in LLVM that could fault
++into an ``invoke`` of a new, potentially-throwing intrinsic would require adding a
++large number of intrinsics, impede optimization of those operations, and make
++compilation slower by introducing many extra basic blocks.  These intrinsics can
++be used instead to mark the region protected by a cleanup, such as for a local
++C++ object with a non-trivial destructor.  ``llvm.seh.scope.begin`` is used to mark
++the start of the region; it is aways called with ``invoke``, with the unwind block
++being the desired unwind destination for any potentially-throwing instructions
++within the region.  `llvm.seh.scope.end` is used to mark when the scope ends
++and the EH cleanup is no longer required (e.g. because the destructor is being
++called).
 +
  .. _int_read_register:
  .. _int_read_volatile_register:
  .. _int_write_register:
 diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td
-index 4918ea876df..7de760291d9 100644
+index 4918ea876df..0d33b64998d 100644
 --- a/llvm/include/llvm/IR/Intrinsics.td
 +++ b/llvm/include/llvm/IR/Intrinsics.td
 @@ -481,6 +481,16 @@ def int_eh_recoverfp : Intrinsic<[llvm_ptr_ty],
@@ -730,14 +995,14 @@ index 4918ea876df..7de760291d9 100644
 +//   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]>;
++def int_seh_scope_begin : Intrinsic<[], [], [IntrNoMem]>;
++def int_seh_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]>,
 diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
-index d2930391f87..7e58de39962 100644
+index d2930391f87..0e5a78f314b 100644
 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
 +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
 @@ -2801,6 +2801,10 @@ void SelectionDAGBuilder::visitInvoke(const InvokeInst &I) {
@@ -745,9 +1010,9 @@ index d2930391f87..7e58de39962 100644
      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_scope_begin:
 +    case Intrinsic::seh_try_end:
-+    case Intrinsic::eha_scope_end:
++    case Intrinsic::seh_scope_end:
        break;
      case Intrinsic::experimental_patchpoint_void:
      case Intrinsic::experimental_patchpoint_i64:
@@ -756,14 +1021,14 @@ index d2930391f87..7e58de39962 100644
      return;
    case Intrinsic::donothing:
 +  case Intrinsic::seh_try_begin:
-+  case Intrinsic::eha_scope_begin:
++  case Intrinsic::seh_scope_begin:
 +  case Intrinsic::seh_try_end:
-+  case Intrinsic::eha_scope_end:
++  case Intrinsic::seh_scope_end:
      // ignore
      return;
    case Intrinsic::experimental_stackmap:
 diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
-index c518ae87ea9..87dd063ee2e 100644
+index c518ae87ea9..6fb5e60c34a 100644
 --- a/llvm/lib/IR/Verifier.cpp
 +++ b/llvm/lib/IR/Verifier.cpp
 @@ -4269,6 +4269,10 @@ void Verifier::visitInstruction(Instruction &I) {
@@ -772,8 +1037,8 @@ index c518ae87ea9..87dd063ee2e 100644
                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::seh_scope_begin ||
++              F->getIntrinsicID() == Intrinsic::seh_scope_end ||
                F->getIntrinsicID() == Intrinsic::coro_resume ||
                F->getIntrinsicID() == Intrinsic::coro_destroy ||
                F->getIntrinsicID() == Intrinsic::experimental_patchpoint_void ||