diff options
author | Lang Hames <lhames@gmail.com> | 2014-03-23 04:22:31 +0000 |
---|---|---|
committer | Lang Hames <lhames@gmail.com> | 2014-03-23 04:22:31 +0000 |
commit | fb51aac12966d07cf512e17ddae9183517d7798e (patch) | |
tree | 8c62bdc174f2c9dc459ffbd210c0c18faa964b11 /lib/Transforms/IPO | |
parent | 0695b20d9adb555b89eb4e095ce377ff8ae04eee (diff) | |
download | llvm-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.cpp | 125 |
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; } |