summaryrefslogtreecommitdiff
path: root/lib/IR
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
commitf73826bef09fcc38d2db7b69baf0b8a45c9788f8 (patch)
treee753a61c30eb9246f6cdd6a467573e35e628120f /lib/IR
parent4efbeb2700506fa1cbbca5e487b57eaad05c60ed (diff)
downloadllvm-f73826bef09fcc38d2db7b69baf0b8a45c9788f8.tar.gz
llvm-f73826bef09fcc38d2db7b69baf0b8a45c9788f8.tar.bz2
llvm-f73826bef09fcc38d2db7b69baf0b8a45c9788f8.tar.xz
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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189000 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/IR')
-rw-r--r--lib/IR/Value.cpp34
1 files changed, 34 insertions, 0 deletions
diff --git a/lib/IR/Value.cpp b/lib/IR/Value.cpp
index 81d7efa774..afa9291c9e 100644
--- a/lib/IR/Value.cpp
+++ b/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);
}