1b8737614SUday Bondhugula //===- LoopUnrollAndJam.cpp - Code to perform loop unroll and jam ---------===//
2b8737614SUday Bondhugula //
3b8737614SUday Bondhugula // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4b8737614SUday Bondhugula // See https://llvm.org/LICENSE.txt for license information.
5b8737614SUday Bondhugula // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b8737614SUday Bondhugula //
7b8737614SUday Bondhugula //===----------------------------------------------------------------------===//
8b8737614SUday Bondhugula //
9b8737614SUday Bondhugula // This file implements loop unroll and jam. Unroll and jam is a transformation
10b8737614SUday Bondhugula // that improves locality, in particular, register reuse, while also improving
11b8737614SUday Bondhugula // operation level parallelism. The example below shows what it does in nearly
12b8737614SUday Bondhugula // the general case. Loop unroll and jam currently works if the bounds of the
13b8737614SUday Bondhugula // loops inner to the loop being unroll-jammed do not depend on the latter.
14b8737614SUday Bondhugula //
15b8737614SUday Bondhugula // Before      After unroll and jam of i by factor 2:
16b8737614SUday Bondhugula //
17b8737614SUday Bondhugula //             for i, step = 2
18b8737614SUday Bondhugula // for i         S1(i);
19b8737614SUday Bondhugula //   S1;         S2(i);
20b8737614SUday Bondhugula //   S2;         S1(i+1);
21b8737614SUday Bondhugula //   for j       S2(i+1);
22b8737614SUday Bondhugula //     S3;       for j
23b8737614SUday Bondhugula //     S4;         S3(i, j);
24b8737614SUday Bondhugula //   S5;           S4(i, j);
25b8737614SUday Bondhugula //   S6;           S3(i+1, j)
26b8737614SUday Bondhugula //                 S4(i+1, j)
27b8737614SUday Bondhugula //               S5(i);
28b8737614SUday Bondhugula //               S6(i);
29b8737614SUday Bondhugula //               S5(i+1);
30b8737614SUday Bondhugula //               S6(i+1);
31b8737614SUday Bondhugula //
32b8737614SUday Bondhugula // Note: 'if/else' blocks are not jammed. So, if there are loops inside if
33b8737614SUday Bondhugula // op's, bodies of those loops will not be jammed.
34b8737614SUday Bondhugula //===----------------------------------------------------------------------===//
351834ad4aSRiver Riddle 
361834ad4aSRiver Riddle #include "PassDetail.h"
37755dc07dSRiver Riddle #include "mlir/Dialect/Affine/Analysis/AffineAnalysis.h"
38755dc07dSRiver Riddle #include "mlir/Dialect/Affine/Analysis/LoopAnalysis.h"
39b8737614SUday Bondhugula #include "mlir/Dialect/Affine/IR/AffineOps.h"
40a70aa7bbSRiver Riddle #include "mlir/Dialect/Affine/LoopUtils.h"
41b8737614SUday Bondhugula #include "mlir/Dialect/Affine/Passes.h"
42b8737614SUday Bondhugula #include "mlir/IR/AffineExpr.h"
43b8737614SUday Bondhugula #include "mlir/IR/AffineMap.h"
44b8737614SUday Bondhugula #include "mlir/IR/BlockAndValueMapping.h"
45b8737614SUday Bondhugula #include "mlir/IR/Builders.h"
46b8737614SUday Bondhugula #include "llvm/ADT/DenseMap.h"
47b8737614SUday Bondhugula #include "llvm/Support/CommandLine.h"
48b8737614SUday Bondhugula 
49b8737614SUday Bondhugula using namespace mlir;
50b8737614SUday Bondhugula 
51b8737614SUday Bondhugula #define DEBUG_TYPE "affine-loop-unroll-jam"
52b8737614SUday Bondhugula 
53b8737614SUday Bondhugula namespace {
54b8737614SUday Bondhugula /// Loop unroll jam pass. Currently, this just unroll jams the first
55b8737614SUday Bondhugula /// outer loop in a Function.
561834ad4aSRiver Riddle struct LoopUnrollAndJam : public AffineLoopUnrollAndJamBase<LoopUnrollAndJam> {
LoopUnrollAndJam__anonc688eb950111::LoopUnrollAndJam57400ad6f9SRiver Riddle   explicit LoopUnrollAndJam(Optional<unsigned> unrollJamFactor = None) {
58400ad6f9SRiver Riddle     if (unrollJamFactor)
59400ad6f9SRiver Riddle       this->unrollJamFactor = *unrollJamFactor;
60400ad6f9SRiver Riddle   }
61b8737614SUday Bondhugula 
6241574554SRiver Riddle   void runOnOperation() override;
63b8737614SUday Bondhugula };
64be0a7e9fSMehdi Amini } // namespace
65b8737614SUday Bondhugula 
66*58ceae95SRiver Riddle std::unique_ptr<OperationPass<func::FuncOp>>
createLoopUnrollAndJamPass(int unrollJamFactor)67b8737614SUday Bondhugula mlir::createLoopUnrollAndJamPass(int unrollJamFactor) {
68b8737614SUday Bondhugula   return std::make_unique<LoopUnrollAndJam>(
69b8737614SUday Bondhugula       unrollJamFactor == -1 ? None : Optional<unsigned>(unrollJamFactor));
70b8737614SUday Bondhugula }
71b8737614SUday Bondhugula 
runOnOperation()7241574554SRiver Riddle void LoopUnrollAndJam::runOnOperation() {
7341574554SRiver Riddle   if (getOperation().isExternal())
7441574554SRiver Riddle     return;
7541574554SRiver Riddle 
76b8737614SUday Bondhugula   // Currently, just the outermost loop from the first loop nest is
77b8737614SUday Bondhugula   // unroll-and-jammed by this pass. However, runOnAffineForOp can be called on
78b8737614SUday Bondhugula   // any for operation.
7941574554SRiver Riddle   auto &entryBlock = getOperation().front();
80b8737614SUday Bondhugula   if (auto forOp = dyn_cast<AffineForOp>(entryBlock.front()))
81e21adfa3SRiver Riddle     (void)loopUnrollJamByFactor(forOp, unrollJamFactor);
82b8737614SUday Bondhugula }
83