1 //===- TestAffineDataCopy.cpp - Test affine data copy utility -------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file implements a pass to test affine data copy utility functions and
12 //===----------------------------------------------------------------------===//
14 #include "mlir/Dialect/Affine/Analysis/Utils.h"
15 #include "mlir/Dialect/Affine/IR/AffineOps.h"
16 #include "mlir/Dialect/Affine/LoopUtils.h"
17 #include "mlir/Dialect/Func/IR/FuncOps.h"
18 #include "mlir/Dialect/MemRef/IR/MemRef.h"
19 #include "mlir/Pass/Pass.h"
20 #include "mlir/Transforms/GreedyPatternRewriteDriver.h"
21 #include "mlir/Transforms/Passes.h"
23 #define PASS_NAME "test-affine-data-copy"
26 using namespace mlir::affine
;
30 struct TestAffineDataCopy
31 : public PassWrapper
<TestAffineDataCopy
, OperationPass
<func::FuncOp
>> {
32 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestAffineDataCopy
)
34 StringRef
getArgument() const final
{ return PASS_NAME
; }
35 StringRef
getDescription() const final
{
36 return "Tests affine data copy utility functions.";
38 TestAffineDataCopy() = default;
39 TestAffineDataCopy(const TestAffineDataCopy
&pass
) : PassWrapper(pass
){};
41 void getDependentDialects(DialectRegistry
®istry
) const override
{
42 registry
.insert
<memref::MemRefDialect
>();
44 void runOnOperation() override
;
47 Option
<bool> clMemRefFilter
{
48 *this, "memref-filter",
50 "Enable memref filter testing in affine data copy optimization"),
51 llvm::cl::init(false)};
52 Option
<bool> clTestGenerateCopyForMemRegion
{
53 *this, "for-memref-region",
54 llvm::cl::desc("Test copy generation for a single memref region"),
55 llvm::cl::init(false)};
60 void TestAffineDataCopy::runOnOperation() {
61 // Gather all AffineForOps by loop depth.
62 std::vector
<SmallVector
<AffineForOp
, 2>> depthToLoops
;
63 gatherLoops(getOperation(), depthToLoops
);
64 if (depthToLoops
.empty())
67 // Only support tests with a single loop nest and a single innermost loop
69 unsigned innermostLoopIdx
= depthToLoops
.size() - 1;
70 if (depthToLoops
[0].size() != 1 || depthToLoops
[innermostLoopIdx
].size() != 1)
73 auto loopNest
= depthToLoops
[0][0];
74 auto innermostLoop
= depthToLoops
[innermostLoopIdx
][0];
76 if (clMemRefFilter
|| clTestGenerateCopyForMemRegion
) {
77 // Gather MemRef filter. For simplicity, we use the first loaded memref
78 // found in the innermost loop.
79 for (auto &op
: *innermostLoop
.getBody()) {
80 if (auto ld
= dyn_cast
<AffineLoadOp
>(op
)) {
89 AffineCopyOptions copyOptions
= {/*generateDma=*/false,
90 /*slowMemorySpace=*/0,
91 /*fastMemorySpace=*/0,
93 /*fastMemCapacityBytes=*/32 * 1024 * 1024UL};
94 DenseSet
<Operation
*> copyNests
;
96 if (failed(affineDataCopyGenerate(loopNest
, copyOptions
, load
.getMemRef(),
99 } else if (clTestGenerateCopyForMemRegion
) {
100 CopyGenerateResult result
;
101 MemRefRegion
region(loopNest
.getLoc());
102 if (failed(region
.compute(load
, /*loopDepth=*/0)))
104 if (failed(generateCopyForMemRegion(region
, loopNest
, copyOptions
, result
)))
108 // Promote any single iteration loops in the copy nests and simplify
110 SmallVector
<Operation
*, 4> copyOps
;
111 for (Operation
*nest
: copyNests
) {
112 // With a post order walk, the erasure of loops does not affect
113 // continuation of the walk or the collection of load/store ops.
114 nest
->walk([&](Operation
*op
) {
115 if (auto forOp
= dyn_cast
<AffineForOp
>(op
))
116 (void)promoteIfSingleIteration(forOp
);
117 else if (auto loadOp
= dyn_cast
<AffineLoadOp
>(op
))
118 copyOps
.push_back(loadOp
);
119 else if (auto storeOp
= dyn_cast
<AffineStoreOp
>(op
))
120 copyOps
.push_back(storeOp
);
124 // Promoting single iteration loops could lead to simplification of
125 // generated load's/store's, and the latter could anyway also be
127 RewritePatternSet
patterns(&getContext());
128 for (Operation
*op
: copyOps
) {
130 if (isa
<AffineLoadOp
>(op
)) {
131 AffineLoadOp::getCanonicalizationPatterns(patterns
, &getContext());
133 assert(isa
<AffineStoreOp
>(op
) && "expected affine store op");
134 AffineStoreOp::getCanonicalizationPatterns(patterns
, &getContext());
137 GreedyRewriteConfig config
;
138 config
.strictMode
= GreedyRewriteStrictness::ExistingAndNewOps
;
139 (void)applyOpPatternsAndFold(copyOps
, std::move(patterns
), config
);
143 void registerTestAffineDataCopyPass() {
144 PassRegistration
<TestAffineDataCopy
>();