[Mlir-commits] [mlir] fe04aaf - [MLIR][Affine] NFC. Expose affine loop tiling validity utility (#99459)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Thu Jul 18 09:36:48 PDT 2024
Author: Uday Bondhugula
Date: 2024-07-18T22:06:44+05:30
New Revision: fe04aafe6c27f32ad4ba38e552d06d14431cb2de
URL: https://github.com/llvm/llvm-project/commit/fe04aafe6c27f32ad4ba38e552d06d14431cb2de
DIFF: https://github.com/llvm/llvm-project/commit/fe04aafe6c27f32ad4ba38e552d06d14431cb2de.diff
LOG: [MLIR][Affine] NFC. Expose affine loop tiling validity utility (#99459)
Move the utility to check for the validity of tiling affine loop nests
to affine loop utils and expose for users outside the loop tiling pass
or downstream users.
Added:
Modified:
mlir/include/mlir/Dialect/Affine/Analysis/LoopAnalysis.h
mlir/lib/Dialect/Affine/Analysis/LoopAnalysis.cpp
mlir/lib/Dialect/Affine/Transforms/LoopTiling.cpp
mlir/test/Dialect/Affine/loop-tiling-validity.mlir
Removed:
################################################################################
diff --git a/mlir/include/mlir/Dialect/Affine/Analysis/LoopAnalysis.h b/mlir/include/mlir/Dialect/Affine/Analysis/LoopAnalysis.h
index 7b92b930fb5f5..ed3c21d952a01 100644
--- a/mlir/include/mlir/Dialect/Affine/Analysis/LoopAnalysis.h
+++ b/mlir/include/mlir/Dialect/Affine/Analysis/LoopAnalysis.h
@@ -109,6 +109,16 @@ bool isVectorizableLoopBody(AffineForOp loop, int *memRefDim,
// the support.
bool isOpwiseShiftValid(AffineForOp forOp, ArrayRef<uint64_t> shifts);
+/// Checks whether hyper-rectangular loop tiling of the nest represented by
+/// `loops` is valid. The validity condition is from Irigoin and Triolet,
+/// which states that two tiles cannot depend on each other. We simplify such
+/// condition to just checking whether there is any negative dependence
+/// direction, since we have the prior knowledge that the tiling results will be
+/// hyper-rectangles, which are scheduled in the lexicographically increasing
+/// order on the vector of loop indices. This function will return failure when
+/// any dependence component is negative along any of `loops`.
+bool isTilingValid(ArrayRef<AffineForOp> loops);
+
} // namespace affine
} // namespace mlir
diff --git a/mlir/lib/Dialect/Affine/Analysis/LoopAnalysis.cpp b/mlir/lib/Dialect/Affine/Analysis/LoopAnalysis.cpp
index 82ba8fc5ccbc1..411b5efb36cab 100644
--- a/mlir/lib/Dialect/Affine/Analysis/LoopAnalysis.cpp
+++ b/mlir/lib/Dialect/Affine/Analysis/LoopAnalysis.cpp
@@ -23,6 +23,7 @@
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Debug.h"
#include <numeric>
#include <optional>
#include <type_traits>
@@ -30,6 +31,8 @@
using namespace mlir;
using namespace mlir::affine;
+#define DEBUG_TYPE "affine-loop-analysis"
+
/// Returns the trip count of the loop as an affine expression if the latter is
/// expressible as an affine expression, and nullptr otherwise. The trip count
/// expression is simplified before returning. This method only utilizes map
@@ -390,3 +393,58 @@ bool mlir::affine::isOpwiseShiftValid(AffineForOp forOp,
}
return true;
}
+
+bool mlir::affine::isTilingValid(ArrayRef<AffineForOp> loops) {
+ assert(!loops.empty() && "no original loops provided");
+
+ // We first find out all dependences we intend to check.
+ SmallVector<Operation *, 8> loadAndStoreOps;
+ loops[0]->walk([&](Operation *op) {
+ if (isa<AffineReadOpInterface, AffineWriteOpInterface>(op))
+ loadAndStoreOps.push_back(op);
+ });
+
+ unsigned numOps = loadAndStoreOps.size();
+ unsigned numLoops = loops.size();
+ for (unsigned d = 1; d <= numLoops + 1; ++d) {
+ for (unsigned i = 0; i < numOps; ++i) {
+ Operation *srcOp = loadAndStoreOps[i];
+ MemRefAccess srcAccess(srcOp);
+ for (unsigned j = 0; j < numOps; ++j) {
+ Operation *dstOp = loadAndStoreOps[j];
+ MemRefAccess dstAccess(dstOp);
+
+ SmallVector<DependenceComponent, 2> depComps;
+ DependenceResult result = checkMemrefAccessDependence(
+ srcAccess, dstAccess, d, /*dependenceConstraints=*/nullptr,
+ &depComps);
+
+ // Skip if there is no dependence in this case.
+ if (!hasDependence(result))
+ continue;
+
+ // Check whether there is any negative direction vector in the
+ // dependence components found above, which means that dependence is
+ // violated by the default hyper-rect tiling method.
+ LLVM_DEBUG(llvm::dbgs() << "Checking whether tiling legality violated "
+ "for dependence at depth: "
+ << Twine(d) << " between:\n";);
+ LLVM_DEBUG(srcAccess.opInst->dump());
+ LLVM_DEBUG(dstAccess.opInst->dump());
+ for (const DependenceComponent &depComp : depComps) {
+ if (depComp.lb.has_value() && depComp.ub.has_value() &&
+ *depComp.lb < *depComp.ub && *depComp.ub < 0) {
+ LLVM_DEBUG(llvm::dbgs()
+ << "Dependence component lb = " << Twine(*depComp.lb)
+ << " ub = " << Twine(*depComp.ub)
+ << " is negative at depth: " << Twine(d)
+ << " and thus violates the legality rule.\n");
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
diff --git a/mlir/lib/Dialect/Affine/Transforms/LoopTiling.cpp b/mlir/lib/Dialect/Affine/Transforms/LoopTiling.cpp
index 2650a06d198ea..c8400dfe8cd5c 100644
--- a/mlir/lib/Dialect/Affine/Transforms/LoopTiling.cpp
+++ b/mlir/lib/Dialect/Affine/Transforms/LoopTiling.cpp
@@ -93,69 +93,6 @@ static void adjustToDivisorsOfTripCounts(ArrayRef<AffineForOp> band,
}
}
-/// Checks whether hyper-rectangular loop tiling of the nest represented by
-/// `origLoops` is valid. The validity condition is from Irigoin and Triolet,
-/// which states that two tiles cannot depend on each other. We simplify such
-/// condition to just checking whether there is any negative dependence
-/// direction, since we have the prior knowledge that the tiling results will be
-/// hyper-rectangles, which are scheduled in the lexicographically increasing
-/// order on the vector of loop indices. This function will return failure when
-/// any dependence component is negative along any of `origLoops`.
-static bool checkTilingLegality(MutableArrayRef<AffineForOp> origLoops) {
- assert(!origLoops.empty() && "no original loops provided");
-
- // We first find out all dependences we intend to check.
- SmallVector<Operation *, 8> loadAndStoreOps;
- origLoops[0]->walk([&](Operation *op) {
- if (isa<AffineReadOpInterface, AffineWriteOpInterface>(op))
- loadAndStoreOps.push_back(op);
- });
-
- unsigned numOps = loadAndStoreOps.size();
- unsigned numLoops = origLoops.size();
- for (unsigned d = 1; d <= numLoops + 1; ++d) {
- for (unsigned i = 0; i < numOps; ++i) {
- Operation *srcOp = loadAndStoreOps[i];
- MemRefAccess srcAccess(srcOp);
- for (unsigned j = 0; j < numOps; ++j) {
- Operation *dstOp = loadAndStoreOps[j];
- MemRefAccess dstAccess(dstOp);
-
- SmallVector<DependenceComponent, 2> depComps;
- DependenceResult result = checkMemrefAccessDependence(
- srcAccess, dstAccess, d, /*dependenceConstraints=*/nullptr,
- &depComps);
-
- // Skip if there is no dependence in this case.
- if (!hasDependence(result))
- continue;
-
- // Check whether there is any negative direction vector in the
- // dependence components found above, which means that dependence is
- // violated by the default hyper-rect tiling method.
- LLVM_DEBUG(llvm::dbgs() << "Checking whether tiling legality violated "
- "for dependence at depth: "
- << Twine(d) << " between:\n";);
- LLVM_DEBUG(srcAccess.opInst->dump(););
- LLVM_DEBUG(dstAccess.opInst->dump(););
- for (const DependenceComponent &depComp : depComps) {
- if (depComp.lb.has_value() && depComp.ub.has_value() &&
- *depComp.lb < *depComp.ub && *depComp.ub < 0) {
- LLVM_DEBUG(llvm::dbgs()
- << "Dependence component lb = " << Twine(*depComp.lb)
- << " ub = " << Twine(*depComp.ub)
- << " is negative at depth: " << Twine(d)
- << " and thus violates the legality rule.\n");
- return false;
- }
- }
- }
- }
- }
-
- return true;
-}
-
// Returns tile sizes to use. Checks CL options; if none are specified, sets it
// based on a simple model that looks at the memory footprint and determines
// tile sizes assuming identity accesses / 1:1 tile size proportional footprint
@@ -242,8 +179,8 @@ void LoopTiling::runOnOperation() {
// Tile each band.
for (auto &band : bands) {
- if (!checkTilingLegality(band)) {
- band.front().emitRemark("tiling code is illegal due to dependences");
+ if (!isTilingValid(band)) {
+ band.front().emitRemark("tiling nest is invalid due to dependences");
continue;
}
diff --git a/mlir/test/Dialect/Affine/loop-tiling-validity.mlir b/mlir/test/Dialect/Affine/loop-tiling-validity.mlir
index d1b80520ca7fe..e2c3832f695cc 100644
--- a/mlir/test/Dialect/Affine/loop-tiling-validity.mlir
+++ b/mlir/test/Dialect/Affine/loop-tiling-validity.mlir
@@ -34,7 +34,7 @@ func.func @illegal_loop_with_diag_dependence() {
%A = memref.alloc() : memref<64x64xf32>
affine.for %i = 0 to 64 {
- // expected-remark at above {{tiling code is illegal due to dependences}}
+ // expected-remark at above {{tiling nest is invalid due to dependences}}
affine.for %j = 0 to 64 {
%0 = affine.load %A[%j, %i] : memref<64x64xf32>
%1 = affine.load %A[%i, %j - 1] : memref<64x64xf32>
More information about the Mlir-commits
mailing list