summaryrefslogtreecommitdiff
path: root/lib/Transforms/IPO
diff options
context:
space:
mode:
authorLang Hames <lhames@gmail.com>2014-03-23 04:22:31 +0000
committerLang Hames <lhames@gmail.com>2014-03-23 04:22:31 +0000
commitfb51aac12966d07cf512e17ddae9183517d7798e (patch)
tree8c62bdc174f2c9dc459ffbd210c0c18faa964b11 /lib/Transforms/IPO
parent0695b20d9adb555b89eb4e095ce377ff8ae04eee (diff)
downloadllvm-fb51aac12966d07cf512e17ddae9183517d7798e.tar.gz
llvm-fb51aac12966d07cf512e17ddae9183517d7798e.tar.bz2
llvm-fb51aac12966d07cf512e17ddae9183517d7798e.tar.xz
Revert r204076 for now - it caused significant regressions in a number of
benchmarks. <rdar://problem/16368461> git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@204558 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Transforms/IPO')
-rw-r--r--lib/Transforms/IPO/GlobalOpt.cpp125
1 files changed, 78 insertions, 47 deletions
diff --git a/lib/Transforms/IPO/GlobalOpt.cpp b/lib/Transforms/IPO/GlobalOpt.cpp
index 06b31c6eb5..1a510cf4db 100644
--- a/lib/Transforms/IPO/GlobalOpt.cpp
+++ b/lib/Transforms/IPO/GlobalOpt.cpp
@@ -1588,16 +1588,18 @@ static bool OptimizeOnceStoredGlobal(GlobalVariable *GV, Value *StoredOnceVal,
return false;
}
-/// TryToAddRangeMetadata - At this point, we have learned that the only
+/// TryToShrinkGlobalToBoolean - At this point, we have learned that the only
/// two values ever stored into GV are its initializer and OtherVal. See if we
-/// can annotate loads from it with range metadata describing this.
-/// This exposes the values to other scalar optimizations.
-static bool TryToAddRangeMetadata(GlobalVariable *GV, Constant *OtherVal) {
+/// can shrink the global into a boolean and select between the two values
+/// whenever it is used. This exposes the values to other scalar optimizations.
+static bool TryToShrinkGlobalToBoolean(GlobalVariable *GV, Constant *OtherVal) {
Type *GVElType = GV->getType()->getElementType();
- // If GVElType is already i1, it already has a minimal range. If the type of
- // the GV is an FP value, pointer or vector, don't do this optimization
- // because range metadata is currently only supported on scalar integers.
+ // If GVElType is already i1, it is already shrunk. If the type of the GV is
+ // an FP value, pointer or vector, don't do this optimization because a select
+ // between them is very expensive and unlikely to lead to later
+ // simplification. In these cases, we typically end up with "cond ? v1 : v2"
+ // where v1 and v2 both require constant pool loads, a big loss.
if (GVElType == Type::getInt1Ty(GV->getContext()) ||
GVElType->isFloatingPointTy() ||
GVElType->isPointerTy() || GVElType->isVectorTy())
@@ -1609,53 +1611,81 @@ static bool TryToAddRangeMetadata(GlobalVariable *GV, Constant *OtherVal) {
if (!isa<LoadInst>(U) && !isa<StoreInst>(U))
return false;
+ DEBUG(dbgs() << " *** SHRINKING TO BOOL: " << *GV);
+
+ // Create the new global, initializing it to false.
+ GlobalVariable *NewGV = new GlobalVariable(Type::getInt1Ty(GV->getContext()),
+ false,
+ GlobalValue::InternalLinkage,
+ ConstantInt::getFalse(GV->getContext()),
+ GV->getName()+".b",
+ GV->getThreadLocalMode(),
+ GV->getType()->getAddressSpace());
+ GV->getParent()->getGlobalList().insert(GV, NewGV);
+
Constant *InitVal = GV->getInitializer();
assert(InitVal->getType() != Type::getInt1Ty(GV->getContext()) &&
- "No reason to add range metadata!");
+ "No reason to shrink to bool!");
- // The MD_range metadata only supports absolute integer constants.
- if (!isa<ConstantInt>(InitVal) || !isa<ConstantInt>(OtherVal))
- return false;
+ // 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->isOne();
- DEBUG(dbgs() << " *** ADDING RANGE METADATA: " << *GV);
-
- for (User *U : GV->users()) {
- Instruction *UI = cast<Instruction>(U);
- if (LoadInst *LI = dyn_cast<LoadInst>(UI)) {
- // If we already have a range, don't add a new one, so that GlobalOpt
- // terminates. In theory, we could merge the two ranges.
- if (LI->getMetadata(LLVMContext::MD_range))
- return false;
- // Add range metadata to the load. Range metadata can represent multiple
- // ranges, but they must be discontiguous, so we have two cases: the case
- // where the values are adjacent, in which case we add one range, and the
- // case where they're not, in which case we add two.
- APInt Min = cast<ConstantInt>(InitVal)->getValue();
- APInt Max = cast<ConstantInt>(OtherVal)->getValue();
- if (Max.slt(Min))
- std::swap(Min, Max);
- APInt Min1 = Min + 1;
- APInt Max1 = Max + 1;
- if (Min1 == Max) {
- Value *Vals[] = {
- ConstantInt::get(GV->getContext(), Min),
- ConstantInt::get(GV->getContext(), Max1),
- };
- MDNode *MD = MDNode::get(LI->getContext(), Vals);
- LI->setMetadata(LLVMContext::MD_range, MD);
+ while (!GV->use_empty()) {
+ Instruction *UI = cast<Instruction>(GV->user_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.
+ Value *StoreVal;
+ if (StoringOther || SI->getOperand(0) == InitVal) {
+ StoreVal = ConstantInt::get(Type::getInt1Ty(GV->getContext()),
+ StoringOther);
} else {
- Value *Vals[] = {
- ConstantInt::get(GV->getContext(), Min),
- ConstantInt::get(GV->getContext(), Min1),
- ConstantInt::get(GV->getContext(), Max),
- ConstantInt::get(GV->getContext(), Max1),
- };
- MDNode *MD = MDNode::get(LI->getContext(), Vals);
- LI->setMetadata(LLVMContext::MD_range, MD);
+ // Otherwise, we are storing a previously loaded copy. To do this,
+ // change the copy from copying the original value to just copying the
+ // bool.
+ Instruction *StoredVal = cast<Instruction>(SI->getOperand(0));
+
+ // If we've already replaced the input, StoredVal will be a cast or
+ // select instruction. If not, it will be a load of the original
+ // global.
+ if (LoadInst *LI = dyn_cast<LoadInst>(StoredVal)) {
+ assert(LI->getOperand(0) == GV && "Not a copy!");
+ // Insert a new load, to preserve the saved value.
+ StoreVal = new LoadInst(NewGV, LI->getName()+".b", false, 0,
+ LI->getOrdering(), LI->getSynchScope(), LI);
+ } else {
+ assert((isa<CastInst>(StoredVal) || isa<SelectInst>(StoredVal)) &&
+ "This is not a form that we understand!");
+ StoreVal = StoredVal->getOperand(0);
+ assert(isa<LoadInst>(StoreVal) && "Not a load of NewGV!");
+ }
}
+ new StoreInst(StoreVal, NewGV, false, 0,
+ SI->getOrdering(), SI->getSynchScope(), SI);
+ } else {
+ // Change the load into a load of bool then a select.
+ LoadInst *LI = cast<LoadInst>(UI);
+ LoadInst *NLI = new LoadInst(NewGV, LI->getName()+".b", false, 0,
+ LI->getOrdering(), LI->getSynchScope(), LI);
+ Value *NSI;
+ if (IsOneZero)
+ NSI = new ZExtInst(NLI, LI->getType(), "", LI);
+ else
+ NSI = SelectInst::Create(NLI, OtherVal, InitVal, "", LI);
+ NSI->takeName(LI);
+ LI->replaceAllUsesWith(NSI);
}
+ UI->eraseFromParent();
}
+ // Retain the name of the old global variable. People who are debugging their
+ // programs may expect these variables to be named the same.
+ NewGV->takeName(GV);
+ GV->eraseFromParent();
return true;
}
@@ -1809,10 +1839,11 @@ bool GlobalOpt::ProcessInternalGlobal(GlobalVariable *GV,
DL, TLI))
return true;
- // Otherwise, if the global was not a boolean, we can add range metadata.
+ // 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 (GS.Ordering == NotAtomic) {
- if (TryToAddRangeMetadata(GV, SOVConstant)) {
+ if (TryToShrinkGlobalToBoolean(GV, SOVConstant)) {
++NumShrunkToBool;
return true;
}