[Mlir-commits] [mlir] 91c0ba6 - [OpenACC] Fix pattern API check failures in acc-loop-tiling pass (#188968)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Mon Apr 13 03:20:59 PDT 2026


Author: Mehdi Amini
Date: 2026-04-13T12:20:55+02:00
New Revision: 91c0ba6de8e742fc92bf166f508157c6fe8b9df4

URL: https://github.com/llvm/llvm-project/commit/91c0ba6de8e742fc92bf166f508157c6fe8b9df4
DIFF: https://github.com/llvm/llvm-project/commit/91c0ba6de8e742fc92bf166f508157c6fe8b9df4.diff

LOG: [OpenACC] Fix pattern API check failures in acc-loop-tiling pass (#188968)

Two bugs were introduced/revealed by
MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS:

1. `ACCLoopTilingImpl::matchAndRewrite` returned `success()` for loops
with no tile values, triggering "pattern returned success but IR did not
change". Fixed by returning `failure()` instead.

2. `moveOpsAndReplaceIVs` moved ops between blocks via `splice()` and
updated operands via `replaceAllUsesInRegionWith()` without notifying
the rewriter. This caused "operation fingerprint changed" errors since
the moved ops' parent op and operands changed without
`startOpModification`/ `finalizeOpModification`. Fixed by wrapping all
moved ops (and their nested ops) with rewriter modification
notifications.

Assisted-by: Claude Code

Added: 
    

Modified: 
    mlir/lib/Dialect/OpenACC/Transforms/ACCLoopTiling.cpp
    mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsTiling.cpp
    mlir/test/Dialect/OpenACC/acc-loop-tiling.mlir

Removed: 
    


################################################################################
diff  --git a/mlir/lib/Dialect/OpenACC/Transforms/ACCLoopTiling.cpp b/mlir/lib/Dialect/OpenACC/Transforms/ACCLoopTiling.cpp
index 495d0247d86d3..6bc95ca896f37 100644
--- a/mlir/lib/Dialect/OpenACC/Transforms/ACCLoopTiling.cpp
+++ b/mlir/lib/Dialect/OpenACC/Transforms/ACCLoopTiling.cpp
@@ -158,7 +158,7 @@ struct ACCLoopTilingImpl : public OpRewritePattern<acc::LoopOp> {
                                 PatternRewriter &rewriter) const override {
 
     if (origLoop.getTileValues().empty())
-      return success();
+      return failure();
 
     SmallVector<Value> tileSizes(origLoop.getTileValues().begin(),
                                  origLoop.getTileValues().end());

diff  --git a/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsTiling.cpp b/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsTiling.cpp
index c39bd06c81cbf..dddaebdee5ebc 100644
--- a/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsTiling.cpp
+++ b/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsTiling.cpp
@@ -121,15 +121,32 @@ static void moveOpsAndReplaceIVs(mlir::acc::LoopOp sourceLoop,
                                  llvm::ArrayRef<mlir::Value> newIVs,
                                  llvm::ArrayRef<mlir::Value> origIVs,
                                  size_t nOps, mlir::RewriterBase &rewriter) {
-  // Move ops from source to target loop [begin, begin + nOps - 1)
+  // nOps includes the terminator; move all ops except the terminator:
+  // [begin, begin + nOps - 1)
   mlir::Block::iterator begin = sourceLoop.getBody().begin();
+  mlir::Block::iterator end = std::next(begin, nOps - 1);
+
+  // Notify the rewriter about all ops being moved (and their nested ops).
+  // Directly moved ops have their parent block changed (rewriter fingerprint
+  // tracking invalidated). Nested ops may have operands replaced by
+  // replaceAllUsesInRegionWith below.
+  llvm::SmallVector<mlir::Operation *> movedOps;
+  for (mlir::Block::iterator it = begin; it != end; ++it)
+    it->walk([&](mlir::Operation *op) {
+      movedOps.push_back(op);
+      rewriter.startOpModification(op);
+    });
+
   targetLoop.getBody().getOperations().splice(
       targetLoop.getBody().getOperations().begin(),
-      sourceLoop.getBody().getOperations(), begin, std::next(begin, nOps - 1));
+      sourceLoop.getBody().getOperations(), begin, end);
 
   // Replace uses of origIV with newIV
   for (auto [i, newIV] : llvm::enumerate(newIVs))
     mlir::replaceAllUsesInRegionWith(origIVs[i], newIV, targetLoop.getRegion());
+
+  for (mlir::Operation *op : movedOps)
+    rewriter.finalizeOpModification(op);
 }
 
 mlir::acc::LoopOp

diff  --git a/mlir/test/Dialect/OpenACC/acc-loop-tiling.mlir b/mlir/test/Dialect/OpenACC/acc-loop-tiling.mlir
index f4a46186b118d..cd13b3d8427f0 100644
--- a/mlir/test/Dialect/OpenACC/acc-loop-tiling.mlir
+++ b/mlir/test/Dialect/OpenACC/acc-loop-tiling.mlir
@@ -102,3 +102,54 @@ func.func @unknown_tile_size(%arg0: memref<1000xf32>) {
   } attributes {independent = [#acc.device_type<none>]}
   return
 }
+
+// Test loop with no tile values: pattern should not apply and loop is unchanged.
+
+// CHECK-LABEL: func.func @no_tile_values
+// CHECK:         acc.loop control(%{{.*}} : index) = (%{{.*}} : index) to (%{{.*}} : index) step (%{{.*}} : index) {
+// CHECK-NOT:       acc.loop
+// CHECK:           acc.yield
+// CHECK:         }
+func.func @no_tile_values() {
+  %c0 = arith.constant 0 : index
+  %c10 = arith.constant 10 : index
+  %c1 = arith.constant 1 : index
+  acc.loop control(%i : index) = (%c0 : index) to (%c10 : index) step (%c1 : index) {
+    acc.yield
+  } attributes {independent = [#acc.device_type<none>]}
+  return
+}
+
+// Test loop tiling when the body contains ops with nested regions.
+// Exercises the walk() in moveOpsAndReplaceIVs that must notify the rewriter
+// about nested ops (required by MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS).
+
+// CHECK-LABEL: func.func @body_with_nested_region
+// CHECK:         acc.loop control(%[[TILE_IV:.*]] : index) = ({{.*}}) to ({{.*}}) step ({{.*}}) {
+// CHECK:           acc.loop control(%[[ELEM_IV:.*]] : index) = ({{.*}}) to ({{.*}}) step ({{.*}}) {
+// CHECK:             scf.if
+// CHECK:               arith.index_castui %[[ELEM_IV]]
+// CHECK:             acc.yield
+// CHECK:           }
+// CHECK:           acc.yield
+// CHECK:         }
+func.func @body_with_nested_region(%arg0: memref<10xi32>) {
+  %c0 = arith.constant 0 : index
+  %c10 = arith.constant 10 : index
+  %c1 = arith.constant 1 : index
+  %c2 = arith.constant 2 : index
+  acc.loop tile({%c2 : index}) control(%i : index) = (%c0 : index) to (%c10 : index) step (%c1 : index) {
+    %threshold = arith.constant 5 : index
+    %cond = arith.cmpi ult, %i, %threshold : index
+    %val = scf.if %cond -> (i32) {
+      %cast = arith.index_castui %i : index to i32
+      scf.yield %cast : i32
+    } else {
+      %c99 = arith.constant 99 : i32
+      scf.yield %c99 : i32
+    }
+    memref.store %val, %arg0[%i] : memref<10xi32>
+    acc.yield
+  } attributes {independent = [#acc.device_type<none>]}
+  return
+}


        


More information about the Mlir-commits mailing list