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 | 989e6308713cec4ea077cc768c473334631118b8 (patch) | |
tree | ec3a60db912ad09d1ae299d697a6681399133454 /llvm/lib/IR/Value.cpp | |
parent | 774cf3190cd99a7476a982563f6cafd0366438fd (diff) | |
download | bcm5719-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.cpp | 34 |
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); } |