From ad3f5e94b9b6bf9c2f92ae1f50cefdc509b91c15 Mon Sep 17 00:00:00 2001 From: Ryotaro Kasuga Date: Thu, 10 Jul 2025 13:20:16 +0000 Subject: [PATCH 1/5] [DA] Set Distance to zero when Direction is EQ --- llvm/lib/Analysis/DependenceAnalysis.cpp | 29 +++++++++++++++++++ .../Analysis/DependenceAnalysis/Banerjee.ll | 18 ++++++------ .../Analysis/DependenceAnalysis/Coupled.ll | 6 ++-- .../NonCanonicalizedSubscript.ll | 2 +- 4 files changed, 42 insertions(+), 13 deletions(-) diff --git a/llvm/lib/Analysis/DependenceAnalysis.cpp b/llvm/lib/Analysis/DependenceAnalysis.cpp index 5b85060f9caa1..df5fd0e938707 100644 --- a/llvm/lib/Analysis/DependenceAnalysis.cpp +++ b/llvm/lib/Analysis/DependenceAnalysis.cpp @@ -187,6 +187,18 @@ static void dumpExampleDependence(raw_ostream &OS, DependenceInfo *DA, OS << " da analyze - "; if (auto D = DA->depends(&*SrcI, &*DstI, /*UnderRuntimeAssumptions=*/true)) { + + // Verify that the distance begin zero is equivalent to the + // direction being EQ. + for (unsigned Level = 1; Level <= D->getLevels(); Level++) { + const SCEV *Distance = D->getDistance(Level); + bool IsDistanceZero = Distance && Distance->isZero(); + bool IsDirectionEQ = + D->getDirection(Level) == Dependence::DVEntry::EQ; + assert(IsDistanceZero == IsDirectionEQ && + "Inconsistent distance and direction."); + } + // Normalize negative direction vectors if required by clients. if (NormalizeResults && D->normalize(&SE)) OS << "normalized - "; @@ -3991,6 +4003,23 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst, if (CompleteLoops[II]) Result.DV[II - 1].Scalar = false; + // Set the distance to zero if the direction is EQ. + // TODO: Ideally, the distance should be set to 0 immediately simultaneously + // with the corresponding direction being set to EQ. + for (unsigned II = 1; II <= Result.getLevels(); ++II) { + if (Result.getDirection(II) == Dependence::DVEntry::EQ) + Result.DV[II - 1].Distance = SE->getZero(SrcSCEV->getType()); + + LLVM_DEBUG({ + // Check that the converse (i.e., if the distance is zero, then the + // direction is EQ) holds. + const SCEV *Distance = Result.getDistance(II); + if (Distance && Distance->isZero()) + assert(Result.getDirection(II) == Dependence::DVEntry::EQ && + "Distance is zero, but direction is not EQ"); + }); + } + if (PossiblyLoopIndependent) { // Make sure the LoopIndependent flag is set correctly. // All directions must include equal, otherwise no diff --git a/llvm/test/Analysis/DependenceAnalysis/Banerjee.ll b/llvm/test/Analysis/DependenceAnalysis/Banerjee.ll index 6768e9067dca3..d3301520fd107 100644 --- a/llvm/test/Analysis/DependenceAnalysis/Banerjee.ll +++ b/llvm/test/Analysis/DependenceAnalysis/Banerjee.ll @@ -802,7 +802,7 @@ define void @banerjee9(ptr %A, ptr %B, i64 %m, i64 %n) nounwind uwtable ssp { ; CHECK-NEXT: Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 0, ptr %arrayidx, align 8 ; CHECK-NEXT: da analyze - output [* *]! ; CHECK-NEXT: Src: store i64 0, ptr %arrayidx, align 8 --> Dst: %1 = load i64, ptr %arrayidx7, align 8 -; CHECK-NEXT: da analyze - flow [<= =|<]! +; CHECK-NEXT: da analyze - flow [<= 0|<]! ; CHECK-NEXT: Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 %1, ptr %B.addr.11, align 8 ; CHECK-NEXT: da analyze - confused! ; CHECK-NEXT: Src: %1 = load i64, ptr %arrayidx7, align 8 --> Dst: %1 = load i64, ptr %arrayidx7, align 8 @@ -816,7 +816,7 @@ define void @banerjee9(ptr %A, ptr %B, i64 %m, i64 %n) nounwind uwtable ssp { ; NORMALIZE-NEXT: Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 0, ptr %arrayidx, align 8 ; NORMALIZE-NEXT: da analyze - output [* *]! ; NORMALIZE-NEXT: Src: store i64 0, ptr %arrayidx, align 8 --> Dst: %1 = load i64, ptr %arrayidx7, align 8 -; NORMALIZE-NEXT: da analyze - flow [<= =|<]! +; NORMALIZE-NEXT: da analyze - flow [<= 0|<]! ; NORMALIZE-NEXT: Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 %1, ptr %B.addr.11, align 8 ; NORMALIZE-NEXT: da analyze - confused! ; NORMALIZE-NEXT: Src: %1 = load i64, ptr %arrayidx7, align 8 --> Dst: %1 = load i64, ptr %arrayidx7, align 8 @@ -830,7 +830,7 @@ define void @banerjee9(ptr %A, ptr %B, i64 %m, i64 %n) nounwind uwtable ssp { ; DELIN-NEXT: Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 0, ptr %arrayidx, align 8 ; DELIN-NEXT: da analyze - output [* *]! ; DELIN-NEXT: Src: store i64 0, ptr %arrayidx, align 8 --> Dst: %1 = load i64, ptr %arrayidx7, align 8 -; DELIN-NEXT: da analyze - flow [<= =|<]! +; DELIN-NEXT: da analyze - flow [<= 0|<]! ; DELIN-NEXT: Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 %1, ptr %B.addr.11, align 8 ; DELIN-NEXT: da analyze - confused! ; DELIN-NEXT: Src: %1 = load i64, ptr %arrayidx7, align 8 --> Dst: %1 = load i64, ptr %arrayidx7, align 8 @@ -888,7 +888,7 @@ define void @banerjee10(ptr %A, ptr %B, i64 %m, i64 %n) nounwind uwtable ssp { ; CHECK-NEXT: Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 0, ptr %arrayidx, align 8 ; CHECK-NEXT: da analyze - none! ; CHECK-NEXT: Src: store i64 0, ptr %arrayidx, align 8 --> Dst: %1 = load i64, ptr %arrayidx6, align 8 -; CHECK-NEXT: da analyze - flow [<> =]! +; CHECK-NEXT: da analyze - flow [<> 0]! ; CHECK-NEXT: Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 %1, ptr %B.addr.11, align 8 ; CHECK-NEXT: da analyze - confused! ; CHECK-NEXT: Src: %1 = load i64, ptr %arrayidx6, align 8 --> Dst: %1 = load i64, ptr %arrayidx6, align 8 @@ -902,7 +902,7 @@ define void @banerjee10(ptr %A, ptr %B, i64 %m, i64 %n) nounwind uwtable ssp { ; NORMALIZE-NEXT: Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 0, ptr %arrayidx, align 8 ; NORMALIZE-NEXT: da analyze - none! ; NORMALIZE-NEXT: Src: store i64 0, ptr %arrayidx, align 8 --> Dst: %1 = load i64, ptr %arrayidx6, align 8 -; NORMALIZE-NEXT: da analyze - flow [<> =]! +; NORMALIZE-NEXT: da analyze - flow [<> 0]! ; NORMALIZE-NEXT: Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 %1, ptr %B.addr.11, align 8 ; NORMALIZE-NEXT: da analyze - confused! ; NORMALIZE-NEXT: Src: %1 = load i64, ptr %arrayidx6, align 8 --> Dst: %1 = load i64, ptr %arrayidx6, align 8 @@ -916,7 +916,7 @@ define void @banerjee10(ptr %A, ptr %B, i64 %m, i64 %n) nounwind uwtable ssp { ; DELIN-NEXT: Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 0, ptr %arrayidx, align 8 ; DELIN-NEXT: da analyze - none! ; DELIN-NEXT: Src: store i64 0, ptr %arrayidx, align 8 --> Dst: %1 = load i64, ptr %arrayidx6, align 8 -; DELIN-NEXT: da analyze - flow [<> =]! +; DELIN-NEXT: da analyze - flow [<> 0]! ; DELIN-NEXT: Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 %1, ptr %B.addr.11, align 8 ; DELIN-NEXT: da analyze - confused! ; DELIN-NEXT: Src: %1 = load i64, ptr %arrayidx6, align 8 --> Dst: %1 = load i64, ptr %arrayidx6, align 8 @@ -1058,7 +1058,7 @@ define void @banerjee12(ptr %A, ptr %B, i64 %m, i64 %n) nounwind uwtable ssp { ; CHECK-NEXT: Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 0, ptr %arrayidx, align 8 ; CHECK-NEXT: da analyze - none! ; CHECK-NEXT: Src: store i64 0, ptr %arrayidx, align 8 --> Dst: %0 = load i64, ptr %arrayidx6, align 8 -; CHECK-NEXT: da analyze - flow [= <>]! +; CHECK-NEXT: da analyze - flow [0 <>]! ; CHECK-NEXT: Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 %0, ptr %B.addr.11, align 8 ; CHECK-NEXT: da analyze - confused! ; CHECK-NEXT: Src: %0 = load i64, ptr %arrayidx6, align 8 --> Dst: %0 = load i64, ptr %arrayidx6, align 8 @@ -1072,7 +1072,7 @@ define void @banerjee12(ptr %A, ptr %B, i64 %m, i64 %n) nounwind uwtable ssp { ; NORMALIZE-NEXT: Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 0, ptr %arrayidx, align 8 ; NORMALIZE-NEXT: da analyze - none! ; NORMALIZE-NEXT: Src: store i64 0, ptr %arrayidx, align 8 --> Dst: %0 = load i64, ptr %arrayidx6, align 8 -; NORMALIZE-NEXT: da analyze - flow [= <>]! +; NORMALIZE-NEXT: da analyze - flow [0 <>]! ; NORMALIZE-NEXT: Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 %0, ptr %B.addr.11, align 8 ; NORMALIZE-NEXT: da analyze - confused! ; NORMALIZE-NEXT: Src: %0 = load i64, ptr %arrayidx6, align 8 --> Dst: %0 = load i64, ptr %arrayidx6, align 8 @@ -1086,7 +1086,7 @@ define void @banerjee12(ptr %A, ptr %B, i64 %m, i64 %n) nounwind uwtable ssp { ; DELIN-NEXT: Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 0, ptr %arrayidx, align 8 ; DELIN-NEXT: da analyze - none! ; DELIN-NEXT: Src: store i64 0, ptr %arrayidx, align 8 --> Dst: %0 = load i64, ptr %arrayidx6, align 8 -; DELIN-NEXT: da analyze - flow [= <>]! +; DELIN-NEXT: da analyze - flow [0 <>]! ; DELIN-NEXT: Src: store i64 0, ptr %arrayidx, align 8 --> Dst: store i64 %0, ptr %B.addr.11, align 8 ; DELIN-NEXT: da analyze - confused! ; DELIN-NEXT: Src: %0 = load i64, ptr %arrayidx6, align 8 --> Dst: %0 = load i64, ptr %arrayidx6, align 8 diff --git a/llvm/test/Analysis/DependenceAnalysis/Coupled.ll b/llvm/test/Analysis/DependenceAnalysis/Coupled.ll index ff9f393f88152..06bfc5d2e8573 100644 --- a/llvm/test/Analysis/DependenceAnalysis/Coupled.ll +++ b/llvm/test/Analysis/DependenceAnalysis/Coupled.ll @@ -285,7 +285,7 @@ define void @couple6(ptr %A, ptr %B, i32 %n) nounwind uwtable ssp { ; CHECK-NEXT: Src: store i32 %conv, ptr %arrayidx1, align 4 --> Dst: store i32 %conv, ptr %arrayidx1, align 4 ; CHECK-NEXT: da analyze - none! ; CHECK-NEXT: Src: store i32 %conv, ptr %arrayidx1, align 4 --> Dst: %0 = load i32, ptr %arrayidx3, align 4 -; CHECK-NEXT: da analyze - flow [=|<]! +; CHECK-NEXT: da analyze - flow [0|<]! ; CHECK-NEXT: Src: store i32 %conv, ptr %arrayidx1, align 4 --> Dst: store i32 %0, ptr %B.addr.01, align 4 ; CHECK-NEXT: da analyze - confused! ; CHECK-NEXT: Src: %0 = load i32, ptr %arrayidx3, align 4 --> Dst: %0 = load i32, ptr %arrayidx3, align 4 @@ -503,7 +503,7 @@ define void @couple11(ptr %A, ptr %B, i32 %n) nounwind uwtable ssp { ; CHECK-NEXT: Src: store i32 %conv, ptr %arrayidx2, align 4 --> Dst: store i32 %conv, ptr %arrayidx2, align 4 ; CHECK-NEXT: da analyze - none! ; CHECK-NEXT: Src: store i32 %conv, ptr %arrayidx2, align 4 --> Dst: %0 = load i32, ptr %arrayidx4, align 4 -; CHECK-NEXT: da analyze - flow [=|<] splitable! +; CHECK-NEXT: da analyze - flow [0|<] splitable! ; CHECK-NEXT: da analyze - split level = 1, iteration = 9! ; CHECK-NEXT: Src: store i32 %conv, ptr %arrayidx2, align 4 --> Dst: store i32 %0, ptr %B.addr.01, align 4 ; CHECK-NEXT: da analyze - confused! @@ -636,7 +636,7 @@ define void @couple14(ptr %A, ptr %B, i32 %n) nounwind uwtable ssp { ; CHECK-NEXT: Src: store i32 %conv, ptr %arrayidx3, align 4 --> Dst: store i32 %conv, ptr %arrayidx3, align 4 ; CHECK-NEXT: da analyze - none! ; CHECK-NEXT: Src: store i32 %conv, ptr %arrayidx3, align 4 --> Dst: %0 = load i32, ptr %arrayidx6, align 4 -; CHECK-NEXT: da analyze - flow [=|<]! +; CHECK-NEXT: da analyze - flow [0|<]! ; CHECK-NEXT: Src: store i32 %conv, ptr %arrayidx3, align 4 --> Dst: store i32 %0, ptr %B.addr.01, align 4 ; CHECK-NEXT: da analyze - confused! ; CHECK-NEXT: Src: %0 = load i32, ptr %arrayidx6, align 4 --> Dst: %0 = load i32, ptr %arrayidx6, align 4 diff --git a/llvm/test/Analysis/DependenceAnalysis/NonCanonicalizedSubscript.ll b/llvm/test/Analysis/DependenceAnalysis/NonCanonicalizedSubscript.ll index f0cd2fd4cd930..e5d5d21e365a1 100644 --- a/llvm/test/Analysis/DependenceAnalysis/NonCanonicalizedSubscript.ll +++ b/llvm/test/Analysis/DependenceAnalysis/NonCanonicalizedSubscript.ll @@ -18,7 +18,7 @@ define void @i32_subscript(ptr %a, ptr %b) { ; CHECK-NEXT: Src: %0 = load i32, ptr %a.addr, align 4 --> Dst: %0 = load i32, ptr %a.addr, align 4 ; CHECK-NEXT: da analyze - none! ; CHECK-NEXT: Src: %0 = load i32, ptr %a.addr, align 4 --> Dst: store i32 %1, ptr %a.addr.2, align 4 -; CHECK-NEXT: da analyze - anti [=|<]! +; CHECK-NEXT: da analyze - anti [0|<]! ; CHECK-NEXT: Src: store i32 %1, ptr %a.addr.2, align 4 --> Dst: store i32 %1, ptr %a.addr.2, align 4 ; CHECK-NEXT: da analyze - none! ; From c3338ba51e9634c88d5dfc60d3ab0e399e212d44 Mon Sep 17 00:00:00 2001 From: Ryotaro Kasuga Date: Fri, 11 Jul 2025 00:49:00 +0900 Subject: [PATCH 2/5] Apply suggestions from code review Co-authored-by: Michael Kruse --- llvm/lib/Analysis/DependenceAnalysis.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Analysis/DependenceAnalysis.cpp b/llvm/lib/Analysis/DependenceAnalysis.cpp index df5fd0e938707..65b803bffc453 100644 --- a/llvm/lib/Analysis/DependenceAnalysis.cpp +++ b/llvm/lib/Analysis/DependenceAnalysis.cpp @@ -188,6 +188,7 @@ static void dumpExampleDependence(raw_ostream &OS, DependenceInfo *DA, if (auto D = DA->depends(&*SrcI, &*DstI, /*UnderRuntimeAssumptions=*/true)) { +#ifndef NDEBUG // Verify that the distance begin zero is equivalent to the // direction being EQ. for (unsigned Level = 1; Level <= D->getLevels(); Level++) { @@ -198,6 +199,7 @@ static void dumpExampleDependence(raw_ostream &OS, DependenceInfo *DA, assert(IsDistanceZero == IsDirectionEQ && "Inconsistent distance and direction."); } +#endif // Normalize negative direction vectors if required by clients. if (NormalizeResults && D->normalize(&SE)) @@ -4010,14 +4012,14 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst, if (Result.getDirection(II) == Dependence::DVEntry::EQ) Result.DV[II - 1].Distance = SE->getZero(SrcSCEV->getType()); - LLVM_DEBUG({ +#ifndef NDEBUG // Check that the converse (i.e., if the distance is zero, then the // direction is EQ) holds. const SCEV *Distance = Result.getDistance(II); if (Distance && Distance->isZero()) assert(Result.getDirection(II) == Dependence::DVEntry::EQ && "Distance is zero, but direction is not EQ"); - }); +#endif } if (PossiblyLoopIndependent) { From 20d5661982ecd143e8f713d11d3b4c0dd1fd686c Mon Sep 17 00:00:00 2001 From: Ryotaro Kasuga Date: Fri, 11 Jul 2025 00:48:47 +0900 Subject: [PATCH 3/5] Add assert for the cases where distance is non-zero and direction is EQ --- llvm/lib/Analysis/DependenceAnalysis.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Analysis/DependenceAnalysis.cpp b/llvm/lib/Analysis/DependenceAnalysis.cpp index 65b803bffc453..ff30b0122f4d3 100644 --- a/llvm/lib/Analysis/DependenceAnalysis.cpp +++ b/llvm/lib/Analysis/DependenceAnalysis.cpp @@ -4009,8 +4009,13 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst, // TODO: Ideally, the distance should be set to 0 immediately simultaneously // with the corresponding direction being set to EQ. for (unsigned II = 1; II <= Result.getLevels(); ++II) { - if (Result.getDirection(II) == Dependence::DVEntry::EQ) - Result.DV[II - 1].Distance = SE->getZero(SrcSCEV->getType()); + if (Result.getDirection(II) == Dependence::DVEntry::EQ) { + if (Result.DV[II - 1].Distance == nullptr) + Result.DV[II - 1].Distance = SE->getZero(SrcSCEV->getType()); + else + assert(Result.DV[II - 1].Distance->isZero() && + "Inconsistency between distance and direction"); + } #ifndef NDEBUG // Check that the converse (i.e., if the distance is zero, then the From 2a8f9c8dc1f5a6499d84d1e681ef96e70d0c63a0 Mon Sep 17 00:00:00 2001 From: Ryotaro Kasuga Date: Fri, 11 Jul 2025 00:51:50 +0900 Subject: [PATCH 4/5] Fix typo --- llvm/lib/Analysis/DependenceAnalysis.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/Analysis/DependenceAnalysis.cpp b/llvm/lib/Analysis/DependenceAnalysis.cpp index ff30b0122f4d3..1aa117043f17e 100644 --- a/llvm/lib/Analysis/DependenceAnalysis.cpp +++ b/llvm/lib/Analysis/DependenceAnalysis.cpp @@ -189,7 +189,7 @@ static void dumpExampleDependence(raw_ostream &OS, DependenceInfo *DA, /*UnderRuntimeAssumptions=*/true)) { #ifndef NDEBUG - // Verify that the distance begin zero is equivalent to the + // Verify that the distance being zero is equivalent to the // direction being EQ. for (unsigned Level = 1; Level <= D->getLevels(); Level++) { const SCEV *Distance = D->getDistance(Level); From dcb667956216cc1d333ca2a12d5a56fe381e655e Mon Sep 17 00:00:00 2001 From: Ryotaro Kasuga Date: Fri, 11 Jul 2025 01:02:31 +0900 Subject: [PATCH 5/5] Apply format --- llvm/lib/Analysis/DependenceAnalysis.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/llvm/lib/Analysis/DependenceAnalysis.cpp b/llvm/lib/Analysis/DependenceAnalysis.cpp index 1aa117043f17e..428342f51ad2e 100644 --- a/llvm/lib/Analysis/DependenceAnalysis.cpp +++ b/llvm/lib/Analysis/DependenceAnalysis.cpp @@ -4018,12 +4018,12 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst, } #ifndef NDEBUG - // Check that the converse (i.e., if the distance is zero, then the - // direction is EQ) holds. - const SCEV *Distance = Result.getDistance(II); - if (Distance && Distance->isZero()) - assert(Result.getDirection(II) == Dependence::DVEntry::EQ && - "Distance is zero, but direction is not EQ"); + // Check that the converse (i.e., if the distance is zero, then the + // direction is EQ) holds. + const SCEV *Distance = Result.getDistance(II); + if (Distance && Distance->isZero()) + assert(Result.getDirection(II) == Dependence::DVEntry::EQ && + "Distance is zero, but direction is not EQ"); #endif }