110282824SYash Jain //===- AffineParallelize.cpp - Affineparallelize Pass---------------------===//
210282824SYash Jain //
310282824SYash Jain // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
410282824SYash Jain // See https://llvm.org/LICENSE.txt for license information.
510282824SYash Jain // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
610282824SYash Jain //
710282824SYash Jain //===----------------------------------------------------------------------===//
810282824SYash Jain //
910282824SYash Jain // This file implements a parallelizer for affine loop nests that is able to
1010282824SYash Jain // perform inner or outer loop parallelization.
1110282824SYash Jain //
1210282824SYash Jain //===----------------------------------------------------------------------===//
1310282824SYash Jain 
1410282824SYash Jain #include "PassDetail.h"
15755dc07dSRiver Riddle #include "mlir/Dialect/Affine/Analysis/AffineAnalysis.h"
16755dc07dSRiver Riddle #include "mlir/Dialect/Affine/Analysis/AffineStructures.h"
17755dc07dSRiver Riddle #include "mlir/Dialect/Affine/Analysis/LoopAnalysis.h"
18755dc07dSRiver Riddle #include "mlir/Dialect/Affine/Analysis/Utils.h"
1910282824SYash Jain #include "mlir/Dialect/Affine/IR/AffineOps.h"
2010282824SYash Jain #include "mlir/Dialect/Affine/IR/AffineValueMap.h"
21a70aa7bbSRiver Riddle #include "mlir/Dialect/Affine/LoopUtils.h"
2210282824SYash Jain #include "mlir/Dialect/Affine/Passes.h"
2310282824SYash Jain #include "mlir/Dialect/Affine/Passes.h.inc"
2410282824SYash Jain #include "mlir/Dialect/Affine/Utils.h"
2510282824SYash Jain #include "llvm/Support/Debug.h"
26297a5b7cSNico Weber #include <deque>
2710282824SYash Jain 
2810282824SYash Jain #define DEBUG_TYPE "affine-parallel"
2910282824SYash Jain 
3010282824SYash Jain using namespace mlir;
3110282824SYash Jain 
3210282824SYash Jain namespace {
3310282824SYash Jain /// Convert all parallel affine.for op into 1-D affine.parallel op.
3410282824SYash Jain struct AffineParallelize : public AffineParallelizeBase<AffineParallelize> {
3541574554SRiver Riddle   void runOnOperation() override;
3610282824SYash Jain };
37545fa378SAlex Zinenko 
38545fa378SAlex Zinenko /// Descriptor of a potentially parallelizable loop.
39545fa378SAlex Zinenko struct ParallelizationCandidate {
ParallelizationCandidate__anonb03fa4320111::ParallelizationCandidate40545fa378SAlex Zinenko   ParallelizationCandidate(AffineForOp l, SmallVector<LoopReduction> &&r)
41545fa378SAlex Zinenko       : loop(l), reductions(std::move(r)) {}
42545fa378SAlex Zinenko 
43545fa378SAlex Zinenko   /// The potentially parallelizable loop.
44545fa378SAlex Zinenko   AffineForOp loop;
45545fa378SAlex Zinenko   /// Desciprtors of reductions that can be parallelized in the loop.
46545fa378SAlex Zinenko   SmallVector<LoopReduction> reductions;
47545fa378SAlex Zinenko };
4810282824SYash Jain } // namespace
4910282824SYash Jain 
runOnOperation()5041574554SRiver Riddle void AffineParallelize::runOnOperation() {
51*58ceae95SRiver Riddle   func::FuncOp f = getOperation();
5280766eccSAlex Zinenko 
5351d43bbcSPrashant Kumar   // The walker proceeds in pre-order to process the outer loops first
5451d43bbcSPrashant Kumar   // and control the number of outer parallel loops.
5551d43bbcSPrashant Kumar   std::vector<ParallelizationCandidate> parallelizableLoops;
5651d43bbcSPrashant Kumar   f.walk<WalkOrder::PreOrder>([&](AffineForOp loop) {
57545fa378SAlex Zinenko     SmallVector<LoopReduction> reductions;
58545fa378SAlex Zinenko     if (isLoopParallel(loop, parallelReductions ? &reductions : nullptr))
59e5639b3fSMehdi Amini       parallelizableLoops.emplace_back(loop, std::move(reductions));
6010282824SYash Jain   });
6180766eccSAlex Zinenko 
62545fa378SAlex Zinenko   for (const ParallelizationCandidate &candidate : parallelizableLoops) {
6380766eccSAlex Zinenko     unsigned numParentParallelOps = 0;
64545fa378SAlex Zinenko     AffineForOp loop = candidate.loop;
6580766eccSAlex Zinenko     for (Operation *op = loop->getParentOp();
6680766eccSAlex Zinenko          op != nullptr && !op->hasTrait<OpTrait::AffineScope>();
6780766eccSAlex Zinenko          op = op->getParentOp()) {
6880766eccSAlex Zinenko       if (isa<AffineParallelOp>(op))
6980766eccSAlex Zinenko         ++numParentParallelOps;
7080766eccSAlex Zinenko     }
7180766eccSAlex Zinenko 
72545fa378SAlex Zinenko     if (numParentParallelOps < maxNested) {
73545fa378SAlex Zinenko       if (failed(affineParallelize(loop, candidate.reductions))) {
74545fa378SAlex Zinenko         LLVM_DEBUG(llvm::dbgs() << "[" DEBUG_TYPE "] failed to parallelize\n"
75545fa378SAlex Zinenko                                 << loop);
76545fa378SAlex Zinenko       }
77545fa378SAlex Zinenko     } else {
78545fa378SAlex Zinenko       LLVM_DEBUG(llvm::dbgs() << "[" DEBUG_TYPE "] too many nested loops\n"
79545fa378SAlex Zinenko                               << loop);
80545fa378SAlex Zinenko     }
8110282824SYash Jain   }
8280766eccSAlex Zinenko }
8310282824SYash Jain 
84*58ceae95SRiver Riddle std::unique_ptr<OperationPass<func::FuncOp>>
createAffineParallelizePass()85*58ceae95SRiver Riddle mlir::createAffineParallelizePass() {
8610282824SYash Jain   return std::make_unique<AffineParallelize>();
8710282824SYash Jain }
88