summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDan Gohman <dan433584@gmail.com>2014-03-17 19:57:04 +0000
committerDan Gohman <dan433584@gmail.com>2014-03-17 19:57:04 +0000
commit43873d4f73f85b434c0828fab5f956fd08ac3757 (patch)
treef0c307871f0aa702e4e07c1aff80026299c4f0db /lib
parent92fca73d521758012e0e425eac33bb77e888112e (diff)
downloadllvm-43873d4f73f85b434c0828fab5f956fd08ac3757.tar.gz
llvm-43873d4f73f85b434c0828fab5f956fd08ac3757.tar.bz2
llvm-43873d4f73f85b434c0828fab5f956fd08ac3757.tar.xz
Use range metadata instead of introducing selects.
When GlobalOpt has determined that a GlobalVariable only ever has two values, it would convert the GlobalVariable to a boolean, and introduce SelectInsts at every load, to choose between the two possible values. These SelectInsts introduce overhead and other unpleasantness. This patch makes GlobalOpt just add range metadata to loads from such GlobalVariables instead. This enables the same main optimization (as seen in test/Transforms/GlobalOpt/integer-bool.ll), without introducing selects. The main downside is that it doesn't get the memory savings of shrinking such GlobalVariables, but this is expected to be negligible. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@204076 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r--lib/Transforms/IPO/GlobalOpt.cpp125
1 files changed, 47 insertions, 78 deletions
diff --git a/lib/Transforms/IPO/GlobalOpt.cpp b/lib/Transforms/IPO/GlobalOpt.cpp
index 1a510cf4db..06b31c6eb5 100644
--- a/lib/Transforms/IPO/GlobalOpt.cpp
+++ b/lib/Transforms/IPO/GlobalOpt.cpp
@@ -1588,18 +1588,16 @@ static bool OptimizeOnceStoredGlobal(GlobalVariable *GV, Value *StoredOnceVal,
return false;
}
-/// TryToShrinkGlobalToBoolean - At this point, we have learned that the only
+/// TryToAddRangeMetadata - At this point, we have learned that the only
/// two values ever stored into GV are its initializer and OtherVal. See if we
-/// 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) {
+/// 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) {
Type *GVElType = GV->getType()->getElementType();
- // 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 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 == Type::getInt1Ty(GV->getContext()) ||
GVElType->isFloatingPointTy() ||
GVElType->isPointerTy() || GVElType->isVectorTy())
@@ -1611,81 +1609,53 @@ static bool TryToShrinkGlobalToBoolean(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 shrink to bool!");
+ "No reason to add range metadata!");
- // 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();
+ // The MD_range metadata only supports absolute integer constants.
+ if (!isa<ConstantInt>(InitVal) || !isa<ConstantInt>(OtherVal))
+ return false;
- 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);
+ 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);
} else {
- // 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!");
- }
+ 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);
}
- 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;
}
@@ -1839,11 +1809,10 @@ bool GlobalOpt::ProcessInternalGlobal(GlobalVariable *GV,
DL, TLI))
return true;
- // Otherwise, if the global was not a boolean, we can shrink it to be a
- // boolean.
+ // Otherwise, if the global was not a boolean, we can add range metadata.
if (Constant *SOVConstant = dyn_cast<Constant>(GS.StoredOnceValue)) {
if (GS.Ordering == NotAtomic) {
- if (TryToShrinkGlobalToBoolean(GV, SOVConstant)) {
+ if (TryToAddRangeMetadata(GV, SOVConstant)) {
++NumShrunkToBool;
return true;
}