[llvm] [LoopInterchange] Detect non-LCSSA PHI in inner loop exit correctly (PR #194323)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Apr 27 02:38:07 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Ryotaro Kasuga (kasuga-fj)
<details>
<summary>Changes</summary>
In the legality check phase, `areInnerLoopExitPHIsSupported` inspects the PHI nodes in the exit block of the inner loop and bail out if certain unsupported PHI node is found. However, this check was not working as intended because the inner loop and the outer loop were mistakenly swapped.
This patch fixes the bug so that unsupported PHIs are now detected correctly.
Fix #<!-- -->193746
---
Full diff: https://github.com/llvm/llvm-project/pull/194323.diff
3 Files Affected:
- (modified) llvm/lib/Transforms/Scalar/LoopInterchange.cpp (+2-2)
- (modified) llvm/test/Transforms/LoopInterchange/lcssa-phi-outer-latch.ll (+13-22)
- (added) llvm/test/Transforms/LoopInterchange/non-lcssa-phi-in-inner-exit.ll (+53)
``````````diff
diff --git a/llvm/lib/Transforms/Scalar/LoopInterchange.cpp b/llvm/lib/Transforms/Scalar/LoopInterchange.cpp
index 49a9e77ef8deb..7d54e824041c1 100644
--- a/llvm/lib/Transforms/Scalar/LoopInterchange.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopInterchange.cpp
@@ -1333,10 +1333,10 @@ bool LoopInterchangeLegality::findInductions(
// users are either reduction PHIs or PHIs outside the outer loop (which means
// the we are only interested in the final value after the loop).
static bool
-areInnerLoopExitPHIsSupported(Loop *InnerL, Loop *OuterL,
+areInnerLoopExitPHIsSupported(Loop *OuterL, Loop *InnerL,
SmallPtrSetImpl<PHINode *> &Reductions,
PHINode *LcssaReduction) {
- BasicBlock *InnerExit = OuterL->getUniqueExitBlock();
+ BasicBlock *InnerExit = InnerL->getUniqueExitBlock();
for (PHINode &PHI : InnerExit->phis()) {
// The reduction LCSSA PHI will have only one incoming block, which comes
// from the loop latch.
diff --git a/llvm/test/Transforms/LoopInterchange/lcssa-phi-outer-latch.ll b/llvm/test/Transforms/LoopInterchange/lcssa-phi-outer-latch.ll
index 92ce3288b4529..1efb37cd67ceb 100644
--- a/llvm/test/Transforms/LoopInterchange/lcssa-phi-outer-latch.ll
+++ b/llvm/test/Transforms/LoopInterchange/lcssa-phi-outer-latch.ll
@@ -12,40 +12,31 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
define i16 @main(ptr %a) {
; CHECK-LABEL: define i16 @main(
; CHECK-SAME: ptr [[A:%.*]]) {
-; CHECK-NEXT: [[ENTRY:.*:]]
-; CHECK-NEXT: br label %[[INNER_HEADER_PREHEADER:.*]]
-; CHECK: [[OUTER_HEADER_PREHEADER:.*]]:
-; CHECK-NEXT: br label %[[OUTER_HEADER:.*]]
-; CHECK: [[OUTER_HEADER]]:
-; CHECK-NEXT: [[I:%.*]] = phi i64 [ [[I_NEXT:%.*]], %[[OUTER_LATCH:.*]] ], [ 1, %[[OUTER_HEADER_PREHEADER]] ]
-; CHECK-NEXT: br label %[[INNER_HEADER_SPLIT:.*]]
-; CHECK: [[INNER_HEADER_PREHEADER]]:
+; CHECK-NEXT: [[INNER_HEADER_PREHEADER:.*]]:
; CHECK-NEXT: br label %[[INNER_HEADER:.*]]
; CHECK: [[INNER_HEADER]]:
-; CHECK-NEXT: [[J:%.*]] = phi i16 [ [[TMP1:%.*]], %[[INNER_LATCH_SPLIT:.*]] ], [ 0, %[[INNER_HEADER_PREHEADER]] ]
-; CHECK-NEXT: br label %[[OUTER_HEADER_PREHEADER]]
-; CHECK: [[INNER_HEADER_SPLIT]]:
+; CHECK-NEXT: [[I:%.*]] = phi i64 [ 1, %[[INNER_HEADER_PREHEADER]] ], [ [[I_NEXT:%.*]], %[[OUTER_LATCH:.*]] ]
+; CHECK-NEXT: br label %[[OUTER_HEADER_PREHEADER:.*]]
+; CHECK: [[OUTER_HEADER_PREHEADER]]:
+; CHECK-NEXT: [[J:%.*]] = phi i16 [ 0, %[[INNER_HEADER]] ], [ [[TMP1:%.*]], %[[OUTER_BODY:.*]] ]
; CHECK-NEXT: [[ARRAYIDX_US_US:%.*]] = getelementptr i16, ptr [[A]], i16 [[J]]
; CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[ARRAYIDX_US_US]], align 1
; CHECK-NEXT: [[COND:%.*]] = select i1 false, i16 0, i16 0
-; CHECK-NEXT: br label %[[INNER_LATCH:.*]]
-; CHECK: [[INNER_LATCH]]:
-; CHECK-NEXT: [[J_NEXT:%.*]] = add i16 [[J]], 1
-; CHECK-NEXT: [[CMP:%.*]] = icmp slt i16 [[J]], 42
-; CHECK-NEXT: br label %[[OUTER_BODY:.*]]
-; CHECK: [[INNER_LATCH_SPLIT]]:
-; CHECK-NEXT: [[NEW_COND_LCSSA:%.*]] = phi i16 [ [[COND]], %[[OUTER_LATCH]] ]
+; CHECK-NEXT: br label %[[OUTER_BODY]]
+; CHECK: [[OUTER_BODY]]:
; CHECK-NEXT: [[TMP1]] = add i16 [[J]], 1
; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i16 [[J]], 42
-; CHECK-NEXT: br i1 [[TMP2]], label %[[INNER_HEADER]], label %[[EXIT:.*]]
-; CHECK: [[OUTER_BODY]]:
+; CHECK-NEXT: br i1 [[TMP2]], label %[[OUTER_HEADER_PREHEADER]], label %[[OUTER_BODY1:.*]]
+; CHECK: [[OUTER_BODY1]]:
+; CHECK-NEXT: [[NEW_COND_LCSSA:%.*]] = phi i16 [ [[COND]], %[[OUTER_BODY]] ]
; CHECK-NEXT: br label %[[OUTER_LATCH]]
; CHECK: [[OUTER_LATCH]]:
+; CHECK-NEXT: [[OLD_COND_LCSSA:%.*]] = phi i16 [ [[NEW_COND_LCSSA]], %[[OUTER_BODY1]] ]
; CHECK-NEXT: [[I_NEXT]] = add i64 [[I]], 1
; CHECK-NEXT: [[CMP286_US:%.*]] = icmp ugt i64 [[I]], 0
-; CHECK-NEXT: br i1 [[CMP286_US]], label %[[OUTER_HEADER]], label %[[INNER_LATCH_SPLIT]]
+; CHECK-NEXT: br i1 [[CMP286_US]], label %[[INNER_HEADER]], label %[[EXIT:.*]]
; CHECK: [[EXIT]]:
-; CHECK-NEXT: [[OLD_COND_LCSSA_LCSSA:%.*]] = phi i16 [ [[NEW_COND_LCSSA]], %[[INNER_LATCH_SPLIT]] ]
+; CHECK-NEXT: [[OLD_COND_LCSSA_LCSSA:%.*]] = phi i16 [ [[OLD_COND_LCSSA]], %[[OUTER_LATCH]] ]
; CHECK-NEXT: ret i16 [[OLD_COND_LCSSA_LCSSA]]
;
entry:
diff --git a/llvm/test/Transforms/LoopInterchange/non-lcssa-phi-in-inner-exit.ll b/llvm/test/Transforms/LoopInterchange/non-lcssa-phi-in-inner-exit.ll
new file mode 100644
index 0000000000000..575c7983452d9
--- /dev/null
+++ b/llvm/test/Transforms/LoopInterchange/non-lcssa-phi-in-inner-exit.ll
@@ -0,0 +1,53 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt < %s -passes=loop-interchange -verify-dom-info -verify-loop-info -verify-scev -verify-loop-lcssa -S | FileCheck %s
+
+; Non-lcssa phi nodes in the inner loop exit are not supported.
+
+define void @f(i1 %cond) {
+; CHECK-LABEL: define void @f(
+; CHECK-SAME: i1 [[COND:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: br label %[[OUTER_HEADER:.*]]
+; CHECK: [[OUTER_HEADER]]:
+; CHECK-NEXT: [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_INC:%.*]], %[[OUTER_LATCH:.*]] ]
+; CHECK-NEXT: br i1 [[COND]], label %[[OUTER_LATCH]], label %[[INNER_PREHEADER:.*]]
+; CHECK: [[INNER_PREHEADER]]:
+; CHECK-NEXT: br label %[[INNER:.*]]
+; CHECK: [[INNER]]:
+; CHECK-NEXT: [[J:%.*]] = phi i64 [ [[J_INC:%.*]], %[[INNER]] ], [ 0, %[[INNER_PREHEADER]] ]
+; CHECK-NEXT: [[J_INC]] = add i64 [[J]], 1
+; CHECK-NEXT: [[EC_J:%.*]] = icmp eq i64 [[J_INC]], 10
+; CHECK-NEXT: br i1 [[EC_J]], label %[[OUTER_LATCH_LOOPEXIT:.*]], label %[[INNER]]
+; CHECK: [[OUTER_LATCH_LOOPEXIT]]:
+; CHECK-NEXT: [[J_LCSSA:%.*]] = phi i64 [ [[J]], %[[INNER]] ]
+; CHECK-NEXT: br label %[[OUTER_LATCH]]
+; CHECK: [[OUTER_LATCH]]:
+; CHECK-NEXT: [[P:%.*]] = phi i64 [ [[I]], %[[OUTER_HEADER]] ], [ [[J_LCSSA]], %[[OUTER_LATCH_LOOPEXIT]] ]
+; CHECK-NEXT: [[I_INC]] = add i64 [[I]], 1
+; CHECK-NEXT: [[EC_I:%.*]] = icmp eq i64 [[I_INC]], 10
+; CHECK-NEXT: br i1 [[EC_I]], label %[[EXIT:.*]], label %[[OUTER_HEADER]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: ret void
+;
+entry:
+ br label %outer.header
+
+outer.header:
+ %i = phi i64 [ 0, %entry ], [ %i.inc, %outer.latch ]
+ br i1 %cond, label %outer.latch, label %inner
+
+inner:
+ %j = phi i64 [ 0, %outer.header ], [ %j.inc, %inner ]
+ %j.inc = add i64 %j, 1
+ %ec.j = icmp eq i64 %j.inc, 10
+ br i1 %ec.j, label %outer.latch, label %inner
+
+outer.latch:
+ %p = phi i64 [ %i, %outer.header ], [ %j, %inner ]
+ %i.inc = add i64 %i, 1
+ %ec.i = icmp eq i64 %i.inc, 10
+ br i1 %ec.i, label %exit, label %outer.header
+
+exit:
+ ret void
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/194323
More information about the llvm-commits
mailing list