summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/Value.h24
-rw-r--r--lib/Analysis/InstructionSimplify.cpp28
-rw-r--r--lib/VMCore/Value.cpp48
3 files changed, 66 insertions, 34 deletions
diff --git a/include/llvm/Value.h b/include/llvm/Value.h
index 9c658cfbd1..9896bc7693 100644
--- a/include/llvm/Value.h
+++ b/include/llvm/Value.h
@@ -263,14 +263,32 @@ public:
return true; // Values are always values.
}
- /// stripPointerCasts - This method strips off any unneeded pointer
- /// casts from the specified value, returning the original uncasted value.
- /// Note that the returned value has pointer type if the specified value does.
+ /// stripPointerCasts - This method strips off any unneeded pointer casts and
+ /// all-zero GEPs from the specified value, returning the original uncasted
+ /// value. If this is called on a non-pointer value, it returns 'this'.
Value *stripPointerCasts();
const Value *stripPointerCasts() const {
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
/// allocated and suitably aligned memory for a simple load or store.
bool isDereferenceablePointer() const;
diff --git a/lib/Analysis/InstructionSimplify.cpp b/lib/Analysis/InstructionSimplify.cpp
index 370ab96288..c024e9260b 100644
--- a/lib/Analysis/InstructionSimplify.cpp
+++ b/lib/Analysis/InstructionSimplify.cpp
@@ -1522,28 +1522,6 @@ static Value *ExtractEquivalentCondition(Value *V, CmpInst::Predicate Pred,
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
/// 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
// comparison of an alloca address to another object. We can rip off all
// inbounds GEP operations, even if they are variable.
- LHSPtr = stripPointerAdjustments(LHSPtr);
+ LHSPtr = LHSPtr->stripInBoundsOffsets();
if (llvm::isIdentifiedObject(LHSPtr)) {
- RHSPtr = stripPointerAdjustments(RHSPtr);
+ RHSPtr = RHSPtr->stripInBoundsOffsets();
if (llvm::isKnownNonNull(LHSPtr) || llvm::isKnownNonNull(RHSPtr)) {
// If both sides are different identified objects, they aren't equal
// unless they're null.
@@ -1644,7 +1622,7 @@ static Value *SimplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS,
if (llvm::isKnownNonNull(LHSPtr) && isa<ConstantPointerNull>(RHSPtr))
return ConstantInt::get(ITy, CmpInst::isFalseWhenEqual(Pred));
} else if (isa<Argument>(LHSPtr)) {
- RHSPtr = stripPointerAdjustments(RHSPtr);
+ RHSPtr = RHSPtr->stripInBoundsOffsets();
// An alloca can't be equal to an argument.
if (isa<AllocaInst>(RHSPtr))
return ConstantInt::get(ITy, CmpInst::isFalseWhenEqual(Pred));
diff --git a/lib/VMCore/Value.cpp b/lib/VMCore/Value.cpp
index 207c06d223..40b2d95e3d 100644
--- a/lib/VMCore/Value.cpp
+++ b/lib/VMCore/Value.cpp
@@ -317,20 +317,43 @@ void Value::replaceAllUsesWith(Value *New) {
BB->replaceSuccessorsPhiUsesWith(cast<BasicBlock>(New));
}
-Value *Value::stripPointerCasts() {
- if (!getType()->isPointerTy())
- return this;
+namespace {
+// Various metrics for how much to strip off of pointers.
+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
// instruction in an unreachable block, which may be on a cycle.
SmallPtrSet<Value *, 4> Visited;
- Value *V = this;
Visited.insert(V);
do {
if (GEPOperator *GEP = dyn_cast<GEPOperator>(V)) {
- if (!GEP->hasAllZeroIndices())
- return V;
+ switch (StripKind) {
+ 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();
} else if (Operator::getOpcode(V) == Instruction::BitCast) {
V = cast<Operator>(V)->getOperand(0);
@@ -346,6 +369,19 @@ Value *Value::stripPointerCasts() {
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
/// allocated and suitably aligned memory for a simple load or store.