[llvm-commits] [llvm] r41946 - /llvm/branches/release_21/lib/Transforms/IPO/GlobalOpt.cpp

Tanya Lattner tonic at nondot.org
Thu Sep 13 18:49:48 PDT 2007


Author: tbrethou
Date: Thu Sep 13 20:49:48 2007
New Revision: 41946

URL: http://llvm.org/viewvc/llvm-project?rev=41946&view=rev
Log:
Merge from mainline for PR1639

Modified:
    llvm/branches/release_21/lib/Transforms/IPO/GlobalOpt.cpp

Modified: llvm/branches/release_21/lib/Transforms/IPO/GlobalOpt.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/branches/release_21/lib/Transforms/IPO/GlobalOpt.cpp?rev=41946&r1=41945&r2=41946&view=diff

==============================================================================
--- llvm/branches/release_21/lib/Transforms/IPO/GlobalOpt.cpp (original)
+++ llvm/branches/release_21/lib/Transforms/IPO/GlobalOpt.cpp Thu Sep 13 20:49:48 2007
@@ -26,6 +26,7 @@
 #include "llvm/Target/TargetData.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/Debug.h"
+#include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/ADT/StringExtras.h"
@@ -493,8 +494,10 @@
 }
 
 /// AllUsesOfValueWillTrapIfNull - Return true if all users of the specified
