From: Reid Kleckner Date: Fri, 10 Apr 2015 17:34:52 +0000 (+0000) Subject: [SEH] Re-land r234532, but use internal linkage for all SEH helpers X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=48d7c1dcf4bf415ce286a534ebc598838f871bf4;p=clang [SEH] Re-land r234532, but use internal linkage for all SEH helpers Even though these symbols are in a comdat group, the Microsoft linker really wants them to have internal linkage. I'm planning to tweak the mangling in a follow-up change. This is a straight revert with a 1-line fix. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@234613 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Mangle.h b/include/clang/AST/Mangle.h index e4bccedff9..1050e65ff0 100644 --- a/include/clang/AST/Mangle.h +++ b/include/clang/AST/Mangle.h @@ -135,6 +135,9 @@ public: virtual void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl, raw_ostream &Out) = 0; + virtual void mangleSEHFinallyBlock(const NamedDecl *EnclosingDecl, + raw_ostream &Out) = 0; + /// Generates a unique string for an externally visible type for use with TBAA /// or type uniquing. /// TODO: Extend this to internal types by generating names that are unique diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index f890719c20..6e55655d85 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -166,6 +166,8 @@ public: raw_ostream &Out) override; void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl, raw_ostream &Out) override; + void mangleSEHFinallyBlock(const NamedDecl *EnclosingDecl, + raw_ostream &Out) override; void mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &) override; void mangleItaniumThreadLocalWrapper(const VarDecl *D, raw_ostream &) override; @@ -3967,6 +3969,16 @@ void ItaniumMangleContextImpl::mangleSEHFilterExpression( Mangler.getStream() << EnclosingDecl->getName(); } +void ItaniumMangleContextImpl::mangleSEHFinallyBlock( + const NamedDecl *EnclosingDecl, raw_ostream &Out) { + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "__fin_"; + if (shouldMangleDeclName(EnclosingDecl)) + Mangler.mangle(EnclosingDecl); + else + Mangler.getStream() << EnclosingDecl->getName(); +} + void ItaniumMangleContextImpl::mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &Out) { // ::= TH diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index bf9d7a0118..269fb1c255 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/lib/AST/MicrosoftMangle.cpp @@ -94,6 +94,7 @@ class MicrosoftMangleContextImpl : public MicrosoftMangleContext { llvm::DenseMap Uniquifier; llvm::DenseMap LambdaIds; llvm::DenseMap SEHFilterIds; + llvm::DenseMap SEHFinallyIds; public: MicrosoftMangleContextImpl(ASTContext &Context, DiagnosticsEngine &Diags) @@ -151,6 +152,8 @@ public: raw_ostream &Out) override; void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl, raw_ostream &Out) override; + void mangleSEHFinallyBlock(const NamedDecl *EnclosingDecl, + raw_ostream &Out) override; void mangleStringLiteral(const StringLiteral *SL, raw_ostream &Out) override; void mangleCXXVTableBitSet(const CXXRecordDecl *RD, raw_ostream &Out) override; @@ -2469,6 +2472,17 @@ void MicrosoftMangleContextImpl::mangleSEHFilterExpression( Mangler.mangleName(EnclosingDecl); } +void MicrosoftMangleContextImpl::mangleSEHFinallyBlock( + const NamedDecl *EnclosingDecl, raw_ostream &Out) { + MicrosoftCXXNameMangler Mangler(*this, Out); + // The function body is in the same comdat as the function with the handler, + // so the numbering here doesn't have to be the same across TUs. + // + // ::= ?fin$ @0 + Mangler.getStream() << "\01?fin$" << SEHFinallyIds[EnclosingDecl]++ << "@0@"; + Mangler.mangleName(EnclosingDecl); +} + void MicrosoftMangleContextImpl::mangleTypeName(QualType T, raw_ostream &Out) { // This is just a made up unique string for the purposes of tbaa. undname // does *not* know how to demangle it. diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index cc16053ac7..ff12a9ab82 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -23,6 +23,7 @@ #include "llvm/IR/CallSite.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/IntrinsicInst.h" +#include "llvm/Support/SaveAndRestore.h" using namespace clang; using namespace CodeGen; @@ -408,13 +409,6 @@ llvm::Value *CodeGenFunction::getSelectorFromSlot() { return Builder.CreateLoad(getEHSelectorSlot(), "sel"); } -llvm::Value *CodeGenFunction::getAbnormalTerminationSlot() { - if (!AbnormalTerminationSlot) - AbnormalTerminationSlot = - CreateTempAlloca(Int8Ty, "abnormal.termination.slot"); - return AbnormalTerminationSlot; -} - void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E, bool KeepInsertionPoint) { if (const Expr *SubExpr = E->getSubExpr()) { @@ -1287,8 +1281,7 @@ void CodeGenFunction::EmitSEHTryStmt(const SEHTryStmt &S) { return; } - SEHFinallyInfo FI; - EnterSEHTryStmt(S, FI); + EnterSEHTryStmt(S); { JumpDest TryExit = getJumpDestInCurrentScope("__try.__leave"); @@ -1301,42 +1294,36 @@ void CodeGenFunction::EmitSEHTryStmt(const SEHTryStmt &S) { else delete TryExit.getBlock(); } - ExitSEHTryStmt(S, FI); + ExitSEHTryStmt(S); } namespace { -struct PerformSEHFinally : EHScopeStack::Cleanup { - CodeGenFunction::SEHFinallyInfo *FI; - PerformSEHFinally(CodeGenFunction::SEHFinallyInfo *FI) : FI(FI) {} +struct PerformSEHFinally : EHScopeStack::Cleanup { + llvm::Function *OutlinedFinally; + PerformSEHFinally(llvm::Function *OutlinedFinally) + : OutlinedFinally(OutlinedFinally) {} void Emit(CodeGenFunction &CGF, Flags F) override { - // Cleanups are emitted at most twice: once for normal control flow and once - // for exception control flow. Branch into the finally block, and remember - // the continuation block so we can branch out later. - if (!FI->FinallyBB) { - FI->FinallyBB = CGF.createBasicBlock("__finally"); - FI->FinallyBB->insertInto(CGF.CurFn); - FI->FinallyBB->moveAfter(CGF.Builder.GetInsertBlock()); - } - - // Set the termination status and branch in. - CGF.Builder.CreateStore( - llvm::ConstantInt::get(CGF.Int8Ty, F.isForEHCleanup()), - CGF.getAbnormalTerminationSlot()); - CGF.Builder.CreateBr(FI->FinallyBB); - - // Create a continuation block for normal or exceptional control. - if (F.isForEHCleanup()) { - assert(!FI->ResumeBB && "double emission for EH"); - FI->ResumeBB = CGF.createBasicBlock("__finally.resume"); - CGF.EmitBlock(FI->ResumeBB); - } else { - assert(F.isForNormalCleanup() && !FI->ContBB && "double normal emission"); - FI->ContBB = CGF.createBasicBlock("__finally.cont"); - CGF.EmitBlock(FI->ContBB); - // Try to keep source order. - FI->ContBB->moveAfter(FI->FinallyBB); - } + ASTContext &Context = CGF.getContext(); + QualType ArgTys[2] = {Context.BoolTy, Context.VoidPtrTy}; + FunctionProtoType::ExtProtoInfo EPI; + const auto *FTP = cast( + Context.getFunctionType(Context.VoidTy, ArgTys, EPI)); + + CallArgList Args; + llvm::Value *IsForEH = + llvm::ConstantInt::get(CGF.ConvertType(ArgTys[0]), F.isForEHCleanup()); + Args.add(RValue::get(IsForEH), ArgTys[0]); + + CodeGenModule &CGM = CGF.CGM; + llvm::Value *Zero = llvm::ConstantInt::get(CGM.Int32Ty, 0); + llvm::Value *FrameAddr = CGM.getIntrinsic(llvm::Intrinsic::frameaddress); + llvm::Value *FP = CGF.Builder.CreateCall(FrameAddr, Zero); + Args.add(RValue::get(FP), ArgTys[1]); + + const CGFunctionInfo &FnInfo = + CGM.getTypes().arrangeFreeFunctionCall(Args, FTP, /*chainCall=*/false); + CGF.EmitCall(FnInfo, OutlinedFinally, ReturnValueSlot(), Args); } }; } @@ -1354,7 +1341,8 @@ struct CaptureFinder : ConstStmtVisitor { // See if this is a capture, then recurse. ConstStmtVisitor::Visit(S); for (const Stmt *Child : S->children()) - Visit(Child); + if (Child) + Visit(Child); } void VisitDeclRefExpr(const DeclRefExpr *E) { @@ -1403,12 +1391,16 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF, CGM.ErrorUnsupported(VD, "VLA captured by SEH"); continue; } - assert((isa(VD) || VD->isLocalVarDeclOrParm()) && "captured non-local variable"); - llvm::Value *ParentVar = ParentCGF.LocalDeclMap[VD]; - assert(ParentVar && "capture was not a local decl"); + // If this decl hasn't been declared yet, it will be declared in the + // OutlinedStmt. + auto I = ParentCGF.LocalDeclMap.find(VD); + if (I == ParentCGF.LocalDeclMap.end()) + continue; + llvm::Value *ParentVar = I->second; + llvm::CallInst *RecoverCall = nullptr; CGBuilderTy Builder(AllocaInsertPt); if (auto *ParentAlloca = dyn_cast(ParentVar)) { @@ -1445,47 +1437,24 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF, } } -/// Create a stub filter function that will ultimately hold the code of the -/// filter expression. The EH preparation passes in LLVM will outline the code -/// from the main function body into this stub. -llvm::Function * -CodeGenFunction::GenerateSEHFilterFunction(CodeGenFunction &ParentCGF, - const SEHExceptStmt &Except) { - const Decl *ParentCodeDecl = ParentCGF.CurCodeDecl; +/// Arrange a function prototype that can be called by Windows exception +/// handling personalities. On Win64, the prototype looks like: +/// RetTy func(void *EHPtrs, void *ParentFP); +void CodeGenFunction::startOutlinedSEHHelper(CodeGenFunction &ParentCGF, + StringRef Name, QualType RetTy, + FunctionArgList &Args, + const Stmt *OutlinedStmt) { llvm::Function *ParentFn = ParentCGF.CurFn; - - Expr *FilterExpr = Except.getFilterExpr(); - - // Get the mangled function name. - SmallString<128> Name; - { - llvm::raw_svector_ostream OS(Name); - const NamedDecl *Parent = dyn_cast_or_null(ParentCodeDecl); - assert(Parent && "FIXME: handle unnamed decls (lambdas, blocks) with SEH"); - CGM.getCXXABI().getMangleContext().mangleSEHFilterExpression(Parent, OS); - } - - // Arrange a function with the declaration: - // int filt(EXCEPTION_POINTERS *exception_pointers, void *frame_pointer) - QualType RetTy = getContext().IntTy; - FunctionArgList Args; - SEHPointersDecl = ImplicitParamDecl::Create( - getContext(), nullptr, FilterExpr->getLocStart(), - &getContext().Idents.get("exception_pointers"), getContext().VoidPtrTy); - Args.push_back(SEHPointersDecl); - Args.push_back(ImplicitParamDecl::Create( - getContext(), nullptr, FilterExpr->getLocStart(), - &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy)); const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeFreeFunctionDeclaration( RetTy, Args, FunctionType::ExtInfo(), /*isVariadic=*/false); + llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo); - llvm::Function *Fn = llvm::Function::Create(FnTy, ParentFn->getLinkage(), - Name.str(), &CGM.getModule()); + llvm::Function *Fn = llvm::Function::Create( + FnTy, llvm::GlobalValue::InternalLinkage, Name.str(), &CGM.getModule()); // The filter is either in the same comdat as the function, or it's internal. if (llvm::Comdat *C = ParentFn->getComdat()) { Fn->setComdat(C); } else if (ParentFn->hasWeakLinkage() || ParentFn->hasLinkOnceLinkage()) { - // FIXME: Unreachable with Rafael's changes? llvm::Comdat *C = CGM.getModule().getOrInsertComdat(ParentFn->getName()); ParentFn->setComdat(C); Fn->setComdat(C); @@ -1493,14 +1462,55 @@ CodeGenFunction::GenerateSEHFilterFunction(CodeGenFunction &ParentCGF, Fn->setLinkage(llvm::GlobalValue::InternalLinkage); } + IsOutlinedSEHHelper = true; + StartFunction(GlobalDecl(), RetTy, Fn, FnInfo, Args, - FilterExpr->getLocStart(), FilterExpr->getLocStart()); + OutlinedStmt->getLocStart(), OutlinedStmt->getLocStart()); - EmitSEHExceptionCodeSave(); + CGM.SetLLVMFunctionAttributes(nullptr, FnInfo, CurFn); auto AI = Fn->arg_begin(); ++AI; - EmitCapturedLocals(ParentCGF, FilterExpr, &*AI); + EmitCapturedLocals(ParentCGF, OutlinedStmt, &*AI); +} + +/// Create a stub filter function that will ultimately hold the code of the +/// filter expression. The EH preparation passes in LLVM will outline the code +/// from the main function body into this stub. +llvm::Function * +CodeGenFunction::GenerateSEHFilterFunction(CodeGenFunction &ParentCGF, + const SEHExceptStmt &Except) { + const Expr *FilterExpr = Except.getFilterExpr(); + SourceLocation StartLoc = FilterExpr->getLocStart(); + + SEHPointersDecl = ImplicitParamDecl::Create( + getContext(), nullptr, StartLoc, + &getContext().Idents.get("exception_pointers"), getContext().VoidPtrTy); + FunctionArgList Args; + Args.push_back(SEHPointersDecl); + Args.push_back(ImplicitParamDecl::Create( + getContext(), nullptr, StartLoc, + &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy)); + + // Get the mangled function name. + SmallString<128> Name; + { + llvm::raw_svector_ostream OS(Name); + const Decl *ParentCodeDecl = ParentCGF.CurCodeDecl; + const NamedDecl *Parent = dyn_cast_or_null(ParentCodeDecl); + assert(Parent && "FIXME: handle unnamed decls (lambdas, blocks) with SEH"); + CGM.getCXXABI().getMangleContext().mangleSEHFilterExpression(Parent, OS); + } + + startOutlinedSEHHelper(ParentCGF, Name, getContext().IntTy, Args, FilterExpr); + + // Mark finally block calls as nounwind and noinline to make LLVM's job a + // little easier. + // FIXME: Remove these restrictions in the future. + CurFn->addFnAttr(llvm::Attribute::NoUnwind); + CurFn->addFnAttr(llvm::Attribute::NoInline); + + EmitSEHExceptionCodeSave(); // Emit the original filter expression, convert to i32, and return. llvm::Value *R = EmitScalarExpr(FilterExpr); @@ -1510,7 +1520,42 @@ CodeGenFunction::GenerateSEHFilterFunction(CodeGenFunction &ParentCGF, FinishFunction(FilterExpr->getLocEnd()); - return Fn; + return CurFn; +} + +llvm::Function * +CodeGenFunction::GenerateSEHFinallyFunction(CodeGenFunction &ParentCGF, + const SEHFinallyStmt &Finally) { + const Stmt *FinallyBlock = Finally.getBlock(); + SourceLocation StartLoc = FinallyBlock->getLocStart(); + + FunctionArgList Args; + Args.push_back(ImplicitParamDecl::Create( + getContext(), nullptr, StartLoc, + &getContext().Idents.get("abnormal_termination"), getContext().BoolTy)); + Args.push_back(ImplicitParamDecl::Create( + getContext(), nullptr, StartLoc, + &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy)); + + // Get the mangled function name. + SmallString<128> Name; + { + llvm::raw_svector_ostream OS(Name); + const Decl *ParentCodeDecl = ParentCGF.CurCodeDecl; + const NamedDecl *Parent = dyn_cast_or_null(ParentCodeDecl); + assert(Parent && "FIXME: handle unnamed decls (lambdas, blocks) with SEH"); + CGM.getCXXABI().getMangleContext().mangleSEHFinallyBlock(Parent, OS); + } + + startOutlinedSEHHelper(ParentCGF, Name, getContext().VoidTy, Args, + FinallyBlock); + + // Emit the original filter expression, convert to i32, and return. + EmitStmt(FinallyBlock); + + FinishFunction(FinallyBlock->getLocEnd()); + + return CurFn; } void CodeGenFunction::EmitSEHExceptionCodeSave() { @@ -1554,21 +1599,24 @@ llvm::Value *CodeGenFunction::EmitSEHExceptionCode() { } llvm::Value *CodeGenFunction::EmitSEHAbnormalTermination() { - // Load from the abnormal termination slot. It will be uninitialized outside - // of __finally blocks, which we should warn or error on. - llvm::Value *IsEH = Builder.CreateLoad(getAbnormalTerminationSlot()); - return Builder.CreateZExt(IsEH, Int32Ty); + // Abnormal termination is just the first parameter to the outlined finally + // helper. + auto AI = CurFn->arg_begin(); + return Builder.CreateZExt(&*AI, Int32Ty); } -void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI) { - if (S.getFinallyHandler()) { +void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) { + CodeGenFunction HelperCGF(CGM, /*suppressNewContext=*/true); + if (const SEHFinallyStmt *Finally = S.getFinallyHandler()) { // Push a cleanup for __finally blocks. - EHStack.pushCleanup(NormalAndEHCleanup, &FI); + llvm::Function *FinallyFunc = + HelperCGF.GenerateSEHFinallyFunction(*this, *Finally); + EHStack.pushCleanup(NormalAndEHCleanup, FinallyFunc); return; } // Otherwise, we must have an __except block. - SEHExceptStmt *Except = S.getExceptHandler(); + const SEHExceptStmt *Except = S.getExceptHandler(); assert(Except); EHCatchScope *CatchScope = EHStack.pushCatch(1); @@ -1583,40 +1631,17 @@ void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI) { // In general, we have to emit an outlined filter function. Use the function // in place of the RTTI typeinfo global that C++ EH uses. - CodeGenFunction FilterCGF(CGM, /*suppressNewContext=*/true); llvm::Function *FilterFunc = - FilterCGF.GenerateSEHFilterFunction(*this, *Except); + HelperCGF.GenerateSEHFilterFunction(*this, *Except); llvm::Constant *OpaqueFunc = llvm::ConstantExpr::getBitCast(FilterFunc, Int8PtrTy); CatchScope->setHandler(0, OpaqueFunc, createBasicBlock("__except")); } -void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI) { +void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) { // Just pop the cleanup if it's a __finally block. - if (const SEHFinallyStmt *Finally = S.getFinallyHandler()) { + if (S.getFinallyHandler()) { PopCleanupBlock(); - assert(FI.ContBB && "did not emit normal cleanup"); - - // Emit the code into FinallyBB. - CGBuilderTy::InsertPoint SavedIP = Builder.saveIP(); - Builder.SetInsertPoint(FI.FinallyBB); - EmitStmt(Finally->getBlock()); - - if (HaveInsertPoint()) { - if (FI.ResumeBB) { - llvm::Value *IsEH = Builder.CreateLoad(getAbnormalTerminationSlot(), - "abnormal.termination"); - IsEH = Builder.CreateICmpEQ(IsEH, llvm::ConstantInt::get(Int8Ty, 0)); - Builder.CreateCondBr(IsEH, FI.ContBB, FI.ResumeBB); - } else { - // There was nothing exceptional in the try body, so we only have normal - // control flow. - Builder.CreateBr(FI.ContBB); - } - } - - Builder.restoreIP(SavedIP); - return; } @@ -1666,7 +1691,13 @@ void CodeGenFunction::EmitSEHLeaveStmt(const SEHLeaveStmt &S) { if (HaveInsertPoint()) EmitStopPoint(&S); - assert(!SEHTryEpilogueStack.empty() && - "sema should have rejected this __leave"); + // This must be a __leave from a __finally block, which we warn on and is UB. + // Just emit unreachable. + if (!isSEHTryScope()) { + Builder.CreateUnreachable(); + Builder.ClearInsertionPoint(); + return; + } + EmitBranchThroughCleanup(*SEHTryEpilogueStack.back()); } diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index e4339849ca..481fdbe227 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -1021,6 +1021,12 @@ void CodeGenFunction::EmitReturnOfRValue(RValue RV, QualType Ty) { /// if the function returns void, or may be missing one if the function returns /// non-void. Fun stuff :). void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) { + // Returning from an outlined SEH helper is UB, and we already warn on it. + if (IsOutlinedSEHHelper) { + Builder.CreateUnreachable(); + Builder.ClearInsertionPoint(); + } + // Emit the result value, even if unused, to evalute the side effects. const Expr *RV = S.getRetValue(); diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index fc4e8c2d1e..93f00113e9 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -41,7 +41,7 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext) CurFn(nullptr), CapturedStmtInfo(nullptr), SanOpts(CGM.getLangOpts().Sanitize), IsSanitizerScope(false), CurFuncIsThunk(false), AutoreleaseResult(false), SawAsmBlock(false), - BlockInfo(nullptr), BlockPointer(nullptr), + IsOutlinedSEHHelper(false), BlockInfo(nullptr), BlockPointer(nullptr), LambdaThisCaptureField(nullptr), NormalCleanupDest(nullptr), NextCleanupDestIndex(1), FirstBlockInfo(nullptr), EHResumeBlock(nullptr), ExceptionSlot(nullptr), EHSelectorSlot(nullptr), diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 7cf1521fcd..474bf57bb7 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -263,6 +263,10 @@ public: /// potentially set the return value. bool SawAsmBlock; + /// True if the current function is an outlined SEH helper. This can be a + /// finally block or filter expression. + bool IsOutlinedSEHHelper; + const CodeGen::CGBlockInfo *BlockInfo; llvm::Value *BlockPointer; @@ -351,17 +355,6 @@ public: void exit(CodeGenFunction &CGF); }; - /// Cleanups can be emitted for two reasons: normal control leaving a region - /// exceptional control flow leaving a region. - struct SEHFinallyInfo { - SEHFinallyInfo() - : FinallyBB(nullptr), ContBB(nullptr), ResumeBB(nullptr) {} - - llvm::BasicBlock *FinallyBB; - llvm::BasicBlock *ContBB; - llvm::BasicBlock *ResumeBB; - }; - /// Returns true inside SEH __try blocks. bool isSEHTryScope() const { return !SEHTryEpilogueStack.empty(); } @@ -1052,10 +1045,6 @@ public: llvm::Value *getExceptionSlot(); llvm::Value *getEHSelectorSlot(); - /// Stack slot that contains whether a __finally block is being executed as an - /// EH cleanup or as a normal cleanup. - llvm::Value *getAbnormalTerminationSlot(); - /// Returns the contents of the function's exception object and selector /// slots. llvm::Value *getExceptionFromSlot(); @@ -2003,12 +1992,19 @@ public: void EmitCXXTryStmt(const CXXTryStmt &S); void EmitSEHTryStmt(const SEHTryStmt &S); void EmitSEHLeaveStmt(const SEHLeaveStmt &S); - void EnterSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI); - void ExitSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI); + void EnterSEHTryStmt(const SEHTryStmt &S); + void ExitSEHTryStmt(const SEHTryStmt &S); + + void startOutlinedSEHHelper(CodeGenFunction &ParentCGF, StringRef Name, + QualType RetTy, FunctionArgList &Args, + const Stmt *OutlinedStmt); llvm::Function *GenerateSEHFilterFunction(CodeGenFunction &ParentCGF, const SEHExceptStmt &Except); + llvm::Function *GenerateSEHFinallyFunction(CodeGenFunction &ParentCGF, + const SEHFinallyStmt &Finally); + void EmitSEHExceptionCodeSave(); llvm::Value *EmitSEHExceptionCode(); llvm::Value *EmitSEHExceptionInfo(); diff --git a/test/CodeGen/exceptions-seh-finally.c b/test/CodeGen/exceptions-seh-finally.c index eeadf0d5ec..a315379d52 100644 --- a/test/CodeGen/exceptions-seh-finally.c +++ b/test/CodeGen/exceptions-seh-finally.c @@ -17,30 +17,20 @@ void basic_finally(void) { // CHECK: to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] // // CHECK: [[invoke_cont]] -// CHECK: store i8 0, i8* %[[abnormal:[^ ]*]] -// CHECK: br label %[[finally:[^ ]*]] -// -// CHECK: [[finally]] -// CHECK: call void @cleanup() -// CHECK: load i8, i8* %[[abnormal]] -// CHECK: icmp eq -// CHECK: br i1 %{{.*}}, label %[[finallycont:[^ ]*]], label %[[resumecont:[^ ]*]] -// -// CHECK: [[finallycont]] +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: call void @"\01?fin$0@0@basic_finally@@"(i1 zeroext false, i8* %[[fp]]) // CHECK-NEXT: ret void // // CHECK: [[lpad]] // CHECK-NEXT: landingpad // CHECK-NEXT: cleanup -// CHECK: store i8 1, i8* %[[abnormal]] -// CHECK: br label %[[finally]] -// -// CHECK: [[resumecont]] -// CHECK: br label %[[ehresume:[^ ]*]] -// -// CHECK: [[ehresume]] +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: call void @"\01?fin$0@0@basic_finally@@"(i1 zeroext true, i8* %[[fp]]) // CHECK: resume { i8*, i32 } +// CHECK: define internal void @"\01?fin$0@0@basic_finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer) +// CHECK: call void @cleanup() + // Mostly check that we don't double emit 'r' which would crash. void decl_in_finally(void) { __try { @@ -67,10 +57,11 @@ l: // CHECK: to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] // // CHECK: [[invoke_cont]] -// CHECK: store i8 0, i8* %[[abnormal:[^ ]*]] -// CHECK: br label %[[finally:[^ ]*]] -// -// CHECK: [[finally]] +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: call void @"\01?fin$0@0@label_in_finally@@"(i1 zeroext false, i8* %[[fp]]) +// CHECK: ret void + +// CHECK: define internal void @"\01?fin$0@0@label_in_finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer) // CHECK: br label %[[l:[^ ]*]] // // CHECK: [[l]] @@ -93,32 +84,22 @@ void use_abnormal_termination(void) { // CHECK: to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] // // CHECK: [[invoke_cont]] -// CHECK: store i8 0, i8* %[[abnormal:[^ ]*]] -// CHECK: br label %[[finally:[^ ]*]] -// -// CHECK: [[finally]] -// CHECK: load i8, i8* %[[abnormal]] -// CHECK: zext i8 %{{.*}} to i32 -// CHECK: store i32 %{{.*}}, i32* @crashed -// CHECK: load i8, i8* %[[abnormal]] -// CHECK: icmp eq -// CHECK: br i1 %{{.*}}, label %[[finallycont:[^ ]*]], label %[[resumecont:[^ ]*]] -// -// CHECK: [[finallycont]] -// CHECK-NEXT: ret void +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: call void @"\01?fin$0@0@use_abnormal_termination@@"(i1 zeroext false, i8* %[[fp]]) +// CHECK: ret void // // CHECK: [[lpad]] // CHECK-NEXT: landingpad // CHECK-NEXT: cleanup -// CHECK: store i8 1, i8* %[[abnormal]] -// CHECK: br label %[[finally]] -// -// CHECK: [[resumecont]] -// CHECK: br label %[[ehresume:[^ ]*]] -// -// CHECK: [[ehresume]] +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: call void @"\01?fin$0@0@use_abnormal_termination@@"(i1 zeroext true, i8* %[[fp]]) // CHECK: resume { i8*, i32 } +// CHECK: define internal void @"\01?fin$0@0@use_abnormal_termination@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer) +// CHECK: %[[abnormal_zext:[^ ]*]] = zext i1 %abnormal_termination to i32 +// CHECK: store i32 %[[abnormal_zext]], i32* @crashed +// CHECK-NEXT: ret void + void noreturn_noop_finally() { __try { __noop(); @@ -128,12 +109,13 @@ void noreturn_noop_finally() { } // CHECK-LABEL: define void @noreturn_noop_finally() -// CHECK: store i8 0, i8* % -// CHECK: br label %[[finally:[^ ]*]] -// CHECK: [[finally]] +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: call void @"\01?fin$0@0@noreturn_noop_finally@@"(i1 zeroext false, i8* %[[fp]]) +// CHECK: ret void + +// CHECK: define internal void @"\01?fin$0@0@noreturn_noop_finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer) // CHECK: call void @abort() -// CHECK-NEXT: unreachable -// CHECK-NOT: load +// CHECK: unreachable void noreturn_finally() { __try { @@ -148,18 +130,20 @@ void noreturn_finally() { // CHECK: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] // // CHECK: [[cont]] -// CHECK: store i8 0, i8* % -// CHECK: br label %[[finally:[^ ]*]] -// -// CHECK: [[finally]] -// CHECK: call void @abort() -// CHECK-NEXT: unreachable +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: call void @"\01?fin$0@0@noreturn_finally@@"(i1 zeroext false, i8* %[[fp]]) +// CHECK: ret void // // CHECK: [[lpad]] // CHECK: landingpad // CHECK-NEXT: cleanup -// CHECK: store i8 1, i8* % -// CHECK: br label %[[finally]] +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: call void @"\01?fin$0@0@noreturn_finally@@"(i1 zeroext true, i8* %[[fp]]) +// CHECK: resume { i8*, i32 } + +// CHECK: define internal void @"\01?fin$0@0@noreturn_finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer) +// CHECK: call void @abort() +// CHECK: unreachable int finally_with_return() { __try { @@ -168,15 +152,17 @@ int finally_with_return() { } } // CHECK-LABEL: define i32 @finally_with_return() -// CHECK: store i8 0, i8* % -// CHECK-NEXT: br label %[[finally:[^ ]*]] -// -// CHECK: [[finally]] -// CHECK-NEXT: br label %[[finallycont:[^ ]*]] -// -// CHECK: [[finallycont]] +// CHECK: alloca i32 +// CHECK-NEXT: store i32 +// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK-NEXT: call void @"\01?fin$0@0@finally_with_return@@"(i1 zeroext false, i8* %[[fp]]) // CHECK-NEXT: ret i32 42 +// CHECK: define internal void @"\01?fin$0@0@finally_with_return@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer) +// CHECK-NOT: br i1 +// CHECK-NOT: br label +// CHECK: ret void + int nested___finally___finally() { __try { __try { @@ -188,38 +174,28 @@ int nested___finally___finally() { } return 0; } + // CHECK-LABEL: define i32 @nested___finally___finally -// CHECK: store i8 0, i8* % -// CHECK-NEXT: br label %[[finally:[^ ]*]] +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: invoke void @"\01?fin$1@0@nested___finally___finally@@"(i1 zeroext false, i8* %[[fp]]) +// CHECK: to label %[[outercont:[^ ]*]] unwind label %[[lpad:[^ ]*]] // -// CHECK: [[finally]] -// CHECK-NEXT: store i32 1, i32* % -// CHECK-NEXT: store i32 1, i32* % -// CHECK-NEXT: br label %[[cleanup:[^ ]*]] +// CHECK: [[outercont]] +// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally@@"(i1 zeroext false, i8* %[[fp]]) +// CHECK-NEXT: ret i32 0 // -// The finally's unreachable continuation block: -// CHECK: store i32 0, i32* % -// CHECK-NEXT: br label %[[cleanup]] -// -// CHECK: [[cleanup]] -// CHECK-NEXT: store i8 0, i8* % -// CHECK-NEXT: br label %[[outerfinally:[^ ]*]] -// -// CHECK: [[outerfinally]] -// CHECK-NEXT: br label %[[finallycont:[^ ]*]] -// -// CHECK: [[finallycont]] -// CHECK-NEXT: %[[dest:[^ ]*]] = load i32, i32* % -// CHECK-NEXT: switch i32 %[[dest]] -// CHECK-NEXT: i32 0, label %[[cleanupcont:[^ ]*]] -// -// CHECK: [[cleanupcont]] -// CHECK-NEXT: store i32 0, i32* % -// CHECK-NEXT: br label %[[return:[^ ]*]] -// -// CHECK: [[return]] -// CHECK-NEXT: %[[reg:[^ ]*]] = load i32, i32* % -// CHECK-NEXT: ret i32 %[[reg]] +// CHECK: [[lpad]] +// CHECK-NEXT: landingpad +// CHECK-NEXT: cleanup +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally@@"(i1 zeroext true, i8* %[[fp]]) + +// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer) +// CHECK: ret void + +// CHECK-LABEL: define internal void @"\01?fin$1@0@nested___finally___finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer) +// CHECK: unreachable int nested___finally___finally_with_eh_edge() { __try { @@ -234,58 +210,35 @@ int nested___finally___finally_with_eh_edge() { return 912; } // CHECK-LABEL: define i32 @nested___finally___finally_with_eh_edge -// CHECK: invoke void @might_crash() #3 -// CHECK-NEXT: to label %[[invokecont:[^ ]*]] unwind label %[[lpad:[^ ]*]] -// -// CHECK: [[invokecont]] -// CHECK-NEXT: store i8 0, i8* %[[abnormal:[^ ]*]] -// CHECK-NEXT: br label %[[finally:[^ ]*]] - -// CHECK: [[finally]] -// CHECK-NEXT: store i32 899, i32* % -// CHECK-NEXT: store i32 1, i32* % -// CHECK-NEXT: br label %[[cleanup:[^ ]*]] -// -// The inner finally's unreachable continuation block: -// CHECK: store i32 0, i32* % -// CHECK-NEXT: br label %[[cleanup]] -// -// CHECK: [[cleanup]] -// CHECK-NEXT: store i8 0, i8* % -// CHECK-NEXT: br label %[[outerfinally:[^ ]*]] -// -// CHECK: [[outerfinally]] -// CHECK-NEXT: %[[abnormallocal:[^ ]*]] = load i8, i8* %[[abnormal]] -// CHECK-NEXT: %[[reg:[^ ]*]] = icmp eq i8 %[[abnormallocal]], 0 -// CHECK-NEXT: br i1 %[[reg]], label %[[finallycont:[^ ]*]], label %[[finallyresume:[^ ]*]] -// -// CHECK: [[finallycont]] -// CHECK-NEXT: %[[dest:[^ ]*]] = load i32, i32* % -// CHECK-NEXT: switch i32 %[[dest]] -// CHECK-NEXT: i32 0, label %[[cleanupcont:[^ ]*]] +// CHECK: invoke void @might_crash() +// CHECK-NEXT: to label %[[invokecont:[^ ]*]] unwind label %[[lpad1:[^ ]*]] // -// CHECK: [[cleanupcont]] -// CHECK-NEXT: store i32 912, i32* % -// CHECK-NEXT: br label %[[return:[^ ]*]] +// [[invokecont]] +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: invoke void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"(i1 zeroext false, i8* %[[fp]]) +// CHECK: to label %[[outercont:[^ ]*]] unwind label %[[lpad2:[^ ]*]] // +// CHECK: [[outercont]] +// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"(i1 zeroext false, i8* %[[fp]]) +// CHECK-NEXT: ret i32 912 // -// CHECK: [[lpad]] +// CHECK: [[lpad1]] // CHECK-NEXT: landingpad // CHECK-NEXT: cleanup -// CHECK: store i8 1, i8* %[[abnormal]] -// CHECK: br label %[[finally]] -// -// The inner finally's unreachable resume block: -// CHECK: store i8 1, i8* %[[abnormal]] -// CHECK-NEXT: br label %[[outerfinally]] +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: invoke void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"(i1 zeroext true, i8* %[[fp]]) +// CHECK: to label %[[outercont:[^ ]*]] unwind label %[[lpad2]] // -// CHECK: [[finallyresume]] -// CHECK-NEXT: br label %[[ehresume:[^ ]*]] -// -// CHECK: [[return]] -// CHECK-NEXT: %[[reg:[^ ]*]] = load i32, i32* % -// CHECK-NEXT: ret i32 %[[reg]] -// -// The ehresume block, not reachable either. -// CHECK: [[ehresume]] +// CHECK: [[lpad2]] +// CHECK-NEXT: landingpad +// CHECK-NEXT: cleanup +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: call void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"(i1 zeroext true, i8* %[[fp]]) // CHECK: resume + +// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer) +// CHECK: ret void + +// CHECK-LABEL: define internal void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer) +// CHECK: unreachable diff --git a/test/CodeGen/exceptions-seh-leave.c b/test/CodeGen/exceptions-seh-leave.c index 0d38439c9b..793501a9fe 100644 --- a/test/CodeGen/exceptions-seh-leave.c +++ b/test/CodeGen/exceptions-seh-leave.c @@ -1,6 +1,6 @@ // RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s -void g(); +void g(void); ////////////////////////////////////////////////////////////////////////////// // __leave with __except @@ -38,7 +38,7 @@ int __leave_with___except() { return 1; } // CHECK-LABEL: define i32 @__leave_with___except() -// CHECK: invoke void bitcast (void (...)* @g to void ()*)() +// CHECK: invoke void @g() // CHECK-NEXT: to label %[[cont:.*]] unwind label %{{.*}} // For __excepts, instead of an explicit __try.__leave label, we could use // use invoke.cont as __leave jump target instead. However, not doing this @@ -74,8 +74,8 @@ int __leave_with___finally_simple() { // CHECK-NEXT: br label %[[tryleave:[^ ]*]] // CHECK-NOT: store i32 23 // CHECK: [[tryleave]] -// CHECK-NEXT: store i8 0, i8* % -// CHECK-NEXT: br label % +// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK-NEXT: call void @"\01?fin$0@0@__leave_with___finally_simple@@"(i1 zeroext false, i8* %[[fp]]) // __finally block doesn't return, __finally.cont doesn't exist. int __leave_with___finally_noreturn() { @@ -94,8 +94,8 @@ int __leave_with___finally_noreturn() { // CHECK-NEXT: br label %[[tryleave:[^ ]*]] // CHECK-NOT: store i32 23 // CHECK: [[tryleave]] -// CHECK-NEXT: store i8 0, i8* % -// CHECK-NEXT: br label % +// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK-NEXT: call void @"\01?fin$0@0@__leave_with___finally_noreturn@@"(i1 zeroext false, i8* %[[fp]]) // The "normal" case. int __leave_with___finally() { @@ -110,7 +110,7 @@ int __leave_with___finally() { return 1; } // CHECK-LABEL: define i32 @__leave_with___finally() -// CHECK: invoke void bitcast (void (...)* @g to void ()*)() +// CHECK: invoke void @g() // CHECK-NEXT: to label %[[cont:.*]] unwind label %{{.*}} // For __finally, there needs to be an explicit __try.__leave, because // abnormal.termination.slot needs to be set there. @@ -118,8 +118,8 @@ int __leave_with___finally() { // CHECK-NEXT: br label %[[tryleave:[^ ]*]] // CHECK-NOT: store i32 23 // CHECK: [[tryleave]] -// CHECK-NEXT: store i8 0, i8* % -// CHECK-NEXT: br label % +// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK-NEXT: call void @"\01?fin$0@0@__leave_with___finally@@"(i1 zeroext false, i8* %[[fp]]) ////////////////////////////////////////////////////////////////////////////// @@ -142,45 +142,37 @@ int nested___except___finally() { } return 1; } -// The order of basic blocks in the below doesn't matter. // CHECK-LABEL: define i32 @nested___except___finally() -// CHECK-LABEL: invoke void bitcast (void (...)* @g to void ()*)() -// CHECK-NEXT: to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]] - -// CHECK: [[g1_cont]] -// CHECK-NEXT: store i8 0, i8* %[[abnormal:[^ ]*]] -// CHECK-NEXT: br label %[[finally:[^ ]*]] +// CHECK-LABEL: invoke void @g() +// CHECK-NEXT: to label %[[g1_cont1:.*]] unwind label %[[g1_lpad:.*]] -// CHECK: [[finally]] -// CHECK-NEXT: invoke void bitcast (void (...)* @g to void ()*)() -// CHECK-NEXT: to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]] - -// CHECK: [[g2_cont]] -// CHECK-NEXT: br label %[[tryleave:[^ ]*]] -// CHECK-NOT: store i32 23 +// CHECK: [[g1_cont1]] +// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK-NEXT: invoke void @"\01?fin$0@0@nested___except___finally@@"(i1 zeroext false, i8* %[[fp]]) +// CHECK-NEXT: to label %[[fin_cont:.*]] unwind label %[[g2_lpad:.*]] -// Unused __finally continuation block +// CHECK: [[fin_cont]] // CHECK: store i32 51, i32* % -// CHECK-NEXT: br label %[[tryleave]] - -// CHECK: [[tryleave]] // CHECK-NEXT: br label %[[trycont:[^ ]*]] // CHECK: [[g1_lpad]] -// CHECK: store i8 1, i8* % -// CHECK-NEXT: br label %[[finally]] +// CHECK-NEXT: landingpad +// CHECK-NEXT: catch i8* null +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK-NEXT: invoke void @"\01?fin$0@0@nested___except___finally@@"(i1 zeroext true, i8* %[[fp]]) +// CHECK-NEXT: to label %[[g1_resume:.*]] unwind label %[[g2_lpad]] // CHECK: [[g2_lpad]] -// CHECK-NOT: %[[abnormal]] -// CHECK: br label %[[except:[^ ]*]] - -// CHECK: [[except]] -// CHECK-NEXT: br label %[[trycont]] +// CHECK: br label %[[trycont]] // CHECK: [[trycont]] // CHECK-NEXT: ret i32 1 +// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___except___finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer) +// CHECK: call void @g() +// CHECK: unreachable + int nested___except___except() { int myres = 0; __try { @@ -202,7 +194,7 @@ int nested___except___except() { // The order of basic blocks in the below doesn't matter. // CHECK-LABEL: define i32 @nested___except___except() -// CHECK-LABEL: invoke void bitcast (void (...)* @g to void ()*)() +// CHECK-LABEL: invoke void @g() // CHECK-NEXT: to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]] // CHECK: [[g1_cont]] @@ -213,7 +205,7 @@ int nested___except___except() { // CHECK: br label %[[except:[^ ]*]] // CHECK: [[except]] -// CHECK-NEXT: invoke void bitcast (void (...)* @g to void ()*)() #3 +// CHECK-NEXT: invoke void @g() // CHECK-NEXT: to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]] // CHECK: [[g2_cont]] @@ -256,7 +248,7 @@ int nested___finally___except() { // The order of basic blocks in the below doesn't matter. // CHECK-LABEL: define i32 @nested___finally___except() -// CHECK-LABEL: invoke void bitcast (void (...)* @g to void ()*)() +// CHECK-LABEL: invoke void @g() // CHECK-NEXT: to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]] // CHECK: [[g1_cont]] @@ -266,7 +258,7 @@ int nested___finally___except() { // CHECK: br label %[[except:[^ ]*]] // CHECK: [[except]] -// CHECK-NEXT: invoke void bitcast (void (...)* @g to void ()*)() +// CHECK-NEXT: invoke void @g() // CHECK-NEXT: to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]] // CHECK: [[g2_cont]] @@ -274,31 +266,25 @@ int nested___finally___except() { // CHECK-NOT: 23 // CHECK: [[g2_lpad]] -// CHECK: store i8 1, i8* %[[abnormal:[^ ]*]] -// CHECK-NEXT: br label %[[finally:[^ ]*]] +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___except@@"(i1 zeroext true, i8* %[[fp]]) +// CHECK-NEXT: br label %[[ehresume:[^ ]*]] // CHECK: [[trycont]] // CHECK: store i32 51, i32* % // CHECK-NEXT: br label %[[tryleave]] // CHECK: [[tryleave]] -// CHECK-NEXT: store i8 0, i8* %[[abnormal]] -// CHECK-NEXT: br label %[[finally:[^ ]*]] - -// CHECK: [[finally]] -// CHECK-NEXT: %[[abnormallocal:[^ ]*]] = load i8, i8* %[[abnormal]] -// CHECK-NEXT: %[[reg:[^ ]*]] = icmp eq i8 %[[abnormallocal]], 0 -// CHECK-NEXT: br i1 %[[reg]], label %[[finallycont:[^ ]*]], label %[[finallyresume:[^ ]*]] - -// CHECK: [[finallycont]] +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___except@@"(i1 zeroext false, i8* %[[fp]]) // CHECK-NEXT: ret i32 1 -// CHECK: [[finallyresume]] -// CHECK-NEXT: br label %[[ehresume:[^ ]*]] - // CHECK: [[ehresume]] // CHECK: resume +// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___except@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer) +// CHECK: ret void + int nested___finally___finally() { int myres = 0; __try { @@ -320,51 +306,44 @@ int nested___finally___finally() { // The order of basic blocks in the below doesn't matter. // CHECK-LABEL: define i32 @nested___finally___finally() -// CHECK-LABEL: invoke void bitcast (void (...)* @g to void ()*)() +// CHECK-LABEL: invoke void @g() // CHECK-NEXT: to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]] // CHECK: [[g1_cont]] // CHECK: store i32 16, i32* %[[myres:[^ ]*]], -// CHECK: store i8 0, i8* %[[abnormal:[^ ]*]] -// CHECK-NEXT: br label %[[finally:[^ ]*]] - -// CHECK: [[finally]] -// CHECK-NEXT: invoke void bitcast (void (...)* @g to void ()*)() #3 -// CHECK-NEXT: to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]] - -// CHECK: [[g2_cont]] -// CHECK-NEXT: br label %[[tryleave:[^ ]*]] -// CHECK-NOT: store i32 23 +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK-NEXT: invoke void @"\01?fin$1@0@nested___finally___finally@@"(i1 zeroext false, i8* %[[fp]]) +// CHECK-NEXT: to label %[[finally_cont:.*]] unwind label %[[g2_lpad:.*]] -// There's an unreachable block for the skipped `myres = 51`. +// CHECK: [[finally_cont]] // CHECK: store i32 51, i32* %[[myres]] -// CHECK-NEXT: br label %[[tryleave]] - -// CHECK: [[tryleave]] -// CHECK-NEXT: store i8 0, i8* %[[abnormal]] -// CHECK-NEXT: br label %[[outerfinally:[^ ]*]] - -// CHECK: [[outerfinally]] -// CHECK-NEXT: %[[abnormallocal:[^ ]*]] = load i8, i8* %[[abnormal]] -// CHECK-NEXT: %[[reg:[^ ]*]] = icmp eq i8 %[[abnormallocal]], 0 -// CHECK-NEXT: br i1 %[[reg]], label %[[finallycont:[^ ]*]], label %[[finallyresume:[^ ]*]] - -// CHECK: [[finallycont]] +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally@@"(i1 zeroext false, i8* %[[fp]]) // CHECK-NEXT: ret i32 1 // CHECK: [[g1_lpad]] -// CHECK: store i8 1, i8* %[[abnormal]] -// CHECK-NEXT: br label %[[finally:[^ ]*]] +// CHECK-NEXT: landingpad +// CHECK-NEXT: cleanup +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK-NEXT: invoke void @"\01?fin$1@0@nested___finally___finally@@"(i1 zeroext true, i8* %[[fp]]) +// CHECK-NEXT: to label %[[finally_cont2:.*]] unwind label %[[g2_lpad]] // CHECK: [[g2_lpad]] -// CHECK: br label %[[ehcleanup:[^ ]*]] +// CHECK-NEXT: landingpad +// CHECK-NEXT: cleanup +// CHECK: br label %[[ehcleanup:.*]] + +// CHECK: [[finally_cont2]] +// CHECK: br label %[[ehcleanup]] // CHECK: [[ehcleanup]] -// CHECK-NEXT: store i8 1, i8* %[[abnormal]] -// CHECK-NEXT: br label %[[outerfinally]] +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally@@"(i1 zeroext true, i8* %[[fp]]) +// CHECK: resume -// CHECK: [[finallyresume]] -// CHECK-NEXT: br label %[[ehresume:[^ ]*]] +// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer) +// CHECK: ret void -// CHECK: [[ehresume]] -// CHECK: resume +// CHECK-LABEL: define internal void @"\01?fin$1@0@nested___finally___finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer) +// CHECK: call void @g() +// CHECK: unreachable diff --git a/test/CodeGen/exceptions-seh.c b/test/CodeGen/exceptions-seh.c index 2d9d4b1f01..9a273ced56 100644 --- a/test/CodeGen/exceptions-seh.c +++ b/test/CodeGen/exceptions-seh.c @@ -118,8 +118,6 @@ int nested_try(void) { // CHECK: [[inner_try_cont]] // CHECK: br label %[[outer_try_cont]] -// FIXME: This lowering of __finally can't actually work, it will have to -// change. static unsigned g = 0; void basic_finally(void) { ++g; @@ -138,24 +136,23 @@ void basic_finally(void) { // CHECK: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] // // CHECK: [[cont]] -// CHECK: br label %[[finally:[^ ]*]] -// -// CHECK: [[finally]] -// CHECK: load i32, i32* @g -// CHECK: add i32 %{{.*}}, -1 -// CHECK: store i32 %{{.*}}, i32* @g -// CHECK: icmp eq -// CHECK: br i1 %{{.*}}, label -// +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: call void @"\01?fin$0@0@basic_finally@@"(i1 zeroext false, i8* %[[fp]]) // CHECK: ret void // // CHECK: [[lpad]] // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) // CHECK-NEXT: cleanup -// CHECK: br label %[[finally]] -// +// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0) +// CHECK: call void @"\01?fin$0@0@basic_finally@@"(i1 zeroext true, i8* %[[fp]]) // CHECK: resume +// CHECK: define internal void @"\01?fin$0@0@basic_finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer) +// CHECK: load i32, i32* @g, align 4 +// CHECK: add i32 %{{.*}}, -1 +// CHECK: store i32 %{{.*}}, i32* @g, align 4 +// CHECK: ret void + int returns_int(void); int except_return(void) { __try {