[llvm-branch-commits] [llvm-tag] r97293 - in /llvm/tags/Apple/llvmCore-2325: ./ lib/CodeGen/DwarfEHPrepare.cpp

Bill Wendling isanbard at gmail.com
Fri Feb 26 16:49:24 PST 2010


Author: void
Date: Fri Feb 26 18:49:24 2010
New Revision: 97293

URL: http://llvm.org/viewvc/llvm-project?rev=97293&view=rev
Log:
Copy of Hermes to test EH patch.

Added:
    llvm/tags/Apple/llvmCore-2325/
      - copied from r97287, llvm/branches/Apple/Hermes/
Modified:
    llvm/tags/Apple/llvmCore-2325/lib/CodeGen/DwarfEHPrepare.cpp

Modified: llvm/tags/Apple/llvmCore-2325/lib/CodeGen/DwarfEHPrepare.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/tags/Apple/llvmCore-2325/lib/CodeGen/DwarfEHPrepare.cpp?rev=97293&r1=97287&r2=97293&view=diff
==============================================================================
--- llvm/tags/Apple/llvmCore-2325/lib/CodeGen/DwarfEHPrepare.cpp (original)
+++ llvm/tags/Apple/llvmCore-2325/lib/CodeGen/DwarfEHPrepare.cpp Fri Feb 26 18:49:24 2010
@@ -8,23 +8,24 @@
 //===----------------------------------------------------------------------===//
 //
 // This pass mulches exception handling code into a form adapted to code
-// generation.  Required if using dwarf exception handling.
+// generation. Required if using dwarf exception handling.
 //
 //===----------------------------------------------------------------------===//
 
 #define DEBUG_TYPE "dwarfehprepare"
-#include "llvm/ADT/Statistic.h"
-#include "llvm/Analysis/Dominators.h"
-#include "llvm/CodeGen/Passes.h"
 #include "llvm/Function.h"
 #include "llvm/Instructions.h"
 #include "llvm/IntrinsicInst.h"
 #include "llvm/Module.h"
 #include "llvm/Pass.h"
+#include "llvm/Analysis/Dominators.h"
+#include "llvm/CodeGen/Passes.h"
 #include "llvm/MC/MCAsmInfo.h"
+#include "llvm/Support/ErrorHandling.h"
 #include "llvm/Target/TargetLowering.h"
 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
 #include "llvm/Transforms/Utils/PromoteMemToReg.h"
+#include "llvm/ADT/Statistic.h"
 using namespace llvm;
 
 STATISTIC(NumLandingPadsSplit,     "Number of landing pads split");
@@ -40,6 +41,12 @@
     // The eh.exception intrinsic.
     Function *ExceptionValueIntrinsic;
 
+    // The eh.selector intrinsic.
+    Function *SelectorIntrinsic;
+
+    // _Unwind_Resume_or_Rethrow call.
+    Constant *URoR;
+
     // _Unwind_Resume or the target equivalent.
     Constant *RewindFunction;
 
@@ -74,11 +81,125 @@
         CreateExceptionValueCall(BB) : CreateValueLoad(BB);
     }
 
