diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/CodeGen/CGCleanup.cpp | 20 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGCleanup.h | 38 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGException.cpp | 165 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.cpp | 12 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.h | 1 | ||||
-rw-r--r-- | clang/lib/CodeGen/EHScopeStack.h | 4 | ||||
-rw-r--r-- | clang/lib/CodeGen/MicrosoftCXXABI.cpp | 42 | ||||
-rw-r--r-- | clang/lib/Frontend/CompilerInvocation.cpp | 1 |
8 files changed, 239 insertions, 44 deletions
diff --git a/clang/lib/CodeGen/CGCleanup.cpp b/clang/lib/CodeGen/CGCleanup.cpp index 3d4c4850f60..ef5a98ead98 100644 --- a/clang/lib/CodeGen/CGCleanup.cpp +++ b/clang/lib/CodeGen/CGCleanup.cpp @@ -247,6 +247,13 @@ void EHScopeStack::pushTerminate() { InnermostEHScope = stable_begin(); } +void EHScopeStack::pushCatchEnd(llvm::BasicBlock *CatchEndBlockBB) { + char *Buffer = allocate(EHCatchEndScope::getSize()); + auto *CES = new (Buffer) EHCatchEndScope(InnermostEHScope); + CES->setCachedEHDispatchBlock(CatchEndBlockBB); + InnermostEHScope = stable_begin(); +} + /// Remove any 'null' fixups on the stack. However, we can't pop more /// fixups than the fixup depth on the innermost normal cleanup, or /// else fixups that we try to add to that cleanup will end up in the @@ -896,6 +903,14 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP(); EmitBlock(EHEntry); + llvm::BasicBlock *NextAction = getEHDispatchBlock(EHParent); + if (CGM.getCodeGenOpts().NewMSEH && + EHPersonality::get(*this).isMSVCPersonality()) { + if (NextAction) + Builder.CreateCleanupPad(VoidTy, NextAction); + else + Builder.CreateCleanupPad(VoidTy, {}); + } // We only actually emit the cleanup code if the cleanup is either // active or was used before it was deactivated. @@ -905,7 +920,10 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { EmitCleanup(*this, Fn, cleanupFlags, EHActiveFlag); } - Builder.CreateBr(getEHDispatchBlock(EHParent)); + if (CGM.getCodeGenOpts().NewMSEH && EHPersonality::get(*this).isMSVCPersonality()) + Builder.CreateCleanupRet(NextAction); + else + Builder.CreateBr(NextAction); Builder.restoreIP(SavedIP); diff --git a/clang/lib/CodeGen/CGCleanup.h b/clang/lib/CodeGen/CGCleanup.h index 8338691ab5d..dcbc40db873 100644 --- a/clang/lib/CodeGen/CGCleanup.h +++ b/clang/lib/CodeGen/CGCleanup.h @@ -40,9 +40,9 @@ class EHScope { class CommonBitFields { friend class EHScope; - unsigned Kind : 2; + unsigned Kind : 3; }; - enum { NumCommonBits = 2 }; + enum { NumCommonBits = 3 }; protected: class CatchBitFields { @@ -81,7 +81,7 @@ protected: /// The number of fixups required by enclosing scopes (not including /// this one). If this is the top cleanup scope, all the fixups /// from this index onwards belong to this scope. - unsigned FixupDepth : 32 - 18 - NumCommonBits; // currently 13 + unsigned FixupDepth : 32 - 18 - NumCommonBits; // currently 12 }; class FilterBitFields { @@ -99,7 +99,7 @@ protected: }; public: - enum Kind { Cleanup, Catch, Terminate, Filter }; + enum Kind { Cleanup, Catch, Terminate, Filter, CatchEnd }; EHScope(Kind kind, EHScopeStack::stable_iterator enclosingEHScope) : CachedLandingPad(nullptr), CachedEHDispatchBlock(nullptr), @@ -466,6 +466,17 @@ public: } }; +class EHCatchEndScope : public EHScope { +public: + EHCatchEndScope(EHScopeStack::stable_iterator enclosingEHScope) + : EHScope(CatchEnd, enclosingEHScope) {} + static size_t getSize() { return sizeof(EHCatchEndScope); } + + static bool classof(const EHScope *scope) { + return scope->getKind() == CatchEnd; + } +}; + /// A non-stable pointer into the scope stack. class EHScopeStack::iterator { char *Ptr; @@ -503,6 +514,10 @@ public: case EHScope::Terminate: Size = EHTerminateScope::getSize(); break; + + case EHScope::CatchEnd: + Size = EHCatchEndScope::getSize(); + break; } Ptr += llvm::RoundUpToAlignment(Size, ScopeStackAlignment); return *this; @@ -551,6 +566,14 @@ inline void EHScopeStack::popTerminate() { deallocate(EHTerminateScope::getSize()); } +inline void EHScopeStack::popCatchEnd() { + assert(!empty() && "popping exception stack when not empty"); + + EHCatchEndScope &scope = cast<EHCatchEndScope>(*begin()); + InnermostEHScope = scope.getEnclosingEHScope(); + deallocate(EHCatchEndScope::getSize()); +} + inline EHScopeStack::iterator EHScopeStack::find(stable_iterator sp) const { assert(sp.isValid() && "finding invalid savepoint"); assert(sp.Size <= stable_begin().Size && "finding savepoint after pop"); @@ -588,6 +611,13 @@ struct EHPersonality { static const EHPersonality MSVC_except_handler; static const EHPersonality MSVC_C_specific_handler; static const EHPersonality MSVC_CxxFrameHandler3; + + bool isMSVCPersonality() const { + return this == &MSVC_except_handler || this == &MSVC_C_specific_handler || + this == &MSVC_CxxFrameHandler3; + } + + bool isMSVCXXPersonality() const { return this == &MSVC_CxxFrameHandler3; } }; } } diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp index d0e86ae2d9a..16dc7d16dd4 100644 --- a/clang/lib/CodeGen/CGException.cpp +++ b/clang/lib/CodeGen/CGException.cpp @@ -559,6 +559,10 @@ void CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) { llvm::BasicBlock * CodeGenFunction::getEHDispatchBlock(EHScopeStack::stable_iterator si) { + if (CGM.getCodeGenOpts().NewMSEH && + EHPersonality::get(*this).isMSVCPersonality()) + return getMSVCDispatchBlock(si); + // The dispatch block for the end of the scope chain is a block that // just resumes unwinding. if (si == EHStack.stable_end()) @@ -595,12 +599,58 @@ CodeGenFunction::getEHDispatchBlock(EHScopeStack::stable_iterator si) { case EHScope::Terminate: dispatchBlock = getTerminateHandler(); break; + + case EHScope::CatchEnd: + llvm_unreachable("CatchEnd unnecessary for Itanium!"); } scope.setCachedEHDispatchBlock(dispatchBlock); } return dispatchBlock; } +llvm::BasicBlock * +CodeGenFunction::getMSVCDispatchBlock(EHScopeStack::stable_iterator SI) { + // Returning nullptr indicates that the previous dispatch block should unwind + // to caller. + if (SI == EHStack.stable_end()) + return nullptr; + + // Otherwise, we should look at the actual scope. + EHScope &EHS = *EHStack.find(SI); + + llvm::BasicBlock *DispatchBlock = EHS.getCachedEHDispatchBlock(); + if (DispatchBlock) + return DispatchBlock; + + if (EHS.getKind() == EHScope::Terminate) + DispatchBlock = getTerminateHandler(); + else + DispatchBlock = createBasicBlock(); + CGBuilderTy Builder(DispatchBlock); + + switch (EHS.getKind()) { + case EHScope::Catch: + DispatchBlock->setName("catch.dispatch"); + break; + + case EHScope::Cleanup: + DispatchBlock->setName("ehcleanup"); + break; + + case EHScope::Filter: + llvm_unreachable("exception specifications not handled yet!"); + + case EHScope::Terminate: + DispatchBlock->setName("terminate"); + break; + + case EHScope::CatchEnd: + llvm_unreachable("CatchEnd dispatch block missing!"); + } + EHS.setCachedEHDispatchBlock(DispatchBlock); + return DispatchBlock; +} + /// Check whether this is a non-EH scope, i.e. a scope which doesn't /// affect exception handling. Currently, the only non-EH scopes are /// normal-only cleanup scopes. @@ -611,6 +661,7 @@ static bool isNonEHScope(const EHScope &S) { case EHScope::Filter: case EHScope::Catch: case EHScope::Terminate: + case EHScope::CatchEnd: return false; } @@ -636,8 +687,19 @@ llvm::BasicBlock *CodeGenFunction::getInvokeDestImpl() { llvm::BasicBlock *LP = EHStack.begin()->getCachedLandingPad(); if (LP) return LP; - // Build the landing pad for this scope. - LP = EmitLandingPad(); + const EHPersonality &Personality = EHPersonality::get(*this); + + if (!CurFn->hasPersonalityFn()) + CurFn->setPersonalityFn(getOpaquePersonalityFn(CGM, Personality)); + + if (CGM.getCodeGenOpts().NewMSEH && Personality.isMSVCPersonality()) { + // We don't need separate landing pads in the MSVC model. + LP = getEHDispatchBlock(EHStack.getInnermostEHScope()); + } else { + // Build the landing pad for this scope. + LP = EmitLandingPad(); + } + assert(LP); // Cache the landing pad on the innermost scope. If this is a @@ -658,6 +720,9 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { case EHScope::Terminate: return getTerminateLandingPad(); + case EHScope::CatchEnd: + llvm_unreachable("CatchEnd unnecessary for Itanium!"); + case EHScope::Catch: case EHScope::Cleanup: case EHScope::Filter: @@ -669,11 +734,6 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { CGBuilderTy::InsertPoint savedIP = Builder.saveAndClearIP(); auto DL = ApplyDebugLocation::CreateDefaultArtificial(*this, CurEHLocation); - const EHPersonality &personality = EHPersonality::get(*this); - - if (!CurFn->hasPersonalityFn()) - CurFn->setPersonalityFn(getOpaquePersonalityFn(CGM, personality)); - // Create and configure the landing pad. llvm::BasicBlock *lpad = createBasicBlock("lpad"); EmitBlock(lpad); @@ -728,6 +788,9 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { case EHScope::Catch: break; + + case EHScope::CatchEnd: + llvm_unreachable("CatchEnd unnecessary for Itanium!"); } EHCatchScope &catchScope = cast<EHCatchScope>(*I); @@ -792,10 +855,63 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { return lpad; } +static llvm::BasicBlock *emitMSVCCatchDispatchBlock(CodeGenFunction &CGF, + EHCatchScope &CatchScope) { + llvm::BasicBlock *DispatchBlock = CatchScope.getCachedEHDispatchBlock(); + assert(DispatchBlock); + + CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveIP(); + CGF.EmitBlockAfterUses(DispatchBlock); + + // Figure out the next block. + llvm::BasicBlock *NextBlock = nullptr; + + // Test against each of the exception types we claim to catch. + for (unsigned I = 0, E = CatchScope.getNumHandlers(); I < E; ++I) { + const EHCatchScope::Handler &Handler = CatchScope.getHandler(I); + + llvm::Value *TypeValue = Handler.Type; + assert(TypeValue != nullptr || Handler.isCatchAll()); + if (!TypeValue) + TypeValue = llvm::Constant::getNullValue(CGF.VoidPtrTy); + + // If this is the last handler, we're at the end, and the next + // block is the block for the enclosing EH scope. + if (I + 1 == E) { + NextBlock = CGF.createBasicBlock("catchendblock"); + CGBuilderTy(NextBlock).CreateCatchEndPad( + CGF.getEHDispatchBlock(CatchScope.getEnclosingEHScope())); + } else { + NextBlock = CGF.createBasicBlock("catch.dispatch"); + } + + if (EHPersonality::get(CGF).isMSVCXXPersonality()) { + CGF.Builder.CreateCatchPad( + CGF.VoidTy, Handler.Block, NextBlock, + {TypeValue, llvm::Constant::getNullValue(CGF.VoidPtrTy)}); + } else { + CGF.Builder.CreateCatchPad(CGF.VoidTy, Handler.Block, NextBlock, + {TypeValue}); + } + + // Otherwise we need to emit and continue at that block. + CGF.EmitBlock(NextBlock); + } + CGF.Builder.restoreIP(SavedIP); + + return NextBlock; +} + /// Emit the structure of the dispatch block for the given catch scope. /// It is an invariant that the dispatch block already exists. -static void emitCatchDispatchBlock(CodeGenFunction &CGF, - EHCatchScope &catchScope) { +/// If the catchblock instructions are used for EH dispatch, then the basic +/// block holding the final catchendblock instruction is returned. +static llvm::BasicBlock *emitCatchDispatchBlock(CodeGenFunction &CGF, + EHCatchScope &catchScope) { + if (CGF.CGM.getCodeGenOpts().NewMSEH && + EHPersonality::get(CGF).isMSVCPersonality()) + return emitMSVCCatchDispatchBlock(CGF, catchScope); + llvm::BasicBlock *dispatchBlock = catchScope.getCachedEHDispatchBlock(); assert(dispatchBlock); @@ -804,7 +920,7 @@ static void emitCatchDispatchBlock(CodeGenFunction &CGF, if (catchScope.getNumHandlers() == 1 && catchScope.getHandler(0).isCatchAll()) { assert(dispatchBlock == catchScope.getHandler(0).Block); - return; + return nullptr; } CGBuilderTy::InsertPoint savedIP = CGF.Builder.saveIP(); @@ -860,11 +976,12 @@ static void emitCatchDispatchBlock(CodeGenFunction &CGF, // If the next handler is a catch-all, we're completely done. if (nextIsEnd) { CGF.Builder.restoreIP(savedIP); - return; + return nullptr; } // Otherwise we need to emit and continue at that block. CGF.EmitBlock(nextBlock); } + return nullptr; } void CodeGenFunction::popCatchScope() { @@ -887,7 +1004,7 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) { } // Emit the structure of the EH dispatch for this catch. - emitCatchDispatchBlock(*this, CatchScope); + llvm::BasicBlock *CatchEndBlockBB = emitCatchDispatchBlock(*this, CatchScope); // Copy the handler blocks off before we pop the EH stack. Emitting // the handlers might scribble on this memory. @@ -911,6 +1028,9 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) { doImplicitRethrow = isa<CXXDestructorDecl>(CurCodeDecl) || isa<CXXConstructorDecl>(CurCodeDecl); + if (CatchEndBlockBB) + EHStack.pushCatchEnd(CatchEndBlockBB); + // Perversely, we emit the handlers backwards precisely because we // want them to appear in source order. In all of these cases, the // catch block will have exactly one predecessor, which will be a @@ -963,6 +1083,8 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) { EmitBlock(ContBB); incrementProfileCounter(&S); + if (CatchEndBlockBB) + EHStack.popCatchEnd(); } namespace { @@ -1200,13 +1322,18 @@ llvm::BasicBlock *CodeGenFunction::getTerminateHandler() { // end of the function by FinishFunction. TerminateHandler = createBasicBlock("terminate.handler"); Builder.SetInsertPoint(TerminateHandler); - llvm::Value *Exn = 0; - if (getLangOpts().CPlusPlus) - Exn = getExceptionFromSlot(); - llvm::CallInst *terminateCall = - CGM.getCXXABI().emitTerminateForUnexpectedException(*this, Exn); - terminateCall->setDoesNotReturn(); - Builder.CreateUnreachable(); + if (CGM.getCodeGenOpts().NewMSEH && + EHPersonality::get(*this).isMSVCPersonality()) { + Builder.CreateTerminatePad(/*UnwindBB=*/nullptr, CGM.getTerminateFn()); + } else { + llvm::Value *Exn = 0; + if (getLangOpts().CPlusPlus) + Exn = getExceptionFromSlot(); + llvm::CallInst *terminateCall = + CGM.getCXXABI().emitTerminateForUnexpectedException(*this, Exn); + terminateCall->setDoesNotReturn(); + Builder.CreateUnreachable(); + } // Restore the saved insertion state. Builder.restoreIP(SavedIP); diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index ec3c75ccd25..9bf4161e945 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -826,15 +826,11 @@ static void TryMarkNoThrow(llvm::Function *F) { // can't do this on functions that can be overwritten. if (F->mayBeOverridden()) return; - for (llvm::Function::iterator FI = F->begin(), FE = F->end(); FI != FE; ++FI) - for (llvm::BasicBlock::iterator - BI = FI->begin(), BE = FI->end(); BI != BE; ++BI) - if (llvm::CallInst *Call = dyn_cast<llvm::CallInst>(&*BI)) { - if (!Call->doesNotThrow()) - return; - } else if (isa<llvm::ResumeInst>(&*BI)) { + for (llvm::BasicBlock &BB : *F) + for (llvm::Instruction &I : BB) + if (I.mayThrow()) return; - } + F->setDoesNotThrow(); } diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index b7d6bbd93d2..c4633501eb7 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -665,6 +665,7 @@ public: llvm::BasicBlock *getEHResumeBlock(bool isCleanup); llvm::BasicBlock *getEHDispatchBlock(EHScopeStack::stable_iterator scope); + llvm::BasicBlock *getMSVCDispatchBlock(EHScopeStack::stable_iterator scope); /// An object to manage conditionally-evaluated expressions. class ConditionalEvaluation { diff --git a/clang/lib/CodeGen/EHScopeStack.h b/clang/lib/CodeGen/EHScopeStack.h index dc7a6c60856..8cad5b61eaf 100644 --- a/clang/lib/CodeGen/EHScopeStack.h +++ b/clang/lib/CodeGen/EHScopeStack.h @@ -329,6 +329,10 @@ public: /// Pops a terminate handler off the stack. void popTerminate(); + void pushCatchEnd(llvm::BasicBlock *CatchEndBlockBB); + + void popCatchEnd(); + // Returns true iff the current scope is either empty or contains only // lifetime markers, i.e. no real cleanup code bool containsOnlyLifetimeMarkers(stable_iterator Old) const; diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index 613d29a63cd..3084446795e 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -855,8 +855,14 @@ namespace { struct CallEndCatchMSVC : EHScopeStack::Cleanup { CallEndCatchMSVC() {} void Emit(CodeGenFunction &CGF, Flags flags) override { - CGF.EmitNounwindRuntimeCall( - CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_endcatch)); + if (CGF.CGM.getCodeGenOpts().NewMSEH) { + llvm::BasicBlock *BB = CGF.createBasicBlock("catchret.dest"); + CGF.Builder.CreateCatchRet(BB); + CGF.EmitBlock(BB); + } else { + CGF.EmitNounwindRuntimeCall( + CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_endcatch)); + } } }; } @@ -866,24 +872,36 @@ void MicrosoftCXXABI::emitBeginCatch(CodeGenFunction &CGF, // In the MS ABI, the runtime handles the copy, and the catch handler is // responsible for destruction. VarDecl *CatchParam = S->getExceptionDecl(); - llvm::Value *Exn = CGF.getExceptionFromSlot(); - llvm::Function *BeginCatch = - CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_begincatch); - + llvm::Value *Exn = nullptr; + llvm::Function *BeginCatch = nullptr; + bool NewEH = CGF.CGM.getCodeGenOpts().NewMSEH; + if (!NewEH) { + Exn = CGF.getExceptionFromSlot(); + BeginCatch = CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_begincatch); + } // If this is a catch-all or the catch parameter is unnamed, we don't need to // emit an alloca to the object. if (!CatchParam || !CatchParam->getDeclName()) { - llvm::Value *Args[2] = {Exn, llvm::Constant::getNullValue(CGF.Int8PtrTy)}; - CGF.EmitNounwindRuntimeCall(BeginCatch, Args); + if (!NewEH) { + llvm::Value *Args[2] = {Exn, llvm::Constant::getNullValue(CGF.Int8PtrTy)}; + CGF.EmitNounwindRuntimeCall(BeginCatch, Args); + } CGF.EHStack.pushCleanup<CallEndCatchMSVC>(NormalCleanup); return; } CodeGenFunction::AutoVarEmission var = CGF.EmitAutoVarAlloca(*CatchParam); - llvm::Value *ParamAddr = - CGF.Builder.CreateBitCast(var.getObjectAddress(CGF), CGF.Int8PtrTy); - llvm::Value *Args[2] = {Exn, ParamAddr}; - CGF.EmitNounwindRuntimeCall(BeginCatch, Args); + if (!NewEH) { + llvm::Value *ParamAddr = + CGF.Builder.CreateBitCast(var.getObjectAddress(CGF), CGF.Int8PtrTy); + llvm::Value *Args[2] = {Exn, ParamAddr}; + CGF.EmitNounwindRuntimeCall(BeginCatch, Args); + } else { + llvm::BasicBlock *CatchPadBB = + CGF.Builder.GetInsertBlock()->getSinglePredecessor(); + auto *CPI = cast<llvm::CatchPadInst>(CatchPadBB->getFirstNonPHI()); + CPI->setArgOperand(1, var.getObjectAddress(CGF)); + } CGF.EHStack.pushCleanup<CallEndCatchMSVC>(NormalCleanup); CGF.EmitAutoVarCleanups(var); } diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index b496c7c01a9..9307711c82f 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -456,6 +456,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.DumpCoverageMapping = Args.hasArg(OPT_dump_coverage_mapping); Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose); Opts.ObjCAutoRefCountExceptions = Args.hasArg(OPT_fobjc_arc_exceptions); + Opts.NewMSEH = Args.hasArg(OPT_fnew_ms_eh); Opts.CXAAtExit = !Args.hasArg(OPT_fno_use_cxa_atexit); Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases); Opts.CodeModel = getCodeModel(Args, Diags); |