Update hardware exceptions patch
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Rafal Kupiec 2020-11-19 21:51:59 +01:00
parent 757c207121
commit d7d7ac54b6
Signed by: belliash
GPG Key ID: 4E829243E0CFE6B4
1 changed files with 360 additions and 95 deletions

View File

@ -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::FunctionCallee SehCppScope =
+ CGM.CreateRuntimeFunction(FTy, "llvm.seh.try.begin");
+ EmitSehEHaScope(*this, SehCppScope);
+ 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::FunctionCallee SehCppScope =
+ CGM.CreateRuntimeFunction(FTy, "llvm.seh.try.end");
+ EmitSehEHaScope(*this, SehCppScope);
+ 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 ||