From: Chandler Carruth Date: Thu, 22 Aug 2013 11:25:11 +0000 (+0000) Subject: Add a new helper method to Value to strip in-bounds constant offsets of X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=f73826bef09fcc38d2db7b69baf0b8a45c9788f8;p=oota-llvm.git 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 --- diff --git a/include/llvm/IR/Value.h b/include/llvm/IR/Value.h index e667b87f03a..e1361fef351 100644 --- a/include/llvm/IR/Value.h +++ b/include/llvm/IR/Value.h @@ -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 ValueSymbolTable; -template class StringMapEntry; -typedef StringMapEntry ValueName; -class raw_ostream; -class AssemblyAnnotationWriter; -class ValueHandleBase; +class Instruction; class LLVMContext; -class Twine; class MDNode; -class Type; class StringRef; +class Twine; +class Type; +class ValueHandleBase; +class ValueSymbolTable; +class raw_ostream; + +template class StringMapEntry; +typedef StringMapEntry ValueName; //===----------------------------------------------------------------------===// // Value Class @@ -287,6 +290,22 @@ public: return const_cast(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(this) + ->stripAndAccumulateInBoundsConstantOffsets(DL, Offset); + } + /// \brief Strips off unneeded pointer casts and any in-bounds offsets from /// the specified value, returning the original pointer value. /// diff --git a/lib/IR/Value.cpp b/lib/IR/Value.cpp index 81d7efa7740..afa9291c9ef 100644 --- a/lib/IR/Value.cpp +++ b/lib/IR/Value.cpp @@ -393,6 +393,40 @@ Value *Value::stripInBoundsConstantOffsets() { return stripPointerCastsAndOffsets(this); } +Value *Value::stripAndAccumulateInBoundsConstantOffsets(const DataLayout &DL, + APInt &Offset) { + if (!getType()->isPointerTy()) + return this; + + assert(Offset.getBitWidth() == DL.getPointerSizeInBits(cast( + 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 Visited; + Visited.insert(this); + Value *V = this; + do { + if (GEPOperator *GEP = dyn_cast(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(V)->getOperand(0); + } else if (GlobalAlias *GA = dyn_cast(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(this); }