aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Analysis/ConstantFolding.cpp
diff options
context:
space:
mode:
authorNikita Popov <npopov@redhat.com>2024-03-20 10:59:45 +0100
committerGitHub <noreply@github.com>2024-03-20 10:59:45 +0100
commit0f46e31cfbf415fcd3d3ce121bef94e92c6ccfc8 (patch)
treef7480770f05cd77458340f1f23104275c9be1614 /llvm/lib/Analysis/ConstantFolding.cpp
parent1f63a56cede85bcd5f4fea3663bd3a47b801a396 (diff)
downloadllvm-0f46e31cfbf415fcd3d3ce121bef94e92c6ccfc8.zip
llvm-0f46e31cfbf415fcd3d3ce121bef94e92c6ccfc8.tar.gz
llvm-0f46e31cfbf415fcd3d3ce121bef94e92c6ccfc8.tar.bz2
[IR] Change representation of getelementptr inrange (#84341)
As part of the migration to ptradd (https://discourse.llvm.org/t/rfc-replacing-getelementptr-with-ptradd/68699), we need to change the representation of the `inrange` attribute, which is used for vtable splitting. Currently, inrange is specified as follows: ``` getelementptr inbounds ({ [4 x ptr], [4 x ptr] }, ptr @vt, i64 0, inrange i32 1, i64 2) ``` The `inrange` is placed on a GEP index, and all accesses must be "in range" of that index. The new representation is as follows: ``` getelementptr inbounds inrange(-16, 16) ({ [4 x ptr], [4 x ptr] }, ptr @vt, i64 0, i32 1, i64 2) ``` This specifies which offsets are "in range" of the GEP result. The new representation will continue working when canonicalizing to ptradd representation: ``` getelementptr inbounds inrange(-16, 16) (i8, ptr @vt, i64 48) ``` The inrange offsets are relative to the return value of the GEP. An alternative design could make them relative to the source pointer instead. The result-relative format was chosen on the off-chance that we want to extend support to non-constant GEPs in the future, in which case this variant is more expressive. This implementation "upgrades" the old inrange representation in bitcode by simply dropping it. This is a very niche feature, and I don't think trying to upgrade it is worthwhile. Let me know if you disagree.
Diffstat (limited to 'llvm/lib/Analysis/ConstantFolding.cpp')
-rw-r--r--llvm/lib/Analysis/ConstantFolding.cpp43
1 files changed, 19 insertions, 24 deletions
diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
index 6b2e88d..6139b5b 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -828,7 +828,7 @@ Constant *SymbolicallyEvaluateBinop(unsigned Opc, Constant *Op0, Constant *Op1,
/// that they aren't implicitly casted by the getelementptr.
Constant *CastGEPIndices(Type *SrcElemTy, ArrayRef<Constant *> Ops,
Type *ResultTy, bool InBounds,
- std::optional<unsigned> InRangeIndex,
+ std::optional<ConstantRange> InRange,
const DataLayout &DL, const TargetLibraryInfo *TLI) {
Type *IntIdxTy = DL.getIndexType(ResultTy);
Type *IntIdxScalarTy = IntIdxTy->getScalarType();
@@ -856,8 +856,8 @@ Constant *CastGEPIndices(Type *SrcElemTy, ArrayRef<Constant *> Ops,
if (!Any)
return nullptr;
- Constant *C = ConstantExpr::getGetElementPtr(
- SrcElemTy, Ops[0], NewIdxs, InBounds, InRangeIndex);
+ Constant *C = ConstantExpr::getGetElementPtr(SrcElemTy, Ops[0], NewIdxs,
+ InBounds, InRange);
return ConstantFoldConstant(C, DL, TLI);
}
@@ -866,7 +866,6 @@ Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP,
ArrayRef<Constant *> Ops,
const DataLayout &DL,
const TargetLibraryInfo *TLI) {
- const GEPOperator *InnermostGEP = GEP;
bool InBounds = GEP->isInBounds();
Type *SrcElemTy = GEP->getSourceElementType();
@@ -875,9 +874,8 @@ Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP,
if (!SrcElemTy->isSized() || isa<ScalableVectorType>(SrcElemTy))
return nullptr;
- if (Constant *C = CastGEPIndices(SrcElemTy, Ops, ResTy,
- GEP->isInBounds(), GEP->getInRangeIndex(),
- DL, TLI))
+ if (Constant *C = CastGEPIndices(SrcElemTy, Ops, ResTy, GEP->isInBounds(),
+ GEP->getInRange(), DL, TLI))
return C;
Constant *Ptr = Ops[0];
@@ -896,9 +894,12 @@ Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP,
DL.getIndexedOffsetInType(
SrcElemTy, ArrayRef((Value *const *)Ops.data() + 1, Ops.size() - 1)));
+ std::optional<ConstantRange> InRange = GEP->getInRange();
+ if (InRange)
+ InRange = InRange->sextOrTrunc(BitWidth);
+
// If this is a GEP of a GEP, fold it all into a single GEP.
while (auto *GEP = dyn_cast<GEPOperator>(Ptr)) {
- InnermostGEP = GEP;
InBounds &= GEP->isInBounds();
SmallVector<Value *, 4> NestedOps(llvm::drop_begin(GEP->operands()));
@@ -913,6 +914,14 @@ Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP,
if (!AllConstantInt)
break;
+ // TODO: Try to intersect two inrange attributes?
+ if (!InRange) {
+ InRange = GEP->getInRange();
+ if (InRange)
+ // Adjust inrange by offset until now.
+ InRange = InRange->sextOrTrunc(BitWidth).subtract(Offset);
+ }
+
Ptr = cast<Constant>(GEP->getOperand(0));
SrcElemTy = GEP->getSourceElementType();
Offset += APInt(BitWidth, DL.getIndexedOffsetInType(SrcElemTy, NestedOps));
@@ -971,21 +980,8 @@ Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP,
NewIdxs.push_back(ConstantInt::get(
Type::getIntNTy(Ptr->getContext(), Index.getBitWidth()), Index));
- // Preserve the inrange index from the innermost GEP if possible. We must
- // have calculated the same indices up to and including the inrange index.
- std::optional<unsigned> InRangeIndex;
- if (std::optional<unsigned> LastIRIndex = InnermostGEP->getInRangeIndex())
- if (SrcElemTy == InnermostGEP->getSourceElementType() &&
- NewIdxs.size() > *LastIRIndex) {
- InRangeIndex = LastIRIndex;
- for (unsigned I = 0; I <= *LastIRIndex; ++I)
- if (NewIdxs[I] != InnermostGEP->getOperand(I + 1))
- return nullptr;
- }
-
- // Create a GEP.
return ConstantExpr::getGetElementPtr(SrcElemTy, Ptr, NewIdxs, InBounds,
- InRangeIndex);
+ InRange);
}
/// Attempt to constant fold an instruction with the
@@ -1033,8 +1029,7 @@ Constant *ConstantFoldInstOperandsImpl(const Value *InstOrCE, unsigned Opcode,
return C;
return ConstantExpr::getGetElementPtr(SrcElemTy, Ops[0], Ops.slice(1),
- GEP->isInBounds(),
- GEP->getInRangeIndex());
+ GEP->isInBounds(), GEP->getInRange());
}
if (auto *CE = dyn_cast<ConstantExpr>(InstOrCE)) {