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 Instruction; +class LLVMContext; +class MDNode; +class StringRef; +class Twine; +class Type; +class ValueHandleBase; class ValueSymbolTable; +class raw_ostream; + template class StringMapEntry; typedef StringMapEntry 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(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); }