-/// value will trap if the value is dynamically null.
-static bool AllUsesOfValueWillTrapIfNull(Value *V) {
+/// value will trap if the value is dynamically null.  PHIs keeps track of any 
+/// phi nodes we've seen to avoid reprocessing them.
+static bool AllUsesOfValueWillTrapIfNull(Value *V,
+                                         SmallPtrSet<PHINode*, 8> &PHIs) {
   for (Value::use_iterator UI = V->use_begin(), E = V->use_end(); UI != E; ++UI)
     if (isa<LoadInst>(*UI)) {
       // Will trap.
@@ -513,10 +516,15 @@
         //cerr << "NONTRAPPING USE: " << **UI;
         return false;  // Not calling the ptr
       }
-    } else if (CastInst *CI = dyn_cast<CastInst>(*UI)) {
-      if (!AllUsesOfValueWillTrapIfNull(CI)) return false;
+    } else if (BitCastInst *CI = dyn_cast<BitCastInst>(*UI)) {
+      if (!AllUsesOfValueWillTrapIfNull(CI, PHIs)) return false;
     } else if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(*UI)) {
-      if (!AllUsesOfValueWillTrapIfNull(GEPI)) return false;
+      if (!AllUsesOfValueWillTrapIfNull(GEPI, PHIs)) return false;
+    } else if (PHINode *PN = dyn_cast<PHINode>(*UI)) {
+      // If we've already seen this phi node, ignore it, it has already been
+      // checked.
+      if (PHIs.insert(PN))
+        return AllUsesOfValueWillTrapIfNull(PN, PHIs);
     } else if (isa<ICmpInst>(*UI) &&
                isa<ConstantPointerNull>(UI->getOperand(1))) {
       // Ignore setcc X, null
@@ -533,7 +541,8 @@
 static bool AllUsesOfLoadedValueWillTrapIfNull(GlobalVariable *GV) {
   for (Value::use_iterator UI = GV->use_begin(), E = GV->use_end(); UI!=E; ++UI)
     if (LoadInst *LI = dyn_cast<LoadInst>(*UI)) {
-      if (!AllUsesOfValueWillTrapIfNull(LI))
+      SmallPtrSet<PHINode*, 8> PHIs;
+      if (!AllUsesOfValueWillTrapIfNull(LI, PHIs))
         return false;
     } else if (isa<StoreInst>(*UI)) {
       // Ignore stores to the global.
@@ -802,7 +811,8 @@
 /// like dereferencing the pointer, but not storing through the address, unless
 /// it is to the specified global.
 static bool ValueIsOnlyUsedLocallyOrStoredToOneGlobal(Instruction *V,
-                                                      GlobalVariable *GV) {
+                                                      GlobalVariable *GV,
+                                              SmallPtrSet<PHINode*, 8> &PHIs) {
   for (Value::use_iterator UI = V->use_begin(), E = V->use_end(); UI != E;++UI)
     if (isa<LoadInst>(*UI) || isa<CmpInst>(*UI)) {
       // Fine, ignore.
@@ -810,9 +820,16 @@
       if (SI->getOperand(0) == V && SI->getOperand(1) != GV)
         return false;  // Storing the pointer itself... bad.
       // Otherwise, storing through it, or storing into GV... fine.
-    } else if (isa<GetElementPtrInst>(*UI) || isa<SelectInst>(*UI)) {
-      if (!ValueIsOnlyUsedLocallyOrStoredToOneGlobal(cast<Instruction>(*UI),GV))
+    } else if (isa<GetElementPtrInst>(*UI) || isa<SelectInst>(*UI) ||
+               isa<BitCastInst>(*UI)) {
+      if (!ValueIsOnlyUsedLocallyOrStoredToOneGlobal(cast<Instruction>(*UI),
+                                                     GV, PHIs))
         return false;
+    } else if (PHINode *PN = dyn_cast<PHINode>(*UI)) {
+      // PHIs are ok if all uses are ok.  Don't infinitely recurse through PHI
+      // cycles.
+      if (PHIs.insert(PN))
+        return ValueIsOnlyUsedLocallyOrStoredToOneGlobal(PN, GV, PHIs);
     } else {
       return false;
     }
@@ -827,24 +844,31 @@
 static void ReplaceUsesOfMallocWithGlobal(Instruction *Alloc, 
                                           GlobalVariable *GV) {
   while (!Alloc->use_empty()) {
-    Instruction *U = Alloc->use_back();
+    Instruction *U = cast<Instruction>(*Alloc->use_begin());
+    Instruction *InsertPt = U;
     if (StoreInst *SI = dyn_cast<StoreInst>(U)) {
       // If this is the store of the allocation into the global, remove it.
       if (SI->getOperand(1) == GV) {
         SI->eraseFromParent();
         continue;
       }
+    } else if (PHINode *PN = dyn_cast<PHINode>(U)) {
+      // Insert the load in the corresponding predecessor, not right before the
+      // PHI.
+      unsigned PredNo = Alloc->use_begin().getOperandNo()/2;
+      InsertPt = PN->getIncomingBlock(PredNo)->getTerminator();
     }
     
     // Insert a load from the global, and use it instead of the malloc.
-    Value *NL = new LoadInst(GV, GV->getName()+".val", U);
+    Value *NL = new LoadInst(GV, GV->getName()+".val", InsertPt);
     U->replaceUsesOfWith(Alloc, NL);
   }
 }
 
 /// GlobalLoadUsesSimpleEnoughForHeapSRA - If all users of values loaded from
 /// GV are simple enough to perform HeapSRA, return true.
-static bool GlobalLoadUsesSimpleEnoughForHeapSRA(GlobalVariable *GV) {
+static bool GlobalLoadUsesSimpleEnoughForHeapSRA(GlobalVariable *GV,
+                                                 MallocInst *MI) {
   for (Value::use_iterator UI = GV->use_begin(), E = GV->use_end(); UI != E; 
        ++UI)
     if (LoadInst *LI = dyn_cast<LoadInst>(*UI)) {
@@ -860,77 +884,148 @@
         }
         
         // getelementptr is also ok, but only a simple form.
-        GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(*UI);
-        if (!GEPI) return false;
+        if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(*UI)) {
+          // Must index into the array and into the struct.
+          if (GEPI->getNumOperands() < 3)
+            return false;
+          
+          // Otherwise the GEP is ok.
+          continue;
+        }
         
-        // Must index into the array and into the struct.
-        if (GEPI->getNumOperands() < 3)
-          return false;
+        if (PHINode *PN = dyn_cast<PHINode>(*UI)) {
+          // We have a phi of a load from the global.  We can only handle this
+          // if the other PHI'd values are actually the same.  In this case,
+          // the rewriter will just drop the phi entirely.
+          for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) {
+            Value *IV = PN->getIncomingValue(i);
+            if (IV == LI) continue;  // Trivial the same.
+            
+            // If the phi'd value is from the malloc that initializes the value,
+            // we can xform it.
+            if (IV == MI) continue;
+            
+            // Otherwise, we don't know what it is.
+            return false;
+          }
+          return true;
+        }
         
-        // Otherwise the GEP is ok.
-        continue;
+        // Otherwise we don't know what this is, not ok.
+        return false;
       }
     }
   return true;
 }
 
-/// RewriteUsesOfLoadForHeapSRoA - We are performing Heap SRoA on a global.  Ptr
-/// is a value loaded from the global.  Eliminate all uses of Ptr, making them
-/// use FieldGlobals instead.  All uses of loaded values satisfy
-/// GlobalLoadUsesSimpleEnoughForHeapSRA.
-static void RewriteUsesOfLoadForHeapSRoA(LoadInst *Ptr, 
-                             const std::vector<GlobalVariable*> &FieldGlobals) {
-  std::vector<Value *> InsertedLoadsForPtr;
-  //InsertedLoadsForPtr.resize(FieldGlobals.size());
-  while (!Ptr->use_empty()) {
-    Instruction *User = Ptr->use_back();
-    
-    // If this is a comparison against null, handle it.
-    if (ICmpInst *SCI = dyn_cast<ICmpInst>(User)) {
-      assert(isa<ConstantPointerNull>(SCI->getOperand(1)));
-      // If we have a setcc of the loaded pointer, we can use a setcc of any
-      // field.
-      Value *NPtr;
-      if (InsertedLoadsForPtr.empty()) {
-        NPtr = new LoadInst(FieldGlobals[0], Ptr->getName()+".f0", Ptr);
-        InsertedLoadsForPtr.push_back(Ptr);
-      } else {
-        NPtr = InsertedLoadsForPtr.back();
-      }
-      
-      Value *New = new ICmpInst(SCI->getPredicate(), NPtr,
-                                Constant::getNullValue(NPtr->getType()),
-                                SCI->getName(), SCI);
-      SCI->replaceAllUsesWith(New);
-      SCI->eraseFromParent();
-      continue;
+/// GetHeapSROALoad - Return the load for the specified field of the HeapSROA'd
+/// value, lazily creating it on demand.
+static Value *GetHeapSROALoad(Instruction *Load, unsigned FieldNo,
+                              const std::vector<GlobalVariable*> &FieldGlobals,
+                              std::vector<Value *> &InsertedLoadsForPtr) {
+  if (InsertedLoadsForPtr.size() <= FieldNo)
+    InsertedLoadsForPtr.resize(FieldNo+1);
+  if (InsertedLoadsForPtr[FieldNo] == 0)
+    InsertedLoadsForPtr[FieldNo] = new LoadInst(FieldGlobals[FieldNo],
+                                                Load->getName()+".f" + 
+                                                utostr(FieldNo), Load);
+  return InsertedLoadsForPtr[FieldNo];
+}
+
+/// RewriteHeapSROALoadUser - Given a load instruction and a value derived from
+/// the load, rewrite the derived value to use the HeapSRoA'd load.
+static void RewriteHeapSROALoadUser(LoadInst *Load, Instruction *LoadUser, 
+                               const std::vector<GlobalVariable*> &FieldGlobals,
+                                    std::vector<Value *> &InsertedLoadsForPtr) {
+  // If this is a comparison against null, handle it.
+  if (ICmpInst *SCI = dyn_cast<ICmpInst>(LoadUser)) {
+    assert(isa<ConstantPointerNull>(SCI->getOperand(1)));
+    // If we have a setcc of the loaded pointer, we can use a setcc of any
+    // field.
+    Value *NPtr;
+    if (InsertedLoadsForPtr.empty()) {
+      NPtr = GetHeapSROALoad(Load, 0, FieldGlobals, InsertedLoadsForPtr);
+    } else {
+      NPtr = InsertedLoadsForPtr.back();
     }
     
-    // Otherwise, this should be: 'getelementptr Ptr, Idx, uint FieldNo ...'
-    GetElementPtrInst *GEPI = cast<GetElementPtrInst>(User);
+    Value *New = new ICmpInst(SCI->getPredicate(), NPtr,
+                              Constant::getNullValue(NPtr->getType()),
+                              SCI->getName(), SCI);
+    SCI->replaceAllUsesWith(New);
+    SCI->eraseFromParent();
+    return;
+  }
+  
+  // Handle 'getelementptr Ptr, Idx, uint FieldNo ...'
+  if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(LoadUser)) {
     assert(GEPI->getNumOperands() >= 3 && isa<ConstantInt>(GEPI->getOperand(2))
            && "Unexpected GEPI!");
-    
+  
     // Load the pointer for this field.
     unsigned FieldNo = cast<ConstantInt>(GEPI->getOperand(2))->getZExtValue();
-    if (InsertedLoadsForPtr.size() <= FieldNo)
-      InsertedLoadsForPtr.resize(FieldNo+1);
-    if (InsertedLoadsForPtr[FieldNo] == 0)
-      InsertedLoadsForPtr[FieldNo] = new LoadInst(FieldGlobals[FieldNo],
-                                                  Ptr->getName()+".f" + 
-                                                  utostr(FieldNo), Ptr);
-    Value *NewPtr = InsertedLoadsForPtr[FieldNo];
-
+    Value *NewPtr = GetHeapSROALoad(Load, FieldNo,
+                                    FieldGlobals, InsertedLoadsForPtr);
+    
     // Create the new GEP idx vector.
     SmallVector<Value*, 8> GEPIdx;
     GEPIdx.push_back(GEPI->getOperand(1));
     GEPIdx.append(GEPI->op_begin()+3, GEPI->op_end());
-
+    
     Value *NGEPI = new GetElementPtrInst(NewPtr, GEPIdx.begin(), GEPIdx.end(),
                                          GEPI->getName(), GEPI);
     GEPI->replaceAllUsesWith(NGEPI);
     GEPI->eraseFromParent();
+    return;
+  }
+  
+  // Handle PHI nodes.  PHI nodes must be merging in the same values, plus
+  // potentially the original malloc.  Insert phi nodes for each field, then
+  // process uses of the PHI.
+  PHINode *PN = cast<PHINode>(LoadUser);
+  std::vector<Value *> PHIsForField;
+  PHIsForField.resize(FieldGlobals.size());
+  for (unsigned i = 0, e = FieldGlobals.size(); i != e; ++i) {
+    Value *LoadV = GetHeapSROALoad(Load, i, FieldGlobals, InsertedLoadsForPtr);
+
+    PHINode *FieldPN = new PHINode(LoadV->getType(),
+                                   PN->getName()+"."+utostr(i), PN);
+    // Fill in the predecessor values.
+    for (unsigned pred = 0, e = PN->getNumIncomingValues(); pred != e; ++pred) {
+      // Each predecessor either uses the load or the original malloc.
+      Value *InVal = PN->getIncomingValue(pred);
+      BasicBlock *BB = PN->getIncomingBlock(pred);
+      Value *NewVal;
+      if (isa<MallocInst>(InVal)) {
+        // Insert a reload from the global in the predecessor.
+        NewVal = GetHeapSROALoad(BB->getTerminator(), i, FieldGlobals,
+                                 PHIsForField);
+      } else {
+        NewVal = InsertedLoadsForPtr[i];
+      }
+      FieldPN->addIncoming(NewVal, BB);
+    }
+    PHIsForField[i] = FieldPN;
   }
+  
+  // Since PHIsForField specifies a phi for every input value, the lazy inserter
+  // will never insert a load.
+  while (!PN->use_empty())
+    RewriteHeapSROALoadUser(Load, PN->use_back(), FieldGlobals, PHIsForField);
+  PN->eraseFromParent();
+}
+
+/// RewriteUsesOfLoadForHeapSRoA - We are performing Heap SRoA on a global.  Ptr
+/// is a value loaded from the global.  Eliminate all uses of Ptr, making them
+/// use FieldGlobals instead.  All uses of loaded values satisfy
+/// GlobalLoadUsesSimpleEnoughForHeapSRA.
+static void RewriteUsesOfLoadForHeapSRoA(LoadInst *Load, 
+                             const std::vector<GlobalVariable*> &FieldGlobals) {
+  std::vector<Value *> InsertedLoadsForPtr;
+  //InsertedLoadsForPtr.resize(FieldGlobals.size());
+  while (!Load->use_empty())
+    RewriteHeapSROALoadUser(Load, Load->use_back(), 
+                            FieldGlobals, InsertedLoadsForPtr);
 }
 
 /// PerformHeapAllocSRoA - MI is an allocation of an array of structures.  Break
@@ -1116,8 +1211,11 @@
       // malloc to be stored into the specified global, loaded setcc'd, and
       // GEP'd.  These are all things we could transform to using the global
       // for.
-      if (!ValueIsOnlyUsedLocallyOrStoredToOneGlobal(MI, GV))
-        return false;
+      {
+        SmallPtrSet<PHINode*, 8> PHIs;
+        if (!ValueIsOnlyUsedLocallyOrStoredToOneGlobal(MI, GV, PHIs))
+          return false;
+      }
 
       
       // If we have a global that is only initialized with a fixed size malloc,
@@ -1143,7 +1241,7 @@
         // This the structure has an unreasonable number of fields, leave it
         // alone.
         if (AllocTy->getNumElements() <= 16 && AllocTy->getNumElements() > 0 &&
-            GlobalLoadUsesSimpleEnoughForHeapSRA(GV)) {
+            GlobalLoadUsesSimpleEnoughForHeapSRA(GV, MI)) {
           GVI = PerformHeapAllocSRoA(GV, MI);
           return true;
         }





More information about the llvm-commits mailing list