summaryrefslogtreecommitdiff
path: root/llvm/lib/Analysis/Loads.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Analysis/Loads.cpp')
-rw-r--r--llvm/lib/Analysis/Loads.cpp109
1 files changed, 90 insertions, 19 deletions
diff --git a/llvm/lib/Analysis/Loads.cpp b/llvm/lib/Analysis/Loads.cpp
index 9a2c9ba63ec7..0c4e3a2e3b23 100644
--- a/llvm/lib/Analysis/Loads.cpp
+++ b/llvm/lib/Analysis/Loads.cpp
@@ -21,6 +21,7 @@
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/GetElementPtrTypeIterator.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Operator.h"
@@ -331,17 +332,10 @@ bool llvm::isDereferenceableAndAlignedInLoop(
: SE.getBackedgeTakenCount(L);
if (isa<SCEVCouldNotCompute>(MaxBECount))
return false;
-
- if (isa<SCEVCouldNotCompute>(BECount)) {
- // TODO: Support symbolic max backedge taken counts for loops without
- // computable backedge taken counts.
- MaxBECount =
- Predicates
- ? SE.getPredicatedConstantMaxBackedgeTakenCount(L, *Predicates)
- : SE.getConstantMaxBackedgeTakenCount(L);
- }
- const auto &[AccessStart, AccessEnd] = getStartAndEndForAccess(
- L, PtrScev, LI->getType(), BECount, MaxBECount, &SE, nullptr, &DT, AC);
+ std::optional<ScalarEvolution::LoopGuards> LoopGuards;
+ const auto &[AccessStart, AccessEnd] =
+ getStartAndEndForAccess(L, PtrScev, LI->getType(), BECount, MaxBECount,
+ &SE, nullptr, &DT, AC, LoopGuards);
if (isa<SCEVCouldNotCompute>(AccessStart) ||
isa<SCEVCouldNotCompute>(AccessEnd))
return false;
@@ -350,7 +344,13 @@ bool llvm::isDereferenceableAndAlignedInLoop(
const SCEV *PtrDiff = SE.getMinusSCEV(AccessEnd, AccessStart);
if (isa<SCEVCouldNotCompute>(PtrDiff))
return false;
- APInt MaxPtrDiff = SE.getUnsignedRangeMax(PtrDiff);
+
+ if (!LoopGuards)
+ LoopGuards.emplace(
+ ScalarEvolution::LoopGuards::collect(AddRec->getLoop(), SE));
+
+ APInt MaxPtrDiff =
+ SE.getUnsignedRangeMax(SE.applyLoopGuards(PtrDiff, *LoopGuards));
Value *Base = nullptr;
APInt AccessSize;
@@ -381,7 +381,10 @@ bool llvm::isDereferenceableAndAlignedInLoop(
if (Offset->getAPInt().urem(Alignment.value()) != 0)
return false;
- AccessSize = MaxPtrDiff + Offset->getAPInt();
+ bool Overflow = false;
+ AccessSize = MaxPtrDiff.uadd_ov(Offset->getAPInt(), Overflow);
+ if (Overflow)
+ return false;
AccessSizeSCEV = SE.getAddExpr(PtrDiff, Offset);
Base = NewBase->getValue();
} else
@@ -390,9 +393,11 @@ bool llvm::isDereferenceableAndAlignedInLoop(
Instruction *HeaderFirstNonPHI = &*L->getHeader()->getFirstNonPHIIt();
return isDereferenceableAndAlignedPointerViaAssumption(
Base, Alignment,
- [&SE, AccessSizeSCEV](const RetainedKnowledge &RK) {
- return SE.isKnownPredicate(CmpInst::ICMP_ULE, AccessSizeSCEV,
- SE.getSCEV(RK.IRArgValue));
+ [&SE, AccessSizeSCEV, &LoopGuards](const RetainedKnowledge &RK) {
+ return SE.isKnownPredicate(
+ CmpInst::ICMP_ULE,
+ SE.applyLoopGuards(AccessSizeSCEV, *LoopGuards),
+ SE.applyLoopGuards(SE.getSCEV(RK.IRArgValue), *LoopGuards));
},
DL, HeaderFirstNonPHI, AC, &DT) ||
isDereferenceableAndAlignedPointer(Base, Alignment, AccessSize, DL,
@@ -855,17 +860,83 @@ bool llvm::canReplacePointersIfEqual(const Value *From, const Value *To,
return isPointerAlwaysReplaceable(From, To, DL);
}
-bool llvm::isDereferenceableReadOnlyLoop(
+bool llvm::isReadOnlyLoop(
Loop *L, ScalarEvolution *SE, DominatorTree *DT, AssumptionCache *AC,
+ SmallVectorImpl<LoadInst *> &NonDereferenceableAndAlignedLoads,
SmallVectorImpl<const SCEVPredicate *> *Predicates) {
for (BasicBlock *BB : L->blocks()) {
for (Instruction &I : *BB) {
if (auto *LI = dyn_cast<LoadInst>(&I)) {
if (!isDereferenceableAndAlignedInLoop(LI, L, *SE, *DT, AC, Predicates))
- return false;
- } else if (I.mayReadFromMemory() || I.mayWriteToMemory() || I.mayThrow())
+ NonDereferenceableAndAlignedLoads.push_back(LI);
+ } else if (I.mayReadFromMemory() || I.mayWriteToMemory() ||
+ I.mayThrow()) {
return false;
+ }
}
}
return true;
}
+
+LinearExpression llvm::decomposeLinearExpression(const DataLayout &DL,
+ Value *Ptr) {
+ assert(Ptr->getType()->isPointerTy() && "Must be called with pointer arg");
+
+ unsigned BitWidth = DL.getIndexTypeSizeInBits(Ptr->getType());
+ LinearExpression Expr(Ptr, BitWidth);
+
+ while (true) {
+ auto *GEP = dyn_cast<GEPOperator>(Expr.BasePtr);
+ if (!GEP || GEP->getSourceElementType()->isScalableTy())
+ return Expr;
+
+ Value *VarIndex = nullptr;
+ for (Value *Index : GEP->indices()) {
+ if (isa<ConstantInt>(Index))
+ continue;
+ // Only allow a single variable index. We do not bother to handle the
+ // case of the same variable index appearing multiple times.
+ if (Expr.Index || VarIndex)
+ return Expr;
+ VarIndex = Index;
+ }
+
+ // Don't return non-canonical indexes.
+ if (VarIndex && !VarIndex->getType()->isIntegerTy(BitWidth))
+ return Expr;
+
+ // We have verified that we can fully handle this GEP, so we can update Expr
+ // members past this point.
+ Expr.BasePtr = GEP->getPointerOperand();
+ Expr.Flags = Expr.Flags.intersectForOffsetAdd(GEP->getNoWrapFlags());
+ for (gep_type_iterator GTI = gep_type_begin(GEP), GTE = gep_type_end(GEP);
+ GTI != GTE; ++GTI) {
+ Value *Index = GTI.getOperand();
+ if (auto *ConstOffset = dyn_cast<ConstantInt>(Index)) {
+ if (ConstOffset->isZero())
+ continue;
+ if (StructType *STy = GTI.getStructTypeOrNull()) {
+ unsigned ElementIdx = ConstOffset->getZExtValue();
+ const StructLayout *SL = DL.getStructLayout(STy);
+ Expr.Offset += SL->getElementOffset(ElementIdx);
+ continue;
+ }
+ // Truncate if type size exceeds index space.
+ APInt IndexedSize(BitWidth, GTI.getSequentialElementStride(DL),
+ /*isSigned=*/false,
+ /*implcitTrunc=*/true);
+ Expr.Offset += ConstOffset->getValue() * IndexedSize;
+ continue;
+ }
+
+ // FIXME: Also look through a mul/shl in the index.
+ assert(Expr.Index == nullptr && "Shouldn't have index yet");
+ Expr.Index = Index;
+ // Truncate if type size exceeds index space.
+ Expr.Scale = APInt(BitWidth, GTI.getSequentialElementStride(DL),
+ /*isSigned=*/false, /*implicitTrunc=*/true);
+ }
+ }
+
+ return Expr;
+}