[Mlir-commits] [mlir] [mlir][loopPermuteValid] Conservatively return false for iter_args loops (PR #155077)
Prathamesh Tagore
llvmlistbot at llvm.org
Fri Aug 22 22:34:29 PDT 2025
https://github.com/meshtag created https://github.com/llvm/llvm-project/pull/155077
We cannot guarantee the validity of the interchange if the loops have iter_args, since the dependence analysis does not take them into account. Conservatively return false in such cases.
Add an option to check permutation validity in test-loop-permutation pass to test this change.
>From e489670a06318f4402d00466ad324cc17713c302 Mon Sep 17 00:00:00 2001
From: Prathamesh Tagore <prathamesh+1 at polymagelabs.com>
Date: Sat, 23 Aug 2025 10:53:37 +0530
Subject: [PATCH] [mlir][loopPermuteValid] Conservatively return false for
iter_args loops
We cannot guarantee the validity of the interchange if the loops have
iter_args, since the dependence analysis does not take them into account.
Conservatively return false in such cases.
Add an option to check permutation validity in test-loop-permutation pass to
test this change.
Signed-off-by: Prathamesh Tagore <prathamesh+1 at polymagelabs.com>
---
mlir/lib/Dialect/Affine/Utils/LoopUtils.cpp | 9 ++++++
mlir/test/Dialect/Affine/loop-permute.mlir | 32 +++++++++++++++++++
.../Dialect/Affine/TestLoopPermutation.cpp | 9 ++++++
3 files changed, 50 insertions(+)
diff --git a/mlir/lib/Dialect/Affine/Utils/LoopUtils.cpp b/mlir/lib/Dialect/Affine/Utils/LoopUtils.cpp
index 2de057d1d0758..4063740a9acd1 100644
--- a/mlir/lib/Dialect/Affine/Utils/LoopUtils.cpp
+++ b/mlir/lib/Dialect/Affine/Utils/LoopUtils.cpp
@@ -1339,6 +1339,15 @@ bool mlir::affine::isValidLoopInterchangePermutation(
unsigned maxLoopDepth = loops.size();
if (maxLoopDepth == 1)
return true;
+
+ // We cannot guarantee the validity of the interchange if the loops have
+ // iter_args, since the dependence analysis does not take them into account.
+ // Conservatively return false in such cases.
+ if (llvm::any_of(loops, [](AffineForOp loop) {
+ return loop.getNumIterOperands() > 0;
+ }))
+ return false;
+
// Gather dependence components for dependences between all ops in loop nest
// rooted at 'loops[0]', at loop depths in range [1, maxLoopDepth].
std::vector<SmallVector<DependenceComponent, 2>> depCompsVec;
diff --git a/mlir/test/Dialect/Affine/loop-permute.mlir b/mlir/test/Dialect/Affine/loop-permute.mlir
index 118165b2fb2a2..e38aeb543fceb 100644
--- a/mlir/test/Dialect/Affine/loop-permute.mlir
+++ b/mlir/test/Dialect/Affine/loop-permute.mlir
@@ -4,6 +4,7 @@
// RUN: mlir-opt -allow-unregistered-dialect %s -test-loop-permutation="permutation-map=0,2,1" | FileCheck %s --check-prefix=CHECK-021
// RUN: mlir-opt -allow-unregistered-dialect %s -test-loop-permutation="permutation-map=2,0,1" | FileCheck %s --check-prefix=CHECK-201
// RUN: mlir-opt -allow-unregistered-dialect %s -test-loop-permutation="permutation-map=2,1,0" | FileCheck %s --check-prefix=CHECK-210
+// RUN: mlir-opt -allow-unregistered-dialect %s -test-loop-permutation="permutation-map=2,1,0 check-validity=1" | FileCheck %s --check-prefix=CHECK-210-VALID
// CHECK-120-LABEL: func @permute
func.func @permute(%U0 : index, %U1 : index, %U2 : index) {
@@ -45,3 +46,34 @@ func.func @permute(%U0 : index, %U1 : index, %U2 : index) {
// CHECK-201: "foo"(%arg5, %arg3)
// CHECK-201-NEXT: "bar"(%arg4)
+
+// -----
+
+// Tests that the permutation validation check utility conservatively returns false when the
+// for loop has an iter_arg.
+
+// CHECK-210-VALID-LABEL: func @check_validity_with_iter_args
+// CHECK-210-VALID-SAME: %[[ARG0:.*]]: index, %[[ARG1:.*]]: index, %[[ARG2:.*]]: index
+func.func @check_validity_with_iter_args(%U0 : index, %U1 : index, %U2 : index) {
+ %buf = memref.alloc() : memref<100x100xf32>
+ %cst = arith.constant 1.0 : f32
+ %c10 = arith.constant 10 : index
+ %c20 = arith.constant 20 : index
+
+ // Check that the loops are not permuted.
+ // CHECK-210-VALID: affine.for %{{.*}} = 0 to %[[ARG0]] {
+ // CHECK-210-VALID-NEXT: affine.for %{{.*}} = 0 to %[[ARG1]] {
+ // CHECK-210-VALID-NEXT: affine.for %{{.*}} = 0 to %[[ARG2]] iter_args(
+ affine.for %arg0 = 0 to %U0 {
+ affine.for %arg1 = 0 to %U1 {
+ %res = affine.for %arg2 = 0 to %U2 iter_args(%iter1 = %cst) -> (f32) {
+ %val = affine.load %buf[%arg0 + 10, %arg1 + 20] : memref<100x100xf32>
+ %newVal = arith.addf %val, %cst : f32
+ affine.store %newVal, %buf[%arg0 + 10, %arg1 + 20] : memref<100x100xf32>
+ %newVal2 = arith.addf %newVal, %iter1 : f32
+ affine.yield %iter1 : f32
+ }
+ }
+ }
+ return
+}
diff --git a/mlir/test/lib/Dialect/Affine/TestLoopPermutation.cpp b/mlir/test/lib/Dialect/Affine/TestLoopPermutation.cpp
index e708b7de690ec..8bab9a0ef55b8 100644
--- a/mlir/test/lib/Dialect/Affine/TestLoopPermutation.cpp
+++ b/mlir/test/lib/Dialect/Affine/TestLoopPermutation.cpp
@@ -42,6 +42,12 @@ struct TestLoopPermutation
ListOption<unsigned> permList{*this, "permutation-map",
llvm::cl::desc("Specify the loop permutation"),
llvm::cl::OneOrMore};
+
+ /// Specify whether to check validity of loop permutation.
+ Option<bool> checkValidity{
+ *this, "check-validity",
+ llvm::cl::desc("Check validity of the loop permutation"),
+ llvm::cl::init(false)};
};
} // namespace
@@ -60,6 +66,9 @@ void TestLoopPermutation::runOnOperation() {
// Permute if the nest's size is consistent with the specified
// permutation.
if (nest.size() >= 2 && nest.size() == permMap.size()) {
+ if (checkValidity.getValue() &&
+ !isValidLoopInterchangePermutation(nest, permMap))
+ continue;
permuteLoops(nest, permMap);
}
}
More information about the Mlir-commits
mailing list