diff options
Diffstat (limited to 'llvm/lib/Transforms')
| -rw-r--r-- | llvm/lib/Transforms/IPO/GlobalOpt.cpp | 125 | 
1 files changed, 78 insertions, 47 deletions
| diff --git a/llvm/lib/Transforms/IPO/GlobalOpt.cpp b/llvm/lib/Transforms/IPO/GlobalOpt.cpp index 06b31c6eb5a..1a510cf4db5 100644 --- a/llvm/lib/Transforms/IPO/GlobalOpt.cpp +++ b/llvm/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;          } | 

