Skip to content

Commit 575d689

Browse files
[mlir][acc] Introduce acc loop tiling pass (#171692)
This pass implements the OpenACC loop tiling transformation for acc.loop operations that have the tile clause (OpenACC 3.4 spec, section 2.9.8). The tile clause specifies that the iterations of the associated loops should be divided into tiles (rectangular blocks). The pass transforms a single or nested acc.loop with tile clauses into a structure of "tile loops" (iterating over tiles) containing "element loops" (iterating within tiles). For example, tiling a 2-level nested loop with tile(T1, T2): ``` // Before tiling: acc.loop tile(T1, T2) control(%i, %j) = ... // After tiling: acc.loop control(%i) step (s1*T1) { // tile loop 1 acc.loop control(%j) step (s2*T2) { // tile loop 2 acc.loop control(%ii) = (%i) to (min(ub1, %i+s1*T1)) { acc.loop control(%jj) = (%j) to (min(ub2, %j+s2*T2)) { // loop body using %ii, %jj } } } } ``` Key features: - Handles constant tile sizes and wildcard tile sizes ('*') which use a configurable default tile size - Properly handles collapsed loops with tile counts exceeding collapse count by uncollapsing loops before tiling - Distributes gang/worker/vector attributes appropriately: gang -> tile loops, vector -> element loops - Validates that tile size types are not wider than loop IV types - Emits optimization remarks for tiling decisions Three test files are added: - acc-loop-tiling.mlir: Tests single and nested loop tiling with constant tile sizes, unknown tile sizes (*), and loops with collapse attributes - acc-loop-tiling-invalid.mlir: Tests error diagnostic when tile size type is wider than the loop IV type - acc-loop-tiling-remarks.mlir: Tests optimization remarks emitted for tiling decisions including default tile size selection Co-authored-by: Vijay Kandiah <[email protected]>
1 parent 5a1299b commit 575d689

File tree

12 files changed

+560
-15
lines changed

12 files changed

+560
-15
lines changed

mlir/include/mlir/Dialect/OpenACC/Analysis/OpenACCSupport.h

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,10 @@
5050
#ifndef MLIR_DIALECT_OPENACC_ANALYSIS_OPENACCSUPPORT_H
5151
#define MLIR_DIALECT_OPENACC_ANALYSIS_OPENACCSUPPORT_H
5252

53+
#include "mlir/IR/Remarks.h"
5354
#include "mlir/IR/Value.h"
5455
#include "mlir/Pass/AnalysisManager.h"
56+
#include "llvm/ADT/StringRef.h"
5557
#include <memory>
5658
#include <string>
5759

@@ -62,6 +64,8 @@ namespace acc {
6264
enum class RecipeKind : uint32_t;
6365
bool isValidSymbolUse(Operation *user, SymbolRefAttr symbol,
6466
Operation **definingOpPtr);
67+
remark::detail::InFlightRemark emitRemark(Operation *op, const Twine &message,
68+
llvm::StringRef category);
6569

6670
namespace detail {
6771
/// This class contains internal trait classes used by OpenACCSupport.
@@ -82,6 +86,14 @@ struct OpenACCSupportTraits {
8286
// Used to report a case that is not supported by the implementation.
8387
virtual InFlightDiagnostic emitNYI(Location loc, const Twine &message) = 0;
8488

89+
// Used to emit an OpenACC remark. The category is optional and is used to
90+
// either capture the pass name or pipeline phase when the remark is
91+
// emitted. When not provided, in the default implementation, the category
92+
// is "openacc".
93+
virtual remark::detail::InFlightRemark
94+
emitRemark(Operation *op, const Twine &message,
95+
llvm::StringRef category) = 0;
96+
8597
/// Check if a symbol use is valid for use in an OpenACC region.
8698
virtual bool isValidSymbolUse(Operation *user, SymbolRefAttr symbol,
8799
Operation **definingOpPtr) = 0;
@@ -101,13 +113,22 @@ struct OpenACCSupportTraits {
101113
Operation **>;
102114

103115
template <typename ImplT, typename... Args>
116+
104117
using isValidValueUse_t =
105118
decltype(std::declval<ImplT>().isValidValueUse(std::declval<Args>()...));
106119

107120
template <typename ImplT>
108121
using has_isValidValueUse =
109122
llvm::is_detected<isValidValueUse_t, ImplT, Value, Region &>;
110123

124+
template <typename ImplT, typename... Args>
125+
using emitRemark_t =
126+
decltype(std::declval<ImplT>().emitRemark(std::declval<Args>()...));
127+
128+
template <typename ImplT>
129+
using has_emitRemark = llvm::is_detected<emitRemark_t, ImplT, Operation *,
130+
const Twine &, llvm::StringRef>;
131+
111132
/// This class wraps a concrete OpenACCSupport implementation and forwards
112133
/// interface calls to it. This provides type erasure, allowing different
113134
/// implementation types to be used interchangeably without inheritance.
@@ -131,6 +152,15 @@ struct OpenACCSupportTraits {
131152
return impl.emitNYI(loc, message);
132153
}
133154

155+
remark::detail::InFlightRemark emitRemark(Operation *op,
156+
const Twine &message,
157+
llvm::StringRef category) final {
158+
if constexpr (has_emitRemark<ImplT>::value)
159+
return impl.emitRemark(op, message, category);
160+
else
161+
return acc::emitRemark(op, message, category);
162+
}
163+
134164
bool isValidSymbolUse(Operation *user, SymbolRefAttr symbol,
135165
Operation **definingOpPtr) final {
136166
if constexpr (has_isValidSymbolUse<ImplT>::value)
@@ -198,6 +228,17 @@ class OpenACCSupport {
198228
/// unsupported case.
199229
InFlightDiagnostic emitNYI(Location loc, const Twine &message);
200230

231+
/// Emit an OpenACC remark.
232+
///
233+
/// \param op The operation to emit the remark for.
234+
/// \param message The remark message.
235+
/// \param category Optional category for the remark. Defaults to "openacc".
236+
/// \return An in-flight remark object that can be used to append
237+
/// additional information to the remark.
238+
remark::detail::InFlightRemark
239+
emitRemark(Operation *op, const Twine &message,
240+
llvm::StringRef category = "openacc");
241+
201242
/// Check if a symbol use is valid for use in an OpenACC region.
202243
///
203244
/// \param user The operation using the symbol.

mlir/include/mlir/Dialect/OpenACC/OpenACCUtils.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
#define MLIR_DIALECT_OPENACC_OPENACCUTILS_H_
1111

1212
#include "mlir/Dialect/OpenACC/OpenACC.h"
13+
#include "mlir/IR/Remarks.h"
1314
#include "llvm/ADT/SmallVector.h"
15+
#include "llvm/ADT/StringRef.h"
1416

1517
namespace mlir {
1618
class DominanceInfo;
@@ -81,6 +83,17 @@ getDominatingDataClauses(mlir::Operation *computeConstructOp,
8183
mlir::DominanceInfo &domInfo,
8284
mlir::PostDominanceInfo &postDomInfo);
8385

86+
/// Emit an OpenACC remark for the given operation with the given message.
87+
///
88+
/// \param op The operation to emit the remark for.
89+
/// \param message The remark message.
90+
/// \param category Optional category for the remark. Defaults to "openacc".
91+
/// \return An in-flight remark object that can be used to append
92+
/// additional information to the remark.
93+
remark::detail::InFlightRemark emitRemark(mlir::Operation *op,
94+
const llvm::Twine &message,
95+
llvm::StringRef category = "openacc");
96+
8497
} // namespace acc
8598
} // namespace mlir
8699

mlir/include/mlir/Dialect/OpenACC/Transforms/Passes.td

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,4 +152,46 @@ def ACCLegalizeSerial : Pass<"acc-legalize-serial", "mlir::func::FuncOp"> {
152152
"mlir::arith::ArithDialect"];
153153
}
154154

155+
156+
def ACCLoopTiling : Pass<"acc-loop-tiling", "mlir::func::FuncOp"> {
157+
let summary = "Tile OpenACC loops with tile clauses";
158+
let description = [{
159+
This pass implements loop tiling transformations for OpenACC loops that
160+
have tile clauses. The pass transforms loops with `tile(size1, size2, ...)`
161+
clauses into tiled loop nests.
162+
163+
For a 2-level nested loop with tile(T1, T2), the transformation produces:
164+
- Outer tile loops that iterate over tiles
165+
- Inner element loops that iterate within each tile
166+
167+
Example transformation:
168+
```
169+
// Before:
170+
#pragma acc loop tile(32, 32)
171+
for (i = 0; i < N; i++)
172+
for (j = 0; j < M; j++)
173+
A[i][j] = ...
174+
175+
// After:
176+
for (i = 0; i < N; i += 32) // tile loop 1
177+
for (j = 0; j < M; j += 32) // tile loop 2
178+
for (ii = i; ii < min(N, i+32); ii++) // element loop 1
179+
for (jj = j; jj < min(M, j+32); jj++) // element loop 2
180+
A[ii][jj] = ...
181+
```
182+
183+
The pass handles:
184+
- Constant tile sizes
185+
- Wildcard tile sizes ('*') which use a default tile size
186+
- Collapsed loops with tile counts exceeding collapse count
187+
- Proper handling of loop attributes (gang, worker, vector)
188+
}];
189+
let dependentDialects = ["mlir::acc::OpenACCDialect",
190+
"mlir::arith::ArithDialect"];
191+
let options = [
192+
Option<"defaultTileSize", "default-tile-size", "int32_t", "32",
193+
"Default tile size to use for wildcard ('*') tile sizes">
194+
];
195+
}
196+
155197
#endif // MLIR_DIALECT_OPENACC_TRANSFORMS_PASSES

mlir/lib/Dialect/OpenACC/Analysis/OpenACCSupport.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ InFlightDiagnostic OpenACCSupport::emitNYI(Location loc, const Twine &message) {
4141
return mlir::emitError(loc, "not yet implemented: " + message);
4242
}
4343

44+
remark::detail::InFlightRemark
45+
OpenACCSupport::emitRemark(Operation *op, const Twine &message,
46+
llvm::StringRef category) {
47+
if (impl)
48+
return impl->emitRemark(op, message, category);
49+
return acc::emitRemark(op, message, category);
50+
}
51+
4452
bool OpenACCSupport::isValidSymbolUse(Operation *user, SymbolRefAttr symbol,
4553
Operation **definingOpPtr) {
4654
if (impl)

0 commit comments

Comments
 (0)