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

Chris Lattner lattner at cs.uiuc.edu
Sun Sep 25 18:43:57 PDT 2005



Changes in directory llvm/lib/Transforms/IPO:

GlobalOpt.cpp updated: 1.41 -> 1.42
---
Log message:

Factor this code out into a few methods.
Implement the start of global ctor optimization.  It is currently smart
enough to remove the global ctor for cases like this:

struct foo {
  foo() {}
} x;

... saving a bit of startup time for the program.



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

 GlobalOpt.cpp |  223 +++++++++++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 190 insertions(+), 33 deletions(-)


Index: llvm/lib/Transforms/IPO/GlobalOpt.cpp
diff -u llvm/lib/Transforms/IPO/GlobalOpt.cpp:1.41 llvm/lib/Transforms/IPO/GlobalOpt.cpp:1.42
--- llvm/lib/Transforms/IPO/GlobalOpt.cpp:1.41	Wed Jun 15 16:11:48 2005
+++ llvm/lib/Transforms/IPO/GlobalOpt.cpp	Sun Sep 25 20:43:45 2005
@@ -45,6 +45,7 @@
                               "Number of global vars shrunk to booleans");
   Statistic<> NumFastCallFns("globalopt",
                              "Number of functions converted to fastcc");
+  Statistic<> NumEmptyCtor  ("globalopt", "Number of empty ctors removed");
 
   struct GlobalOpt : public ModulePass {
     virtual void getAnalysisUsage(AnalysisUsage &AU) const {
@@ -54,6 +55,10 @@
     bool runOnModule(Module &M);
 
   private:
+    GlobalVariable *FindGlobalCtors(Module &M);
+    bool OptimizeFunctions(Module &M);
+    bool OptimizeGlobalVars(Module &M);
+    bool OptimizeGlobalCtorsList(GlobalVariable *&GCL);
     bool ProcessInternalGlobal(GlobalVariable *GV, Module::global_iterator &GVI);
   };
 
@@ -1077,47 +1082,199 @@
   }
 }
 
