diff --git a/lib/Transforms/IPO/GlobalOpt.cpp b/lib/Transforms/IPO/GlobalOpt.cpp index 0b4b351d659..b9625fe30f8 100644 --- a/lib/Transforms/IPO/GlobalOpt.cpp +++ b/lib/Transforms/IPO/GlobalOpt.cpp @@ -46,6 +46,7 @@ namespace { Statistic<> NumFastCallFns("globalopt", "Number of functions converted to fastcc"); Statistic<> NumEmptyCtor ("globalopt", "Number of empty ctors removed"); + Statistic<> NumCtorsEvaluated("globalopt","Number of static ctors evaluated"); struct GlobalOpt : public ModulePass { virtual void getAnalysisUsage(AnalysisUsage &AU) const { @@ -1189,9 +1190,9 @@ static GlobalVariable *InstallGlobalCtors(GlobalVariable *GCL, // Create the new init list. std::vector CAList; for (unsigned i = 0, e = Ctors.size(); i != e; ++i) { - if (Ctors[i]) + if (Ctors[i]) { CSVals[1] = Ctors[i]; - else { + } else { const Type *FTy = FunctionType::get(Type::VoidTy, std::vector(), false); const PointerType *PFTy = PointerType::get(FTy); @@ -1234,7 +1235,99 @@ static GlobalVariable *InstallGlobalCtors(GlobalVariable *GCL, else return 0; } - + + +static Constant *getVal(std::map &ComputedValues, + Value *V) { + if (Constant *CV = dyn_cast(V)) return CV; + Constant *R = ComputedValues[V]; + assert(R && "Reference to an uncomputed value!"); + return R; +} + +/// isSimpleEnoughPointerToCommit - Return true if this constant is simple +/// enough for us to understand. In particular, if it is a cast of something, +/// we punt. We basically just support direct accesses to globals and GEP's of +/// globals. This should be kept up to date with CommitValueTo. +static bool isSimpleEnoughPointerToCommit(Constant *C) { + if (GlobalVariable *GV = dyn_cast(C)) + return !GV->isExternal(); // reject external globals. + return false; +} + +/// CommitValueTo - We have decided that Addr (which satisfies the predicate +/// isSimpleEnoughPointerToCommit) should get Val as its value. Make it happen. +static void CommitValueTo(Constant *Val, Constant *Addr) { + GlobalVariable *GV = cast(Addr); + assert(GV->hasInitializer()); + GV->setInitializer(Val); +} + +/// EvaluateStaticConstructor - Evaluate static constructors in the function, if +/// we can. Return true if we can, false otherwise. +static bool EvaluateStaticConstructor(Function *F) { + /// Values - As we compute SSA register values, we store their contents here. + std::map Values; + + /// MutatedMemory - For each store we execute, we update this map. Loads + /// check this to get the most up-to-date value. If evaluation is successful, + /// this state is committed to the process. + std::map MutatedMemory; + + // CurInst - The current instruction we're evaluating. + BasicBlock::iterator CurInst = F->begin()->begin(); + + // This is the main evaluation loop. + while (1) { + Constant *InstResult = 0; + + if (StoreInst *SI = dyn_cast(CurInst)) { + Constant *Ptr = getVal(Values, SI->getOperand(1)); + if (!isSimpleEnoughPointerToCommit(Ptr)) + // If this is too complex for us to commit, reject it. + return false; + Constant *Val = getVal(Values, SI->getOperand(0)); + MutatedMemory[Ptr] = Val; + } else if (BinaryOperator *BO = dyn_cast(CurInst)) { + InstResult = ConstantExpr::get(BO->getOpcode(), + getVal(Values, BO->getOperand(0)), + getVal(Values, BO->getOperand(1))); + } else if (ShiftInst *SI = dyn_cast(CurInst)) { + InstResult = ConstantExpr::get(SI->getOpcode(), + getVal(Values, SI->getOperand(0)), + getVal(Values, SI->getOperand(1))); + } else if (CastInst *CI = dyn_cast(CurInst)) { + InstResult = ConstantExpr::getCast(getVal(Values, CI->getOperand(0)), + CI->getType()); + } else if (SelectInst *SI = dyn_cast(CurInst)) { + InstResult = ConstantExpr::getSelect(getVal(Values, SI->getOperand(0)), + getVal(Values, SI->getOperand(1)), + getVal(Values, SI->getOperand(2))); + } else if (ReturnInst *RI = dyn_cast(CurInst)) { + assert(RI->getNumOperands() == 0); + break; // We succeeded at evaluating this ctor! + } else { + // TODO: use ConstantFoldCall for function calls. + + // Did not know how to evaluate this! + return false; + } + + if (!CurInst->use_empty()) + Values[CurInst] = InstResult; + + // Advance program counter. + ++CurInst; + } + + // If we get here, we know that we succeeded at evaluation: commit the result. + // + for (std::map::iterator I = MutatedMemory.begin(), + E = MutatedMemory.end(); I != E; ++I) + CommitValueTo(I->second, I->first); + return true; +} + /// OptimizeGlobalCtorsList - Simplify and evaluation global ctors if possible. /// Return true if anything changed. @@ -1256,13 +1349,26 @@ bool GlobalOpt::OptimizeGlobalCtorsList(GlobalVariable *&GCL) { break; } + // We cannot simplify external ctor functions. + if (F->empty()) continue; + + // If we can evaluate the ctor at compile time, do. + if (EvaluateStaticConstructor(F)) { + Ctors.erase(Ctors.begin()+i); + MadeChange = true; + --i; + ++NumCtorsEvaluated; + continue; + } + // If the function is empty, just remove it from the ctor list. - if (!F->empty() && isa(F->begin()->getTerminator()) && + if (isa(F->begin()->getTerminator()) && &F->begin()->front() == F->begin()->getTerminator()) { Ctors.erase(Ctors.begin()+i); MadeChange = true; --i; ++NumEmptyCtor; + continue; } }