aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/IR
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/IR')
-rw-r--r--llvm/lib/IR/AsmWriter.cpp13
-rw-r--r--llvm/lib/IR/ConstantFold.cpp35
-rw-r--r--llvm/lib/IR/Constants.cpp28
-rw-r--r--llvm/lib/IR/ConstantsContext.h51
-rw-r--r--llvm/lib/IR/Operator.cpp8
5 files changed, 80 insertions, 55 deletions
diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp
index d7fee60..5caed51 100644
--- a/llvm/lib/IR/AsmWriter.cpp
+++ b/llvm/lib/IR/AsmWriter.cpp
@@ -1414,6 +1414,10 @@ static void WriteOptimizationInfo(raw_ostream &Out, const User *U) {
} else if (const GEPOperator *GEP = dyn_cast<GEPOperator>(U)) {
if (GEP->isInBounds())
Out << " inbounds";
+ if (auto InRange = GEP->getInRange()) {
+ Out << " inrange(" << InRange->getLower() << ", " << InRange->getUpper()
+ << ")";
+ }
} else if (const auto *NNI = dyn_cast<PossiblyNonNegInst>(U)) {
if (NNI->hasNonNeg())
Out << " nneg";
@@ -1691,18 +1695,13 @@ static void WriteConstantInternal(raw_ostream &Out, const Constant *CV,
Out << ' ' << static_cast<CmpInst::Predicate>(CE->getPredicate());
Out << " (";
- std::optional<unsigned> InRangeOp;
if (const GEPOperator *GEP = dyn_cast<GEPOperator>(CE)) {
WriterCtx.TypePrinter->print(GEP->getSourceElementType(), Out);
Out << ", ";
- InRangeOp = GEP->getInRangeIndex();
- if (InRangeOp)
- ++*InRangeOp;
}
- for (User::const_op_iterator OI=CE->op_begin(); OI != CE->op_end(); ++OI) {
- if (InRangeOp && unsigned(OI - CE->op_begin()) == *InRangeOp)
- Out << "inrange ";
+ for (User::const_op_iterator OI = CE->op_begin(); OI != CE->op_end();
+ ++OI) {
WriterCtx.TypePrinter->print((*OI)->getType(), Out);
Out << ' ';
WriteAsOperandInternal(Out, *OI, WriterCtx);
diff --git a/llvm/lib/IR/ConstantFold.cpp b/llvm/lib/IR/ConstantFold.cpp
index e227851..a766b1f 100644
--- a/llvm/lib/IR/ConstantFold.cpp
+++ b/llvm/lib/IR/ConstantFold.cpp
@@ -1468,6 +1468,10 @@ static Constant *foldGEPOfGEP(GEPOperator *GEP, Type *PointeeTy, bool InBounds,
if (PointeeTy != GEP->getResultElementType())
return nullptr;
+ // Leave inrange handling to DL-aware constant folding.
+ if (GEP->getInRange())
+ return nullptr;
+
Constant *Idx0 = cast<Constant>(Idxs[0]);
if (Idx0->isNullValue()) {
// Handle the simple case of a zero index.
@@ -1477,7 +1481,7 @@ static Constant *foldGEPOfGEP(GEPOperator *GEP, Type *PointeeTy, bool InBounds,
NewIndices.append(Idxs.begin() + 1, Idxs.end());
return ConstantExpr::getGetElementPtr(
GEP->getSourceElementType(), cast<Constant>(GEP->getPointerOperand()),
- NewIndices, InBounds && GEP->isInBounds(), GEP->getInRangeIndex());
+ NewIndices, InBounds && GEP->isInBounds());
}
gep_type_iterator LastI = gep_type_end(GEP);
@@ -1526,21 +1530,14 @@ static Constant *foldGEPOfGEP(GEPOperator *GEP, Type *PointeeTy, bool InBounds,
NewIndices.push_back(ConstantExpr::get(Instruction::Add, Idx0, LastIdx));
NewIndices.append(Idxs.begin() + 1, Idxs.end());
- // The combined GEP normally inherits its index inrange attribute from
- // the inner GEP, but if the inner GEP's last index was adjusted by the
- // outer GEP, any inbounds attribute on that index is invalidated.
- std::optional<unsigned> IRIndex = GEP->getInRangeIndex();
- if (IRIndex && *IRIndex == GEP->getNumIndices() - 1)
- IRIndex = std::nullopt;
-
return ConstantExpr::getGetElementPtr(
GEP->getSourceElementType(), cast<Constant>(GEP->getPointerOperand()),
- NewIndices, InBounds && GEP->isInBounds(), IRIndex);
+ NewIndices, InBounds && GEP->isInBounds());
}
Constant *llvm::ConstantFoldGetElementPtr(Type *PointeeTy, Constant *C,
bool InBounds,
- std::optional<unsigned> InRangeIndex,
+ std::optional<ConstantRange> InRange,
ArrayRef<Value *> Idxs) {
if (Idxs.empty()) return C;
@@ -1556,7 +1553,7 @@ Constant *llvm::ConstantFoldGetElementPtr(Type *PointeeTy, Constant *C,
auto IsNoOp = [&]() {
// Avoid losing inrange information.
- if (InRangeIndex)
+ if (InRange)
return false;
return all_of(Idxs, [](Value *Idx) {
@@ -1594,12 +1591,6 @@ Constant *llvm::ConstantFoldGetElementPtr(Type *PointeeTy, Constant *C,
if (!isa<ConstantInt>(Idxs[i - 1]) && !isa<ConstantDataVector>(Idxs[i - 1]))
// Skip if the type of the previous index is not supported.
continue;
- if (InRangeIndex && i == *InRangeIndex + 1) {
- // If an index is marked inrange, we cannot apply this canonicalization to
- // the following index, as that will cause the inrange index to point to
- // the wrong element.
- continue;
- }
if (isa<StructType>(Ty)) {
// The verify makes sure that GEPs into a struct are in range.
continue;
@@ -1621,16 +1612,16 @@ Constant *llvm::ConstantFoldGetElementPtr(Type *PointeeTy, Constant *C,
}
} else {
auto *CV = cast<ConstantDataVector>(Idxs[i]);
- bool InRange = true;
+ bool IsInRange = true;
for (unsigned I = 0, E = CV->getNumElements(); I != E; ++I) {
auto *CI = cast<ConstantInt>(CV->getElementAsConstant(I));
- InRange &= isIndexInRangeOfArrayType(STy->getNumElements(), CI);
+ IsInRange &= isIndexInRangeOfArrayType(STy->getNumElements(), CI);
if (CI->isNegative()) {
Unknown = true;
break;
}
}
- if (InRange || Unknown)
+ if (IsInRange || Unknown)
// It's in range, skip to the next index.
// It's out of range and negative, don't try to factor it.
continue;
@@ -1720,7 +1711,7 @@ Constant *llvm::ConstantFoldGetElementPtr(Type *PointeeTy, Constant *C,
for (unsigned i = 0, e = Idxs.size(); i != e; ++i)
if (!NewIdxs[i]) NewIdxs[i] = cast<Constant>(Idxs[i]);
return ConstantExpr::getGetElementPtr(PointeeTy, C, NewIdxs, InBounds,
- InRangeIndex);
+ InRange);
}
// If all indices are known integers and normalized, we can do a simple
@@ -1730,7 +1721,7 @@ Constant *llvm::ConstantFoldGetElementPtr(Type *PointeeTy, Constant *C,
if (!GV->hasExternalWeakLinkage() && GV->getValueType() == PointeeTy &&
isInBoundsIndices(Idxs))
return ConstantExpr::getGetElementPtr(PointeeTy, C, Idxs,
- /*InBounds=*/true, InRangeIndex);
+ /*InBounds=*/true, InRange);
return nullptr;
}
diff --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp
index 07b5bce..c17419b 100644
--- a/llvm/lib/IR/Constants.cpp
+++ b/llvm/lib/IR/Constants.cpp
@@ -1568,7 +1568,7 @@ Constant *ConstantExpr::getWithOperands(ArrayRef<Constant *> Ops, Type *Ty,
assert(SrcTy || (Ops[0]->getType() == getOperand(0)->getType()));
return ConstantExpr::getGetElementPtr(
SrcTy ? SrcTy : GEPO->getSourceElementType(), Ops[0], Ops.slice(1),
- GEPO->isInBounds(), GEPO->getInRangeIndex(), OnlyIfReducedTy);
+ GEPO->isInBounds(), GEPO->getInRange(), OnlyIfReducedTy);
}
case Instruction::ICmp:
case Instruction::FCmp:
@@ -2349,17 +2349,16 @@ Constant *ConstantExpr::getCompare(unsigned short Predicate, Constant *C1,
Constant *ConstantExpr::getGetElementPtr(Type *Ty, Constant *C,
ArrayRef<Value *> Idxs, bool InBounds,
- std::optional<unsigned> InRangeIndex,
+ std::optional<ConstantRange> InRange,
Type *OnlyIfReducedTy) {
assert(Ty && "Must specify element type");
assert(isSupportedGetElementPtr(Ty) && "Element type is unsupported!");
- if (Constant *FC =
- ConstantFoldGetElementPtr(Ty, C, InBounds, InRangeIndex, Idxs))
- return FC; // Fold a few common cases.
+ if (Constant *FC = ConstantFoldGetElementPtr(Ty, C, InBounds, InRange, Idxs))
+ return FC; // Fold a few common cases.
- assert(GetElementPtrInst::getIndexedType(Ty, Idxs) &&
- "GEP indices invalid!");;
+ assert(GetElementPtrInst::getIndexedType(Ty, Idxs) && "GEP indices invalid!");
+ ;
// Get the result type of the getelementptr!
Type *ReqTy = GetElementPtrInst::getGEPReturnType(C, Idxs);
@@ -2392,10 +2391,9 @@ Constant *ConstantExpr::getGetElementPtr(Type *Ty, Constant *C,
}
unsigned SubClassOptionalData = InBounds ? GEPOperator::IsInBounds : 0;
- if (InRangeIndex && *InRangeIndex < 63)
- SubClassOptionalData |= (*InRangeIndex + 1) << 1;
const ConstantExprKeyType Key(Instruction::GetElementPtr, ArgVec, 0,
- SubClassOptionalData, std::nullopt, Ty);
+ SubClassOptionalData, std::nullopt, Ty,
+ InRange);
LLVMContextImpl *pImpl = C->getContext().pImpl;
return pImpl->ExprConstants.getOrCreate(ReqTy, Key);
@@ -2691,13 +2689,15 @@ const char *ConstantExpr::getOpcodeName() const {
}
GetElementPtrConstantExpr::GetElementPtrConstantExpr(
- Type *SrcElementTy, Constant *C, ArrayRef<Constant *> IdxList, Type *DestTy)
+ Type *SrcElementTy, Constant *C, ArrayRef<Constant *> IdxList, Type *DestTy,
+ std::optional<ConstantRange> InRange)
: ConstantExpr(DestTy, Instruction::GetElementPtr,
OperandTraits<GetElementPtrConstantExpr>::op_end(this) -
(IdxList.size() + 1),
IdxList.size() + 1),
SrcElementTy(SrcElementTy),
- ResElementTy(GetElementPtrInst::getIndexedType(SrcElementTy, IdxList)) {
+ ResElementTy(GetElementPtrInst::getIndexedType(SrcElementTy, IdxList)),
+ InRange(std::move(InRange)) {
Op<0>() = C;
Use *OperandList = getOperandList();
for (unsigned i = 0, E = IdxList.size(); i != E; ++i)
@@ -2712,6 +2712,10 @@ Type *GetElementPtrConstantExpr::getResultElementType() const {
return ResElementTy;
}
+std::optional<ConstantRange> GetElementPtrConstantExpr::getInRange() const {
+ return InRange;
+}
+
//===----------------------------------------------------------------------===//
// ConstantData* implementations
diff --git a/llvm/lib/IR/ConstantsContext.h b/llvm/lib/IR/ConstantsContext.h
index 44a926b..7067d0d 100644
--- a/llvm/lib/IR/ConstantsContext.h
+++ b/llvm/lib/IR/ConstantsContext.h
@@ -183,25 +183,29 @@ public:
/// GetElementPtrConstantExpr - This class is private to Constants.cpp, and is
/// used behind the scenes to implement getelementptr constant exprs.
-class GetElementPtrConstantExpr final : public ConstantExpr {
+class GetElementPtrConstantExpr : public ConstantExpr {
Type *SrcElementTy;
Type *ResElementTy;
+ std::optional<ConstantRange> InRange;
GetElementPtrConstantExpr(Type *SrcElementTy, Constant *C,
- ArrayRef<Constant *> IdxList, Type *DestTy);
+ ArrayRef<Constant *> IdxList, Type *DestTy,
+ std::optional<ConstantRange> InRange);
public:
- static GetElementPtrConstantExpr *Create(Type *SrcElementTy, Constant *C,
- ArrayRef<Constant *> IdxList,
- Type *DestTy, unsigned Flags) {
+ static GetElementPtrConstantExpr *
+ Create(Type *SrcElementTy, Constant *C, ArrayRef<Constant *> IdxList,
+ Type *DestTy, unsigned Flags, std::optional<ConstantRange> InRange) {
GetElementPtrConstantExpr *Result = new (IdxList.size() + 1)
- GetElementPtrConstantExpr(SrcElementTy, C, IdxList, DestTy);
+ GetElementPtrConstantExpr(SrcElementTy, C, IdxList, DestTy,
+ std::move(InRange));
Result->SubclassOptionalData = Flags;
return Result;
}
Type *getSourceElementType() const;
Type *getResultElementType() const;
+ std::optional<ConstantRange> getInRange() const;
/// Transparently provide more efficient getOperand methods.
DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
@@ -405,6 +409,7 @@ private:
ArrayRef<Constant *> Ops;
ArrayRef<int> ShuffleMask;
Type *ExplicitTy;
+ std::optional<ConstantRange> InRange;
static ArrayRef<int> getShuffleMaskIfValid(const ConstantExpr *CE) {
if (CE->getOpcode() == Instruction::ShuffleVector)
@@ -418,22 +423,31 @@ private:
return nullptr;
}
+ static std::optional<ConstantRange>
+ getInRangeIfValid(const ConstantExpr *CE) {
+ if (auto *GEPCE = dyn_cast<GetElementPtrConstantExpr>(CE))
+ return GEPCE->getInRange();
+ return std::nullopt;
+ }
+
public:
ConstantExprKeyType(unsigned Opcode, ArrayRef<Constant *> Ops,
unsigned short SubclassData = 0,
unsigned short SubclassOptionalData = 0,
ArrayRef<int> ShuffleMask = std::nullopt,
- Type *ExplicitTy = nullptr)
+ Type *ExplicitTy = nullptr,
+ std::optional<ConstantRange> InRange = std::nullopt)
: Opcode(Opcode), SubclassOptionalData(SubclassOptionalData),
SubclassData(SubclassData), Ops(Ops), ShuffleMask(ShuffleMask),
- ExplicitTy(ExplicitTy) {}
+ ExplicitTy(ExplicitTy), InRange(std::move(InRange)) {}
ConstantExprKeyType(ArrayRef<Constant *> Operands, const ConstantExpr *CE)
: Opcode(CE->getOpcode()),
SubclassOptionalData(CE->getRawSubclassOptionalData()),
SubclassData(CE->isCompare() ? CE->getPredicate() : 0), Ops(Operands),
ShuffleMask(getShuffleMaskIfValid(CE)),
- ExplicitTy(getSourceElementTypeIfValid(CE)) {}
+ ExplicitTy(getSourceElementTypeIfValid(CE)),
+ InRange(getInRangeIfValid(CE)) {}
ConstantExprKeyType(const ConstantExpr *CE,
SmallVectorImpl<Constant *> &Storage)
@@ -441,17 +455,26 @@ public:
SubclassOptionalData(CE->getRawSubclassOptionalData()),
SubclassData(CE->isCompare() ? CE->getPredicate() : 0),
ShuffleMask(getShuffleMaskIfValid(CE)),
- ExplicitTy(getSourceElementTypeIfValid(CE)) {
+ ExplicitTy(getSourceElementTypeIfValid(CE)),
+ InRange(getInRangeIfValid(CE)) {
assert(Storage.empty() && "Expected empty storage");
for (unsigned I = 0, E = CE->getNumOperands(); I != E; ++I)
Storage.push_back(CE->getOperand(I));
Ops = Storage;
}
+ static bool rangesEqual(const std::optional<ConstantRange> &A,
+ const std::optional<ConstantRange> &B) {
+ if (!A.has_value() || !B.has_value())
+ return A.has_value() == B.has_value();
+ return A->getBitWidth() == B->getBitWidth() && A == B;
+ }
+
bool operator==(const ConstantExprKeyType &X) const {
return Opcode == X.Opcode && SubclassData == X.SubclassData &&
SubclassOptionalData == X.SubclassOptionalData && Ops == X.Ops &&
- ShuffleMask == X.ShuffleMask && ExplicitTy == X.ExplicitTy;
+ ShuffleMask == X.ShuffleMask && ExplicitTy == X.ExplicitTy &&
+ rangesEqual(InRange, X.InRange);
}
bool operator==(const ConstantExpr *CE) const {
@@ -470,6 +493,8 @@ public:
return false;
if (ExplicitTy != getSourceElementTypeIfValid(CE))
return false;
+ if (!rangesEqual(InRange, getInRangeIfValid(CE)))
+ return false;
return true;
}
@@ -499,8 +524,8 @@ public:
case Instruction::ShuffleVector:
return new ShuffleVectorConstantExpr(Ops[0], Ops[1], ShuffleMask);
case Instruction::GetElementPtr:
- return GetElementPtrConstantExpr::Create(ExplicitTy, Ops[0], Ops.slice(1),
- Ty, SubclassOptionalData);
+ return GetElementPtrConstantExpr::Create(
+ ExplicitTy, Ops[0], Ops.slice(1), Ty, SubclassOptionalData, InRange);
case Instruction::ICmp:
return new CompareConstantExpr(Ty, Instruction::ICmp, SubclassData,
Ops[0], Ops[1]);
diff --git a/llvm/lib/IR/Operator.cpp b/llvm/lib/IR/Operator.cpp
index caf8fe6..b9cd219 100644
--- a/llvm/lib/IR/Operator.cpp
+++ b/llvm/lib/IR/Operator.cpp
@@ -37,7 +37,7 @@ bool Operator::hasPoisonGeneratingFlags() const {
case Instruction::GetElementPtr: {
auto *GEP = cast<GEPOperator>(this);
// Note: inrange exists on constexpr only
- return GEP->isInBounds() || GEP->getInRangeIndex() != std::nullopt;
+ return GEP->isInBounds() || GEP->getInRange() != std::nullopt;
}
case Instruction::ZExt:
if (auto *NNI = dyn_cast<PossiblyNonNegInst>(this))
@@ -69,6 +69,12 @@ Type *GEPOperator::getResultElementType() const {
return cast<GetElementPtrConstantExpr>(this)->getResultElementType();
}
+std::optional<ConstantRange> GEPOperator::getInRange() const {
+ if (auto *CE = dyn_cast<GetElementPtrConstantExpr>(this))
+ return CE->getInRange();
+ return std::nullopt;
+}
+
Align GEPOperator::getMaxPreservedAlignment(const DataLayout &DL) const {
/// compute the worse possible offset for every level of the GEP et accumulate
/// the minimum alignment into Result.