summaryrefslogtreecommitdiffstats
path: root/llvm/lib/IR/Value.cpp
diff options
context:
space:
mode:
authorChandler Carruth <chandlerc@gmail.com>2013-08-22 11:25:11 +0000
committerChandler Carruth <chandlerc@gmail.com>2013-08-22 11:25:11 +0000
commit989e6308713cec4ea077cc768c473334631118b8 (patch)
treeec3a60db912ad09d1ae299d697a6681399133454 /llvm/lib/IR/Value.cpp
parent774cf3190cd99a7476a982563f6cafd0366438fd (diff)
downloadbcm5719-llvm-989e6308713cec4ea077cc768c473334631118b8.tar.gz
bcm5719-llvm-989e6308713cec4ea077cc768c473334631118b8.zip
Add a new helper method to Value to strip in-bounds constant offsets of
pointers, but accumulate the offset into an APInt in the process of stripping it. This is a pretty handy thing to have, such as when trying to determine if two pointers are at some constant relative offset. I'll be committing a patch shortly to use it for exactly that purpose. llvm-svn: 189000
Diffstat (limited to 'llvm/lib/IR/Value.cpp')
-rw-r--r--llvm/lib/IR/Value.cpp34
1 files changed, 34 insertions, 0 deletions
diff --git a/llvm/lib/IR/Value.cpp b/llvm/lib/IR/Value.cpp
index 81d7efa7740..afa9291c9ef 100644
--- a/llvm/lib/IR/Value.cpp
+++ b/llvm/lib/IR/Value.cpp
@@ -393,6 +393,40 @@ Value *Value::stripInBoundsConstantOffsets() {
return stripPointerCastsAndOffsets<PSK_InBoundsConstantIndices>(this);
}
+Value *Value::stripAndAccumulateInBoundsConstantOffsets(const DataLayout &DL,
+ APInt &Offset) {
+ if (!getType()->isPointerTy())
+ return this;
+
+ assert(Offset.getBitWidth() == DL.getPointerSizeInBits(cast<PointerType>(
+ getType())->getAddressSpace()) &&
+ "The offset must have exactly as many bits as our pointer.");
+
+ // 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;
+ Visited.insert(this);
+ Value *V = this;
+ do {
+ if (GEPOperator *GEP = dyn_cast<GEPOperator>(V)) {
+ if (!GEP->isInBounds())
+ return V;
+ if (!GEP->accumulateConstantOffset(DL, Offset))
+ return V;
+ V = GEP->getPointerOperand();
+ } else if (Operator::getOpcode(V) == Instruction::BitCast) {
+ V = cast<Operator>(V)->getOperand(0);
+ } else if (GlobalAlias *GA = dyn_cast<GlobalAlias>(V)) {
+ V = GA->getAliasee();
+ } else {
+ return V;
+ }
+ assert(V->getType()->isPointerTy() && "Unexpected operand type!");
+ } while (Visited.insert(V));
+
+ return V;
+}
+
Value *Value::stripInBoundsOffsets() {
return stripPointerCastsAndOffsets<PSK_InBounds>(this);
}
OpenPOWER on IntegriCloud