Skip to content

Commit 77f0889

Browse files
committed
[LAA] Use SCEVUse to add extra NUW flags to pointer bounds.
Use SCEVUse to add a NUW flag to the upper bound of an accessed pointer. We must already have proved that the pointers do not wrap, as otherwise we could not use them for runtime check computations. By adding the use-specific NUW flag, we can detect cases where SCEV can prove that the compared pointers must overlap, so the runtime checks will always be false. In that case, there is no point in vectorizing with runtime checks. Note that this depends c2895cd27fbf200d1da056bc66d77eeb62690bf0, which could be submitted separately if desired; without the current change, I don't think it triggers in practice though.
1 parent 8938362 commit 77f0889

12 files changed

+132
-239
lines changed

llvm/include/llvm/Analysis/LoopAccessAnalysis.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -372,10 +372,10 @@ struct RuntimeCheckingPtrGroup {
372372

373373
/// The SCEV expression which represents the upper bound of all the
374374
/// pointers in this group.
375-
const SCEV *High;
375+
SCEVUse High;
376376
/// The SCEV expression which represents the lower bound of all the
377377
/// pointers in this group.
378-
const SCEV *Low;
378+
SCEVUse Low;
379379
/// Indices of all the pointers that constitute this grouping.
380380
SmallVector<unsigned, 2> Members;
381381
/// Address space of the involved pointers.
@@ -413,10 +413,10 @@ class RuntimePointerChecking {
413413
TrackingVH<Value> PointerValue;
414414
/// Holds the smallest byte address accessed by the pointer throughout all
415415
/// iterations of the loop.
416-
const SCEV *Start;
416+
SCEVUse Start;
417417
/// Holds the largest byte address accessed by the pointer throughout all
418418
/// iterations of the loop, plus 1.
419-
const SCEV *End;
419+
SCEVUse End;
420420
/// Holds the information if this pointer is used for writing to memory.
421421
bool IsWritePtr;
422422
/// Holds the id of the set of pointers that could be dependent because of a
@@ -429,7 +429,7 @@ class RuntimePointerChecking {
429429
/// True if the pointer expressions needs to be frozen after expansion.
430430
bool NeedsFreeze;
431431

432-
PointerInfo(Value *PointerValue, const SCEV *Start, const SCEV *End,
432+
PointerInfo(Value *PointerValue, SCEVUse Start, SCEVUse End,
433433
bool IsWritePtr, unsigned DependencySetId, unsigned AliasSetId,
434434
const SCEV *Expr, bool NeedsFreeze)
435435
: PointerValue(PointerValue), Start(Start), End(End),
@@ -443,8 +443,10 @@ class RuntimePointerChecking {
443443
/// Reset the state of the pointer runtime information.
444444
void reset() {
445445
Need = false;
446+
AlwaysFalse = false;
446447
Pointers.clear();
447448
Checks.clear();
449+
CheckingGroups.clear();
448450
}
449451

450452
/// Insert a pointer and calculate the start and end SCEVs.
@@ -501,6 +503,8 @@ class RuntimePointerChecking {
501503
/// This flag indicates if we need to add the runtime check.
502504
bool Need = false;
503505

506+
bool AlwaysFalse = false;
507+
504508
/// Information about the pointers that may require checking.
505509
SmallVector<PointerInfo, 2> Pointers;
506510

llvm/lib/Analysis/LoopAccessAnalysis.cpp

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -203,13 +203,13 @@ RuntimeCheckingPtrGroup::RuntimeCheckingPtrGroup(
203203
///
204204
/// There is no conflict when the intervals are disjoint:
205205
/// NoConflict = (P2.Start >= P1.End) || (P1.Start >= P2.End)
206-
static std::pair<const SCEV *, const SCEV *>
206+
static std::pair<SCEVUse, SCEVUse>
207207
getStartAndEndForAccess(const Loop *Lp, const SCEV *PtrExpr, Type *AccessTy,
208208
PredicatedScalarEvolution &PSE) {
209209
ScalarEvolution *SE = PSE.getSE();
210210

211-
const SCEV *ScStart;
212-
const SCEV *ScEnd;
211+
SCEVUse ScStart;
212+
SCEVUse ScEnd;
213213

214214
if (SE->isLoopInvariant(PtrExpr, Lp)) {
215215
ScStart = ScEnd = PtrExpr;
@@ -219,6 +219,8 @@ getStartAndEndForAccess(const Loop *Lp, const SCEV *PtrExpr, Type *AccessTy,
219219
ScStart = AR->getStart();
220220
ScEnd = AR->evaluateAtIteration(Ex, *SE);
221221
const SCEV *Step = AR->getStepRecurrence(*SE);
222+
if (auto *Comm = dyn_cast<SCEVCommutativeExpr>(ScEnd))
223+
ScEnd = SCEVUse(ScEnd, 2);
222224

223225
// For expressions with negative step, the upper bound is ScStart and the
224226
// lower bound is ScEnd.
@@ -242,7 +244,10 @@ getStartAndEndForAccess(const Loop *Lp, const SCEV *PtrExpr, Type *AccessTy,
242244
auto &DL = Lp->getHeader()->getModule()->getDataLayout();
243245
Type *IdxTy = DL.getIndexType(PtrExpr->getType());
244246
const SCEV *EltSizeSCEV = SE->getStoreSizeOfExpr(IdxTy, AccessTy);
245-
ScEnd = SE->getAddExpr(ScEnd, EltSizeSCEV);
247+
// TODO: this computes one-past-the-end. ScEnd + EltSizeSCEV - 1 is the last
248+
// accessed byte. Not entirely sure if one-past-the-end must also not wrap? If
249+
// it does, could compute and use last accessed byte instead.
250+
ScEnd = SCEVUse(SE->getAddExpr(ScEnd, EltSizeSCEV), 2);
246251

247252
return {ScStart, ScEnd};
248253
}
@@ -377,6 +382,11 @@ SmallVector<RuntimePointerCheck, 4> RuntimePointerChecking::generateChecks() {
377382
if (needsChecking(CGI, CGJ)) {
378383
CanUseDiffCheck = CanUseDiffCheck && tryToCreateDiffCheck(CGI, CGJ);
379384
Checks.push_back(std::make_pair(&CGI, &CGJ));
385+
if (SE->isKnownPredicate(CmpInst::ICMP_UGT, CGI.High, CGJ.Low) &&
386+
SE->isKnownPredicate(CmpInst::ICMP_ULE, CGI.Low, CGJ.High)) {
387+
AlwaysFalse = true;
388+
return {};
389+
}
380390
}
381391
}
382392
}
@@ -633,8 +643,7 @@ void RuntimePointerChecking::print(raw_ostream &OS, unsigned Depth) const {
633643
const auto &CG = CheckingGroups[I];
634644

635645
OS.indent(Depth + 2) << "Group " << &CG << ":\n";
636-
OS.indent(Depth + 4) << "(Low: " << *CG.Low << " High: " << *CG.High
637-
<< ")\n";
646+
OS.indent(Depth + 4) << "(Low: " << CG.Low << " High: " << CG.High << ")\n";
638647
for (unsigned J = 0; J < CG.Members.size(); ++J) {
639648
OS.indent(Depth + 6) << "Member: " << *Pointers[CG.Members[J]].Expr
640649
<< "\n";
@@ -1272,6 +1281,7 @@ bool AccessAnalysis::canCheckPtrAtRT(RuntimePointerChecking &RtCheck,
12721281
// If we can do run-time checks, but there are no checks, no runtime checks
12731282
// are needed. This can happen when all pointers point to the same underlying
12741283
// object for example.
1284+
CanDoRT &= !RtCheck.AlwaysFalse;
12751285
RtCheck.Need = CanDoRT ? RtCheck.getNumberOfChecks() != 0 : MayNeedRTCheck;
12761286

12771287
bool CanDoRTIfNeeded = !RtCheck.Need || CanDoRT;

llvm/lib/Analysis/ScalarEvolution.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11889,6 +11889,8 @@ bool ScalarEvolution::splitBinaryAdd(SCEVUse Expr, SCEVUse &L, SCEVUse &R,
1188911889
L = AE->getOperand(0);
1189011890
R = AE->getOperand(1);
1189111891
Flags = AE->getNoWrapFlags();
11892+
Flags = setFlags(AE->getNoWrapFlags(),
11893+
static_cast<SCEV::NoWrapFlags>(Expr.getInt()));
1189211894
return true;
1189311895
}
1189411896

llvm/test/Analysis/LoopAccessAnalysis/different-strides-safe-dep-due-to-backedge-taken-count.ll

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,6 @@ define void @forward_dep_not_known_safe_due_to_backedge_taken_count(ptr %A) {
4141
; CHECK-NEXT: loop:
4242
; CHECK-NEXT: Memory dependences are safe
4343
; CHECK-NEXT: Dependences:
44-
; CHECK-NEXT: Forward:
45-
; CHECK-NEXT: %l = load i32, ptr %gep.mul.2, align 4 ->
46-
; CHECK-NEXT: store i32 %add, ptr %gep, align 4
47-
; CHECK-EMPTY:
4844
; CHECK-NEXT: Run-time memory checks:
4945
; CHECK-NEXT: Grouped accesses:
5046
; CHECK-EMPTY:
@@ -109,13 +105,8 @@ exit:
109105
define void @unknown_dep_not_known_safe_due_to_backedge_taken_count(ptr %A) {
110106
; CHECK-LABEL: 'unknown_dep_not_known_safe_due_to_backedge_taken_count'
111107
; CHECK-NEXT: loop:
112-
; CHECK-NEXT: Report: unsafe dependent memory operations in loop. Use #pragma clang loop distribute(enable) to allow loop distribution to attempt to isolate the offending operations into a separate loop
113-
; CHECK-NEXT: Unknown data dependence.
108+
; CHECK-NEXT: Memory dependences are safe
114109
; CHECK-NEXT: Dependences:
115-
; CHECK-NEXT: Unknown:
116-
; CHECK-NEXT: %l = load i32, ptr %gep, align 4 ->
117-
; CHECK-NEXT: store i32 %add, ptr %gep.mul.2, align 4
118-
; CHECK-EMPTY:
119110
; CHECK-NEXT: Run-time memory checks:
120111
; CHECK-NEXT: Grouped accesses:
121112
; CHECK-EMPTY:

0 commit comments

Comments
 (0)