diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h --- a/clang/include/clang/AST/Stmt.h +++ b/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(bool SE) { SideEntry = SE; } }; /// Represents an attribute applied to a statement. diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def --- a/clang/include/clang/Basic/LangOptions.def +++ b/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") diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -883,6 +883,8 @@ def fcreate_profile : Flag<["-"], "fcreate-profile">, Group; def fcxx_exceptions: Flag<["-"], "fcxx-exceptions">, Group, HelpText<"Enable C++ exceptions">, Flags<[CC1Option]>; +def fasync_exceptions: Flag<["-"], "fasync-exceptions">, Group, + HelpText<"Enable EH Asynchronous exceptions">, Flags<[CC1Option]>; def fcxx_modules : Flag <["-"], "fcxx-modules">, Group, Flags<[DriverOption]>; def fdebug_pass_arguments : Flag<["-"], "fdebug-pass-arguments">, Group; @@ -1526,6 +1528,7 @@ Flags<[CC1Option]>, HelpText<"Disable creation of CodeFoundation-type constant strings">; def fno_cxx_exceptions: Flag<["-"], "fno-cxx-exceptions">, Group; +def fno_fasync_exceptions: Flag<["-"], "fno-fasync-exceptions">, Group; 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 --- a/clang/lib/AST/JSONNodeDumper.cpp +++ b/clang/lib/AST/JSONNodeDumper.cpp @@ -1448,6 +1448,7 @@ 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 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -695,6 +695,8 @@ 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 --- a/clang/lib/CodeGen/CGCleanup.cpp +++ b/clang/lib/CodeGen/CGCleanup.cpp @@ -196,6 +196,11 @@ 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(); } @@ -761,14 +766,31 @@ 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 { // 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 SEH scope end for fall-through flow + if (IsEHa && getInvokeDest()) { + if (Personality.isMSVCXXPersonality()) + EmitSehCppScopeEnd(); + else + EmitSehTryScopeEnd(); + } destroyOptimisticNormalEntry(*this, Scope); EHStack.popCleanup(); @@ -803,6 +825,14 @@ // should already be branched to it. EmitBlock(NormalEntry); + // intercept normal cleanup to mark SEH scope end + if (IsEHa) { + if (Personality.isMSVCXXPersonality()) + EmitSehCppScopeEnd(); + else + EmitSehTryScopeEnd(); + } + // III. Figure out where we're going and build the cleanup // epilogue. @@ -1250,11 +1280,18 @@ // 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; } @@ -1278,3 +1315,60 @@ pushDestroy(NormalAndEHCleanup, Ptr, TempType, destroyCXXObject, /*useEHCleanup*/ true); } + +// Need to set "funclet" in OperandBundle properly for noThrow +// intrinsic (see CGCall.cpp) +static void EmitSehScope(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 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.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.seh.scope.begin"); + EmitSehScope(*this, SehCppScope); +} + +// 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.seh.scope.end"); + EmitSehScope(*this, SehCppScope); +} + +// 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"); + EmitSehScope(*this, SehCppScope); +} + +// 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"); + EmitSehScope(*this, SehCppScope); +} \ No newline at end of file diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp --- a/clang/lib/CodeGen/CGException.cpp +++ b/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); @@ -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(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 under async exceptions */) { EHStack.popTerminate(); } else if (EST == EST_Dynamic || EST == EST_DynamicNone) { // TODO: Revisit exception specifications for the MS ABI. There is a way to @@ -585,6 +599,10 @@ } else { // No exception decl indicates '...', a catch-all. CatchScope->setHandler(I, CGM.getCXXABI().getCatchAllTypeInfo(), Handler); + // Under async exceptions, catch(...) need to catch HW exception too + // Mark scope with SehTryBegin as a SEH __try scope + if (getLangOpts().EHAsynch) + EmitRuntimeCallOrInvoke(getSehTryBeginFn(CGM)); } } } @@ -706,7 +724,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 +1620,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 Visited; + VolatilizeTryBlocks(TryBB, Visited); + } + SEHTryEpilogueStack.pop_back(); if (!TryExit.getBlock()->use_empty()) @@ -1613,6 +1647,38 @@ ExitSEHTryStmt(S); } +// Recursively walk through blocks in a _try +// and make all memory instructions volatile +void CodeGenFunction::VolatilizeTryBlocks( + llvm::BasicBlock *BB, llvm::SmallPtrSet &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(J)) { + auto LI = dyn_cast(J); + LI->setVolatile(true); + } else if (isa(J)) { + auto SI = dyn_cast(J); + SI->setVolatile(true); + } else if (isa(J)) { + auto *MCI = dyn_cast(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 +2116,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"); diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/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()); } diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/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 &V); void pushSEHCleanup(CleanupKind kind, llvm::Function *FinallyFunc); diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -70,6 +70,7 @@ CGM.getCodeGenOpts(), CGM.getLangOpts())) { if (!suppressNewContext) CGM.getCXXABI().getMangleContext().startNewFunction(); + EHStack.setCGF(this); llvm::FastMathFlags FMF; if (CGM.getLangOpts().FastMath) diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/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(); diff --git a/clang/lib/CodeGen/EHScopeStack.h b/clang/lib/CodeGen/EHScopeStack.h --- a/clang/lib/CodeGen/EHScopeStack.h +++ b/clang/lib/CodeGen/EHScopeStack.h @@ -241,6 +241,9 @@ /// 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 @@ -268,7 +271,7 @@ 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. @@ -316,6 +319,8 @@ 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 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -131,7 +131,12 @@ /// MSVC needs an extra flag to indicate a catchall. CatchTypeInfo getCatchAllTypeInfo() override { - return CatchTypeInfo{nullptr, 0x40}; + // For -EHa catch(...) must handle HW exception + // Adjective = HT_IsStdDotDot (0x40), only catch C++ exceptions + if (getContext().getLangOpts().EHAsynch) + return CatchTypeInfo{nullptr, 0}; + else + return CatchTypeInfo{nullptr, 0x40}; } bool shouldTypeidBeNullChecked(bool IsDeref, QualType SrcRecordTy) override; diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/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_fasync_exceptions); 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_fasync_exceptions, + options::OPT_fasync_exceptions, false); + if (EHa) { + CmdArgs.push_back("-fasync-exceptions"); + 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("-fasync-exceptions"); } + if (types::isCXX(InputType) && EH.Synch && EH.NoUnwindC) CmdArgs.push_back("-fexternc-nounwind"); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/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_fasync_exceptions); // -ffixed-point Opts.FixedPoint = diff --git a/clang/lib/Sema/JumpDiagnostics.cpp b/clang/lib/Sema/JumpDiagnostics.cpp --- a/clang/lib/Sema/JumpDiagnostics.cpp +++ b/clang/lib/Sema/JumpDiagnostics.cpp @@ -930,6 +930,9 @@ if (!ToScopesWarning.empty()) { S.Diag(DiagLoc, JumpDiagWarning); NoteJumpIntoScopes(ToScopesWarning); + assert(isa(To)); + LabelStmt *Label = cast(To); + Label->setSideEntry(true); } // Handle errors. diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -185,11 +185,13 @@ 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 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -115,6 +115,7 @@ 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 --- /dev/null +++ b/clang/test/CodeGen/windows-seh-EHa-CppCatchDotDotDot.cpp @@ -0,0 +1,58 @@ +// RUN: %clang_cc1 -triple x86_64-windows -fasync-exceptions -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.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] +// 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; +} diff --git a/clang/test/CodeGen/windows-seh-EHa-CppCatchDotDotDot.ll b/clang/test/CodeGen/windows-seh-EHa-CppCatchDotDotDot.ll new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/windows-seh-EHa-CppCatchDotDotDot.ll @@ -0,0 +1,251 @@ +; ModuleID = 'windows-seh-EHa-CppCatchDotDotDot.cpp' +source_filename = "windows-seh-EHa-CppCatchDotDotDot.cpp" +target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-windows-msvc" + +%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] } +%eh.CatchableType = type { i32, i32, i32, i32, i32, i32, i32 } +%eh.CatchableTypeArray.1 = type { i32, [1 x i32] } +%eh.ThrowInfo = type { i32, i32, i32, i32 } +%struct.A = type { i8 } + +$"??_C@_0BJ@EIKFKKLB@?5in?5catch?$CI?4?4?4?$CJ?5funclet?5?6?$AA@" = comdat any + +$"??_R0H@8" = comdat any + +$"_CT??_R0H@84" = comdat any + +$_CTA1H = comdat any + +$_TI1H = comdat any + +$"??_C@_0CN@MKCAOFNA@?5Test?5CPP?5unwind?3?5in?5except?5hand@" = comdat any + +$"??_C@_0N@LJHFFAKD@?5in?5A?5ctor?5?6?$AA@" = comdat any + +$"??_C@_0N@HMNCGOCN@?5in?5A?5dtor?5?6?$AA@" = comdat any + +@"?NullPtr@@3PECHEC" = dso_local global i32* null, align 8 +@"?pt1@@3PEAHEA" = dso_local global i32* null, align 8 +@"?pt2@@3PEAHEA" = dso_local global i32* null, align 8 +@"?pt3@@3PEAHEA" = dso_local global i32* null, align 8 +@"?g@@3HA" = dso_local global i32 0, align 4 +@"??_C@_0BJ@EIKFKKLB@?5in?5catch?$CI?4?4?4?$CJ?5funclet?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [25 x i8] c" in catch(...) funclet \0A\00", comdat, align 1 +@"??_7type_info@@6B@" = external constant i8* +@"??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat +@__ImageBase = external dso_local constant i8 +@"_CT??_R0H@84" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 1, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor2* @"??_R0H@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 -1, i32 0, i32 4, i32 0 }, section ".xdata", comdat +@_CTA1H = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.1 { i32 1, [1 x i32] [i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableType* @"_CT??_R0H@84" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32)] }, section ".xdata", comdat +@_TI1H = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i32 0, i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableTypeArray.1* @_CTA1H to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, section ".xdata", comdat +@"??_C@_0CN@MKCAOFNA@?5Test?5CPP?5unwind?3?5in?5except?5hand@" = linkonce_odr dso_local unnamed_addr constant [45 x i8] c" Test CPP unwind: in except handler i = %d \0A\00", comdat, align 1 +@"??_C@_0N@LJHFFAKD@?5in?5A?5ctor?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [13 x i8] c" in A ctor \0A\00", comdat, align 1 +@"??_C@_0N@HMNCGOCN@?5in?5A?5dtor?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [13 x i8] c" in A dtor \0A\00", comdat, align 1 + +; Function Attrs: noinline nounwind optnone +define dso_local void @"?foo@@YAXXZ"() #0 { +entry: + %0 = load i32*, i32** @"?NullPtr@@3PECHEC", align 8 + store volatile i32 0, i32* %0, align 4 + ret void +} + +; Function Attrs: noinline optnone +define dso_local void @"?crash@@YAXH@Z"(i32 %i) #1 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { +entry: + %i.addr = alloca i32, align 4 + %ObjA = alloca %struct.A, align 1 + %tmp = alloca i32, align 4 + store i32 %i, i32* %i.addr, align 4 + %0 = load i32, i32* %i.addr, align 4 + store i32 %0, i32* @"?g@@3HA", align 4 + invoke void @llvm.seh.try.begin() + to label %invoke.cont unwind label %catch.dispatch + +invoke.cont: ; preds = %entry + %call = invoke %struct.A* @"??0A@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.A* %ObjA) + to label %invoke.cont1 unwind label %catch.dispatch + +invoke.cont1: ; preds = %invoke.cont + invoke void @llvm.seh.scope.begin() + to label %invoke.cont2 unwind label %ehcleanup + +invoke.cont2: ; preds = %invoke.cont1 + %1 = load i32, i32* %i.addr, align 4 + %cmp = icmp eq i32 %1, 1 + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %invoke.cont2 + %2 = load i32*, i32** @"?NullPtr@@3PECHEC", align 8 + store volatile i32 0, i32* %2, align 4 + br label %if.end + +if.end: ; preds = %if.then, %invoke.cont2 + invoke void @llvm.seh.scope.end() + to label %invoke.cont3 unwind label %ehcleanup + +invoke.cont3: ; preds = %if.end + call void @"??1A@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.A* %ObjA) #6 + br label %try.cont + +ehcleanup: ; preds = %if.end, %invoke.cont1 + %3 = cleanuppad within none [] + call void @"??1A@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.A* %ObjA) #6 [ "funclet"(token %3) ] + cleanupret from %3 unwind label %catch.dispatch + +catch.dispatch: ; preds = %ehcleanup, %invoke.cont, %entry + %4 = catchswitch within none [label %catch] unwind to caller + +catch: ; preds = %catch.dispatch + %5 = catchpad within %4 [i8* null, i32 0, i8* null] + call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([25 x i8], [25 x i8]* @"??_C@_0BJ@EIKFKKLB@?5in?5catch?$CI?4?4?4?$CJ?5funclet?5?6?$AA@", i64 0, i64 0)) [ "funclet"(token %5) ] + %6 = load i32, i32* %i.addr, align 4 + %cmp4 = icmp eq i32 %6, 1 + br i1 %cmp4, label %if.then5, label %if.end6 + +if.then5: ; preds = %catch + %7 = load i32, i32* %i.addr, align 4 + store i32 %7, i32* %tmp, align 4 + %8 = bitcast i32* %tmp to i8* + call void @_CxxThrowException(i8* %8, %eh.ThrowInfo* @_TI1H) #7 [ "funclet"(token %5) ] + unreachable + +if.end6: ; preds = %catch + catchret from %5 to label %catchret.dest + +catchret.dest: ; preds = %if.end6 + br label %try.cont + +try.cont: ; preds = %catchret.dest, %invoke.cont3 + ret void +} + +; Function Attrs: nounwind willreturn +declare dso_local void @llvm.seh.try.begin() #2 + +declare dso_local i32 @__CxxFrameHandler3(...) + +; Function Attrs: noinline optnone +define internal %struct.A* @"??0A@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.A* returned %this) unnamed_addr #1 align 2 { +entry: + %retval = alloca %struct.A*, align 8 + %this.addr = alloca %struct.A*, align 8 + store %struct.A* %this, %struct.A** %this.addr, align 8 + %this1 = load %struct.A*, %struct.A** %this.addr, align 8 + store %struct.A* %this1, %struct.A** %retval, align 8 + call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @"??_C@_0N@LJHFFAKD@?5in?5A?5ctor?5?6?$AA@", i64 0, i64 0)) + %0 = load i32, i32* @"?g@@3HA", align 4 + %cmp = icmp eq i32 %0, 0 + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %entry + %1 = load i32*, i32** @"?NullPtr@@3PECHEC", align 8 + store volatile i32 0, i32* %1, align 4 + br label %if.end + +if.end: ; preds = %if.then, %entry + %2 = load %struct.A*, %struct.A** %retval, align 8 + ret %struct.A* %2 +} + +; Function Attrs: nounwind readnone +declare dso_local void @llvm.seh.scope.begin() #3 + +; Function Attrs: nounwind readnone +declare dso_local void @llvm.seh.scope.end() #3 + +; Function Attrs: noinline nounwind optnone +define internal void @"??1A@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.A* %this) unnamed_addr #0 align 2 { +entry: + %this.addr = alloca %struct.A*, align 8 + store %struct.A* %this, %struct.A** %this.addr, align 8 + %this1 = load %struct.A*, %struct.A** %this.addr, align 8 + call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @"??_C@_0N@HMNCGOCN@?5in?5A?5dtor?5?6?$AA@", i64 0, i64 0)) + ret void +} + +declare dso_local void @"?printf@@YAXZZ"(...) #4 + +declare dso_local void @_CxxThrowException(i8*, %eh.ThrowInfo*) + +; Function Attrs: noinline norecurse optnone +define dso_local i32 @main() #5 personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) { +entry: + %retval = alloca i32, align 4 + %i = alloca i32, align 4 + %__exception_code = alloca i32, align 4 + store i32 0, i32* %retval, align 4 + store i32 0, i32* %i, align 4 + br label %for.cond + +for.cond: ; preds = %for.inc, %entry + %0 = load i32, i32* %i, align 4 + %cmp = icmp slt i32 %0, 2 + br i1 %cmp, label %for.body, label %for.end + +for.body: ; preds = %for.cond + invoke void @llvm.seh.try.begin() + to label %invoke.cont unwind label %catch.dispatch + +invoke.cont: ; preds = %for.body + %1 = load volatile i32, i32* %i, align 4 + invoke void @"?crash@@YAXH@Z"(i32 %1) #8 + to label %invoke.cont1 unwind label %catch.dispatch + +invoke.cont1: ; preds = %invoke.cont + invoke void @llvm.seh.try.end() + to label %invoke.cont2 unwind label %catch.dispatch + +catch.dispatch: ; preds = %invoke.cont1, %invoke.cont, %for.body + %2 = catchswitch within none [label %__except] unwind to caller + +__except: ; preds = %catch.dispatch + %3 = catchpad within %2 [i8* null] + catchret from %3 to label %__except3 + +__except3: ; preds = %__except + %4 = call i32 @llvm.eh.exceptioncode(token %3) + store i32 %4, i32* %__exception_code, align 4 + %5 = load i32, i32* %i, align 4 + call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([45 x i8], [45 x i8]* @"??_C@_0CN@MKCAOFNA@?5Test?5CPP?5unwind?3?5in?5except?5hand@", i64 0, i64 0), i32 %5) + br label %__try.cont + +__try.cont: ; preds = %__except3, %invoke.cont2 + br label %for.inc + +for.inc: ; preds = %__try.cont + %6 = load i32, i32* %i, align 4 + %inc = add nsw i32 %6, 1 + store i32 %inc, i32* %i, align 4 + br label %for.cond + +invoke.cont2: ; preds = %invoke.cont1 + br label %__try.cont + +for.end: ; preds = %for.cond + ret i32 0 +} + +declare dso_local i32 @__C_specific_handler(...) + +; Function Attrs: nounwind willreturn +declare dso_local void @llvm.seh.try.end() #2 + +; Function Attrs: nounwind readnone +declare i32 @llvm.eh.exceptioncode(token) #3 + +attributes #0 = { noinline nounwind optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { noinline optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind willreturn } +attributes #3 = { nounwind readnone } +attributes #4 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #5 = { noinline norecurse optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #6 = { nounwind } +attributes #7 = { noreturn } +attributes #8 = { noinline } + +!llvm.module.flags = !{!0, !1} +!llvm.ident = !{!2} + +!0 = !{i32 1, !"wchar_size", i32 2} +!1 = !{i32 2, !"eh-asynch", i32 1} +!2 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project 7ee479a760e0a4402b4eb7fb6168768a44f66945)"} diff --git a/clang/test/CodeGen/windows-seh-EHa-CppCondiTemps.cpp b/clang/test/CodeGen/windows-seh-EHa-CppCondiTemps.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/windows-seh-EHa-CppCondiTemps.cpp @@ -0,0 +1,129 @@ +// RUN: %clang_cc1 -triple x86_64-windows -fasync-exceptions -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-CppCondiTemps.ll b/clang/test/CodeGen/windows-seh-EHa-CppCondiTemps.ll new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/windows-seh-EHa-CppCondiTemps.ll @@ -0,0 +1,531 @@ +; ModuleID = 'windows-seh-EHa-CppCondiTemps.cpp' +source_filename = "windows-seh-EHa-CppCondiTemps.cpp" +target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-windows-msvc" + +%class.B1 = type { i32 } +%class.B2 = type { %class.B1 } +%class.B3 = type { %class.B2 } + +$"??1B1@@QEAA@XZ" = comdat any + +$"??1B2@@QEAA@XZ" = comdat any + +$"??0B2@@QEAA@XZ" = comdat any + +$"??0B3@@QEAA@XZ" = comdat any + +$"??1B3@@QEAA@XZ" = comdat any + +$"??0B1@@QEAA@XZ" = comdat any + +$"??_C@_0N@FMGAAAAM@in?5B1?5Dtor?5?6?$AA@" = comdat any + +$"??_C@_0N@GFONDMMJ@in?5B2?5Dtor?5?6?$AA@" = comdat any + +$"??_C@_0N@HCJGCIIK@in?5B3?5Dtor?5?6?$AA@" = comdat any + +@"?xxxx@@3HA" = dso_local global i32 0, align 4 +@"?ptr@@3PEAHEA" = dso_local global i32* null, align 8 +@"??_C@_0N@FMGAAAAM@in?5B1?5Dtor?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [13 x i8] c"in B1 Dtor \0A\00", comdat, align 1 +@"??_C@_0N@GFONDMMJ@in?5B2?5Dtor?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [13 x i8] c"in B2 Dtor \0A\00", comdat, align 1 +@"??_C@_0N@HCJGCIIK@in?5B3?5Dtor?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [13 x i8] c"in B3 Dtor \0A\00", comdat, align 1 + +; Function Attrs: noinline nounwind optnone +define dso_local i32 @"?foo@@YAHH@Z"(i32 %a) #0 { +entry: + %a.addr = alloca i32, align 4 + store i32 %a, i32* %a.addr, align 4 + %0 = load i32, i32* @"?xxxx@@3HA", align 4 + %1 = load i32, i32* %a.addr, align 4 + %add = add nsw i32 %0, %1 + ret i32 %add +} + +; Function Attrs: noinline optnone +define dso_local i32 @"?bar@@YAHHVB1@@VB2@@@Z"(i32 %j, i32 %b1Bar.coerce, i32 %b2Bar.coerce) #1 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { +entry: + %b1Bar = alloca %class.B1, align 4 + %b2Bar = alloca %class.B2, align 4 + %j.addr = alloca i32, align 4 + %ww = alloca i32, align 4 + %coerce.dive = getelementptr inbounds %class.B1, %class.B1* %b1Bar, i32 0, i32 0 + store i32 %b1Bar.coerce, i32* %coerce.dive, align 4 + %coerce.dive1 = getelementptr inbounds %class.B2, %class.B2* %b2Bar, i32 0, i32 0 + %coerce.dive2 = getelementptr inbounds %class.B1, %class.B1* %coerce.dive1, i32 0, i32 0 + store i32 %b2Bar.coerce, i32* %coerce.dive2, align 4 + invoke void @llvm.seh.scope.begin() + to label %invoke.cont unwind label %ehcleanup7 + +invoke.cont: ; preds = %entry + invoke void @llvm.seh.scope.begin() + to label %invoke.cont3 unwind label %ehcleanup + +invoke.cont3: ; preds = %invoke.cont + store i32 %j, i32* %j.addr, align 4 + %0 = load i32, i32* %j.addr, align 4 + %cmp = icmp sgt i32 %0, 0 + br i1 %cmp, label %if.then, label %if.else + +if.then: ; preds = %invoke.cont3 + %data = getelementptr inbounds %class.B1, %class.B1* %b1Bar, i32 0, i32 0 + %1 = load i32, i32* %data, align 4 + store i32 %1, i32* %ww, align 4 + br label %if.end + +if.else: ; preds = %invoke.cont3 + %2 = bitcast %class.B2* %b2Bar to %class.B1* + %data4 = getelementptr inbounds %class.B1, %class.B1* %2, i32 0, i32 0 + %3 = load i32, i32* %data4, align 4 + store i32 %3, i32* %ww, align 4 + br label %if.end + +if.end: ; preds = %if.else, %if.then + %4 = load i32, i32* %ww, align 4 + %5 = load i32*, i32** @"?ptr@@3PEAHEA", align 8 + %6 = load i32, i32* %5, align 4 + %add = add nsw i32 %4, %6 + invoke void @llvm.seh.scope.end() + to label %invoke.cont5 unwind label %ehcleanup + +invoke.cont5: ; preds = %if.end + call void @"??1B1@@QEAA@XZ"(%class.B1* %b1Bar) #6 + invoke void @llvm.seh.scope.end() + to label %invoke.cont6 unwind label %ehcleanup7 + +ehcleanup: ; preds = %if.end, %invoke.cont + %7 = cleanuppad within none [] + call void @"??1B1@@QEAA@XZ"(%class.B1* %b1Bar) #6 [ "funclet"(token %7) ] + cleanupret from %7 unwind label %ehcleanup7 + +invoke.cont6: ; preds = %invoke.cont5 + call void @"??1B2@@QEAA@XZ"(%class.B2* %b2Bar) #6 + ret i32 %add + +ehcleanup7: ; preds = %invoke.cont5, %ehcleanup, %entry + %8 = cleanuppad within none [] + call void @"??1B2@@QEAA@XZ"(%class.B2* %b2Bar) #6 [ "funclet"(token %8) ] + cleanupret from %8 unwind to caller +} + +; Function Attrs: nounwind readnone +declare dso_local void @llvm.seh.scope.begin() #2 + +declare dso_local i32 @__CxxFrameHandler3(...) + +; Function Attrs: nounwind readnone +declare dso_local void @llvm.seh.scope.end() #2 + +; Function Attrs: noinline nounwind optnone +define linkonce_odr dso_local void @"??1B1@@QEAA@XZ"(%class.B1* %this) unnamed_addr #0 comdat align 2 { +entry: + %this.addr = alloca %class.B1*, align 8 + store %class.B1* %this, %class.B1** %this.addr, align 8 + %this1 = load %class.B1*, %class.B1** %this.addr, align 8 + call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @"??_C@_0N@FMGAAAAM@in?5B1?5Dtor?5?6?$AA@", i64 0, i64 0)) + ret void +} + +; Function Attrs: noinline nounwind optnone +define linkonce_odr dso_local void @"??1B2@@QEAA@XZ"(%class.B2* %this) unnamed_addr #0 comdat align 2 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { +entry: + %this.addr = alloca %class.B2*, align 8 + store %class.B2* %this, %class.B2** %this.addr, align 8 + %this1 = load %class.B2*, %class.B2** %this.addr, align 8 + invoke void @llvm.seh.scope.begin() + to label %invoke.cont unwind label %ehcleanup + +invoke.cont: ; preds = %entry + invoke void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @"??_C@_0N@GFONDMMJ@in?5B2?5Dtor?5?6?$AA@", i64 0, i64 0)) + to label %invoke.cont2 unwind label %ehcleanup + +invoke.cont2: ; preds = %invoke.cont + invoke void @llvm.seh.scope.end() + to label %invoke.cont3 unwind label %ehcleanup + +invoke.cont3: ; preds = %invoke.cont2 + %0 = bitcast %class.B2* %this1 to %class.B1* + call void @"??1B1@@QEAA@XZ"(%class.B1* %0) #6 + ret void + +ehcleanup: ; preds = %invoke.cont2, %invoke.cont, %entry + %1 = cleanuppad within none [] + %2 = bitcast %class.B2* %this1 to %class.B1* + call void @"??1B1@@QEAA@XZ"(%class.B1* %2) #6 [ "funclet"(token %1) ] + cleanupret from %1 unwind to caller +} + +; Function Attrs: noinline optnone +define dso_local void @"?goo@@YA?AVB1@@H@Z"(%class.B1* noalias sret align 4 %agg.result, i32 %w) #1 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { +entry: + %result.ptr = alloca i8*, align 8 + %w.addr = alloca i32, align 4 + %b2ingoo = alloca %class.B2, align 4 + %0 = bitcast %class.B1* %agg.result to i8* + store i8* %0, i8** %result.ptr, align 8 + store i32 %w, i32* %w.addr, align 4 + %call = call %class.B2* @"??0B2@@QEAA@XZ"(%class.B2* %b2ingoo) + invoke void @llvm.seh.scope.begin() + to label %invoke.cont unwind label %ehcleanup + +invoke.cont: ; preds = %entry + %1 = load i32, i32* %w.addr, align 4 + %2 = bitcast %class.B2* %b2ingoo to %class.B1* + %data = getelementptr inbounds %class.B1, %class.B1* %2, i32 0, i32 0 + %3 = load i32, i32* %data, align 4 + %add = add nsw i32 %3, %1 + store i32 %add, i32* %data, align 4 + %4 = bitcast %class.B2* %b2ingoo to %class.B1* + %5 = bitcast %class.B1* %agg.result to i8* + %6 = bitcast %class.B1* %4 to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %5, i8* align 4 %6, i64 4, i1 false) + invoke void @llvm.seh.scope.end() + to label %invoke.cont1 unwind label %ehcleanup + +invoke.cont1: ; preds = %invoke.cont + call void @"??1B2@@QEAA@XZ"(%class.B2* %b2ingoo) #6 + ret void + +ehcleanup: ; preds = %invoke.cont, %entry + %7 = cleanuppad within none [] + call void @"??1B2@@QEAA@XZ"(%class.B2* %b2ingoo) #6 [ "funclet"(token %7) ] + cleanupret from %7 unwind to caller +} + +; Function Attrs: noinline optnone +define linkonce_odr dso_local %class.B2* @"??0B2@@QEAA@XZ"(%class.B2* returned %this) unnamed_addr #1 comdat align 2 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { +entry: + %this.addr = alloca %class.B2*, align 8 + store %class.B2* %this, %class.B2** %this.addr, align 8 + %this1 = load %class.B2*, %class.B2** %this.addr, align 8 + %0 = bitcast %class.B2* %this1 to %class.B1* + %call = call %class.B1* @"??0B1@@QEAA@XZ"(%class.B1* %0) + invoke void @llvm.seh.scope.begin() + to label %invoke.cont unwind label %ehcleanup + +invoke.cont: ; preds = %entry + %1 = bitcast %class.B2* %this1 to %class.B1* + %data = getelementptr inbounds %class.B1, %class.B1* %1, i32 0, i32 0 + %2 = load i32, i32* %data, align 4 + %add = add nsw i32 %2, 222 + %call3 = invoke i32 @"?foo@@YAHH@Z"(i32 %add) + to label %invoke.cont2 unwind label %ehcleanup + +invoke.cont2: ; preds = %invoke.cont + invoke void @llvm.seh.scope.end() + to label %invoke.cont4 unwind label %ehcleanup + +invoke.cont4: ; preds = %invoke.cont2 + ret %class.B2* %this1 + +ehcleanup: ; preds = %invoke.cont2, %invoke.cont, %entry + %3 = cleanuppad within none [] + %4 = bitcast %class.B2* %this1 to %class.B1* + call void @"??1B1@@QEAA@XZ"(%class.B1* %4) #6 [ "funclet"(token %3) ] + cleanupret from %3 unwind to caller +} + +; Function Attrs: argmemonly nounwind willreturn +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #3 + +; Function Attrs: noinline norecurse optnone +define dso_local i32 @main() #4 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { +entry: + %retval = alloca i32, align 4 + %b3inmain = alloca %class.B3, align 4 + %m = alloca i32, align 4 + %ref.tmp = alloca %class.B2, align 4 + %cleanup.cond = alloca i1, align 1 + %ref.tmp6 = alloca %class.B3, align 4 + %cleanup.cond10 = alloca i1, align 1 + %i = alloca i32, align 4 + %agg.tmp = alloca %class.B2, align 4 + %agg.tmp30 = alloca %class.B1, align 4 + %b1fromgoo = alloca %class.B1, align 4 + store i32 0, i32* %retval, align 4 + %call = call %class.B3* @"??0B3@@QEAA@XZ"(%class.B3* %b3inmain) + invoke void @llvm.seh.scope.begin() + to label %invoke.cont unwind label %ehcleanup53 + +invoke.cont: ; preds = %entry + %0 = load i32, i32* @"?xxxx@@3HA", align 4 + %cmp = icmp sgt i32 %0, 1 + store i1 false, i1* %cleanup.cond, align 1 + store i1 false, i1* %cleanup.cond10, align 1 + br i1 %cmp, label %cond.true, label %cond.false + +cond.true: ; preds = %invoke.cont + %call2 = invoke %class.B2* @"??0B2@@QEAA@XZ"(%class.B2* %ref.tmp) + to label %invoke.cont1 unwind label %ehcleanup53 + +invoke.cont1: ; preds = %cond.true + invoke void @llvm.seh.scope.begin() + to label %invoke.cont3 unwind label %ehcleanup23 + +invoke.cont3: ; preds = %invoke.cont1 + store i1 true, i1* %cleanup.cond, align 1 + %1 = bitcast %class.B2* %ref.tmp to %class.B1* + %data = getelementptr inbounds %class.B1, %class.B1* %1, i32 0, i32 0 + %2 = load i32, i32* %data, align 4 + %call5 = invoke i32 @"?foo@@YAHH@Z"(i32 99) + to label %invoke.cont4 unwind label %ehcleanup23 + +invoke.cont4: ; preds = %invoke.cont3 + %add = add nsw i32 %2, %call5 + br label %cond.end + +cond.false: ; preds = %invoke.cont + %call8 = invoke %class.B3* @"??0B3@@QEAA@XZ"(%class.B3* %ref.tmp6) + to label %invoke.cont7 unwind label %ehcleanup23 + +invoke.cont7: ; preds = %cond.false + invoke void @llvm.seh.scope.begin() + to label %invoke.cont9 unwind label %ehcleanup + +invoke.cont9: ; preds = %invoke.cont7 + store i1 true, i1* %cleanup.cond10, align 1 + %3 = bitcast %class.B3* %ref.tmp6 to %class.B1* + %data11 = getelementptr inbounds %class.B1, %class.B1* %3, i32 0, i32 0 + %4 = load i32, i32* %data11, align 4 + %call13 = invoke i32 @"?foo@@YAHH@Z"(i32 88) + to label %invoke.cont12 unwind label %ehcleanup + +invoke.cont12: ; preds = %invoke.cont9 + %add14 = add nsw i32 %4, %call13 + br label %cond.end + +cond.end: ; preds = %invoke.cont12, %invoke.cont4 + %cond = phi i32 [ %add, %invoke.cont4 ], [ %add14, %invoke.cont12 ] + invoke void @llvm.seh.scope.end() + to label %invoke.cont15 unwind label %ehcleanup + +invoke.cont15: ; preds = %cond.end + %cleanup.is_active = load i1, i1* %cleanup.cond10, align 1 + br i1 %cleanup.is_active, label %cleanup.action, label %cleanup.done + +cleanup.action: ; preds = %invoke.cont15 + call void @"??1B3@@QEAA@XZ"(%class.B3* %ref.tmp6) #6 + br label %cleanup.done + +cleanup.done: ; preds = %cleanup.action, %invoke.cont15 + invoke void @llvm.seh.scope.end() + to label %invoke.cont19 unwind label %ehcleanup23 + +invoke.cont19: ; preds = %cleanup.done + %cleanup.is_active20 = load i1, i1* %cleanup.cond, align 1 + br i1 %cleanup.is_active20, label %cleanup.action21, label %cleanup.done22 + +cleanup.action21: ; preds = %invoke.cont19 + call void @"??1B2@@QEAA@XZ"(%class.B2* %ref.tmp) #6 + br label %cleanup.done22 + +cleanup.done22: ; preds = %cleanup.action21, %invoke.cont19 + store i32 %cond, i32* %m, align 4 + %call28 = invoke %class.B2* @"??0B2@@QEAA@XZ"(%class.B2* %agg.tmp) + to label %invoke.cont27 unwind label %ehcleanup53 + +invoke.cont27: ; preds = %cleanup.done22 + invoke void @llvm.seh.scope.begin() + to label %invoke.cont29 unwind label %ehcleanup41 + +invoke.cont29: ; preds = %invoke.cont27 + %call32 = invoke %class.B1* @"??0B1@@QEAA@XZ"(%class.B1* %agg.tmp30) + to label %invoke.cont31 unwind label %ehcleanup41 + +invoke.cont31: ; preds = %invoke.cont29 + invoke void @llvm.seh.scope.begin() + to label %invoke.cont33 unwind label %ehcleanup39 + +invoke.cont33: ; preds = %invoke.cont31 + %call35 = invoke i32 @"?foo@@YAHH@Z"(i32 0) + to label %invoke.cont34 unwind label %ehcleanup39 + +invoke.cont34: ; preds = %invoke.cont33 + %coerce.dive = getelementptr inbounds %class.B1, %class.B1* %agg.tmp30, i32 0, i32 0 + %5 = load i32, i32* %coerce.dive, align 4 + %coerce.dive36 = getelementptr inbounds %class.B2, %class.B2* %agg.tmp, i32 0, i32 0 + %coerce.dive37 = getelementptr inbounds %class.B1, %class.B1* %coerce.dive36, i32 0, i32 0 + %6 = load i32, i32* %coerce.dive37, align 4 + invoke void @llvm.seh.scope.end() + to label %invoke.cont38 unwind label %ehcleanup39 + +invoke.cont38: ; preds = %invoke.cont34 + invoke void @llvm.seh.scope.end() + to label %invoke.cont40 unwind label %ehcleanup41 + +invoke.cont40: ; preds = %invoke.cont38 + %call43 = invoke i32 @"?bar@@YAHHVB1@@VB2@@@Z"(i32 %call35, i32 %5, i32 %6) + to label %invoke.cont42 unwind label %ehcleanup53 + +invoke.cont42: ; preds = %invoke.cont40 + store i32 %call43, i32* %i, align 4 + %7 = load i32, i32* %i, align 4 + invoke void @"?goo@@YA?AVB1@@H@Z"(%class.B1* sret align 4 %b1fromgoo, i32 %7) + to label %invoke.cont44 unwind label %ehcleanup53 + +invoke.cont44: ; preds = %invoke.cont42 + invoke void @llvm.seh.scope.begin() + to label %invoke.cont45 unwind label %ehcleanup51 + +invoke.cont45: ; preds = %invoke.cont44 + %8 = load i32, i32* %m, align 4 + %data46 = getelementptr inbounds %class.B1, %class.B1* %b1fromgoo, i32 0, i32 0 + %9 = load i32, i32* %data46, align 4 + %add47 = add nsw i32 %8, %9 + %10 = bitcast %class.B3* %b3inmain to %class.B1* + %data48 = getelementptr inbounds %class.B1, %class.B1* %10, i32 0, i32 0 + %11 = load i32, i32* %data48, align 4 + %add49 = add nsw i32 %add47, %11 + store i32 %add49, i32* %retval, align 4 + invoke void @llvm.seh.scope.end() + to label %invoke.cont50 unwind label %ehcleanup51 + +ehcleanup: ; preds = %cond.end, %invoke.cont9, %invoke.cont7 + %12 = cleanuppad within none [] + %cleanup.is_active16 = load i1, i1* %cleanup.cond10, align 1 + br i1 %cleanup.is_active16, label %cleanup.action17, label %cleanup.done18 + +cleanup.action17: ; preds = %ehcleanup + call void @"??1B3@@QEAA@XZ"(%class.B3* %ref.tmp6) #6 [ "funclet"(token %12) ] + br label %cleanup.done18 + +cleanup.done18: ; preds = %cleanup.action17, %ehcleanup + cleanupret from %12 unwind label %ehcleanup23 + +ehcleanup23: ; preds = %cleanup.done, %cleanup.done18, %cond.false, %invoke.cont3, %invoke.cont1 + %13 = cleanuppad within none [] + %cleanup.is_active24 = load i1, i1* %cleanup.cond, align 1 + br i1 %cleanup.is_active24, label %cleanup.action25, label %cleanup.done26 + +cleanup.action25: ; preds = %ehcleanup23 + call void @"??1B2@@QEAA@XZ"(%class.B2* %ref.tmp) #6 [ "funclet"(token %13) ] + br label %cleanup.done26 + +cleanup.done26: ; preds = %cleanup.action25, %ehcleanup23 + cleanupret from %13 unwind label %ehcleanup53 + +ehcleanup39: ; preds = %invoke.cont34, %invoke.cont33, %invoke.cont31 + %14 = cleanuppad within none [] + call void @"??1B1@@QEAA@XZ"(%class.B1* %agg.tmp30) #6 [ "funclet"(token %14) ] + cleanupret from %14 unwind label %ehcleanup41 + +ehcleanup41: ; preds = %invoke.cont38, %ehcleanup39, %invoke.cont29, %invoke.cont27 + %15 = cleanuppad within none [] + call void @"??1B2@@QEAA@XZ"(%class.B2* %agg.tmp) #6 [ "funclet"(token %15) ] + cleanupret from %15 unwind label %ehcleanup53 + +invoke.cont50: ; preds = %invoke.cont45 + call void @"??1B1@@QEAA@XZ"(%class.B1* %b1fromgoo) #6 + invoke void @llvm.seh.scope.end() + to label %invoke.cont52 unwind label %ehcleanup53 + +ehcleanup51: ; preds = %invoke.cont45, %invoke.cont44 + %16 = cleanuppad within none [] + call void @"??1B1@@QEAA@XZ"(%class.B1* %b1fromgoo) #6 [ "funclet"(token %16) ] + cleanupret from %16 unwind label %ehcleanup53 + +invoke.cont52: ; preds = %invoke.cont50 + call void @"??1B3@@QEAA@XZ"(%class.B3* %b3inmain) #6 + %17 = load i32, i32* %retval, align 4 + ret i32 %17 + +ehcleanup53: ; preds = %invoke.cont50, %ehcleanup51, %invoke.cont42, %invoke.cont40, %ehcleanup41, %cleanup.done22, %cleanup.done26, %cond.true, %entry + %18 = cleanuppad within none [] + call void @"??1B3@@QEAA@XZ"(%class.B3* %b3inmain) #6 [ "funclet"(token %18) ] + cleanupret from %18 unwind to caller +} + +; Function Attrs: noinline optnone +define linkonce_odr dso_local %class.B3* @"??0B3@@QEAA@XZ"(%class.B3* returned %this) unnamed_addr #1 comdat align 2 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { +entry: + %this.addr = alloca %class.B3*, align 8 + store %class.B3* %this, %class.B3** %this.addr, align 8 + %this1 = load %class.B3*, %class.B3** %this.addr, align 8 + %0 = bitcast %class.B3* %this1 to %class.B2* + %call = call %class.B2* @"??0B2@@QEAA@XZ"(%class.B2* %0) + invoke void @llvm.seh.scope.begin() + to label %invoke.cont unwind label %ehcleanup + +invoke.cont: ; preds = %entry + %1 = bitcast %class.B3* %this1 to %class.B1* + %data = getelementptr inbounds %class.B1, %class.B1* %1, i32 0, i32 0 + %2 = load i32, i32* %data, align 4 + %add = add nsw i32 %2, 333 + %call3 = invoke i32 @"?foo@@YAHH@Z"(i32 %add) + to label %invoke.cont2 unwind label %ehcleanup + +invoke.cont2: ; preds = %invoke.cont + invoke void @llvm.seh.scope.end() + to label %invoke.cont4 unwind label %ehcleanup + +invoke.cont4: ; preds = %invoke.cont2 + ret %class.B3* %this1 + +ehcleanup: ; preds = %invoke.cont2, %invoke.cont, %entry + %3 = cleanuppad within none [] + %4 = bitcast %class.B3* %this1 to %class.B2* + call void @"??1B2@@QEAA@XZ"(%class.B2* %4) #6 [ "funclet"(token %3) ] + cleanupret from %3 unwind to caller +} + +; Function Attrs: noinline nounwind optnone +define linkonce_odr dso_local void @"??1B3@@QEAA@XZ"(%class.B3* %this) unnamed_addr #0 comdat align 2 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { +entry: + %this.addr = alloca %class.B3*, align 8 + store %class.B3* %this, %class.B3** %this.addr, align 8 + %this1 = load %class.B3*, %class.B3** %this.addr, align 8 + invoke void @llvm.seh.scope.begin() + to label %invoke.cont unwind label %ehcleanup + +invoke.cont: ; preds = %entry + invoke void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @"??_C@_0N@HCJGCIIK@in?5B3?5Dtor?5?6?$AA@", i64 0, i64 0)) + to label %invoke.cont2 unwind label %ehcleanup + +invoke.cont2: ; preds = %invoke.cont + invoke void @llvm.seh.scope.end() + to label %invoke.cont3 unwind label %ehcleanup + +invoke.cont3: ; preds = %invoke.cont2 + %0 = bitcast %class.B3* %this1 to %class.B2* + call void @"??1B2@@QEAA@XZ"(%class.B2* %0) #6 + ret void + +ehcleanup: ; preds = %invoke.cont2, %invoke.cont, %entry + %1 = cleanuppad within none [] + %2 = bitcast %class.B3* %this1 to %class.B2* + call void @"??1B2@@QEAA@XZ"(%class.B2* %2) #6 [ "funclet"(token %1) ] + cleanupret from %1 unwind to caller +} + +; Function Attrs: noinline nounwind optnone +define linkonce_odr dso_local %class.B1* @"??0B1@@QEAA@XZ"(%class.B1* returned %this) unnamed_addr #0 comdat align 2 { +entry: + %this.addr = alloca %class.B1*, align 8 + store %class.B1* %this, %class.B1** %this.addr, align 8 + %this1 = load %class.B1*, %class.B1** %this.addr, align 8 + %data = getelementptr inbounds %class.B1, %class.B1* %this1, i32 0, i32 0 + store i32 90, i32* %data, align 4 + %data2 = getelementptr inbounds %class.B1, %class.B1* %this1, i32 0, i32 0 + %0 = load i32, i32* %data2, align 4 + %add = add nsw i32 %0, 111 + %call = call i32 @"?foo@@YAHH@Z"(i32 %add) + ret %class.B1* %this1 +} + +declare dso_local void @"?printf@@YAXZZ"(...) #5 + +attributes #0 = { noinline nounwind optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { noinline optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } +attributes #3 = { argmemonly nounwind willreturn } +attributes #4 = { noinline norecurse optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #5 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #6 = { nounwind } + +!llvm.module.flags = !{!0, !1} +!llvm.ident = !{!2} + +!0 = !{i32 1, !"wchar_size", i32 2} +!1 = !{i32 2, !"eh-asynch", i32 1} +!2 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project 7ee479a760e0a4402b4eb7fb6168768a44f66945)"} + diff --git a/clang/test/CodeGen/windows-seh-EHa-CppDtors01.asm b/clang/test/CodeGen/windows-seh-EHa-CppDtors01.asm new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/windows-seh-EHa-CppDtors01.asm @@ -0,0 +1,410 @@ + .text + .def @feat.00; + .scl 3; + .type 0; + .endef + .globl @feat.00 +.set @feat.00, 0 + .intel_syntax noprefix + .file "windows-seh-EHa-CppDtors01.cpp" + .def "?crash@@YAXH@Z"; + .scl 2; + .type 32; + .endef + .globl "?crash@@YAXH@Z" # -- Begin function ?crash@@YAXH@Z + .p2align 4, 0x90 +"?crash@@YAXH@Z": # @"?crash@@YAXH@Z" +.Lfunc_begin0: +.seh_proc "?crash@@YAXH@Z" + .seh_handler __CxxFrameHandler3, @unwind, @except +# %bb.0: # %entry + push rbp + .seh_pushreg rbp + sub rsp, 64 + .seh_stackalloc 64 + lea rbp, [rsp + 64] + .seh_setframe rbp, 64 + .seh_endprologue + mov qword ptr [rbp - 8], -2 +.Ltmp0: + nop + mov dword ptr [rbp - 12], ecx +.Ltmp1: + jmp .LBB0_1 +.LBB0_1: # %invoke.cont +.Ltmp2: + nop + cmp dword ptr [rbp - 12], 0 +.Ltmp3: + jne .LBB0_3 +# %bb.2: # %if.then +.Ltmp4: + nop + mov rax, qword ptr [rip + "?NullPtr@@3PECHEC"] + mov dword ptr [rax], 0 +.Ltmp5: +.LBB0_3: # %if.end + jmp .LBB0_4 +.LBB0_4: # %invoke.cont1 +.Ltmp6: + nop + cmp dword ptr [rbp - 12], 1 +.Ltmp7: + jne .LBB0_6 +# %bb.5: # %if.then3 +.Ltmp8: + nop + mov rax, qword ptr [rip + "?NullPtr@@3PECHEC"] + mov dword ptr [rax], 0 +.Ltmp9: +.LBB0_6: # %if.end4 + jmp .LBB0_7 +.LBB0_7: # %invoke.cont5 +.Ltmp10: + nop + cmp dword ptr [rbp - 12], 2 +.Ltmp11: + jne .LBB0_9 +# %bb.8: # %if.then7 +.Ltmp12: + nop + mov rax, qword ptr [rip + "?NullPtr@@3PECHEC"] + mov dword ptr [rax], 0 +.Ltmp13: +.LBB0_9: # %if.end8 + jmp .LBB0_10 +.LBB0_10: # %invoke.cont9 +.Ltmp14: + lea rcx, [rbp - 32] + call "??1C@?1??crash@@YAXH@Z@QEAA@XZ" +.Ltmp15: + jmp .LBB0_11 +.LBB0_11: # %invoke.cont10 +.Ltmp16: + lea rcx, [rbp - 24] + call "??1B@?1??crash@@YAXH@Z@QEAA@XZ" +.Ltmp17: + jmp .LBB0_12 +.LBB0_12: # %invoke.cont12 +.Ltmp18: + lea rcx, [rbp - 16] + call "??1A@?1??crash@@YAXH@Z@QEAA@XZ" +.Ltmp19: + nop + add rsp, 64 + pop rbp + ret + .seh_handlerdata + .long ("$cppxdata$?crash@@YAXH@Z")@IMGREL + .text + .seh_endproc + .def "?dtor$13@?0??crash@@YAXH@Z@4HA"; + .scl 3; + .type 32; + .endef + .p2align 4, 0x90 +"?dtor$13@?0??crash@@YAXH@Z@4HA": +.seh_proc "?dtor$13@?0??crash@@YAXH@Z@4HA" +.LBB0_13: # %ehcleanup + mov qword ptr [rsp + 16], rdx + push rbp + .seh_pushreg rbp + sub rsp, 32 + .seh_stackalloc 32 + lea rbp, [rdx + 64] + .seh_endprologue +.Ltmp20: + lea rcx, [rbp - 32] + call "??1C@?1??crash@@YAXH@Z@QEAA@XZ" +.Ltmp21: + nop + add rsp, 32 + pop rbp + ret # CLEANUPRET + .seh_handlerdata + .text + .seh_endproc + .def "?dtor$14@?0??crash@@YAXH@Z@4HA"; + .scl 3; + .type 32; + .endef + .p2align 4, 0x90 +"?dtor$14@?0??crash@@YAXH@Z@4HA": +.seh_proc "?dtor$14@?0??crash@@YAXH@Z@4HA" +.LBB0_14: # %ehcleanup11 + mov qword ptr [rsp + 16], rdx + push rbp + .seh_pushreg rbp + sub rsp, 32 + .seh_stackalloc 32 + lea rbp, [rdx + 64] + .seh_endprologue +.Ltmp22: + lea rcx, [rbp - 24] + call "??1B@?1??crash@@YAXH@Z@QEAA@XZ" +.Ltmp23: + nop + add rsp, 32 + pop rbp + ret # CLEANUPRET + .seh_handlerdata + .text + .seh_endproc + .def "?dtor$15@?0??crash@@YAXH@Z@4HA"; + .scl 3; + .type 32; + .endef + .p2align 4, 0x90 +"?dtor$15@?0??crash@@YAXH@Z@4HA": +.seh_proc "?dtor$15@?0??crash@@YAXH@Z@4HA" +.LBB0_15: # %ehcleanup13 + mov qword ptr [rsp + 16], rdx + push rbp + .seh_pushreg rbp + sub rsp, 32 + .seh_stackalloc 32 + lea rbp, [rdx + 64] + .seh_endprologue +.Ltmp24: + lea rcx, [rbp - 16] + call "??1A@?1??crash@@YAXH@Z@QEAA@XZ" +.Ltmp25: + nop + add rsp, 32 + pop rbp + ret # CLEANUPRET +.Lfunc_end0: + .seh_handlerdata + .text + .seh_endproc + .section .xdata,"dr" + .p2align 2 +"$cppxdata$?crash@@YAXH@Z": + .long 429065506 # MagicNumber + .long 3 # MaxState + .long ("$stateUnwindMap$?crash@@YAXH@Z")@IMGREL # UnwindMap + .long 0 # NumTryBlocks + .long 0 # TryBlockMap + .long 7 # IPMapEntries + .long ("$ip2state$?crash@@YAXH@Z")@IMGREL # IPToStateXData + .long 56 # UnwindHelp + .long 0 # ESTypeList + .long 0 # EHFlags +"$stateUnwindMap$?crash@@YAXH@Z": + .long -1 # ToState + .long "?dtor$15@?0??crash@@YAXH@Z@4HA"@IMGREL # Action + .long 0 # ToState + .long "?dtor$14@?0??crash@@YAXH@Z@4HA"@IMGREL # Action + .long 1 # ToState + .long "?dtor$13@?0??crash@@YAXH@Z@4HA"@IMGREL # Action +"$ip2state$?crash@@YAXH@Z": + .long .Lfunc_begin0@IMGREL # IP + .long -1 # ToState + .long .Ltmp2@IMGREL+1 # IP + .long 0 # ToState + .long .Ltmp6@IMGREL+1 # IP + .long 1 # ToState + .long .Ltmp10@IMGREL+1 # IP + .long 2 # ToState + .long .Ltmp14@IMGREL+1 # IP + .long 1 # ToState + .long .Ltmp16@IMGREL+1 # IP + .long 0 # ToState + .long .Ltmp18@IMGREL+1 # IP + .long -1 # ToState + .text + # -- End function + .def "??1C@?1??crash@@YAXH@Z@QEAA@XZ"; + .scl 3; + .type 32; + .endef + .p2align 4, 0x90 # -- Begin function ??1C@?1??crash@@YAXH@Z@QEAA@XZ +"??1C@?1??crash@@YAXH@Z@QEAA@XZ": # @"??1C@?1??crash@@YAXH@Z@QEAA@XZ" +.seh_proc "??1C@?1??crash@@YAXH@Z@QEAA@XZ" +# %bb.0: # %entry + sub rsp, 40 + .seh_stackalloc 40 + .seh_endprologue + mov qword ptr [rsp + 32], rcx + lea rcx, [rip + "??_C@_0N@FCCEEGKL@?5in?5C?5dtor?5?6?$AA@"] + call "?printf@@YAXZZ" + nop + add rsp, 40 + ret + .seh_handlerdata + .text + .seh_endproc + # -- End function + .def "??1B@?1??crash@@YAXH@Z@QEAA@XZ"; + .scl 3; + .type 32; + .endef + .p2align 4, 0x90 # -- Begin function ??1B@?1??crash@@YAXH@Z@QEAA@XZ +"??1B@?1??crash@@YAXH@Z@QEAA@XZ": # @"??1B@?1??crash@@YAXH@Z@QEAA@XZ" +.seh_proc "??1B@?1??crash@@YAXH@Z@QEAA@XZ" +# %bb.0: # %entry + sub rsp, 40 + .seh_stackalloc 40 + .seh_endprologue + mov qword ptr [rsp + 32], rcx + lea rcx, [rip + "??_C@_0N@EFFPFCOI@?5in?5B?5dtor?5?6?$AA@"] + call "?printf@@YAXZZ" + nop + add rsp, 40 + ret + .seh_handlerdata + .text + .seh_endproc + # -- End function + .def "??1A@?1??crash@@YAXH@Z@QEAA@XZ"; + .scl 3; + .type 32; + .endef + .p2align 4, 0x90 # -- Begin function ??1A@?1??crash@@YAXH@Z@QEAA@XZ +"??1A@?1??crash@@YAXH@Z@QEAA@XZ": # @"??1A@?1??crash@@YAXH@Z@QEAA@XZ" +.seh_proc "??1A@?1??crash@@YAXH@Z@QEAA@XZ" +# %bb.0: # %entry + sub rsp, 40 + .seh_stackalloc 40 + .seh_endprologue + mov qword ptr [rsp + 32], rcx + lea rcx, [rip + "??_C@_0N@HMNCGOCN@?5in?5A?5dtor?5?6?$AA@"] + call "?printf@@YAXZZ" + nop + add rsp, 40 + ret + .seh_handlerdata + .text + .seh_endproc + # -- End function + .def main; + .scl 2; + .type 32; + .endef + .globl main # -- Begin function main + .p2align 4, 0x90 +main: # @main +.Lfunc_begin1: +.seh_proc main + .seh_handler __C_specific_handler, @unwind, @except +# %bb.0: # %entry + push rbp + .seh_pushreg rbp + sub rsp, 64 + .seh_stackalloc 64 + lea rbp, [rsp + 64] + .seh_setframe rbp, 64 + .seh_endprologue +.Ltmp28: + nop + mov dword ptr [rbp - 4], 0 + mov dword ptr [rbp - 8], 0 +.Ltmp29: +.LBB4_1: # %for.cond + # =>This Inner Loop Header: Depth=1 +.Ltmp30: + nop + cmp dword ptr [rbp - 8], 3 +.Ltmp31: + jge .LBB4_9 +# %bb.2: # %for.body + # in Loop: Header=BB4_1 Depth=1 + jmp .LBB4_3 +.LBB4_3: # %invoke.cont + # in Loop: Header=BB4_1 Depth=1 +.Ltmp32: + nop + mov ecx, dword ptr [rbp - 8] +.Ltmp26: + call "?crash@@YAXH@Z" +.Ltmp27: +.Ltmp33: + jmp .LBB4_4 +.LBB4_4: # %invoke.cont1 + # in Loop: Header=BB4_1 Depth=1 + jmp .LBB4_8 +.LBB4_5: # %__except + # in Loop: Header=BB4_1 Depth=1 + mov qword ptr [rbp - 24], rax # 8-byte Spill + jmp .LBB4_6 +.LBB4_6: # %__except3 + # in Loop: Header=BB4_1 Depth=1 +.Ltmp34: + nop + mov rax, qword ptr [rbp - 24] # 8-byte Reload + mov ecx, eax + mov dword ptr [rbp - 12], ecx + mov edx, dword ptr [rbp - 8] + lea rcx, [rip + "??_C@_0CM@KAOHJHDK@?5Test?5CPP?5unwind?3?5in?5catch?5handl@"] + call "?printf@@YAXZZ" +.Ltmp35: +.LBB4_7: # %__try.cont + # in Loop: Header=BB4_1 Depth=1 +.Ltmp36: + nop + mov eax, dword ptr [rbp - 8] + add eax, 1 + mov dword ptr [rbp - 8], eax +.Ltmp37: + jmp .LBB4_1 +.LBB4_8: # %invoke.cont2 + # in Loop: Header=BB4_1 Depth=1 + jmp .LBB4_7 +.LBB4_9: # %for.end + xor eax, eax + add rsp, 64 + pop rbp + ret +.Lfunc_end1: + .seh_handlerdata +.set .Lmain$parent_frame_offset, 64 + .long (.Llsda_end0-.Llsda_begin0)/16 # Number of call sites +.Llsda_begin0: + .long .Ltmp32@IMGREL+1 # LabelStart + .long .Ltmp27@IMGREL+1 # LabelEnd + .long 1 # CatchAll + .long .LBB4_5@IMGREL # ExceptionHandler +.Llsda_end0: + .text + .seh_endproc + # -- End function + .bss + .globl "?NullPtr@@3PECHEC" # @"?NullPtr@@3PECHEC" + .p2align 3 +"?NullPtr@@3PECHEC": + .quad 0 + + .globl "?g@@3HA" # @"?g@@3HA" + .p2align 2 +"?g@@3HA": + .long 0 # 0x0 + + .section .rdata,"dr",discard,"??_C@_0CM@KAOHJHDK@?5Test?5CPP?5unwind?3?5in?5catch?5handl@" + .globl "??_C@_0CM@KAOHJHDK@?5Test?5CPP?5unwind?3?5in?5catch?5handl@" # @"??_C@_0CM@KAOHJHDK@?5Test?5CPP?5unwind?3?5in?5catch?5handl@" +"??_C@_0CM@KAOHJHDK@?5Test?5CPP?5unwind?3?5in?5catch?5handl@": + .asciz " Test CPP unwind: in catch handler i = %d \n" + + .section .rdata,"dr",discard,"??_C@_0N@FCCEEGKL@?5in?5C?5dtor?5?6?$AA@" + .globl "??_C@_0N@FCCEEGKL@?5in?5C?5dtor?5?6?$AA@" # @"??_C@_0N@FCCEEGKL@?5in?5C?5dtor?5?6?$AA@" +"??_C@_0N@FCCEEGKL@?5in?5C?5dtor?5?6?$AA@": + .asciz " in C dtor \n" + + .section .rdata,"dr",discard,"??_C@_0N@EFFPFCOI@?5in?5B?5dtor?5?6?$AA@" + .globl "??_C@_0N@EFFPFCOI@?5in?5B?5dtor?5?6?$AA@" # @"??_C@_0N@EFFPFCOI@?5in?5B?5dtor?5?6?$AA@" +"??_C@_0N@EFFPFCOI@?5in?5B?5dtor?5?6?$AA@": + .asciz " in B dtor \n" + + .section .rdata,"dr",discard,"??_C@_0N@HMNCGOCN@?5in?5A?5dtor?5?6?$AA@" + .globl "??_C@_0N@HMNCGOCN@?5in?5A?5dtor?5?6?$AA@" # @"??_C@_0N@HMNCGOCN@?5in?5A?5dtor?5?6?$AA@" +"??_C@_0N@HMNCGOCN@?5in?5A?5dtor?5?6?$AA@": + .asciz " in A dtor \n" + + .section .drectve,"yn" + .ascii " /DEFAULTLIB:libcmt.lib" + .ascii " /DEFAULTLIB:oldnames.lib" + .addrsig + .addrsig_sym "?crash@@YAXH@Z" + .addrsig_sym __CxxFrameHandler3 + .addrsig_sym __C_specific_handler + .addrsig_sym "?printf@@YAXZZ" + .addrsig_sym "?NullPtr@@3PECHEC" diff --git a/clang/test/CodeGen/windows-seh-EHa-CppDtors01.cpp b/clang/test/CodeGen/windows-seh-EHa-CppDtors01.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/windows-seh-EHa-CppDtors01.cpp @@ -0,0 +1,60 @@ +// RUN: %clang_cc1 -triple x86_64-windows fasync-exceptions -fcxx-exceptions -fexceptions -fms-extensions -x c++ -Wno-implicit-function-declaration -S -emit-llvm %s -o - | FileCheck %s + +// 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 +// 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; +} diff --git a/clang/test/CodeGen/windows-seh-EHa-CppDtors01.ll b/clang/test/CodeGen/windows-seh-EHa-CppDtors01.ll new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/windows-seh-EHa-CppDtors01.ll @@ -0,0 +1,228 @@ +; ModuleID = 'windows-seh-EHa-CppDtors01.cpp' +source_filename = "windows-seh-EHa-CppDtors01.cpp" +target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-windows-msvc" + +%struct.A = type { i8 } +%struct.B = type { i8 } +%struct.C = type { i8 } + +$"??_C@_0CM@KAOHJHDK@?5Test?5CPP?5unwind?3?5in?5catch?5handl@" = comdat any + +$"??_C@_0N@FCCEEGKL@?5in?5C?5dtor?5?6?$AA@" = comdat any + +$"??_C@_0N@EFFPFCOI@?5in?5B?5dtor?5?6?$AA@" = comdat any + +$"??_C@_0N@HMNCGOCN@?5in?5A?5dtor?5?6?$AA@" = comdat any + +@"?g@@3HA" = dso_local global i32 0, align 4 +@"??_C@_0CM@KAOHJHDK@?5Test?5CPP?5unwind?3?5in?5catch?5handl@" = linkonce_odr dso_local unnamed_addr constant [44 x i8] c" Test CPP unwind: in catch handler i = %d \0A\00", comdat, align 1 +@"??_C@_0N@FCCEEGKL@?5in?5C?5dtor?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [13 x i8] c" in C dtor \0A\00", comdat, align 1 +@"??_C@_0N@EFFPFCOI@?5in?5B?5dtor?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [13 x i8] c" in B dtor \0A\00", comdat, align 1 +@"??_C@_0N@HMNCGOCN@?5in?5A?5dtor?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [13 x i8] c" in A dtor \0A\00", comdat, align 1 + +; Function Attrs: noinline optnone +define dso_local void @"?crash@@YAXH@Z"(i32 %i) #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { +entry: + %i.addr = alloca i32, align 4 + %ObjA = alloca %struct.A, align 1 + %ObjB = alloca %struct.B, align 1 + %ObjC = alloca %struct.C, align 1 + store i32 %i, i32* %i.addr, align 4 + invoke void @llvm.seh.scope.begin() + to label %invoke.cont unwind label %ehcleanup13 + +invoke.cont: ; preds = %entry + %0 = load i32, i32* %i.addr, align 4 + %cmp = icmp eq i32 %0, 0 + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %invoke.cont + store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4 + br label %if.end + +if.end: ; preds = %if.then, %invoke.cont + invoke void @llvm.seh.scope.begin() + to label %invoke.cont1 unwind label %ehcleanup11 + +invoke.cont1: ; preds = %if.end + %1 = load i32, i32* %i.addr, align 4 + %cmp2 = icmp eq i32 %1, 1 + br i1 %cmp2, label %if.then3, label %if.end4 + +if.then3: ; preds = %invoke.cont1 + store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4 + br label %if.end4 + +if.end4: ; preds = %if.then3, %invoke.cont1 + invoke void @llvm.seh.scope.begin() + to label %invoke.cont5 unwind label %ehcleanup + +invoke.cont5: ; preds = %if.end4 + %2 = load i32, i32* %i.addr, align 4 + %cmp6 = icmp eq i32 %2, 2 + br i1 %cmp6, label %if.then7, label %if.end8 + +if.then7: ; preds = %invoke.cont5 + store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4 + br label %if.end8 + +if.end8: ; preds = %if.then7, %invoke.cont5 + invoke void @llvm.seh.scope.end() + to label %invoke.cont9 unwind label %ehcleanup + +invoke.cont9: ; preds = %if.end8 + call void @"??1C@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.C* %ObjC) #6 + invoke void @llvm.seh.scope.end() + to label %invoke.cont10 unwind label %ehcleanup11 + +invoke.cont10: ; preds = %invoke.cont9 + call void @"??1B@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.B* %ObjB) #6 + invoke void @llvm.seh.scope.end() + to label %invoke.cont12 unwind label %ehcleanup13 + +invoke.cont12: ; preds = %invoke.cont10 + call void @"??1A@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.A* %ObjA) #6 + ret void + +ehcleanup: ; preds = %if.end8, %if.end4 + %3 = cleanuppad within none [] + call void @"??1C@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.C* %ObjC) #6 [ "funclet"(token %3) ] + cleanupret from %3 unwind label %ehcleanup11 + +ehcleanup11: ; preds = %invoke.cont9, %ehcleanup, %if.end + %4 = cleanuppad within none [] + call void @"??1B@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.B* %ObjB) #6 [ "funclet"(token %4) ] + cleanupret from %4 unwind label %ehcleanup13 + +ehcleanup13: ; preds = %invoke.cont10, %ehcleanup11, %entry + %5 = cleanuppad within none [] + call void @"??1A@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.A* %ObjA) #6 [ "funclet"(token %5) ] + cleanupret from %5 unwind to caller +} + +; Function Attrs: nounwind readnone +declare dso_local void @llvm.seh.scope.begin() #1 + +declare dso_local i32 @__CxxFrameHandler3(...) + +; Function Attrs: nounwind readnone +declare dso_local void @llvm.seh.scope.end() #1 + +; Function Attrs: noinline nounwind optnone +define internal void @"??1C@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.C* %this) unnamed_addr #2 align 2 { +entry: + %this.addr = alloca %struct.C*, align 8 + store %struct.C* %this, %struct.C** %this.addr, align 8 + %this1 = load %struct.C*, %struct.C** %this.addr, align 8 + call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @"??_C@_0N@FCCEEGKL@?5in?5C?5dtor?5?6?$AA@", i64 0, i64 0)) + ret void +} + +; Function Attrs: noinline nounwind optnone +define internal void @"??1B@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.B* %this) unnamed_addr #2 align 2 { +entry: + %this.addr = alloca %struct.B*, align 8 + store %struct.B* %this, %struct.B** %this.addr, align 8 + %this1 = load %struct.B*, %struct.B** %this.addr, align 8 + call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @"??_C@_0N@EFFPFCOI@?5in?5B?5dtor?5?6?$AA@", i64 0, i64 0)) + ret void +} + +; Function Attrs: noinline nounwind optnone +define internal void @"??1A@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.A* %this) unnamed_addr #2 align 2 { +entry: + %this.addr = alloca %struct.A*, align 8 + store %struct.A* %this, %struct.A** %this.addr, align 8 + %this1 = load %struct.A*, %struct.A** %this.addr, align 8 + call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @"??_C@_0N@HMNCGOCN@?5in?5A?5dtor?5?6?$AA@", i64 0, i64 0)) + ret void +} + +; Function Attrs: noinline norecurse optnone +define dso_local i32 @main() #3 personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) { +entry: + %retval = alloca i32, align 4 + %i = alloca i32, align 4 + %__exception_code = alloca i32, align 4 + store i32 0, i32* %retval, align 4 + store i32 0, i32* %i, align 4 + br label %for.cond + +for.cond: ; preds = %for.inc, %entry + %0 = load i32, i32* %i, align 4 + %cmp = icmp slt i32 %0, 3 + br i1 %cmp, label %for.body, label %for.end + +for.body: ; preds = %for.cond + invoke void @llvm.seh.try.begin() + to label %invoke.cont unwind label %catch.dispatch + +invoke.cont: ; preds = %for.body + %1 = load volatile i32, i32* %i, align 4 + invoke void @"?crash@@YAXH@Z"(i32 %1) #7 + to label %invoke.cont1 unwind label %catch.dispatch + +invoke.cont1: ; preds = %invoke.cont + invoke void @llvm.seh.try.end() + to label %invoke.cont2 unwind label %catch.dispatch + +catch.dispatch: ; preds = %invoke.cont1, %invoke.cont, %for.body + %2 = catchswitch within none [label %__except] unwind to caller + +__except: ; preds = %catch.dispatch + %3 = catchpad within %2 [i8* null] + catchret from %3 to label %__except3 + +__except3: ; preds = %__except + %4 = call i32 @llvm.eh.exceptioncode(token %3) + store i32 %4, i32* %__exception_code, align 4 + %5 = load i32, i32* %i, align 4 + call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([44 x i8], [44 x i8]* @"??_C@_0CM@KAOHJHDK@?5Test?5CPP?5unwind?3?5in?5catch?5handl@", i64 0, i64 0), i32 %5) + br label %__try.cont + +__try.cont: ; preds = %__except3, %invoke.cont2 + br label %for.inc + +for.inc: ; preds = %__try.cont + %6 = load i32, i32* %i, align 4 + %inc = add nsw i32 %6, 1 + store i32 %inc, i32* %i, align 4 + br label %for.cond + +invoke.cont2: ; preds = %invoke.cont1 + br label %__try.cont + +for.end: ; preds = %for.cond + ret i32 0 +} + +; Function Attrs: nounwind willreturn +declare dso_local void @llvm.seh.try.begin() #4 + +declare dso_local i32 @__C_specific_handler(...) + +; Function Attrs: nounwind willreturn +declare dso_local void @llvm.seh.try.end() #4 + +; Function Attrs: nounwind readnone +declare i32 @llvm.eh.exceptioncode(token) #1 + +declare dso_local void @"?printf@@YAXZZ"(...) #5 + +attributes #0 = { noinline optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { noinline nounwind optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #3 = { noinline norecurse optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #4 = { nounwind willreturn } +attributes #5 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #6 = { nounwind } +attributes #7 = { noinline } + +!llvm.module.flags = !{!0, !1} +!llvm.ident = !{!2} + +!0 = !{i32 1, !"wchar_size", i32 2} +!1 = !{i32 2, !"eh-asynch", i32 1} +!2 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project 7ee479a760e0a4402b4eb7fb6168768a44f66945)"} + diff --git a/clang/test/CodeGen/windows-seh-EHa-CppDtors01.obj b/clang/test/CodeGen/windows-seh-EHa-CppDtors01.obj new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@This Inner Loop Header: Depth=1 +.Ltmp6: + movl %esi, %ecx + callq "?crash@@YAXH@Z" +.Ltmp7: +.LBB1_3: # %for.inc + # in Loop: Header=BB1_1 Depth=1 + addl $1, %esi + cmpl $3, %esi + jne .LBB1_1 + jmp .LBB1_4 +.LBB1_2: # %__except + # in Loop: Header=BB1_1 Depth=1 + movq %rdi, %rcx + movl %esi, %edx + callq "?printf@@YAXZZ" + jmp .LBB1_3 +.LBB1_4: # %for.cond.cleanup + xorl %eax, %eax + addq $32, %rsp + popq %rdi + popq %rsi + popq %rbp + retq +.Lfunc_end1: + .seh_handlerdata +.set .Lmain$parent_frame_offset, 32 + .long (.Llsda_end0-.Llsda_begin0)/16 # Number of call sites +.Llsda_begin0: + .long .Ltmp6@IMGREL+1 # LabelStart + .long .Ltmp7@IMGREL+1 # LabelEnd + .long 1 # CatchAll + .long .LBB1_2@IMGREL # ExceptionHandler +.Llsda_end0: + .text + .seh_endproc + # -- End function + .bss + .globl "?NullPtr@@3PECHEC" # @"?NullPtr@@3PECHEC" + .p2align 3 +"?NullPtr@@3PECHEC": + .quad 0 + + .globl "?g@@3HA" # @"?g@@3HA" + .p2align 2 +"?g@@3HA": + .long 0 # 0x0 + + .section .rdata,"dr",discard,"??_C@_0CM@KAOHJHDK@?5Test?5CPP?5unwind?3?5in?5catch?5handl@" + .globl "??_C@_0CM@KAOHJHDK@?5Test?5CPP?5unwind?3?5in?5catch?5handl@" # @"??_C@_0CM@KAOHJHDK@?5Test?5CPP?5unwind?3?5in?5catch?5handl@" +"??_C@_0CM@KAOHJHDK@?5Test?5CPP?5unwind?3?5in?5catch?5handl@": + .asciz " Test CPP unwind: in catch handler i = %d \n" + + .section .rdata,"dr",discard,"??_C@_0N@FCCEEGKL@?5in?5C?5dtor?5?6?$AA@" + .globl "??_C@_0N@FCCEEGKL@?5in?5C?5dtor?5?6?$AA@" # @"??_C@_0N@FCCEEGKL@?5in?5C?5dtor?5?6?$AA@" +"??_C@_0N@FCCEEGKL@?5in?5C?5dtor?5?6?$AA@": + .asciz " in C dtor \n" + + .section .rdata,"dr",discard,"??_C@_0N@EFFPFCOI@?5in?5B?5dtor?5?6?$AA@" + .globl "??_C@_0N@EFFPFCOI@?5in?5B?5dtor?5?6?$AA@" # @"??_C@_0N@EFFPFCOI@?5in?5B?5dtor?5?6?$AA@" +"??_C@_0N@EFFPFCOI@?5in?5B?5dtor?5?6?$AA@": + .asciz " in B dtor \n" + + .section .rdata,"dr",discard,"??_C@_0N@HMNCGOCN@?5in?5A?5dtor?5?6?$AA@" + .globl "??_C@_0N@HMNCGOCN@?5in?5A?5dtor?5?6?$AA@" # @"??_C@_0N@HMNCGOCN@?5in?5A?5dtor?5?6?$AA@" +"??_C@_0N@HMNCGOCN@?5in?5A?5dtor?5?6?$AA@": + .asciz " in A dtor \n" + + .addrsig + .addrsig_sym __C_specific_handler + .addrsig_sym __CxxFrameHandler3 diff --git a/clang/test/CodeGen/windows-seh-EHa-TryInFinally.asm b/clang/test/CodeGen/windows-seh-EHa-TryInFinally.asm new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/windows-seh-EHa-TryInFinally.asm @@ -0,0 +1,371 @@ +; Listing generated by Microsoft (R) Optimizing Compiler Version 19.28.29333.0 + +include listing.inc + +INCLUDELIB LIBCMT +INCLUDELIB OLDNAMES + +PUBLIC ?NullPtr@@3PECHEC ; NullPtr +_BSS SEGMENT +?NullPtr@@3PECHEC DQ 01H DUP (?) ; NullPtr +_BSS ENDS +CONST SEGMENT +$SG2783 DB ' --- Test _Try in _finally --- i = %d ', 0aH, 00H +$SG2786 DB ' In outer _try i = %d ', 0aH, 00H + ORG $+7 +$SG2789 DB ' In outer _finally i = %d ', 0aH, 00H + ORG $+3 +$SG2791 DB ' In Inner _finally i = %d ', 0aH, 00H + ORG $+3 +$SG2793 DB ' --- In outer except handler i = %d ', 0aH, 00H +CONST ENDS +PUBLIC main +EXTRN ?printf@@YAXZZ:PROC ; printf +EXTRN __C_specific_handler:PROC +pdata SEGMENT +$pdata$main DD imagerel $LN37 + DD imagerel $LN37+192 + DD imagerel $unwind$main +pdata ENDS +pdata SEGMENT +$pdata$main$fin$1 DD imagerel main$fin$1 + DD imagerel main$fin$1+91 + DD imagerel $unwind$main$fin$1 +$pdata$main$fin$0 DD imagerel main$fin$0 + DD imagerel main$fin$0+55 + DD imagerel $unwind$main$fin$0 +$pdata$main$fin$2 DD imagerel main$fin$2 + DD imagerel main$fin$2+51 + DD imagerel $unwind$main$fin$2 +$pdata$main$filt$3 DD imagerel main$filt$3 + DD imagerel main$filt$3+21 + DD imagerel $unwind$main$filt$3 +pdata ENDS +xdata SEGMENT +$unwind$main DD 010419H + DD 06204H + DD imagerel __C_specific_handler + DD 03H + DD imagerel $LN37+52 + DD imagerel $LN37+88 + DD imagerel main$fin$1 + DD 00H + DD imagerel $LN37+89 + DD imagerel $LN37+125 + DD imagerel main$fin$2 + DD 00H + DD imagerel $LN37+52 + DD imagerel $LN37+163 + DD imagerel main$filt$3 + DD imagerel $LN37+163 +$unwind$main$fin$1 DD 020611H + DD 050023206H + DD imagerel __C_specific_handler + DD 01H + DD imagerel main$fin$1+14 + DD imagerel main$fin$1+49 + DD imagerel main$fin$0 + DD 00H +$unwind$main$fin$0 DD 020601H + DD 050023206H +$unwind$main$fin$2 DD 020601H + DD 050023206H +$unwind$main$filt$3 DD 020601H + DD 050023206H +xdata ENDS +; Function compile flags: /Odtp +_TEXT SEGMENT +i$1 = 32 +main PROC +; File C:\LLVM6\llvm-project\clang\test\CodeGen\windows-seh-EHa-TryInFinally.cpp +; Line 18 +$LN37: + sub rsp, 56 ; 00000038H +; Line 19 + mov DWORD PTR i$1[rsp], 0 + jmp SHORT $LN4@main +$LN2@main: + mov eax, DWORD PTR i$1[rsp] + inc eax + mov DWORD PTR i$1[rsp], eax +$LN4@main: + cmp DWORD PTR i$1[rsp], 3 + jge $LN3@main +; Line 20 + mov edx, DWORD PTR i$1[rsp] + lea rcx, OFFSET FLAT:$SG2783 + call ?printf@@YAXZZ ; printf + npad 1 +; Line 23 + mov edx, DWORD PTR i$1[rsp] + lea rcx, OFFSET FLAT:$SG2786 + call ?printf@@YAXZZ ; printf +; Line 24 + cmp DWORD PTR i$1[rsp], 0 + jne SHORT $LN7@main +; Line 25 + mov rax, QWORD PTR ?NullPtr@@3PECHEC ; NullPtr + mov DWORD PTR [rax], 0 +$LN7@main: + npad 1 +$LN25@main: +; Line 28 + mov edx, DWORD PTR i$1[rsp] + lea rcx, OFFSET FLAT:$SG2789 + call ?printf@@YAXZZ ; printf +; Line 29 + cmp DWORD PTR i$1[rsp], 1 + jne SHORT $LN13@main +; Line 30 + mov rax, QWORD PTR ?NullPtr@@3PECHEC ; NullPtr + mov DWORD PTR [rax], 0 +$LN13@main: +$LN33@main: +; Line 32 + mov edx, DWORD PTR i$1[rsp] + lea rcx, OFFSET FLAT:$SG2791 + call ?printf@@YAXZZ ; printf +; Line 33 + cmp DWORD PTR i$1[rsp], 2 + jne SHORT $LN16@main +; Line 34 + mov rax, QWORD PTR ?NullPtr@@3PECHEC ; NullPtr + mov DWORD PTR [rax], 0 +$LN16@main: +; Line 36 + jmp SHORT $LN21@main +$LN19@main: +; Line 38 + mov edx, DWORD PTR i$1[rsp] + lea rcx, OFFSET FLAT:$SG2793 + call ?printf@@YAXZZ ; printf + npad 1 +$LN21@main: +; Line 40 + jmp $LN2@main +$LN3@main: +; Line 41 + xor eax, eax +$LN17@main: +; Line 42 + add rsp, 56 ; 00000038H + ret 0 +main ENDP +_TEXT ENDS +text$x SEGMENT +i$1 = 32 +main$fin$1 PROC +; Line 26 + push rbp + sub rsp, 32 ; 00000020H + mov rbp, rdx + mov QWORD PTR [rsp+56], rbp +$LN22@main$fin$1: +; Line 28 + mov edx, DWORD PTR i$1[rbp] + lea rcx, OFFSET FLAT:$SG2789 + call ?printf@@YAXZZ ; printf + npad 1 +; Line 29 + cmp DWORD PTR i$1[rbp], 1 + jne SHORT $LN9@main$fin$1 +; Line 30 + mov rax, QWORD PTR ?NullPtr@@3PECHEC ; NullPtr + mov DWORD PTR [rax], 0 +$LN9@main$fin$1: +$LN29@main$fin$1: +; Line 32 + mov edx, DWORD PTR i$1[rbp] + lea rcx, OFFSET FLAT:$SG2791 + call ?printf@@YAXZZ ; printf + npad 1 +; Line 33 + cmp DWORD PTR i$1[rbp], 2 + jne SHORT $LN23@main$fin$1 +; Line 34 + mov rax, QWORD PTR ?NullPtr@@3PECHEC ; NullPtr + mov DWORD PTR [rax], 0 +$LN23@main$fin$1: + add rsp, 32 ; 00000020H + pop rbp + ret 0 + int 3 +main$fin$1 ENDP +i$1 = 32 +main$fin$0 PROC +; Line 31 + push rbp + sub rsp, 32 ; 00000020H + mov rbp, rdx + mov rbp, QWORD PTR [rbp+56] +$LN26@main$fin$0: +; Line 32 + mov edx, DWORD PTR i$1[rbp] + lea rcx, OFFSET FLAT:$SG2791 + call ?printf@@YAXZZ ; printf + npad 1 +; Line 33 + cmp DWORD PTR i$1[rbp], 2 + jne SHORT $LN27@main$fin$0 +; Line 34 + mov rax, QWORD PTR ?NullPtr@@3PECHEC ; NullPtr + mov DWORD PTR [rax], 0 +$LN27@main$fin$0: + add rsp, 32 ; 00000020H + pop rbp + ret 0 + int 3 +main$fin$0 ENDP +i$1 = 32 +main$fin$2 PROC +; Line 31 + push rbp + sub rsp, 32 ; 00000020H + mov rbp, rdx +$LN30@main$fin$2: +; Line 32 + mov edx, DWORD PTR i$1[rbp] + lea rcx, OFFSET FLAT:$SG2791 + call ?printf@@YAXZZ ; printf + npad 1 +; Line 33 + cmp DWORD PTR i$1[rbp], 2 + jne SHORT $LN31@main$fin$2 +; Line 34 + mov rax, QWORD PTR ?NullPtr@@3PECHEC ; NullPtr + mov DWORD PTR [rax], 0 +$LN31@main$fin$2: + add rsp, 32 ; 00000020H + pop rbp + ret 0 + int 3 +main$fin$2 ENDP +i$1 = 32 +main$filt$3 PROC + push rbp + sub rsp, 32 ; 00000020H + mov rbp, rdx +$LN18@main$filt$: +; Line 37 + mov eax, 1 +$LN20@main$filt$: + add rsp, 32 ; 00000020H + pop rbp + ret 0 + int 3 +main$filt$3 ENDP +text$x ENDS +; Function compile flags: /Odtp +text$x SEGMENT +i$1 = 32 +main$fin$1 PROC +; Line 26 + push rbp + sub rsp, 32 ; 00000020H + mov rbp, rdx + mov QWORD PTR [rsp+56], rbp +$LN22@main$fin$1: +; Line 28 + mov edx, DWORD PTR i$1[rbp] + lea rcx, OFFSET FLAT:$SG2789 + call ?printf@@YAXZZ ; printf + npad 1 +; Line 29 + cmp DWORD PTR i$1[rbp], 1 + jne SHORT $LN9@main$fin$1 +; Line 30 + mov rax, QWORD PTR ?NullPtr@@3PECHEC ; NullPtr + mov DWORD PTR [rax], 0 +$LN9@main$fin$1: +$LN29@main$fin$1: +; Line 32 + mov edx, DWORD PTR i$1[rbp] + lea rcx, OFFSET FLAT:$SG2791 + call ?printf@@YAXZZ ; printf + npad 1 +; Line 33 + cmp DWORD PTR i$1[rbp], 2 + jne SHORT $LN23@main$fin$1 +; Line 34 + mov rax, QWORD PTR ?NullPtr@@3PECHEC ; NullPtr + mov DWORD PTR [rax], 0 +$LN23@main$fin$1: + add rsp, 32 ; 00000020H + pop rbp + ret 0 + int 3 +main$fin$1 ENDP +text$x ENDS +; Function compile flags: /Odtp +text$x SEGMENT +i$1 = 32 +main$fin$0 PROC +; Line 31 + push rbp + sub rsp, 32 ; 00000020H + mov rbp, rdx + mov rbp, QWORD PTR [rbp+56] +$LN26@main$fin$0: +; Line 32 + mov edx, DWORD PTR i$1[rbp] + lea rcx, OFFSET FLAT:$SG2791 + call ?printf@@YAXZZ ; printf + npad 1 +; Line 33 + cmp DWORD PTR i$1[rbp], 2 + jne SHORT $LN27@main$fin$0 +; Line 34 + mov rax, QWORD PTR ?NullPtr@@3PECHEC ; NullPtr + mov DWORD PTR [rax], 0 +$LN27@main$fin$0: + add rsp, 32 ; 00000020H + pop rbp + ret 0 + int 3 +main$fin$0 ENDP +text$x ENDS +; Function compile flags: /Odtp +text$x SEGMENT +i$1 = 32 +main$fin$2 PROC +; Line 31 + push rbp + sub rsp, 32 ; 00000020H + mov rbp, rdx +$LN30@main$fin$2: +; Line 32 + mov edx, DWORD PTR i$1[rbp] + lea rcx, OFFSET FLAT:$SG2791 + call ?printf@@YAXZZ ; printf + npad 1 +; Line 33 + cmp DWORD PTR i$1[rbp], 2 + jne SHORT $LN31@main$fin$2 +; Line 34 + mov rax, QWORD PTR ?NullPtr@@3PECHEC ; NullPtr + mov DWORD PTR [rax], 0 +$LN31@main$fin$2: + add rsp, 32 ; 00000020H + pop rbp + ret 0 + int 3 +main$fin$2 ENDP +text$x ENDS +; Function compile flags: /Odtp +text$x SEGMENT +i$1 = 32 +main$filt$3 PROC + push rbp + sub rsp, 32 ; 00000020H + mov rbp, rdx +$LN18@main$filt$: +; Line 37 + mov eax, 1 +$LN20@main$filt$: + add rsp, 32 ; 00000020H + pop rbp + ret 0 + int 3 +main$filt$3 ENDP +text$x ENDS +END diff --git a/clang/test/CodeGen/windows-seh-EHa-TryInFinally.cpp b/clang/test/CodeGen/windows-seh-EHa-TryInFinally.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/windows-seh-EHa-TryInFinally.cpp @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -triple x86_64-windows fasync-exceptions -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; +} diff --git a/clang/test/CodeGen/windows-seh-EHa-TryInFinally.ll b/clang/test/CodeGen/windows-seh-EHa-TryInFinally.ll new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/windows-seh-EHa-TryInFinally.ll @@ -0,0 +1,213 @@ +; ModuleID = 'windows-seh-EHa-TryInFinally.cpp' +source_filename = "windows-seh-EHa-TryInFinally.cpp" +target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-windows-msvc" + +$"??_C@_0CI@MDFPIOJJ@?5?9?9?9?5Test?5_Try?5in?5_finally?5?9?9?9?5i@" = comdat any + +$"??_C@_0BN@HHKJHLBE@?5?5In?5Inner?5_finally?5i?5?$DN?5?$CFd?5?6?$AA@" = comdat any + +$"??_C@_0BN@HAIIIOKI@?5?5In?5outer?5_finally?5i?5?$DN?5?$CFd?5?6?$AA@" = comdat any + +$"??_C@_0BJ@OJMMAGCD@?5?5In?5outer?5_try?5i?5?$DN?5?$CFd?5?6?$AA@" = comdat any + +$"??_C@_0CG@ENDJHCGA@?5?9?9?9?5In?5outer?5except?5handler?5i?5?$DN@" = comdat any + +@"??_C@_0CI@MDFPIOJJ@?5?9?9?9?5Test?5_Try?5in?5_finally?5?9?9?9?5i@" = linkonce_odr dso_local unnamed_addr constant [40 x i8] c" --- Test _Try in _finally --- i = %d \0A\00", comdat, align 1 +@"??_C@_0BN@HHKJHLBE@?5?5In?5Inner?5_finally?5i?5?$DN?5?$CFd?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [29 x i8] c" In Inner _finally i = %d \0A\00", comdat, align 1 +@"??_C@_0BN@HAIIIOKI@?5?5In?5outer?5_finally?5i?5?$DN?5?$CFd?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [29 x i8] c" In outer _finally i = %d \0A\00", comdat, align 1 +@"??_C@_0BJ@OJMMAGCD@?5?5In?5outer?5_try?5i?5?$DN?5?$CFd?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [25 x i8] c" In outer _try i = %d \0A\00", comdat, align 1 +@"??_C@_0CG@ENDJHCGA@?5?9?9?9?5In?5outer?5except?5handler?5i?5?$DN@" = linkonce_odr dso_local unnamed_addr constant [38 x i8] c" --- In outer except handler i = %d \0A\00", comdat, align 1 + +; Function Attrs: noinline norecurse optnone +define dso_local i32 @main() #0 personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) { +entry: + %retval = alloca i32, align 4 + %i = alloca i32, align 4 + %__exception_code = alloca i32, align 4 + call void (...) @llvm.localescape(i32* %i) + store i32 0, i32* %retval, align 4 + store i32 0, i32* %i, align 4 + br label %for.cond + +for.cond: ; preds = %for.inc, %entry + %0 = load i32, i32* %i, align 4 + %cmp = icmp slt i32 %0, 3 + br i1 %cmp, label %for.body, label %for.end + +for.body: ; preds = %for.cond + %1 = load i32, i32* %i, align 4 + call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([40 x i8], [40 x i8]* @"??_C@_0CI@MDFPIOJJ@?5?9?9?9?5Test?5_Try?5in?5_finally?5?9?9?9?5i@", i64 0, i64 0), i32 %1) + invoke void @llvm.seh.try.begin() + to label %invoke.cont unwind label %catch.dispatch + +invoke.cont: ; preds = %for.body + invoke void @llvm.seh.try.begin() + to label %invoke.cont1 unwind label %ehcleanup + +invoke.cont1: ; preds = %invoke.cont + %2 = load volatile i32, i32* %i, align 4 + invoke void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([25 x i8], [25 x i8]* @"??_C@_0BJ@OJMMAGCD@?5?5In?5outer?5_try?5i?5?$DN?5?$CFd?5?6?$AA@", i64 0, i64 0), i32 %2) #6 + to label %invoke.cont2 unwind label %ehcleanup + +invoke.cont2: ; preds = %invoke.cont1 + %3 = load volatile i32, i32* %i, align 4 + %cmp3 = icmp eq i32 %3, 0 + br i1 %cmp3, label %if.then, label %if.end + +if.then: ; preds = %invoke.cont2 + store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4 + br label %if.end + +if.end: ; preds = %if.then, %invoke.cont2 + invoke void @llvm.seh.try.end() + to label %invoke.cont4 unwind label %ehcleanup + +invoke.cont4: ; preds = %if.end + %4 = call i8* @llvm.localaddress() + invoke void @"?fin$0@0@main@@"(i8 0, i8* %4) #6 + to label %invoke.cont5 unwind label %catch.dispatch + +invoke.cont5: ; preds = %invoke.cont4 + invoke void @llvm.seh.try.end() + to label %invoke.cont7 unwind label %catch.dispatch + +catch.dispatch: ; preds = %invoke.cont5, %invoke.cont6, %ehcleanup, %invoke.cont4, %for.body + %5 = catchswitch within none [label %__except] unwind to caller + +__except: ; preds = %catch.dispatch + %6 = catchpad within %5 [i8* null] + catchret from %6 to label %__except8 + +__except8: ; preds = %__except + %7 = call i32 @llvm.eh.exceptioncode(token %6) + store i32 %7, i32* %__exception_code, align 4 + %8 = load i32, i32* %i, align 4 + call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([38 x i8], [38 x i8]* @"??_C@_0CG@ENDJHCGA@?5?9?9?9?5In?5outer?5except?5handler?5i?5?$DN@", i64 0, i64 0), i32 %8) + br label %__try.cont + +__try.cont: ; preds = %__except8, %invoke.cont7 + br label %for.inc + +for.inc: ; preds = %__try.cont + %9 = load i32, i32* %i, align 4 + %inc = add nsw i32 %9, 1 + store i32 %inc, i32* %i, align 4 + br label %for.cond + +invoke.cont7: ; preds = %invoke.cont5 + br label %__try.cont + +ehcleanup: ; preds = %if.end, %invoke.cont1, %invoke.cont + %10 = cleanuppad within none [] + %11 = call i8* @llvm.localaddress() + invoke void @"?fin$0@0@main@@"(i8 1, i8* %11) #6 [ "funclet"(token %10) ] + to label %invoke.cont6 unwind label %catch.dispatch + +invoke.cont6: ; preds = %ehcleanup + cleanupret from %10 unwind label %catch.dispatch + +for.end: ; preds = %for.cond + ret i32 0 +} + +declare dso_local void @"?printf@@YAXZZ"(...) #1 + +; Function Attrs: nounwind willreturn +declare dso_local void @llvm.seh.try.begin() #2 + +declare dso_local i32 @__C_specific_handler(...) + +; Function Attrs: noinline +define internal void @"?fin$0@0@main@@"(i8 %abnormal_termination, i8* %frame_pointer) #3 personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) { +entry: + %frame_pointer.addr = alloca i8*, align 8 + %abnormal_termination.addr = alloca i8, align 1 + %0 = call i8* @llvm.localrecover(i8* bitcast (i32 ()* @main to i8*), i8* %frame_pointer, i32 0) + %i = bitcast i8* %0 to i32* + store i8* %frame_pointer, i8** %frame_pointer.addr, align 8 + store i8 %abnormal_termination, i8* %abnormal_termination.addr, align 1 + invoke void @llvm.seh.try.begin() + to label %invoke.cont unwind label %ehcleanup + +invoke.cont: ; preds = %entry + %1 = load volatile i32, i32* %i, align 4 + invoke void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([29 x i8], [29 x i8]* @"??_C@_0BN@HAIIIOKI@?5?5In?5outer?5_finally?5i?5?$DN?5?$CFd?5?6?$AA@", i64 0, i64 0), i32 %1) #6 + to label %invoke.cont1 unwind label %ehcleanup + +invoke.cont1: ; preds = %invoke.cont + %2 = load volatile i32, i32* %i, align 4 + %cmp = icmp eq i32 %2, 1 + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %invoke.cont1 + store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4 + br label %if.end + +if.end: ; preds = %if.then, %invoke.cont1 + invoke void @llvm.seh.try.end() + to label %invoke.cont2 unwind label %ehcleanup + +invoke.cont2: ; preds = %if.end + call void @"?fin$1@0@main@@"(i8 0, i8* %frame_pointer) + ret void + +ehcleanup: ; preds = %if.end, %invoke.cont, %entry + %3 = cleanuppad within none [] + call void @"?fin$1@0@main@@"(i8 1, i8* %frame_pointer) [ "funclet"(token %3) ] + cleanupret from %3 unwind to caller +} + +; Function Attrs: nounwind readnone +declare i8* @llvm.localrecover(i8*, i8*, i32 immarg) #4 + +; Function Attrs: noinline +define internal void @"?fin$1@0@main@@"(i8 %abnormal_termination, i8* %frame_pointer) #3 { +entry: + %frame_pointer.addr = alloca i8*, align 8 + %abnormal_termination.addr = alloca i8, align 1 + %0 = call i8* @llvm.localrecover(i8* bitcast (i32 ()* @main to i8*), i8* %frame_pointer, i32 0) + %i = bitcast i8* %0 to i32* + store i8* %frame_pointer, i8** %frame_pointer.addr, align 8 + store i8 %abnormal_termination, i8* %abnormal_termination.addr, align 1 + %1 = load i32, i32* %i, align 4 + call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([29 x i8], [29 x i8]* @"??_C@_0BN@HHKJHLBE@?5?5In?5Inner?5_finally?5i?5?$DN?5?$CFd?5?6?$AA@", i64 0, i64 0), i32 %1) + %2 = load i32, i32* %i, align 4 + %cmp = icmp eq i32 %2, 2 + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %entry + store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4 + br label %if.end + +if.end: ; preds = %if.then, %entry + ret void +} + +; Function Attrs: nounwind willreturn +declare dso_local void @llvm.seh.try.end() #2 + +; Function Attrs: nounwind readnone +declare i8* @llvm.localaddress() #4 + +; Function Attrs: nounwind readnone +declare i32 @llvm.eh.exceptioncode(token) #4 + +; Function Attrs: nounwind +declare void @llvm.localescape(...) #5 + +attributes #0 = { noinline norecurse optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind willreturn } +attributes #3 = { noinline "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #4 = { nounwind readnone } +attributes #5 = { nounwind } +attributes #6 = { noinline } + +!llvm.module.flags = !{!0, !1} +!llvm.ident = !{!2} + +!0 = !{i32 1, !"wchar_size", i32 2} +!1 = !{i32 2, !"eh-asynch", i32 1} +!2 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project 7ee479a760e0a4402b4eb7fb6168768a44f66945)"} + diff --git a/clang/test/CodeGen/windows-seh-EHa-TryInFinally.obj b/clang/test/CodeGen/windows-seh-EHa-TryInFinally.obj new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@ FuncletBaseStateMap; DenseMap InvokeStateMap; DenseMap> LabelToStateMap; + DenseMap BlockToStateMap; // for IsEHa SmallVector CxxUnwindMap; SmallVector TryBlockMap; SmallVector SEHUnwindMap; @@ -104,6 +105,8 @@ void addIPToStateRange(const InvokeInst *II, MCSymbol *InvokeBegin, MCSymbol *InvokeEnd); + void addIPToStateRange(int State, MCSymbol *InvokeBegin, MCSymbol *InvokeEnd); + int EHRegNodeFrameIndex = std::numeric_limits::max(); int EHRegNodeEndOffset = std::numeric_limits::max(); int EHGuardFrameIndex = std::numeric_limits::max(); @@ -122,6 +125,11 @@ WinEHFuncInfo &FuncInfo); void calculateClrEHStateNumbers(const Function *Fn, WinEHFuncInfo &FuncInfo); +// For IsEHa +void calculateCXXStateForBlocks(const BasicBlock *BB, int State, + WinEHFuncInfo &FuncInfo); +void calculateSEHStateForBlocks(const BasicBlock *BB, int State, + WinEHFuncInfo &FuncInfo); } // end namespace llvm diff --git a/llvm/include/llvm/IR/BasicBlock.h b/llvm/include/llvm/IR/BasicBlock.h --- a/llvm/include/llvm/IR/BasicBlock.h +++ b/llvm/include/llvm/IR/BasicBlock.h @@ -189,6 +189,13 @@ ->getFirstInsertionPt().getNonConst(); } + /// Returns the first potential -EHa faulty instruction + const Instruction *getFirstFaultyInst() const; + Instruction *getFirstFaultyInst() { + return const_cast( + static_cast(this)->getFirstFaultyInst()); + } + /// Return a const iterator range over the instructions in the block, skipping /// any debug instructions. iterator_range; +// 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_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/include/llvm/Support/ManagedStatic.h b/llvm/include/llvm/Support/ManagedStatic.h --- a/llvm/include/llvm/Support/ManagedStatic.h +++ b/llvm/include/llvm/Support/ManagedStatic.h @@ -55,9 +55,9 @@ #else // This should only be used as a static variable, which guarantees that this // will be zero initialized. - mutable std::atomic Ptr; - mutable void (*DeleterFn)(void *); - mutable const ManagedStaticBase *Next; + mutable std::atomic Ptr{ nullptr }; + mutable void (*DeleterFn)(void *) = nullptr; + mutable const ManagedStaticBase *Next = nullptr; #endif void RegisterManagedStatic(void *(*creator)(), void (*deleter)(void*)) const; diff --git a/llvm/lib/Analysis/EHPersonalities.cpp b/llvm/lib/Analysis/EHPersonalities.cpp --- a/llvm/lib/Analysis/EHPersonalities.cpp +++ b/llvm/lib/Analysis/EHPersonalities.cpp @@ -12,6 +12,7 @@ #include "llvm/IR/Constants.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instructions.h" +#include "llvm/IR/Module.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -71,7 +72,11 @@ // We can't simplify any invokes to nounwind functions if the personality // function wants to catch asynch exceptions. The nounwind attribute only // implies that the function does not throw synchronous exceptions. - return !isAsynchronousEHPersonality(Personality); + + // Cannot simplify CXX Personality under EHa + const llvm::Module *M = (const llvm::Module *)F->getParent(); + bool EHa = M->getModuleFlag("eh-asynch"); + return !isAsynchronousEHPersonality(Personality) && !EHa; } DenseMap llvm::colorEHFunclets(Function &F) { diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1104,7 +1104,7 @@ // Print out code for the function. bool HasAnyRealCode = false; int NumInstsInFunction = 0; - + bool IsEHa = MMI->getModule()->getModuleFlag("eh-asynch"); for (auto &MBB : *MF) { // Print a label for the basic block. emitBasicBlockStart(MBB); @@ -1140,10 +1140,24 @@ emitFrameAlloc(MI); break; case TargetOpcode::ANNOTATION_LABEL: - case TargetOpcode::EH_LABEL: case TargetOpcode::GC_LABEL: OutStreamer->emitLabel(MI.getOperand(0).getMCSymbol()); break; + case TargetOpcode::EH_LABEL: + OutStreamer->emitLabel(MI.getOperand(0).getMCSymbol()); + // For IsEHa, insert a Nop if followed by a trap inst + // Or the exception won't be caught. + // (see MCConstantExpr::create(1,..) in WinException.cpp) + // Ignore SDiv/UDiv bcause a DIV with Const-0 divisor + // must have being turned into an UndefValue. + // Div with variable opnds must be led by at least a Load + { + auto MI2 = std::next(MI.getIterator()); + if (IsEHa && MI2 != MBB.end() && + (MI2->mayLoadOrStore() || MI2->mayRaiseFPException())) + emitNops(1); + } + break; case TargetOpcode::INLINEASM: case TargetOpcode::INLINEASM_BR: emitInlineAsm(&MI); diff --git a/llvm/lib/CodeGen/AsmPrinter/WinException.cpp b/llvm/lib/CodeGen/AsmPrinter/WinException.cpp --- a/llvm/lib/CodeGen/AsmPrinter/WinException.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/WinException.cpp @@ -746,7 +746,11 @@ OS.emitInt32(0); AddComment("EHFlags"); - OS.emitInt32(1); + if (MMI->getModule()->getModuleFlag("eh-asynch")) { + OS.emitInt32(0); // -EHa + } else { + OS.emitInt32(1); + } // UnwindMapEntry { // int32_t ToState; diff --git a/llvm/lib/CodeGen/BranchFolding.cpp b/llvm/lib/CodeGen/BranchFolding.cpp --- a/llvm/lib/CodeGen/BranchFolding.cpp +++ b/llvm/lib/CodeGen/BranchFolding.cpp @@ -1206,7 +1206,7 @@ MadeChange |= OptimizeBlock(MBB); // If it is dead, remove it. - if (MBB->pred_empty()) { + if (MBB->pred_empty() && !MBB->hasAddressTaken()) { RemoveDeadBlock(MBB); MadeChange = true; ++NumDeadBlocks; diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/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::seh_scope_begin: + case Intrinsic::seh_try_end: + case Intrinsic::seh_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::seh_scope_begin: + case Intrinsic::seh_try_end: + case Intrinsic::seh_scope_end: // ignore return; case Intrinsic::experimental_stackmap: diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -58,6 +58,7 @@ #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/CodeGen/ValueTypes.h" +#include "llvm/CodeGen/WinEHFuncInfo.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" @@ -1295,6 +1296,40 @@ return true; } +// Mark and Report IPToState for each Block under IsEHa +void SelectionDAGISel::reportIPToStateForBlocks(MachineFunction *MF) { + MachineModuleInfo &MMI = MF->getMMI(); + llvm::WinEHFuncInfo *EHInfo = MF->getWinEHFuncInfo(); + if (!EHInfo) + return; + for (auto MBBI = MF->begin(); MBBI != MF->end(); ++MBBI) { + MachineBasicBlock *MBB = &*MBBI; + const BasicBlock *BB = MBB->getBasicBlock(); + int State = EHInfo->BlockToStateMap[BB]; + if (BB->getFirstFaultyInst()) { + // Report IP range only for blocks with Faulty inst + MCSymbol *BeginLabel = MMI.getContext().createTempSymbol(); + MCSymbol *EndLabel = MMI.getContext().createTempSymbol(); + EHInfo->addIPToStateRange(State, BeginLabel, EndLabel); + + // Insert EH Labels + auto MBBb = MBB->getFirstNonPHI(); + BuildMI(*MBB, MBBb, SDB->getCurDebugLoc(), + TII->get(TargetOpcode::EH_LABEL)) + .addSym(BeginLabel); + auto MBBe = MBB->instr_end(); + MachineInstr *MIb = &*(--MBBe); + // insert before (possible multiple) terminators + while (MIb->isTerminator()) + MIb = &*(--MBBe); + ++MBBe; + BuildMI(*MBB, MBBe, SDB->getCurDebugLoc(), + TII->get(TargetOpcode::EH_LABEL)) + .addSym(EndLabel); + } + } +} + /// isFoldedOrDeadInstruction - Return true if the specified instruction is /// side-effect free and is either dead or folded into a generated instruction. /// Return false if it needs to be emitted. @@ -1624,6 +1659,10 @@ ElidedArgCopyInstrs.clear(); } + // IsEHa: Report Block State under -EHa + if (Fn.getParent()->getModuleFlag("eh-asynch")) + reportIPToStateForBlocks(MF); + SP.copyToMachineFrameInfo(MF->getFrameInfo()); SwiftError->propagateVRegs(); diff --git a/llvm/lib/CodeGen/WinEHPrepare.cpp b/llvm/lib/CodeGen/WinEHPrepare.cpp --- a/llvm/lib/CodeGen/WinEHPrepare.cpp +++ b/llvm/lib/CodeGen/WinEHPrepare.cpp @@ -215,6 +215,97 @@ } } +// See comments below for calculateSEHStateForBlocks(). +// State - incoming State of normal paths +void llvm::calculateCXXStateForBlocks(const BasicBlock *BB, int State, + WinEHFuncInfo &EHInfo) { + if (EHInfo.BlockToStateMap.count(BB) && EHInfo.BlockToStateMap[BB] <= State) + return; // skip already visited or EHPad + + const llvm::Instruction *I = BB->getFirstNonPHI(); + const llvm::Instruction *TI = BB->getTerminator(); + if (I->isEHPad()) + State = EHInfo.EHPadStateMap[I]; + EHInfo.BlockToStateMap[BB] = State; // Record state, also flag visiting + + if ((isa(TI) || isa(TI)) && State > 0) { + // Retrive the new State + State = EHInfo.CxxUnwindMap[State].ToState; // Retrive next State + } else if (isa(TI)) { + auto *Call = dyn_cast(TI); + const Function *Fn = Call->getCalledFunction(); + if (Fn && Fn->isIntrinsic() && + (Fn->getIntrinsicID() == Intrinsic::seh_scope_begin || + Fn->getIntrinsicID() == Intrinsic::seh_try_begin)) + // Retrive the new State from eha_scope_begin + State = EHInfo.InvokeStateMap[cast(TI)]; + else if (Fn && Fn->isIntrinsic() && + (Fn->getIntrinsicID() == Intrinsic::seh_scope_end || + Fn->getIntrinsicID() == Intrinsic::seh_try_end)) { + // In case of conditional ctor, let's retrieve State from Invoke + State = EHInfo.InvokeStateMap[cast(TI)]; + // end of current state, retrive new state from UnwindMap + State = EHInfo.CxxUnwindMap[State].ToState; + } + } + // Continue traveling successors recursively + for (auto *SuccBB : successors(BB)) { + calculateCXXStateForBlocks(SuccBB, State, EHInfo); + } +} + +// The central theory of this routine is based on the following: +// A _try scope is always a SEME (Single Entry Multiple Exits) region +// as jumping into a _try is not allowed +// The single entry must start with a seh_try_begin() invoke with a +// correct State number that is the initial state of the SEME. +// Through control-flow, state number is propagated into all blocks. +// Side exits marked by seh_try_end() will unwind to parent state via +// existing SEHUnwindMap[]. +// Side exits can ONLY jump into parent scopes (lower state number). +// Thus, when a block succeeds various states from its predecessors, +// the lowest State triumphs others. +// If some exits flow to unreachable, propagation on those paths terminate, +// not affecting remaining blocks. +void llvm::calculateSEHStateForBlocks(const BasicBlock *BB, int State, + WinEHFuncInfo &EHInfo) { + if (EHInfo.BlockToStateMap.count(BB) && EHInfo.BlockToStateMap[BB] <= State) + return; // skip already visited by lower State + + const llvm::Instruction *I = BB->getFirstNonPHI(); + const llvm::Instruction *TI = BB->getTerminator(); + if (I->isEHPad()) + State = EHInfo.EHPadStateMap[I]; + EHInfo.BlockToStateMap[BB] = State; // Record state + + if (isa(I) && isa(TI)) { + const Constant *FilterOrNull = cast( + cast(I)->getArgOperand(0)->stripPointerCasts()); + const Function *Filter = dyn_cast(FilterOrNull); + if (!Filter || !Filter->getName().startswith("__IsLocalUnwind")) + State = EHInfo.SEHUnwindMap[State].ToState; // Retrive next State + } else if ((isa(TI) || isa(TI)) && + State > 0) { + // Retrive the new State. + State = EHInfo.SEHUnwindMap[State].ToState; // Retrive next State + } else if (isa(TI)) { + auto *Call = dyn_cast(TI); + const Function *Fn = Call->getCalledFunction(); + if (Fn && Fn->isIntrinsic() && + Fn->getIntrinsicID() == Intrinsic::seh_try_begin) + // Retrive the new State from seh_try_begin + State = EHInfo.InvokeStateMap[cast(TI)]; + else if (Fn && Fn->isIntrinsic() && + Fn->getIntrinsicID() == Intrinsic::seh_try_end) + // end of current state, retrive new state from UnwindMap + State = EHInfo.SEHUnwindMap[State].ToState; + } + // Continue traveling successors recursively + for (auto *SuccBB : successors(BB)) { + calculateSEHStateForBlocks(SuccBB, State, EHInfo); + } +} + // Given BB which ends in an unwind edge, return the EHPad that this BB belongs // to. If the unwind edge came from an invoke, return null. static const BasicBlock *getEHPadFromPredecessor(const BasicBlock *BB, @@ -275,6 +366,7 @@ for (const auto *CatchPad : Handlers) { FuncInfo.FuncletBaseStateMap[CatchPad] = CatchLow; + FuncInfo.EHPadStateMap[CatchPad] = CatchLow; for (const User *U : CatchPad->users()) { const auto *UserI = cast(U); if (auto *InnerCatchSwitch = dyn_cast(UserI)) { @@ -383,6 +475,7 @@ // Everything in the __try block uses TryState as its parent state. FuncInfo.EHPadStateMap[CatchSwitch] = TryState; + FuncInfo.EHPadStateMap[CatchPad] = TryState; LLVM_DEBUG(dbgs() << "Assigning state #" << TryState << " to BB " << CatchPadBB->getName() << '\n'); for (const BasicBlock *PredBlock : predecessors(BB)) @@ -463,6 +556,12 @@ } calculateStateNumbersForInvokes(Fn, FuncInfo); + + bool IsEHa = Fn->getParent()->getModuleFlag("eh-asynch"); + if (IsEHa) { + const BasicBlock *EntryBB = &(Fn->getEntryBlock()); + calculateSEHStateForBlocks(EntryBB, -1, FuncInfo); + } } void llvm::calculateWinCXXEHStateNumbers(const Function *Fn, @@ -481,6 +580,12 @@ } calculateStateNumbersForInvokes(Fn, FuncInfo); + + bool IsEHa = Fn->getParent()->getModuleFlag("eh-asynch"); + if (IsEHa) { + const BasicBlock *EntryBB = &(Fn->getEntryBlock()); + calculateCXXStateForBlocks(EntryBB, -1, FuncInfo); + } } static int addClrEHHandler(WinEHFuncInfo &FuncInfo, int HandlerParentState, @@ -1267,4 +1372,8 @@ LabelToStateMap[InvokeBegin] = std::make_pair(InvokeStateMap[II], InvokeEnd); } +void WinEHFuncInfo::addIPToStateRange(int State, MCSymbol *InvokeBegin, + MCSymbol *InvokeEnd) { + LabelToStateMap[InvokeBegin] = std::make_pair(State, InvokeEnd); +} WinEHFuncInfo::WinEHFuncInfo() {} diff --git a/llvm/lib/IR/BasicBlock.cpp b/llvm/lib/IR/BasicBlock.cpp --- a/llvm/lib/IR/BasicBlock.cpp +++ b/llvm/lib/IR/BasicBlock.cpp @@ -211,6 +211,15 @@ return BB->getTerminatingDeoptimizeCall(); } +const Instruction *BasicBlock::getFirstFaultyInst() const { + if (InstList.empty()) + return nullptr; + for (const Instruction &I : *this) + if (isa(I) || isa(I) || isa(I)) + return &I; + return nullptr; +} + const Instruction* BasicBlock::getFirstNonPHI() const { for (const Instruction &I : *this) if (!isa(I)) diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -4223,6 +4223,10 @@ Assert( !F->isIntrinsic() || isa(I) || F->getIntrinsicID() == Intrinsic::donothing || + F->getIntrinsicID() == Intrinsic::seh_try_begin || + F->getIntrinsicID() == Intrinsic::seh_try_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 ||