From 201f5f039f25921b459263e4fb71e3dc4925ecf0 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 29 Mar 2010 23:37:07 +0000 Subject: Re-add back in the slow way of determining of a clean-up should become a catch-all. The "dominates" way won't catch all of the selectors which must be changed. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@99850 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/DwarfEHPrepare.cpp | 135 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) (limited to 'lib/CodeGen/DwarfEHPrepare.cpp') diff --git a/lib/CodeGen/DwarfEHPrepare.cpp b/lib/CodeGen/DwarfEHPrepare.cpp index 1416f5b..8bae9ed 100644 --- a/lib/CodeGen/DwarfEHPrepare.cpp +++ b/lib/CodeGen/DwarfEHPrepare.cpp @@ -101,6 +101,57 @@ namespace { /// pad. bool HandleURoRInvokes(); + /// FindSelectorAndURoR - Find the eh.selector call and URoR call associated + /// with the eh.exception call. This recursively looks past instructions + /// which don't change the EH pointer value, like casts or PHI nodes. + bool FindSelectorAndURoR(Instruction *Inst, bool &URoRInvoke, + SmallPtrSet &SelCalls); + + /// DoMem2RegPromotion - Take an alloca call and promote it from memory to a + /// register. + bool DoMem2RegPromotion(Value *V) { + AllocaInst *AI = dyn_cast(V); + if (!AI || !isAllocaPromotable(AI)) return false; + + // Turn the alloca into a register. + std::vector Allocas(1, AI); + PromoteMemToReg(Allocas, *DT, *DF); + return true; + } + + /// PromoteStoreInst - Perform Mem2Reg on a StoreInst. + bool PromoteStoreInst(StoreInst *SI) { + if (!SI || !DT || !DF) return false; + if (DoMem2RegPromotion(SI->getOperand(1))) + return true; + return false; + } + + /// PromoteEHPtrStore - Promote the storing of an EH pointer into a + /// register. This should get rid of the store and subsequent loads. + bool PromoteEHPtrStore(IntrinsicInst *II) { + if (!DT || !DF) return false; + + bool Changed = false; + StoreInst *SI; + + while (1) { + SI = 0; + for (Value::use_iterator + I = II->use_begin(), E = II->use_end(); I != E; ++I) { + SI = dyn_cast(I); + if (SI) break; + } + + if (!PromoteStoreInst(SI)) + break; + + Changed = true; + } + + return false; + } + public: static char ID; // Pass identification, replacement for typeid. DwarfEHPrepare(const TargetLowering *tli, bool fast) : @@ -196,6 +247,45 @@ bool DwarfEHPrepare::CleanupSelectors() { return Changed; } +/// FindSelectorAndURoR - Find the eh.selector call associated with the +/// eh.exception call. And indicate if there is a URoR "invoke" associated with +/// the eh.exception call. This recursively looks past instructions which don't +/// change the EH pointer value, like casts or PHI nodes. +bool +DwarfEHPrepare::FindSelectorAndURoR(Instruction *Inst, bool &URoRInvoke, + SmallPtrSet &SelCalls) { + SmallPtrSet SeenPHIs; + bool Changed = false; + + restart: + for (Value::use_iterator + I = Inst->use_begin(), E = Inst->use_end(); I != E; ++I) { + Instruction *II = dyn_cast(I); + if (!II || II->getParent()->getParent() != F) continue; + + if (IntrinsicInst *Sel = dyn_cast(II)) { + if (Sel->getIntrinsicID() == Intrinsic::eh_selector) + SelCalls.insert(Sel); + } else if (InvokeInst *Invoke = dyn_cast(II)) { + if (Invoke->getCalledFunction() == URoR) + URoRInvoke = true; + } else if (CastInst *CI = dyn_cast(II)) { + Changed |= FindSelectorAndURoR(CI, URoRInvoke, SelCalls); + } else if (StoreInst *SI = dyn_cast(II)) { + if (!PromoteStoreInst(SI)) continue; + Changed = true; + SeenPHIs.clear(); + goto restart; // Uses may have changed, restart loop. + } else if (PHINode *PN = dyn_cast(II)) { + if (SeenPHIs.insert(PN)) + // Don't process a PHI node more than once. + Changed |= FindSelectorAndURoR(PN, URoRInvoke, SelCalls); + } + } + + return Changed; +} + /// HandleURoRInvokes - Handle invokes of "_Unwind_Resume_or_Rethrow" calls. The /// "unwind" part of these invokes jump to a landing pad within the current /// function. This is a candidate to merge the selector associated with the URoR @@ -242,6 +332,51 @@ bool DwarfEHPrepare::HandleURoRInvokes() { bool Changed = false; + if (Sels.size() != SelsToConvert.size()) { + // If we haven't been able to convert all of the clean-up selectors, then + // loop through the slow way to see if they still need to be converted. + if (!ExceptionValueIntrinsic) { + ExceptionValueIntrinsic = + Intrinsic::getDeclaration(F->getParent(), Intrinsic::eh_exception); + if (!ExceptionValueIntrinsic) return CleanupSelectors(); + } + + for (Value::use_iterator + I = ExceptionValueIntrinsic->use_begin(), + E = ExceptionValueIntrinsic->use_end(); I != E; ++I) { + IntrinsicInst *EHPtr = dyn_cast(I); + if (!EHPtr || EHPtr->getParent()->getParent() != F) continue; + + Changed |= PromoteEHPtrStore(EHPtr); + + bool URoRInvoke = false; + SmallPtrSet SelCalls; + Changed |= FindSelectorAndURoR(EHPtr, URoRInvoke, SelCalls); + + if (URoRInvoke) { + // This EH pointer is being used by an invoke of an URoR instruction and + // an eh.selector intrinsic call. If the eh.selector is a 'clean-up', we + // need to convert it to a 'catch-all'. + for (SmallPtrSet::iterator + SI = SelCalls.begin(), SE = SelCalls.end(); SI != SE; ++SI) { + IntrinsicInst *II = *SI; + unsigned NumOps = II->getNumOperands(); + + if (NumOps <= 4) { + bool IsCleanUp = (NumOps == 3); + + if (!IsCleanUp) + if (ConstantInt *CI = dyn_cast(II->getOperand(3))) + IsCleanUp = (CI->getZExtValue() == 0); + + if (IsCleanUp) + SelsToConvert.insert(II); + } + } + } + } + } + if (!SelsToConvert.empty()) { // Convert all clean-up eh.selectors, which are associated with "invokes" of // URoR calls, into catch-all eh.selectors. -- cgit v1.1