diff options
author | Reid Kleckner <reid@kleckner.net> | 2015-04-14 20:59:00 +0000 |
---|---|---|
committer | Reid Kleckner <reid@kleckner.net> | 2015-04-14 20:59:00 +0000 |
commit | ebaf28d13de293ff22dc49a5f40a0540c0aae4bb (patch) | |
tree | 21c4e32f36d0b28625933e652d6fc437da2f111f /clang/lib/CodeGen | |
parent | bef47e497f6d8851c29c554a9021183f53065ace (diff) | |
download | bcm5719-llvm-ebaf28d13de293ff22dc49a5f40a0540c0aae4bb.tar.gz bcm5719-llvm-ebaf28d13de293ff22dc49a5f40a0540c0aae4bb.zip |
Reland r234613 (and follow-ups 234614, 234616, 234618)
The frameescape intrinsic cannot be inlined, so I fixed the inliner in
r234937. This should address PR23216.
llvm-svn: 234942
Diffstat (limited to 'clang/lib/CodeGen')
-rw-r--r-- | clang/lib/CodeGen/CGException.cpp | 265 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGStmt.cpp | 6 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.cpp | 2 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.h | 30 |
4 files changed, 168 insertions, 135 deletions
diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp index cc16053ac7f..ff12a9ab829 100644 --- a/clang/lib/CodeGen/CGException.cpp +++ b/clang/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<FunctionType>( + 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<CaptureFinder> { // See if this is a capture, then recurse. ConstStmtVisitor<CaptureFinder>::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<ImplicitParamDecl>(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<llvm::AllocaInst>(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<NamedDecl>(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<NamedDecl>(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<NamedDecl>(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<PerformSEHFinally>(NormalAndEHCleanup, &FI); + llvm::Function *FinallyFunc = + HelperCGF.GenerateSEHFinallyFunction(*this, *Finally); + EHStack.pushCleanup<PerformSEHFinally>(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/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index e4339849ca3..481fdbe2278 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/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/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 8401d722f42..42c3a423fa0 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -40,7 +40,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/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 9116b71b08e..708929683b6 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/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(); @@ -2000,12 +1989,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(); |