Avoid extra calls to MD->getNumOperands()
[oota-llvm.git] / lib / Transforms / Utils / PromoteMemoryToRegister.cpp
index 438ac43bcbaeb0660b0c704251075140d85cc1fa..221abd63b8db887a7cbcad95221a97fc82f6bd38 100644 (file)
@@ -23,6 +23,8 @@
 #include "llvm/Function.h"
 #include "llvm/Instructions.h"
 #include "llvm/IntrinsicInst.h"
+#include "llvm/Metadata.h"
+#include "llvm/Analysis/DebugInfo.h"
 #include "llvm/Analysis/Dominators.h"
 #include "llvm/Analysis/AliasSetTracker.h"
 #include "llvm/ADT/DenseMap.h"
@@ -55,7 +57,6 @@ struct DenseMapInfo<std::pair<BasicBlock*, unsigned> > {
   static bool isEqual(const EltTy &LHS, const EltTy &RHS) {
     return LHS == RHS;
   }
-  static bool isPod() { return true; }
 };
 }
 
@@ -77,16 +78,6 @@ bool llvm::isAllocaPromotable(const AllocaInst *AI) {
         return false;   // Don't allow a store OF the AI, only INTO the AI.
       if (SI->isVolatile())
         return false;
-    } else if (const BitCastInst *BC = dyn_cast<BitCastInst>(*UI)) {
-      // A bitcast that does not feed into debug info inhibits promotion.
-      if (!BC->hasOneUse() || !isa<DbgInfoIntrinsic>(*BC->use_begin()))
-        return false;
-      // If the only use is by debug info, this alloca will not exist in
-      // non-debug code, so don't try to promote; this ensures the same
-      // codegen with debug info.  Otherwise, debug info should not
-      // inhibit promotion (but we must examine other uses).
-      if (AI->hasOneUse())
-        return false;
     } else {
       return false;
     }
@@ -94,6 +85,17 @@ bool llvm::isAllocaPromotable(const AllocaInst *AI) {
   return true;
 }
 
