Skip to content

Commit a6e47d1

Browse files
authored
[MLIR][Affine] Fix affine loop permute validity check for iter_args loops (llvm#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. Signed-off-by: Prathamesh Tagore <[email protected]>
1 parent 7681855 commit a6e47d1

File tree

3 files changed

+50
-0
lines changed

3 files changed

+50
-0
lines changed

mlir/lib/Dialect/Affine/Utils/LoopUtils.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1339,6 +1339,15 @@ bool mlir::affine::isValidLoopInterchangePermutation(
13391339
unsigned maxLoopDepth = loops.size();
13401340
if (maxLoopDepth == 1)
13411341
return true;
1342+
1343+
// We cannot guarantee the validity of the interchange if the loops have
1344+
// iter_args, since the dependence analysis does not take them into account.
1345+
// Conservatively return false in such cases.
1346+
if (llvm::any_of(loops, [](AffineForOp loop) {
1347+
return loop.getNumIterOperands() > 0;
1348+
}))
1349+
return false;
1350+
13421351
// Gather dependence components for dependences between all ops in loop nest
13431352
// rooted at 'loops[0]', at loop depths in range [1, maxLoopDepth].
13441353
std::vector<SmallVector<DependenceComponent, 2>> depCompsVec;

mlir/test/Dialect/Affine/loop-permute.mlir

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// RUN: mlir-opt -allow-unregistered-dialect %s -test-loop-permutation="permutation-map=0,2,1" | FileCheck %s --check-prefix=CHECK-021
55
// RUN: mlir-opt -allow-unregistered-dialect %s -test-loop-permutation="permutation-map=2,0,1" | FileCheck %s --check-prefix=CHECK-201
66
// RUN: mlir-opt -allow-unregistered-dialect %s -test-loop-permutation="permutation-map=2,1,0" | FileCheck %s --check-prefix=CHECK-210
7+
// 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
78

89
// CHECK-120-LABEL: func @permute
910
func.func @permute(%U0 : index, %U1 : index, %U2 : index) {
@@ -45,3 +46,34 @@ func.func @permute(%U0 : index, %U1 : index, %U2 : index) {
4546

4647
// CHECK-201: "foo"(%arg5, %arg3)
4748
// CHECK-201-NEXT: "bar"(%arg4)
49+
50+
// -----
51+
52+
// Tests that the permutation validation check utility conservatively returns false when the
53+
// for loop has an iter_arg.
54+
55+
// CHECK-210-VALID-LABEL: func @check_validity_with_iter_args
56+
// CHECK-210-VALID-SAME: %[[ARG0:.*]]: index, %[[ARG1:.*]]: index, %[[ARG2:.*]]: index
57+
func.func @check_validity_with_iter_args(%U0 : index, %U1 : index, %U2 : index) {
58+
%buf = memref.alloc() : memref<100x100xf32>
59+
%cst = arith.constant 1.0 : f32
60+
%c10 = arith.constant 10 : index
61+
%c20 = arith.constant 20 : index
62+
63+
// Check that the loops are not permuted.
64+
// CHECK-210-VALID: affine.for %{{.*}} = 0 to %[[ARG0]] {
65+
// CHECK-210-VALID-NEXT: affine.for %{{.*}} = 0 to %[[ARG1]] {
66+
// CHECK-210-VALID-NEXT: affine.for %{{.*}} = 0 to %[[ARG2]] iter_args(
67+
affine.for %arg0 = 0 to %U0 {
68+
affine.for %arg1 = 0 to %U1 {
69+
%res = affine.for %arg2 = 0 to %U2 iter_args(%iter1 = %cst) -> (f32) {
70+
%val = affine.load %buf[%arg0 + 10, %arg1 + 20] : memref<100x100xf32>
71+
%newVal = arith.addf %val, %cst : f32
72+
affine.store %newVal, %buf[%arg0 + 10, %arg1 + 20] : memref<100x100xf32>
73+
%newVal2 = arith.addf %newVal, %iter1 : f32
74+
affine.yield %iter1 : f32
75+
}
76+
}
77+
}
78+
return
79+
}

mlir/test/lib/Dialect/Affine/TestLoopPermutation.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ struct TestLoopPermutation
4242
ListOption<unsigned> permList{*this, "permutation-map",
4343
llvm::cl::desc("Specify the loop permutation"),
4444
llvm::cl::OneOrMore};
45+
46+
/// Specify whether to check validity of loop permutation.
47+
Option<bool> checkValidity{
48+
*this, "check-validity",
49+
llvm::cl::desc("Check validity of the loop permutation"),
50+
llvm::cl::init(false)};
4551
};
4652

4753
} // namespace
@@ -60,6 +66,9 @@ void TestLoopPermutation::runOnOperation() {
6066
// Permute if the nest's size is consistent with the specified
6167
// permutation.
6268
if (nest.size() >= 2 && nest.size() == permMap.size()) {
69+
if (checkValidity.getValue() &&
70+
!isValidLoopInterchangePermutation(nest, permMap))
71+
continue;
6372
permuteLoops(nest, permMap);
6473
}
6574
}

0 commit comments

Comments
 (0)