+    /// FarmCatchTypesAndFilterIDs - Get all of the catch types and filter IDs
+    /// from an eh.selector call.
+    void FarmCatchTypesAndFilterIDs(Instruction *Sel,
+                                    SmallVectorImpl<Value*> &CatchTys,
+                                    SmallVectorImpl<Value*> &FilterIDs,
+                                    Value *&CatchAll,
+                                    bool &CleanupSpecified);
+
+    /// MergeSelectors - Take two selectors and merge them: combine their catch
+    /// types, filter IDs, and whether it should act like a catch-all or
+    /// clean-up. The new selector is inserted before Sel1.
+    CallInst *MergeSelectors(Instruction *Sel1, Instruction *Sel2);
+
+    /// 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 HandleURoRInvokes();
+
+    /// IsEHExceptionIntrinsic - Return "true" if this is a call to the
+    /// eh.exception intrinsic.
+    bool IsEHExceptionIntrinsic(const Value *I) const {
+      const IntrinsicInst *EH = dyn_cast<IntrinsicInst>(I);
+      return EH && EH->getIntrinsicID() == Intrinsic::eh_exception;
+    }
+
+    /// FindEHExceptionCall - Find the eh.exception call in the landing pad.
+    IntrinsicInst *FindEHExceptionCall(BasicBlock *LandingPad) {
+      for (BasicBlock::iterator
+             I = LandingPad->getFirstNonPHI(), E = LandingPad->end();
+           I != E; ++I)
+        if (IsEHExceptionIntrinsic(I))
+          return cast<IntrinsicInst>(I);
+
+      assert(0 && "Could not find eh.exception call in landing pad!");
+      return 0;
+    }
+
+    /// FindEHSelector - Find the eh.selector intrinsic call associated with the
+    /// eh.exception intrinsic call. We're making the assumption that there's
+    /// one and only one eh.selector call associated with a call to
+    /// eh.exception.
+    IntrinsicInst *FindEHSelector(Value *EHPtrVal) {
+      for (Value::use_iterator
+             I = EHPtrVal->use_begin(), E = EHPtrVal->use_end(); I != E; ++I)
+        if (IntrinsicInst *EH = dyn_cast<IntrinsicInst>(I))
+          if (EH->getIntrinsicID() == Intrinsic::eh_selector)
+            return EH;
+
+      return 0;
+    }
+
+    /// 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;
+    }
+
+    /// PromoteEHPointer - Promote the EH pointer, that the URoR invoke
+    /// reference and which is begin stored and loaded via a temporary, into
+    /// registers. This makes it much easier to find all of it's definitions and
+    /// uses.
+    bool PromoteEHPointer(InvokeInst *II) {
+      if (!DT || !DF) return false;
+
+      bool Changed = false;
+      Value *EHPtr = II->getOperand(3);
+
+      while (LoadInst *LI = dyn_cast<LoadInst>(EHPtr))
+        if (DoMem2RegPromotion(LI->getOperand(0))) {
+          EHPtr = II->getOperand(3); // Get new EH pointer.
+          Changed = true;
+        } else {
+          return Changed;
+        }
+
+      return Changed;
+    }
+
+    /// 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 (!SI) break;
+
+        if (DoMem2RegPromotion(SI->getOperand(1)))
+          Changed = true;
+        else
+          break;                // Bail.
+      }
+
+      return Changed;
+    }
+
   public:
     static char ID; // Pass identification, replacement for typeid.
     DwarfEHPrepare(const TargetLowering *tli, bool fast) :
       FunctionPass(&ID), TLI(tli), CompileFast(fast),
-      ExceptionValueIntrinsic(0), RewindFunction(0) {}
+      ExceptionValueIntrinsic(0), SelectorIntrinsic(0),
+      URoR(0), RewindFunction(0) {}
 
     virtual bool runOnFunction(Function &Fn);
 
@@ -105,6 +226,192 @@
   return new DwarfEHPrepare(tli, fast);
 }
 
