Refactor some methods to look through bitcasts and GEPs on pointers into

a common collection of methods on Value, and share their implementation.
We had two variations in two different places already, and I need the
third variation for inline cost estimation.

Reviewed by Duncan Sands on IRC, but further comments here welcome.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@152490 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chandler Carruth 2012-03-10 08:39:09 +00:00
parent e060eb8916
commit 84dfc32ff9
3 changed files with 66 additions and 34 deletions

View File

@ -263,14 +263,32 @@ public:
return true; // Values are always values. return true; // Values are always values.
} }
/// stripPointerCasts - This method strips off any unneeded pointer /// stripPointerCasts - This method strips off any unneeded pointer casts and
/// casts from the specified value, returning the original uncasted value. /// all-zero GEPs from the specified value, returning the original uncasted
/// Note that the returned value has pointer type if the specified value does. /// value. If this is called on a non-pointer value, it returns 'this'.
Value *stripPointerCasts(); Value *stripPointerCasts();
const Value *stripPointerCasts() const { const Value *stripPointerCasts() const {
return const_cast<Value*>(this)->stripPointerCasts(); return const_cast<Value*>(this)->stripPointerCasts();
} }
/// stripConstantOffsets - This method strips off unneeded pointer casts and
/// all-constant GEPs from the specified value, returning the original
/// pointer value. If this is called on a non-pointer value, it returns
/// 'this'.
Value *stripConstantOffsets();
const Value *stripConstantOffsets() const {
return const_cast<Value*>(this)->stripConstantOffsets();
}
/// stripInBoundsOffsets - This method strips off unneeded pointer casts and
/// any in-bounds Offsets from the specified value, returning the original
/// pointer value. If this is called on a non-pointer value, it returns
/// 'this'.
Value *stripInBoundsOffsets();
const Value *stripInBoundsOffsets() const {
return const_cast<Value*>(this)->stripInBoundsOffsets();
}
/// isDereferenceablePointer - Test if this value is always a pointer to /// isDereferenceablePointer - Test if this value is always a pointer to
/// allocated and suitably aligned memory for a simple load or store. /// allocated and suitably aligned memory for a simple load or store.
bool isDereferenceablePointer() const; bool isDereferenceablePointer() const;

View File

