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, Flags<[DriverOption]>; def fno_diagnostics_fixit_info : Flag<["-"], "fno-diagnostics-fixit-info">, 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()) { +\ 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(To)); + LabelStmt *Label = cast(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(); + 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 ||