1 | //===- AffineParallelize.cpp - Affineparallelize Pass---------------------===// |
---|---|
2 | // |
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 |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file implements a parallelizer for affine loop nests that is able to |
10 | // perform inner or outer loop parallelization. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "mlir/Dialect/Affine/Passes.h" |
15 | |
16 | #include "mlir/Dialect/Affine/Analysis/AffineAnalysis.h" |
17 | #include "mlir/Dialect/Affine/Analysis/AffineStructures.h" |
18 | #include "mlir/Dialect/Affine/Analysis/LoopAnalysis.h" |
19 | #include "mlir/Dialect/Affine/Analysis/Utils.h" |
20 | #include "mlir/Dialect/Affine/IR/AffineOps.h" |
21 | #include "mlir/Dialect/Affine/IR/AffineValueMap.h" |
22 | #include "mlir/Dialect/Affine/LoopUtils.h" |
23 | #include "mlir/Dialect/Affine/Passes.h.inc" |
24 | #include "mlir/Dialect/Affine/Utils.h" |
25 | #include "mlir/Dialect/Func/IR/FuncOps.h" |
26 | #include "llvm/Support/Debug.h" |
27 | #include <deque> |
28 | |
29 | namespace mlir { |
30 | namespace affine { |
31 | #define GEN_PASS_DEF_AFFINEPARALLELIZE |
32 | #include "mlir/Dialect/Affine/Passes.h.inc" |
33 | } // namespace affine |
34 | } // namespace mlir |
35 | |
36 | #define DEBUG_TYPE "affine-parallel" |
37 | |
38 | using namespace mlir; |
39 | using namespace mlir::affine; |
40 | |
41 | namespace { |
42 | /// Convert all parallel affine.for op into 1-D affine.parallel op. |
43 | struct AffineParallelize |
44 | : public affine::impl::AffineParallelizeBase<AffineParallelize> { |
45 | void runOnOperation() override; |
46 | }; |
47 | |
48 | /// Descriptor of a potentially parallelizable loop. |
49 | struct ParallelizationCandidate { |
50 | ParallelizationCandidate(AffineForOp l, SmallVector<LoopReduction> &&r) |
51 | : loop(l), reductions(std::move(r)) {} |
52 | |
53 | /// The potentially parallelizable loop. |
54 | AffineForOp loop; |
55 | /// Desciprtors of reductions that can be parallelized in the loop. |
56 | SmallVector<LoopReduction> reductions; |
57 | }; |
58 | } // namespace |
59 | |
60 | void AffineParallelize::runOnOperation() { |
61 | func::FuncOp f = getOperation(); |
62 | |
63 | // The walker proceeds in pre-order to process the outer loops first |
64 | // and control the number of outer parallel loops. |
65 | std::vector<ParallelizationCandidate> parallelizableLoops; |
66 | f.walk<WalkOrder::PreOrder>([&](AffineForOp loop) { |
67 | SmallVector<LoopReduction> reductions; |
68 | if (isLoopParallel(loop, parallelReductions ? &reductions : nullptr)) |
69 | parallelizableLoops.emplace_back(loop, std::move(reductions)); |
70 | }); |
71 | |
72 | for (const ParallelizationCandidate &candidate : parallelizableLoops) { |
73 | unsigned numParentParallelOps = 0; |
74 | AffineForOp loop = candidate.loop; |
75 | for (Operation *op = loop->getParentOp(); |
76 | op != nullptr && !op->hasTrait<OpTrait::AffineScope>(); |
77 | op = op->getParentOp()) { |
78 | if (isa<AffineParallelOp>(Val: op)) |
79 | ++numParentParallelOps; |
80 | } |
81 | |
82 | if (numParentParallelOps < maxNested) { |
83 | if (failed(affineParallelize(loop, candidate.reductions))) { |
84 | LLVM_DEBUG(llvm::dbgs() << "["DEBUG_TYPE "] failed to parallelize\n" |
85 | << loop); |
86 | } |
87 | } else { |
88 | LLVM_DEBUG(llvm::dbgs() << "["DEBUG_TYPE "] too many nested loops\n" |
89 | << loop); |
90 | } |
91 | } |
92 | } |
93 | |
94 | std::unique_ptr<OperationPass<func::FuncOp>> |
95 | mlir::affine::createAffineParallelizePass() { |
96 | return std::make_unique<AffineParallelize>(); |
97 | } |
98 |