@ -1522,28 +1522,6 @@ static Value *ExtractEquivalentCondition(Value *V, CmpInst::Predicate Pred,
return 0; return 0;
} }
/// stripPointerAdjustments - This is like Value::stripPointerCasts, but also
/// removes inbounds gep operations, regardless of their indices.
static Value *stripPointerAdjustmentsImpl(Value *V,
SmallPtrSet<GEPOperator*, 8> &VisitedGEPs) {
GEPOperator *GEP = dyn_cast<GEPOperator>(V);
if (GEP == 0 || !GEP->isInBounds())
return V;
// If we've already seen this GEP, we will end up infinitely looping. This
// can happen in unreachable code.
if (!VisitedGEPs.insert(GEP))
return V;
return stripPointerAdjustmentsImpl(GEP->getOperand(0)->stripPointerCasts(),
VisitedGEPs);
}
static Value *stripPointerAdjustments(Value *V) {
SmallPtrSet<GEPOperator*, 8> VisitedGEPs;
return stripPointerAdjustmentsImpl(V, VisitedGEPs);
}
/// SimplifyICmpInst - Given operands for an ICmpInst, see if we can /// SimplifyICmpInst - Given operands for an ICmpInst, see if we can
/// fold the result. If not, this returns null. /// fold the result. If not, this returns null.
@ -1625,9 +1603,9 @@ static Value *SimplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS,
// Be more aggressive about stripping pointer adjustments when checking a // Be more aggressive about stripping pointer adjustments when checking a
// comparison of an alloca address to another object. We can rip off all // comparison of an alloca address to another object. We can rip off all
// inbounds GEP operations, even if they are variable. // inbounds GEP operations, even if they are variable.
LHSPtr = stripPointerAdjustments(LHSPtr); LHSPtr = LHSPtr->stripInBoundsOffsets();
if (llvm::isIdentifiedObject(LHSPtr)) { if (llvm::isIdentifiedObject(LHSPtr)) {
RHSPtr = stripPointerAdjustments(RHSPtr); RHSPtr = RHSPtr->stripInBoundsOffsets();
if (llvm::isKnownNonNull(LHSPtr) || llvm::isKnownNonNull(RHSPtr)) { if (llvm::isKnownNonNull(LHSPtr) || llvm::isKnownNonNull(RHSPtr)) {
// If both sides are different identified objects, they aren't equal // If both sides are different identified objects, they aren't equal
// unless they're null. // unless they're null.
@ -1644,7 +1622,7 @@ static Value *SimplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS,
if (llvm::isKnownNonNull(LHSPtr) && isa<ConstantPointerNull>(RHSPtr)) if (llvm::isKnownNonNull(LHSPtr) && isa<ConstantPointerNull>(RHSPtr))
return ConstantInt::get(ITy, CmpInst::isFalseWhenEqual(Pred)); return ConstantInt::get(ITy, CmpInst::isFalseWhenEqual(Pred));
} else if (isa<Argument>(LHSPtr)) { } else if (isa<Argument>(LHSPtr)) {
RHSPtr = stripPointerAdjustments(RHSPtr); RHSPtr = RHSPtr->stripInBoundsOffsets();
// An alloca can't be equal to an argument. // An alloca can't be equal to an argument.
if (isa<AllocaInst>(RHSPtr)) if (isa<AllocaInst>(RHSPtr))
return ConstantInt::get(ITy, CmpInst::isFalseWhenEqual(Pred)); return ConstantInt::get(ITy, CmpInst::isFalseWhenEqual(Pred));

View File

@ -317,20 +317,43 @@ void Value::replaceAllUsesWith(Value *New) {
BB->replaceSuccessorsPhiUsesWith(cast<BasicBlock>(New)); BB->replaceSuccessorsPhiUsesWith(cast<BasicBlock>(New));
} }
Value *Value::stripPointerCasts() { namespace {
if (!getType()->isPointerTy()) // Various metrics for how much to strip off of pointers.
return this; enum PointerStripKind {
PSK_ZeroIndices,
PSK_ConstantIndices,
PSK_InBounds,
PSK_All
};
template <PointerStripKind StripKind>
static Value *stripPointerCastsAndOffsets(Value *V) {
if (!V->getType()->isPointerTy())
return V;
// Even though we don't look through PHI nodes, we could be called on an // Even though we don't look through PHI nodes, we could be called on an
// instruction in an unreachable block, which may be on a cycle. // instruction in an unreachable block, which may be on a cycle.
SmallPtrSet<Value *, 4> Visited; SmallPtrSet<Value *, 4> Visited;
Value *V = this;
Visited.insert(V); Visited.insert(V);
do { do {
if (GEPOperator *GEP = dyn_cast<GEPOperator>(V)) { if (GEPOperator *GEP = dyn_cast<GEPOperator>(V)) {
if (!GEP->hasAllZeroIndices()) switch (StripKind) {
return V; case PSK_ZeroIndices:
if (!GEP->hasAllZeroIndices())
return V;
break;
case PSK_ConstantIndices:
if (!GEP->hasAllConstantIndices())
return V;
break;
case PSK_InBounds:
if (!GEP->isInBounds())
return V;
break;
case PSK_All:
break;
}
V = GEP->getPointerOperand(); V = GEP->getPointerOperand();
} else if (Operator::getOpcode(V) == Instruction::BitCast) { } else if (Operator::getOpcode(V) == Instruction::BitCast) {
V = cast<Operator>(V)->getOperand(0); V = cast<Operator>(V)->getOperand(0);
@ -346,6 +369,19 @@ Value *Value::stripPointerCasts() {
return V; return V;
} }
} // namespace
Value *Value::stripPointerCasts() {
return stripPointerCastsAndOffsets<PSK_ZeroIndices>(this);
}
Value *Value::stripConstantOffsets() {
return stripPointerCastsAndOffsets<PSK_ConstantIndices>(this);
}
Value *Value::stripInBoundsOffsets() {
return stripPointerCastsAndOffsets<PSK_InBounds>(this);
}
/// isDereferenceablePointer - Test if this value is always a pointer to /// isDereferenceablePointer - Test if this value is always a pointer to
/// allocated and suitably aligned memory for a simple load or store. /// allocated and suitably aligned memory for a simple load or store.