+/// FarmCatchTypesAndFilterIDs - Get all of the catch types and filter IDs from
+/// an eh.selector call.
+void
+DwarfEHPrepare::FarmCatchTypesAndFilterIDs(Instruction *Sel,
+                                           SmallVectorImpl<Value*> &CatchTys,
+                                           SmallVectorImpl<Value*> &FilterIDs,
+                                           Value *&CatchAll,
+                                           bool &CleanupSpecified) {
+  assert(isa<IntrinsicInst>(Sel) &&
+         cast<IntrinsicInst>(Sel)->getIntrinsicID() ==
+         Intrinsic::eh_selector && "Expected a selector call!");
+  
+  unsigned NumOps = Sel->getNumOperands();
+  for (unsigned I = 3; I < NumOps; ++I) {
+    Value *Val = Sel->getOperand(I)->stripPointerCasts();
+
+    if (const ConstantInt *CI = dyn_cast<ConstantInt>(Val)) {
+      const APInt &Num = CI->getValue();
+      if (Num.isStrictlyPositive()) {
+        // A list of filter IDs follows.
+        uint64_t NumIDs = CI->getZExtValue() - 1; // 1-based counting.
+
+        for (uint64_t J = 0; J < NumIDs; ++J) {
+          Value *ID = Sel->getOperand(++I)->stripPointerCasts();
+
+          // We want the filter ID to be in the list only once.
+          bool IDExists = false;
+          for (SmallVectorImpl<Value*>::iterator
+                 FI = FilterIDs.begin(), FE = FilterIDs.end(); FI != FE; ++FI) {
+            if (*FI == ID) {
+              IDExists = true;
+              break;
+            }
+          }
+
+          if (!IDExists) FilterIDs.push_back(ID);
+        }
+      } else if (Num == 0) {
+        CleanupSpecified = true;
+      } else {
+        llvm_report_error("Negative entry in eh.selector call!");
+      }
+    } else if (isa<ConstantPointerNull>(Val)) {
+      // This is a catch-all. Get the original, non-stripped value so that we
+      // can cast it correctly in the new eh.selector call.
+      CatchAll = Sel->getOperand(I);
+    } else {
+      // We want the type to be in the list only once.
+      bool TypeExists = false;
+      for (SmallVectorImpl<Value*>::iterator
+             CI = CatchTys.begin(), CE = CatchTys.end(); CI != CE; ++CI)
+        if (*CI == Val) {
+          TypeExists = true;
+          break;
+        }
+
+      if (!TypeExists) CatchTys.push_back(Val);
+    }
+  }
+}
+
+/// MergeSelectors - Take two selectors and merge them: combine their catch
+/// types, filter IDs, and whether it should act like a catch-all or
+/// clean-up. The new selector is inserted before Sel1.
+CallInst *DwarfEHPrepare::MergeSelectors(Instruction *Sel1, Instruction *Sel2) {
+  LLVMContext &Ctx = F->getContext();
+
+  if (!SelectorIntrinsic)
+    SelectorIntrinsic = Intrinsic::getDeclaration(F->getParent(),
+                                                  Intrinsic::eh_selector);
+
+  SmallVector<Value*, 8> Args;
+
+  // Use the exception object pointer and the personality function from the LHS
+  // selector.
+  Args.push_back(Sel1->getOperand(1)); // Exception object pointer.
+  Args.push_back(Sel1->getOperand(2)); // Personality function.
+
+  // Gather all of the catch type and filter ID information from the original
+  // eh.selector calls. We'll use them to construct the new eh.selector call in
+  // the same format.
+  SmallVector<Value*, 8> CatchTys;
+  SmallVector<Value*, 8> FilterIDs;
+  Value *CatchAll = 0;
+  bool CleanupSpecified = false;
+
+  FarmCatchTypesAndFilterIDs(Sel1, CatchTys, FilterIDs, CatchAll,
+                             CleanupSpecified);
+  FarmCatchTypesAndFilterIDs(Sel2, CatchTys, FilterIDs, CatchAll,
+                             CleanupSpecified);
+
+  for (SmallVectorImpl<Value*>::iterator
+         I = CatchTys.begin(), E = CatchTys.end(); I != E; ++I)
+    Args.push_back(new BitCastInst(*I, Type::getInt8PtrTy(Ctx),
+                                   "", Sel1));
+
+  if (!FilterIDs.empty()) {
+    // Indicate the length of the filter IDs.
+    Args.push_back(ConstantInt::get(Type::getInt32Ty(Ctx),
+                                    FilterIDs.size() + 1));
+
+    for (SmallVectorImpl<Value*>::iterator
+           I = FilterIDs.begin(), E = FilterIDs.end(); I != E; ++I)
+      Args.push_back(new BitCastInst(*I, Type::getInt8PtrTy(Ctx),
+                                     "", Sel1));
+  }
+
+  // If there was a catch-all associated with either of the eh.selector calls,
+  // add it to the new one. Same for clean-ups. No need to add both. The
+  // catch-all should run any clean-ups automatically.
+  if (CatchAll)
+    Args.push_back(CatchAll);
+  else if (CleanupSpecified)
+    Args.push_back(ConstantInt::get(Type::getInt32Ty(Ctx), 0));
+
+  // Create the call.
+  return CallInst::Create(SelectorIntrinsic, Args.begin(), Args.end(),
+                          "eh.sel.merge", Sel1);
+}
+
+/// 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 (!URoR) {
+    LLVMContext &Ctx = F->getContext();
+    std::vector<const Type*> Params(1, Type::getInt8PtrTy(Ctx));
+    FunctionType *FTy = FunctionType::get(Type::getVoidTy(Ctx), Params, false);
+    URoR =
+      F->getParent()->getOrInsertFunction("_Unwind_Resume_or_Rethrow", FTy);
+  }
+
+  bool Changed = false;
+
+  for (Value::use_iterator
+         I = URoR->use_begin(), E = URoR->use_end(); I != E; ++I) {
+    // A function that inlines another function through an "invoke" will turn
+    // it's calls into invokes. If we have an "invoke" of _URoR, then it was
+    // inlined into this function through an invoke.
+    InvokeInst *II = dyn_cast<InvokeInst>(I);
+    if (!II || II->getParent()->getParent() != F) continue;
+
+    BasicBlock *UnwindBB = II->getUnwindDest();
+
+    // Promote the EH pointer the URoR call uses to registers if need be.
+    Changed |= PromoteEHPointer(II);
+    Value *URoREHPtr = II->getOperand(3);
+
+    // FIXME: Handle PHI nodes?
+    if (isa<PHINode>(URoREHPtr)) continue;
+
+    assert(IsEHExceptionIntrinsic(URoREHPtr) &&
+           "URoR invoke not directly using the EH pointer!");
+
+    IntrinsicInst *URoRSel = FindEHSelector(URoREHPtr);
+    assert(URoRSel && "No eh.selector associated with the eh.exception!");
+
+    // At this point, the calls to eh.exception are in the landing pads
+    // themselves.
+    IntrinsicInst *LPadEHPtr = FindEHExceptionCall(UnwindBB);
+    Changed |= PromoteEHPtrStore(LPadEHPtr);
+
+    // Try to find the eh.selector call associated with this eh.exception. If we
+    // don't find one, we can't process this further.
+    IntrinsicInst *LPadSel = FindEHSelector(LPadEHPtr);
+    if (!LPadSel) continue;     // Bail.
+
+    // After this point, we want to convert the selectors.
+    Changed = true;
+
+    // Merge the URoR's selector and the one from the landing pad for LRoR into
+    // one selector.
+    CallInst *NewSelector = MergeSelectors(URoRSel, LPadSel);
+    NewSelector->setTailCall(URoRSel->isTailCall());
+    NewSelector->setAttributes(URoRSel->getAttributes());
+    NewSelector->setCallingConv(URoRSel->getCallingConv());
+
+    // Replace URoR's selector with new selector.
+    URoRSel->replaceAllUsesWith(NewSelector);
+    URoRSel->eraseFromParent();
+  }
+
+  return Changed;
+}
+
 /// NormalizeLandingPads - Normalize and discover landing pads, noting them
 /// in the LandingPads set.  A landing pad is normal if the only CFG edges
 /// that end at it are unwind edges from invoke instructions. If we inlined
@@ -269,6 +576,7 @@
                                     CreateReadOfExceptionValue(TI->getParent()),
                                     "", TI);
     CI->setCallingConv(TLI->getLibcallCallingConv(RTLIB::UNWIND_RESUME));
+
     // ...followed by an UnreachableInst.
     new UnreachableInst(TI->getContext(), TI);
 
@@ -422,6 +730,9 @@
   if (!CompileFast)
     Changed |= PromoteStackTemporaries();
 
+  //  if (false)
+    Changed |= HandleURoRInvokes();
+
   LandingPads.clear();
 
   return Changed;





More information about the llvm-branch-commits mailing list