[llvm] [LoopInterchange] Add tests for outer-variant inner IV step (NFC) (PR #202750)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 9 12:52:22 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Ryotaro Kasuga (kasuga-fj)

<details>
<summary>Changes</summary>

Adds test cases for #<!-- -->202383 and #<!-- -->202401. Both have an induction variable in the inner loop whose step value is not loop-invariant with respect to the outer loop.

---
Full diff: https://github.com/llvm/llvm-project/pull/202750.diff


1 Files Affected:

- (added) llvm/test/Transforms/LoopInterchange/inner-induciton-step-is-not-invariant.ll (+147) 


``````````diff
diff --git a/llvm/test/Transforms/LoopInterchange/inner-induciton-step-is-not-invariant.ll b/llvm/test/Transforms/LoopInterchange/inner-induciton-step-is-not-invariant.ll
new file mode 100644
index 0000000000000..37bc9266942ed
--- /dev/null
+++ b/llvm/test/Transforms/LoopInterchange/inner-induciton-step-is-not-invariant.ll
@@ -0,0 +1,147 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt < %s -passes=loop-interchange -loop-interchange-profitabilities=ignore -S | FileCheck %s
+
+; When the inner loop has induction variables whose step recurrence values are
+; not loop-invariant with respect to the outer loop, it is generally not safe
+; to interchange the loops. These tests check that we don't perform
+; loop-interchange in such cases.
+
+; for (i = 1; i < 8; i++)
+;   for (j = 0, k = 0; k < 16 + i; j++, k += i)
+;     A[8*j + i] += 1;
+;
+; FIXME: This is now interchanged.
+;
+define void @step_of_k_is_i_0(ptr %A) {
+; CHECK-LABEL: define void @step_of_k_is_i_0(
+; CHECK-SAME: ptr [[A:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    br label %[[OUTER_HEADER:.*]]
+; CHECK:       [[OUTER_HEADER_PREHEADER:.*]]:
+; CHECK-NEXT:    br label %[[INNER:.*]]
+; CHECK:       [[INNER]]:
+; CHECK-NEXT:    [[I:%.*]] = phi i64 [ [[I_NEXT:%.*]], %[[OUTER_LATCH:.*]] ], [ 1, %[[OUTER_HEADER_PREHEADER]] ]
+; CHECK-NEXT:    br label %[[INNER_SPLIT1:.*]]
+; CHECK:       [[OUTER_HEADER]]:
+; CHECK-NEXT:    br label %[[INNER1:.*]]
+; CHECK:       [[INNER1]]:
+; CHECK-NEXT:    [[J:%.*]] = phi i64 [ [[TMP1:%.*]], %[[INNER_SPLIT:.*]] ], [ 0, %[[OUTER_HEADER]] ]
+; CHECK-NEXT:    [[K:%.*]] = phi i64 [ [[TMP0:%.*]], %[[INNER_SPLIT]] ], [ 0, %[[OUTER_HEADER]] ]
+; CHECK-NEXT:    br label %[[OUTER_HEADER_PREHEADER]]
+; CHECK:       [[INNER_SPLIT1]]:
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr [8 x i8], ptr [[A]], i64 [[J]], i64 [[I]]
+; CHECK-NEXT:    [[OLD:%.*]] = load i8, ptr [[GEP]], align 1
+; CHECK-NEXT:    [[NEW:%.*]] = add i8 [[OLD]], 1
+; CHECK-NEXT:    store i8 [[NEW]], ptr [[GEP]], align 1
+; CHECK-NEXT:    [[J_NEXT:%.*]] = add i64 [[J]], 1
+; CHECK-NEXT:    [[K_NEXT:%.*]] = add i64 [[K]], [[I]]
+; CHECK-NEXT:    [[EC_INNER_NOT:%.*]] = icmp slt i64 [[K]], 16
+; CHECK-NEXT:    br label %[[OUTER_LATCH]]
+; CHECK:       [[INNER_SPLIT]]:
+; CHECK-NEXT:    [[I_LCSSA:%.*]] = phi i64 [ [[I]], %[[OUTER_LATCH]] ]
+; CHECK-NEXT:    [[TMP0]] = add i64 [[K]], [[I_LCSSA]]
+; CHECK-NEXT:    [[TMP1]] = add i64 [[J]], 1
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i64 [[K]], 16
+; CHECK-NEXT:    br i1 [[TMP2]], label %[[INNER1]], label %[[EXIT:.*]]
+; CHECK:       [[OUTER_LATCH]]:
+; CHECK-NEXT:    [[I_NEXT]] = add i64 [[I]], 1
+; CHECK-NEXT:    [[CMP_I:%.*]] = icmp slt i64 [[I_NEXT]], 8
+; CHECK-NEXT:    br i1 [[CMP_I]], label %[[INNER]], label %[[INNER_SPLIT]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %outer.header
+
+outer.header:
+  %i = phi i64 [ 1, %entry ], [ %i.next, %outer.latch ]
+  br label %inner
+
+inner:
+  %j = phi i64 [ 0, %outer.header ], [ %j.next, %inner ]
+  %k = phi i64 [ 0, %outer.header ], [ %k.next, %inner ]
+  %gep = getelementptr [8 x i8], ptr %A, i64 %j, i64 %i
+  %old = load i8, ptr %gep
+  %new = add i8 %old, 1
+  store i8 %new, ptr %gep
+  %j.next = add i64 %j, 1
+  %k.next = add i64 %k, %i
+  %ec.inner.not = icmp slt i64 %k, 16
+  br i1 %ec.inner.not, label %inner, label %outer.latch
+
+outer.latch:
+  %i.next = add i64 %i, 1
+  %cmp.i = icmp slt i64 %i.next, 8
+  br i1 %cmp.i, label %outer.header, label %exit
+
+exit:
+  ret void
+}
+
+; for (i = 0; i < 6; i++)
+;   for (j = 0, k = 0; j < 30; j++, k += i)
+;     A[i][j] = k;
+;
+; FIXME: This is now interchanged.
+;
+define void @step_ok_k_is_i_1(ptr %A) {
+; CHECK-LABEL: define void @step_ok_k_is_i_1(
+; CHECK-SAME: ptr [[A:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    br label %[[OUTER_HEADER:.*]]
+; CHECK:       [[OUTER_HEADER_PREHEADER:.*]]:
+; CHECK-NEXT:    br label %[[INNER:.*]]
+; CHECK:       [[INNER]]:
+; CHECK-NEXT:    [[I:%.*]] = phi i64 [ [[I_NEXT:%.*]], %[[OUTER_LATCH:.*]] ], [ 0, %[[OUTER_HEADER_PREHEADER]] ]
+; CHECK-NEXT:    br label %[[INNER_SPLIT1:.*]]
+; CHECK:       [[OUTER_HEADER]]:
+; CHECK-NEXT:    br label %[[INNER1:.*]]
+; CHECK:       [[INNER1]]:
+; CHECK-NEXT:    [[J:%.*]] = phi i64 [ [[TMP1:%.*]], %[[INNER_SPLIT:.*]] ], [ 0, %[[OUTER_HEADER]] ]
+; CHECK-NEXT:    [[K:%.*]] = phi i64 [ [[TMP0:%.*]], %[[INNER_SPLIT]] ], [ 0, %[[OUTER_HEADER]] ]
+; CHECK-NEXT:    br label %[[OUTER_HEADER_PREHEADER]]
+; CHECK:       [[INNER_SPLIT1]]:
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds [40 x i64], ptr [[A]], i64 [[I]], i64 [[J]]
+; CHECK-NEXT:    store i64 [[K]], ptr [[GEP]], align 4
+; CHECK-NEXT:    [[J_NEXT:%.*]] = add i64 [[J]], 1
+; CHECK-NEXT:    [[K_NEXT:%.*]] = add i64 [[K]], [[I]]
+; CHECK-NEXT:    [[EC_INNER:%.*]] = icmp eq i64 [[J]], 30
+; CHECK-NEXT:    br label %[[OUTER_LATCH]]
+; CHECK:       [[INNER_SPLIT]]:
+; CHECK-NEXT:    [[I_LCSSA:%.*]] = phi i64 [ [[I]], %[[OUTER_LATCH]] ]
+; CHECK-NEXT:    [[TMP0]] = add i64 [[K]], [[I_LCSSA]]
+; CHECK-NEXT:    [[TMP1]] = add i64 [[J]], 1
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i64 [[J]], 30
+; CHECK-NEXT:    br i1 [[TMP2]], label %[[EXIT:.*]], label %[[INNER1]]
+; CHECK:       [[OUTER_LATCH]]:
+; CHECK-NEXT:    [[I_NEXT]] = add i64 [[I]], 1
+; CHECK-NEXT:    [[EC_I:%.*]] = icmp eq i64 [[I_NEXT]], 6
+; CHECK-NEXT:    br i1 [[EC_I]], label %[[INNER_SPLIT]], label %[[INNER]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %outer.header
+
+outer.header:
+  %i = phi i64 [ 0, %entry ], [ %i.next, %outer.latch ]
+  br label %inner
+
+inner:
+  %j = phi i64 [ 0, %outer.header ], [ %j.next, %inner ]
+  %k = phi i64 [ 0, %outer.header ], [ %k.next, %inner ]
+  %gep = getelementptr inbounds [40 x i64], ptr %A, i64 %i, i64 %j
+  store i64 %k, ptr %gep
+  %j.next = add i64 %j, 1
+  %k.next = add i64 %k, %i
+  %ec.inner = icmp eq i64 %j, 30
+  br i1 %ec.inner, label %outer.latch, label %inner
+
+outer.latch:
+  %i.next = add i64 %i, 1
+  %ec.i = icmp eq i64 %i.next, 6
+  br i1 %ec.i, label %exit, label %outer.header
+
+exit:
+  ret void
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/202750


More information about the llvm-commits mailing list