+/// Finds the llvm.dbg.declare intrinsic describing V, if any.
+static DbgDeclareInst *findDbgDeclare(Value *V) {
+  if (MDNode *DebugNode = MDNode::getIfExists(V->getContext(), &V, 1))
+    for (Value::use_iterator UI = DebugNode->use_begin(),
+         E = DebugNode->use_end(); UI != E; ++UI)
+      if (DbgDeclareInst *DDI = dyn_cast<DbgDeclareInst>(*UI))
+        return DDI;
+
+  return 0;
+}
+
 namespace {
   struct AllocaInfo;
 
@@ -174,6 +176,7 @@ namespace {
     std::vector<AllocaInst*> Allocas;
     DominatorTree &DT;
     DominanceFrontier &DF;
+    DIFactory *DIF;
 
     /// AST - An AliasSetTracker object to update.  If null, don't update it.
     ///
@@ -197,6 +200,11 @@ namespace {
     ///
     std::vector<Value*> PointerAllocaValues;
 
+    /// AllocaDbgDeclares - For each alloca, we keep track of the dbg.declare
+    /// intrinsic that describes it, if any, so that we can convert it to a
+    /// dbg.value intrinsic if the alloca gets promoted.
+    SmallVector<DbgDeclareInst*, 8> AllocaDbgDeclares;
+
     /// Visited - The set of basic blocks the renamer has already visited.
     ///
     SmallPtrSet<BasicBlock*, 16> Visited;
@@ -210,7 +218,10 @@ namespace {
   public:
     PromoteMem2Reg(const std::vector<AllocaInst*> &A, DominatorTree &dt,
                    DominanceFrontier &df, AliasSetTracker *ast)
-      : Allocas(A), DT(dt), DF(df), AST(ast) {}
+      : Allocas(A), DT(dt), DF(df), DIF(0), AST(ast) {}
+    ~PromoteMem2Reg() {
+      if (DIF) delete DIF;
+    }
 
     void run();
 
@@ -252,6 +263,8 @@ namespace {
                                   LargeBlockInfo &LBI);
     void PromoteSingleBlockAlloca(AllocaInst *AI, AllocaInfo &Info,
                                   LargeBlockInfo &LBI);
+    void ConvertDebugDeclareToDebugValue(DbgDeclareInst *DDI, StoreInst *SI,
+                                         uint64_t Offset);
 
     
     void RenamePass(BasicBlock *BB, BasicBlock *Pred,
@@ -270,6 +283,7 @@ namespace {
     bool OnlyUsedInOneBlock;
     
     Value *AllocaPointerVal;
+    DbgDeclareInst *DbgDeclare;
     
     void clear() {
       DefiningBlocks.clear();
@@ -278,6 +292,7 @@ namespace {
       OnlyBlock = 0;
       OnlyUsedInOneBlock = true;
       AllocaPointerVal = 0;
+      DbgDeclare = 0;
     }
     
     /// AnalyzeAlloca - Scan the uses of the specified alloca, filling in our
@@ -291,15 +306,7 @@ namespace {
       for (Value::use_iterator UI = AI->use_begin(), E = AI->use_end();
            UI != E;)  {
         Instruction *User = cast<Instruction>(*UI++);
-        if (BitCastInst *BC = dyn_cast<BitCastInst>(User)) {
-          // Remove any uses of this alloca in DbgInfoInstrinsics.
-          assert(BC->hasOneUse() && "Unexpected alloca uses!");
-          DbgInfoIntrinsic *DI = cast<DbgInfoIntrinsic>(*BC->use_begin());
-          DI->eraseFromParent();
-          BC->eraseFromParent();
-          continue;
-        } 
-        
+
         if (StoreInst *SI = dyn_cast<StoreInst>(User)) {
           // Remember the basic blocks which define new values for the alloca
           DefiningBlocks.push_back(SI->getParent());
@@ -320,6 +327,8 @@ namespace {
             OnlyUsedInOneBlock = false;
         }
       }
+      
+      DbgDeclare = findDbgDeclare(AI);
     }
   };
 }  // end of anonymous namespace
@@ -329,6 +338,7 @@ void PromoteMem2Reg::run() {
   Function &F = *DF.getRoot()->getParent();
 
   if (AST) PointerAllocaValues.resize(Allocas.size());
+  AllocaDbgDeclares.resize(Allocas.size());
 
   AllocaInfo Info;
   LargeBlockInfo LBI;
@@ -363,6 +373,8 @@ void PromoteMem2Reg::run() {
 
       // Finally, after the scan, check to see if the store is all that is left.
       if (Info.UsingBlocks.empty()) {
+        // Record debuginfo for the store before removing it.
+        ConvertDebugDeclareToDebugValue(Info.DbgDeclare, Info.OnlyStore, 0);
         // Remove the (now dead) store and alloca.
         Info.OnlyStore->eraseFromParent();
         LBI.deleteValue(Info.OnlyStore);
@@ -391,6 +403,8 @@ void PromoteMem2Reg::run() {
         // Remove the (now dead) stores and alloca.
         while (!AI->use_empty()) {
           StoreInst *SI = cast<StoreInst>(AI->use_back());
+          // Record debuginfo for the store before removing it.
+          ConvertDebugDeclareToDebugValue(Info.DbgDeclare, SI, 0);
           SI->eraseFromParent();
           LBI.deleteValue(SI);
         }
@@ -419,6 +433,9 @@ void PromoteMem2Reg::run() {
     // stored into the alloca.
     if (AST)
       PointerAllocaValues[AllocaNum] = Info.AllocaPointerVal;
+      
+    // Remember the dbg.declare intrinsic describing this alloca, if any.
+    if (Info.DbgDeclare) AllocaDbgDeclares[AllocaNum] = Info.DbgDeclare;
     
     // Keep the reverse mapping of the 'Allocas' array for the rename pass.
     AllocaLookup[Allocas[AllocaNum]] = AllocaNum;
@@ -449,13 +466,13 @@ void PromoteMem2Reg::run() {
   //
   std::vector<RenamePassData> RenamePassWorkList;
   RenamePassWorkList.push_back(RenamePassData(F.begin(), 0, Values));
-  while (!RenamePassWorkList.empty()) {
+  do {
     RenamePassData RPD;
     RPD.swap(RenamePassWorkList.back());
     RenamePassWorkList.pop_back();
     // RenamePass may add new worklist entries.
     RenamePass(RPD.BB, RPD.Pred, RPD.Values, RenamePassWorkList);
-  }
+  } while (!RenamePassWorkList.empty());
   
   // The renamer uses the Visited set to avoid infinite loops.  Clear it now.
   Visited.clear();
@@ -852,6 +869,22 @@ void PromoteMem2Reg::PromoteSingleBlockAlloca(AllocaInst *AI, AllocaInfo &Info,
   }
 }
 
+// Inserts a llvm.dbg.value instrinsic before the stores to an alloca'd value
+// that has an associated llvm.dbg.decl intrinsic.
+void PromoteMem2Reg::ConvertDebugDeclareToDebugValue(DbgDeclareInst *DDI,
+                                                     StoreInst *SI,
+                                                     uint64_t Offset) {
+  if (!DDI)
+    return;
+
+  DIVariable DIVar(DDI->getVariable());
+  if (!DIVar.getNode())
+    return;
+
+  if (!DIF)
+    DIF = new DIFactory(*SI->getParent()->getParent()->getParent());
+  DIF->InsertDbgValueIntrinsic(SI->getOperand(0), Offset, DIVar, SI);
+}
 
 // QueuePhiNode - queues a phi-node to be added to a basic-block for a specific
 // Alloca returns true if there wasn't already a phi-node for that variable
@@ -965,6 +998,8 @@ NextIteration:
       
       // what value were we writing?
       IncomingVals[ai->second] = SI->getOperand(0);
+      // Record debuginfo for the store before removing it.
+      ConvertDebugDeclareToDebugValue(AllocaDbgDeclares[ai->second], SI, 0);
       BB->getInstList().erase(SI);
     }
   }