summaryrefslogtreecommitdiffstats
path: root/llvm/lib/IR/Value.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/IR/Value.cpp')
-rw-r--r--llvm/lib/IR/Value.cpp48
1 files changed, 30 insertions, 18 deletions
diff --git a/llvm/lib/IR/Value.cpp b/llvm/lib/IR/Value.cpp
index 9e0a43ce1e3..b7f77dc3043 100644
--- a/llvm/lib/IR/Value.cpp
+++ b/llvm/lib/IR/Value.cpp
@@ -555,13 +555,13 @@ const Value *Value::stripPointerCastsAndInvariantGroups() const {
}
const Value *
-Value::stripAndAccumulateInBoundsConstantOffsets(const DataLayout &DL,
- APInt &Offset) const {
- if (!getType()->isPointerTy())
+Value::stripAndAccumulateConstantOffsets(const DataLayout &DL, APInt &Offset,
+ bool AllowNonInbounds) const {
+ if (!getType()->isPtrOrPtrVectorTy())
return this;
- assert(Offset.getBitWidth() == DL.getIndexSizeInBits(cast<PointerType>(
- getType())->getAddressSpace()) &&
+ unsigned BitWidth = Offset.getBitWidth();
+ assert(BitWidth == DL.getIndexTypeSizeInBits(getType()) &&
"The offset bit width does not match the DL specification.");
// Even though we don't look through PHI nodes, we could be called on an
@@ -571,27 +571,39 @@ Value::stripAndAccumulateInBoundsConstantOffsets(const DataLayout &DL,
const Value *V = this;
do {
if (auto *GEP = dyn_cast<GEPOperator>(V)) {
- if (!GEP->isInBounds())
+ // If in-bounds was requested, we do not strip non-in-bounds GEPs.
+ if (!AllowNonInbounds && !GEP->isInBounds())
return V;
- APInt GEPOffset(Offset);
+
+ // If one of the values we have visited is an addrspacecast, then
+ // the pointer type of this GEP may be different from the type
+ // of the Ptr parameter which was passed to this function. This
+ // means when we construct GEPOffset, we need to use the size
+ // of GEP's pointer type rather than the size of the original
+ // pointer type.
+ APInt GEPOffset(DL.getIndexTypeSizeInBits(V->getType()), 0);
if (!GEP->accumulateConstantOffset(DL, GEPOffset))
return V;
- Offset = GEPOffset;
+
+ // Stop traversal if the pointer offset wouldn't fit in the bit-width
+ // provided by the Offset argument. This can happen due to AddrSpaceCast
+ // stripping.
+ if (GEPOffset.getMinSignedBits() > BitWidth)
+ return V;
+
+ Offset += GEPOffset.sextOrTrunc(BitWidth);
V = GEP->getPointerOperand();
- } else if (Operator::getOpcode(V) == Instruction::BitCast) {
+ } else if (Operator::getOpcode(V) == Instruction::BitCast ||
+ Operator::getOpcode(V) == Instruction::AddrSpaceCast) {
V = cast<Operator>(V)->getOperand(0);
} else if (auto *GA = dyn_cast<GlobalAlias>(V)) {
- V = GA->getAliasee();
- } else {
- if (const auto *Call = dyn_cast<CallBase>(V))
- if (const Value *RV = Call->getReturnedArgOperand()) {
+ if (!GA->isInterposable())
+ V = GA->getAliasee();
+ } else if (const auto *Call = dyn_cast<CallBase>(V)) {
+ if (const Value *RV = Call->getReturnedArgOperand())
V = RV;
- continue;
- }
-
- return V;
}
- assert(V->getType()->isPointerTy() && "Unexpected operand type!");
+ assert(V->getType()->isPtrOrPtrVectorTy() && "Unexpected operand type!");
} while (Visited.insert(V).second);
return V;
OpenPOWER on IntegriCloud