diff options
author | Chandler Carruth <chandlerc@gmail.com> | 2013-08-22 11:25:11 +0000 |
---|---|---|
committer | Chandler Carruth <chandlerc@gmail.com> | 2013-08-22 11:25:11 +0000 |
commit | f73826bef09fcc38d2db7b69baf0b8a45c9788f8 (patch) | |
tree | e753a61c30eb9246f6cdd6a467573e35e628120f /lib/IR | |
parent | 4efbeb2700506fa1cbbca5e487b57eaad05c60ed (diff) | |
download | llvm-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.cpp | 34 |
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); } |