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
This commit is contained in:
Chandler Carruth 2013-08-22 11:25:11 +00:00
parent 774cf3190c
commit 989e630871
2 changed files with 65 additions and 12 deletions

View File

@ -22,26 +22,29 @@
namespace llvm {
class Constant;
class APInt;
class Argument;
class Instruction;
class AssemblyAnnotationWriter;
class BasicBlock;
class GlobalValue;
class Constant;
class DataLayout;
class Function;
class GlobalVariable;
class GlobalAlias;
class GlobalValue;
class GlobalVariable;
class InlineAsm;
class Instruction;
class LLVMContext;
class MDNode;
class StringRef;
class Twine;
class Type;
class ValueHandleBase;
class ValueSymbolTable;
class raw_ostream;
template<typename ValueTy> class StringMapEntry;
typedef StringMapEntry<Value*> ValueName;
class raw_ostream;
class AssemblyAnnotationWriter;
class ValueHandleBase;
class LLVMContext;
class Twine;
class MDNode;
class Type;
class StringRef;
//===----------------------------------------------------------------------===//
// Value Class
@ -287,6 +290,22 @@ public:
return const_cast<Value*>(this)->stripInBoundsConstantOffsets();
}
/// \brief Strips like \c stripInBoundsConstantOffsets but also accumulates
/// the constant offset stripped.
///
/// Stores the resulting constant offset stripped into the APInt provided.
/// The provided APInt will be extended or truncated as needed to be the
/// correct bitwidth for an offset of this pointer type.
///
/// If this is called on a non-pointer value, it returns 'this'.
Value *stripAndAccumulateInBoundsConstantOffsets(const DataLayout &DL,
APInt &Offset);
const Value *stripAndAccumulateInBoundsConstantOffsets(const DataLayout &DL,
APInt &Offset) const {
return const_cast<Value *>(this)
->stripAndAccumulateInBoundsConstantOffsets(DL, Offset);
}
/// \brief Strips off unneeded pointer casts and any in-bounds offsets from
/// the specified value, returning the original pointer value.
///

View File

@ -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);
}