-bool GlobalOpt::runOnModule(Module &M) {
+bool GlobalOpt::OptimizeFunctions(Module &M) {
   bool Changed = false;
+  // Optimize functions.
+  for (Module::iterator FI = M.begin(), E = M.end(); FI != E; ) {
+    Function *F = FI++;
+    F->removeDeadConstantUsers();
+    if (F->use_empty() && (F->hasInternalLinkage() ||
+                           F->hasLinkOnceLinkage())) {
+      M.getFunctionList().erase(F);
+      Changed = true;
+      ++NumFnDeleted;
+    } else if (F->hasInternalLinkage() &&
+               F->getCallingConv() == CallingConv::C &&  !F->isVarArg() &&
+               OnlyCalledDirectly(F)) {
+      // If this function has C calling conventions, is not a varargs
+      // function, and is only called directly, promote it to use the Fast
+      // calling convention.
+      F->setCallingConv(CallingConv::Fast);
+      ChangeCalleesToFastCall(F);
+      ++NumFastCallFns;
+      Changed = true;
+    }
+  }
+  return Changed;
+}
 
-  // As a prepass, delete functions that are trivially dead.
-  bool LocalChange = true;
-  while (LocalChange) {
-    LocalChange = false;
-    for (Module::iterator FI = M.begin(), E = M.end(); FI != E; ) {
-      Function *F = FI++;
-      F->removeDeadConstantUsers();
-      if (F->use_empty() && (F->hasInternalLinkage() ||
-                             F->hasLinkOnceLinkage())) {
-        M.getFunctionList().erase(F);
-        LocalChange = true;
-        ++NumFnDeleted;
-      } else if (F->hasInternalLinkage() &&
-                 F->getCallingConv() == CallingConv::C &&  !F->isVarArg() &&
-                 OnlyCalledDirectly(F)) {
-        // If this function has C calling conventions, is not a varargs
-        // function, and is only called directly, promote it to use the Fast
-        // calling convention.
-        F->setCallingConv(CallingConv::Fast);
-        ChangeCalleesToFastCall(F);
-        ++NumFastCallFns;
-        LocalChange = true;
-      }
+bool GlobalOpt::OptimizeGlobalVars(Module &M) {
+  bool Changed = false;
+  for (Module::global_iterator GVI = M.global_begin(), E = M.global_end();
+       GVI != E; ) {
+    GlobalVariable *GV = GVI++;
+    if (!GV->isConstant() && GV->hasInternalLinkage() &&
+        GV->hasInitializer())
+      Changed |= ProcessInternalGlobal(GV, GVI);
+  }
+  return Changed;
+}
+
+/// FindGlobalCtors - Find the llvm.globalctors list, verifying that all
+/// initializers have an init priority of 65535.
+GlobalVariable *GlobalOpt::FindGlobalCtors(Module &M) {
+  for (Module::giterator I = M.global_begin(), E = M.global_end(); I != E; ++I)
+    if (I->getName() == "llvm.global_ctors") {
+      // Found it, verify it's an array of { int, void()* }.
+      const ArrayType *ATy =dyn_cast<ArrayType>(I->getType()->getElementType());
+      if (!ATy) return 0;
+      const StructType *STy = dyn_cast<StructType>(ATy->getElementType());
+      if (!STy || STy->getNumElements() != 2 ||
+          STy->getElementType(0) != Type::IntTy) return 0;
+      const PointerType *PFTy = dyn_cast<PointerType>(STy->getElementType(1));
+      if (!PFTy) return 0;
+      const FunctionType *FTy = dyn_cast<FunctionType>(PFTy->getElementType());
+      if (!FTy || FTy->getReturnType() != Type::VoidTy || FTy->isVarArg() ||
+          FTy->getNumParams() != 0)
+        return 0;
+      
+      // Verify that the initializer is simple enough for us to handle.
+      if (!I->hasInitializer()) return 0;
+      ConstantArray *CA = dyn_cast<ConstantArray>(I->getInitializer());
+      if (!CA) return 0;
+      for (unsigned i = 0, e = CA->getNumOperands(); i != e; ++i)
+        if (ConstantStruct *CS = dyn_cast<ConstantStruct>(CA->getOperand(i))) {
+          // Init priority must be standard.
+          ConstantInt *CI = dyn_cast<ConstantInt>(CS->getOperand(0));
+          if (!CI || CI->getRawValue() != 65535)
+            return 0;
+          
+          // Must have a function or null ptr.
+          if (!isa<Function>(CS->getOperand(1)) &&
+              !isa<ConstantPointerNull>(CS->getOperand(1)))
+            return 0;
+        } else {
+          return 0;
+        }
+      
+      return I;
+    }
+  return 0;
+}
+
+static std::vector<Function*> ParseGlobalCtors(GlobalVariable *GV) {
+  ConstantArray *CA = cast<ConstantArray>(GV->getInitializer());
+  std::vector<Function*> Result;
+  Result.reserve(CA->getNumOperands());
+  for (unsigned i = 0, e = CA->getNumOperands(); i != e; ++i) {
+    ConstantStruct *CS = cast<ConstantStruct>(CA->getOperand(i));
+    Result.push_back(dyn_cast<Function>(CS->getOperand(1)));
+  }
+  return Result;
+}
+
+/// OptimizeGlobalCtorsList - Simplify and evaluation global ctors if possible.
+/// Return true if anything changed.
+bool GlobalOpt::OptimizeGlobalCtorsList(GlobalVariable *&GCL) {
+  std::vector<Function*> Ctors = ParseGlobalCtors(GCL);
+  bool MadeChange = false;
+  if (Ctors.empty()) return false;
+  
+  // Loop over global ctors, optimizing them when we can.
+  for (unsigned i = 0; i != Ctors.size(); ++i) {
+    Function *F = Ctors[i];
+    // Found a null terminator in the middle of the list, prune off the rest of
+    // the list.
+    if (F == 0 && i != Ctors.size()-1) {
+      Ctors.resize(i+1);
+      MadeChange = true;
+      break;
+    }
+    
+    // If the function is empty, just remove it from the ctor list.
+    if (!F->empty() && isa<ReturnInst>(F->begin()->getTerminator()) &&
+        &F->begin()->front() == F->begin()->getTerminator()) {
+      Ctors.erase(Ctors.begin()+i);
+      MadeChange = true;
+      --i;
+      ++NumEmptyCtor;
     }
-    Changed |= LocalChange;
+  }
+  
+  if (!MadeChange) return false;
+  
+  std::vector<Constant*> CSVals;
+  CSVals.push_back(ConstantSInt::get(Type::IntTy, 65535));
+  CSVals.push_back(0);
+  
+  // Create the new init list.
+  std::vector<Constant*> CAList;
+  for (unsigned i = 0, e = Ctors.size(); i != e; ++i) {
+    if (Ctors[i])
+      CSVals[1] = Ctors[i];
+    else {
+      const Type *FTy = FunctionType::get(Type::VoidTy,
+                                          std::vector<const Type*>(), false);
+      const PointerType *PFTy = PointerType::get(FTy);
+      CSVals[1] = Constant::getNullValue(PFTy);
+    }
+    CAList.push_back(ConstantStruct::get(CSVals));
   }
 
-  LocalChange = true;
+  // Create the array initializer.
+  const Type *StructTy =
+    cast<ArrayType>(GCL->getType()->getElementType())->getElementType();
+  Constant *CA = ConstantArray::get(ArrayType::get(StructTy, CAList.size()),
+                                    CAList);
+  
+  // Create the new global and insert it next to the existing list.
+  GlobalVariable *NGV = new GlobalVariable(CA->getType(), GCL->isConstant(),
+                                           GCL->getLinkage(), CA,
+                                           GCL->getName());
+  GCL->setName("");
+  GCL->getParent()->getGlobalList().insert(GCL, NGV);
+  
+  // Nuke the old list, replacing any uses with the new one.
+  if (!GCL->use_empty()) {
+    Constant *V = NGV;
+    if (V->getType() != GCL->getType())
+      V = ConstantExpr::getCast(V, GCL->getType());
+    GCL->replaceAllUsesWith(V);
+  }
+  GCL->eraseFromParent();
+  
+  if (Ctors.size())
+    GCL = NGV;
+  else
+    GCL = 0;
+  return true;
+}
+
+
+bool GlobalOpt::runOnModule(Module &M) {
+  bool Changed = false;
+  
+  // Try to find the llvm.globalctors list.
+  GlobalVariable *GlobalCtors = FindGlobalCtors(M);
+
+  bool LocalChange = true;
   while (LocalChange) {
     LocalChange = false;
-    for (Module::global_iterator GVI = M.global_begin(), E = M.global_end();
-         GVI != E; ) {
-      GlobalVariable *GV = GVI++;
-      if (!GV->isConstant() && GV->hasInternalLinkage() &&
-          GV->hasInitializer())
-        LocalChange |= ProcessInternalGlobal(GV, GVI);
-    }
+    
+    // Delete functions that are trivially dead, ccc -> fastcc
+    LocalChange |= OptimizeFunctions(M);
+    
+    // Optimize global_ctors list.
+    if (GlobalCtors)
+      LocalChange |= OptimizeGlobalCtorsList(GlobalCtors);
+    
+    // Optimize non-address-taken globals.
+    LocalChange |= OptimizeGlobalVars(M);
     Changed |= LocalChange;
   }
+  
+  // TODO: Move all global ctors functions to the end of the module for code
+  // layout.
+  
   return Changed;
 }






More information about the llvm-commits mailing list