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

Chris Lattner lattner at cs.uiuc.edu
Fri Oct 8 10:32:23 PDT 2004



Changes in directory llvm/lib/Transforms/IPO:

GlobalOpt.cpp updated: 1.12 -> 1.13
---
Log message:

Implement SRA for global variables.  This allows the other global variable
optimizations to trigger much more often.  This allows the elimination of
several dozen more global variables in Programs/External.  Note that we only
do this for non-constant globals: constant globals will already be optimized
out if the accesses to them permit it.

This implements Transforms/GlobalOpt/globalsra.llx


---
Diffs of the changes:  (+138 -33)

Index: llvm/lib/Transforms/IPO/GlobalOpt.cpp
diff -u llvm/lib/Transforms/IPO/GlobalOpt.cpp:1.12 llvm/lib/Transforms/IPO/GlobalOpt.cpp:1.13
--- llvm/lib/Transforms/IPO/GlobalOpt.cpp:1.12	Thu Oct  7 16:30:30 2004
+++ llvm/lib/Transforms/IPO/GlobalOpt.cpp	Fri Oct  8 12:32:09 2004
@@ -22,13 +22,16 @@
 #include "llvm/Pass.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/StringExtras.h"
 #include <set>
 #include <algorithm>
 using namespace llvm;
 
 namespace {
-  Statistic<> NumMarked ("globalopt", "Number of globals marked constant");
-  Statistic<> NumDeleted("globalopt", "Number of globals deleted");
+  Statistic<> NumMarked   ("globalopt", "Number of globals marked constant");
+  Statistic<> NumSRA      ("globalopt", "Number of aggregate globals broken "
+                           "into scalars");
+  Statistic<> NumDeleted  ("globalopt", "Number of globals deleted");
   Statistic<> NumFnDeleted("globalopt", "Number of functions deleted");
 
   struct GlobalOpt : public ModulePass {
@@ -95,6 +98,21 @@
       if (AnalyzeGlobal(CE, GS, PHIUsers)) return true;
       if (CE->getOpcode() != Instruction::GetElementPtr)
         GS.isNotSuitableForSRA = true;
+      else if (!GS.isNotSuitableForSRA) {
+        // Check to see if this ConstantExpr GEP is SRA'able.  In particular, we
+        // don't like < 3 operand CE's, and we don't like non-constant integer
+        // indices.
+        if (CE->getNumOperands() < 3 || !CE->getOperand(1)->isNullValue())
+          GS.isNotSuitableForSRA = true;
+        else {
+          for (unsigned i = 1, e = CE->getNumOperands(); i != e; ++i)
+            if (!isa<ConstantInt>(CE->getOperand(i))) {
+              GS.isNotSuitableForSRA = true;
+              break;
+            }
+        }
+      }
+
     } else if (Instruction *I = dyn_cast<Instruction>(*UI)) {
       if (isa<LoadInst>(I)) {
         GS.isLoaded = true;
@@ -124,12 +142,10 @@
           }
       } else if (I->getOpcode() == Instruction::GetElementPtr) {
         if (AnalyzeGlobal(I, GS, PHIUsers)) return true;
-        if (!GS.isNotSuitableForSRA)// Check to see if we have any variable idxs
-          for (unsigned i = 1, e = I->getNumOperands(); i != e; ++i)
-            if (!isa<Constant>(I->getOperand(i))) {
-              GS.isNotSuitableForSRA = true;
-              break;
-            }
+        // Theoretically we could SRA globals with GEP insts if all indexes are
+        // constants.  In practice, these GEPs would already be constant exprs
+        // if that was the case though.
+        GS.isNotSuitableForSRA = true;
       } else if (I->getOpcode() == Instruction::Select) {
         if (AnalyzeGlobal(I, GS, PHIUsers)) return true;
         GS.isNotSuitableForSRA = true;
@@ -152,7 +168,29 @@
   return false;
 }
 
-
+static Constant *getAggregateConstantElement(Constant *Agg, Constant *Idx) {
+  ConstantInt *CI = dyn_cast<ConstantInt>(Idx);
+  if (!CI) return 0;
+  uint64_t IdxV = CI->getRawValue();
+
+  if (ConstantStruct *CS = dyn_cast<ConstantStruct>(Agg)) {
+    if (IdxV < CS->getNumOperands()) return CS->getOperand(IdxV);
+  } else if (ConstantArray *CA = dyn_cast<ConstantArray>(Agg)) {
+    if (IdxV < CA->getNumOperands()) return CA->getOperand(IdxV);
+  } else if (ConstantPacked *CP = dyn_cast<ConstantPacked>(Agg)) {
+    if (IdxV < CP->getNumOperands()) return CP->getOperand(IdxV);
+  } else if (ConstantAggregateZero *CAZ = 
+             dyn_cast<ConstantAggregateZero>(Agg)) {
+    if (const StructType *STy = dyn_cast<StructType>(Agg->getType())) {
+      if (IdxV < STy->getNumElements())
+        return Constant::getNullValue(STy->getElementType(IdxV));
+    } else if (const SequentialType *STy =
+               dyn_cast<SequentialType>(Agg->getType())) {
+      return Constant::getNullValue(STy->getElementType());
+    }
+  }
+  return 0;
+}
 
 static Constant *TraverseGEPInitializer(User *GEP, Constant *Init) {
   if (GEP->getNumOperands() == 1 ||
@@ -163,30 +201,8 @@
   for (unsigned i = 2, e = GEP->getNumOperands(); i != e; ++i) {
     ConstantInt *Idx = dyn_cast<ConstantInt>(GEP->getOperand(i));
     if (!Idx) return 0;
-    uint64_t IdxV = Idx->getRawValue();
-    if (ConstantStruct *CS = dyn_cast<ConstantStruct>(Init)) {
-      if (IdxV >= CS->getNumOperands()) return 0;
-      Init = CS->getOperand(IdxV);
-    } else if (ConstantArray *CA = dyn_cast<ConstantArray>(Init)) {
-      if (IdxV >= CA->getNumOperands()) return 0;
-      Init = CA->getOperand(IdxV);
-    } else if (ConstantPacked *CP = dyn_cast<ConstantPacked>(Init)) {
-      if (IdxV >= CP->getNumOperands()) return 0;
-      Init = CP->getOperand(IdxV);
-    } else if (ConstantAggregateZero *CAZ = 
-               dyn_cast<ConstantAggregateZero>(Init)) {
-      if (const StructType *STy = dyn_cast<StructType>(Init->getType())) {
-        if (IdxV >= STy->getNumElements()) return 0;
-        Init = Constant::getNullValue(STy->getElementType(IdxV));
-      } else if (const SequentialType *STy =
-                 dyn_cast<SequentialType>(Init->getType())) {
-        Init = Constant::getNullValue(STy->getElementType());
-      } else {
-        return 0;
-      }
-    } else {
-      return 0;
-    }
+    Init = getAggregateConstantElement(Init, Idx);
+    if (Init == 0) return 0;
   }
   return Init;
 }
@@ -220,6 +236,90 @@
   }
 }
 
