[llvm] [LAA] Make Ptr argument optional in isNoWrap. (PR #127410)
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Sun Feb 16 11:45:28 PST 2025
https://github.com/fhahn created https://github.com/llvm/llvm-project/pull/127410
Update isNoWrap to make the IR Ptr argument optional. This allows using isNoWrap when dealing with things like pointer-selects, where a select is translated to multiple pointer SCEV expressions, but there is no IR value that can be used. We don't try to retrieve pointer values for the pointer SCEVs and using info from the IR would not be safe. For example, we cannot use inbounds, because the pointer may never be accessed.
>From 171135fbd5214c82e96f5a226c701b398d776656 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Fri, 14 Feb 2025 15:37:45 +0100
Subject: [PATCH] [LAA] Make Ptr argument optional in isNoWrap.
Update isNoWrap to make the IR Ptr argument optional. This allows using
isNoWrap when dealing with things like pointer-selects, where a select
is translated to multiple pointer SCEV expressions, but there is no IR
value that can be used. We don't try to retrieve pointer values for the
pointer SCEVs and using info from the IR would not be safe. For example,
we cannot use inbounds, because the pointer may never be accessed.
---
llvm/lib/Analysis/LoopAccessAnalysis.cpp | 39 ++++++++++------
...ter-dependence-analysis-forked-pointers.ll | 44 ++++++++++++++++++-
2 files changed, 69 insertions(+), 14 deletions(-)
diff --git a/llvm/lib/Analysis/LoopAccessAnalysis.cpp b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
index 7d6dbd51a404d..63bb79f061bea 100644
--- a/llvm/lib/Analysis/LoopAccessAnalysis.cpp
+++ b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
@@ -799,8 +799,13 @@ getStrideFromAddRec(const SCEVAddRecExpr *AR, const Loop *Lp, Type *AccessTy,
Value *Ptr, PredicatedScalarEvolution &PSE) {
// The access function must stride over the innermost loop.
if (Lp != AR->getLoop()) {
- LLVM_DEBUG(dbgs() << "LAA: Bad stride - Not striding over innermost loop "
- << *Ptr << " SCEV: " << *AR << "\n");
+ LLVM_DEBUG({
+ dbgs() << "LAA: Bad stride - Not striding over innermost loop ";
+ if (Ptr)
+ dbgs() << *Ptr << " ";
+
+ dbgs() << "SCEV: " << *AR << "\n";
+ });
return std::nullopt;
}
@@ -810,8 +815,12 @@ getStrideFromAddRec(const SCEVAddRecExpr *AR, const Loop *Lp, Type *AccessTy,
// Calculate the pointer stride and check if it is constant.
const SCEVConstant *C = dyn_cast<SCEVConstant>(Step);
if (!C) {
- LLVM_DEBUG(dbgs() << "LAA: Bad stride - Not a constant strided " << *Ptr
- << " SCEV: " << *AR << "\n");
+ LLVM_DEBUG({
+ dbgs() << "LAA: Bad stride - Not a constant strided ";
+ if (Ptr)
+ dbgs() << *Ptr << " ";
+ dbgs() << "SCEV: " << *AR << "\n";
+ });
return std::nullopt;
}
@@ -838,7 +847,8 @@ getStrideFromAddRec(const SCEVAddRecExpr *AR, const Loop *Lp, Type *AccessTy,
static bool isNoWrapAddRec(Value *Ptr, const SCEVAddRecExpr *AR,
PredicatedScalarEvolution &PSE, const Loop *L);
-/// Check whether a pointer address cannot wrap.
+/// Check whether a pointer address cannot wrap. If \p Ptr is not nullptr, use
+/// informating from the IR pointer value to determine no-wrap.
static bool isNoWrap(PredicatedScalarEvolution &PSE, const SCEVAddRecExpr *AR,
Value *Ptr, Type *AccessTy, const Loop *L, bool Assume,
std::optional<int64_t> Stride = std::nullopt) {
@@ -852,7 +862,7 @@ static bool isNoWrap(PredicatedScalarEvolution &PSE, const SCEVAddRecExpr *AR,
// location will be larger than half the pointer index type space. In that
// case, the GEP would be poison and any memory access dependent on it would
// be immediate UB when executed.
- if (auto *GEP = dyn_cast<GetElementPtrInst>(Ptr);
+ if (auto *GEP = dyn_cast_if_present<GetElementPtrInst>(Ptr);
GEP && GEP->hasNoUnsignedSignedWrap())
return true;
@@ -868,6 +878,9 @@ static bool isNoWrap(PredicatedScalarEvolution &PSE, const SCEVAddRecExpr *AR,
return true;
}
+ if (!Ptr)
+ return false;
+
if (Assume) {
PSE.setNoOverflow(Ptr, SCEVWrapPredicate::IncrementNUSW);
LLVM_DEBUG(dbgs() << "LAA: Pointer may wrap:\n"
@@ -1135,13 +1148,10 @@ bool AccessAnalysis::createCheckForAccess(RuntimePointerChecking &RtCheck,
// When we run after a failing dependency check we have to make sure
// we don't have wrapping pointers.
- if (ShouldCheckWrap) {
- // Skip wrap checking when translating pointers.
- if (TranslatedPtrs.size() > 1)
- return false;
-
- if (!isNoWrap(PSE, AR, Ptr, AccessTy, TheLoop, Assume))
- return false;
+ if (ShouldCheckWrap &&
+ !isNoWrap(PSE, AR, TranslatedPtrs.size() == 1 ? Ptr : nullptr, AccessTy,
+ TheLoop, Assume)) {
+ return false;
}
}
@@ -1454,6 +1464,9 @@ static bool isNoWrapAddRec(Value *Ptr, const SCEVAddRecExpr *AR,
if (AR->getNoWrapFlags(SCEV::NoWrapMask))
return true;
+ if (!Ptr)
+ return false;
+
if (PSE.hasNoOverflow(Ptr, SCEVWrapPredicate::IncrementNUSW))
return true;
diff --git a/llvm/test/Analysis/LoopAccessAnalysis/retry-runtime-checks-after-dependence-analysis-forked-pointers.ll b/llvm/test/Analysis/LoopAccessAnalysis/retry-runtime-checks-after-dependence-analysis-forked-pointers.ll
index 5e9dc7f2b91cc..38b7389ae9083 100644
--- a/llvm/test/Analysis/LoopAccessAnalysis/retry-runtime-checks-after-dependence-analysis-forked-pointers.ll
+++ b/llvm/test/Analysis/LoopAccessAnalysis/retry-runtime-checks-after-dependence-analysis-forked-pointers.ll
@@ -83,10 +83,52 @@ exit:
define void @dependency_check_and_runtime_checks_needed_select_of_ptr_add_recs(ptr %a, ptr %b, ptr %c, i64 %offset, i64 %n) {
; CHECK-LABEL: 'dependency_check_and_runtime_checks_needed_select_of_ptr_add_recs'
; CHECK-NEXT: loop:
-; CHECK-NEXT: Report: cannot check memory dependencies at runtime
+; CHECK-NEXT: Memory dependences are safe with run-time checks
; CHECK-NEXT: Dependences:
; CHECK-NEXT: Run-time memory checks:
+; CHECK-NEXT: Check 0:
+; CHECK-NEXT: Comparing group ([[GRP5:0x[0-9a-f]+]]):
+; CHECK-NEXT: %gep.a.iv = getelementptr inbounds float, ptr %a, i64 %iv
+; CHECK-NEXT: Against group ([[GRP6:0x[0-9a-f]+]]):
+; CHECK-NEXT: %select = select i1 %cmp, ptr %gep.b, ptr %gep.c
+; CHECK-NEXT: Check 1:
+; CHECK-NEXT: Comparing group ([[GRP5]]):
+; CHECK-NEXT: %gep.a.iv = getelementptr inbounds float, ptr %a, i64 %iv
+; CHECK-NEXT: Against group ([[GRP7:0x[0-9a-f]+]]):
+; CHECK-NEXT: %select = select i1 %cmp, ptr %gep.b, ptr %gep.c
+; CHECK-NEXT: Check 2:
+; CHECK-NEXT: Comparing group ([[GRP5]]):
+; CHECK-NEXT: %gep.a.iv = getelementptr inbounds float, ptr %a, i64 %iv
+; CHECK-NEXT: Against group ([[GRP8:0x[0-9a-f]+]]):
+; CHECK-NEXT: %gep.a.iv.off = getelementptr inbounds float, ptr %a, i64 %iv.offset
+; CHECK-NEXT: Check 3:
+; CHECK-NEXT: Comparing group ([[GRP6]]):
+; CHECK-NEXT: %select = select i1 %cmp, ptr %gep.b, ptr %gep.c
+; CHECK-NEXT: Against group ([[GRP7]]):
+; CHECK-NEXT: %select = select i1 %cmp, ptr %gep.b, ptr %gep.c
+; CHECK-NEXT: Check 4:
+; CHECK-NEXT: Comparing group ([[GRP6]]):
+; CHECK-NEXT: %select = select i1 %cmp, ptr %gep.b, ptr %gep.c
+; CHECK-NEXT: Against group ([[GRP8]]):
+; CHECK-NEXT: %gep.a.iv.off = getelementptr inbounds float, ptr %a, i64 %iv.offset
+; CHECK-NEXT: Check 5:
+; CHECK-NEXT: Comparing group ([[GRP7]]):
+; CHECK-NEXT: %select = select i1 %cmp, ptr %gep.b, ptr %gep.c
+; CHECK-NEXT: Against group ([[GRP8]]):
+; CHECK-NEXT: %gep.a.iv.off = getelementptr inbounds float, ptr %a, i64 %iv.offset
; CHECK-NEXT: Grouped accesses:
+; CHECK-NEXT: Group [[GRP5]]:
+; CHECK-NEXT: (Low: %a High: ((4 * %n) + %a))
+; CHECK-NEXT: Member: {%a,+,4}<nuw><%loop>
+; CHECK-NEXT: Group [[GRP6]]:
+; CHECK-NEXT: (Low: %b High: ((4 * %n) + %b))
+; CHECK-NEXT: Member: {%b,+,4}<%loop>
+; CHECK-NEXT: Group [[GRP7]]:
+; CHECK-NEXT: (Low: %c High: ((4 * %n) + %c))
+; CHECK-NEXT: Member: {%c,+,4}<%loop>
+; CHECK-NEXT: Group [[GRP8]]:
+; CHECK-NEXT: (Low: ((4 * %offset) + %a) High: ((4 * %offset) + (4 * %n) + %a))
+; CHECK-NEXT: Member: {((4 * %offset) + %a),+,4}<%loop>
; CHECK-EMPTY:
; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop.
; CHECK-NEXT: SCEV assumptions:
More information about the llvm-commits
mailing list