10b57cec5SDimitry Andric //===-- WinEHPrepare - Prepare exception handling for code generation ---===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This pass lowers LLVM IR exception handling into something closer to what the 100b57cec5SDimitry Andric // backend wants for functions using a personality function from a runtime 110b57cec5SDimitry Andric // provided by MSVC. Functions with other personality functions are left alone 120b57cec5SDimitry Andric // and may be prepared by other passes. In particular, all supported MSVC 130b57cec5SDimitry Andric // personality functions require cleanup code to be outlined, and the C++ 140b57cec5SDimitry Andric // personality requires catch handler code to be outlined. 150b57cec5SDimitry Andric // 160b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 170b57cec5SDimitry Andric 185f757f3fSDimitry Andric #include "llvm/CodeGen/WinEHPrepare.h" 190b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h" 200b57cec5SDimitry Andric #include "llvm/ADT/MapVector.h" 210b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 220b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h" 230b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h" 240b57cec5SDimitry Andric #include "llvm/CodeGen/WinEHFuncInfo.h" 2581ad6265SDimitry Andric #include "llvm/IR/Constants.h" 2606c3fb27SDimitry Andric #include "llvm/IR/EHPersonalities.h" 2781ad6265SDimitry Andric #include "llvm/IR/Instructions.h" 28*0fca6ea1SDimitry Andric #include "llvm/IR/Module.h" 290b57cec5SDimitry Andric #include "llvm/IR/Verifier.h" 30480093f4SDimitry Andric #include "llvm/InitializePasses.h" 310b57cec5SDimitry Andric #include "llvm/Pass.h" 32480093f4SDimitry Andric #include "llvm/Support/CommandLine.h" 330b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 340b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 3506c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h" 360b57cec5SDimitry Andric #include "llvm/Transforms/Utils/BasicBlockUtils.h" 370b57cec5SDimitry Andric #include "llvm/Transforms/Utils/Cloning.h" 38480093f4SDimitry Andric #include "llvm/Transforms/Utils/Local.h" 390b57cec5SDimitry Andric #include "llvm/Transforms/Utils/SSAUpdater.h" 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric using namespace llvm; 420b57cec5SDimitry Andric 435f757f3fSDimitry Andric #define DEBUG_TYPE "win-eh-prepare" 440b57cec5SDimitry Andric 450b57cec5SDimitry Andric static cl::opt<bool> DisableDemotion( 460b57cec5SDimitry Andric "disable-demotion", cl::Hidden, 470b57cec5SDimitry Andric cl::desc( 480b57cec5SDimitry Andric "Clone multicolor basic blocks but do not demote cross scopes"), 490b57cec5SDimitry Andric cl::init(false)); 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric static cl::opt<bool> DisableCleanups( 520b57cec5SDimitry Andric "disable-cleanups", cl::Hidden, 530b57cec5SDimitry Andric cl::desc("Do not remove implausible terminators or other similar cleanups"), 540b57cec5SDimitry Andric cl::init(false)); 550b57cec5SDimitry Andric 565f757f3fSDimitry Andric // TODO: Remove this option when we fully migrate to new pass manager 570b57cec5SDimitry Andric static cl::opt<bool> DemoteCatchSwitchPHIOnlyOpt( 580b57cec5SDimitry Andric "demote-catchswitch-only", cl::Hidden, 590b57cec5SDimitry Andric cl::desc("Demote catchswitch BBs only (for wasm EH)"), cl::init(false)); 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric namespace { 620b57cec5SDimitry Andric 635f757f3fSDimitry Andric class WinEHPrepareImpl { 640b57cec5SDimitry Andric public: 655f757f3fSDimitry Andric WinEHPrepareImpl(bool DemoteCatchSwitchPHIOnly) 665f757f3fSDimitry Andric : DemoteCatchSwitchPHIOnly(DemoteCatchSwitchPHIOnly) {} 670b57cec5SDimitry Andric 685f757f3fSDimitry Andric bool runOnFunction(Function &Fn); 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric private: 710b57cec5SDimitry Andric void insertPHIStores(PHINode *OriginalPHI, AllocaInst *SpillSlot); 720b57cec5SDimitry Andric void 730b57cec5SDimitry Andric insertPHIStore(BasicBlock *PredBlock, Value *PredVal, AllocaInst *SpillSlot, 740b57cec5SDimitry Andric SmallVectorImpl<std::pair<BasicBlock *, Value *>> &Worklist); 750b57cec5SDimitry Andric AllocaInst *insertPHILoads(PHINode *PN, Function &F); 760b57cec5SDimitry Andric void replaceUseWithLoad(Value *V, Use &U, AllocaInst *&SpillSlot, 770b57cec5SDimitry Andric DenseMap<BasicBlock *, Value *> &Loads, Function &F); 780b57cec5SDimitry Andric bool prepareExplicitEH(Function &F); 790b57cec5SDimitry Andric void colorFunclets(Function &F); 800b57cec5SDimitry Andric 810b57cec5SDimitry Andric void demotePHIsOnFunclets(Function &F, bool DemoteCatchSwitchPHIOnly); 820b57cec5SDimitry Andric void cloneCommonBlocks(Function &F); 830b57cec5SDimitry Andric void removeImplausibleInstructions(Function &F); 840b57cec5SDimitry Andric void cleanupPreparedFunclets(Function &F); 850b57cec5SDimitry Andric void verifyPreparedFunclets(Function &F); 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric bool DemoteCatchSwitchPHIOnly; 880b57cec5SDimitry Andric 890b57cec5SDimitry Andric // All fields are reset by runOnFunction. 900b57cec5SDimitry Andric EHPersonality Personality = EHPersonality::Unknown; 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric const DataLayout *DL = nullptr; 930b57cec5SDimitry Andric DenseMap<BasicBlock *, ColorVector> BlockColors; 940b57cec5SDimitry Andric MapVector<BasicBlock *, std::vector<BasicBlock *>> FuncletBlocks; 950b57cec5SDimitry Andric }; 960b57cec5SDimitry Andric 975f757f3fSDimitry Andric class WinEHPrepare : public FunctionPass { 985f757f3fSDimitry Andric bool DemoteCatchSwitchPHIOnly; 995f757f3fSDimitry Andric 1005f757f3fSDimitry Andric public: 1015f757f3fSDimitry Andric static char ID; // Pass identification, replacement for typeid. 1025f757f3fSDimitry Andric 1035f757f3fSDimitry Andric WinEHPrepare(bool DemoteCatchSwitchPHIOnly = false) 1045f757f3fSDimitry Andric : FunctionPass(ID), DemoteCatchSwitchPHIOnly(DemoteCatchSwitchPHIOnly) {} 1055f757f3fSDimitry Andric 1065f757f3fSDimitry Andric StringRef getPassName() const override { 1075f757f3fSDimitry Andric return "Windows exception handling preparation"; 1085f757f3fSDimitry Andric } 1095f757f3fSDimitry Andric 1105f757f3fSDimitry Andric bool runOnFunction(Function &Fn) override { 1115f757f3fSDimitry Andric return WinEHPrepareImpl(DemoteCatchSwitchPHIOnly).runOnFunction(Fn); 1125f757f3fSDimitry Andric } 1135f757f3fSDimitry Andric }; 1145f757f3fSDimitry Andric 1150b57cec5SDimitry Andric } // end anonymous namespace 1160b57cec5SDimitry Andric 1175f757f3fSDimitry Andric PreservedAnalyses WinEHPreparePass::run(Function &F, 1185f757f3fSDimitry Andric FunctionAnalysisManager &) { 1195f757f3fSDimitry Andric bool Changed = WinEHPrepareImpl(DemoteCatchSwitchPHIOnly).runOnFunction(F); 1205f757f3fSDimitry Andric return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all(); 1215f757f3fSDimitry Andric } 1225f757f3fSDimitry Andric 1230b57cec5SDimitry Andric char WinEHPrepare::ID = 0; 1245f757f3fSDimitry Andric INITIALIZE_PASS(WinEHPrepare, DEBUG_TYPE, "Prepare Windows exceptions", false, 1255f757f3fSDimitry Andric false) 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric FunctionPass *llvm::createWinEHPass(bool DemoteCatchSwitchPHIOnly) { 1280b57cec5SDimitry Andric return new WinEHPrepare(DemoteCatchSwitchPHIOnly); 1290b57cec5SDimitry Andric } 1300b57cec5SDimitry Andric 1315f757f3fSDimitry Andric bool WinEHPrepareImpl::runOnFunction(Function &Fn) { 1320b57cec5SDimitry Andric if (!Fn.hasPersonalityFn()) 1330b57cec5SDimitry Andric return false; 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric // Classify the personality to see what kind of preparation we need. 1360b57cec5SDimitry Andric Personality = classifyEHPersonality(Fn.getPersonalityFn()); 1370b57cec5SDimitry Andric 1380b57cec5SDimitry Andric // Do nothing if this is not a scope-based personality. 1390b57cec5SDimitry Andric if (!isScopedEHPersonality(Personality)) 1400b57cec5SDimitry Andric return false; 1410b57cec5SDimitry Andric 142*0fca6ea1SDimitry Andric DL = &Fn.getDataLayout(); 1430b57cec5SDimitry Andric return prepareExplicitEH(Fn); 1440b57cec5SDimitry Andric } 1450b57cec5SDimitry Andric 1460b57cec5SDimitry Andric static int addUnwindMapEntry(WinEHFuncInfo &FuncInfo, int ToState, 1470b57cec5SDimitry Andric const BasicBlock *BB) { 1480b57cec5SDimitry Andric CxxUnwindMapEntry UME; 1490b57cec5SDimitry Andric UME.ToState = ToState; 1500b57cec5SDimitry Andric UME.Cleanup = BB; 1510b57cec5SDimitry Andric FuncInfo.CxxUnwindMap.push_back(UME); 1520b57cec5SDimitry Andric return FuncInfo.getLastStateNumber(); 1530b57cec5SDimitry Andric } 1540b57cec5SDimitry Andric 1550b57cec5SDimitry Andric static void addTryBlockMapEntry(WinEHFuncInfo &FuncInfo, int TryLow, 1560b57cec5SDimitry Andric int TryHigh, int CatchHigh, 1570b57cec5SDimitry Andric ArrayRef<const CatchPadInst *> Handlers) { 1580b57cec5SDimitry Andric WinEHTryBlockMapEntry TBME; 1590b57cec5SDimitry Andric TBME.TryLow = TryLow; 1600b57cec5SDimitry Andric TBME.TryHigh = TryHigh; 1610b57cec5SDimitry Andric TBME.CatchHigh = CatchHigh; 1620b57cec5SDimitry Andric assert(TBME.TryLow <= TBME.TryHigh); 1630b57cec5SDimitry Andric for (const CatchPadInst *CPI : Handlers) { 1640b57cec5SDimitry Andric WinEHHandlerType HT; 1650b57cec5SDimitry Andric Constant *TypeInfo = cast<Constant>(CPI->getArgOperand(0)); 1660b57cec5SDimitry Andric if (TypeInfo->isNullValue()) 1670b57cec5SDimitry Andric HT.TypeDescriptor = nullptr; 1680b57cec5SDimitry Andric else 1690b57cec5SDimitry Andric HT.TypeDescriptor = cast<GlobalVariable>(TypeInfo->stripPointerCasts()); 1700b57cec5SDimitry Andric HT.Adjectives = cast<ConstantInt>(CPI->getArgOperand(1))->getZExtValue(); 1710b57cec5SDimitry Andric HT.Handler = CPI->getParent(); 1720b57cec5SDimitry Andric if (auto *AI = 1730b57cec5SDimitry Andric dyn_cast<AllocaInst>(CPI->getArgOperand(2)->stripPointerCasts())) 1740b57cec5SDimitry Andric HT.CatchObj.Alloca = AI; 1750b57cec5SDimitry Andric else 1760b57cec5SDimitry Andric HT.CatchObj.Alloca = nullptr; 1770b57cec5SDimitry Andric TBME.HandlerArray.push_back(HT); 1780b57cec5SDimitry Andric } 1790b57cec5SDimitry Andric FuncInfo.TryBlockMap.push_back(TBME); 1800b57cec5SDimitry Andric } 1810b57cec5SDimitry Andric 1820b57cec5SDimitry Andric static BasicBlock *getCleanupRetUnwindDest(const CleanupPadInst *CleanupPad) { 1830b57cec5SDimitry Andric for (const User *U : CleanupPad->users()) 1840b57cec5SDimitry Andric if (const auto *CRI = dyn_cast<CleanupReturnInst>(U)) 1850b57cec5SDimitry Andric return CRI->getUnwindDest(); 1860b57cec5SDimitry Andric return nullptr; 1870b57cec5SDimitry Andric } 1880b57cec5SDimitry Andric 1890b57cec5SDimitry Andric static void calculateStateNumbersForInvokes(const Function *Fn, 1900b57cec5SDimitry Andric WinEHFuncInfo &FuncInfo) { 1910b57cec5SDimitry Andric auto *F = const_cast<Function *>(Fn); 1920b57cec5SDimitry Andric DenseMap<BasicBlock *, ColorVector> BlockColors = colorEHFunclets(*F); 1930b57cec5SDimitry Andric for (BasicBlock &BB : *F) { 1940b57cec5SDimitry Andric auto *II = dyn_cast<InvokeInst>(BB.getTerminator()); 1950b57cec5SDimitry Andric if (!II) 1960b57cec5SDimitry Andric continue; 1970b57cec5SDimitry Andric 1980b57cec5SDimitry Andric auto &BBColors = BlockColors[&BB]; 1990b57cec5SDimitry Andric assert(BBColors.size() == 1 && "multi-color BB not removed by preparation"); 2000b57cec5SDimitry Andric BasicBlock *FuncletEntryBB = BBColors.front(); 2010b57cec5SDimitry Andric 2020b57cec5SDimitry Andric BasicBlock *FuncletUnwindDest; 2030b57cec5SDimitry Andric auto *FuncletPad = 2040b57cec5SDimitry Andric dyn_cast<FuncletPadInst>(FuncletEntryBB->getFirstNonPHI()); 2050b57cec5SDimitry Andric assert(FuncletPad || FuncletEntryBB == &Fn->getEntryBlock()); 2060b57cec5SDimitry Andric if (!FuncletPad) 2070b57cec5SDimitry Andric FuncletUnwindDest = nullptr; 2080b57cec5SDimitry Andric else if (auto *CatchPad = dyn_cast<CatchPadInst>(FuncletPad)) 2090b57cec5SDimitry Andric FuncletUnwindDest = CatchPad->getCatchSwitch()->getUnwindDest(); 2100b57cec5SDimitry Andric else if (auto *CleanupPad = dyn_cast<CleanupPadInst>(FuncletPad)) 2110b57cec5SDimitry Andric FuncletUnwindDest = getCleanupRetUnwindDest(CleanupPad); 2120b57cec5SDimitry Andric else 2130b57cec5SDimitry Andric llvm_unreachable("unexpected funclet pad!"); 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric BasicBlock *InvokeUnwindDest = II->getUnwindDest(); 2160b57cec5SDimitry Andric int BaseState = -1; 2170b57cec5SDimitry Andric if (FuncletUnwindDest == InvokeUnwindDest) { 2180b57cec5SDimitry Andric auto BaseStateI = FuncInfo.FuncletBaseStateMap.find(FuncletPad); 2190b57cec5SDimitry Andric if (BaseStateI != FuncInfo.FuncletBaseStateMap.end()) 2200b57cec5SDimitry Andric BaseState = BaseStateI->second; 2210b57cec5SDimitry Andric } 2220b57cec5SDimitry Andric 2230b57cec5SDimitry Andric if (BaseState != -1) { 2240b57cec5SDimitry Andric FuncInfo.InvokeStateMap[II] = BaseState; 2250b57cec5SDimitry Andric } else { 2260b57cec5SDimitry Andric Instruction *PadInst = InvokeUnwindDest->getFirstNonPHI(); 2270b57cec5SDimitry Andric assert(FuncInfo.EHPadStateMap.count(PadInst) && "EH Pad has no state!"); 2280b57cec5SDimitry Andric FuncInfo.InvokeStateMap[II] = FuncInfo.EHPadStateMap[PadInst]; 2290b57cec5SDimitry Andric } 2300b57cec5SDimitry Andric } 2310b57cec5SDimitry Andric } 2320b57cec5SDimitry Andric 23306c3fb27SDimitry Andric // See comments below for calculateSEHStateForAsynchEH(). 23406c3fb27SDimitry Andric // State - incoming State of normal paths 23506c3fb27SDimitry Andric struct WorkItem { 23606c3fb27SDimitry Andric const BasicBlock *Block; 23706c3fb27SDimitry Andric int State; 23806c3fb27SDimitry Andric WorkItem(const BasicBlock *BB, int St) { 23906c3fb27SDimitry Andric Block = BB; 24006c3fb27SDimitry Andric State = St; 24106c3fb27SDimitry Andric } 24206c3fb27SDimitry Andric }; 24306c3fb27SDimitry Andric void llvm::calculateCXXStateForAsynchEH(const BasicBlock *BB, int State, 24406c3fb27SDimitry Andric WinEHFuncInfo &EHInfo) { 24506c3fb27SDimitry Andric SmallVector<struct WorkItem *, 8> WorkList; 24606c3fb27SDimitry Andric struct WorkItem *WI = new WorkItem(BB, State); 24706c3fb27SDimitry Andric WorkList.push_back(WI); 24806c3fb27SDimitry Andric 24906c3fb27SDimitry Andric while (!WorkList.empty()) { 25006c3fb27SDimitry Andric WI = WorkList.pop_back_val(); 25106c3fb27SDimitry Andric const BasicBlock *BB = WI->Block; 25206c3fb27SDimitry Andric int State = WI->State; 25306c3fb27SDimitry Andric delete WI; 25406c3fb27SDimitry Andric if (EHInfo.BlockToStateMap.count(BB) && EHInfo.BlockToStateMap[BB] <= State) 25506c3fb27SDimitry Andric continue; // skip blocks already visited by lower State 25606c3fb27SDimitry Andric 25706c3fb27SDimitry Andric const llvm::Instruction *I = BB->getFirstNonPHI(); 25806c3fb27SDimitry Andric const llvm::Instruction *TI = BB->getTerminator(); 25906c3fb27SDimitry Andric if (I->isEHPad()) 26006c3fb27SDimitry Andric State = EHInfo.EHPadStateMap[I]; 26106c3fb27SDimitry Andric EHInfo.BlockToStateMap[BB] = State; // Record state, also flag visiting 26206c3fb27SDimitry Andric 26306c3fb27SDimitry Andric if ((isa<CleanupReturnInst>(TI) || isa<CatchReturnInst>(TI)) && State > 0) { 26406c3fb27SDimitry Andric // Retrive the new State 26506c3fb27SDimitry Andric State = EHInfo.CxxUnwindMap[State].ToState; // Retrive next State 26606c3fb27SDimitry Andric } else if (isa<InvokeInst>(TI)) { 26706c3fb27SDimitry Andric auto *Call = cast<CallBase>(TI); 26806c3fb27SDimitry Andric const Function *Fn = Call->getCalledFunction(); 26906c3fb27SDimitry Andric if (Fn && Fn->isIntrinsic() && 27006c3fb27SDimitry Andric (Fn->getIntrinsicID() == Intrinsic::seh_scope_begin || 27106c3fb27SDimitry Andric Fn->getIntrinsicID() == Intrinsic::seh_try_begin)) 27206c3fb27SDimitry Andric // Retrive the new State from seh_scope_begin 27306c3fb27SDimitry Andric State = EHInfo.InvokeStateMap[cast<InvokeInst>(TI)]; 27406c3fb27SDimitry Andric else if (Fn && Fn->isIntrinsic() && 27506c3fb27SDimitry Andric (Fn->getIntrinsicID() == Intrinsic::seh_scope_end || 27606c3fb27SDimitry Andric Fn->getIntrinsicID() == Intrinsic::seh_try_end)) { 27706c3fb27SDimitry Andric // In case of conditional ctor, let's retrieve State from Invoke 27806c3fb27SDimitry Andric State = EHInfo.InvokeStateMap[cast<InvokeInst>(TI)]; 27906c3fb27SDimitry Andric // end of current state, retrive new state from UnwindMap 28006c3fb27SDimitry Andric State = EHInfo.CxxUnwindMap[State].ToState; 28106c3fb27SDimitry Andric } 28206c3fb27SDimitry Andric } 28306c3fb27SDimitry Andric // Continue push successors into worklist 28406c3fb27SDimitry Andric for (auto *SuccBB : successors(BB)) { 28506c3fb27SDimitry Andric WI = new WorkItem(SuccBB, State); 28606c3fb27SDimitry Andric WorkList.push_back(WI); 28706c3fb27SDimitry Andric } 28806c3fb27SDimitry Andric } 28906c3fb27SDimitry Andric } 29006c3fb27SDimitry Andric 29106c3fb27SDimitry Andric // The central theory of this routine is based on the following: 29206c3fb27SDimitry Andric // A _try scope is always a SEME (Single Entry Multiple Exits) region 29306c3fb27SDimitry Andric // as jumping into a _try is not allowed 29406c3fb27SDimitry Andric // The single entry must start with a seh_try_begin() invoke with a 29506c3fb27SDimitry Andric // correct State number that is the initial state of the SEME. 29606c3fb27SDimitry Andric // Through control-flow, state number is propagated into all blocks. 29706c3fb27SDimitry Andric // Side exits marked by seh_try_end() will unwind to parent state via 29806c3fb27SDimitry Andric // existing SEHUnwindMap[]. 29906c3fb27SDimitry Andric // Side exits can ONLY jump into parent scopes (lower state number). 30006c3fb27SDimitry Andric // Thus, when a block succeeds various states from its predecessors, 30106c3fb27SDimitry Andric // the lowest State trumphs others. 30206c3fb27SDimitry Andric // If some exits flow to unreachable, propagation on those paths terminate, 30306c3fb27SDimitry Andric // not affecting remaining blocks. 30406c3fb27SDimitry Andric void llvm::calculateSEHStateForAsynchEH(const BasicBlock *BB, int State, 30506c3fb27SDimitry Andric WinEHFuncInfo &EHInfo) { 30606c3fb27SDimitry Andric SmallVector<struct WorkItem *, 8> WorkList; 30706c3fb27SDimitry Andric struct WorkItem *WI = new WorkItem(BB, State); 30806c3fb27SDimitry Andric WorkList.push_back(WI); 30906c3fb27SDimitry Andric 31006c3fb27SDimitry Andric while (!WorkList.empty()) { 31106c3fb27SDimitry Andric WI = WorkList.pop_back_val(); 31206c3fb27SDimitry Andric const BasicBlock *BB = WI->Block; 31306c3fb27SDimitry Andric int State = WI->State; 31406c3fb27SDimitry Andric delete WI; 31506c3fb27SDimitry Andric if (EHInfo.BlockToStateMap.count(BB) && EHInfo.BlockToStateMap[BB] <= State) 31606c3fb27SDimitry Andric continue; // skip blocks already visited by lower State 31706c3fb27SDimitry Andric 31806c3fb27SDimitry Andric const llvm::Instruction *I = BB->getFirstNonPHI(); 31906c3fb27SDimitry Andric const llvm::Instruction *TI = BB->getTerminator(); 32006c3fb27SDimitry Andric if (I->isEHPad()) 32106c3fb27SDimitry Andric State = EHInfo.EHPadStateMap[I]; 32206c3fb27SDimitry Andric EHInfo.BlockToStateMap[BB] = State; // Record state 32306c3fb27SDimitry Andric 32406c3fb27SDimitry Andric if (isa<CatchPadInst>(I) && isa<CatchReturnInst>(TI)) { 32506c3fb27SDimitry Andric const Constant *FilterOrNull = cast<Constant>( 32606c3fb27SDimitry Andric cast<CatchPadInst>(I)->getArgOperand(0)->stripPointerCasts()); 32706c3fb27SDimitry Andric const Function *Filter = dyn_cast<Function>(FilterOrNull); 3285f757f3fSDimitry Andric if (!Filter || !Filter->getName().starts_with("__IsLocalUnwind")) 32906c3fb27SDimitry Andric State = EHInfo.SEHUnwindMap[State].ToState; // Retrive next State 33006c3fb27SDimitry Andric } else if ((isa<CleanupReturnInst>(TI) || isa<CatchReturnInst>(TI)) && 33106c3fb27SDimitry Andric State > 0) { 33206c3fb27SDimitry Andric // Retrive the new State. 33306c3fb27SDimitry Andric State = EHInfo.SEHUnwindMap[State].ToState; // Retrive next State 33406c3fb27SDimitry Andric } else if (isa<InvokeInst>(TI)) { 33506c3fb27SDimitry Andric auto *Call = cast<CallBase>(TI); 33606c3fb27SDimitry Andric const Function *Fn = Call->getCalledFunction(); 33706c3fb27SDimitry Andric if (Fn && Fn->isIntrinsic() && 33806c3fb27SDimitry Andric Fn->getIntrinsicID() == Intrinsic::seh_try_begin) 33906c3fb27SDimitry Andric // Retrive the new State from seh_try_begin 34006c3fb27SDimitry Andric State = EHInfo.InvokeStateMap[cast<InvokeInst>(TI)]; 34106c3fb27SDimitry Andric else if (Fn && Fn->isIntrinsic() && 34206c3fb27SDimitry Andric Fn->getIntrinsicID() == Intrinsic::seh_try_end) 34306c3fb27SDimitry Andric // end of current state, retrive new state from UnwindMap 34406c3fb27SDimitry Andric State = EHInfo.SEHUnwindMap[State].ToState; 34506c3fb27SDimitry Andric } 34606c3fb27SDimitry Andric // Continue push successors into worklist 34706c3fb27SDimitry Andric for (auto *SuccBB : successors(BB)) { 34806c3fb27SDimitry Andric WI = new WorkItem(SuccBB, State); 34906c3fb27SDimitry Andric WorkList.push_back(WI); 35006c3fb27SDimitry Andric } 35106c3fb27SDimitry Andric } 35206c3fb27SDimitry Andric } 35306c3fb27SDimitry Andric 3540b57cec5SDimitry Andric // Given BB which ends in an unwind edge, return the EHPad that this BB belongs 3550b57cec5SDimitry Andric // to. If the unwind edge came from an invoke, return null. 3560b57cec5SDimitry Andric static const BasicBlock *getEHPadFromPredecessor(const BasicBlock *BB, 3570b57cec5SDimitry Andric Value *ParentPad) { 3580b57cec5SDimitry Andric const Instruction *TI = BB->getTerminator(); 3590b57cec5SDimitry Andric if (isa<InvokeInst>(TI)) 3600b57cec5SDimitry Andric return nullptr; 3610b57cec5SDimitry Andric if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(TI)) { 3620b57cec5SDimitry Andric if (CatchSwitch->getParentPad() != ParentPad) 3630b57cec5SDimitry Andric return nullptr; 3640b57cec5SDimitry Andric return BB; 3650b57cec5SDimitry Andric } 3660b57cec5SDimitry Andric assert(!TI->isEHPad() && "unexpected EHPad!"); 3670b57cec5SDimitry Andric auto *CleanupPad = cast<CleanupReturnInst>(TI)->getCleanupPad(); 3680b57cec5SDimitry Andric if (CleanupPad->getParentPad() != ParentPad) 3690b57cec5SDimitry Andric return nullptr; 3700b57cec5SDimitry Andric return CleanupPad->getParent(); 3710b57cec5SDimitry Andric } 3720b57cec5SDimitry Andric 3735ffd83dbSDimitry Andric // Starting from a EHPad, Backward walk through control-flow graph 3745ffd83dbSDimitry Andric // to produce two primary outputs: 3755ffd83dbSDimitry Andric // FuncInfo.EHPadStateMap[] and FuncInfo.CxxUnwindMap[] 3760b57cec5SDimitry Andric static void calculateCXXStateNumbers(WinEHFuncInfo &FuncInfo, 3770b57cec5SDimitry Andric const Instruction *FirstNonPHI, 3780b57cec5SDimitry Andric int ParentState) { 3790b57cec5SDimitry Andric const BasicBlock *BB = FirstNonPHI->getParent(); 3800b57cec5SDimitry Andric assert(BB->isEHPad() && "not a funclet!"); 3810b57cec5SDimitry Andric 3820b57cec5SDimitry Andric if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(FirstNonPHI)) { 3830b57cec5SDimitry Andric assert(FuncInfo.EHPadStateMap.count(CatchSwitch) == 0 && 3840b57cec5SDimitry Andric "shouldn't revist catch funclets!"); 3850b57cec5SDimitry Andric 3860b57cec5SDimitry Andric SmallVector<const CatchPadInst *, 2> Handlers; 3870b57cec5SDimitry Andric for (const BasicBlock *CatchPadBB : CatchSwitch->handlers()) { 3880b57cec5SDimitry Andric auto *CatchPad = cast<CatchPadInst>(CatchPadBB->getFirstNonPHI()); 3890b57cec5SDimitry Andric Handlers.push_back(CatchPad); 3900b57cec5SDimitry Andric } 3910b57cec5SDimitry Andric int TryLow = addUnwindMapEntry(FuncInfo, ParentState, nullptr); 3920b57cec5SDimitry Andric FuncInfo.EHPadStateMap[CatchSwitch] = TryLow; 3930b57cec5SDimitry Andric for (const BasicBlock *PredBlock : predecessors(BB)) 3940b57cec5SDimitry Andric if ((PredBlock = getEHPadFromPredecessor(PredBlock, 3950b57cec5SDimitry Andric CatchSwitch->getParentPad()))) 3960b57cec5SDimitry Andric calculateCXXStateNumbers(FuncInfo, PredBlock->getFirstNonPHI(), 3970b57cec5SDimitry Andric TryLow); 3980b57cec5SDimitry Andric int CatchLow = addUnwindMapEntry(FuncInfo, ParentState, nullptr); 3990b57cec5SDimitry Andric 4000b57cec5SDimitry Andric // catchpads are separate funclets in C++ EH due to the way rethrow works. 4010b57cec5SDimitry Andric int TryHigh = CatchLow - 1; 4025ffd83dbSDimitry Andric 4035ffd83dbSDimitry Andric // MSVC FrameHandler3/4 on x64&Arm64 expect Catch Handlers in $tryMap$ 4045ffd83dbSDimitry Andric // stored in pre-order (outer first, inner next), not post-order 4055ffd83dbSDimitry Andric // Add to map here. Fix the CatchHigh after children are processed 4065ffd83dbSDimitry Andric const Module *Mod = BB->getParent()->getParent(); 4075ffd83dbSDimitry Andric bool IsPreOrder = Triple(Mod->getTargetTriple()).isArch64Bit(); 4085ffd83dbSDimitry Andric if (IsPreOrder) 4095ffd83dbSDimitry Andric addTryBlockMapEntry(FuncInfo, TryLow, TryHigh, CatchLow, Handlers); 4105ffd83dbSDimitry Andric unsigned TBMEIdx = FuncInfo.TryBlockMap.size() - 1; 4115ffd83dbSDimitry Andric 4120b57cec5SDimitry Andric for (const auto *CatchPad : Handlers) { 4130b57cec5SDimitry Andric FuncInfo.FuncletBaseStateMap[CatchPad] = CatchLow; 41406c3fb27SDimitry Andric FuncInfo.EHPadStateMap[CatchPad] = CatchLow; 4150b57cec5SDimitry Andric for (const User *U : CatchPad->users()) { 4160b57cec5SDimitry Andric const auto *UserI = cast<Instruction>(U); 4170b57cec5SDimitry Andric if (auto *InnerCatchSwitch = dyn_cast<CatchSwitchInst>(UserI)) { 4180b57cec5SDimitry Andric BasicBlock *UnwindDest = InnerCatchSwitch->getUnwindDest(); 4190b57cec5SDimitry Andric if (!UnwindDest || UnwindDest == CatchSwitch->getUnwindDest()) 4200b57cec5SDimitry Andric calculateCXXStateNumbers(FuncInfo, UserI, CatchLow); 4210b57cec5SDimitry Andric } 4220b57cec5SDimitry Andric if (auto *InnerCleanupPad = dyn_cast<CleanupPadInst>(UserI)) { 4230b57cec5SDimitry Andric BasicBlock *UnwindDest = getCleanupRetUnwindDest(InnerCleanupPad); 4240b57cec5SDimitry Andric // If a nested cleanup pad reports a null unwind destination and the 4250b57cec5SDimitry Andric // enclosing catch pad doesn't it must be post-dominated by an 4260b57cec5SDimitry Andric // unreachable instruction. 4270b57cec5SDimitry Andric if (!UnwindDest || UnwindDest == CatchSwitch->getUnwindDest()) 4280b57cec5SDimitry Andric calculateCXXStateNumbers(FuncInfo, UserI, CatchLow); 4290b57cec5SDimitry Andric } 4300b57cec5SDimitry Andric } 4310b57cec5SDimitry Andric } 4320b57cec5SDimitry Andric int CatchHigh = FuncInfo.getLastStateNumber(); 4335ffd83dbSDimitry Andric // Now child Catches are processed, update CatchHigh 4345ffd83dbSDimitry Andric if (IsPreOrder) 4355ffd83dbSDimitry Andric FuncInfo.TryBlockMap[TBMEIdx].CatchHigh = CatchHigh; 4365ffd83dbSDimitry Andric else // PostOrder 4370b57cec5SDimitry Andric addTryBlockMapEntry(FuncInfo, TryLow, TryHigh, CatchHigh, Handlers); 4385ffd83dbSDimitry Andric 4390b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "TryLow[" << BB->getName() << "]: " << TryLow << '\n'); 4400b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "TryHigh[" << BB->getName() << "]: " << TryHigh 4410b57cec5SDimitry Andric << '\n'); 4420b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "CatchHigh[" << BB->getName() << "]: " << CatchHigh 4430b57cec5SDimitry Andric << '\n'); 4440b57cec5SDimitry Andric } else { 4450b57cec5SDimitry Andric auto *CleanupPad = cast<CleanupPadInst>(FirstNonPHI); 4460b57cec5SDimitry Andric 4470b57cec5SDimitry Andric // It's possible for a cleanup to be visited twice: it might have multiple 4480b57cec5SDimitry Andric // cleanupret instructions. 4490b57cec5SDimitry Andric if (FuncInfo.EHPadStateMap.count(CleanupPad)) 4500b57cec5SDimitry Andric return; 4510b57cec5SDimitry Andric 4520b57cec5SDimitry Andric int CleanupState = addUnwindMapEntry(FuncInfo, ParentState, BB); 4530b57cec5SDimitry Andric FuncInfo.EHPadStateMap[CleanupPad] = CleanupState; 4540b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Assigning state #" << CleanupState << " to BB " 4550b57cec5SDimitry Andric << BB->getName() << '\n'); 4560b57cec5SDimitry Andric for (const BasicBlock *PredBlock : predecessors(BB)) { 4570b57cec5SDimitry Andric if ((PredBlock = getEHPadFromPredecessor(PredBlock, 4580b57cec5SDimitry Andric CleanupPad->getParentPad()))) { 4590b57cec5SDimitry Andric calculateCXXStateNumbers(FuncInfo, PredBlock->getFirstNonPHI(), 4600b57cec5SDimitry Andric CleanupState); 4610b57cec5SDimitry Andric } 4620b57cec5SDimitry Andric } 4630b57cec5SDimitry Andric for (const User *U : CleanupPad->users()) { 4640b57cec5SDimitry Andric const auto *UserI = cast<Instruction>(U); 4650b57cec5SDimitry Andric if (UserI->isEHPad()) 4660b57cec5SDimitry Andric report_fatal_error("Cleanup funclets for the MSVC++ personality cannot " 4670b57cec5SDimitry Andric "contain exceptional actions"); 4680b57cec5SDimitry Andric } 4690b57cec5SDimitry Andric } 4700b57cec5SDimitry Andric } 4710b57cec5SDimitry Andric 4720b57cec5SDimitry Andric static int addSEHExcept(WinEHFuncInfo &FuncInfo, int ParentState, 4730b57cec5SDimitry Andric const Function *Filter, const BasicBlock *Handler) { 4740b57cec5SDimitry Andric SEHUnwindMapEntry Entry; 4750b57cec5SDimitry Andric Entry.ToState = ParentState; 4760b57cec5SDimitry Andric Entry.IsFinally = false; 4770b57cec5SDimitry Andric Entry.Filter = Filter; 4780b57cec5SDimitry Andric Entry.Handler = Handler; 4790b57cec5SDimitry Andric FuncInfo.SEHUnwindMap.push_back(Entry); 4800b57cec5SDimitry Andric return FuncInfo.SEHUnwindMap.size() - 1; 4810b57cec5SDimitry Andric } 4820b57cec5SDimitry Andric 4830b57cec5SDimitry Andric static int addSEHFinally(WinEHFuncInfo &FuncInfo, int ParentState, 4840b57cec5SDimitry Andric const BasicBlock *Handler) { 4850b57cec5SDimitry Andric SEHUnwindMapEntry Entry; 4860b57cec5SDimitry Andric Entry.ToState = ParentState; 4870b57cec5SDimitry Andric Entry.IsFinally = true; 4880b57cec5SDimitry Andric Entry.Filter = nullptr; 4890b57cec5SDimitry Andric Entry.Handler = Handler; 4900b57cec5SDimitry Andric FuncInfo.SEHUnwindMap.push_back(Entry); 4910b57cec5SDimitry Andric return FuncInfo.SEHUnwindMap.size() - 1; 4920b57cec5SDimitry Andric } 4930b57cec5SDimitry Andric 4945ffd83dbSDimitry Andric // Starting from a EHPad, Backward walk through control-flow graph 4955ffd83dbSDimitry Andric // to produce two primary outputs: 4965ffd83dbSDimitry Andric // FuncInfo.EHPadStateMap[] and FuncInfo.SEHUnwindMap[] 4970b57cec5SDimitry Andric static void calculateSEHStateNumbers(WinEHFuncInfo &FuncInfo, 4980b57cec5SDimitry Andric const Instruction *FirstNonPHI, 4990b57cec5SDimitry Andric int ParentState) { 5000b57cec5SDimitry Andric const BasicBlock *BB = FirstNonPHI->getParent(); 5010b57cec5SDimitry Andric assert(BB->isEHPad() && "no a funclet!"); 5020b57cec5SDimitry Andric 5030b57cec5SDimitry Andric if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(FirstNonPHI)) { 5040b57cec5SDimitry Andric assert(FuncInfo.EHPadStateMap.count(CatchSwitch) == 0 && 5050b57cec5SDimitry Andric "shouldn't revist catch funclets!"); 5060b57cec5SDimitry Andric 5070b57cec5SDimitry Andric // Extract the filter function and the __except basic block and create a 5080b57cec5SDimitry Andric // state for them. 5090b57cec5SDimitry Andric assert(CatchSwitch->getNumHandlers() == 1 && 5100b57cec5SDimitry Andric "SEH doesn't have multiple handlers per __try"); 5110b57cec5SDimitry Andric const auto *CatchPad = 5120b57cec5SDimitry Andric cast<CatchPadInst>((*CatchSwitch->handler_begin())->getFirstNonPHI()); 5130b57cec5SDimitry Andric const BasicBlock *CatchPadBB = CatchPad->getParent(); 5140b57cec5SDimitry Andric const Constant *FilterOrNull = 5150b57cec5SDimitry Andric cast<Constant>(CatchPad->getArgOperand(0)->stripPointerCasts()); 5160b57cec5SDimitry Andric const Function *Filter = dyn_cast<Function>(FilterOrNull); 5170b57cec5SDimitry Andric assert((Filter || FilterOrNull->isNullValue()) && 5180b57cec5SDimitry Andric "unexpected filter value"); 5190b57cec5SDimitry Andric int TryState = addSEHExcept(FuncInfo, ParentState, Filter, CatchPadBB); 5200b57cec5SDimitry Andric 5210b57cec5SDimitry Andric // Everything in the __try block uses TryState as its parent state. 5220b57cec5SDimitry Andric FuncInfo.EHPadStateMap[CatchSwitch] = TryState; 52306c3fb27SDimitry Andric FuncInfo.EHPadStateMap[CatchPad] = TryState; 5240b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Assigning state #" << TryState << " to BB " 5250b57cec5SDimitry Andric << CatchPadBB->getName() << '\n'); 5260b57cec5SDimitry Andric for (const BasicBlock *PredBlock : predecessors(BB)) 5270b57cec5SDimitry Andric if ((PredBlock = getEHPadFromPredecessor(PredBlock, 5280b57cec5SDimitry Andric CatchSwitch->getParentPad()))) 5290b57cec5SDimitry Andric calculateSEHStateNumbers(FuncInfo, PredBlock->getFirstNonPHI(), 5300b57cec5SDimitry Andric TryState); 5310b57cec5SDimitry Andric 5320b57cec5SDimitry Andric // Everything in the __except block unwinds to ParentState, just like code 5330b57cec5SDimitry Andric // outside the __try. 5340b57cec5SDimitry Andric for (const User *U : CatchPad->users()) { 5350b57cec5SDimitry Andric const auto *UserI = cast<Instruction>(U); 5360b57cec5SDimitry Andric if (auto *InnerCatchSwitch = dyn_cast<CatchSwitchInst>(UserI)) { 5370b57cec5SDimitry Andric BasicBlock *UnwindDest = InnerCatchSwitch->getUnwindDest(); 5380b57cec5SDimitry Andric if (!UnwindDest || UnwindDest == CatchSwitch->getUnwindDest()) 5390b57cec5SDimitry Andric calculateSEHStateNumbers(FuncInfo, UserI, ParentState); 5400b57cec5SDimitry Andric } 5410b57cec5SDimitry Andric if (auto *InnerCleanupPad = dyn_cast<CleanupPadInst>(UserI)) { 5420b57cec5SDimitry Andric BasicBlock *UnwindDest = getCleanupRetUnwindDest(InnerCleanupPad); 5430b57cec5SDimitry Andric // If a nested cleanup pad reports a null unwind destination and the 5440b57cec5SDimitry Andric // enclosing catch pad doesn't it must be post-dominated by an 5450b57cec5SDimitry Andric // unreachable instruction. 5460b57cec5SDimitry Andric if (!UnwindDest || UnwindDest == CatchSwitch->getUnwindDest()) 5470b57cec5SDimitry Andric calculateSEHStateNumbers(FuncInfo, UserI, ParentState); 5480b57cec5SDimitry Andric } 5490b57cec5SDimitry Andric } 5500b57cec5SDimitry Andric } else { 5510b57cec5SDimitry Andric auto *CleanupPad = cast<CleanupPadInst>(FirstNonPHI); 5520b57cec5SDimitry Andric 5530b57cec5SDimitry Andric // It's possible for a cleanup to be visited twice: it might have multiple 5540b57cec5SDimitry Andric // cleanupret instructions. 5550b57cec5SDimitry Andric if (FuncInfo.EHPadStateMap.count(CleanupPad)) 5560b57cec5SDimitry Andric return; 5570b57cec5SDimitry Andric 5580b57cec5SDimitry Andric int CleanupState = addSEHFinally(FuncInfo, ParentState, BB); 5590b57cec5SDimitry Andric FuncInfo.EHPadStateMap[CleanupPad] = CleanupState; 5600b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Assigning state #" << CleanupState << " to BB " 5610b57cec5SDimitry Andric << BB->getName() << '\n'); 5620b57cec5SDimitry Andric for (const BasicBlock *PredBlock : predecessors(BB)) 5630b57cec5SDimitry Andric if ((PredBlock = 5640b57cec5SDimitry Andric getEHPadFromPredecessor(PredBlock, CleanupPad->getParentPad()))) 5650b57cec5SDimitry Andric calculateSEHStateNumbers(FuncInfo, PredBlock->getFirstNonPHI(), 5660b57cec5SDimitry Andric CleanupState); 5670b57cec5SDimitry Andric for (const User *U : CleanupPad->users()) { 5680b57cec5SDimitry Andric const auto *UserI = cast<Instruction>(U); 5690b57cec5SDimitry Andric if (UserI->isEHPad()) 5700b57cec5SDimitry Andric report_fatal_error("Cleanup funclets for the SEH personality cannot " 5710b57cec5SDimitry Andric "contain exceptional actions"); 5720b57cec5SDimitry Andric } 5730b57cec5SDimitry Andric } 5740b57cec5SDimitry Andric } 5750b57cec5SDimitry Andric 5760b57cec5SDimitry Andric static bool isTopLevelPadForMSVC(const Instruction *EHPad) { 5770b57cec5SDimitry Andric if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(EHPad)) 5780b57cec5SDimitry Andric return isa<ConstantTokenNone>(CatchSwitch->getParentPad()) && 5790b57cec5SDimitry Andric CatchSwitch->unwindsToCaller(); 5800b57cec5SDimitry Andric if (auto *CleanupPad = dyn_cast<CleanupPadInst>(EHPad)) 5810b57cec5SDimitry Andric return isa<ConstantTokenNone>(CleanupPad->getParentPad()) && 5820b57cec5SDimitry Andric getCleanupRetUnwindDest(CleanupPad) == nullptr; 5830b57cec5SDimitry Andric if (isa<CatchPadInst>(EHPad)) 5840b57cec5SDimitry Andric return false; 5850b57cec5SDimitry Andric llvm_unreachable("unexpected EHPad!"); 5860b57cec5SDimitry Andric } 5870b57cec5SDimitry Andric 5880b57cec5SDimitry Andric void llvm::calculateSEHStateNumbers(const Function *Fn, 5890b57cec5SDimitry Andric WinEHFuncInfo &FuncInfo) { 5900b57cec5SDimitry Andric // Don't compute state numbers twice. 5910b57cec5SDimitry Andric if (!FuncInfo.SEHUnwindMap.empty()) 5920b57cec5SDimitry Andric return; 5930b57cec5SDimitry Andric 5940b57cec5SDimitry Andric for (const BasicBlock &BB : *Fn) { 5950b57cec5SDimitry Andric if (!BB.isEHPad()) 5960b57cec5SDimitry Andric continue; 5970b57cec5SDimitry Andric const Instruction *FirstNonPHI = BB.getFirstNonPHI(); 5980b57cec5SDimitry Andric if (!isTopLevelPadForMSVC(FirstNonPHI)) 5990b57cec5SDimitry Andric continue; 6000b57cec5SDimitry Andric ::calculateSEHStateNumbers(FuncInfo, FirstNonPHI, -1); 6010b57cec5SDimitry Andric } 6020b57cec5SDimitry Andric 6030b57cec5SDimitry Andric calculateStateNumbersForInvokes(Fn, FuncInfo); 60406c3fb27SDimitry Andric 60506c3fb27SDimitry Andric bool IsEHa = Fn->getParent()->getModuleFlag("eh-asynch"); 60606c3fb27SDimitry Andric if (IsEHa) { 60706c3fb27SDimitry Andric const BasicBlock *EntryBB = &(Fn->getEntryBlock()); 60806c3fb27SDimitry Andric calculateSEHStateForAsynchEH(EntryBB, -1, FuncInfo); 60906c3fb27SDimitry Andric } 6100b57cec5SDimitry Andric } 6110b57cec5SDimitry Andric 6120b57cec5SDimitry Andric void llvm::calculateWinCXXEHStateNumbers(const Function *Fn, 6130b57cec5SDimitry Andric WinEHFuncInfo &FuncInfo) { 6140b57cec5SDimitry Andric // Return if it's already been done. 6150b57cec5SDimitry Andric if (!FuncInfo.EHPadStateMap.empty()) 6160b57cec5SDimitry Andric return; 6170b57cec5SDimitry Andric 6180b57cec5SDimitry Andric for (const BasicBlock &BB : *Fn) { 6190b57cec5SDimitry Andric if (!BB.isEHPad()) 6200b57cec5SDimitry Andric continue; 6210b57cec5SDimitry Andric const Instruction *FirstNonPHI = BB.getFirstNonPHI(); 6220b57cec5SDimitry Andric if (!isTopLevelPadForMSVC(FirstNonPHI)) 6230b57cec5SDimitry Andric continue; 6240b57cec5SDimitry Andric calculateCXXStateNumbers(FuncInfo, FirstNonPHI, -1); 6250b57cec5SDimitry Andric } 6260b57cec5SDimitry Andric 6270b57cec5SDimitry Andric calculateStateNumbersForInvokes(Fn, FuncInfo); 62806c3fb27SDimitry Andric 62906c3fb27SDimitry Andric bool IsEHa = Fn->getParent()->getModuleFlag("eh-asynch"); 63006c3fb27SDimitry Andric if (IsEHa) { 63106c3fb27SDimitry Andric const BasicBlock *EntryBB = &(Fn->getEntryBlock()); 63206c3fb27SDimitry Andric calculateCXXStateForAsynchEH(EntryBB, -1, FuncInfo); 63306c3fb27SDimitry Andric } 6340b57cec5SDimitry Andric } 6350b57cec5SDimitry Andric 6360b57cec5SDimitry Andric static int addClrEHHandler(WinEHFuncInfo &FuncInfo, int HandlerParentState, 6370b57cec5SDimitry Andric int TryParentState, ClrHandlerType HandlerType, 6380b57cec5SDimitry Andric uint32_t TypeToken, const BasicBlock *Handler) { 6390b57cec5SDimitry Andric ClrEHUnwindMapEntry Entry; 6400b57cec5SDimitry Andric Entry.HandlerParentState = HandlerParentState; 6410b57cec5SDimitry Andric Entry.TryParentState = TryParentState; 6420b57cec5SDimitry Andric Entry.Handler = Handler; 6430b57cec5SDimitry Andric Entry.HandlerType = HandlerType; 6440b57cec5SDimitry Andric Entry.TypeToken = TypeToken; 6450b57cec5SDimitry Andric FuncInfo.ClrEHUnwindMap.push_back(Entry); 6460b57cec5SDimitry Andric return FuncInfo.ClrEHUnwindMap.size() - 1; 6470b57cec5SDimitry Andric } 6480b57cec5SDimitry Andric 6490b57cec5SDimitry Andric void llvm::calculateClrEHStateNumbers(const Function *Fn, 6500b57cec5SDimitry Andric WinEHFuncInfo &FuncInfo) { 6510b57cec5SDimitry Andric // Return if it's already been done. 6520b57cec5SDimitry Andric if (!FuncInfo.EHPadStateMap.empty()) 6530b57cec5SDimitry Andric return; 6540b57cec5SDimitry Andric 6550b57cec5SDimitry Andric // This numbering assigns one state number to each catchpad and cleanuppad. 6560b57cec5SDimitry Andric // It also computes two tree-like relations over states: 6570b57cec5SDimitry Andric // 1) Each state has a "HandlerParentState", which is the state of the next 6580b57cec5SDimitry Andric // outer handler enclosing this state's handler (same as nearest ancestor 6590b57cec5SDimitry Andric // per the ParentPad linkage on EH pads, but skipping over catchswitches). 6600b57cec5SDimitry Andric // 2) Each state has a "TryParentState", which: 6610b57cec5SDimitry Andric // a) for a catchpad that's not the last handler on its catchswitch, is 6620b57cec5SDimitry Andric // the state of the next catchpad on that catchswitch 6630b57cec5SDimitry Andric // b) for all other pads, is the state of the pad whose try region is the 6640b57cec5SDimitry Andric // next outer try region enclosing this state's try region. The "try 6650b57cec5SDimitry Andric // regions are not present as such in the IR, but will be inferred 6660b57cec5SDimitry Andric // based on the placement of invokes and pads which reach each other 6670b57cec5SDimitry Andric // by exceptional exits 6680b57cec5SDimitry Andric // Catchswitches do not get their own states, but each gets mapped to the 6690b57cec5SDimitry Andric // state of its first catchpad. 6700b57cec5SDimitry Andric 6710b57cec5SDimitry Andric // Step one: walk down from outermost to innermost funclets, assigning each 6720b57cec5SDimitry Andric // catchpad and cleanuppad a state number. Add an entry to the 6730b57cec5SDimitry Andric // ClrEHUnwindMap for each state, recording its HandlerParentState and 6740b57cec5SDimitry Andric // handler attributes. Record the TryParentState as well for each catchpad 6750b57cec5SDimitry Andric // that's not the last on its catchswitch, but initialize all other entries' 6760b57cec5SDimitry Andric // TryParentStates to a sentinel -1 value that the next pass will update. 6770b57cec5SDimitry Andric 6780b57cec5SDimitry Andric // Seed a worklist with pads that have no parent. 6790b57cec5SDimitry Andric SmallVector<std::pair<const Instruction *, int>, 8> Worklist; 6800b57cec5SDimitry Andric for (const BasicBlock &BB : *Fn) { 6810b57cec5SDimitry Andric const Instruction *FirstNonPHI = BB.getFirstNonPHI(); 6820b57cec5SDimitry Andric const Value *ParentPad; 6830b57cec5SDimitry Andric if (const auto *CPI = dyn_cast<CleanupPadInst>(FirstNonPHI)) 6840b57cec5SDimitry Andric ParentPad = CPI->getParentPad(); 6850b57cec5SDimitry Andric else if (const auto *CSI = dyn_cast<CatchSwitchInst>(FirstNonPHI)) 6860b57cec5SDimitry Andric ParentPad = CSI->getParentPad(); 6870b57cec5SDimitry Andric else 6880b57cec5SDimitry Andric continue; 6890b57cec5SDimitry Andric if (isa<ConstantTokenNone>(ParentPad)) 6900b57cec5SDimitry Andric Worklist.emplace_back(FirstNonPHI, -1); 6910b57cec5SDimitry Andric } 6920b57cec5SDimitry Andric 6930b57cec5SDimitry Andric // Use the worklist to visit all pads, from outer to inner. Record 6940b57cec5SDimitry Andric // HandlerParentState for all pads. Record TryParentState only for catchpads 6950b57cec5SDimitry Andric // that aren't the last on their catchswitch (setting all other entries' 6960b57cec5SDimitry Andric // TryParentStates to an initial value of -1). This loop is also responsible 6970b57cec5SDimitry Andric // for setting the EHPadStateMap entry for all catchpads, cleanuppads, and 6980b57cec5SDimitry Andric // catchswitches. 6990b57cec5SDimitry Andric while (!Worklist.empty()) { 7000b57cec5SDimitry Andric const Instruction *Pad; 7010b57cec5SDimitry Andric int HandlerParentState; 7020b57cec5SDimitry Andric std::tie(Pad, HandlerParentState) = Worklist.pop_back_val(); 7030b57cec5SDimitry Andric 7040b57cec5SDimitry Andric if (const auto *Cleanup = dyn_cast<CleanupPadInst>(Pad)) { 7050b57cec5SDimitry Andric // Create the entry for this cleanup with the appropriate handler 7060b57cec5SDimitry Andric // properties. Finally and fault handlers are distinguished by arity. 7070b57cec5SDimitry Andric ClrHandlerType HandlerType = 708bdd1243dSDimitry Andric (Cleanup->arg_size() ? ClrHandlerType::Fault 7090b57cec5SDimitry Andric : ClrHandlerType::Finally); 7100b57cec5SDimitry Andric int CleanupState = addClrEHHandler(FuncInfo, HandlerParentState, -1, 7110b57cec5SDimitry Andric HandlerType, 0, Pad->getParent()); 7120b57cec5SDimitry Andric // Queue any child EH pads on the worklist. 7130b57cec5SDimitry Andric for (const User *U : Cleanup->users()) 7140b57cec5SDimitry Andric if (const auto *I = dyn_cast<Instruction>(U)) 7150b57cec5SDimitry Andric if (I->isEHPad()) 7160b57cec5SDimitry Andric Worklist.emplace_back(I, CleanupState); 7170b57cec5SDimitry Andric // Remember this pad's state. 7180b57cec5SDimitry Andric FuncInfo.EHPadStateMap[Cleanup] = CleanupState; 7190b57cec5SDimitry Andric } else { 7200b57cec5SDimitry Andric // Walk the handlers of this catchswitch in reverse order since all but 7210b57cec5SDimitry Andric // the last need to set the following one as its TryParentState. 7220b57cec5SDimitry Andric const auto *CatchSwitch = cast<CatchSwitchInst>(Pad); 7230b57cec5SDimitry Andric int CatchState = -1, FollowerState = -1; 7240b57cec5SDimitry Andric SmallVector<const BasicBlock *, 4> CatchBlocks(CatchSwitch->handlers()); 7250eae32dcSDimitry Andric for (const BasicBlock *CatchBlock : llvm::reverse(CatchBlocks)) { 7260b57cec5SDimitry Andric // Create the entry for this catch with the appropriate handler 7270b57cec5SDimitry Andric // properties. 7280b57cec5SDimitry Andric const auto *Catch = cast<CatchPadInst>(CatchBlock->getFirstNonPHI()); 7290b57cec5SDimitry Andric uint32_t TypeToken = static_cast<uint32_t>( 7300b57cec5SDimitry Andric cast<ConstantInt>(Catch->getArgOperand(0))->getZExtValue()); 7310b57cec5SDimitry Andric CatchState = 7320b57cec5SDimitry Andric addClrEHHandler(FuncInfo, HandlerParentState, FollowerState, 7330b57cec5SDimitry Andric ClrHandlerType::Catch, TypeToken, CatchBlock); 7340b57cec5SDimitry Andric // Queue any child EH pads on the worklist. 7350b57cec5SDimitry Andric for (const User *U : Catch->users()) 7360b57cec5SDimitry Andric if (const auto *I = dyn_cast<Instruction>(U)) 7370b57cec5SDimitry Andric if (I->isEHPad()) 7380b57cec5SDimitry Andric Worklist.emplace_back(I, CatchState); 7390b57cec5SDimitry Andric // Remember this catch's state. 7400b57cec5SDimitry Andric FuncInfo.EHPadStateMap[Catch] = CatchState; 7410eae32dcSDimitry Andric FollowerState = CatchState; 7420b57cec5SDimitry Andric } 7430b57cec5SDimitry Andric // Associate the catchswitch with the state of its first catch. 7440b57cec5SDimitry Andric assert(CatchSwitch->getNumHandlers()); 7450b57cec5SDimitry Andric FuncInfo.EHPadStateMap[CatchSwitch] = CatchState; 7460b57cec5SDimitry Andric } 7470b57cec5SDimitry Andric } 7480b57cec5SDimitry Andric 7490b57cec5SDimitry Andric // Step two: record the TryParentState of each state. For cleanuppads that 7500b57cec5SDimitry Andric // don't have cleanuprets, we may need to infer this from their child pads, 7510b57cec5SDimitry Andric // so visit pads in descendant-most to ancestor-most order. 7520eae32dcSDimitry Andric for (ClrEHUnwindMapEntry &Entry : llvm::reverse(FuncInfo.ClrEHUnwindMap)) { 7530b57cec5SDimitry Andric const Instruction *Pad = 75406c3fb27SDimitry Andric cast<const BasicBlock *>(Entry.Handler)->getFirstNonPHI(); 7550b57cec5SDimitry Andric // For most pads, the TryParentState is the state associated with the 7560b57cec5SDimitry Andric // unwind dest of exceptional exits from it. 7570b57cec5SDimitry Andric const BasicBlock *UnwindDest; 7580b57cec5SDimitry Andric if (const auto *Catch = dyn_cast<CatchPadInst>(Pad)) { 7590b57cec5SDimitry Andric // If a catch is not the last in its catchswitch, its TryParentState is 7600b57cec5SDimitry Andric // the state associated with the next catch in the switch, even though 7610b57cec5SDimitry Andric // that's not the unwind dest of exceptions escaping the catch. Those 7620b57cec5SDimitry Andric // cases were already assigned a TryParentState in the first pass, so 7630b57cec5SDimitry Andric // skip them. 7640eae32dcSDimitry Andric if (Entry.TryParentState != -1) 7650b57cec5SDimitry Andric continue; 7660b57cec5SDimitry Andric // Otherwise, get the unwind dest from the catchswitch. 7670b57cec5SDimitry Andric UnwindDest = Catch->getCatchSwitch()->getUnwindDest(); 7680b57cec5SDimitry Andric } else { 7690b57cec5SDimitry Andric const auto *Cleanup = cast<CleanupPadInst>(Pad); 7700b57cec5SDimitry Andric UnwindDest = nullptr; 7710b57cec5SDimitry Andric for (const User *U : Cleanup->users()) { 7720b57cec5SDimitry Andric if (auto *CleanupRet = dyn_cast<CleanupReturnInst>(U)) { 7730b57cec5SDimitry Andric // Common and unambiguous case -- cleanupret indicates cleanup's 7740b57cec5SDimitry Andric // unwind dest. 7750b57cec5SDimitry Andric UnwindDest = CleanupRet->getUnwindDest(); 7760b57cec5SDimitry Andric break; 7770b57cec5SDimitry Andric } 7780b57cec5SDimitry Andric 7790b57cec5SDimitry Andric // Get an unwind dest for the user 7800b57cec5SDimitry Andric const BasicBlock *UserUnwindDest = nullptr; 7810b57cec5SDimitry Andric if (auto *Invoke = dyn_cast<InvokeInst>(U)) { 7820b57cec5SDimitry Andric UserUnwindDest = Invoke->getUnwindDest(); 7830b57cec5SDimitry Andric } else if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(U)) { 7840b57cec5SDimitry Andric UserUnwindDest = CatchSwitch->getUnwindDest(); 7850b57cec5SDimitry Andric } else if (auto *ChildCleanup = dyn_cast<CleanupPadInst>(U)) { 7860b57cec5SDimitry Andric int UserState = FuncInfo.EHPadStateMap[ChildCleanup]; 7870b57cec5SDimitry Andric int UserUnwindState = 7880b57cec5SDimitry Andric FuncInfo.ClrEHUnwindMap[UserState].TryParentState; 7890b57cec5SDimitry Andric if (UserUnwindState != -1) 79006c3fb27SDimitry Andric UserUnwindDest = cast<const BasicBlock *>( 79106c3fb27SDimitry Andric FuncInfo.ClrEHUnwindMap[UserUnwindState].Handler); 7920b57cec5SDimitry Andric } 7930b57cec5SDimitry Andric 7940b57cec5SDimitry Andric // Not having an unwind dest for this user might indicate that it 7950b57cec5SDimitry Andric // doesn't unwind, so can't be taken as proof that the cleanup itself 7960b57cec5SDimitry Andric // may unwind to caller (see e.g. SimplifyUnreachable and 7970b57cec5SDimitry Andric // RemoveUnwindEdge). 7980b57cec5SDimitry Andric if (!UserUnwindDest) 7990b57cec5SDimitry Andric continue; 8000b57cec5SDimitry Andric 8010b57cec5SDimitry Andric // Now we have an unwind dest for the user, but we need to see if it 8020b57cec5SDimitry Andric // unwinds all the way out of the cleanup or if it stays within it. 8030b57cec5SDimitry Andric const Instruction *UserUnwindPad = UserUnwindDest->getFirstNonPHI(); 8040b57cec5SDimitry Andric const Value *UserUnwindParent; 8050b57cec5SDimitry Andric if (auto *CSI = dyn_cast<CatchSwitchInst>(UserUnwindPad)) 8060b57cec5SDimitry Andric UserUnwindParent = CSI->getParentPad(); 8070b57cec5SDimitry Andric else 8080b57cec5SDimitry Andric UserUnwindParent = 8090b57cec5SDimitry Andric cast<CleanupPadInst>(UserUnwindPad)->getParentPad(); 8100b57cec5SDimitry Andric 8110b57cec5SDimitry Andric // The unwind stays within the cleanup iff it targets a child of the 8120b57cec5SDimitry Andric // cleanup. 8130b57cec5SDimitry Andric if (UserUnwindParent == Cleanup) 8140b57cec5SDimitry Andric continue; 8150b57cec5SDimitry Andric 8160b57cec5SDimitry Andric // This unwind exits the cleanup, so its dest is the cleanup's dest. 8170b57cec5SDimitry Andric UnwindDest = UserUnwindDest; 8180b57cec5SDimitry Andric break; 8190b57cec5SDimitry Andric } 8200b57cec5SDimitry Andric } 8210b57cec5SDimitry Andric 8220b57cec5SDimitry Andric // Record the state of the unwind dest as the TryParentState. 8230b57cec5SDimitry Andric int UnwindDestState; 8240b57cec5SDimitry Andric 8250b57cec5SDimitry Andric // If UnwindDest is null at this point, either the pad in question can 8260b57cec5SDimitry Andric // be exited by unwind to caller, or it cannot be exited by unwind. In 8270b57cec5SDimitry Andric // either case, reporting such cases as unwinding to caller is correct. 8280b57cec5SDimitry Andric // This can lead to EH tables that "look strange" -- if this pad's is in 8290b57cec5SDimitry Andric // a parent funclet which has other children that do unwind to an enclosing 8300b57cec5SDimitry Andric // pad, the try region for this pad will be missing the "duplicate" EH 8310b57cec5SDimitry Andric // clause entries that you'd expect to see covering the whole parent. That 8320b57cec5SDimitry Andric // should be benign, since the unwind never actually happens. If it were 8330b57cec5SDimitry Andric // an issue, we could add a subsequent pass that pushes unwind dests down 8340b57cec5SDimitry Andric // from parents that have them to children that appear to unwind to caller. 8350b57cec5SDimitry Andric if (!UnwindDest) { 8360b57cec5SDimitry Andric UnwindDestState = -1; 8370b57cec5SDimitry Andric } else { 8380b57cec5SDimitry Andric UnwindDestState = FuncInfo.EHPadStateMap[UnwindDest->getFirstNonPHI()]; 8390b57cec5SDimitry Andric } 8400b57cec5SDimitry Andric 8410eae32dcSDimitry Andric Entry.TryParentState = UnwindDestState; 8420b57cec5SDimitry Andric } 8430b57cec5SDimitry Andric 8440b57cec5SDimitry Andric // Step three: transfer information from pads to invokes. 8450b57cec5SDimitry Andric calculateStateNumbersForInvokes(Fn, FuncInfo); 8460b57cec5SDimitry Andric } 8470b57cec5SDimitry Andric 8485f757f3fSDimitry Andric void WinEHPrepareImpl::colorFunclets(Function &F) { 8490b57cec5SDimitry Andric BlockColors = colorEHFunclets(F); 8500b57cec5SDimitry Andric 8510b57cec5SDimitry Andric // Invert the map from BB to colors to color to BBs. 8520b57cec5SDimitry Andric for (BasicBlock &BB : F) { 8530b57cec5SDimitry Andric ColorVector &Colors = BlockColors[&BB]; 8540b57cec5SDimitry Andric for (BasicBlock *Color : Colors) 8550b57cec5SDimitry Andric FuncletBlocks[Color].push_back(&BB); 8560b57cec5SDimitry Andric } 8570b57cec5SDimitry Andric } 8580b57cec5SDimitry Andric 8595f757f3fSDimitry Andric void WinEHPrepareImpl::demotePHIsOnFunclets(Function &F, 8600b57cec5SDimitry Andric bool DemoteCatchSwitchPHIOnly) { 8610b57cec5SDimitry Andric // Strip PHI nodes off of EH pads. 8620b57cec5SDimitry Andric SmallVector<PHINode *, 16> PHINodes; 863fe6060f1SDimitry Andric for (BasicBlock &BB : make_early_inc_range(F)) { 864fe6060f1SDimitry Andric if (!BB.isEHPad()) 8650b57cec5SDimitry Andric continue; 866fe6060f1SDimitry Andric if (DemoteCatchSwitchPHIOnly && !isa<CatchSwitchInst>(BB.getFirstNonPHI())) 8670b57cec5SDimitry Andric continue; 8680b57cec5SDimitry Andric 869fe6060f1SDimitry Andric for (Instruction &I : make_early_inc_range(BB)) { 870fe6060f1SDimitry Andric auto *PN = dyn_cast<PHINode>(&I); 8710b57cec5SDimitry Andric // Stop at the first non-PHI. 8720b57cec5SDimitry Andric if (!PN) 8730b57cec5SDimitry Andric break; 8740b57cec5SDimitry Andric 8750b57cec5SDimitry Andric AllocaInst *SpillSlot = insertPHILoads(PN, F); 8760b57cec5SDimitry Andric if (SpillSlot) 8770b57cec5SDimitry Andric insertPHIStores(PN, SpillSlot); 8780b57cec5SDimitry Andric 8790b57cec5SDimitry Andric PHINodes.push_back(PN); 8800b57cec5SDimitry Andric } 8810b57cec5SDimitry Andric } 8820b57cec5SDimitry Andric 8830b57cec5SDimitry Andric for (auto *PN : PHINodes) { 8840b57cec5SDimitry Andric // There may be lingering uses on other EH PHIs being removed 885bdd1243dSDimitry Andric PN->replaceAllUsesWith(PoisonValue::get(PN->getType())); 8860b57cec5SDimitry Andric PN->eraseFromParent(); 8870b57cec5SDimitry Andric } 8880b57cec5SDimitry Andric } 8890b57cec5SDimitry Andric 8905f757f3fSDimitry Andric void WinEHPrepareImpl::cloneCommonBlocks(Function &F) { 8910b57cec5SDimitry Andric // We need to clone all blocks which belong to multiple funclets. Values are 8920b57cec5SDimitry Andric // remapped throughout the funclet to propagate both the new instructions 8930b57cec5SDimitry Andric // *and* the new basic blocks themselves. 8940b57cec5SDimitry Andric for (auto &Funclets : FuncletBlocks) { 8950b57cec5SDimitry Andric BasicBlock *FuncletPadBB = Funclets.first; 8960b57cec5SDimitry Andric std::vector<BasicBlock *> &BlocksInFunclet = Funclets.second; 8970b57cec5SDimitry Andric Value *FuncletToken; 8980b57cec5SDimitry Andric if (FuncletPadBB == &F.getEntryBlock()) 8990b57cec5SDimitry Andric FuncletToken = ConstantTokenNone::get(F.getContext()); 9000b57cec5SDimitry Andric else 9010b57cec5SDimitry Andric FuncletToken = FuncletPadBB->getFirstNonPHI(); 9020b57cec5SDimitry Andric 9030b57cec5SDimitry Andric std::vector<std::pair<BasicBlock *, BasicBlock *>> Orig2Clone; 9040b57cec5SDimitry Andric ValueToValueMapTy VMap; 9050b57cec5SDimitry Andric for (BasicBlock *BB : BlocksInFunclet) { 9060b57cec5SDimitry Andric ColorVector &ColorsForBB = BlockColors[BB]; 9070b57cec5SDimitry Andric // We don't need to do anything if the block is monochromatic. 9080b57cec5SDimitry Andric size_t NumColorsForBB = ColorsForBB.size(); 9090b57cec5SDimitry Andric if (NumColorsForBB == 1) 9100b57cec5SDimitry Andric continue; 9110b57cec5SDimitry Andric 9125f757f3fSDimitry Andric DEBUG_WITH_TYPE("win-eh-prepare-coloring", 9130b57cec5SDimitry Andric dbgs() << " Cloning block \'" << BB->getName() 9140b57cec5SDimitry Andric << "\' for funclet \'" << FuncletPadBB->getName() 9150b57cec5SDimitry Andric << "\'.\n"); 9160b57cec5SDimitry Andric 9170b57cec5SDimitry Andric // Create a new basic block and copy instructions into it! 9180b57cec5SDimitry Andric BasicBlock *CBB = 9190b57cec5SDimitry Andric CloneBasicBlock(BB, VMap, Twine(".for.", FuncletPadBB->getName())); 9200b57cec5SDimitry Andric // Insert the clone immediately after the original to ensure determinism 9210b57cec5SDimitry Andric // and to keep the same relative ordering of any funclet's blocks. 9220b57cec5SDimitry Andric CBB->insertInto(&F, BB->getNextNode()); 9230b57cec5SDimitry Andric 9240b57cec5SDimitry Andric // Add basic block mapping. 9250b57cec5SDimitry Andric VMap[BB] = CBB; 9260b57cec5SDimitry Andric 9270b57cec5SDimitry Andric // Record delta operations that we need to perform to our color mappings. 9280b57cec5SDimitry Andric Orig2Clone.emplace_back(BB, CBB); 9290b57cec5SDimitry Andric } 9300b57cec5SDimitry Andric 9310b57cec5SDimitry Andric // If nothing was cloned, we're done cloning in this funclet. 9320b57cec5SDimitry Andric if (Orig2Clone.empty()) 9330b57cec5SDimitry Andric continue; 9340b57cec5SDimitry Andric 9350b57cec5SDimitry Andric // Update our color mappings to reflect that one block has lost a color and 9360b57cec5SDimitry Andric // another has gained a color. 9370b57cec5SDimitry Andric for (auto &BBMapping : Orig2Clone) { 9380b57cec5SDimitry Andric BasicBlock *OldBlock = BBMapping.first; 9390b57cec5SDimitry Andric BasicBlock *NewBlock = BBMapping.second; 9400b57cec5SDimitry Andric 9410b57cec5SDimitry Andric BlocksInFunclet.push_back(NewBlock); 9420b57cec5SDimitry Andric ColorVector &NewColors = BlockColors[NewBlock]; 9430b57cec5SDimitry Andric assert(NewColors.empty() && "A new block should only have one color!"); 9440b57cec5SDimitry Andric NewColors.push_back(FuncletPadBB); 9450b57cec5SDimitry Andric 9465f757f3fSDimitry Andric DEBUG_WITH_TYPE("win-eh-prepare-coloring", 9470b57cec5SDimitry Andric dbgs() << " Assigned color \'" << FuncletPadBB->getName() 9480b57cec5SDimitry Andric << "\' to block \'" << NewBlock->getName() 9490b57cec5SDimitry Andric << "\'.\n"); 9500b57cec5SDimitry Andric 9515f757f3fSDimitry Andric llvm::erase(BlocksInFunclet, OldBlock); 9520b57cec5SDimitry Andric ColorVector &OldColors = BlockColors[OldBlock]; 9535f757f3fSDimitry Andric llvm::erase(OldColors, FuncletPadBB); 9540b57cec5SDimitry Andric 9555f757f3fSDimitry Andric DEBUG_WITH_TYPE("win-eh-prepare-coloring", 9560b57cec5SDimitry Andric dbgs() << " Removed color \'" << FuncletPadBB->getName() 9570b57cec5SDimitry Andric << "\' from block \'" << OldBlock->getName() 9580b57cec5SDimitry Andric << "\'.\n"); 9590b57cec5SDimitry Andric } 9600b57cec5SDimitry Andric 9610b57cec5SDimitry Andric // Loop over all of the instructions in this funclet, fixing up operand 9620b57cec5SDimitry Andric // references as we go. This uses VMap to do all the hard work. 9630b57cec5SDimitry Andric for (BasicBlock *BB : BlocksInFunclet) 9640b57cec5SDimitry Andric // Loop over all instructions, fixing each one as we find it... 9650b57cec5SDimitry Andric for (Instruction &I : *BB) 9660b57cec5SDimitry Andric RemapInstruction(&I, VMap, 9670b57cec5SDimitry Andric RF_IgnoreMissingLocals | RF_NoModuleLevelChanges); 9680b57cec5SDimitry Andric 9690b57cec5SDimitry Andric // Catchrets targeting cloned blocks need to be updated separately from 9700b57cec5SDimitry Andric // the loop above because they are not in the current funclet. 9710b57cec5SDimitry Andric SmallVector<CatchReturnInst *, 2> FixupCatchrets; 9720b57cec5SDimitry Andric for (auto &BBMapping : Orig2Clone) { 9730b57cec5SDimitry Andric BasicBlock *OldBlock = BBMapping.first; 9740b57cec5SDimitry Andric BasicBlock *NewBlock = BBMapping.second; 9750b57cec5SDimitry Andric 9760b57cec5SDimitry Andric FixupCatchrets.clear(); 9770b57cec5SDimitry Andric for (BasicBlock *Pred : predecessors(OldBlock)) 9780b57cec5SDimitry Andric if (auto *CatchRet = dyn_cast<CatchReturnInst>(Pred->getTerminator())) 9790b57cec5SDimitry Andric if (CatchRet->getCatchSwitchParentPad() == FuncletToken) 9800b57cec5SDimitry Andric FixupCatchrets.push_back(CatchRet); 9810b57cec5SDimitry Andric 9820b57cec5SDimitry Andric for (CatchReturnInst *CatchRet : FixupCatchrets) 9830b57cec5SDimitry Andric CatchRet->setSuccessor(NewBlock); 9840b57cec5SDimitry Andric } 9850b57cec5SDimitry Andric 9860b57cec5SDimitry Andric auto UpdatePHIOnClonedBlock = [&](PHINode *PN, bool IsForOldBlock) { 9870b57cec5SDimitry Andric unsigned NumPreds = PN->getNumIncomingValues(); 9880b57cec5SDimitry Andric for (unsigned PredIdx = 0, PredEnd = NumPreds; PredIdx != PredEnd; 9890b57cec5SDimitry Andric ++PredIdx) { 9900b57cec5SDimitry Andric BasicBlock *IncomingBlock = PN->getIncomingBlock(PredIdx); 9910b57cec5SDimitry Andric bool EdgeTargetsFunclet; 9920b57cec5SDimitry Andric if (auto *CRI = 9930b57cec5SDimitry Andric dyn_cast<CatchReturnInst>(IncomingBlock->getTerminator())) { 9940b57cec5SDimitry Andric EdgeTargetsFunclet = (CRI->getCatchSwitchParentPad() == FuncletToken); 9950b57cec5SDimitry Andric } else { 9960b57cec5SDimitry Andric ColorVector &IncomingColors = BlockColors[IncomingBlock]; 9970b57cec5SDimitry Andric assert(!IncomingColors.empty() && "Block not colored!"); 9980b57cec5SDimitry Andric assert((IncomingColors.size() == 1 || 999bdd1243dSDimitry Andric !llvm::is_contained(IncomingColors, FuncletPadBB)) && 10000b57cec5SDimitry Andric "Cloning should leave this funclet's blocks monochromatic"); 10010b57cec5SDimitry Andric EdgeTargetsFunclet = (IncomingColors.front() == FuncletPadBB); 10020b57cec5SDimitry Andric } 10030b57cec5SDimitry Andric if (IsForOldBlock != EdgeTargetsFunclet) 10040b57cec5SDimitry Andric continue; 10050b57cec5SDimitry Andric PN->removeIncomingValue(IncomingBlock, /*DeletePHIIfEmpty=*/false); 10060b57cec5SDimitry Andric // Revisit the next entry. 10070b57cec5SDimitry Andric --PredIdx; 10080b57cec5SDimitry Andric --PredEnd; 10090b57cec5SDimitry Andric } 10100b57cec5SDimitry Andric }; 10110b57cec5SDimitry Andric 10120b57cec5SDimitry Andric for (auto &BBMapping : Orig2Clone) { 10130b57cec5SDimitry Andric BasicBlock *OldBlock = BBMapping.first; 10140b57cec5SDimitry Andric BasicBlock *NewBlock = BBMapping.second; 10150b57cec5SDimitry Andric for (PHINode &OldPN : OldBlock->phis()) { 10160b57cec5SDimitry Andric UpdatePHIOnClonedBlock(&OldPN, /*IsForOldBlock=*/true); 10170b57cec5SDimitry Andric } 10180b57cec5SDimitry Andric for (PHINode &NewPN : NewBlock->phis()) { 10190b57cec5SDimitry Andric UpdatePHIOnClonedBlock(&NewPN, /*IsForOldBlock=*/false); 10200b57cec5SDimitry Andric } 10210b57cec5SDimitry Andric } 10220b57cec5SDimitry Andric 10230b57cec5SDimitry Andric // Check to see if SuccBB has PHI nodes. If so, we need to add entries to 10240b57cec5SDimitry Andric // the PHI nodes for NewBB now. 10250b57cec5SDimitry Andric for (auto &BBMapping : Orig2Clone) { 10260b57cec5SDimitry Andric BasicBlock *OldBlock = BBMapping.first; 10270b57cec5SDimitry Andric BasicBlock *NewBlock = BBMapping.second; 10280b57cec5SDimitry Andric for (BasicBlock *SuccBB : successors(NewBlock)) { 10290b57cec5SDimitry Andric for (PHINode &SuccPN : SuccBB->phis()) { 10300b57cec5SDimitry Andric // Ok, we have a PHI node. Figure out what the incoming value was for 10310b57cec5SDimitry Andric // the OldBlock. 10320b57cec5SDimitry Andric int OldBlockIdx = SuccPN.getBasicBlockIndex(OldBlock); 10330b57cec5SDimitry Andric if (OldBlockIdx == -1) 10340b57cec5SDimitry Andric break; 10350b57cec5SDimitry Andric Value *IV = SuccPN.getIncomingValue(OldBlockIdx); 10360b57cec5SDimitry Andric 10370b57cec5SDimitry Andric // Remap the value if necessary. 10380b57cec5SDimitry Andric if (auto *Inst = dyn_cast<Instruction>(IV)) { 10390b57cec5SDimitry Andric ValueToValueMapTy::iterator I = VMap.find(Inst); 10400b57cec5SDimitry Andric if (I != VMap.end()) 10410b57cec5SDimitry Andric IV = I->second; 10420b57cec5SDimitry Andric } 10430b57cec5SDimitry Andric 10440b57cec5SDimitry Andric SuccPN.addIncoming(IV, NewBlock); 10450b57cec5SDimitry Andric } 10460b57cec5SDimitry Andric } 10470b57cec5SDimitry Andric } 10480b57cec5SDimitry Andric 10490b57cec5SDimitry Andric for (ValueToValueMapTy::value_type VT : VMap) { 10500b57cec5SDimitry Andric // If there were values defined in BB that are used outside the funclet, 10510b57cec5SDimitry Andric // then we now have to update all uses of the value to use either the 10520b57cec5SDimitry Andric // original value, the cloned value, or some PHI derived value. This can 10530b57cec5SDimitry Andric // require arbitrary PHI insertion, of which we are prepared to do, clean 10540b57cec5SDimitry Andric // these up now. 10550b57cec5SDimitry Andric SmallVector<Use *, 16> UsesToRename; 10560b57cec5SDimitry Andric 10570b57cec5SDimitry Andric auto *OldI = dyn_cast<Instruction>(const_cast<Value *>(VT.first)); 10580b57cec5SDimitry Andric if (!OldI) 10590b57cec5SDimitry Andric continue; 10600b57cec5SDimitry Andric auto *NewI = cast<Instruction>(VT.second); 10610b57cec5SDimitry Andric // Scan all uses of this instruction to see if it is used outside of its 10620b57cec5SDimitry Andric // funclet, and if so, record them in UsesToRename. 10630b57cec5SDimitry Andric for (Use &U : OldI->uses()) { 10640b57cec5SDimitry Andric Instruction *UserI = cast<Instruction>(U.getUser()); 10650b57cec5SDimitry Andric BasicBlock *UserBB = UserI->getParent(); 10660b57cec5SDimitry Andric ColorVector &ColorsForUserBB = BlockColors[UserBB]; 10670b57cec5SDimitry Andric assert(!ColorsForUserBB.empty()); 10680b57cec5SDimitry Andric if (ColorsForUserBB.size() > 1 || 10690b57cec5SDimitry Andric *ColorsForUserBB.begin() != FuncletPadBB) 10700b57cec5SDimitry Andric UsesToRename.push_back(&U); 10710b57cec5SDimitry Andric } 10720b57cec5SDimitry Andric 10730b57cec5SDimitry Andric // If there are no uses outside the block, we're done with this 10740b57cec5SDimitry Andric // instruction. 10750b57cec5SDimitry Andric if (UsesToRename.empty()) 10760b57cec5SDimitry Andric continue; 10770b57cec5SDimitry Andric 10780b57cec5SDimitry Andric // We found a use of OldI outside of the funclet. Rename all uses of OldI 10790b57cec5SDimitry Andric // that are outside its funclet to be uses of the appropriate PHI node 10800b57cec5SDimitry Andric // etc. 10810b57cec5SDimitry Andric SSAUpdater SSAUpdate; 10820b57cec5SDimitry Andric SSAUpdate.Initialize(OldI->getType(), OldI->getName()); 10830b57cec5SDimitry Andric SSAUpdate.AddAvailableValue(OldI->getParent(), OldI); 10840b57cec5SDimitry Andric SSAUpdate.AddAvailableValue(NewI->getParent(), NewI); 10850b57cec5SDimitry Andric 10860b57cec5SDimitry Andric while (!UsesToRename.empty()) 10870b57cec5SDimitry Andric SSAUpdate.RewriteUseAfterInsertions(*UsesToRename.pop_back_val()); 10880b57cec5SDimitry Andric } 10890b57cec5SDimitry Andric } 10900b57cec5SDimitry Andric } 10910b57cec5SDimitry Andric 10925f757f3fSDimitry Andric void WinEHPrepareImpl::removeImplausibleInstructions(Function &F) { 10930b57cec5SDimitry Andric // Remove implausible terminators and replace them with UnreachableInst. 10940b57cec5SDimitry Andric for (auto &Funclet : FuncletBlocks) { 10950b57cec5SDimitry Andric BasicBlock *FuncletPadBB = Funclet.first; 10960b57cec5SDimitry Andric std::vector<BasicBlock *> &BlocksInFunclet = Funclet.second; 10970b57cec5SDimitry Andric Instruction *FirstNonPHI = FuncletPadBB->getFirstNonPHI(); 10980b57cec5SDimitry Andric auto *FuncletPad = dyn_cast<FuncletPadInst>(FirstNonPHI); 10990b57cec5SDimitry Andric auto *CatchPad = dyn_cast_or_null<CatchPadInst>(FuncletPad); 11000b57cec5SDimitry Andric auto *CleanupPad = dyn_cast_or_null<CleanupPadInst>(FuncletPad); 11010b57cec5SDimitry Andric 11020b57cec5SDimitry Andric for (BasicBlock *BB : BlocksInFunclet) { 11030b57cec5SDimitry Andric for (Instruction &I : *BB) { 11045ffd83dbSDimitry Andric auto *CB = dyn_cast<CallBase>(&I); 11055ffd83dbSDimitry Andric if (!CB) 11060b57cec5SDimitry Andric continue; 11070b57cec5SDimitry Andric 11080b57cec5SDimitry Andric Value *FuncletBundleOperand = nullptr; 11095ffd83dbSDimitry Andric if (auto BU = CB->getOperandBundle(LLVMContext::OB_funclet)) 11100b57cec5SDimitry Andric FuncletBundleOperand = BU->Inputs.front(); 11110b57cec5SDimitry Andric 11120b57cec5SDimitry Andric if (FuncletBundleOperand == FuncletPad) 11130b57cec5SDimitry Andric continue; 11140b57cec5SDimitry Andric 11150b57cec5SDimitry Andric // Skip call sites which are nounwind intrinsics or inline asm. 11160b57cec5SDimitry Andric auto *CalledFn = 11175ffd83dbSDimitry Andric dyn_cast<Function>(CB->getCalledOperand()->stripPointerCasts()); 11185ffd83dbSDimitry Andric if (CalledFn && ((CalledFn->isIntrinsic() && CB->doesNotThrow()) || 11195ffd83dbSDimitry Andric CB->isInlineAsm())) 11200b57cec5SDimitry Andric continue; 11210b57cec5SDimitry Andric 11220b57cec5SDimitry Andric // This call site was not part of this funclet, remove it. 11235ffd83dbSDimitry Andric if (isa<InvokeInst>(CB)) { 11240b57cec5SDimitry Andric // Remove the unwind edge if it was an invoke. 11250b57cec5SDimitry Andric removeUnwindEdge(BB); 11260b57cec5SDimitry Andric // Get a pointer to the new call. 11270b57cec5SDimitry Andric BasicBlock::iterator CallI = 11280b57cec5SDimitry Andric std::prev(BB->getTerminator()->getIterator()); 11290b57cec5SDimitry Andric auto *CI = cast<CallInst>(&*CallI); 1130fe6060f1SDimitry Andric changeToUnreachable(CI); 11310b57cec5SDimitry Andric } else { 1132fe6060f1SDimitry Andric changeToUnreachable(&I); 11330b57cec5SDimitry Andric } 11340b57cec5SDimitry Andric 11350b57cec5SDimitry Andric // There are no more instructions in the block (except for unreachable), 11360b57cec5SDimitry Andric // we are done. 11370b57cec5SDimitry Andric break; 11380b57cec5SDimitry Andric } 11390b57cec5SDimitry Andric 11400b57cec5SDimitry Andric Instruction *TI = BB->getTerminator(); 11410b57cec5SDimitry Andric // CatchPadInst and CleanupPadInst can't transfer control to a ReturnInst. 11420b57cec5SDimitry Andric bool IsUnreachableRet = isa<ReturnInst>(TI) && FuncletPad; 11430b57cec5SDimitry Andric // The token consumed by a CatchReturnInst must match the funclet token. 11440b57cec5SDimitry Andric bool IsUnreachableCatchret = false; 11450b57cec5SDimitry Andric if (auto *CRI = dyn_cast<CatchReturnInst>(TI)) 11460b57cec5SDimitry Andric IsUnreachableCatchret = CRI->getCatchPad() != CatchPad; 11470b57cec5SDimitry Andric // The token consumed by a CleanupReturnInst must match the funclet token. 11480b57cec5SDimitry Andric bool IsUnreachableCleanupret = false; 11490b57cec5SDimitry Andric if (auto *CRI = dyn_cast<CleanupReturnInst>(TI)) 11500b57cec5SDimitry Andric IsUnreachableCleanupret = CRI->getCleanupPad() != CleanupPad; 11510b57cec5SDimitry Andric if (IsUnreachableRet || IsUnreachableCatchret || 11520b57cec5SDimitry Andric IsUnreachableCleanupret) { 1153fe6060f1SDimitry Andric changeToUnreachable(TI); 11540b57cec5SDimitry Andric } else if (isa<InvokeInst>(TI)) { 11550b57cec5SDimitry Andric if (Personality == EHPersonality::MSVC_CXX && CleanupPad) { 11560b57cec5SDimitry Andric // Invokes within a cleanuppad for the MSVC++ personality never 11570b57cec5SDimitry Andric // transfer control to their unwind edge: the personality will 11580b57cec5SDimitry Andric // terminate the program. 11590b57cec5SDimitry Andric removeUnwindEdge(BB); 11600b57cec5SDimitry Andric } 11610b57cec5SDimitry Andric } 11620b57cec5SDimitry Andric } 11630b57cec5SDimitry Andric } 11640b57cec5SDimitry Andric } 11650b57cec5SDimitry Andric 11665f757f3fSDimitry Andric void WinEHPrepareImpl::cleanupPreparedFunclets(Function &F) { 11670b57cec5SDimitry Andric // Clean-up some of the mess we made by removing useles PHI nodes, trivial 11680b57cec5SDimitry Andric // branches, etc. 1169fe6060f1SDimitry Andric for (BasicBlock &BB : llvm::make_early_inc_range(F)) { 1170fe6060f1SDimitry Andric SimplifyInstructionsInBlock(&BB); 1171fe6060f1SDimitry Andric ConstantFoldTerminator(&BB, /*DeleteDeadConditions=*/true); 1172fe6060f1SDimitry Andric MergeBlockIntoPredecessor(&BB); 11730b57cec5SDimitry Andric } 11740b57cec5SDimitry Andric 11750b57cec5SDimitry Andric // We might have some unreachable blocks after cleaning up some impossible 11760b57cec5SDimitry Andric // control flow. 11770b57cec5SDimitry Andric removeUnreachableBlocks(F); 11780b57cec5SDimitry Andric } 11790b57cec5SDimitry Andric 11800b57cec5SDimitry Andric #ifndef NDEBUG 11815f757f3fSDimitry Andric void WinEHPrepareImpl::verifyPreparedFunclets(Function &F) { 11820b57cec5SDimitry Andric for (BasicBlock &BB : F) { 11830b57cec5SDimitry Andric size_t NumColors = BlockColors[&BB].size(); 11840b57cec5SDimitry Andric assert(NumColors == 1 && "Expected monochromatic BB!"); 11850b57cec5SDimitry Andric if (NumColors == 0) 11860b57cec5SDimitry Andric report_fatal_error("Uncolored BB!"); 11870b57cec5SDimitry Andric if (NumColors > 1) 11880b57cec5SDimitry Andric report_fatal_error("Multicolor BB!"); 11890b57cec5SDimitry Andric assert((DisableDemotion || !(BB.isEHPad() && isa<PHINode>(BB.begin()))) && 11900b57cec5SDimitry Andric "EH Pad still has a PHI!"); 11910b57cec5SDimitry Andric } 11920b57cec5SDimitry Andric } 11930b57cec5SDimitry Andric #endif 11940b57cec5SDimitry Andric 11955f757f3fSDimitry Andric bool WinEHPrepareImpl::prepareExplicitEH(Function &F) { 11960b57cec5SDimitry Andric // Remove unreachable blocks. It is not valuable to assign them a color and 11970b57cec5SDimitry Andric // their existence can trick us into thinking values are alive when they are 11980b57cec5SDimitry Andric // not. 11990b57cec5SDimitry Andric removeUnreachableBlocks(F); 12000b57cec5SDimitry Andric 12010b57cec5SDimitry Andric // Determine which blocks are reachable from which funclet entries. 12020b57cec5SDimitry Andric colorFunclets(F); 12030b57cec5SDimitry Andric 12040b57cec5SDimitry Andric cloneCommonBlocks(F); 12050b57cec5SDimitry Andric 12060b57cec5SDimitry Andric if (!DisableDemotion) 12070b57cec5SDimitry Andric demotePHIsOnFunclets(F, DemoteCatchSwitchPHIOnly || 12080b57cec5SDimitry Andric DemoteCatchSwitchPHIOnlyOpt); 12090b57cec5SDimitry Andric 12100b57cec5SDimitry Andric if (!DisableCleanups) { 12115ffd83dbSDimitry Andric assert(!verifyFunction(F, &dbgs())); 12120b57cec5SDimitry Andric removeImplausibleInstructions(F); 12130b57cec5SDimitry Andric 12145ffd83dbSDimitry Andric assert(!verifyFunction(F, &dbgs())); 12150b57cec5SDimitry Andric cleanupPreparedFunclets(F); 12160b57cec5SDimitry Andric } 12170b57cec5SDimitry Andric 12180b57cec5SDimitry Andric LLVM_DEBUG(verifyPreparedFunclets(F)); 12190b57cec5SDimitry Andric // Recolor the CFG to verify that all is well. 12200b57cec5SDimitry Andric LLVM_DEBUG(colorFunclets(F)); 12210b57cec5SDimitry Andric LLVM_DEBUG(verifyPreparedFunclets(F)); 12220b57cec5SDimitry Andric 12230b57cec5SDimitry Andric return true; 12240b57cec5SDimitry Andric } 12250b57cec5SDimitry Andric 12260b57cec5SDimitry Andric // TODO: Share loads when one use dominates another, or when a catchpad exit 12270b57cec5SDimitry Andric // dominates uses (needs dominators). 12285f757f3fSDimitry Andric AllocaInst *WinEHPrepareImpl::insertPHILoads(PHINode *PN, Function &F) { 12290b57cec5SDimitry Andric BasicBlock *PHIBlock = PN->getParent(); 12300b57cec5SDimitry Andric AllocaInst *SpillSlot = nullptr; 12310b57cec5SDimitry Andric Instruction *EHPad = PHIBlock->getFirstNonPHI(); 12320b57cec5SDimitry Andric 12330b57cec5SDimitry Andric if (!EHPad->isTerminator()) { 12340b57cec5SDimitry Andric // If the EHPad isn't a terminator, then we can insert a load in this block 12350b57cec5SDimitry Andric // that will dominate all uses. 12360b57cec5SDimitry Andric SpillSlot = new AllocaInst(PN->getType(), DL->getAllocaAddrSpace(), nullptr, 12370b57cec5SDimitry Andric Twine(PN->getName(), ".wineh.spillslot"), 1238*0fca6ea1SDimitry Andric F.getEntryBlock().begin()); 12390b57cec5SDimitry Andric Value *V = new LoadInst(PN->getType(), SpillSlot, 12400b57cec5SDimitry Andric Twine(PN->getName(), ".wineh.reload"), 1241*0fca6ea1SDimitry Andric PHIBlock->getFirstInsertionPt()); 12420b57cec5SDimitry Andric PN->replaceAllUsesWith(V); 12430b57cec5SDimitry Andric return SpillSlot; 12440b57cec5SDimitry Andric } 12450b57cec5SDimitry Andric 12460b57cec5SDimitry Andric // Otherwise, we have a PHI on a terminator EHPad, and we give up and insert 12470b57cec5SDimitry Andric // loads of the slot before every use. 12480b57cec5SDimitry Andric DenseMap<BasicBlock *, Value *> Loads; 1249fe6060f1SDimitry Andric for (Use &U : llvm::make_early_inc_range(PN->uses())) { 12500b57cec5SDimitry Andric auto *UsingInst = cast<Instruction>(U.getUser()); 12510b57cec5SDimitry Andric if (isa<PHINode>(UsingInst) && UsingInst->getParent()->isEHPad()) { 12520b57cec5SDimitry Andric // Use is on an EH pad phi. Leave it alone; we'll insert loads and 12530b57cec5SDimitry Andric // stores for it separately. 12540b57cec5SDimitry Andric continue; 12550b57cec5SDimitry Andric } 12560b57cec5SDimitry Andric replaceUseWithLoad(PN, U, SpillSlot, Loads, F); 12570b57cec5SDimitry Andric } 12580b57cec5SDimitry Andric return SpillSlot; 12590b57cec5SDimitry Andric } 12600b57cec5SDimitry Andric 12610b57cec5SDimitry Andric // TODO: improve store placement. Inserting at def is probably good, but need 12620b57cec5SDimitry Andric // to be careful not to introduce interfering stores (needs liveness analysis). 12630b57cec5SDimitry Andric // TODO: identify related phi nodes that can share spill slots, and share them 12640b57cec5SDimitry Andric // (also needs liveness). 12655f757f3fSDimitry Andric void WinEHPrepareImpl::insertPHIStores(PHINode *OriginalPHI, 12660b57cec5SDimitry Andric AllocaInst *SpillSlot) { 12670b57cec5SDimitry Andric // Use a worklist of (Block, Value) pairs -- the given Value needs to be 12680b57cec5SDimitry Andric // stored to the spill slot by the end of the given Block. 12690b57cec5SDimitry Andric SmallVector<std::pair<BasicBlock *, Value *>, 4> Worklist; 12700b57cec5SDimitry Andric 12710b57cec5SDimitry Andric Worklist.push_back({OriginalPHI->getParent(), OriginalPHI}); 12720b57cec5SDimitry Andric 12730b57cec5SDimitry Andric while (!Worklist.empty()) { 12740b57cec5SDimitry Andric BasicBlock *EHBlock; 12750b57cec5SDimitry Andric Value *InVal; 12760b57cec5SDimitry Andric std::tie(EHBlock, InVal) = Worklist.pop_back_val(); 12770b57cec5SDimitry Andric 12780b57cec5SDimitry Andric PHINode *PN = dyn_cast<PHINode>(InVal); 12790b57cec5SDimitry Andric if (PN && PN->getParent() == EHBlock) { 12800b57cec5SDimitry Andric // The value is defined by another PHI we need to remove, with no room to 12810b57cec5SDimitry Andric // insert a store after the PHI, so each predecessor needs to store its 12820b57cec5SDimitry Andric // incoming value. 12830b57cec5SDimitry Andric for (unsigned i = 0, e = PN->getNumIncomingValues(); i < e; ++i) { 12840b57cec5SDimitry Andric Value *PredVal = PN->getIncomingValue(i); 12850b57cec5SDimitry Andric 12860b57cec5SDimitry Andric // Undef can safely be skipped. 12870b57cec5SDimitry Andric if (isa<UndefValue>(PredVal)) 12880b57cec5SDimitry Andric continue; 12890b57cec5SDimitry Andric 12900b57cec5SDimitry Andric insertPHIStore(PN->getIncomingBlock(i), PredVal, SpillSlot, Worklist); 12910b57cec5SDimitry Andric } 12920b57cec5SDimitry Andric } else { 12930b57cec5SDimitry Andric // We need to store InVal, which dominates EHBlock, but can't put a store 12940b57cec5SDimitry Andric // in EHBlock, so need to put stores in each predecessor. 12950b57cec5SDimitry Andric for (BasicBlock *PredBlock : predecessors(EHBlock)) { 12960b57cec5SDimitry Andric insertPHIStore(PredBlock, InVal, SpillSlot, Worklist); 12970b57cec5SDimitry Andric } 12980b57cec5SDimitry Andric } 12990b57cec5SDimitry Andric } 13000b57cec5SDimitry Andric } 13010b57cec5SDimitry Andric 13025f757f3fSDimitry Andric void WinEHPrepareImpl::insertPHIStore( 13030b57cec5SDimitry Andric BasicBlock *PredBlock, Value *PredVal, AllocaInst *SpillSlot, 13040b57cec5SDimitry Andric SmallVectorImpl<std::pair<BasicBlock *, Value *>> &Worklist) { 13050b57cec5SDimitry Andric 13060b57cec5SDimitry Andric if (PredBlock->isEHPad() && PredBlock->getFirstNonPHI()->isTerminator()) { 13070b57cec5SDimitry Andric // Pred is unsplittable, so we need to queue it on the worklist. 13080b57cec5SDimitry Andric Worklist.push_back({PredBlock, PredVal}); 13090b57cec5SDimitry Andric return; 13100b57cec5SDimitry Andric } 13110b57cec5SDimitry Andric 13120b57cec5SDimitry Andric // Otherwise, insert the store at the end of the basic block. 1313*0fca6ea1SDimitry Andric new StoreInst(PredVal, SpillSlot, PredBlock->getTerminator()->getIterator()); 13140b57cec5SDimitry Andric } 13150b57cec5SDimitry Andric 13165f757f3fSDimitry Andric void WinEHPrepareImpl::replaceUseWithLoad( 13175f757f3fSDimitry Andric Value *V, Use &U, AllocaInst *&SpillSlot, 13185f757f3fSDimitry Andric DenseMap<BasicBlock *, Value *> &Loads, Function &F) { 13190b57cec5SDimitry Andric // Lazilly create the spill slot. 13200b57cec5SDimitry Andric if (!SpillSlot) 13210b57cec5SDimitry Andric SpillSlot = new AllocaInst(V->getType(), DL->getAllocaAddrSpace(), nullptr, 13220b57cec5SDimitry Andric Twine(V->getName(), ".wineh.spillslot"), 1323*0fca6ea1SDimitry Andric F.getEntryBlock().begin()); 13240b57cec5SDimitry Andric 13250b57cec5SDimitry Andric auto *UsingInst = cast<Instruction>(U.getUser()); 13260b57cec5SDimitry Andric if (auto *UsingPHI = dyn_cast<PHINode>(UsingInst)) { 13270b57cec5SDimitry Andric // If this is a PHI node, we can't insert a load of the value before 13280b57cec5SDimitry Andric // the use. Instead insert the load in the predecessor block 13290b57cec5SDimitry Andric // corresponding to the incoming value. 13300b57cec5SDimitry Andric // 13310b57cec5SDimitry Andric // Note that if there are multiple edges from a basic block to this 13320b57cec5SDimitry Andric // PHI node that we cannot have multiple loads. The problem is that 13330b57cec5SDimitry Andric // the resulting PHI node will have multiple values (from each load) 13340b57cec5SDimitry Andric // coming in from the same block, which is illegal SSA form. 13350b57cec5SDimitry Andric // For this reason, we keep track of and reuse loads we insert. 13360b57cec5SDimitry Andric BasicBlock *IncomingBlock = UsingPHI->getIncomingBlock(U); 13370b57cec5SDimitry Andric if (auto *CatchRet = 13380b57cec5SDimitry Andric dyn_cast<CatchReturnInst>(IncomingBlock->getTerminator())) { 13390b57cec5SDimitry Andric // Putting a load above a catchret and use on the phi would still leave 13400b57cec5SDimitry Andric // a cross-funclet def/use. We need to split the edge, change the 13410b57cec5SDimitry Andric // catchret to target the new block, and put the load there. 13420b57cec5SDimitry Andric BasicBlock *PHIBlock = UsingInst->getParent(); 13430b57cec5SDimitry Andric BasicBlock *NewBlock = SplitEdge(IncomingBlock, PHIBlock); 13440b57cec5SDimitry Andric // SplitEdge gives us: 13450b57cec5SDimitry Andric // IncomingBlock: 13460b57cec5SDimitry Andric // ... 13470b57cec5SDimitry Andric // br label %NewBlock 13480b57cec5SDimitry Andric // NewBlock: 13490b57cec5SDimitry Andric // catchret label %PHIBlock 13500b57cec5SDimitry Andric // But we need: 13510b57cec5SDimitry Andric // IncomingBlock: 13520b57cec5SDimitry Andric // ... 13530b57cec5SDimitry Andric // catchret label %NewBlock 13540b57cec5SDimitry Andric // NewBlock: 13550b57cec5SDimitry Andric // br label %PHIBlock 13560b57cec5SDimitry Andric // So move the terminators to each others' blocks and swap their 13570b57cec5SDimitry Andric // successors. 13580b57cec5SDimitry Andric BranchInst *Goto = cast<BranchInst>(IncomingBlock->getTerminator()); 13590b57cec5SDimitry Andric Goto->removeFromParent(); 13600b57cec5SDimitry Andric CatchRet->removeFromParent(); 1361bdd1243dSDimitry Andric CatchRet->insertInto(IncomingBlock, IncomingBlock->end()); 1362bdd1243dSDimitry Andric Goto->insertInto(NewBlock, NewBlock->end()); 13630b57cec5SDimitry Andric Goto->setSuccessor(0, PHIBlock); 13640b57cec5SDimitry Andric CatchRet->setSuccessor(NewBlock); 13650b57cec5SDimitry Andric // Update the color mapping for the newly split edge. 13660b57cec5SDimitry Andric // Grab a reference to the ColorVector to be inserted before getting the 13670b57cec5SDimitry Andric // reference to the vector we are copying because inserting the new 13680b57cec5SDimitry Andric // element in BlockColors might cause the map to be reallocated. 13690b57cec5SDimitry Andric ColorVector &ColorsForNewBlock = BlockColors[NewBlock]; 13700b57cec5SDimitry Andric ColorVector &ColorsForPHIBlock = BlockColors[PHIBlock]; 13710b57cec5SDimitry Andric ColorsForNewBlock = ColorsForPHIBlock; 13720b57cec5SDimitry Andric for (BasicBlock *FuncletPad : ColorsForPHIBlock) 13730b57cec5SDimitry Andric FuncletBlocks[FuncletPad].push_back(NewBlock); 13740b57cec5SDimitry Andric // Treat the new block as incoming for load insertion. 13750b57cec5SDimitry Andric IncomingBlock = NewBlock; 13760b57cec5SDimitry Andric } 13770b57cec5SDimitry Andric Value *&Load = Loads[IncomingBlock]; 13780b57cec5SDimitry Andric // Insert the load into the predecessor block 13790b57cec5SDimitry Andric if (!Load) 1380*0fca6ea1SDimitry Andric Load = new LoadInst( 1381*0fca6ea1SDimitry Andric V->getType(), SpillSlot, Twine(V->getName(), ".wineh.reload"), 1382*0fca6ea1SDimitry Andric /*isVolatile=*/false, IncomingBlock->getTerminator()->getIterator()); 13830b57cec5SDimitry Andric 13840b57cec5SDimitry Andric U.set(Load); 13850b57cec5SDimitry Andric } else { 13860b57cec5SDimitry Andric // Reload right before the old use. 13870b57cec5SDimitry Andric auto *Load = new LoadInst(V->getType(), SpillSlot, 13880b57cec5SDimitry Andric Twine(V->getName(), ".wineh.reload"), 1389*0fca6ea1SDimitry Andric /*isVolatile=*/false, UsingInst->getIterator()); 13900b57cec5SDimitry Andric U.set(Load); 13910b57cec5SDimitry Andric } 13920b57cec5SDimitry Andric } 13930b57cec5SDimitry Andric 13940b57cec5SDimitry Andric void WinEHFuncInfo::addIPToStateRange(const InvokeInst *II, 13950b57cec5SDimitry Andric MCSymbol *InvokeBegin, 13960b57cec5SDimitry Andric MCSymbol *InvokeEnd) { 13970b57cec5SDimitry Andric assert(InvokeStateMap.count(II) && 13980b57cec5SDimitry Andric "should get invoke with precomputed state"); 13990b57cec5SDimitry Andric LabelToStateMap[InvokeBegin] = std::make_pair(InvokeStateMap[II], InvokeEnd); 14000b57cec5SDimitry Andric } 14010b57cec5SDimitry Andric 140206c3fb27SDimitry Andric void WinEHFuncInfo::addIPToStateRange(int State, MCSymbol* InvokeBegin, 140306c3fb27SDimitry Andric MCSymbol* InvokeEnd) { 140406c3fb27SDimitry Andric LabelToStateMap[InvokeBegin] = std::make_pair(State, InvokeEnd); 140506c3fb27SDimitry Andric } 140606c3fb27SDimitry Andric 140781ad6265SDimitry Andric WinEHFuncInfo::WinEHFuncInfo() = default; 1408