+/// SRAGlobal - Perform scalar replacement of aggregates on the specified global
+/// variable.  This opens the door for other optimizations by exposing the
+/// behavior of the program in a more fine-grained way.  We have determined that
+/// this transformation is safe already.  We return the first global variable we
+/// insert so that the caller can reprocess it.
+static GlobalVariable *SRAGlobal(GlobalVariable *GV) {
+  assert(GV->hasInternalLinkage() && !GV->isConstant());
+  Constant *Init = GV->getInitializer();
+  const Type *Ty = Init->getType();
+  
+  std::vector<GlobalVariable*> NewGlobals;
+  Module::GlobalListType &Globals = GV->getParent()->getGlobalList();
+
+  if (const StructType *STy = dyn_cast<StructType>(Ty)) {
+    NewGlobals.reserve(STy->getNumElements());
+    for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
+      Constant *In = getAggregateConstantElement(Init,
+                                            ConstantUInt::get(Type::UIntTy, i));
+      assert(In && "Couldn't get element of initializer?");
+      GlobalVariable *NGV = new GlobalVariable(STy->getElementType(i), false,
+                                               GlobalVariable::InternalLinkage,
+                                               In, GV->getName()+"."+utostr(i));
+      Globals.insert(GV, NGV);
+      NewGlobals.push_back(NGV);
+    }
+  } else if (const SequentialType *STy = dyn_cast<SequentialType>(Ty)) {
+    unsigned NumElements = 0;
+    if (const ArrayType *ATy = dyn_cast<ArrayType>(STy))
+      NumElements = ATy->getNumElements();
+    else if (const PackedType *PTy = dyn_cast<PackedType>(STy))
+      NumElements = PTy->getNumElements();
+    else
+      assert(0 && "Unknown aggregate sequential type!");
+
+    if (NumElements > 16) return 0; // It's not worth it.
+    NewGlobals.reserve(NumElements);
+    for (unsigned i = 0, e = NumElements; i != e; ++i) {
+      Constant *In = getAggregateConstantElement(Init,
+                                            ConstantUInt::get(Type::UIntTy, i));
+      assert(In && "Couldn't get element of initializer?");
+
+      GlobalVariable *NGV = new GlobalVariable(STy->getElementType(), false,
+                                               GlobalVariable::InternalLinkage,
+                                               In, GV->getName()+"."+utostr(i));
+      Globals.insert(GV, NGV);
+      NewGlobals.push_back(NGV);
+    }
+  }
+
+  if (NewGlobals.empty())
+    return 0;
+
+  Constant *NullInt = Constant::getNullValue(Type::IntTy);
+
+  // Loop over all of the uses of the global, replacing the constantexpr geps,
+  // with smaller constantexpr geps or direct references.
+  while (!GV->use_empty()) {
+    ConstantExpr *CE = cast<ConstantExpr>(GV->use_back());
+    assert(CE->getOpcode() == Instruction::GetElementPtr &&
+           "NonGEP CE's are not SRAable!");
+    // Ignore the 1th operand, which has to be zero or else the program is quite
+    // broken (undefined).  Get the 2nd operand, which is the structure or array
+    // index.
+    unsigned Val = cast<ConstantInt>(CE->getOperand(2))->getRawValue();
+    if (Val >= NewGlobals.size()) Val = 0; // Out of bound array access.
+
+    Constant *NewPtr = NewGlobals[Val];
+
+    // Form a shorter GEP if needed.
+    if (CE->getNumOperands() > 3) {
+      std::vector<Constant*> Idxs;
+      Idxs.push_back(NullInt);
+      for (unsigned i = 3, e = CE->getNumOperands(); i != e; ++i)
+        Idxs.push_back(CE->getOperand(i));
+      NewPtr = ConstantExpr::getGetElementPtr(NewPtr, Idxs);
+    }
+    CE->replaceAllUsesWith(NewPtr);
+    CE->destroyConstant();
+  }
+
+  ++NumSRA;
+  return NewGlobals[0];
+}
+
 bool GlobalOpt::runOnModule(Module &M) {
   bool Changed = false;
 
@@ -277,6 +377,11 @@
           
           ++NumMarked;
           Changed = true;
+        } else if (!GS.isNotSuitableForSRA &&
+                   !GV->getInitializer()->getType()->isFirstClassType()) {
+          DEBUG(std::cerr << "PERFORMING GLOBAL SRA ON: " << *GV);
+          if (GlobalVariable *FirstNewGV = SRAGlobal(GV))
+            GVI = FirstNewGV;  // Don't skip the newly produced globals!
         }
       }
     }






More information about the llvm-commits mailing list