From 40e4cec9eedaae504101d40bca92c198e007b740 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sun, 12 Dec 2004 05:53:50 +0000 Subject: [PATCH] If a variable can only hold two values, and is not already a bool, shrink it down to actually BE a bool. This allows simple value range propagation stuff work harder, deleting comparisons in bzip2 in some hot loops. This implements GlobalOpt/integer-bool.ll, which is the essence of the loop condition distilled into a testcase. llvm-svn: 18817 --- llvm/lib/Transforms/IPO/GlobalOpt.cpp | 100 ++++++++++++++++++++------ 1 file changed, 78 insertions(+), 22 deletions(-) diff --git a/llvm/lib/Transforms/IPO/GlobalOpt.cpp b/llvm/lib/Transforms/IPO/GlobalOpt.cpp index 0fde1d94a3d6..6309c3b50814 100644 --- a/llvm/lib/Transforms/IPO/GlobalOpt.cpp +++ b/llvm/lib/Transforms/IPO/GlobalOpt.cpp @@ -38,6 +38,8 @@ namespace { Statistic<> NumDeleted ("globalopt", "Number of globals deleted"); Statistic<> NumFnDeleted("globalopt", "Number of functions deleted"); Statistic<> NumGlobUses ("globalopt", "Number of global uses devirtualized"); + Statistic<> NumShrunkToBool("globalopt", + "Number of global vars shrunk to booleans"); struct GlobalOpt : public ModulePass { virtual void getAnalysisUsage(AnalysisUsage &AU) const { @@ -817,6 +819,50 @@ static bool OptimizeOnceStoredGlobal(GlobalVariable *GV, Value *StoredOnceVal, return false; } +/// ShrinkGlobalToBoolean - At this point, we have learned that the only two +/// values ever stored into GV are its initializer and OtherVal. +static void ShrinkGlobalToBoolean(GlobalVariable *GV, Constant *OtherVal) { + // Create the new global, initializing it to false. + GlobalVariable *NewGV = new GlobalVariable(Type::BoolTy, false, + GlobalValue::InternalLinkage, ConstantBool::False, GV->getName()+".b"); + GV->getParent()->getGlobalList().insert(GV, NewGV); + + Constant *InitVal = GV->getInitializer(); + assert(InitVal->getType() != Type::BoolTy && "No reason to shrink to bool!"); + + // If initialized to zero and storing one into the global, we can use a cast + // instead of a select to synthesize the desired value. + bool IsOneZero = false; + if (ConstantInt *CI = dyn_cast(OtherVal)) + IsOneZero = InitVal->isNullValue() && CI->equalsInt(1); + + while (!GV->use_empty()) { + Instruction *UI = cast(GV->use_back()); + if (StoreInst *SI = dyn_cast(UI)) { + // Change the store into a boolean store. + bool StoringOther = SI->getOperand(0) == OtherVal; + // Only do this if we weren't storing a loaded value. + if (StoringOther || SI->getOperand(0) == InitVal) + new StoreInst(ConstantBool::get(StoringOther), NewGV, SI); + } else { + // Change the load into a load of bool then a select. + LoadInst *LI = cast(UI); + std::string Name = LI->getName(); LI->setName(""); + LoadInst *NLI = new LoadInst(NewGV, Name+".b", LI); + Value *NSI; + if (IsOneZero) + NSI = new CastInst(NLI, LI->getType(), Name, LI); + else + NSI = new SelectInst(NLI, OtherVal, InitVal, Name, LI); + LI->replaceAllUsesWith(NSI); + } + UI->eraseFromParent(); + } + + GV->eraseFromParent(); +} + + /// ProcessInternalGlobal - Analyze the specified global variable and optimize /// it if possible. If we make a change, return true. bool GlobalOpt::ProcessInternalGlobal(GlobalVariable *GV, @@ -875,35 +921,45 @@ bool GlobalOpt::ProcessInternalGlobal(GlobalVariable *GV, return true; } } else if (GS.StoredType == GlobalStatus::isStoredOnce) { - // If the initial value for the global was an undef value, and if only one - // other value was stored into it, we can just change the initializer to - // be an undef value, then delete all stores to the global. This allows - // us to mark it constant. - if (isa(GV->getInitializer()) && - isa(GS.StoredOnceValue)) { - // Change the initial value here. - GV->setInitializer(cast(GS.StoredOnceValue)); - - // Clean up any obviously simplifiable users now. - CleanupConstantGlobalUsers(GV, GV->getInitializer()); - - if (GV->use_empty()) { - DEBUG(std::cerr << " *** Substituting initializer allowed us to " - "simplify all users and delete global!\n"); - GV->eraseFromParent(); - ++NumDeleted; - } else { - GVI = GV; + // If the initial value for the global was an undef value, and if only + // one other value was stored into it, we can just change the + // initializer to be an undef value, then delete all stores to the + // global. This allows us to mark it constant. + if (Constant *SOVConstant = dyn_cast(GS.StoredOnceValue)) + if (isa(GV->getInitializer())) { + // Change the initial value here. + GV->setInitializer(SOVConstant); + + // Clean up any obviously simplifiable users now. + CleanupConstantGlobalUsers(GV, GV->getInitializer()); + + if (GV->use_empty()) { + DEBUG(std::cerr << " *** Substituting initializer allowed us to " + "simplify all users and delete global!\n"); + GV->eraseFromParent(); + ++NumDeleted; + } else { + GVI = GV; + } + ++NumSubstitute; + return true; } - ++NumSubstitute; - return true; - } // 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, GVI, getAnalysis())) return true; + + // Otherwise, if the global was not a boolean, we can shrink it to be a + // boolean. + if (Constant *SOVConstant = dyn_cast(GS.StoredOnceValue)) + if (GV->getType()->getElementType() != Type::BoolTy) { + DEBUG(std::cerr << " *** SHRINKING TO BOOL: " << *GV); + ShrinkGlobalToBoolean(GV, SOVConstant); + ++NumShrunkToBool; + return true; + } } } return false;