mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 03:33:20 +01:00
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
This commit is contained in:
parent
ff477f8594
commit
f125dc0e49
@ -38,6 +38,8 @@ namespace {
|
|||||||
Statistic<> NumDeleted ("globalopt", "Number of globals deleted");
|
Statistic<> NumDeleted ("globalopt", "Number of globals deleted");
|
||||||
Statistic<> NumFnDeleted("globalopt", "Number of functions deleted");
|
Statistic<> NumFnDeleted("globalopt", "Number of functions deleted");
|
||||||
Statistic<> NumGlobUses ("globalopt", "Number of global uses devirtualized");
|
Statistic<> NumGlobUses ("globalopt", "Number of global uses devirtualized");
|
||||||
|
Statistic<> NumShrunkToBool("globalopt",
|
||||||
|
"Number of global vars shrunk to booleans");
|
||||||
|
|
||||||
struct GlobalOpt : public ModulePass {
|
struct GlobalOpt : public ModulePass {
|
||||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||||
@ -817,6 +819,50 @@ static bool OptimizeOnceStoredGlobal(GlobalVariable *GV, Value *StoredOnceVal,
|
|||||||
return false;
|
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<ConstantInt>(OtherVal))
|
||||||
|
IsOneZero = InitVal->isNullValue() && CI->equalsInt(1);
|
||||||
|
|
||||||
|
while (!GV->use_empty()) {
|
||||||
|
Instruction *UI = cast<Instruction>(GV->use_back());
|
||||||
|
if (StoreInst *SI = dyn_cast<StoreInst>(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<LoadInst>(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
|
/// ProcessInternalGlobal - Analyze the specified global variable and optimize
|
||||||
/// it if possible. If we make a change, return true.
|
/// it if possible. If we make a change, return true.
|
||||||
bool GlobalOpt::ProcessInternalGlobal(GlobalVariable *GV,
|
bool GlobalOpt::ProcessInternalGlobal(GlobalVariable *GV,
|
||||||
@ -875,35 +921,45 @@ bool GlobalOpt::ProcessInternalGlobal(GlobalVariable *GV,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (GS.StoredType == GlobalStatus::isStoredOnce) {
|
} else if (GS.StoredType == GlobalStatus::isStoredOnce) {
|
||||||
// If the initial value for the global was an undef value, and if only one
|
// If the initial value for the global was an undef value, and if only
|
||||||
// other value was stored into it, we can just change the initializer to
|
// one other value was stored into it, we can just change the
|
||||||
// be an undef value, then delete all stores to the global. This allows
|
// initializer to be an undef value, then delete all stores to the
|
||||||
// us to mark it constant.
|
// global. This allows us to mark it constant.
|
||||||
if (isa<UndefValue>(GV->getInitializer()) &&
|
if (Constant *SOVConstant = dyn_cast<Constant>(GS.StoredOnceValue))
|
||||||
isa<Constant>(GS.StoredOnceValue)) {
|
if (isa<UndefValue>(GV->getInitializer())) {
|
||||||
// Change the initial value here.
|
// Change the initial value here.
|
||||||
GV->setInitializer(cast<Constant>(GS.StoredOnceValue));
|
GV->setInitializer(SOVConstant);
|
||||||
|
|
||||||
// Clean up any obviously simplifiable users now.
|
// Clean up any obviously simplifiable users now.
|
||||||
CleanupConstantGlobalUsers(GV, GV->getInitializer());
|
CleanupConstantGlobalUsers(GV, GV->getInitializer());
|
||||||
|
|
||||||
if (GV->use_empty()) {
|
if (GV->use_empty()) {
|
||||||
DEBUG(std::cerr << " *** Substituting initializer allowed us to "
|
DEBUG(std::cerr << " *** Substituting initializer allowed us to "
|
||||||
"simplify all users and delete global!\n");
|
"simplify all users and delete global!\n");
|
||||||
GV->eraseFromParent();
|
GV->eraseFromParent();
|
||||||
++NumDeleted;
|
++NumDeleted;
|
||||||
} else {
|
} else {
|
||||||
GVI = GV;
|
GVI = GV;
|
||||||
|
}
|
||||||
|
++NumSubstitute;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
++NumSubstitute;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to optimize globals based on the knowledge that only one value
|
// Try to optimize globals based on the knowledge that only one value
|
||||||
// (besides its initializer) is ever stored to the global.
|
// (besides its initializer) is ever stored to the global.
|
||||||
if (OptimizeOnceStoredGlobal(GV, GS.StoredOnceValue, GVI,
|
if (OptimizeOnceStoredGlobal(GV, GS.StoredOnceValue, GVI,
|
||||||
getAnalysis<TargetData>()))
|
getAnalysis<TargetData>()))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
// Otherwise, if the global was not a boolean, we can shrink it to be a
|
||||||
|
// boolean.
|
||||||
|
if (Constant *SOVConstant = dyn_cast<Constant>(GS.StoredOnceValue))
|
||||||
|
if (GV->getType()->getElementType() != Type::BoolTy) {
|
||||||
|
DEBUG(std::cerr << " *** SHRINKING TO BOOL: " << *GV);
|
||||||
|
ShrinkGlobalToBoolean(GV, SOVConstant);
|
||||||
|
++NumShrunkToBool;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
Loading…
Reference in New Issue
Block a user