[llvm-commits] CVS: llvm/lib/Transforms/IPO/GlobalOpt.cpp

Chris Lattner lattner at cs.uiuc.edu
Sat Oct 9 14:48:59 PDT 2004



Changes in directory llvm/lib/Transforms/IPO:

GlobalOpt.cpp updated: 1.17 -> 1.18
---
Log message:

Eliminate global pointers that are only stored a single value and null if
we know that all uses of the global will trap if the pointer contained is
null.  In this case, we forward substitute the stored value to any uses.

This has the effect of devirtualizing trivial globals in trivial cases.  For 
example, 164.gzip contains this:

gzip.h:extern   int (*read_buf) OF((char *buf, unsigned size));
bits.c: read_buf  = file_read;
deflate.c:    lookahead = read_buf((char*)window,
deflate.c:        n = read_buf((char*)window+strstart+lookahead, more);

Since read_buf has to point to file_read at every use, we just replace
the calls through read_buf with a direct call to file_read.

This occurs in several benchmarks, including 176.gcc and 164.gzip.  Direct
calls are good and stuff.



---
Diffs of the changes:  (+103 -0)

Index: llvm/lib/Transforms/IPO/GlobalOpt.cpp
diff -u llvm/lib/Transforms/IPO/GlobalOpt.cpp:1.17 llvm/lib/Transforms/IPO/GlobalOpt.cpp:1.18
--- llvm/lib/Transforms/IPO/GlobalOpt.cpp:1.17	Fri Oct  8 22:32:52 2004
+++ llvm/lib/Transforms/IPO/GlobalOpt.cpp	Sat Oct  9 16:48:45 2004
@@ -353,6 +353,104 @@
   return NewGlobals[0];
 }
 
+/// AllUsesOfValueWillTrapIfNull - Return true if all users of the specified
+/// value will trap if the value is dynamically null.
+static bool AllUsesOfValueWillTrapIfNull(Value *V) {
+  for (Value::use_iterator UI = V->use_begin(), E = V->use_end(); UI != E; ++UI)
+    if (isa<LoadInst>(*UI)) {
+      // Will trap.
+    } else if (StoreInst *SI = dyn_cast<StoreInst>(*UI)) {
+      if (SI->getOperand(0) == V) {
+        //std::cerr << "NONTRAPPING USE: " << **UI;
+        return false;  // Storing the value.
+      }
+    } else if (CallInst *CI = dyn_cast<CallInst>(*UI)) {
+      if (CI->getOperand(0) != V) {
+        //std::cerr << "NONTRAPPING USE: " << **UI;
+        return false;  // Not calling the ptr
+      }
+    } else if (InvokeInst *II = dyn_cast<InvokeInst>(*UI)) {
+      if (II->getOperand(0) != V) {
+        //std::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 (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(*UI)) {
+      if (!AllUsesOfValueWillTrapIfNull(GEPI)) return false;
+    } else {
+      //std::cerr << "NONTRAPPING USE: " << **UI;
+      return false;
+    }
+  return true;
+}
+
+/// AllUsesOfLoadedValueWillTrapIfNull - Return true if all uses of any loads
+/// from GV will trap if the loaded value is null.
+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))
+        return false;
+    } else if (isa<StoreInst>(*UI)) {
+      // Ignore stores to the global.
+    } else {
+      // We don't know or understand this user, bail out.
+      //std::cerr << "UNKNOWN USER OF GLOBAL!: " << **UI;
+      return false;
+    }
+
+  return true;
+}
+
+// OptimizeOnceStoredGlobal - Try to optimize globals based on the knowledge
+// that only one value (besides its initializer) is ever stored to the global.
+static bool OptimizeOnceStoredGlobal(GlobalVariable *GV, Value *StoredOnceVal) {
+  if (CastInst *CI = dyn_cast<CastInst>(StoredOnceVal))
+    StoredOnceVal = CI->getOperand(0);
+  else if (GetElementPtrInst *GEPI =dyn_cast<GetElementPtrInst>(StoredOnceVal)){
+    bool IsJustACast = true;
+    for (unsigned i = 1, e = GEPI->getNumOperands(); i != e; ++i)
+      if (!isa<Constant>(GEPI->getOperand(i)) ||
+          !cast<Constant>(GEPI->getOperand(i))->isNullValue()) {
+        IsJustACast = false;
+        break;
+      }
+    if (IsJustACast)
+      StoredOnceVal = GEPI->getOperand(0);
+  }
+
+  // If we are dealing with a pointer global that is initialized to null, only
+  // has one (non-null) value stored into, and if we know that all users of the
+  // loaded value trap if null, then the load users must never get the
+  // initializer.  Instead, replace all of the loads with the stored value.
+  if (isa<PointerType>(GV->getInitializer()->getType()) &&
+      GV->getInitializer()->isNullValue()) {
+    if (isa<Constant>(StoredOnceVal) &&
+        AllUsesOfLoadedValueWillTrapIfNull(GV)) {
+      DEBUG(std::cerr << "REPLACING STORED GLOBAL POINTER: " << *GV);
+
+      //std::cerr << " Stored Value: " << *StoredOnceVal << "\n";
+
+      // Replace all uses of loads with uses of uses of the stored value.
+      while (!GV->use_empty())
+        if (LoadInst *LI = dyn_cast<LoadInst>(GV->use_back())) {
+          LI->replaceAllUsesWith(StoredOnceVal);
+          LI->getParent()->getInstList().erase(LI); // Nuke the load.
+        } else if (StoreInst *SI = dyn_cast<StoreInst>(GV->use_back())) {
+          SI->getParent()->getInstList().erase(SI); // Nuke the store
+        } else {
+          assert(0 && "Unknown user of stored once global!");
+        }
+
+      // Nuke the now-dead global.
+      GV->getParent()->getGlobalList().erase(GV);
+      return true;
+    }
+    //if (isa<MallocInst>(StoredOnceValue))
+  }
+  return false;
+}
 
 /// ProcessInternalGlobal - Analyze the specified global variable and optimize
 /// it if possible.  If we make a change, return true.
@@ -415,6 +513,11 @@
         GVI = FirstNewGV;  // Don't skip the newly produced globals!
         return true;
       }
+    } else if (GS.StoredType == GlobalStatus::isStoredOnce) {
+      // Try to optimize globals based on the knowledge that only one value
+      // (besides its initializer) is ever stored to the global.
+      if (OptimizeOnceStoredGlobal(GV, GS.StoredOnceValue))
+        return true;
     }
   }
   return false;






More information about the llvm-commits mailing list