#include "llvm/Analysis/Dominators.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/Support/CallSite.h"
#include "llvm/Target/TargetLowering.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/PromoteMemToReg.h"
namespace {
class DwarfEHPrepare : public FunctionPass {
+ const TargetMachine *TM;
const TargetLowering *TLI;
bool CompileFast;
}
/// CleanupSelectors - Any remaining eh.selector intrinsic calls which still
- /// use the ".llvm.eh.catch.all.value" call need to convert to using it's
+ /// use the "llvm.eh.catch.all.value" call need to convert to using its
/// initializer instead.
- bool CleanupSelectors();
+ bool CleanupSelectors(SmallPtrSet<IntrinsicInst*, 32> &Sels);
+
+ bool HasCatchAllInSelector(IntrinsicInst *);
/// FindAllCleanupSelectors - Find all eh.selector calls that are clean-ups.
- void FindAllCleanupSelectors(SmallPtrSet<IntrinsicInst*, 32> &Sels);
+ void FindAllCleanupSelectors(SmallPtrSet<IntrinsicInst*, 32> &Sels,
+ SmallPtrSet<IntrinsicInst*, 32> &CatchAllSels);
/// FindAllURoRInvokes - Find all URoR invokes in the function.
void FindAllURoRInvokes(SmallPtrSet<InvokeInst*, 32> &URoRInvokes);
/// 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<IntrinsicInst*, 8> &SelCalls);
+
+ /// DoMem2RegPromotion - Take an alloca call and promote it from memory to a
+ /// register.
+ bool DoMem2RegPromotion(Value *V) {
+ AllocaInst *AI = dyn_cast<AllocaInst>(V);
+ if (!AI || !isAllocaPromotable(AI)) return false;
+
+ // Turn the alloca into a register.
+ std::vector<AllocaInst*> 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<StoreInst>(*I);
+ if (SI) break;
+ }
+
+ if (!PromoteStoreInst(SI))
+ break;
+
+ Changed = true;
+ }
+
+ return Changed;
+ }
+
public:
static char ID; // Pass identification, replacement for typeid.
- DwarfEHPrepare(const TargetLowering *tli, bool fast) :
- FunctionPass(&ID), TLI(tli), CompileFast(fast),
+ DwarfEHPrepare(const TargetMachine *tm, bool fast) :
+ FunctionPass(ID), TM(tm), TLI(TM->getTargetLowering()),
+ CompileFast(fast),
ExceptionValueIntrinsic(0), SelectorIntrinsic(0),
URoR(0), EHCatchAllValue(0), RewindFunction(0) {}
char DwarfEHPrepare::ID = 0;
-FunctionPass *llvm::createDwarfEHPass(const TargetLowering *tli, bool fast) {
- return new DwarfEHPrepare(tli, fast);
+FunctionPass *llvm::createDwarfEHPass(const TargetMachine *tm, bool fast) {
+ return new DwarfEHPrepare(tm, fast);
+}
+
+/// HasCatchAllInSelector - Return true if the intrinsic instruction has a
+/// catch-all.
+bool DwarfEHPrepare::HasCatchAllInSelector(IntrinsicInst *II) {
+ if (!EHCatchAllValue) return false;
+
+ unsigned ArgIdx = II->getNumArgOperands() - 1;
+ GlobalVariable *GV = dyn_cast<GlobalVariable>(II->getArgOperand(ArgIdx));
+ return GV == EHCatchAllValue;
}
/// FindAllCleanupSelectors - Find all eh.selector calls that are clean-ups.
void DwarfEHPrepare::
-FindAllCleanupSelectors(SmallPtrSet<IntrinsicInst*, 32> &Sels) {
+FindAllCleanupSelectors(SmallPtrSet<IntrinsicInst*, 32> &Sels,
+ SmallPtrSet<IntrinsicInst*, 32> &CatchAllSels) {
for (Value::use_iterator
I = SelectorIntrinsic->use_begin(),
E = SelectorIntrinsic->use_end(); I != E; ++I) {
- IntrinsicInst *SI = cast<IntrinsicInst>(I);
- if (!SI || SI->getParent()->getParent() != F) continue;
-
- unsigned NumOps = SI->getNumOperands();
- if (NumOps > 4) continue;
- bool IsCleanUp = (NumOps == 3);
+ IntrinsicInst *II = cast<IntrinsicInst>(*I);
- if (!IsCleanUp)
- if (ConstantInt *CI = dyn_cast<ConstantInt>(SI->getOperand(3)))
- IsCleanUp = (CI->getZExtValue() == 0);
+ if (II->getParent()->getParent() != F)
+ continue;
- if (IsCleanUp)
- Sels.insert(SI);
+ if (!HasCatchAllInSelector(II))
+ Sels.insert(II);
+ else
+ CatchAllSels.insert(II);
}
}
for (Value::use_iterator
I = URoR->use_begin(),
E = URoR->use_end(); I != E; ++I) {
- if (InvokeInst *II = dyn_cast<InvokeInst>(I))
+ if (InvokeInst *II = dyn_cast<InvokeInst>(*I))
URoRInvokes.insert(II);
}
}
/// CleanupSelectors - Any remaining eh.selector intrinsic calls which still use
-/// the ".llvm.eh.catch.all.value" call need to convert to using it's
+/// the "llvm.eh.catch.all.value" call need to convert to using its
/// initializer instead.
-bool DwarfEHPrepare::CleanupSelectors() {
+bool DwarfEHPrepare::CleanupSelectors(SmallPtrSet<IntrinsicInst*, 32> &Sels) {
if (!EHCatchAllValue) return false;
if (!SelectorIntrinsic) {
}
bool Changed = false;
- for (Value::use_iterator
- I = SelectorIntrinsic->use_begin(),
- E = SelectorIntrinsic->use_end(); I != E; ++I) {
- IntrinsicInst *Sel = dyn_cast<IntrinsicInst>(I);
- if (!Sel || Sel->getParent()->getParent() != F) continue;
+ for (SmallPtrSet<IntrinsicInst*, 32>::iterator
+ I = Sels.begin(), E = Sels.end(); I != E; ++I) {
+ IntrinsicInst *Sel = *I;
- // Index of the ".llvm.eh.catch.all.value" variable.
- unsigned OpIdx = Sel->getNumOperands() - 1;
- GlobalVariable *GV = dyn_cast<GlobalVariable>(Sel->getOperand(OpIdx));
+ // Index of the "llvm.eh.catch.all.value" variable.
+ unsigned OpIdx = Sel->getNumArgOperands() - 1;
+ GlobalVariable *GV = dyn_cast<GlobalVariable>(Sel->getArgOperand(OpIdx));
if (GV != EHCatchAllValue) continue;
- Sel->setOperand(OpIdx, EHCatchAllValue->getInitializer());
+ Sel->setArgOperand(OpIdx, EHCatchAllValue->getInitializer());
Changed = true;
}
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<IntrinsicInst*, 8> &SelCalls) {
+ SmallPtrSet<PHINode*, 32> SeenPHIs;
+ bool Changed = false;
+
+ restart:
+ for (Value::use_iterator
+ I = Inst->use_begin(), E = Inst->use_end(); I != E; ++I) {
+ Instruction *II = dyn_cast<Instruction>(*I);
+ if (!II || II->getParent()->getParent() != F) continue;
+
+ if (IntrinsicInst *Sel = dyn_cast<IntrinsicInst>(II)) {
+ if (Sel->getIntrinsicID() == Intrinsic::eh_selector)
+ SelCalls.insert(Sel);
+ } else if (InvokeInst *Invoke = dyn_cast<InvokeInst>(II)) {
+ if (Invoke->getCalledFunction() == URoR)
+ URoRInvoke = true;
+ } else if (CastInst *CI = dyn_cast<CastInst>(II)) {
+ Changed |= FindSelectorAndURoR(CI, URoRInvoke, SelCalls);
+ } else if (StoreInst *SI = dyn_cast<StoreInst>(II)) {
+ if (!PromoteStoreInst(SI)) continue;
+ Changed = true;
+ SeenPHIs.clear();
+ goto restart; // Uses may have changed, restart loop.
+ } else if (PHINode *PN = dyn_cast<PHINode>(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
/// invoke with the one from the URoR's landing pad.
bool DwarfEHPrepare::HandleURoRInvokes() {
- if (!DT) return CleanupSelectors(); // We require DominatorTree information.
-
if (!EHCatchAllValue) {
EHCatchAllValue =
- F->getParent()->getNamedGlobal(".llvm.eh.catch.all.value");
+ F->getParent()->getNamedGlobal("llvm.eh.catch.all.value");
if (!EHCatchAllValue) return false;
}
if (!SelectorIntrinsic) return false;
}
+ SmallPtrSet<IntrinsicInst*, 32> Sels;
+ SmallPtrSet<IntrinsicInst*, 32> CatchAllSels;
+ FindAllCleanupSelectors(Sels, CatchAllSels);
+
+ if (!DT)
+ // We require DominatorTree information.
+ return CleanupSelectors(CatchAllSels);
+
if (!URoR) {
URoR = F->getParent()->getFunction("_Unwind_Resume_or_Rethrow");
- if (!URoR) return CleanupSelectors();
+ if (!URoR) return CleanupSelectors(CatchAllSels);
}
- SmallPtrSet<IntrinsicInst*, 32> Sels;
SmallPtrSet<InvokeInst*, 32> URoRInvokes;
- FindAllCleanupSelectors(Sels);
FindAllURoRInvokes(URoRInvokes);
SmallPtrSet<IntrinsicInst*, 32> SelsToConvert;
for (SmallPtrSet<InvokeInst*, 32>::iterator
UI = URoRInvokes.begin(), UE = URoRInvokes.end(); UI != UE; ++UI) {
const BasicBlock *URoRBB = (*UI)->getParent();
- if (SelBB == URoRBB || DT->dominates(SelBB, URoRBB)) {
+ if (DT->dominates(SelBB, URoRBB)) {
SelsToConvert.insert(*SI);
break;
}
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(CatchAllSels);
+ }
+
+ for (Value::use_iterator
+ I = ExceptionValueIntrinsic->use_begin(),
+ E = ExceptionValueIntrinsic->use_end(); I != E; ++I) {
+ IntrinsicInst *EHPtr = dyn_cast<IntrinsicInst>(*I);
+ if (!EHPtr || EHPtr->getParent()->getParent() != F) continue;
+
+ Changed |= PromoteEHPtrStore(EHPtr);
+
+ bool URoRInvoke = false;
+ SmallPtrSet<IntrinsicInst*, 8> 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<IntrinsicInst*, 8>::iterator
+ SI = SelCalls.begin(), SE = SelCalls.end(); SI != SE; ++SI)
+ if (!HasCatchAllInSelector(*SI))
+ SelsToConvert.insert(*SI);
+ }
+ }
+ }
+
if (!SelsToConvert.empty()) {
// Convert all clean-up eh.selectors, which are associated with "invokes" of
// URoR calls, into catch-all eh.selectors.
SI = SelsToConvert.begin(), SE = SelsToConvert.end();
SI != SE; ++SI) {
IntrinsicInst *II = *SI;
- SmallVector<Value*, 8> Args;
// Use the exception object pointer and the personality function
// from the original selector.
- Args.push_back(II->getOperand(1)); // Exception object pointer.
- Args.push_back(II->getOperand(2)); // Personality function.
+ CallSite CS(II);
+ IntrinsicInst::op_iterator I = CS.arg_begin();
+ IntrinsicInst::op_iterator E = CS.arg_end();
+ IntrinsicInst::op_iterator B = prior(E);
+
+ // Exclude last argument if it is an integer.
+ if (isa<ConstantInt>(B)) E = B;
+
+ // Add exception object pointer (front).
+ // Add personality function (next).
+ // Add in any filter IDs (rest).
+ SmallVector<Value*, 8> Args(I, E);
+
Args.push_back(EHCatchAllValue->getInitializer()); // Catch-all indicator.
CallInst *NewSelector =
}
}
- Changed |= CleanupSelectors();
+ Changed |= CleanupSelectors(CatchAllSels);
return Changed;
}
bool DwarfEHPrepare::NormalizeLandingPads() {
bool Changed = false;
- const MCAsmInfo *MAI = TLI->getTargetMachine().getMCAsmInfo();
+ const MCAsmInfo *MAI = TM->getMCAsmInfo();
bool usingSjLjEH = MAI->getExceptionHandlingType() == ExceptionHandling::SjLj;
for (Function::iterator I = F->begin(), E = F->end(); I != E; ++I) {
/// the start of the basic block (unless there already is one, in which case
/// the existing call is returned).
Instruction *DwarfEHPrepare::CreateExceptionValueCall(BasicBlock *BB) {
- Instruction *Start = BB->getFirstNonPHI();
+ Instruction *Start = BB->getFirstNonPHIOrDbg();
// Is this a call to eh.exception?
if (IntrinsicInst *CI = dyn_cast<IntrinsicInst>(Start))
if (CI->getIntrinsicID() == Intrinsic::eh_exception)
/// (creating it if necessary) at the start of the basic block (unless
/// there already is a load, in which case the existing load is returned).
Instruction *DwarfEHPrepare::CreateValueLoad(BasicBlock *BB) {
- Instruction *Start = BB->getFirstNonPHI();
+ Instruction *Start = BB->getFirstNonPHIOrDbg();
// Is this a load of the exception temporary?
if (ExceptionValueVar)
if (LoadInst* LI = dyn_cast<LoadInst>(Start))