X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FCodeGen%2FWinEHPrepare.cpp;h=ca69d321f3b3d3fb89a0ae97e6c1ca5f5354c0eb;hb=813b365fd0cc3b916f02fc58f343dc404674a12d;hp=1325821d498e71dc96158c74aa5faf64af124c82;hpb=7d3dd38582fb7a2d4133edc9a06f8581e5d8988f;p=oota-llvm.git diff --git a/lib/CodeGen/WinEHPrepare.cpp b/lib/CodeGen/WinEHPrepare.cpp index 1325821d498..ca69d321f3b 100644 --- a/lib/CodeGen/WinEHPrepare.cpp +++ b/lib/CodeGen/WinEHPrepare.cpp @@ -8,70 +8,47 @@ //===----------------------------------------------------------------------===// // // This pass lowers LLVM IR exception handling into something closer to what the -// backend wants. It snifs the personality function to see which kind of -// preparation is necessary. If the personality function uses the Itanium LSDA, -// this pass delegates to the DWARF EH preparation pass. +// backend wants for functions using a personality function from a runtime +// provided by MSVC. Functions with other personality functions are left alone +// and may be prepared by other passes. In particular, all supported MSVC +// personality functions require cleanup code to be outlined, and the C++ +// personality requires catch handler code to be outlined. // //===----------------------------------------------------------------------===// #include "llvm/CodeGen/Passes.h" -#include "llvm/ADT/MapVector.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallSet.h" -#include "llvm/ADT/SetVector.h" -#include "llvm/ADT/TinyPtrVector.h" +#include "llvm/Analysis/CFG.h" #include "llvm/Analysis/LibCallSemantics.h" #include "llvm/CodeGen/WinEHFuncInfo.h" -#include "llvm/IR/Dominators.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/IntrinsicInst.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/PatternMatch.h" #include "llvm/Pass.h" -#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/Cloning.h" #include "llvm/Transforms/Utils/Local.h" -#include "llvm/Transforms/Utils/PromoteMemToReg.h" -#include +#include "llvm/Transforms/Utils/SSAUpdater.h" using namespace llvm; -using namespace llvm::PatternMatch; #define DEBUG_TYPE "winehprepare" -namespace { - -// This map is used to model frame variable usage during outlining, to -// construct a structure type to hold the frame variables in a frame -// allocation block, and to remap the frame variable allocas (including -// spill locations as needed) to GEPs that get the variable from the -// frame allocation structure. -typedef MapVector> FrameVarInfoMap; - -// TinyPtrVector cannot hold nullptr, so we need our own sentinel that isn't -// quite null. -AllocaInst *getCatchObjectSentinel() { - return static_cast(nullptr) + 1; -} +static cl::opt DisableDemotion( + "disable-demotion", cl::Hidden, + cl::desc( + "Clone multicolor basic blocks but do not demote cross funclet values"), + cl::init(false)); -typedef SmallSet VisitedBlockSet; +static cl::opt DisableCleanups( + "disable-cleanups", cl::Hidden, + cl::desc("Do not remove implausible terminators or other similar cleanups"), + cl::init(false)); -class LandingPadActions; -class LandingPadMap; - -typedef DenseMap CatchHandlerMapTy; -typedef DenseMap CleanupHandlerMapTy; +namespace { class WinEHPrepare : public FunctionPass { public: static char ID; // Pass identification, replacement for typeid. - WinEHPrepare(const TargetMachine *TM = nullptr) - : FunctionPass(ID), DT(nullptr), SEHExceptionCodeSlot(nullptr) {} + WinEHPrepare(const TargetMachine *TM = nullptr) : FunctionPass(ID) {} bool runOnFunction(Function &Fn) override; @@ -84,235 +61,34 @@ public: } private: - bool prepareExceptionHandlers(Function &F, - SmallVectorImpl &LPads); - void promoteLandingPadValues(LandingPadInst *LPad); - void demoteValuesLiveAcrossHandlers(Function &F, - SmallVectorImpl &LPads); - void completeNestedLandingPad(Function *ParentFn, - LandingPadInst *OutlinedLPad, - const LandingPadInst *OriginalLPad, - FrameVarInfoMap &VarInfo); - bool outlineHandler(ActionHandler *Action, Function *SrcFn, - LandingPadInst *LPad, BasicBlock *StartBB, - FrameVarInfoMap &VarInfo); - void addStubInvokeToHandlerIfNeeded(Function *Handler, Value *PersonalityFn); - - void mapLandingPadBlocks(LandingPadInst *LPad, LandingPadActions &Actions); - CatchHandler *findCatchHandler(BasicBlock *BB, BasicBlock *&NextBB, - VisitedBlockSet &VisitedBlocks); - void findCleanupHandlers(LandingPadActions &Actions, BasicBlock *StartBB, - BasicBlock *EndBB); - - void processSEHCatchHandler(CatchHandler *Handler, BasicBlock *StartBB); + void insertPHIStores(PHINode *OriginalPHI, AllocaInst *SpillSlot); + void + insertPHIStore(BasicBlock *PredBlock, Value *PredVal, AllocaInst *SpillSlot, + SmallVectorImpl> &Worklist); + AllocaInst *insertPHILoads(PHINode *PN, Function &F); + void replaceUseWithLoad(Value *V, Use &U, AllocaInst *&SpillSlot, + DenseMap &Loads, Function &F); + void demoteNonlocalUses(Value *V, std::set &ColorsForBB, + Function &F); + bool prepareExplicitEH(Function &F, + SmallVectorImpl &EntryBlocks); + void replaceTerminatePadWithCleanup(Function &F); + void colorFunclets(Function &F, SmallVectorImpl &EntryBlocks); + void demotePHIsOnFunclets(Function &F); + void demoteUsesBetweenFunclets(Function &F); + void demoteArgumentUses(Function &F); + void cloneCommonBlocks(Function &F, + SmallVectorImpl &EntryBlocks); + void removeImplausibleTerminators(Function &F); + void cleanupPreparedFunclets(Function &F); + void verifyPreparedFunclets(Function &F); // All fields are reset by runOnFunction. - DominatorTree *DT; - EHPersonality Personality; - CatchHandlerMapTy CatchHandlerMap; - CleanupHandlerMapTy CleanupHandlerMap; - DenseMap LPadMaps; - - // This maps landing pad instructions found in outlined handlers to - // the landing pad instruction in the parent function from which they - // were cloned. The cloned/nested landing pad is used as the key - // because the landing pad may be cloned into multiple handlers. - // This map will be used to add the llvm.eh.actions call to the nested - // landing pads after all handlers have been outlined. - DenseMap NestedLPtoOriginalLP; - - // This maps blocks in the parent function which are destinations of - // catch handlers to cloned blocks in (other) outlined handlers. This - // handles the case where a nested landing pads has a catch handler that - // returns to a handler function rather than the parent function. - // The original block is used as the key here because there should only - // ever be one handler function from which the cloned block is not pruned. - // The original block will be pruned from the parent function after all - // handlers have been outlined. This map will be used to adjust the - // return instructions of handlers which return to the block that was - // outlined into a handler. This is done after all handlers have been - // outlined but before the outlined code is pruned from the parent function. - DenseMap LPadTargetBlocks; - - AllocaInst *SEHExceptionCodeSlot; -}; - -class WinEHFrameVariableMaterializer : public ValueMaterializer { -public: - WinEHFrameVariableMaterializer(Function *OutlinedFn, - FrameVarInfoMap &FrameVarInfo); - ~WinEHFrameVariableMaterializer() override {} - - Value *materializeValueFor(Value *V) override; - - void escapeCatchObject(Value *V); - -private: - FrameVarInfoMap &FrameVarInfo; - IRBuilder<> Builder; -}; - -class LandingPadMap { -public: - LandingPadMap() : OriginLPad(nullptr) {} - void mapLandingPad(const LandingPadInst *LPad); - - bool isInitialized() { return OriginLPad != nullptr; } - - bool isOriginLandingPadBlock(const BasicBlock *BB) const; - bool isLandingPadSpecificInst(const Instruction *Inst) const; - - void remapEHValues(ValueToValueMapTy &VMap, Value *EHPtrValue, - Value *SelectorValue) const; - -private: - const LandingPadInst *OriginLPad; - // We will normally only see one of each of these instructions, but - // if more than one occurs for some reason we can handle that. - TinyPtrVector ExtractedEHPtrs; - TinyPtrVector ExtractedSelectors; -}; - -class WinEHCloningDirectorBase : public CloningDirector { -public: - WinEHCloningDirectorBase(Function *HandlerFn, FrameVarInfoMap &VarInfo, - LandingPadMap &LPadMap) - : Materializer(HandlerFn, VarInfo), - SelectorIDType(Type::getInt32Ty(HandlerFn->getContext())), - Int8PtrType(Type::getInt8PtrTy(HandlerFn->getContext())), - LPadMap(LPadMap) { - auto AI = HandlerFn->getArgumentList().begin(); - ++AI; - EstablisherFrame = AI; - } - - CloningAction handleInstruction(ValueToValueMapTy &VMap, - const Instruction *Inst, - BasicBlock *NewBB) override; - - virtual CloningAction handleBeginCatch(ValueToValueMapTy &VMap, - const Instruction *Inst, - BasicBlock *NewBB) = 0; - virtual CloningAction handleEndCatch(ValueToValueMapTy &VMap, - const Instruction *Inst, - BasicBlock *NewBB) = 0; - virtual CloningAction handleTypeIdFor(ValueToValueMapTy &VMap, - const Instruction *Inst, - BasicBlock *NewBB) = 0; - virtual CloningAction handleInvoke(ValueToValueMapTy &VMap, - const InvokeInst *Invoke, - BasicBlock *NewBB) = 0; - virtual CloningAction handleResume(ValueToValueMapTy &VMap, - const ResumeInst *Resume, - BasicBlock *NewBB) = 0; - virtual CloningAction handleCompare(ValueToValueMapTy &VMap, - const CmpInst *Compare, - BasicBlock *NewBB) = 0; - virtual CloningAction handleLandingPad(ValueToValueMapTy &VMap, - const LandingPadInst *LPad, - BasicBlock *NewBB) = 0; - - ValueMaterializer *getValueMaterializer() override { return &Materializer; } - -protected: - WinEHFrameVariableMaterializer Materializer; - Type *SelectorIDType; - Type *Int8PtrType; - LandingPadMap &LPadMap; - - /// The value representing the parent frame pointer. - Value *EstablisherFrame; -}; - -class WinEHCatchDirector : public WinEHCloningDirectorBase { -public: - WinEHCatchDirector( - Function *CatchFn, Value *Selector, FrameVarInfoMap &VarInfo, - LandingPadMap &LPadMap, - DenseMap &NestedLPads) - : WinEHCloningDirectorBase(CatchFn, VarInfo, LPadMap), - CurrentSelector(Selector->stripPointerCasts()), - ExceptionObjectVar(nullptr), NestedLPtoOriginalLP(NestedLPads) {} - - CloningAction handleBeginCatch(ValueToValueMapTy &VMap, - const Instruction *Inst, - BasicBlock *NewBB) override; - CloningAction handleEndCatch(ValueToValueMapTy &VMap, const Instruction *Inst, - BasicBlock *NewBB) override; - CloningAction handleTypeIdFor(ValueToValueMapTy &VMap, - const Instruction *Inst, - BasicBlock *NewBB) override; - CloningAction handleInvoke(ValueToValueMapTy &VMap, const InvokeInst *Invoke, - BasicBlock *NewBB) override; - CloningAction handleResume(ValueToValueMapTy &VMap, const ResumeInst *Resume, - BasicBlock *NewBB) override; - CloningAction handleCompare(ValueToValueMapTy &VMap, - const CmpInst *Compare, BasicBlock *NewBB) override; - CloningAction handleLandingPad(ValueToValueMapTy &VMap, - const LandingPadInst *LPad, - BasicBlock *NewBB) override; - - Value *getExceptionVar() { return ExceptionObjectVar; } - TinyPtrVector &getReturnTargets() { return ReturnTargets; } - -private: - Value *CurrentSelector; - - Value *ExceptionObjectVar; - TinyPtrVector ReturnTargets; - - // This will be a reference to the field of the same name in the WinEHPrepare - // object which instantiates this WinEHCatchDirector object. - DenseMap &NestedLPtoOriginalLP; -}; - -class WinEHCleanupDirector : public WinEHCloningDirectorBase { -public: - WinEHCleanupDirector(Function *CleanupFn, FrameVarInfoMap &VarInfo, - LandingPadMap &LPadMap) - : WinEHCloningDirectorBase(CleanupFn, VarInfo, LPadMap) {} - - CloningAction handleBeginCatch(ValueToValueMapTy &VMap, - const Instruction *Inst, - BasicBlock *NewBB) override; - CloningAction handleEndCatch(ValueToValueMapTy &VMap, const Instruction *Inst, - BasicBlock *NewBB) override; - CloningAction handleTypeIdFor(ValueToValueMapTy &VMap, - const Instruction *Inst, - BasicBlock *NewBB) override; - CloningAction handleInvoke(ValueToValueMapTy &VMap, const InvokeInst *Invoke, - BasicBlock *NewBB) override; - CloningAction handleResume(ValueToValueMapTy &VMap, const ResumeInst *Resume, - BasicBlock *NewBB) override; - CloningAction handleCompare(ValueToValueMapTy &VMap, - const CmpInst *Compare, BasicBlock *NewBB) override; - CloningAction handleLandingPad(ValueToValueMapTy &VMap, - const LandingPadInst *LPad, - BasicBlock *NewBB) override; -}; - -class LandingPadActions { -public: - LandingPadActions() : HasCleanupHandlers(false) {} - - void insertCatchHandler(CatchHandler *Action) { Actions.push_back(Action); } - void insertCleanupHandler(CleanupHandler *Action) { - Actions.push_back(Action); - HasCleanupHandlers = true; - } - - bool includesCleanup() const { return HasCleanupHandlers; } - - SmallVectorImpl &actions() { return Actions; } - SmallVectorImpl::iterator begin() { return Actions.begin(); } - SmallVectorImpl::iterator end() { return Actions.end(); } + EHPersonality Personality = EHPersonality::Unknown; -private: - // Note that this class does not own the ActionHandler objects in this vector. - // The ActionHandlers are owned by the CatchHandlerMap and CleanupHandlerMap - // in the WinEHPrepare class. - SmallVector Actions; - bool HasCleanupHandlers; + std::map> BlockColors; + std::map> FuncletBlocks; + std::map> FuncletChildren; }; } // end anonymous namespace @@ -325,1810 +101,1144 @@ FunctionPass *llvm::createWinEHPass(const TargetMachine *TM) { return new WinEHPrepare(TM); } -bool WinEHPrepare::runOnFunction(Function &Fn) { - // No need to prepare outlined handlers. - if (Fn.hasFnAttribute("wineh-parent")) - return false; - - SmallVector LPads; - SmallVector Resumes; +static void findFuncletEntryPoints(Function &Fn, + SmallVectorImpl &EntryBlocks) { + EntryBlocks.push_back(&Fn.getEntryBlock()); for (BasicBlock &BB : Fn) { - if (auto *LP = BB.getLandingPadInst()) - LPads.push_back(LP); - if (auto *Resume = dyn_cast(BB.getTerminator())) - Resumes.push_back(Resume); + Instruction *First = BB.getFirstNonPHI(); + if (!First->isEHPad()) + continue; + assert(!isa(First) && + "landingpad cannot be used with funclet EH personality"); + // Find EH pad blocks that represent funclet start points. + if (!isa(First) && !isa(First)) + EntryBlocks.push_back(&BB); } +} - // No need to prepare functions that lack landing pads. - if (LPads.empty()) +bool WinEHPrepare::runOnFunction(Function &Fn) { + if (!Fn.hasPersonalityFn()) return false; // Classify the personality to see what kind of preparation we need. - Personality = classifyEHPersonality(LPads.back()->getPersonalityFn()); + Personality = classifyEHPersonality(Fn.getPersonalityFn()); - // Do nothing if this is not an MSVC personality. - if (!isMSVCEHPersonality(Personality)) + // Do nothing if this is not a funclet-based personality. + if (!isFuncletEHPersonality(Personality)) return false; - DT = &getAnalysis().getDomTree(); + // Remove unreachable blocks. It is not valuable to assign them a color and + // their existence can trick us into thinking values are alive when they are + // not. + removeUnreachableBlocks(Fn); - // If there were any landing pads, prepareExceptionHandlers will make changes. - prepareExceptionHandlers(Fn, LPads); - return true; + SmallVector EntryBlocks; + findFuncletEntryPoints(Fn, EntryBlocks); + return prepareExplicitEH(Fn, EntryBlocks); } bool WinEHPrepare::doFinalization(Module &M) { return false; } -void WinEHPrepare::getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequired(); -} +void WinEHPrepare::getAnalysisUsage(AnalysisUsage &AU) const {} -static bool isSelectorDispatch(BasicBlock *BB, BasicBlock *&CatchHandler, - Constant *&Selector, BasicBlock *&NextBB); - -// Finds blocks reachable from the starting set Worklist. Does not follow unwind -// edges or blocks listed in StopPoints. -static void findReachableBlocks(SmallPtrSetImpl &ReachableBBs, - SetVector &Worklist, - const SetVector *StopPoints) { - while (!Worklist.empty()) { - BasicBlock *BB = Worklist.pop_back_val(); - - // Don't cross blocks that we should stop at. - if (StopPoints && StopPoints->count(BB)) - continue; - - if (!ReachableBBs.insert(BB).second) - continue; // Already visited. - - // Don't follow unwind edges of invokes. - if (auto *II = dyn_cast(BB->getTerminator())) { - Worklist.insert(II->getNormalDest()); - continue; - } - - // Otherwise, follow all successors. - Worklist.insert(succ_begin(BB), succ_end(BB)); - } +static int addUnwindMapEntry(WinEHFuncInfo &FuncInfo, int ToState, + const BasicBlock *BB) { + CxxUnwindMapEntry UME; + UME.ToState = ToState; + UME.Cleanup = BB; + FuncInfo.CxxUnwindMap.push_back(UME); + return FuncInfo.getLastStateNumber(); } -/// Find all points where exceptional control rejoins normal control flow via -/// llvm.eh.endcatch. Add them to the normal bb reachability worklist. -static void findCXXEHReturnPoints(Function &F, - SetVector &EHReturnBlocks) { - for (auto BBI = F.begin(), BBE = F.end(); BBI != BBE; ++BBI) { - BasicBlock *BB = BBI; - for (Instruction &I : *BB) { - if (match(&I, m_Intrinsic())) { - // Split the block after the call to llvm.eh.endcatch if there is - // anything other than an unconditional branch, or if the successor - // starts with a phi. - auto *Br = dyn_cast(I.getNextNode()); - if (!Br || !Br->isUnconditional() || - isa(Br->getSuccessor(0)->begin())) { - DEBUG(dbgs() << "splitting block " << BB->getName() - << " with llvm.eh.endcatch\n"); - BBI = BB->splitBasicBlock(I.getNextNode(), "ehreturn"); - } - // The next BB is normal control flow. - EHReturnBlocks.insert(BB->getTerminator()->getSuccessor(0)); - break; - } - } +static void addTryBlockMapEntry(WinEHFuncInfo &FuncInfo, int TryLow, + int TryHigh, int CatchHigh, + ArrayRef Handlers) { + WinEHTryBlockMapEntry TBME; + TBME.TryLow = TryLow; + TBME.TryHigh = TryHigh; + TBME.CatchHigh = CatchHigh; + assert(TBME.TryLow <= TBME.TryHigh); + for (const CatchPadInst *CPI : Handlers) { + WinEHHandlerType HT; + Constant *TypeInfo = cast(CPI->getArgOperand(0)); + if (TypeInfo->isNullValue()) + HT.TypeDescriptor = nullptr; + else + HT.TypeDescriptor = cast(TypeInfo->stripPointerCasts()); + HT.Adjectives = cast(CPI->getArgOperand(1))->getZExtValue(); + HT.Handler = CPI->getParent(); + if (isa(CPI->getArgOperand(2))) + HT.CatchObj.Alloca = nullptr; + else + HT.CatchObj.Alloca = cast(CPI->getArgOperand(2)); + TBME.HandlerArray.push_back(HT); } + FuncInfo.TryBlockMap.push_back(TBME); } -static bool isCatchAllLandingPad(const BasicBlock *BB) { - const LandingPadInst *LP = BB->getLandingPadInst(); - if (!LP) - return false; - unsigned N = LP->getNumClauses(); - return (N > 0 && LP->isCatch(N - 1) && - isa(LP->getClause(N - 1))); +static const CatchPadInst *getSingleCatchPadPredecessor(const BasicBlock *BB) { + for (const BasicBlock *PredBlock : predecessors(BB)) + if (auto *CPI = dyn_cast(PredBlock->getFirstNonPHI())) + return CPI; + return nullptr; } -/// Find all points where exceptions control rejoins normal control flow via -/// selector dispatch. -static void findSEHEHReturnPoints(Function &F, - SetVector &EHReturnBlocks) { - for (auto BBI = F.begin(), BBE = F.end(); BBI != BBE; ++BBI) { - BasicBlock *BB = BBI; - // If the landingpad is a catch-all, treat the whole lpad as if it is - // reachable from normal control flow. - // FIXME: This is imprecise. We need a better way of identifying where a - // catch-all starts and cleanups stop. As far as LLVM is concerned, there - // is no difference. - if (isCatchAllLandingPad(BB)) { - EHReturnBlocks.insert(BB); - continue; - } - - BasicBlock *CatchHandler; - BasicBlock *NextBB; - Constant *Selector; - if (isSelectorDispatch(BB, CatchHandler, Selector, NextBB)) { - // Split the edge if there is a phi node. Returning from EH to a phi node - // is just as impossible as having a phi after an indirectbr. - if (isa(CatchHandler->begin())) { - DEBUG(dbgs() << "splitting EH return edge from " << BB->getName() - << " to " << CatchHandler->getName() << '\n'); - BBI = CatchHandler = SplitCriticalEdge( - BB, std::find(succ_begin(BB), succ_end(BB), CatchHandler)); - } - EHReturnBlocks.insert(CatchHandler); - } +/// Find all the catchpads that feed directly into the catchendpad. Frontends +/// using this personality should ensure that each catchendpad and catchpad has +/// one or zero catchpad predecessors. +/// +/// The following C++ generates the IR after it: +/// try { +/// } catch (A) { +/// } catch (B) { +/// } +/// +/// IR: +/// %catchpad.A +/// catchpad [i8* A typeinfo] +/// to label %catch.A unwind label %catchpad.B +/// %catchpad.B +/// catchpad [i8* B typeinfo] +/// to label %catch.B unwind label %endcatches +/// %endcatches +/// catchendblock unwind to caller +static void +findCatchPadsForCatchEndPad(const BasicBlock *CatchEndBB, + SmallVectorImpl &Handlers) { + const CatchPadInst *CPI = getSingleCatchPadPredecessor(CatchEndBB); + while (CPI) { + Handlers.push_back(CPI); + CPI = getSingleCatchPadPredecessor(CPI->getParent()); } + // We've pushed these back into reverse source order. Reverse them to get + // the list back into source order. + std::reverse(Handlers.begin(), Handlers.end()); } -/// Ensure that all values live into and out of exception handlers are stored -/// in memory. -/// FIXME: This falls down when values are defined in one handler and live into -/// another handler. For example, a cleanup defines a value used only by a -/// catch handler. -void WinEHPrepare::demoteValuesLiveAcrossHandlers( - Function &F, SmallVectorImpl &LPads) { - DEBUG(dbgs() << "Demoting values live across exception handlers in function " - << F.getName() << '\n'); - - // Build a set of all non-exceptional blocks and exceptional blocks. - // - Non-exceptional blocks are blocks reachable from the entry block while - // not following invoke unwind edges. - // - Exceptional blocks are blocks reachable from landingpads. Analysis does - // not follow llvm.eh.endcatch blocks, which mark a transition from - // exceptional to normal control. - SmallPtrSet NormalBlocks; - SmallPtrSet EHBlocks; - SetVector EHReturnBlocks; - SetVector Worklist; - - if (Personality == EHPersonality::MSVC_CXX) - findCXXEHReturnPoints(F, EHReturnBlocks); - else - findSEHEHReturnPoints(F, EHReturnBlocks); - - DEBUG({ - dbgs() << "identified the following blocks as EH return points:\n"; - for (BasicBlock *BB : EHReturnBlocks) - dbgs() << " " << BB->getName() << '\n'; - }); - - // Join points should not have phis at this point, unless they are a - // landingpad, in which case we will demote their phis later. -#ifndef NDEBUG - for (BasicBlock *BB : EHReturnBlocks) - assert((BB->isLandingPad() || !isa(BB->begin())) && - "non-lpad EH return block has phi"); -#endif - - // Normal blocks are the blocks reachable from the entry block and all EH - // return points. - Worklist = EHReturnBlocks; - Worklist.insert(&F.getEntryBlock()); - findReachableBlocks(NormalBlocks, Worklist, nullptr); - DEBUG({ - dbgs() << "marked the following blocks as normal:\n"; - for (BasicBlock *BB : NormalBlocks) - dbgs() << " " << BB->getName() << '\n'; - }); - - // Exceptional blocks are the blocks reachable from landingpads that don't - // cross EH return points. - Worklist.clear(); - for (auto *LPI : LPads) - Worklist.insert(LPI->getParent()); - findReachableBlocks(EHBlocks, Worklist, &EHReturnBlocks); - DEBUG({ - dbgs() << "marked the following blocks as exceptional:\n"; - for (BasicBlock *BB : EHBlocks) - dbgs() << " " << BB->getName() << '\n'; - }); - - SetVector ArgsToDemote; - SetVector InstrsToDemote; - for (BasicBlock &BB : F) { - bool IsNormalBB = NormalBlocks.count(&BB); - bool IsEHBB = EHBlocks.count(&BB); - if (!IsNormalBB && !IsEHBB) - continue; // Blocks that are neither normal nor EH are unreachable. - for (Instruction &I : BB) { - for (Value *Op : I.operands()) { - // Don't demote static allocas, constants, and labels. - if (isa(Op) || isa(Op) || isa(Op)) - continue; - auto *AI = dyn_cast(Op); - if (AI && AI->isStaticAlloca()) - continue; - - if (auto *Arg = dyn_cast(Op)) { - if (IsEHBB) { - DEBUG(dbgs() << "Demoting argument " << *Arg - << " used by EH instr: " << I << "\n"); - ArgsToDemote.insert(Arg); - } - continue; - } +// 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) { + const TerminatorInst *TI = BB->getTerminator(); + if (isa(TI)) + return nullptr; + if (TI->isEHPad()) + return BB; + return cast(TI)->getCleanupPad()->getParent(); +} - auto *OpI = cast(Op); - BasicBlock *OpBB = OpI->getParent(); - // If a value is produced and consumed in the same BB, we don't need to - // demote it. - if (OpBB == &BB) - continue; - bool IsOpNormalBB = NormalBlocks.count(OpBB); - bool IsOpEHBB = EHBlocks.count(OpBB); - if (IsNormalBB != IsOpNormalBB || IsEHBB != IsOpEHBB) { - DEBUG({ - dbgs() << "Demoting instruction live in-out from EH:\n"; - dbgs() << "Instr: " << *OpI << '\n'; - dbgs() << "User: " << I << '\n'; - }); - InstrsToDemote.insert(OpI); - } - } - } - } +static void calculateExplicitCXXStateNumbers(WinEHFuncInfo &FuncInfo, + const BasicBlock &BB, + int ParentState) { + assert(BB.isEHPad()); + const Instruction *FirstNonPHI = BB.getFirstNonPHI(); + // All catchpad instructions will be handled when we process their + // respective catchendpad instruction. + if (isa(FirstNonPHI)) + return; - // Demote values live into and out of handlers. - // FIXME: This demotion is inefficient. We should insert spills at the point - // of definition, insert one reload in each handler that uses the value, and - // insert reloads in the BB used to rejoin normal control flow. - Instruction *AllocaInsertPt = F.getEntryBlock().getFirstInsertionPt(); - for (Instruction *I : InstrsToDemote) - DemoteRegToStack(*I, false, AllocaInsertPt); - - // Demote arguments separately, and only for uses in EH blocks. - for (Argument *Arg : ArgsToDemote) { - auto *Slot = new AllocaInst(Arg->getType(), nullptr, - Arg->getName() + ".reg2mem", AllocaInsertPt); - SmallVector Users(Arg->user_begin(), Arg->user_end()); - for (User *U : Users) { - auto *I = dyn_cast(U); - if (I && EHBlocks.count(I->getParent())) { - auto *Reload = new LoadInst(Slot, Arg->getName() + ".reload", false, I); - U->replaceUsesOfWith(Arg, Reload); - } - } - new StoreInst(Arg, Slot, AllocaInsertPt); + if (isa(FirstNonPHI)) { + SmallVector Handlers; + findCatchPadsForCatchEndPad(&BB, Handlers); + const BasicBlock *FirstTryPad = Handlers.front()->getParent(); + int TryLow = addUnwindMapEntry(FuncInfo, ParentState, nullptr); + FuncInfo.EHPadStateMap[Handlers.front()] = TryLow; + for (const BasicBlock *PredBlock : predecessors(FirstTryPad)) + if ((PredBlock = getEHPadFromPredecessor(PredBlock))) + calculateExplicitCXXStateNumbers(FuncInfo, *PredBlock, TryLow); + int CatchLow = addUnwindMapEntry(FuncInfo, ParentState, nullptr); + + // catchpads are separate funclets in C++ EH due to the way rethrow works. + // In SEH, they aren't, so no invokes will unwind to the catchendpad. + FuncInfo.EHPadStateMap[FirstNonPHI] = CatchLow; + int TryHigh = CatchLow - 1; + for (const BasicBlock *PredBlock : predecessors(&BB)) + if ((PredBlock = getEHPadFromPredecessor(PredBlock))) + calculateExplicitCXXStateNumbers(FuncInfo, *PredBlock, CatchLow); + int CatchHigh = FuncInfo.getLastStateNumber(); + addTryBlockMapEntry(FuncInfo, TryLow, TryHigh, CatchHigh, Handlers); + DEBUG(dbgs() << "TryLow[" << FirstTryPad->getName() << "]: " << TryLow + << '\n'); + DEBUG(dbgs() << "TryHigh[" << FirstTryPad->getName() << "]: " << TryHigh + << '\n'); + DEBUG(dbgs() << "CatchHigh[" << FirstTryPad->getName() << "]: " << CatchHigh + << '\n'); + } else if (isa(FirstNonPHI)) { + // A cleanup can have multiple exits; don't re-process after the first. + if (FuncInfo.EHPadStateMap.count(FirstNonPHI)) + return; + int CleanupState = addUnwindMapEntry(FuncInfo, ParentState, &BB); + FuncInfo.EHPadStateMap[FirstNonPHI] = CleanupState; + DEBUG(dbgs() << "Assigning state #" << CleanupState << " to BB " + << BB.getName() << '\n'); + for (const BasicBlock *PredBlock : predecessors(&BB)) + if ((PredBlock = getEHPadFromPredecessor(PredBlock))) + calculateExplicitCXXStateNumbers(FuncInfo, *PredBlock, CleanupState); + } else if (auto *CEPI = dyn_cast(FirstNonPHI)) { + // Propagate ParentState to the cleanuppad in case it doesn't have + // any cleanuprets. + BasicBlock *CleanupBlock = CEPI->getCleanupPad()->getParent(); + calculateExplicitCXXStateNumbers(FuncInfo, *CleanupBlock, ParentState); + // Anything unwinding through CleanupEndPadInst is in ParentState. + FuncInfo.EHPadStateMap[FirstNonPHI] = ParentState; + for (const BasicBlock *PredBlock : predecessors(&BB)) + if ((PredBlock = getEHPadFromPredecessor(PredBlock))) + calculateExplicitCXXStateNumbers(FuncInfo, *PredBlock, ParentState); + } else if (isa(FirstNonPHI)) { + report_fatal_error("Not yet implemented!"); + } else { + llvm_unreachable("unexpected EH Pad!"); } +} - // Demote landingpad phis, as the landingpad will be removed from the machine - // CFG. - for (LandingPadInst *LPI : LPads) { - BasicBlock *BB = LPI->getParent(); - while (auto *Phi = dyn_cast(BB->begin())) - DemotePHIToStack(Phi, AllocaInsertPt); - } +static int addSEHExcept(WinEHFuncInfo &FuncInfo, int ParentState, + const Function *Filter, const BasicBlock *Handler) { + SEHUnwindMapEntry Entry; + Entry.ToState = ParentState; + Entry.IsFinally = false; + Entry.Filter = Filter; + Entry.Handler = Handler; + FuncInfo.SEHUnwindMap.push_back(Entry); + return FuncInfo.SEHUnwindMap.size() - 1; +} - DEBUG(dbgs() << "Demoted " << InstrsToDemote.size() << " instructions and " - << ArgsToDemote.size() << " arguments for WinEHPrepare\n\n"); +static int addSEHFinally(WinEHFuncInfo &FuncInfo, int ParentState, + const BasicBlock *Handler) { + SEHUnwindMapEntry Entry; + Entry.ToState = ParentState; + Entry.IsFinally = true; + Entry.Filter = nullptr; + Entry.Handler = Handler; + FuncInfo.SEHUnwindMap.push_back(Entry); + return FuncInfo.SEHUnwindMap.size() - 1; } -bool WinEHPrepare::prepareExceptionHandlers( - Function &F, SmallVectorImpl &LPads) { - // Don't run on functions that are already prepared. - for (LandingPadInst *LPad : LPads) { - BasicBlock *LPadBB = LPad->getParent(); - for (Instruction &Inst : *LPadBB) - if (match(&Inst, m_Intrinsic())) - return false; - } +static void calculateExplicitSEHStateNumbers(WinEHFuncInfo &FuncInfo, + const BasicBlock &BB, + int ParentState) { + assert(BB.isEHPad()); + const Instruction *FirstNonPHI = BB.getFirstNonPHI(); + // All catchpad instructions will be handled when we process their + // respective catchendpad instruction. + if (isa(FirstNonPHI)) + return; - demoteValuesLiveAcrossHandlers(F, LPads); + if (isa(FirstNonPHI)) { + // Extract the filter function and the __except basic block and create a + // state for them. + SmallVector Handlers; + findCatchPadsForCatchEndPad(&BB, Handlers); + assert(Handlers.size() == 1 && + "SEH doesn't have multiple handlers per __try"); + const CatchPadInst *CPI = Handlers.front(); + const BasicBlock *CatchPadBB = CPI->getParent(); + const Constant *FilterOrNull = + cast(CPI->getArgOperand(0)->stripPointerCasts()); + const Function *Filter = dyn_cast(FilterOrNull); + assert((Filter || FilterOrNull->isNullValue()) && + "unexpected filter value"); + int TryState = addSEHExcept(FuncInfo, ParentState, Filter, CatchPadBB); + + // Everything in the __try block uses TryState as its parent state. + FuncInfo.EHPadStateMap[CPI] = TryState; + DEBUG(dbgs() << "Assigning state #" << TryState << " to BB " + << CatchPadBB->getName() << '\n'); + for (const BasicBlock *PredBlock : predecessors(CatchPadBB)) + if ((PredBlock = getEHPadFromPredecessor(PredBlock))) + calculateExplicitSEHStateNumbers(FuncInfo, *PredBlock, TryState); + + // Everything in the __except block unwinds to ParentState, just like code + // outside the __try. + FuncInfo.EHPadStateMap[FirstNonPHI] = ParentState; + DEBUG(dbgs() << "Assigning state #" << ParentState << " to BB " + << BB.getName() << '\n'); + for (const BasicBlock *PredBlock : predecessors(&BB)) + if ((PredBlock = getEHPadFromPredecessor(PredBlock))) + calculateExplicitSEHStateNumbers(FuncInfo, *PredBlock, ParentState); + } else if (isa(FirstNonPHI)) { + // A cleanup can have multiple exits; don't re-process after the first. + if (FuncInfo.EHPadStateMap.count(FirstNonPHI)) + return; + int CleanupState = addSEHFinally(FuncInfo, ParentState, &BB); + FuncInfo.EHPadStateMap[FirstNonPHI] = CleanupState; + DEBUG(dbgs() << "Assigning state #" << CleanupState << " to BB " + << BB.getName() << '\n'); + for (const BasicBlock *PredBlock : predecessors(&BB)) + if ((PredBlock = getEHPadFromPredecessor(PredBlock))) + calculateExplicitSEHStateNumbers(FuncInfo, *PredBlock, CleanupState); + } else if (auto *CEPI = dyn_cast(FirstNonPHI)) { + // Propagate ParentState to the cleanuppad in case it doesn't have + // any cleanuprets. + BasicBlock *CleanupBlock = CEPI->getCleanupPad()->getParent(); + calculateExplicitSEHStateNumbers(FuncInfo, *CleanupBlock, ParentState); + // Anything unwinding through CleanupEndPadInst is in ParentState. + FuncInfo.EHPadStateMap[FirstNonPHI] = ParentState; + DEBUG(dbgs() << "Assigning state #" << ParentState << " to BB " + << BB.getName() << '\n'); + for (const BasicBlock *PredBlock : predecessors(&BB)) + if ((PredBlock = getEHPadFromPredecessor(PredBlock))) + calculateExplicitSEHStateNumbers(FuncInfo, *PredBlock, ParentState); + } else if (isa(FirstNonPHI)) { + report_fatal_error("Not yet implemented!"); + } else { + llvm_unreachable("unexpected EH Pad!"); + } +} - // These containers are used to re-map frame variables that are used in - // outlined catch and cleanup handlers. They will be populated as the - // handlers are outlined. - FrameVarInfoMap FrameVarInfo; +/// Check if the EH Pad unwinds to caller. Cleanups are a little bit of a +/// special case because we have to look at the cleanupret instruction that uses +/// the cleanuppad. +static bool doesEHPadUnwindToCaller(const Instruction *EHPad) { + auto *CPI = dyn_cast(EHPad); + if (!CPI) + return EHPad->mayThrow(); - bool HandlersOutlined = false; + // This cleanup does not return or unwind, so we say it unwinds to caller. + if (CPI->use_empty()) + return true; - Module *M = F.getParent(); - LLVMContext &Context = M->getContext(); + const Instruction *User = CPI->user_back(); + if (auto *CRI = dyn_cast(User)) + return CRI->unwindsToCaller(); + return cast(User)->unwindsToCaller(); +} - // Create a new function to receive the handler contents. - PointerType *Int8PtrType = Type::getInt8PtrTy(Context); - Type *Int32Type = Type::getInt32Ty(Context); - Function *ActionIntrin = Intrinsic::getDeclaration(M, Intrinsic::eh_actions); +void llvm::calculateSEHStateNumbers(const Function *Fn, + WinEHFuncInfo &FuncInfo) { + // Don't compute state numbers twice. + if (!FuncInfo.SEHUnwindMap.empty()) + return; - if (isAsynchronousEHPersonality(Personality)) { - // FIXME: Switch the ehptr type to i32 and then switch this. - SEHExceptionCodeSlot = - new AllocaInst(Int8PtrType, nullptr, "seh_exception_code", - F.getEntryBlock().getFirstInsertionPt()); + for (const BasicBlock &BB : *Fn) { + if (!BB.isEHPad() || !doesEHPadUnwindToCaller(BB.getFirstNonPHI())) + continue; + calculateExplicitSEHStateNumbers(FuncInfo, BB, -1); } +} - for (LandingPadInst *LPad : LPads) { - // Look for evidence that this landingpad has already been processed. - bool LPadHasActionList = false; - BasicBlock *LPadBB = LPad->getParent(); - for (Instruction &Inst : *LPadBB) { - if (match(&Inst, m_Intrinsic())) { - LPadHasActionList = true; - break; - } - } +void llvm::calculateWinCXXEHStateNumbers(const Function *Fn, + WinEHFuncInfo &FuncInfo) { + // Return if it's already been done. + if (!FuncInfo.EHPadStateMap.empty()) + return; - // If we've already outlined the handlers for this landingpad, - // there's nothing more to do here. - if (LPadHasActionList) + for (const BasicBlock &BB : *Fn) { + if (!BB.isEHPad()) + continue; + if (BB.isLandingPad()) + report_fatal_error("MSVC C++ EH cannot use landingpads"); + const Instruction *FirstNonPHI = BB.getFirstNonPHI(); + if (!doesEHPadUnwindToCaller(FirstNonPHI)) continue; + calculateExplicitCXXStateNumbers(FuncInfo, BB, -1); + } +} - // If either of the values in the aggregate returned by the landing pad is - // extracted and stored to memory, promote the stored value to a register. - promoteLandingPadValues(LPad); +static int addClrEHHandler(WinEHFuncInfo &FuncInfo, int ParentState, + ClrHandlerType HandlerType, uint32_t TypeToken, + const BasicBlock *Handler) { + ClrEHUnwindMapEntry Entry; + Entry.Parent = ParentState; + Entry.Handler = Handler; + Entry.HandlerType = HandlerType; + Entry.TypeToken = TypeToken; + FuncInfo.ClrEHUnwindMap.push_back(Entry); + return FuncInfo.ClrEHUnwindMap.size() - 1; +} - LandingPadActions Actions; - mapLandingPadBlocks(LPad, Actions); +void llvm::calculateClrEHStateNumbers(const Function *Fn, + WinEHFuncInfo &FuncInfo) { + // Return if it's already been done. + if (!FuncInfo.EHPadStateMap.empty()) + return; - HandlersOutlined |= !Actions.actions().empty(); - for (ActionHandler *Action : Actions) { - if (Action->hasBeenProcessed()) - continue; - BasicBlock *StartBB = Action->getStartBlock(); - - // SEH doesn't do any outlining for catches. Instead, pass the handler - // basic block addr to llvm.eh.actions and list the block as a return - // target. - if (isAsynchronousEHPersonality(Personality)) { - if (auto *CatchAction = dyn_cast(Action)) { - processSEHCatchHandler(CatchAction, StartBB); - continue; - } - } + SmallVector, 8> Worklist; - outlineHandler(Action, &F, LPad, StartBB, FrameVarInfo); - } + // Each pad needs to be able to refer to its parent, so scan the function + // looking for top-level handlers and seed the worklist with them. + for (const BasicBlock &BB : *Fn) { + if (!BB.isEHPad()) + continue; + if (BB.isLandingPad()) + report_fatal_error("CoreCLR EH cannot use landingpads"); + const Instruction *FirstNonPHI = BB.getFirstNonPHI(); + if (!doesEHPadUnwindToCaller(FirstNonPHI)) + continue; + // queue this with sentinel parent state -1 to mean unwind to caller. + Worklist.emplace_back(FirstNonPHI, -1); + } - // Split the block after the landingpad instruction so that it is just a - // call to llvm.eh.actions followed by indirectbr. - assert(!isa(LPadBB->begin()) && "lpad phi not removed"); - LPadBB->splitBasicBlock(LPad->getNextNode(), - LPadBB->getName() + ".prepsplit"); - // Erase the branch inserted by the split so we can insert indirectbr. - LPadBB->getTerminator()->eraseFromParent(); - - // Replace all extracted values with undef and ultimately replace the - // landingpad with undef. - SmallVector SEHCodeUses; - SmallVector EHUndefs; - for (User *U : LPad->users()) { - auto *E = dyn_cast(U); - if (!E) + while (!Worklist.empty()) { + const Instruction *Pad; + int ParentState; + std::tie(Pad, ParentState) = Worklist.pop_back_val(); + + int PredState; + if (const CleanupEndPadInst *EndPad = dyn_cast(Pad)) { + FuncInfo.EHPadStateMap[EndPad] = ParentState; + // Queue the cleanuppad, in case it doesn't have a cleanupret. + Worklist.emplace_back(EndPad->getCleanupPad(), ParentState); + // Preds of the endpad should get the parent state. + PredState = ParentState; + } else if (const CleanupPadInst *Cleanup = dyn_cast(Pad)) { + // A cleanup can have multiple exits; don't re-process after the first. + if (FuncInfo.EHPadStateMap.count(Pad)) continue; - assert(E->getNumIndices() == 1 && - "Unexpected operation: extracting both landing pad values"); - unsigned Idx = *E->idx_begin(); - assert((Idx == 0 || Idx == 1) && "unexpected index"); - if (Idx == 0 && isAsynchronousEHPersonality(Personality)) - SEHCodeUses.push_back(E); - else - EHUndefs.push_back(E); - } - for (Instruction *E : EHUndefs) { - E->replaceAllUsesWith(UndefValue::get(E->getType())); - E->eraseFromParent(); - } - LPad->replaceAllUsesWith(UndefValue::get(LPad->getType())); - - // Rewrite uses of the exception pointer to loads of an alloca. - for (Instruction *E : SEHCodeUses) { - SmallVector Uses; - for (Use &U : E->uses()) - Uses.push_back(&U); - for (Use *U : Uses) { - auto *I = cast(U->getUser()); - if (isa(I)) - continue; - LoadInst *LI; - if (auto *Phi = dyn_cast(I)) - LI = new LoadInst(SEHExceptionCodeSlot, "sehcode", false, - Phi->getIncomingBlock(*U)); - else - LI = new LoadInst(SEHExceptionCodeSlot, "sehcode", false, I); - U->set(LI); - } - E->replaceAllUsesWith(UndefValue::get(E->getType())); - E->eraseFromParent(); + // CoreCLR personality uses arity to distinguish faults from finallies. + const BasicBlock *PadBlock = Cleanup->getParent(); + ClrHandlerType HandlerType = + (Cleanup->getNumOperands() ? ClrHandlerType::Fault + : ClrHandlerType::Finally); + int NewState = + addClrEHHandler(FuncInfo, ParentState, HandlerType, 0, PadBlock); + FuncInfo.EHPadStateMap[Cleanup] = NewState; + // Propagate the new state to all preds of the cleanup + PredState = NewState; + } else if (const CatchEndPadInst *EndPad = dyn_cast(Pad)) { + FuncInfo.EHPadStateMap[EndPad] = ParentState; + // Preds of the endpad should get the parent state. + PredState = ParentState; + } else if (const CatchPadInst *Catch = dyn_cast(Pad)) { + const BasicBlock *PadBlock = Catch->getParent(); + uint32_t TypeToken = static_cast( + cast(Catch->getArgOperand(0))->getZExtValue()); + int NewState = addClrEHHandler(FuncInfo, ParentState, + ClrHandlerType::Catch, TypeToken, PadBlock); + FuncInfo.EHPadStateMap[Catch] = NewState; + // Preds of the catch get its state + PredState = NewState; + } else { + llvm_unreachable("Unexpected EH pad"); } - // Add a call to describe the actions for this landing pad. - std::vector ActionArgs; - for (ActionHandler *Action : Actions) { - // Action codes from docs are: 0 cleanup, 1 catch. - if (auto *CatchAction = dyn_cast(Action)) { - ActionArgs.push_back(ConstantInt::get(Int32Type, 1)); - ActionArgs.push_back(CatchAction->getSelector()); - // Find the frame escape index of the exception object alloca in the - // parent. - int FrameEscapeIdx = -1; - Value *EHObj = const_cast(CatchAction->getExceptionVar()); - if (EHObj && !isa(EHObj)) { - auto I = FrameVarInfo.find(EHObj); - assert(I != FrameVarInfo.end() && - "failed to map llvm.eh.begincatch var"); - FrameEscapeIdx = std::distance(FrameVarInfo.begin(), I); - } - ActionArgs.push_back(ConstantInt::get(Int32Type, FrameEscapeIdx)); - } else { - ActionArgs.push_back(ConstantInt::get(Int32Type, 0)); - } - ActionArgs.push_back(Action->getHandlerBlockOrFunc()); + // Queue all predecessors with the given state + for (const BasicBlock *Pred : predecessors(Pad->getParent())) { + if ((Pred = getEHPadFromPredecessor(Pred))) + Worklist.emplace_back(Pred->getFirstNonPHI(), PredState); } - CallInst *Recover = - CallInst::Create(ActionIntrin, ActionArgs, "recover", LPadBB); - - // Add an indirect branch listing possible successors of the catch handlers. - SetVector ReturnTargets; - for (ActionHandler *Action : Actions) { - if (auto *CatchAction = dyn_cast(Action)) { - const auto &CatchTargets = CatchAction->getReturnTargets(); - ReturnTargets.insert(CatchTargets.begin(), CatchTargets.end()); - } - } - IndirectBrInst *Branch = - IndirectBrInst::Create(Recover, ReturnTargets.size(), LPadBB); - for (BasicBlock *Target : ReturnTargets) - Branch->addDestination(Target); - } // End for each landingpad - - // If nothing got outlined, there is no more processing to be done. - if (!HandlersOutlined) - return false; + } +} - // Replace any nested landing pad stubs with the correct action handler. - // This must be done before we remove unreachable blocks because it - // cleans up references to outlined blocks that will be deleted. - for (auto &LPadPair : NestedLPtoOriginalLP) - completeNestedLandingPad(&F, LPadPair.first, LPadPair.second, FrameVarInfo); - NestedLPtoOriginalLP.clear(); +void WinEHPrepare::replaceTerminatePadWithCleanup(Function &F) { + if (Personality != EHPersonality::MSVC_CXX) + return; + for (BasicBlock &BB : F) { + Instruction *First = BB.getFirstNonPHI(); + auto *TPI = dyn_cast(First); + if (!TPI) + continue; - F.addFnAttr("wineh-parent", F.getName()); + if (TPI->getNumArgOperands() != 1) + report_fatal_error( + "Expected a unary terminatepad for MSVC C++ personalities!"); - // Delete any blocks that were only used by handlers that were outlined above. - removeUnreachableBlocks(F); + auto *TerminateFn = dyn_cast(TPI->getArgOperand(0)); + if (!TerminateFn) + report_fatal_error("Function operand expected in terminatepad for MSVC " + "C++ personalities!"); - BasicBlock *Entry = &F.getEntryBlock(); - IRBuilder<> Builder(F.getParent()->getContext()); - Builder.SetInsertPoint(Entry->getFirstInsertionPt()); - - Function *FrameEscapeFn = - Intrinsic::getDeclaration(M, Intrinsic::frameescape); - Function *RecoverFrameFn = - Intrinsic::getDeclaration(M, Intrinsic::framerecover); - SmallVector AllocasToEscape; - - // Scan the entry block for an existing call to llvm.frameescape. We need to - // keep escaping those objects. - for (Instruction &I : F.front()) { - auto *II = dyn_cast(&I); - if (II && II->getIntrinsicID() == Intrinsic::frameescape) { - auto Args = II->arg_operands(); - AllocasToEscape.append(Args.begin(), Args.end()); - II->eraseFromParent(); - break; - } - } + // Insert the cleanuppad instruction. + auto *CPI = CleanupPadInst::Create( + BB.getContext(), {}, Twine("terminatepad.for.", BB.getName()), &BB); - // Finally, replace all of the temporary allocas for frame variables used in - // the outlined handlers with calls to llvm.framerecover. - for (auto &VarInfoEntry : FrameVarInfo) { - Value *ParentVal = VarInfoEntry.first; - TinyPtrVector &Allocas = VarInfoEntry.second; - AllocaInst *ParentAlloca = cast(ParentVal); - - // FIXME: We should try to sink unescaped allocas from the parent frame into - // the child frame. If the alloca is escaped, we have to use the lifetime - // markers to ensure that the alloca is only live within the child frame. - - // Add this alloca to the list of things to escape. - AllocasToEscape.push_back(ParentAlloca); - - // Next replace all outlined allocas that are mapped to it. - for (AllocaInst *TempAlloca : Allocas) { - if (TempAlloca == getCatchObjectSentinel()) - continue; // Skip catch parameter sentinels. - Function *HandlerFn = TempAlloca->getParent()->getParent(); - // FIXME: Sink this GEP into the blocks where it is used. - Builder.SetInsertPoint(TempAlloca); - Builder.SetCurrentDebugLocation(TempAlloca->getDebugLoc()); - Value *RecoverArgs[] = { - Builder.CreateBitCast(&F, Int8PtrType, ""), - &(HandlerFn->getArgumentList().back()), - llvm::ConstantInt::get(Int32Type, AllocasToEscape.size() - 1)}; - Value *RecoveredAlloca = Builder.CreateCall(RecoverFrameFn, RecoverArgs); - // Add a pointer bitcast if the alloca wasn't an i8. - if (RecoveredAlloca->getType() != TempAlloca->getType()) { - RecoveredAlloca->setName(Twine(TempAlloca->getName()) + ".i8"); - RecoveredAlloca = - Builder.CreateBitCast(RecoveredAlloca, TempAlloca->getType()); - } - TempAlloca->replaceAllUsesWith(RecoveredAlloca); - TempAlloca->removeFromParent(); - RecoveredAlloca->takeName(TempAlloca); - delete TempAlloca; - } - } // End for each FrameVarInfo entry. + // Insert the call to the terminate instruction. + auto *CallTerminate = CallInst::Create(TerminateFn, {}, &BB); + CallTerminate->setDoesNotThrow(); + CallTerminate->setDoesNotReturn(); + CallTerminate->setCallingConv(TerminateFn->getCallingConv()); - // Insert 'call void (...)* @llvm.frameescape(...)' at the end of the entry - // block. - Builder.SetInsertPoint(&F.getEntryBlock().back()); - Builder.CreateCall(FrameEscapeFn, AllocasToEscape); + // Insert a new terminator for the cleanuppad using the same successor as + // the terminatepad. + CleanupReturnInst::Create(CPI, TPI->getUnwindDest(), &BB); - if (SEHExceptionCodeSlot) { - if (SEHExceptionCodeSlot->hasNUses(0)) - SEHExceptionCodeSlot->eraseFromParent(); - else - PromoteMemToReg(SEHExceptionCodeSlot, *DT); + // Let's remove the terminatepad now that we've inserted the new + // instructions. + TPI->eraseFromParent(); } +} - // Clean up the handler action maps we created for this function - DeleteContainerSeconds(CatchHandlerMap); - CatchHandlerMap.clear(); - DeleteContainerSeconds(CleanupHandlerMap); - CleanupHandlerMap.clear(); +static void +colorFunclets(Function &F, SmallVectorImpl &EntryBlocks, + std::map> &BlockColors, + std::map> &FuncletBlocks, + std::map> &FuncletChildren) { + SmallVector, 16> Worklist; + BasicBlock *EntryBlock = &F.getEntryBlock(); + + // Build up the color map, which maps each block to its set of 'colors'. + // For any block B, the "colors" of B are the set of funclets F (possibly + // including a root "funclet" representing the main function), such that + // F will need to directly contain B or a copy of B (where the term "directly + // contain" is used to distinguish from being "transitively contained" in + // a nested funclet). + // Use a CFG walk driven by a worklist of (block, color) pairs. The "color" + // sets attached during this processing to a block which is the entry of some + // funclet F is actually the set of F's parents -- i.e. the union of colors + // of all predecessors of F's entry. For all other blocks, the color sets + // are as defined above. A post-pass fixes up the block color map to reflect + // the same sense of "color" for funclet entries as for other blocks. + + Worklist.push_back({EntryBlock, EntryBlock}); - return HandlersOutlined; -} + while (!Worklist.empty()) { + BasicBlock *Visiting; + BasicBlock *Color; + std::tie(Visiting, Color) = Worklist.pop_back_val(); + Instruction *VisitingHead = Visiting->getFirstNonPHI(); + if (VisitingHead->isEHPad() && !isa(VisitingHead) && + !isa(VisitingHead)) { + // Mark this as a funclet head as a member of itself. + FuncletBlocks[Visiting].insert(Visiting); + // Queue exits (i.e. successors of rets/endpads) with the parent color. + // Skip any exits that are catchendpads, since the parent color must then + // represent one of the catches chained to that catchendpad, but the + // catchendpad should get the color of the common parent of all its + // chained catches (i.e. the grandparent color of the current pad). + // We don't need to worry abou catchendpads going unvisited, since the + // catches chained to them must have unwind edges to them by which we will + // visit them. + for (User *U : VisitingHead->users()) { + if (auto *Exit = dyn_cast(U)) { + for (BasicBlock *Succ : successors(Exit->getParent())) + if (!isa(*Succ->getFirstNonPHI())) + if (BlockColors[Succ].insert(Color).second) + Worklist.push_back({Succ, Color}); + } + } + // Handle CatchPad specially since its successors need different colors. + if (CatchPadInst *CatchPad = dyn_cast(VisitingHead)) { + // Visit the normal successor with the color of the new EH pad, and + // visit the unwind successor with the color of the parent. + BasicBlock *NormalSucc = CatchPad->getNormalDest(); + if (BlockColors[NormalSucc].insert(Visiting).second) { + Worklist.push_back({NormalSucc, Visiting}); + } + BasicBlock *UnwindSucc = CatchPad->getUnwindDest(); + if (BlockColors[UnwindSucc].insert(Color).second) { + Worklist.push_back({UnwindSucc, Color}); + } + continue; + } + // Switch color to the current node, except for terminate pads which + // have no bodies and only unwind successors and so need their successors + // visited with the color of the parent. + if (!isa(VisitingHead)) + Color = Visiting; + } else { + // Note that this is a member of the given color. + FuncletBlocks[Color].insert(Visiting); + } -void WinEHPrepare::promoteLandingPadValues(LandingPadInst *LPad) { - // If the return values of the landing pad instruction are extracted and - // stored to memory, we want to promote the store locations to reg values. - SmallVector EHAllocas; - - // The landingpad instruction returns an aggregate value. Typically, its - // value will be passed to a pair of extract value instructions and the - // results of those extracts are often passed to store instructions. - // In unoptimized code the stored value will often be loaded and then stored - // again. - for (auto *U : LPad->users()) { - ExtractValueInst *Extract = dyn_cast(U); - if (!Extract) + TerminatorInst *Terminator = Visiting->getTerminator(); + if (isa(Terminator) || + isa(Terminator) || + isa(Terminator)) { + // These blocks' successors have already been queued with the parent + // color. continue; - - for (auto *EU : Extract->users()) { - if (auto *Store = dyn_cast(EU)) { - auto *AV = cast(Store->getPointerOperand()); - EHAllocas.push_back(AV); + } + for (BasicBlock *Succ : successors(Visiting)) { + if (isa(Succ->getFirstNonPHI())) { + // The catchendpad needs to be visited with the parent's color, not + // the current color. This will happen in the code above that visits + // any catchpad unwind successor with the parent color, so we can + // safely skip this successor here. + continue; + } + if (BlockColors[Succ].insert(Color).second) { + Worklist.push_back({Succ, Color}); } } } - // We can't do this without a dominator tree. - assert(DT); - - if (!EHAllocas.empty()) { - PromoteMemToReg(EHAllocas, *DT); - EHAllocas.clear(); + // The processing above actually accumulated the parent set for this + // funclet into the color set for its entry; use the parent set to + // populate the children map, and reset the color set to include just + // the funclet itself (no instruction can target a funclet entry except on + // that transitions to the child funclet). + for (BasicBlock *FuncletEntry : EntryBlocks) { + std::set &ColorMapItem = BlockColors[FuncletEntry]; + for (BasicBlock *Parent : ColorMapItem) + FuncletChildren[Parent].insert(FuncletEntry); + ColorMapItem.clear(); + ColorMapItem.insert(FuncletEntry); } +} - // After promotion, some extracts may be trivially dead. Remove them. - SmallVector Users(LPad->user_begin(), LPad->user_end()); - for (auto *U : Users) - RecursivelyDeleteTriviallyDeadInstructions(U); +void WinEHPrepare::colorFunclets(Function &F, + SmallVectorImpl &EntryBlocks) { + ::colorFunclets(F, EntryBlocks, BlockColors, FuncletBlocks, FuncletChildren); } -void WinEHPrepare::completeNestedLandingPad(Function *ParentFn, - LandingPadInst *OutlinedLPad, - const LandingPadInst *OriginalLPad, - FrameVarInfoMap &FrameVarInfo) { - // Get the nested block and erase the unreachable instruction that was - // temporarily inserted as its terminator. - LLVMContext &Context = ParentFn->getContext(); - BasicBlock *OutlinedBB = OutlinedLPad->getParent(); - assert(isa(OutlinedBB->getTerminator())); - OutlinedBB->getTerminator()->eraseFromParent(); - // That should leave OutlinedLPad as the last instruction in its block. - assert(&OutlinedBB->back() == OutlinedLPad); - - // The original landing pad will have already had its action intrinsic - // built by the outlining loop. We need to clone that into the outlined - // location. It may also be necessary to add references to the exception - // variables to the outlined handler in which this landing pad is nested - // and remap return instructions in the nested handlers that should return - // to an address in the outlined handler. - Function *OutlinedHandlerFn = OutlinedBB->getParent(); - BasicBlock::const_iterator II = OriginalLPad; - ++II; - // The instruction after the landing pad should now be a call to eh.actions. - const Instruction *Recover = II; - assert(match(Recover, m_Intrinsic())); - IntrinsicInst *EHActions = cast(Recover->clone()); - - // Remap the exception variables into the outlined function. - WinEHFrameVariableMaterializer Materializer(OutlinedHandlerFn, FrameVarInfo); - SmallVector ActionTargets; - SmallVector ActionList; - parseEHActions(EHActions, ActionList); - for (auto *Action : ActionList) { - auto *Catch = dyn_cast(Action); - if (!Catch) - continue; - // The dyn_cast to function here selects C++ catch handlers and skips - // SEH catch handlers. - auto *Handler = dyn_cast(Catch->getHandlerBlockOrFunc()); - if (!Handler) +void llvm::calculateCatchReturnSuccessorColors(const Function *Fn, + WinEHFuncInfo &FuncInfo) { + SmallVector EntryBlocks; + // colorFunclets needs the set of EntryBlocks, get them using + // findFuncletEntryPoints. + findFuncletEntryPoints(const_cast(*Fn), EntryBlocks); + + std::map> BlockColors; + std::map> FuncletBlocks; + std::map> FuncletChildren; + // Figure out which basic blocks belong to which funclets. + colorFunclets(const_cast(*Fn), EntryBlocks, BlockColors, + FuncletBlocks, FuncletChildren); + + // We need to find the catchret successors. To do this, we must first find + // all the catchpad funclets. + for (auto &Funclet : FuncletBlocks) { + // Figure out what kind of funclet we are looking at; We only care about + // catchpads. + BasicBlock *FuncletPadBB = Funclet.first; + Instruction *FirstNonPHI = FuncletPadBB->getFirstNonPHI(); + auto *CatchPad = dyn_cast(FirstNonPHI); + if (!CatchPad) continue; - // Visit all the return instructions, looking for places that return - // to a location within OutlinedHandlerFn. - for (BasicBlock &NestedHandlerBB : *Handler) { - auto *Ret = dyn_cast(NestedHandlerBB.getTerminator()); - if (!Ret) - continue; - - // Handler functions must always return a block address. - BlockAddress *BA = cast(Ret->getReturnValue()); - // The original target will have been in the main parent function, - // but if it is the address of a block that has been outlined, it - // should be a block that was outlined into OutlinedHandlerFn. - assert(BA->getFunction() == ParentFn); - // Ignore targets that aren't part of OutlinedHandlerFn. - if (!LPadTargetBlocks.count(BA->getBasicBlock())) + // The users of a catchpad are always catchrets. + for (User *Exit : CatchPad->users()) { + auto *CatchReturn = dyn_cast(Exit); + if (!CatchReturn) continue; - - // If the return value is the address ofF a block that we - // previously outlined into the parent handler function, replace - // the return instruction and add the mapped target to the list - // of possible return addresses. - BasicBlock *MappedBB = LPadTargetBlocks[BA->getBasicBlock()]; - assert(MappedBB->getParent() == OutlinedHandlerFn); - BlockAddress *NewBA = BlockAddress::get(OutlinedHandlerFn, MappedBB); - Ret->eraseFromParent(); - ReturnInst::Create(Context, NewBA, &NestedHandlerBB); - ActionTargets.push_back(NewBA); + BasicBlock *CatchRetSuccessor = CatchReturn->getSuccessor(); + std::set &SuccessorColors = BlockColors[CatchRetSuccessor]; + assert(SuccessorColors.size() == 1 && "Expected BB to be monochrome!"); + BasicBlock *Color = *SuccessorColors.begin(); + // Record the catchret successor's funclet membership. + FuncInfo.CatchRetSuccessorColorMap[CatchReturn] = Color; } } - DeleteContainerPointers(ActionList); - ActionList.clear(); - OutlinedBB->getInstList().push_back(EHActions); - - // Insert an indirect branch into the outlined landing pad BB. - IndirectBrInst *IBr = IndirectBrInst::Create(EHActions, 0, OutlinedBB); - // Add the previously collected action targets. - for (auto *Target : ActionTargets) - IBr->addDestination(Target->getBasicBlock()); } -// This function examines a block to determine whether the block ends with a -// conditional branch to a catch handler based on a selector comparison. -// This function is used both by the WinEHPrepare::findSelectorComparison() and -// WinEHCleanupDirector::handleTypeIdFor(). -static bool isSelectorDispatch(BasicBlock *BB, BasicBlock *&CatchHandler, - Constant *&Selector, BasicBlock *&NextBB) { - ICmpInst::Predicate Pred; - BasicBlock *TBB, *FBB; - Value *LHS, *RHS; - - if (!match(BB->getTerminator(), - m_Br(m_ICmp(Pred, m_Value(LHS), m_Value(RHS)), TBB, FBB))) - return false; +void WinEHPrepare::demotePHIsOnFunclets(Function &F) { + // Strip PHI nodes off of EH pads. + SmallVector PHINodes; + for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE;) { + BasicBlock *BB = &*FI++; + if (!BB->isEHPad()) + continue; + for (BasicBlock::iterator BI = BB->begin(), BE = BB->end(); BI != BE;) { + Instruction *I = &*BI++; + auto *PN = dyn_cast(I); + // Stop at the first non-PHI. + if (!PN) + break; - if (!match(LHS, - m_Intrinsic(m_Constant(Selector))) && - !match(RHS, m_Intrinsic(m_Constant(Selector)))) - return false; + AllocaInst *SpillSlot = insertPHILoads(PN, F); + if (SpillSlot) + insertPHIStores(PN, SpillSlot); - if (Pred == CmpInst::ICMP_EQ) { - CatchHandler = TBB; - NextBB = FBB; - return true; + PHINodes.push_back(PN); + } } - if (Pred == CmpInst::ICMP_NE) { - CatchHandler = FBB; - NextBB = TBB; - return true; + for (auto *PN : PHINodes) { + // There may be lingering uses on other EH PHIs being removed + PN->replaceAllUsesWith(UndefValue::get(PN->getType())); + PN->eraseFromParent(); } - - return false; } -static bool isCatchBlock(BasicBlock *BB) { - for (BasicBlock::iterator II = BB->getFirstNonPHIOrDbg(), IE = BB->end(); - II != IE; ++II) { - if (match(cast(II), m_Intrinsic())) - return true; +void WinEHPrepare::demoteUsesBetweenFunclets(Function &F) { + // Turn all inter-funclet uses of a Value into loads and stores. + for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE;) { + BasicBlock *BB = &*FI++; + std::set &ColorsForBB = BlockColors[BB]; + for (BasicBlock::iterator BI = BB->begin(), BE = BB->end(); BI != BE;) { + Instruction *I = &*BI++; + // Funclets are permitted to use static allocas. + if (auto *AI = dyn_cast(I)) + if (AI->isStaticAlloca()) + continue; + + demoteNonlocalUses(I, ColorsForBB, F); + } } - return false; } -static BasicBlock *createStubLandingPad(Function *Handler, - Value *PersonalityFn) { - // FIXME: Finish this! - LLVMContext &Context = Handler->getContext(); - BasicBlock *StubBB = BasicBlock::Create(Context, "stub"); - Handler->getBasicBlockList().push_back(StubBB); - IRBuilder<> Builder(StubBB); - LandingPadInst *LPad = Builder.CreateLandingPad( - llvm::StructType::get(Type::getInt8PtrTy(Context), - Type::getInt32Ty(Context), nullptr), - PersonalityFn, 0); - // Insert a call to llvm.eh.actions so that we don't try to outline this lpad. - Function *ActionIntrin = Intrinsic::getDeclaration(Handler->getParent(), - Intrinsic::eh_actions); - Builder.CreateCall(ActionIntrin, "recover"); - LPad->setCleanup(true); - Builder.CreateUnreachable(); - return StubBB; +void WinEHPrepare::demoteArgumentUses(Function &F) { + // Also demote function parameters used in funclets. + std::set &ColorsForEntry = BlockColors[&F.getEntryBlock()]; + for (Argument &Arg : F.args()) + demoteNonlocalUses(&Arg, ColorsForEntry, F); } -// Cycles through the blocks in an outlined handler function looking for an -// invoke instruction and inserts an invoke of llvm.donothing with an empty -// landing pad if none is found. The code that generates the .xdata tables for -// the handler needs at least one landing pad to identify the parent function's -// personality. -void WinEHPrepare::addStubInvokeToHandlerIfNeeded(Function *Handler, - Value *PersonalityFn) { - ReturnInst *Ret = nullptr; - UnreachableInst *Unreached = nullptr; - for (BasicBlock &BB : *Handler) { - TerminatorInst *Terminator = BB.getTerminator(); - // If we find an invoke, there is nothing to be done. - auto *II = dyn_cast(Terminator); - if (II) - return; - // If we've already recorded a return instruction, keep looking for invokes. - if (!Ret) - Ret = dyn_cast(Terminator); - // If we haven't recorded an unreachable instruction, try this terminator. - if (!Unreached) - Unreached = dyn_cast(Terminator); - } - - // If we got this far, the handler contains no invokes. We should have seen - // at least one return or unreachable instruction. We'll insert an invoke of - // llvm.donothing ahead of that instruction. - assert(Ret || Unreached); - TerminatorInst *Term; - if (Ret) - Term = Ret; - else - Term = Unreached; - BasicBlock *OldRetBB = Term->getParent(); - BasicBlock *NewRetBB = SplitBlock(OldRetBB, Term); - // SplitBlock adds an unconditional branch instruction at the end of the - // parent block. We want to replace that with an invoke call, so we can - // erase it now. - OldRetBB->getTerminator()->eraseFromParent(); - BasicBlock *StubLandingPad = createStubLandingPad(Handler, PersonalityFn); - Function *F = - Intrinsic::getDeclaration(Handler->getParent(), Intrinsic::donothing); - InvokeInst::Create(F, NewRetBB, StubLandingPad, None, "", OldRetBB); -} +void WinEHPrepare::cloneCommonBlocks( + Function &F, SmallVectorImpl &EntryBlocks) { + // We need to clone all blocks which belong to multiple funclets. Values are + // remapped throughout the funclet to propogate both the new instructions + // *and* the new basic blocks themselves. + for (BasicBlock *FuncletPadBB : EntryBlocks) { + std::set &BlocksInFunclet = FuncletBlocks[FuncletPadBB]; + + std::map Orig2Clone; + ValueToValueMapTy VMap; + for (BasicBlock *BB : BlocksInFunclet) { + std::set &ColorsForBB = BlockColors[BB]; + // We don't need to do anything if the block is monochromatic. + size_t NumColorsForBB = ColorsForBB.size(); + if (NumColorsForBB == 1) + continue; -bool WinEHPrepare::outlineHandler(ActionHandler *Action, Function *SrcFn, - LandingPadInst *LPad, BasicBlock *StartBB, - FrameVarInfoMap &VarInfo) { - Module *M = SrcFn->getParent(); - LLVMContext &Context = M->getContext(); - - // Create a new function to receive the handler contents. - Type *Int8PtrType = Type::getInt8PtrTy(Context); - std::vector ArgTys; - ArgTys.push_back(Int8PtrType); - ArgTys.push_back(Int8PtrType); - Function *Handler; - if (Action->getType() == Catch) { - FunctionType *FnType = FunctionType::get(Int8PtrType, ArgTys, false); - Handler = Function::Create(FnType, GlobalVariable::InternalLinkage, - SrcFn->getName() + ".catch", M); - } else { - FunctionType *FnType = - FunctionType::get(Type::getVoidTy(Context), ArgTys, false); - Handler = Function::Create(FnType, GlobalVariable::InternalLinkage, - SrcFn->getName() + ".cleanup", M); - } + // Create a new basic block and copy instructions into it! + BasicBlock *CBB = + CloneBasicBlock(BB, VMap, Twine(".for.", FuncletPadBB->getName())); + // Insert the clone immediately after the original to ensure determinism + // and to keep the same relative ordering of any funclet's blocks. + CBB->insertInto(&F, BB->getNextNode()); - Handler->addFnAttr("wineh-parent", SrcFn->getName()); + // Add basic block mapping. + VMap[BB] = CBB; - // Generate a standard prolog to setup the frame recovery structure. - IRBuilder<> Builder(Context); - BasicBlock *Entry = BasicBlock::Create(Context, "entry"); - Handler->getBasicBlockList().push_front(Entry); - Builder.SetInsertPoint(Entry); - Builder.SetCurrentDebugLocation(LPad->getDebugLoc()); + // Record delta operations that we need to perform to our color mappings. + Orig2Clone[BB] = CBB; + } - std::unique_ptr Director; + // If nothing was cloned, we're done cloning in this funclet. + if (Orig2Clone.empty()) + continue; - ValueToValueMapTy VMap; + // Update our color mappings to reflect that one block has lost a color and + // another has gained a color. + for (auto &BBMapping : Orig2Clone) { + BasicBlock *OldBlock = BBMapping.first; + BasicBlock *NewBlock = BBMapping.second; - LandingPadMap &LPadMap = LPadMaps[LPad]; - if (!LPadMap.isInitialized()) - LPadMap.mapLandingPad(LPad); - if (auto *CatchAction = dyn_cast(Action)) { - Constant *Sel = CatchAction->getSelector(); - Director.reset(new WinEHCatchDirector(Handler, Sel, VarInfo, LPadMap, - NestedLPtoOriginalLP)); - LPadMap.remapEHValues(VMap, UndefValue::get(Int8PtrType), - ConstantInt::get(Type::getInt32Ty(Context), 1)); - } else { - Director.reset(new WinEHCleanupDirector(Handler, VarInfo, LPadMap)); - LPadMap.remapEHValues(VMap, UndefValue::get(Int8PtrType), - UndefValue::get(Type::getInt32Ty(Context))); - } + BlocksInFunclet.insert(NewBlock); + BlockColors[NewBlock].insert(FuncletPadBB); - SmallVector Returns; - ClonedCodeInfo OutlinedFunctionInfo; - - // If the start block contains PHI nodes, we need to map them. - BasicBlock::iterator II = StartBB->begin(); - while (auto *PN = dyn_cast(II)) { - bool Mapped = false; - // Look for PHI values that we have already mapped (such as the selector). - for (Value *Val : PN->incoming_values()) { - if (VMap.count(Val)) { - VMap[PN] = VMap[Val]; - Mapped = true; - } + BlocksInFunclet.erase(OldBlock); + BlockColors[OldBlock].erase(FuncletPadBB); } - // If we didn't find a match for this value, map it as an undef. - if (!Mapped) { - VMap[PN] = UndefValue::get(PN->getType()); - } - ++II; - } - // The landing pad value may be used by PHI nodes. It will ultimately be - // eliminated, but we need it in the map for intermediate handling. - VMap[LPad] = UndefValue::get(LPad->getType()); - - // Skip over PHIs and, if applicable, landingpad instructions. - II = StartBB->getFirstInsertionPt(); - - CloneAndPruneIntoFromInst(Handler, SrcFn, II, VMap, - /*ModuleLevelChanges=*/false, Returns, "", - &OutlinedFunctionInfo, Director.get()); - - // Move all the instructions in the cloned "entry" block into our entry block. - // Depending on how the parent function was laid out, the block that will - // correspond to the outlined entry block may not be the first block in the - // list. We can recognize it, however, as the cloned block which has no - // predecessors. Any other block wouldn't have been cloned if it didn't - // have a predecessor which was also cloned. - Function::iterator ClonedIt = std::next(Function::iterator(Entry)); - while (!pred_empty(ClonedIt)) - ++ClonedIt; - BasicBlock *ClonedEntryBB = ClonedIt; - assert(ClonedEntryBB); - Entry->getInstList().splice(Entry->end(), ClonedEntryBB->getInstList()); - ClonedEntryBB->eraseFromParent(); - - // Make sure we can identify the handler's personality later. - addStubInvokeToHandlerIfNeeded(Handler, LPad->getPersonalityFn()); - - if (auto *CatchAction = dyn_cast(Action)) { - WinEHCatchDirector *CatchDirector = - reinterpret_cast(Director.get()); - CatchAction->setExceptionVar(CatchDirector->getExceptionVar()); - CatchAction->setReturnTargets(CatchDirector->getReturnTargets()); - - // Look for blocks that are not part of the landing pad that we just - // outlined but terminate with a call to llvm.eh.endcatch and a - // branch to a block that is in the handler we just outlined. - // These blocks will be part of a nested landing pad that intends to - // return to an address in this handler. This case is best handled - // after both landing pads have been outlined, so for now we'll just - // save the association of the blocks in LPadTargetBlocks. The - // return instructions which are created from these branches will be - // replaced after all landing pads have been outlined. - for (const auto MapEntry : VMap) { - // VMap maps all values and blocks that were just cloned, but dead - // blocks which were pruned will map to nullptr. - if (!isa(MapEntry.first) || MapEntry.second == nullptr) - continue; - const BasicBlock *MappedBB = cast(MapEntry.first); - for (auto *Pred : predecessors(const_cast(MappedBB))) { - auto *Branch = dyn_cast(Pred->getTerminator()); - if (!Branch || !Branch->isUnconditional() || Pred->size() <= 1) - continue; - BasicBlock::iterator II = const_cast(Branch); - --II; - if (match(cast(II), m_Intrinsic())) { - // This would indicate that a nested landing pad wants to return - // to a block that is outlined into two different handlers. - assert(!LPadTargetBlocks.count(MappedBB)); - LPadTargetBlocks[MappedBB] = cast(MapEntry.second); + // Loop over all of the instructions in this funclet, fixing up operand + // references as we go. This uses VMap to do all the hard work. + for (BasicBlock *BB : BlocksInFunclet) + // Loop over all instructions, fixing each one as we find it... + for (Instruction &I : *BB) + RemapInstruction(&I, VMap, + RF_IgnoreMissingEntries | RF_NoModuleLevelChanges); + + // Check to see if SuccBB has PHI nodes. If so, we need to add entries to + // the PHI nodes for NewBB now. + for (auto &BBMapping : Orig2Clone) { + BasicBlock *OldBlock = BBMapping.first; + BasicBlock *NewBlock = BBMapping.second; + for (BasicBlock *SuccBB : successors(NewBlock)) { + for (Instruction &SuccI : *SuccBB) { + auto *SuccPN = dyn_cast(&SuccI); + if (!SuccPN) + break; + + // Ok, we have a PHI node. Figure out what the incoming value was for + // the OldBlock. + int OldBlockIdx = SuccPN->getBasicBlockIndex(OldBlock); + if (OldBlockIdx == -1) + break; + Value *IV = SuccPN->getIncomingValue(OldBlockIdx); + + // Remap the value if necessary. + if (auto *Inst = dyn_cast(IV)) { + ValueToValueMapTy::iterator I = VMap.find(Inst); + if (I != VMap.end()) + IV = I->second; + } + + SuccPN->addIncoming(IV, NewBlock); } } } - } // End if (CatchAction) - Action->setHandlerBlockOrFunc(Handler); + for (ValueToValueMapTy::value_type VT : VMap) { + // If there were values defined in BB that are used outside the funclet, + // then we now have to update all uses of the value to use either the + // original value, the cloned value, or some PHI derived value. This can + // require arbitrary PHI insertion, of which we are prepared to do, clean + // these up now. + SmallVector UsesToRename; - return true; -} - -/// This BB must end in a selector dispatch. All we need to do is pass the -/// handler block to llvm.eh.actions and list it as a possible indirectbr -/// target. -void WinEHPrepare::processSEHCatchHandler(CatchHandler *CatchAction, - BasicBlock *StartBB) { - BasicBlock *HandlerBB; - BasicBlock *NextBB; - Constant *Selector; - bool Res = isSelectorDispatch(StartBB, HandlerBB, Selector, NextBB); - if (Res) { - // If this was EH dispatch, this must be a conditional branch to the handler - // block. - // FIXME: Handle instructions in the dispatch block. Currently we drop them, - // leading to crashes if some optimization hoists stuff here. - assert(CatchAction->getSelector() && HandlerBB && - "expected catch EH dispatch"); - } else { - // This must be a catch-all. Split the block after the landingpad. - assert(CatchAction->getSelector()->isNullValue() && "expected catch-all"); - HandlerBB = - StartBB->splitBasicBlock(StartBB->getFirstInsertionPt(), "catch.all"); - } - IRBuilder<> Builder(HandlerBB->getFirstInsertionPt()); - Function *EHCodeFn = Intrinsic::getDeclaration( - StartBB->getParent()->getParent(), Intrinsic::eh_exceptioncode); - Value *Code = Builder.CreateCall(EHCodeFn, "sehcode"); - Code = Builder.CreateIntToPtr(Code, SEHExceptionCodeSlot->getAllocatedType()); - Builder.CreateStore(Code, SEHExceptionCodeSlot); - CatchAction->setHandlerBlockOrFunc(BlockAddress::get(HandlerBB)); - TinyPtrVector Targets(HandlerBB); - CatchAction->setReturnTargets(Targets); -} - -void LandingPadMap::mapLandingPad(const LandingPadInst *LPad) { - // Each instance of this class should only ever be used to map a single - // landing pad. - assert(OriginLPad == nullptr || OriginLPad == LPad); + auto *OldI = dyn_cast(const_cast(VT.first)); + if (!OldI) + continue; + auto *NewI = cast(VT.second); + // Scan all uses of this instruction to see if it is used outside of its + // funclet, and if so, record them in UsesToRename. + for (Use &U : OldI->uses()) { + Instruction *UserI = cast(U.getUser()); + BasicBlock *UserBB = UserI->getParent(); + std::set &ColorsForUserBB = BlockColors[UserBB]; + assert(!ColorsForUserBB.empty()); + if (ColorsForUserBB.size() > 1 || + *ColorsForUserBB.begin() != FuncletPadBB) + UsesToRename.push_back(&U); + } - // If the landing pad has already been mapped, there's nothing more to do. - if (OriginLPad == LPad) - return; + // If there are no uses outside the block, we're done with this + // instruction. + if (UsesToRename.empty()) + continue; - OriginLPad = LPad; + // We found a use of OldI outside of the funclet. Rename all uses of OldI + // that are outside its funclet to be uses of the appropriate PHI node + // etc. + SSAUpdater SSAUpdate; + SSAUpdate.Initialize(OldI->getType(), OldI->getName()); + SSAUpdate.AddAvailableValue(OldI->getParent(), OldI); + SSAUpdate.AddAvailableValue(NewI->getParent(), NewI); - // The landingpad instruction returns an aggregate value. Typically, its - // value will be passed to a pair of extract value instructions and the - // results of those extracts will have been promoted to reg values before - // this routine is called. - for (auto *U : LPad->users()) { - const ExtractValueInst *Extract = dyn_cast(U); - if (!Extract) - continue; - assert(Extract->getNumIndices() == 1 && - "Unexpected operation: extracting both landing pad values"); - unsigned int Idx = *(Extract->idx_begin()); - assert((Idx == 0 || Idx == 1) && - "Unexpected operation: extracting an unknown landing pad element"); - if (Idx == 0) { - ExtractedEHPtrs.push_back(Extract); - } else if (Idx == 1) { - ExtractedSelectors.push_back(Extract); + while (!UsesToRename.empty()) + SSAUpdate.RewriteUseAfterInsertions(*UsesToRename.pop_back_val()); } } } -bool LandingPadMap::isOriginLandingPadBlock(const BasicBlock *BB) const { - return BB->getLandingPadInst() == OriginLPad; -} - -bool LandingPadMap::isLandingPadSpecificInst(const Instruction *Inst) const { - if (Inst == OriginLPad) - return true; - for (auto *Extract : ExtractedEHPtrs) { - if (Inst == Extract) - return true; - } - for (auto *Extract : ExtractedSelectors) { - if (Inst == Extract) - return true; - } - return false; -} - -void LandingPadMap::remapEHValues(ValueToValueMapTy &VMap, Value *EHPtrValue, - Value *SelectorValue) const { - // Remap all landing pad extract instructions to the specified values. - for (auto *Extract : ExtractedEHPtrs) - VMap[Extract] = EHPtrValue; - for (auto *Extract : ExtractedSelectors) - VMap[Extract] = SelectorValue; -} - -static bool isFrameAddressCall(const Value *V) { - return match(const_cast(V), - m_Intrinsic(m_SpecificInt(0))); -} - -CloningDirector::CloningAction WinEHCloningDirectorBase::handleInstruction( - ValueToValueMapTy &VMap, const Instruction *Inst, BasicBlock *NewBB) { - // If this is one of the boilerplate landing pad instructions, skip it. - // The instruction will have already been remapped in VMap. - if (LPadMap.isLandingPadSpecificInst(Inst)) - return CloningDirector::SkipInstruction; - - // Nested landing pads will be cloned as stubs, with just the - // landingpad instruction and an unreachable instruction. When - // all landingpads have been outlined, we'll replace this with the - // llvm.eh.actions call and indirect branch created when the - // landing pad was outlined. - if (auto *LPad = dyn_cast(Inst)) { - return handleLandingPad(VMap, LPad, NewBB); - } - - if (auto *Invoke = dyn_cast(Inst)) - return handleInvoke(VMap, Invoke, NewBB); - - if (auto *Resume = dyn_cast(Inst)) - return handleResume(VMap, Resume, NewBB); - - if (auto *Cmp = dyn_cast(Inst)) - return handleCompare(VMap, Cmp, NewBB); - - if (match(Inst, m_Intrinsic())) - return handleBeginCatch(VMap, Inst, NewBB); - if (match(Inst, m_Intrinsic())) - return handleEndCatch(VMap, Inst, NewBB); - if (match(Inst, m_Intrinsic())) - return handleTypeIdFor(VMap, Inst, NewBB); +void WinEHPrepare::removeImplausibleTerminators(Function &F) { + // Remove implausible terminators and replace them with UnreachableInst. + for (auto &Funclet : FuncletBlocks) { + BasicBlock *FuncletPadBB = Funclet.first; + std::set &BlocksInFunclet = Funclet.second; + Instruction *FirstNonPHI = FuncletPadBB->getFirstNonPHI(); + auto *CatchPad = dyn_cast(FirstNonPHI); + auto *CleanupPad = dyn_cast(FirstNonPHI); + + for (BasicBlock *BB : BlocksInFunclet) { + TerminatorInst *TI = BB->getTerminator(); + // CatchPadInst and CleanupPadInst can't transfer control to a ReturnInst. + bool IsUnreachableRet = isa(TI) && (CatchPad || CleanupPad); + // The token consumed by a CatchReturnInst must match the funclet token. + bool IsUnreachableCatchret = false; + if (auto *CRI = dyn_cast(TI)) + IsUnreachableCatchret = CRI->getCatchPad() != CatchPad; + // The token consumed by a CleanupReturnInst must match the funclet token. + bool IsUnreachableCleanupret = false; + if (auto *CRI = dyn_cast(TI)) + IsUnreachableCleanupret = CRI->getCleanupPad() != CleanupPad; + // The token consumed by a CleanupEndPadInst must match the funclet token. + bool IsUnreachableCleanupendpad = false; + if (auto *CEPI = dyn_cast(TI)) + IsUnreachableCleanupendpad = CEPI->getCleanupPad() != CleanupPad; + if (IsUnreachableRet || IsUnreachableCatchret || + IsUnreachableCleanupret || IsUnreachableCleanupendpad) { + // Loop through all of our successors and make sure they know that one + // of their predecessors is going away. + for (BasicBlock *SuccBB : TI->successors()) + SuccBB->removePredecessor(BB); + + if (IsUnreachableCleanupendpad) { + // We can't simply replace a cleanupendpad with unreachable, because + // its predecessor edges are EH edges and unreachable is not an EH + // pad. Change all predecessors to the "unwind to caller" form. + for (pred_iterator PI = pred_begin(BB), PE = pred_end(BB); + PI != PE;) { + BasicBlock *Pred = *PI++; + removeUnwindEdge(Pred); + } + } - // When outlining llvm.frameaddress(i32 0), remap that to the second argument, - // which is the FP of the parent. - if (isFrameAddressCall(Inst)) { - VMap[Inst] = EstablisherFrame; - return CloningDirector::SkipInstruction; + new UnreachableInst(BB->getContext(), TI); + TI->eraseFromParent(); + } + // FIXME: Check for invokes/cleanuprets/cleanupendpads which unwind to + // implausible catchendpads (i.e. catchendpad not in immediate parent + // funclet). + } } - - // Continue with the default cloning behavior. - return CloningDirector::CloneInstruction; -} - -CloningDirector::CloningAction WinEHCatchDirector::handleLandingPad( - ValueToValueMapTy &VMap, const LandingPadInst *LPad, BasicBlock *NewBB) { - Instruction *NewInst = LPad->clone(); - if (LPad->hasName()) - NewInst->setName(LPad->getName()); - // Save this correlation for later processing. - NestedLPtoOriginalLP[cast(NewInst)] = LPad; - VMap[LPad] = NewInst; - BasicBlock::InstListType &InstList = NewBB->getInstList(); - InstList.push_back(NewInst); - InstList.push_back(new UnreachableInst(NewBB->getContext())); - return CloningDirector::StopCloningBB; -} - -CloningDirector::CloningAction WinEHCatchDirector::handleBeginCatch( - ValueToValueMapTy &VMap, const Instruction *Inst, BasicBlock *NewBB) { - // The argument to the call is some form of the first element of the - // landingpad aggregate value, but that doesn't matter. It isn't used - // here. - // The second argument is an outparameter where the exception object will be - // stored. Typically the exception object is a scalar, but it can be an - // aggregate when catching by value. - // FIXME: Leave something behind to indicate where the exception object lives - // for this handler. Should it be part of llvm.eh.actions? - assert(ExceptionObjectVar == nullptr && "Multiple calls to " - "llvm.eh.begincatch found while " - "outlining catch handler."); - ExceptionObjectVar = Inst->getOperand(1)->stripPointerCasts(); - if (isa(ExceptionObjectVar)) - return CloningDirector::SkipInstruction; - assert(cast(ExceptionObjectVar)->isStaticAlloca() && - "catch parameter is not static alloca"); - Materializer.escapeCatchObject(ExceptionObjectVar); - return CloningDirector::SkipInstruction; } -CloningDirector::CloningAction -WinEHCatchDirector::handleEndCatch(ValueToValueMapTy &VMap, - const Instruction *Inst, BasicBlock *NewBB) { - auto *IntrinCall = dyn_cast(Inst); - // It might be interesting to track whether or not we are inside a catch - // function, but that might make the algorithm more brittle than it needs - // to be. - - // The end catch call can occur in one of two places: either in a - // landingpad block that is part of the catch handlers exception mechanism, - // or at the end of the catch block. However, a catch-all handler may call - // end catch from the original landing pad. If the call occurs in a nested - // landing pad block, we must skip it and continue so that the landing pad - // gets cloned. - auto *ParentBB = IntrinCall->getParent(); - if (ParentBB->isLandingPad() && !LPadMap.isOriginLandingPadBlock(ParentBB)) - return CloningDirector::SkipInstruction; - - // If an end catch occurs anywhere else we want to terminate the handler - // with a return to the code that follows the endcatch call. If the - // next instruction is not an unconditional branch, we need to split the - // block to provide a clear target for the return instruction. - BasicBlock *ContinueBB; - auto Next = std::next(BasicBlock::const_iterator(IntrinCall)); - const BranchInst *Branch = dyn_cast(Next); - if (!Branch || !Branch->isUnconditional()) { - // We're interrupting the cloning process at this location, so the - // const_cast we're doing here will not cause a problem. - ContinueBB = SplitBlock(const_cast(ParentBB), - const_cast(cast(Next))); - } else { - ContinueBB = Branch->getSuccessor(0); +void WinEHPrepare::cleanupPreparedFunclets(Function &F) { + // Clean-up some of the mess we made by removing useles PHI nodes, trivial + // branches, etc. + for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE;) { + BasicBlock *BB = &*FI++; + SimplifyInstructionsInBlock(BB); + ConstantFoldTerminator(BB, /*DeleteDeadConditions=*/true); + MergeBlockIntoPredecessor(BB); } - ReturnInst::Create(NewBB->getContext(), BlockAddress::get(ContinueBB), NewBB); - ReturnTargets.push_back(ContinueBB); - - // We just added a terminator to the cloned block. - // Tell the caller to stop processing the current basic block so that - // the branch instruction will be skipped. - return CloningDirector::StopCloningBB; -} - -CloningDirector::CloningAction WinEHCatchDirector::handleTypeIdFor( - ValueToValueMapTy &VMap, const Instruction *Inst, BasicBlock *NewBB) { - auto *IntrinCall = dyn_cast(Inst); - Value *Selector = IntrinCall->getArgOperand(0)->stripPointerCasts(); - // This causes a replacement that will collapse the landing pad CFG based - // on the filter function we intend to match. - if (Selector == CurrentSelector) - VMap[Inst] = ConstantInt::get(SelectorIDType, 1); - else - VMap[Inst] = ConstantInt::get(SelectorIDType, 0); - // Tell the caller not to clone this instruction. - return CloningDirector::SkipInstruction; -} - -CloningDirector::CloningAction -WinEHCatchDirector::handleInvoke(ValueToValueMapTy &VMap, - const InvokeInst *Invoke, BasicBlock *NewBB) { - return CloningDirector::CloneInstruction; -} - -CloningDirector::CloningAction -WinEHCatchDirector::handleResume(ValueToValueMapTy &VMap, - const ResumeInst *Resume, BasicBlock *NewBB) { - // Resume instructions shouldn't be reachable from catch handlers. - // We still need to handle it, but it will be pruned. - BasicBlock::InstListType &InstList = NewBB->getInstList(); - InstList.push_back(new UnreachableInst(NewBB->getContext())); - return CloningDirector::StopCloningBB; + // We might have some unreachable blocks after cleaning up some impossible + // control flow. + removeUnreachableBlocks(F); } -CloningDirector::CloningAction -WinEHCatchDirector::handleCompare(ValueToValueMapTy &VMap, - const CmpInst *Compare, BasicBlock *NewBB) { - const IntrinsicInst *IntrinCall = nullptr; - if (match(Compare->getOperand(0), m_Intrinsic())) { - IntrinCall = dyn_cast(Compare->getOperand(0)); - } else if (match(Compare->getOperand(1), m_Intrinsic())) { - IntrinCall = dyn_cast(Compare->getOperand(1)); - } - if (IntrinCall) { - Value *Selector = IntrinCall->getArgOperand(0)->stripPointerCasts(); - // This causes a replacement that will collapse the landing pad CFG based - // on the filter function we intend to match. - if (Selector == CurrentSelector->stripPointerCasts()) { - VMap[Compare] = ConstantInt::get(SelectorIDType, 1); - } - else { - VMap[Compare] = ConstantInt::get(SelectorIDType, 0); +void WinEHPrepare::verifyPreparedFunclets(Function &F) { + // Recolor the CFG to verify that all is well. + for (BasicBlock &BB : F) { + size_t NumColors = BlockColors[&BB].size(); + assert(NumColors == 1 && "Expected monochromatic BB!"); + if (NumColors == 0) + report_fatal_error("Uncolored BB!"); + if (NumColors > 1) + report_fatal_error("Multicolor BB!"); + if (!DisableDemotion) { + bool EHPadHasPHI = BB.isEHPad() && isa(BB.begin()); + assert(!EHPadHasPHI && "EH Pad still has a PHI!"); + if (EHPadHasPHI) + report_fatal_error("EH Pad still has a PHI!"); } - return CloningDirector::SkipInstruction; } - return CloningDirector::CloneInstruction; -} - -CloningDirector::CloningAction WinEHCleanupDirector::handleLandingPad( - ValueToValueMapTy &VMap, const LandingPadInst *LPad, BasicBlock *NewBB) { - // The MS runtime will terminate the process if an exception occurs in a - // cleanup handler, so we shouldn't encounter landing pads in the actual - // cleanup code, but they may appear in catch blocks. Depending on where - // we started cloning we may see one, but it will get dropped during dead - // block pruning. - Instruction *NewInst = new UnreachableInst(NewBB->getContext()); - VMap[LPad] = NewInst; - BasicBlock::InstListType &InstList = NewBB->getInstList(); - InstList.push_back(NewInst); - return CloningDirector::StopCloningBB; -} - -CloningDirector::CloningAction WinEHCleanupDirector::handleBeginCatch( - ValueToValueMapTy &VMap, const Instruction *Inst, BasicBlock *NewBB) { - // Cleanup code may flow into catch blocks or the catch block may be part - // of a branch that will be optimized away. We'll insert a return - // instruction now, but it may be pruned before the cloning process is - // complete. - ReturnInst::Create(NewBB->getContext(), nullptr, NewBB); - return CloningDirector::StopCloningBB; -} - -CloningDirector::CloningAction WinEHCleanupDirector::handleEndCatch( - ValueToValueMapTy &VMap, const Instruction *Inst, BasicBlock *NewBB) { - // Cleanup handlers nested within catch handlers may begin with a call to - // eh.endcatch. We can just ignore that instruction. - return CloningDirector::SkipInstruction; } -CloningDirector::CloningAction WinEHCleanupDirector::handleTypeIdFor( - ValueToValueMapTy &VMap, const Instruction *Inst, BasicBlock *NewBB) { - // If we encounter a selector comparison while cloning a cleanup handler, - // we want to stop cloning immediately. Anything after the dispatch - // will be outlined into a different handler. - BasicBlock *CatchHandler; - Constant *Selector; - BasicBlock *NextBB; - if (isSelectorDispatch(const_cast(Inst->getParent()), - CatchHandler, Selector, NextBB)) { - ReturnInst::Create(NewBB->getContext(), nullptr, NewBB); - return CloningDirector::StopCloningBB; - } - // If eg.typeid.for is called for any other reason, it can be ignored. - VMap[Inst] = ConstantInt::get(SelectorIDType, 0); - return CloningDirector::SkipInstruction; -} +bool WinEHPrepare::prepareExplicitEH( + Function &F, SmallVectorImpl &EntryBlocks) { + replaceTerminatePadWithCleanup(F); -CloningDirector::CloningAction WinEHCleanupDirector::handleInvoke( - ValueToValueMapTy &VMap, const InvokeInst *Invoke, BasicBlock *NewBB) { - // All invokes in cleanup handlers can be replaced with calls. - SmallVector CallArgs(Invoke->op_begin(), Invoke->op_end() - 3); - // Insert a normal call instruction... - CallInst *NewCall = - CallInst::Create(const_cast(Invoke->getCalledValue()), CallArgs, - Invoke->getName(), NewBB); - NewCall->setCallingConv(Invoke->getCallingConv()); - NewCall->setAttributes(Invoke->getAttributes()); - NewCall->setDebugLoc(Invoke->getDebugLoc()); - VMap[Invoke] = NewCall; - - // Remap the operands. - llvm::RemapInstruction(NewCall, VMap, RF_None, nullptr, &Materializer); - - // Insert an unconditional branch to the normal destination. - BranchInst::Create(Invoke->getNormalDest(), NewBB); - - // The unwind destination won't be cloned into the new function, so - // we don't need to clean up its phi nodes. - - // We just added a terminator to the cloned block. - // Tell the caller to stop processing the current basic block. - return CloningDirector::CloneSuccessors; -} + // Determine which blocks are reachable from which funclet entries. + colorFunclets(F, EntryBlocks); -CloningDirector::CloningAction WinEHCleanupDirector::handleResume( - ValueToValueMapTy &VMap, const ResumeInst *Resume, BasicBlock *NewBB) { - ReturnInst::Create(NewBB->getContext(), nullptr, NewBB); + if (!DisableDemotion) { + demotePHIsOnFunclets(F); - // We just added a terminator to the cloned block. - // Tell the caller to stop processing the current basic block so that - // the branch instruction will be skipped. - return CloningDirector::StopCloningBB; -} + demoteUsesBetweenFunclets(F); -CloningDirector::CloningAction -WinEHCleanupDirector::handleCompare(ValueToValueMapTy &VMap, - const CmpInst *Compare, BasicBlock *NewBB) { - if (match(Compare->getOperand(0), m_Intrinsic()) || - match(Compare->getOperand(1), m_Intrinsic())) { - VMap[Compare] = ConstantInt::get(SelectorIDType, 1); - return CloningDirector::SkipInstruction; + demoteArgumentUses(F); } - return CloningDirector::CloneInstruction; -} + cloneCommonBlocks(F, EntryBlocks); -WinEHFrameVariableMaterializer::WinEHFrameVariableMaterializer( - Function *OutlinedFn, FrameVarInfoMap &FrameVarInfo) - : FrameVarInfo(FrameVarInfo), Builder(OutlinedFn->getContext()) { - BasicBlock *EntryBB = &OutlinedFn->getEntryBlock(); - Builder.SetInsertPoint(EntryBB, EntryBB->getFirstInsertionPt()); -} + if (!DisableCleanups) { + removeImplausibleTerminators(F); -Value *WinEHFrameVariableMaterializer::materializeValueFor(Value *V) { - // If we're asked to materialize a static alloca, we temporarily create an - // alloca in the outlined function and add this to the FrameVarInfo map. When - // all the outlining is complete, we'll replace these temporary allocas with - // calls to llvm.framerecover. - if (auto *AV = dyn_cast(V)) { - assert(AV->isStaticAlloca() && - "cannot materialize un-demoted dynamic alloca"); - AllocaInst *NewAlloca = dyn_cast(AV->clone()); - Builder.Insert(NewAlloca, AV->getName()); - FrameVarInfo[AV].push_back(NewAlloca); - return NewAlloca; + cleanupPreparedFunclets(F); } - if (isa(V) || isa(V)) { - errs() << "Failed to demote instruction used in exception handler:\n"; - errs() << " " << *V << '\n'; - report_fatal_error("WinEHPrepare failed to demote instruction"); - } + verifyPreparedFunclets(F); - // Don't materialize other values. - return nullptr; -} + BlockColors.clear(); + FuncletBlocks.clear(); + FuncletChildren.clear(); -void WinEHFrameVariableMaterializer::escapeCatchObject(Value *V) { - // Catch parameter objects have to live in the parent frame. When we see a use - // of a catch parameter, add a sentinel to the multimap to indicate that it's - // used from another handler. This will prevent us from trying to sink the - // alloca into the handler and ensure that the catch parameter is present in - // the call to llvm.frameescape. - FrameVarInfo[V].push_back(getCatchObjectSentinel()); + return true; } -// This function maps the catch and cleanup handlers that are reachable from the -// specified landing pad. The landing pad sequence will have this basic shape: -// -// -// -// -// -// -// -// -// ... -// -// Any of the cleanup slots may be absent. The cleanup slots may be occupied by -// any arbitrary control flow, but all paths through the cleanup code must -// eventually reach the next selector comparison and no path can skip to a -// different selector comparisons, though some paths may terminate abnormally. -// Therefore, we will use a depth first search from the start of any given -// cleanup block and stop searching when we find the next selector comparison. -// -// If the landingpad instruction does not have a catch clause, we will assume -// that any instructions other than selector comparisons and catch handlers can -// be ignored. In practice, these will only be the boilerplate instructions. -// -// The catch handlers may also have any control structure, but we are only -// interested in the start of the catch handlers, so we don't need to actually -// follow the flow of the catch handlers. The start of the catch handlers can -// be located from the compare instructions, but they can be skipped in the -// flow by following the contrary branch. -void WinEHPrepare::mapLandingPadBlocks(LandingPadInst *LPad, - LandingPadActions &Actions) { - unsigned int NumClauses = LPad->getNumClauses(); - unsigned int HandlersFound = 0; - BasicBlock *BB = LPad->getParent(); - - DEBUG(dbgs() << "Mapping landing pad: " << BB->getName() << "\n"); - - if (NumClauses == 0) { - findCleanupHandlers(Actions, BB, nullptr); - return; +// TODO: Share loads when one use dominates another, or when a catchpad exit +// dominates uses (needs dominators). +AllocaInst *WinEHPrepare::insertPHILoads(PHINode *PN, Function &F) { + BasicBlock *PHIBlock = PN->getParent(); + AllocaInst *SpillSlot = nullptr; + + if (isa(PHIBlock->getFirstNonPHI())) { + // Insert a load in place of the PHI and replace all uses. + SpillSlot = new AllocaInst(PN->getType(), nullptr, + Twine(PN->getName(), ".wineh.spillslot"), + &F.getEntryBlock().front()); + Value *V = new LoadInst(SpillSlot, Twine(PN->getName(), ".wineh.reload"), + &*PHIBlock->getFirstInsertionPt()); + PN->replaceAllUsesWith(V); + return SpillSlot; } - VisitedBlockSet VisitedBlocks; - - while (HandlersFound != NumClauses) { - BasicBlock *NextBB = nullptr; - - // Skip over filter clauses. - if (LPad->isFilter(HandlersFound)) { - ++HandlersFound; + DenseMap Loads; + for (Value::use_iterator UI = PN->use_begin(), UE = PN->use_end(); + UI != UE;) { + Use &U = *UI++; + auto *UsingInst = cast(U.getUser()); + BasicBlock *UsingBB = UsingInst->getParent(); + if (UsingBB->isEHPad()) { + // Use is on an EH pad phi. Leave it alone; we'll insert loads and + // stores for it separately. + assert(isa(UsingInst)); continue; } + replaceUseWithLoad(PN, U, SpillSlot, Loads, F); + } + return SpillSlot; +} - // See if the clause we're looking for is a catch-all. - // If so, the catch begins immediately. - Constant *ExpectedSelector = LPad->getClause(HandlersFound)->stripPointerCasts(); - if (isa(ExpectedSelector)) { - // The catch all must occur last. - assert(HandlersFound == NumClauses - 1); - - // There can be additional selector dispatches in the call chain that we - // need to ignore. - BasicBlock *CatchBlock = nullptr; - Constant *Selector; - while (BB && isSelectorDispatch(BB, CatchBlock, Selector, NextBB)) { - DEBUG(dbgs() << " Found extra catch dispatch in block " - << CatchBlock->getName() << "\n"); - BB = NextBB; - } - - // For C++ EH, check if there is any interesting cleanup code before we - // begin the catch. This is important because cleanups cannot rethrow - // exceptions but code called from catches can. For SEH, it isn't - // important if some finally code before a catch-all is executed out of - // line or after recovering from the exception. - if (Personality == EHPersonality::MSVC_CXX) - findCleanupHandlers(Actions, BB, BB); - - // Add the catch handler to the action list. - CatchHandler *Action = nullptr; - if (CatchHandlerMap.count(BB) && CatchHandlerMap[BB] != nullptr) { - // If the CatchHandlerMap already has an entry for this BB, re-use it. - Action = CatchHandlerMap[BB]; - assert(Action->getSelector() == ExpectedSelector); - } else { - // Since this is a catch-all handler, the selector won't actually appear - // in the code anywhere. ExpectedSelector here is the constant null ptr - // that we got from the landing pad instruction. - Action = new CatchHandler(BB, ExpectedSelector, nullptr); - CatchHandlerMap[BB] = Action; - } - Actions.insertCatchHandler(Action); - DEBUG(dbgs() << " Catch all handler at block " << BB->getName() << "\n"); - ++HandlersFound; - - // Once we reach a catch-all, don't expect to hit a resume instruction. - BB = nullptr; - break; - } - - CatchHandler *CatchAction = findCatchHandler(BB, NextBB, VisitedBlocks); - assert(CatchAction); +// TODO: improve store placement. Inserting at def is probably good, but need +// to be careful not to introduce interfering stores (needs liveness analysis). +// TODO: identify related phi nodes that can share spill slots, and share them +// (also needs liveness). +void WinEHPrepare::insertPHIStores(PHINode *OriginalPHI, + AllocaInst *SpillSlot) { + // Use a worklist of (Block, Value) pairs -- the given Value needs to be + // stored to the spill slot by the end of the given Block. + SmallVector, 4> Worklist; - // See if there is any interesting code executed before the dispatch. - findCleanupHandlers(Actions, BB, CatchAction->getStartBlock()); + Worklist.push_back({OriginalPHI->getParent(), OriginalPHI}); - // When the source program contains multiple nested try blocks the catch - // handlers can get strung together in such a way that we can encounter - // a dispatch for a selector that we've already had a handler for. - if (CatchAction->getSelector()->stripPointerCasts() == ExpectedSelector) { - ++HandlersFound; + while (!Worklist.empty()) { + BasicBlock *EHBlock; + Value *InVal; + std::tie(EHBlock, InVal) = Worklist.pop_back_val(); + + PHINode *PN = dyn_cast(InVal); + if (PN && PN->getParent() == EHBlock) { + // The value is defined by another PHI we need to remove, with no room to + // insert a store after the PHI, so each predecessor needs to store its + // incoming value. + for (unsigned i = 0, e = PN->getNumIncomingValues(); i < e; ++i) { + Value *PredVal = PN->getIncomingValue(i); + + // Undef can safely be skipped. + if (isa(PredVal)) + continue; - // Add the catch handler to the action list. - DEBUG(dbgs() << " Found catch dispatch in block " - << CatchAction->getStartBlock()->getName() << "\n"); - Actions.insertCatchHandler(CatchAction); + insertPHIStore(PN->getIncomingBlock(i), PredVal, SpillSlot, Worklist); + } } else { - // Under some circumstances optimized IR will flow unconditionally into a - // handler block without checking the selector. This can only happen if - // the landing pad has a catch-all handler and the handler for the - // preceeding catch clause is identical to the catch-call handler - // (typically an empty catch). In this case, the handler must be shared - // by all remaining clauses. - if (isa( - CatchAction->getSelector()->stripPointerCasts())) { - DEBUG(dbgs() << " Applying early catch-all handler in block " - << CatchAction->getStartBlock()->getName() - << " to all remaining clauses.\n"); - Actions.insertCatchHandler(CatchAction); - return; + // We need to store InVal, which dominates EHBlock, but can't put a store + // in EHBlock, so need to put stores in each predecessor. + for (BasicBlock *PredBlock : predecessors(EHBlock)) { + insertPHIStore(PredBlock, InVal, SpillSlot, Worklist); } - - DEBUG(dbgs() << " Found extra catch dispatch in block " - << CatchAction->getStartBlock()->getName() << "\n"); } - - // Move on to the block after the catch handler. - BB = NextBB; } - - // If we didn't wind up in a catch-all, see if there is any interesting code - // executed before the resume. - findCleanupHandlers(Actions, BB, BB); - - // It's possible that some optimization moved code into a landingpad that - // wasn't - // previously being used for cleanup. If that happens, we need to execute - // that - // extra code from a cleanup handler. - if (Actions.includesCleanup() && !LPad->isCleanup()) - LPad->setCleanup(true); } -// This function searches starting with the input block for the next -// block that terminates with a branch whose condition is based on a selector -// comparison. This may be the input block. See the mapLandingPadBlocks -// comments for a discussion of control flow assumptions. -// -CatchHandler *WinEHPrepare::findCatchHandler(BasicBlock *BB, - BasicBlock *&NextBB, - VisitedBlockSet &VisitedBlocks) { - // See if we've already found a catch handler use it. - // Call count() first to avoid creating a null entry for blocks - // we haven't seen before. - if (CatchHandlerMap.count(BB) && CatchHandlerMap[BB] != nullptr) { - CatchHandler *Action = cast(CatchHandlerMap[BB]); - NextBB = Action->getNextBB(); - return Action; - } +void WinEHPrepare::insertPHIStore( + BasicBlock *PredBlock, Value *PredVal, AllocaInst *SpillSlot, + SmallVectorImpl> &Worklist) { - // VisitedBlocks applies only to the current search. We still - // need to consider blocks that we've visited while mapping other - // landing pads. - VisitedBlocks.insert(BB); - - BasicBlock *CatchBlock = nullptr; - Constant *Selector = nullptr; - - // If this is the first time we've visited this block from any landing pad - // look to see if it is a selector dispatch block. - if (!CatchHandlerMap.count(BB)) { - if (isSelectorDispatch(BB, CatchBlock, Selector, NextBB)) { - CatchHandler *Action = new CatchHandler(BB, Selector, NextBB); - CatchHandlerMap[BB] = Action; - return Action; - } - // If we encounter a block containing an llvm.eh.begincatch before we - // find a selector dispatch block, the handler is assumed to be - // reached unconditionally. This happens for catch-all blocks, but - // it can also happen for other catch handlers that have been combined - // with the catch-all handler during optimization. - if (isCatchBlock(BB)) { - PointerType *Int8PtrTy = Type::getInt8PtrTy(BB->getContext()); - Constant *NullSelector = ConstantPointerNull::get(Int8PtrTy); - CatchHandler *Action = new CatchHandler(BB, NullSelector, nullptr); - CatchHandlerMap[BB] = Action; - return Action; - } + if (PredBlock->isEHPad() && + !isa(PredBlock->getFirstNonPHI())) { + // Pred is unsplittable, so we need to queue it on the worklist. + Worklist.push_back({PredBlock, PredVal}); + return; } - // Visit each successor, looking for the dispatch. - // FIXME: We expect to find the dispatch quickly, so this will probably - // work better as a breadth first search. - for (BasicBlock *Succ : successors(BB)) { - if (VisitedBlocks.count(Succ)) - continue; - - CatchHandler *Action = findCatchHandler(Succ, NextBB, VisitedBlocks); - if (Action) - return Action; - } - return nullptr; + // Otherwise, insert the store at the end of the basic block. + new StoreInst(PredVal, SpillSlot, PredBlock->getTerminator()); } -// These are helper functions to combine repeated code from findCleanupHandlers. -static void createCleanupHandler(LandingPadActions &Actions, - CleanupHandlerMapTy &CleanupHandlerMap, - BasicBlock *BB) { - CleanupHandler *Action = new CleanupHandler(BB); - CleanupHandlerMap[BB] = Action; - Actions.insertCleanupHandler(Action); - DEBUG(dbgs() << " Found cleanup code in block " - << Action->getStartBlock()->getName() << "\n"); -} +// TODO: Share loads for same-funclet uses (requires dominators if funclets +// aren't properly nested). +void WinEHPrepare::demoteNonlocalUses(Value *V, + std::set &ColorsForBB, + Function &F) { + // Tokens can only be used non-locally due to control flow involving + // unreachable edges. Don't try to demote the token usage, we'll simply + // delete the cloned user later. + if (isa(V) || isa(V)) + return; -static CallSite matchOutlinedFinallyCall(BasicBlock *BB, - Instruction *MaybeCall) { - // Look for finally blocks that Clang has already outlined for us. - // %fp = call i8* @llvm.frameaddress(i32 0) - // call void @"fin$parent"(iN 1, i8* %fp) - if (isFrameAddressCall(MaybeCall) && MaybeCall != BB->getTerminator()) - MaybeCall = MaybeCall->getNextNode(); - CallSite FinallyCall(MaybeCall); - if (!FinallyCall || FinallyCall.arg_size() != 2) - return CallSite(); - if (!match(FinallyCall.getArgument(0), m_SpecificInt(1))) - return CallSite(); - if (!isFrameAddressCall(FinallyCall.getArgument(1))) - return CallSite(); - return FinallyCall; -} + DenseMap Loads; + AllocaInst *SpillSlot = nullptr; + for (Value::use_iterator UI = V->use_begin(), UE = V->use_end(); UI != UE;) { + Use &U = *UI++; + auto *UsingInst = cast(U.getUser()); + BasicBlock *UsingBB = UsingInst->getParent(); + + // Is the Use inside a block which is colored the same as the Def? + // If so, we don't need to escape the Def because we will clone + // ourselves our own private copy. + std::set &ColorsForUsingBB = BlockColors[UsingBB]; + if (ColorsForUsingBB == ColorsForBB) + continue; -static BasicBlock *followSingleUnconditionalBranches(BasicBlock *BB) { - // Skip single ubr blocks. - while (BB->getFirstNonPHIOrDbg() == BB->getTerminator()) { - auto *Br = dyn_cast(BB->getTerminator()); - if (Br && Br->isUnconditional()) - BB = Br->getSuccessor(0); - else - return BB; + replaceUseWithLoad(V, U, SpillSlot, Loads, F); } - return BB; -} - -// This function searches starting with the input block for the next block that -// contains code that is not part of a catch handler and would not be eliminated -// during handler outlining. -// -void WinEHPrepare::findCleanupHandlers(LandingPadActions &Actions, - BasicBlock *StartBB, BasicBlock *EndBB) { - // Here we will skip over the following: - // - // landing pad prolog: - // - // Unconditional branches - // - // Selector dispatch - // - // Resume pattern - // - // Anything else marks the start of an interesting block - - BasicBlock *BB = StartBB; - // Anything other than an unconditional branch will kick us out of this loop - // one way or another. - while (BB) { - BB = followSingleUnconditionalBranches(BB); - // If we've already scanned this block, don't scan it again. If it is - // a cleanup block, there will be an action in the CleanupHandlerMap. - // If we've scanned it and it is not a cleanup block, there will be a - // nullptr in the CleanupHandlerMap. If we have not scanned it, there will - // be no entry in the CleanupHandlerMap. We must call count() first to - // avoid creating a null entry for blocks we haven't scanned. - if (CleanupHandlerMap.count(BB)) { - if (auto *Action = CleanupHandlerMap[BB]) { - Actions.insertCleanupHandler(Action); - DEBUG(dbgs() << " Found cleanup code in block " - << Action->getStartBlock()->getName() << "\n"); - // FIXME: This cleanup might chain into another, and we need to discover - // that. - return; - } else { - // Here we handle the case where the cleanup handler map contains a - // value for this block but the value is a nullptr. This means that - // we have previously analyzed the block and determined that it did - // not contain any cleanup code. Based on the earlier analysis, we - // know the the block must end in either an unconditional branch, a - // resume or a conditional branch that is predicated on a comparison - // with a selector. Either the resume or the selector dispatch - // would terminate the search for cleanup code, so the unconditional - // branch is the only case for which we might need to continue - // searching. - BasicBlock *SuccBB = followSingleUnconditionalBranches(BB); - if (SuccBB == BB || SuccBB == EndBB) - return; - BB = SuccBB; - continue; - } - } - - // Create an entry in the cleanup handler map for this block. Initially - // we create an entry that says this isn't a cleanup block. If we find - // cleanup code, the caller will replace this entry. - CleanupHandlerMap[BB] = nullptr; - - TerminatorInst *Terminator = BB->getTerminator(); - - // Landing pad blocks have extra instructions we need to accept. - LandingPadMap *LPadMap = nullptr; - if (BB->isLandingPad()) { - LandingPadInst *LPad = BB->getLandingPadInst(); - LPadMap = &LPadMaps[LPad]; - if (!LPadMap->isInitialized()) - LPadMap->mapLandingPad(LPad); - } - - // Look for the bare resume pattern: - // %lpad.val1 = insertvalue { i8*, i32 } undef, i8* %exn, 0 - // %lpad.val2 = insertvalue { i8*, i32 } %lpad.val1, i32 %sel, 1 - // resume { i8*, i32 } %lpad.val2 - if (auto *Resume = dyn_cast(Terminator)) { - InsertValueInst *Insert1 = nullptr; - InsertValueInst *Insert2 = nullptr; - Value *ResumeVal = Resume->getOperand(0); - // If the resume value isn't a phi or landingpad value, it should be a - // series of insertions. Identify them so we can avoid them when scanning - // for cleanups. - if (!isa(ResumeVal) && !isa(ResumeVal)) { - Insert2 = dyn_cast(ResumeVal); - if (!Insert2) - return createCleanupHandler(Actions, CleanupHandlerMap, BB); - Insert1 = dyn_cast(Insert2->getAggregateOperand()); - if (!Insert1) - return createCleanupHandler(Actions, CleanupHandlerMap, BB); - } - for (BasicBlock::iterator II = BB->getFirstNonPHIOrDbg(), IE = BB->end(); - II != IE; ++II) { - Instruction *Inst = II; - if (LPadMap && LPadMap->isLandingPadSpecificInst(Inst)) - continue; - if (Inst == Insert1 || Inst == Insert2 || Inst == Resume) - continue; - if (!Inst->hasOneUse() || - (Inst->user_back() != Insert1 && Inst->user_back() != Insert2)) { - return createCleanupHandler(Actions, CleanupHandlerMap, BB); - } - } - return; - } - - BranchInst *Branch = dyn_cast(Terminator); - if (Branch && Branch->isConditional()) { - // Look for the selector dispatch. - // %2 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIf to i8*)) - // %matches = icmp eq i32 %sel, %2 - // br i1 %matches, label %catch14, label %eh.resume - CmpInst *Compare = dyn_cast(Branch->getCondition()); - if (!Compare || !Compare->isEquality()) - return createCleanupHandler(Actions, CleanupHandlerMap, BB); - for (BasicBlock::iterator II = BB->getFirstNonPHIOrDbg(), IE = BB->end(); - II != IE; ++II) { - Instruction *Inst = II; - if (LPadMap && LPadMap->isLandingPadSpecificInst(Inst)) - continue; - if (Inst == Compare || Inst == Branch) - continue; - if (match(Inst, m_Intrinsic())) - continue; - return createCleanupHandler(Actions, CleanupHandlerMap, BB); - } - // The selector dispatch block should always terminate our search. - assert(BB == EndBB); - return; - } - - if (isAsynchronousEHPersonality(Personality)) { - // If this is a landingpad block, split the block at the first non-landing - // pad instruction. - Instruction *MaybeCall = BB->getFirstNonPHIOrDbg(); - if (LPadMap) { - while (MaybeCall != BB->getTerminator() && - LPadMap->isLandingPadSpecificInst(MaybeCall)) - MaybeCall = MaybeCall->getNextNode(); - } - - // Look for outlined finally calls. - if (CallSite FinallyCall = matchOutlinedFinallyCall(BB, MaybeCall)) { - Function *Fin = FinallyCall.getCalledFunction(); - assert(Fin && "outlined finally call should be direct"); - auto *Action = new CleanupHandler(BB); - Action->setHandlerBlockOrFunc(Fin); - Actions.insertCleanupHandler(Action); - CleanupHandlerMap[BB] = Action; - DEBUG(dbgs() << " Found frontend-outlined finally call to " - << Fin->getName() << " in block " - << Action->getStartBlock()->getName() << "\n"); - - // Split the block if there were more interesting instructions and look - // for finally calls in the normal successor block. - BasicBlock *SuccBB = BB; - if (FinallyCall.getInstruction() != BB->getTerminator() && - FinallyCall.getInstruction()->getNextNode() != BB->getTerminator()) { - SuccBB = BB->splitBasicBlock(FinallyCall.getInstruction()->getNextNode()); - } else { - if (FinallyCall.isInvoke()) { - SuccBB = cast(FinallyCall.getInstruction())->getNormalDest(); - } else { - SuccBB = BB->getUniqueSuccessor(); - assert(SuccBB && "splitOutlinedFinallyCalls didn't insert a branch"); - } - } - BB = SuccBB; - if (BB == EndBB) - return; - continue; + if (SpillSlot) { + // Insert stores of the computed value into the stack slot. + // We have to be careful if I is an invoke instruction, + // because we can't insert the store AFTER the terminator instruction. + BasicBlock::iterator InsertPt; + if (isa(V)) { + InsertPt = F.getEntryBlock().getTerminator()->getIterator(); + } else if (isa(V)) { + auto *II = cast(V); + // We cannot demote invoke instructions to the stack if their normal + // edge is critical. Therefore, split the critical edge and create a + // basic block into which the store can be inserted. + if (!II->getNormalDest()->getSinglePredecessor()) { + unsigned SuccNum = + GetSuccessorNumber(II->getParent(), II->getNormalDest()); + assert(isCriticalEdge(II, SuccNum) && "Expected a critical edge!"); + BasicBlock *NewBlock = SplitCriticalEdge(II, SuccNum); + assert(NewBlock && "Unable to split critical edge."); + // Update the color mapping for the newly split edge. + std::set &ColorsForUsingBB = BlockColors[II->getParent()]; + BlockColors[NewBlock] = ColorsForUsingBB; + for (BasicBlock *FuncletPad : ColorsForUsingBB) + FuncletBlocks[FuncletPad].insert(NewBlock); } + InsertPt = II->getNormalDest()->getFirstInsertionPt(); + } else { + InsertPt = cast(V)->getIterator(); + ++InsertPt; + // Don't insert before PHI nodes or EH pad instrs. + for (; isa(InsertPt) || InsertPt->isEHPad(); ++InsertPt) + ; } + new StoreInst(V, SpillSlot, &*InsertPt); + } +} - // Anything else is either a catch block or interesting cleanup code. - for (BasicBlock::iterator II = BB->getFirstNonPHIOrDbg(), IE = BB->end(); - II != IE; ++II) { - Instruction *Inst = II; - if (LPadMap && LPadMap->isLandingPadSpecificInst(Inst)) - continue; - // Unconditional branches fall through to this loop. - if (Inst == Branch) - continue; - // If this is a catch block, there is no cleanup code to be found. - if (match(Inst, m_Intrinsic())) - return; - // If this a nested landing pad, it may contain an endcatch call. - if (match(Inst, m_Intrinsic())) - return; - // Anything else makes this interesting cleanup code. - return createCleanupHandler(Actions, CleanupHandlerMap, BB); +void WinEHPrepare::replaceUseWithLoad(Value *V, Use &U, AllocaInst *&SpillSlot, + DenseMap &Loads, + Function &F) { + // Lazilly create the spill slot. + if (!SpillSlot) + SpillSlot = new AllocaInst(V->getType(), nullptr, + Twine(V->getName(), ".wineh.spillslot"), + &F.getEntryBlock().front()); + + auto *UsingInst = cast(U.getUser()); + if (auto *UsingPHI = dyn_cast(UsingInst)) { + // If this is a PHI node, we can't insert a load of the value before + // the use. Instead insert the load in the predecessor block + // corresponding to the incoming value. + // + // Note that if there are multiple edges from a basic block to this + // PHI node that we cannot have multiple loads. The problem is that + // the resulting PHI node will have multiple values (from each load) + // coming in from the same block, which is illegal SSA form. + // For this reason, we keep track of and reuse loads we insert. + BasicBlock *IncomingBlock = UsingPHI->getIncomingBlock(U); + if (auto *CatchRet = + dyn_cast(IncomingBlock->getTerminator())) { + // Putting a load above a catchret and use on the phi would still leave + // a cross-funclet def/use. We need to split the edge, change the + // catchret to target the new block, and put the load there. + BasicBlock *PHIBlock = UsingInst->getParent(); + BasicBlock *NewBlock = SplitEdge(IncomingBlock, PHIBlock); + // SplitEdge gives us: + // IncomingBlock: + // ... + // br label %NewBlock + // NewBlock: + // catchret label %PHIBlock + // But we need: + // IncomingBlock: + // ... + // catchret label %NewBlock + // NewBlock: + // br label %PHIBlock + // So move the terminators to each others' blocks and swap their + // successors. + BranchInst *Goto = cast(IncomingBlock->getTerminator()); + Goto->removeFromParent(); + CatchRet->removeFromParent(); + IncomingBlock->getInstList().push_back(CatchRet); + NewBlock->getInstList().push_back(Goto); + Goto->setSuccessor(0, PHIBlock); + CatchRet->setSuccessor(NewBlock); + // Update the color mapping for the newly split edge. + std::set &ColorsForPHIBlock = BlockColors[PHIBlock]; + BlockColors[NewBlock] = ColorsForPHIBlock; + for (BasicBlock *FuncletPad : ColorsForPHIBlock) + FuncletBlocks[FuncletPad].insert(NewBlock); + // Treat the new block as incoming for load insertion. + IncomingBlock = NewBlock; } + Value *&Load = Loads[IncomingBlock]; + // Insert the load into the predecessor block + if (!Load) + Load = new LoadInst(SpillSlot, Twine(V->getName(), ".wineh.reload"), + /*Volatile=*/false, IncomingBlock->getTerminator()); - // Only unconditional branches in empty blocks should get this far. - assert(Branch && Branch->isUnconditional()); - if (BB == EndBB) - return; - BB = Branch->getSuccessor(0); + U.set(Load); + } else { + // Reload right before the old use. + auto *Load = new LoadInst(SpillSlot, Twine(V->getName(), ".wineh.reload"), + /*Volatile=*/false, UsingInst); + U.set(Load); } } -// This is a public function, declared in WinEHFuncInfo.h and is also -// referenced by WinEHNumbering in FunctionLoweringInfo.cpp. -void llvm::parseEHActions(const IntrinsicInst *II, - SmallVectorImpl &Actions) { - for (unsigned I = 0, E = II->getNumArgOperands(); I != E;) { - uint64_t ActionKind = - cast(II->getArgOperand(I))->getZExtValue(); - if (ActionKind == /*catch=*/1) { - auto *Selector = cast(II->getArgOperand(I + 1)); - ConstantInt *EHObjIndex = cast(II->getArgOperand(I + 2)); - int64_t EHObjIndexVal = EHObjIndex->getSExtValue(); - Constant *Handler = cast(II->getArgOperand(I + 3)); - I += 4; - auto *CH = new CatchHandler(/*BB=*/nullptr, Selector, /*NextBB=*/nullptr); - CH->setHandlerBlockOrFunc(Handler); - CH->setExceptionVarIndex(EHObjIndexVal); - Actions.push_back(CH); - } else if (ActionKind == 0) { - Constant *Handler = cast(II->getArgOperand(I + 1)); - I += 2; - auto *CH = new CleanupHandler(/*BB=*/nullptr); - CH->setHandlerBlockOrFunc(Handler); - Actions.push_back(CH); - } else { - llvm_unreachable("Expected either a catch or cleanup handler!"); - } - } - std::reverse(Actions.begin(), Actions.end()); +void WinEHFuncInfo::addIPToStateRange(const BasicBlock *PadBB, + MCSymbol *InvokeBegin, + MCSymbol *InvokeEnd) { + assert(PadBB->isEHPad() && EHPadStateMap.count(PadBB->getFirstNonPHI()) && + "should get EH pad BB with precomputed state"); + InvokeToStateMap[InvokeBegin] = + std::make_pair(EHPadStateMap[PadBB->getFirstNonPHI()], InvokeEnd); }