Skip to content

Commit c6f0b74

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 eed10c9 commit c6f0b74

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
@@ -406,10 +406,10 @@ struct RuntimeCheckingPtrGroup {
406406

407407
/// The SCEV expression which represents the upper bound of all the
408408
/// pointers in this group.
409-
const SCEV *High;
409+
SCEVUse High;
410410
/// The SCEV expression which represents the lower bound of all the
411411
/// pointers in this group.
412-
const SCEV *Low;
412+
SCEVUse Low;
413413
/// Indices of all the pointers that constitute this grouping.
414414
SmallVector<unsigned, 2> Members;
415415
/// Address space of the involved pointers.
@@ -447,10 +447,10 @@ class RuntimePointerChecking {
447447
TrackingVH<Value> PointerValue;
448448
/// Holds the smallest byte address accessed by the pointer throughout all
449449
/// iterations of the loop.
450-
const SCEV *Start;
450+
SCEVUse Start;
451451
/// Holds the largest byte address accessed by the pointer throughout all
452452
/// iterations of the loop, plus 1.
453-
const SCEV *End;
453+
SCEVUse End;
454454
/// Holds the information if this pointer is used for writing to memory.
455455
bool IsWritePtr;
456456
/// Holds the id of the set of pointers that could be dependent because of a
@@ -463,7 +463,7 @@ class RuntimePointerChecking {
463463
/// True if the pointer expressions needs to be frozen after expansion.
464464
bool NeedsFreeze;
465465

466-
PointerInfo(Value *PointerValue, const SCEV *Start, const SCEV *End,
466+
PointerInfo(Value *PointerValue, SCEVUse Start, SCEVUse End,
467467
bool IsWritePtr, unsigned DependencySetId, unsigned AliasSetId,
468468
const SCEV *Expr, bool NeedsFreeze)
469469
: PointerValue(PointerValue), Start(Start), End(End),
@@ -477,8 +477,10 @@ class RuntimePointerChecking {
477477
/// Reset the state of the pointer runtime information.
478478
void reset() {
479479
Need = false;
480+
AlwaysFalse = false;
480481
Pointers.clear();
481482
Checks.clear();
483+
CheckingGroups.clear();
482484
}
483485

484486
/// Insert a pointer and calculate the start and end SCEVs.
@@ -535,6 +537,8 @@ class RuntimePointerChecking {
535537
/// This flag indicates if we need to add the runtime check.
536538
bool Need = false;
537539

540+
bool AlwaysFalse = false;
541+
538542
/// Information about the pointers that may require checking.
539543
SmallVector<PointerInfo, 2> Pointers;
540544

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
}
@@ -631,8 +641,7 @@ void RuntimePointerChecking::print(raw_ostream &OS, unsigned Depth) const {
631641
const auto &CG = CheckingGroups[I];
632642

633643
OS.indent(Depth + 2) << "Group " << &CG << ":\n";
634-
OS.indent(Depth + 4) << "(Low: " << *CG.Low << " High: " << *CG.High
635-
<< ")\n";
644+
OS.indent(Depth + 4) << "(Low: " << CG.Low << " High: " << CG.High << ")\n";
636645
for (unsigned J = 0; J < CG.Members.size(); ++J) {
637646
OS.indent(Depth + 6) << "Member: " << *Pointers[CG.Members[J]].Expr
638647
<< "\n";
@@ -1268,6 +1277,7 @@ bool AccessAnalysis::canCheckPtrAtRT(RuntimePointerChecking &RtCheck,
12681277
// If we can do run-time checks, but there are no checks, no runtime checks
12691278
// are needed. This can happen when all pointers point to the same underlying
12701279
// object for example.
1280+
CanDoRT &= !RtCheck.AlwaysFalse;
12711281
RtCheck.Need = CanDoRT ? RtCheck.getNumberOfChecks() != 0 : MayNeedRTCheck;
12721282

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

llvm/lib/Analysis/ScalarEvolution.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11950,6 +11950,8 @@ bool ScalarEvolution::splitBinaryAdd(SCEVUse Expr, SCEVUse &L, SCEVUse &R,
1195011950
L = AE->getOperand(0);
1195111951
R = AE->getOperand(1);
1195211952
Flags = AE->getNoWrapFlags();
11953+
Flags = setFlags(AE->getNoWrapFlags(),
11954+
static_cast<SCEV::NoWrapFlags>(Expr.getInt()));
1195311955
return true;
1195411956
}
1195511957

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)