xref: /llvm-project/flang/lib/Optimizer/Transforms/AffinePromotion.cpp (revision db791b278a414fb6df1acc1799adcf11d8fb9169)
1d70938bbSJean Perier //===-- AffinePromotion.cpp -----------------------------------------------===//
2d70938bbSJean Perier //
3d70938bbSJean Perier // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4d70938bbSJean Perier // See https://llvm.org/LICENSE.txt for license information.
5d70938bbSJean Perier // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6d70938bbSJean Perier //
7d70938bbSJean Perier //===----------------------------------------------------------------------===//
8b2169992SValentin Clement //
9b2169992SValentin Clement // This transformation is a prototype that promote FIR loops operations
10b2169992SValentin Clement // to affine dialect operations.
11b2169992SValentin Clement // It is not part of the production pipeline and would need more work in order
12b2169992SValentin Clement // to be used in production.
13b2169992SValentin Clement // More information can be found in this presentation:
14b2169992SValentin Clement // https://slides.com/rajanwalia/deck
15b2169992SValentin Clement //
16b2169992SValentin Clement //===----------------------------------------------------------------------===//
17d70938bbSJean Perier 
18d70938bbSJean Perier #include "flang/Optimizer/Dialect/FIRDialect.h"
19d70938bbSJean Perier #include "flang/Optimizer/Dialect/FIROps.h"
20d70938bbSJean Perier #include "flang/Optimizer/Dialect/FIRType.h"
21d70938bbSJean Perier #include "flang/Optimizer/Transforms/Passes.h"
22d70938bbSJean Perier #include "mlir/Dialect/Affine/IR/AffineOps.h"
2323aa5a74SRiver Riddle #include "mlir/Dialect/Func/IR/FuncOps.h"
248b68da2cSAlex Zinenko #include "mlir/Dialect/SCF/IR/SCF.h"
25d70938bbSJean Perier #include "mlir/IR/BuiltinAttributes.h"
26d70938bbSJean Perier #include "mlir/IR/IntegerSet.h"
27d70938bbSJean Perier #include "mlir/IR/Visitors.h"
28d70938bbSJean Perier #include "mlir/Transforms/DialectConversion.h"
29d70938bbSJean Perier #include "llvm/ADT/DenseMap.h"
30d70938bbSJean Perier #include "llvm/Support/Debug.h"
314d4d4785SKazu Hirata #include <optional>
32d70938bbSJean Perier 
3367d0d7acSMichele Scuttari namespace fir {
3467d0d7acSMichele Scuttari #define GEN_PASS_DEF_AFFINEDIALECTPROMOTION
3567d0d7acSMichele Scuttari #include "flang/Optimizer/Transforms/Passes.h.inc"
3667d0d7acSMichele Scuttari } // namespace fir
3767d0d7acSMichele Scuttari 
38d70938bbSJean Perier #define DEBUG_TYPE "flang-affine-promotion"
39d70938bbSJean Perier 
40d70938bbSJean Perier using namespace fir;
41092601d4SAndrzej Warzynski using namespace mlir;
42d70938bbSJean Perier 
43d70938bbSJean Perier namespace {
44d70938bbSJean Perier struct AffineLoopAnalysis;
45d70938bbSJean Perier struct AffineIfAnalysis;
46d70938bbSJean Perier 
47d70938bbSJean Perier /// Stores analysis objects for all loops and if operations inside a function
48d70938bbSJean Perier /// these analysis are used twice, first for marking operations for rewrite and
49d70938bbSJean Perier /// second when doing rewrite.
50d70938bbSJean Perier struct AffineFunctionAnalysis {
AffineFunctionAnalysis__anond3ac08d00111::AffineFunctionAnalysis5158ceae95SRiver Riddle   explicit AffineFunctionAnalysis(mlir::func::FuncOp funcOp) {
52d70938bbSJean Perier     for (fir::DoLoopOp op : funcOp.getOps<fir::DoLoopOp>())
53d70938bbSJean Perier       loopAnalysisMap.try_emplace(op, op, *this);
54d70938bbSJean Perier   }
55d70938bbSJean Perier 
56d70938bbSJean Perier   AffineLoopAnalysis getChildLoopAnalysis(fir::DoLoopOp op) const;
57d70938bbSJean Perier 
58d70938bbSJean Perier   AffineIfAnalysis getChildIfAnalysis(fir::IfOp op) const;
59d70938bbSJean Perier 
60d70938bbSJean Perier   llvm::DenseMap<mlir::Operation *, AffineLoopAnalysis> loopAnalysisMap;
61d70938bbSJean Perier   llvm::DenseMap<mlir::Operation *, AffineIfAnalysis> ifAnalysisMap;
62d70938bbSJean Perier };
63d70938bbSJean Perier } // namespace
64d70938bbSJean Perier 
analyzeCoordinate(mlir::Value coordinate,mlir::Operation * op)65d70938bbSJean Perier static bool analyzeCoordinate(mlir::Value coordinate, mlir::Operation *op) {
6657b26790SChristian Sigg   if (auto blockArg = mlir::dyn_cast<mlir::BlockArgument>(coordinate)) {
67d70938bbSJean Perier     if (isa<fir::DoLoopOp>(blockArg.getOwner()->getParentOp()))
68d70938bbSJean Perier       return true;
69d70938bbSJean Perier     LLVM_DEBUG(llvm::dbgs() << "AffineLoopAnalysis: array coordinate is not a "
70d70938bbSJean Perier                                "loop induction variable (owner not loopOp)\n";
71d70938bbSJean Perier                op->dump());
72d70938bbSJean Perier     return false;
73d70938bbSJean Perier   }
74d70938bbSJean Perier   LLVM_DEBUG(
75d70938bbSJean Perier       llvm::dbgs() << "AffineLoopAnalysis: array coordinate is not a loop "
76d70938bbSJean Perier                       "induction variable (not a block argument)\n";
77d70938bbSJean Perier       op->dump(); coordinate.getDefiningOp()->dump());
78d70938bbSJean Perier   return false;
79d70938bbSJean Perier }
80d70938bbSJean Perier 
81d70938bbSJean Perier namespace {
82d70938bbSJean Perier struct AffineLoopAnalysis {
83d70938bbSJean Perier   AffineLoopAnalysis() = default;
84d70938bbSJean Perier 
AffineLoopAnalysis__anond3ac08d00211::AffineLoopAnalysis85d70938bbSJean Perier   explicit AffineLoopAnalysis(fir::DoLoopOp op, AffineFunctionAnalysis &afa)
86d70938bbSJean Perier       : legality(analyzeLoop(op, afa)) {}
87d70938bbSJean Perier 
canPromoteToAffine__anond3ac08d00211::AffineLoopAnalysis88d70938bbSJean Perier   bool canPromoteToAffine() { return legality; }
89d70938bbSJean Perier 
90d70938bbSJean Perier private:
analyzeBody__anond3ac08d00211::AffineLoopAnalysis91d70938bbSJean Perier   bool analyzeBody(fir::DoLoopOp loopOperation,
92d70938bbSJean Perier                    AffineFunctionAnalysis &functionAnalysis) {
93d70938bbSJean Perier     for (auto loopOp : loopOperation.getOps<fir::DoLoopOp>()) {
94d70938bbSJean Perier       auto analysis = functionAnalysis.loopAnalysisMap
95d70938bbSJean Perier                           .try_emplace(loopOp, loopOp, functionAnalysis)
96d70938bbSJean Perier                           .first->getSecond();
97d70938bbSJean Perier       if (!analysis.canPromoteToAffine())
98d70938bbSJean Perier         return false;
99d70938bbSJean Perier     }
100d70938bbSJean Perier     for (auto ifOp : loopOperation.getOps<fir::IfOp>())
101d70938bbSJean Perier       functionAnalysis.ifAnalysisMap.try_emplace(ifOp, ifOp, functionAnalysis);
102d70938bbSJean Perier     return true;
103d70938bbSJean Perier   }
104d70938bbSJean Perier 
analyzeLoop__anond3ac08d00211::AffineLoopAnalysis105d70938bbSJean Perier   bool analyzeLoop(fir::DoLoopOp loopOperation,
106d70938bbSJean Perier                    AffineFunctionAnalysis &functionAnalysis) {
107d70938bbSJean Perier     LLVM_DEBUG(llvm::dbgs() << "AffineLoopAnalysis: \n"; loopOperation.dump(););
108d70938bbSJean Perier     return analyzeMemoryAccess(loopOperation) &&
109d70938bbSJean Perier            analyzeBody(loopOperation, functionAnalysis);
110d70938bbSJean Perier   }
111d70938bbSJean Perier 
analyzeReference__anond3ac08d00211::AffineLoopAnalysis112d70938bbSJean Perier   bool analyzeReference(mlir::Value memref, mlir::Operation *op) {
113d70938bbSJean Perier     if (auto acoOp = memref.getDefiningOp<ArrayCoorOp>()) {
114fac349a1SChristian Sigg       if (mlir::isa<fir::BoxType>(acoOp.getMemref().getType())) {
115d70938bbSJean Perier         // TODO: Look if and how fir.box can be promoted to affine.
116d70938bbSJean Perier         LLVM_DEBUG(llvm::dbgs() << "AffineLoopAnalysis: cannot promote loop, "
117d70938bbSJean Perier                                    "array memory operation uses fir.box\n";
118d70938bbSJean Perier                    op->dump(); acoOp.dump(););
119d70938bbSJean Perier         return false;
120d70938bbSJean Perier       }
121d70938bbSJean Perier       bool canPromote = true;
122149ad3d5SShraiysh Vaishay       for (auto coordinate : acoOp.getIndices())
123d70938bbSJean Perier         canPromote = canPromote && analyzeCoordinate(coordinate, op);
124d70938bbSJean Perier       return canPromote;
125d70938bbSJean Perier     }
126d70938bbSJean Perier     if (auto coOp = memref.getDefiningOp<CoordinateOp>()) {
127d70938bbSJean Perier       LLVM_DEBUG(llvm::dbgs()
128d70938bbSJean Perier                      << "AffineLoopAnalysis: cannot promote loop, "
129d70938bbSJean Perier                         "array memory operation uses non ArrayCoorOp\n";
130d70938bbSJean Perier                  op->dump(); coOp.dump(););
131d70938bbSJean Perier 
132d70938bbSJean Perier       return false;
133d70938bbSJean Perier     }
134d70938bbSJean Perier     LLVM_DEBUG(llvm::dbgs() << "AffineLoopAnalysis: unknown type of memory "
135d70938bbSJean Perier                                "reference for array load\n";
136d70938bbSJean Perier                op->dump(););
137d70938bbSJean Perier     return false;
138d70938bbSJean Perier   }
139d70938bbSJean Perier 
analyzeMemoryAccess__anond3ac08d00211::AffineLoopAnalysis140d70938bbSJean Perier   bool analyzeMemoryAccess(fir::DoLoopOp loopOperation) {
141d70938bbSJean Perier     for (auto loadOp : loopOperation.getOps<fir::LoadOp>())
142149ad3d5SShraiysh Vaishay       if (!analyzeReference(loadOp.getMemref(), loadOp))
143d70938bbSJean Perier         return false;
144d70938bbSJean Perier     for (auto storeOp : loopOperation.getOps<fir::StoreOp>())
145149ad3d5SShraiysh Vaishay       if (!analyzeReference(storeOp.getMemref(), storeOp))
146d70938bbSJean Perier         return false;
147d70938bbSJean Perier     return true;
148d70938bbSJean Perier   }
149d70938bbSJean Perier 
150d70938bbSJean Perier   bool legality{};
151d70938bbSJean Perier };
152d70938bbSJean Perier } // namespace
153d70938bbSJean Perier 
154d70938bbSJean Perier AffineLoopAnalysis
getChildLoopAnalysis(fir::DoLoopOp op) const155d70938bbSJean Perier AffineFunctionAnalysis::getChildLoopAnalysis(fir::DoLoopOp op) const {
156d70938bbSJean Perier   auto it = loopAnalysisMap.find_as(op);
157d70938bbSJean Perier   if (it == loopAnalysisMap.end()) {
158d70938bbSJean Perier     LLVM_DEBUG(llvm::dbgs() << "AffineFunctionAnalysis: not computed for:\n";
159d70938bbSJean Perier                op.dump(););
160d70938bbSJean Perier     op.emitError("error in fetching loop analysis in AffineFunctionAnalysis\n");
161d70938bbSJean Perier     return {};
162d70938bbSJean Perier   }
163d70938bbSJean Perier   return it->getSecond();
164d70938bbSJean Perier }
165d70938bbSJean Perier 
166d70938bbSJean Perier namespace {
167d70938bbSJean Perier /// Calculates arguments for creating an IntegerSet. symCount, dimCount are the
168d70938bbSJean Perier /// final number of symbols and dimensions of the affine map. Integer set if
169d70938bbSJean Perier /// possible is in Optional IntegerSet.
170d70938bbSJean Perier struct AffineIfCondition {
171c0921586SKazu Hirata   using MaybeAffineExpr = std::optional<mlir::AffineExpr>;
172d70938bbSJean Perier 
AffineIfCondition__anond3ac08d00311::AffineIfCondition173d70938bbSJean Perier   explicit AffineIfCondition(mlir::Value fc) : firCondition(fc) {
174a54f4eaeSMogball     if (auto condDef = firCondition.getDefiningOp<mlir::arith::CmpIOp>())
175d70938bbSJean Perier       fromCmpIOp(condDef);
176d70938bbSJean Perier   }
177d70938bbSJean Perier 
hasIntegerSet__anond3ac08d00311::AffineIfCondition178c82fb16fSKazu Hirata   bool hasIntegerSet() const { return integerSet.has_value(); }
179d70938bbSJean Perier 
getIntegerSet__anond3ac08d00311::AffineIfCondition180d70938bbSJean Perier   mlir::IntegerSet getIntegerSet() const {
181d70938bbSJean Perier     assert(hasIntegerSet() && "integer set is missing");
18215a9a72eSFangrui Song     return *integerSet;
183d70938bbSJean Perier   }
184d70938bbSJean Perier 
getAffineArgs__anond3ac08d00311::AffineIfCondition185d70938bbSJean Perier   mlir::ValueRange getAffineArgs() const { return affineArgs; }
186d70938bbSJean Perier 
187d70938bbSJean Perier private:
affineBinaryOp__anond3ac08d00311::AffineIfCondition188d70938bbSJean Perier   MaybeAffineExpr affineBinaryOp(mlir::AffineExprKind kind, mlir::Value lhs,
189d70938bbSJean Perier                                  mlir::Value rhs) {
190d70938bbSJean Perier     return affineBinaryOp(kind, toAffineExpr(lhs), toAffineExpr(rhs));
191d70938bbSJean Perier   }
192d70938bbSJean Perier 
affineBinaryOp__anond3ac08d00311::AffineIfCondition193d70938bbSJean Perier   MaybeAffineExpr affineBinaryOp(mlir::AffineExprKind kind, MaybeAffineExpr lhs,
194d70938bbSJean Perier                                  MaybeAffineExpr rhs) {
19586b8c1d9SKazu Hirata     if (lhs && rhs)
196009ab172SKazu Hirata       return mlir::getAffineBinaryOpExpr(kind, *lhs, *rhs);
197d70938bbSJean Perier     return {};
198d70938bbSJean Perier   }
199d70938bbSJean Perier 
toAffineExpr__anond3ac08d00311::AffineIfCondition200d70938bbSJean Perier   MaybeAffineExpr toAffineExpr(MaybeAffineExpr e) { return e; }
201d70938bbSJean Perier 
toAffineExpr__anond3ac08d00311::AffineIfCondition202d70938bbSJean Perier   MaybeAffineExpr toAffineExpr(int64_t value) {
203d70938bbSJean Perier     return {mlir::getAffineConstantExpr(value, firCondition.getContext())};
204d70938bbSJean Perier   }
205d70938bbSJean Perier 
206d70938bbSJean Perier   /// Returns an AffineExpr if it is a result of operations that can be done
207d70938bbSJean Perier   /// in an affine expression, this includes -, +, *, rem, constant.
208d70938bbSJean Perier   /// block arguments of a loopOp or forOp are used as dimensions
toAffineExpr__anond3ac08d00311::AffineIfCondition209d70938bbSJean Perier   MaybeAffineExpr toAffineExpr(mlir::Value value) {
210a54f4eaeSMogball     if (auto op = value.getDefiningOp<mlir::arith::SubIOp>())
211feeee78aSJacques Pienaar       return affineBinaryOp(
212feeee78aSJacques Pienaar           mlir::AffineExprKind::Add, toAffineExpr(op.getLhs()),
213feeee78aSJacques Pienaar           affineBinaryOp(mlir::AffineExprKind::Mul, toAffineExpr(op.getRhs()),
214d70938bbSJean Perier                          toAffineExpr(-1)));
215a54f4eaeSMogball     if (auto op = value.getDefiningOp<mlir::arith::AddIOp>())
216feeee78aSJacques Pienaar       return affineBinaryOp(mlir::AffineExprKind::Add, op.getLhs(),
217feeee78aSJacques Pienaar                             op.getRhs());
218a54f4eaeSMogball     if (auto op = value.getDefiningOp<mlir::arith::MulIOp>())
219feeee78aSJacques Pienaar       return affineBinaryOp(mlir::AffineExprKind::Mul, op.getLhs(),
220feeee78aSJacques Pienaar                             op.getRhs());
221a54f4eaeSMogball     if (auto op = value.getDefiningOp<mlir::arith::RemUIOp>())
222feeee78aSJacques Pienaar       return affineBinaryOp(mlir::AffineExprKind::Mod, op.getLhs(),
223feeee78aSJacques Pienaar                             op.getRhs());
224a54f4eaeSMogball     if (auto op = value.getDefiningOp<mlir::arith::ConstantOp>())
225fac349a1SChristian Sigg       if (auto intConstant = mlir::dyn_cast<IntegerAttr>(op.getValue()))
226d70938bbSJean Perier         return toAffineExpr(intConstant.getInt());
22757b26790SChristian Sigg     if (auto blockArg = mlir::dyn_cast<mlir::BlockArgument>(value)) {
228d70938bbSJean Perier       affineArgs.push_back(value);
229d70938bbSJean Perier       if (isa<fir::DoLoopOp>(blockArg.getOwner()->getParentOp()) ||
2304c48f016SMatthias Springer           isa<mlir::affine::AffineForOp>(blockArg.getOwner()->getParentOp()))
231d70938bbSJean Perier         return {mlir::getAffineDimExpr(dimCount++, value.getContext())};
232d70938bbSJean Perier       return {mlir::getAffineSymbolExpr(symCount++, value.getContext())};
233d70938bbSJean Perier     }
234d70938bbSJean Perier     return {};
235d70938bbSJean Perier   }
236d70938bbSJean Perier 
fromCmpIOp__anond3ac08d00311::AffineIfCondition237a54f4eaeSMogball   void fromCmpIOp(mlir::arith::CmpIOp cmpOp) {
238feeee78aSJacques Pienaar     auto lhsAffine = toAffineExpr(cmpOp.getLhs());
239feeee78aSJacques Pienaar     auto rhsAffine = toAffineExpr(cmpOp.getRhs());
24086b8c1d9SKazu Hirata     if (!lhsAffine || !rhsAffine)
241d70938bbSJean Perier       return;
2423356d72aSKazu Hirata     auto constraintPair =
2433356d72aSKazu Hirata         constraint(cmpOp.getPredicate(), *rhsAffine - *lhsAffine);
244d70938bbSJean Perier     if (!constraintPair)
245d70938bbSJean Perier       return;
246fac0fb4dSKazu Hirata     integerSet = mlir::IntegerSet::get(
247fac0fb4dSKazu Hirata         dimCount, symCount, {constraintPair->first}, {constraintPair->second});
248d70938bbSJean Perier   }
249d70938bbSJean Perier 
250c0921586SKazu Hirata   std::optional<std::pair<AffineExpr, bool>>
constraint__anond3ac08d00311::AffineIfCondition251a54f4eaeSMogball   constraint(mlir::arith::CmpIPredicate predicate, mlir::AffineExpr basic) {
252d70938bbSJean Perier     switch (predicate) {
253a54f4eaeSMogball     case mlir::arith::CmpIPredicate::slt:
254d70938bbSJean Perier       return {std::make_pair(basic - 1, false)};
255a54f4eaeSMogball     case mlir::arith::CmpIPredicate::sle:
256d70938bbSJean Perier       return {std::make_pair(basic, false)};
257a54f4eaeSMogball     case mlir::arith::CmpIPredicate::sgt:
258d70938bbSJean Perier       return {std::make_pair(1 - basic, false)};
259a54f4eaeSMogball     case mlir::arith::CmpIPredicate::sge:
260d70938bbSJean Perier       return {std::make_pair(0 - basic, false)};
261a54f4eaeSMogball     case mlir::arith::CmpIPredicate::eq:
262d70938bbSJean Perier       return {std::make_pair(basic, true)};
263d70938bbSJean Perier     default:
264d70938bbSJean Perier       return {};
265d70938bbSJean Perier     }
266d70938bbSJean Perier   }
267d70938bbSJean Perier 
268d70938bbSJean Perier   llvm::SmallVector<mlir::Value> affineArgs;
269c0921586SKazu Hirata   std::optional<mlir::IntegerSet> integerSet;
270d70938bbSJean Perier   mlir::Value firCondition;
271d70938bbSJean Perier   unsigned symCount{0u};
272d70938bbSJean Perier   unsigned dimCount{0u};
273d70938bbSJean Perier };
274d70938bbSJean Perier } // namespace
275d70938bbSJean Perier 
276d70938bbSJean Perier namespace {
277d70938bbSJean Perier /// Analysis for affine promotion of fir.if
278d70938bbSJean Perier struct AffineIfAnalysis {
279d70938bbSJean Perier   AffineIfAnalysis() = default;
280d70938bbSJean Perier 
AffineIfAnalysis__anond3ac08d00411::AffineIfAnalysis281d70938bbSJean Perier   explicit AffineIfAnalysis(fir::IfOp op, AffineFunctionAnalysis &afa)
282d70938bbSJean Perier       : legality(analyzeIf(op, afa)) {}
283d70938bbSJean Perier 
canPromoteToAffine__anond3ac08d00411::AffineIfAnalysis284d70938bbSJean Perier   bool canPromoteToAffine() { return legality; }
285d70938bbSJean Perier 
286d70938bbSJean Perier private:
analyzeIf__anond3ac08d00411::AffineIfAnalysis287d70938bbSJean Perier   bool analyzeIf(fir::IfOp op, AffineFunctionAnalysis &afa) {
288d70938bbSJean Perier     if (op.getNumResults() == 0)
289d70938bbSJean Perier       return true;
290d70938bbSJean Perier     LLVM_DEBUG(llvm::dbgs()
291d70938bbSJean Perier                    << "AffineIfAnalysis: not promoting as op has results\n";);
292d70938bbSJean Perier     return false;
293d70938bbSJean Perier   }
294d70938bbSJean Perier 
295d70938bbSJean Perier   bool legality{};
296d70938bbSJean Perier };
297d70938bbSJean Perier } // namespace
298d70938bbSJean Perier 
299d70938bbSJean Perier AffineIfAnalysis
getChildIfAnalysis(fir::IfOp op) const300d70938bbSJean Perier AffineFunctionAnalysis::getChildIfAnalysis(fir::IfOp op) const {
301d70938bbSJean Perier   auto it = ifAnalysisMap.find_as(op);
302d70938bbSJean Perier   if (it == ifAnalysisMap.end()) {
303d70938bbSJean Perier     LLVM_DEBUG(llvm::dbgs() << "AffineFunctionAnalysis: not computed for:\n";
304d70938bbSJean Perier                op.dump(););
305d70938bbSJean Perier     op.emitError("error in fetching if analysis in AffineFunctionAnalysis\n");
306d70938bbSJean Perier     return {};
307d70938bbSJean Perier   }
308d70938bbSJean Perier   return it->getSecond();
309d70938bbSJean Perier }
310d70938bbSJean Perier 
311d70938bbSJean Perier /// AffineMap rewriting fir.array_coor operation to affine apply,
312d70938bbSJean Perier /// %dim = fir.gendim %lowerBound, %upperBound, %stride
313d70938bbSJean Perier /// %a = fir.array_coor %arr(%dim) %i
314d70938bbSJean Perier /// returning affineMap = affine_map<(i)[lb, ub, st] -> (i*st - lb)>
createArrayIndexAffineMap(unsigned dimensions,MLIRContext * context)315d70938bbSJean Perier static mlir::AffineMap createArrayIndexAffineMap(unsigned dimensions,
316d70938bbSJean Perier                                                  MLIRContext *context) {
317d70938bbSJean Perier   auto index = mlir::getAffineConstantExpr(0, context);
318d70938bbSJean Perier   auto accuExtent = mlir::getAffineConstantExpr(1, context);
319d70938bbSJean Perier   for (unsigned i = 0; i < dimensions; ++i) {
320d70938bbSJean Perier     mlir::AffineExpr idx = mlir::getAffineDimExpr(i, context),
321d70938bbSJean Perier                      lowerBound = mlir::getAffineSymbolExpr(i * 3, context),
322d70938bbSJean Perier                      currentExtent =
323d70938bbSJean Perier                          mlir::getAffineSymbolExpr(i * 3 + 1, context),
324d70938bbSJean Perier                      stride = mlir::getAffineSymbolExpr(i * 3 + 2, context),
325d70938bbSJean Perier                      currentPart = (idx * stride - lowerBound) * accuExtent;
326d70938bbSJean Perier     index = currentPart + index;
327d70938bbSJean Perier     accuExtent = accuExtent * currentExtent;
328d70938bbSJean Perier   }
329d70938bbSJean Perier   return mlir::AffineMap::get(dimensions, dimensions * 3, index);
330d70938bbSJean Perier }
331d70938bbSJean Perier 
constantIntegerLike(const mlir::Value value)332c0921586SKazu Hirata static std::optional<int64_t> constantIntegerLike(const mlir::Value value) {
333a54f4eaeSMogball   if (auto definition = value.getDefiningOp<mlir::arith::ConstantOp>())
334fac349a1SChristian Sigg     if (auto stepAttr = mlir::dyn_cast<IntegerAttr>(definition.getValue()))
335d70938bbSJean Perier       return stepAttr.getInt();
336d70938bbSJean Perier   return {};
337d70938bbSJean Perier }
338d70938bbSJean Perier 
coordinateArrayElement(fir::ArrayCoorOp op)339d70938bbSJean Perier static mlir::Type coordinateArrayElement(fir::ArrayCoorOp op) {
340149ad3d5SShraiysh Vaishay   if (auto refType =
341fac349a1SChristian Sigg           mlir::dyn_cast_or_null<ReferenceType>(op.getMemref().getType())) {
342fac349a1SChristian Sigg     if (auto seqType =
343fac349a1SChristian Sigg             mlir::dyn_cast_or_null<SequenceType>(refType.getEleTy())) {
344d70938bbSJean Perier       return seqType.getEleTy();
345d70938bbSJean Perier     }
346d70938bbSJean Perier   }
347d70938bbSJean Perier   op.emitError(
348d70938bbSJean Perier       "AffineLoopConversion: array type in coordinate operation not valid\n");
349d70938bbSJean Perier   return mlir::Type();
350d70938bbSJean Perier }
351d70938bbSJean Perier 
populateIndexArgs(fir::ArrayCoorOp acoOp,fir::ShapeOp shape,SmallVectorImpl<mlir::Value> & indexArgs,mlir::PatternRewriter & rewriter)352d70938bbSJean Perier static void populateIndexArgs(fir::ArrayCoorOp acoOp, fir::ShapeOp shape,
353d70938bbSJean Perier                               SmallVectorImpl<mlir::Value> &indexArgs,
354d70938bbSJean Perier                               mlir::PatternRewriter &rewriter) {
355a54f4eaeSMogball   auto one = rewriter.create<mlir::arith::ConstantOp>(
356d70938bbSJean Perier       acoOp.getLoc(), rewriter.getIndexType(), rewriter.getIndexAttr(1));
357149ad3d5SShraiysh Vaishay   auto extents = shape.getExtents();
358d70938bbSJean Perier   for (auto i = extents.begin(); i < extents.end(); i++) {
359d70938bbSJean Perier     indexArgs.push_back(one);
360d70938bbSJean Perier     indexArgs.push_back(*i);
361d70938bbSJean Perier     indexArgs.push_back(one);
362d70938bbSJean Perier   }
363d70938bbSJean Perier }
364d70938bbSJean Perier 
populateIndexArgs(fir::ArrayCoorOp acoOp,fir::ShapeShiftOp shape,SmallVectorImpl<mlir::Value> & indexArgs,mlir::PatternRewriter & rewriter)365d70938bbSJean Perier static void populateIndexArgs(fir::ArrayCoorOp acoOp, fir::ShapeShiftOp shape,
366d70938bbSJean Perier                               SmallVectorImpl<mlir::Value> &indexArgs,
367d70938bbSJean Perier                               mlir::PatternRewriter &rewriter) {
368a54f4eaeSMogball   auto one = rewriter.create<mlir::arith::ConstantOp>(
369d70938bbSJean Perier       acoOp.getLoc(), rewriter.getIndexType(), rewriter.getIndexAttr(1));
370149ad3d5SShraiysh Vaishay   auto extents = shape.getPairs();
371d70938bbSJean Perier   for (auto i = extents.begin(); i < extents.end();) {
372d70938bbSJean Perier     indexArgs.push_back(*i++);
373d70938bbSJean Perier     indexArgs.push_back(*i++);
374d70938bbSJean Perier     indexArgs.push_back(one);
375d70938bbSJean Perier   }
376d70938bbSJean Perier }
377d70938bbSJean Perier 
populateIndexArgs(fir::ArrayCoorOp acoOp,fir::SliceOp slice,SmallVectorImpl<mlir::Value> & indexArgs,mlir::PatternRewriter & rewriter)378d70938bbSJean Perier static void populateIndexArgs(fir::ArrayCoorOp acoOp, fir::SliceOp slice,
379d70938bbSJean Perier                               SmallVectorImpl<mlir::Value> &indexArgs,
380d70938bbSJean Perier                               mlir::PatternRewriter &rewriter) {
381149ad3d5SShraiysh Vaishay   auto extents = slice.getTriples();
382d70938bbSJean Perier   for (auto i = extents.begin(); i < extents.end();) {
383d70938bbSJean Perier     indexArgs.push_back(*i++);
384d70938bbSJean Perier     indexArgs.push_back(*i++);
385d70938bbSJean Perier     indexArgs.push_back(*i++);
386d70938bbSJean Perier   }
387d70938bbSJean Perier }
388d70938bbSJean Perier 
populateIndexArgs(fir::ArrayCoorOp acoOp,SmallVectorImpl<mlir::Value> & indexArgs,mlir::PatternRewriter & rewriter)389d70938bbSJean Perier static void populateIndexArgs(fir::ArrayCoorOp acoOp,
390d70938bbSJean Perier                               SmallVectorImpl<mlir::Value> &indexArgs,
391d70938bbSJean Perier                               mlir::PatternRewriter &rewriter) {
392149ad3d5SShraiysh Vaishay   if (auto shape = acoOp.getShape().getDefiningOp<ShapeOp>())
393d70938bbSJean Perier     return populateIndexArgs(acoOp, shape, indexArgs, rewriter);
394149ad3d5SShraiysh Vaishay   if (auto shapeShift = acoOp.getShape().getDefiningOp<ShapeShiftOp>())
395d70938bbSJean Perier     return populateIndexArgs(acoOp, shapeShift, indexArgs, rewriter);
396149ad3d5SShraiysh Vaishay   if (auto slice = acoOp.getShape().getDefiningOp<SliceOp>())
397d70938bbSJean Perier     return populateIndexArgs(acoOp, slice, indexArgs, rewriter);
398d70938bbSJean Perier }
399d70938bbSJean Perier 
400d70938bbSJean Perier /// Returns affine.apply and fir.convert from array_coor and gendims
4014c48f016SMatthias Springer static std::pair<affine::AffineApplyOp, fir::ConvertOp>
createAffineOps(mlir::Value arrayRef,mlir::PatternRewriter & rewriter)402d70938bbSJean Perier createAffineOps(mlir::Value arrayRef, mlir::PatternRewriter &rewriter) {
403d70938bbSJean Perier   auto acoOp = arrayRef.getDefiningOp<ArrayCoorOp>();
404d70938bbSJean Perier   auto affineMap =
405149ad3d5SShraiysh Vaishay       createArrayIndexAffineMap(acoOp.getIndices().size(), acoOp.getContext());
406d70938bbSJean Perier   SmallVector<mlir::Value> indexArgs;
407149ad3d5SShraiysh Vaishay   indexArgs.append(acoOp.getIndices().begin(), acoOp.getIndices().end());
408d70938bbSJean Perier 
409d70938bbSJean Perier   populateIndexArgs(acoOp, indexArgs, rewriter);
410d70938bbSJean Perier 
4114c48f016SMatthias Springer   auto affineApply = rewriter.create<affine::AffineApplyOp>(
4124c48f016SMatthias Springer       acoOp.getLoc(), affineMap, indexArgs);
413d70938bbSJean Perier   auto arrayElementType = coordinateArrayElement(acoOp);
414fb4cedccSAliia Khasanova   auto newType =
415399638f9SAliia Khasanova       mlir::MemRefType::get({mlir::ShapedType::kDynamic}, arrayElementType);
416149ad3d5SShraiysh Vaishay   auto arrayConvert = rewriter.create<fir::ConvertOp>(acoOp.getLoc(), newType,
417149ad3d5SShraiysh Vaishay                                                       acoOp.getMemref());
418d70938bbSJean Perier   return std::make_pair(affineApply, arrayConvert);
419d70938bbSJean Perier }
420d70938bbSJean Perier 
rewriteLoad(fir::LoadOp loadOp,mlir::PatternRewriter & rewriter)421d70938bbSJean Perier static void rewriteLoad(fir::LoadOp loadOp, mlir::PatternRewriter &rewriter) {
422d70938bbSJean Perier   rewriter.setInsertionPoint(loadOp);
423149ad3d5SShraiysh Vaishay   auto affineOps = createAffineOps(loadOp.getMemref(), rewriter);
4244c48f016SMatthias Springer   rewriter.replaceOpWithNewOp<affine::AffineLoadOp>(
425d70938bbSJean Perier       loadOp, affineOps.second.getResult(), affineOps.first.getResult());
426d70938bbSJean Perier }
427d70938bbSJean Perier 
rewriteStore(fir::StoreOp storeOp,mlir::PatternRewriter & rewriter)428d70938bbSJean Perier static void rewriteStore(fir::StoreOp storeOp,
429d70938bbSJean Perier                          mlir::PatternRewriter &rewriter) {
430d70938bbSJean Perier   rewriter.setInsertionPoint(storeOp);
431149ad3d5SShraiysh Vaishay   auto affineOps = createAffineOps(storeOp.getMemref(), rewriter);
4324c48f016SMatthias Springer   rewriter.replaceOpWithNewOp<affine::AffineStoreOp>(
4334c48f016SMatthias Springer       storeOp, storeOp.getValue(), affineOps.second.getResult(),
434d70938bbSJean Perier       affineOps.first.getResult());
435d70938bbSJean Perier }
436d70938bbSJean Perier 
rewriteMemoryOps(Block * block,mlir::PatternRewriter & rewriter)437d70938bbSJean Perier static void rewriteMemoryOps(Block *block, mlir::PatternRewriter &rewriter) {
438d70938bbSJean Perier   for (auto &bodyOp : block->getOperations()) {
439d70938bbSJean Perier     if (isa<fir::LoadOp>(bodyOp))
440d70938bbSJean Perier       rewriteLoad(cast<fir::LoadOp>(bodyOp), rewriter);
441d70938bbSJean Perier     if (isa<fir::StoreOp>(bodyOp))
442d70938bbSJean Perier       rewriteStore(cast<fir::StoreOp>(bodyOp), rewriter);
443d70938bbSJean Perier   }
444d70938bbSJean Perier }
445d70938bbSJean Perier 
446d70938bbSJean Perier namespace {
447d70938bbSJean Perier /// Convert `fir.do_loop` to `affine.for`, creates fir.convert for arrays to
448d70938bbSJean Perier /// memref, rewrites array_coor to affine.apply with affine_map. Rewrites fir
449d70938bbSJean Perier /// loads and stores to affine.
450d70938bbSJean Perier class AffineLoopConversion : public mlir::OpRewritePattern<fir::DoLoopOp> {
451d70938bbSJean Perier public:
452d70938bbSJean Perier   using OpRewritePattern::OpRewritePattern;
AffineLoopConversion(mlir::MLIRContext * context,AffineFunctionAnalysis & afa)453d70938bbSJean Perier   AffineLoopConversion(mlir::MLIRContext *context, AffineFunctionAnalysis &afa)
454d70938bbSJean Perier       : OpRewritePattern(context), functionAnalysis(afa) {}
455d70938bbSJean Perier 
456*db791b27SRamkumar Ramachandra   llvm::LogicalResult
matchAndRewrite(fir::DoLoopOp loop,mlir::PatternRewriter & rewriter) const457d70938bbSJean Perier   matchAndRewrite(fir::DoLoopOp loop,
458d70938bbSJean Perier                   mlir::PatternRewriter &rewriter) const override {
459d70938bbSJean Perier     LLVM_DEBUG(llvm::dbgs() << "AffineLoopConversion: rewriting loop:\n";
460d70938bbSJean Perier                loop.dump(););
461d70938bbSJean Perier     LLVM_ATTRIBUTE_UNUSED auto loopAnalysis =
462d70938bbSJean Perier         functionAnalysis.getChildLoopAnalysis(loop);
463d70938bbSJean Perier     auto &loopOps = loop.getBody()->getOperations();
464d70938bbSJean Perier     auto loopAndIndex = createAffineFor(loop, rewriter);
465d70938bbSJean Perier     auto affineFor = loopAndIndex.first;
466d70938bbSJean Perier     auto inductionVar = loopAndIndex.second;
467d70938bbSJean Perier 
4685fcf907bSMatthias Springer     rewriter.startOpModification(affineFor.getOperation());
469d70938bbSJean Perier     affineFor.getBody()->getOperations().splice(
470d70938bbSJean Perier         std::prev(affineFor.getBody()->end()), loopOps, loopOps.begin(),
471d70938bbSJean Perier         std::prev(loopOps.end()));
4725fcf907bSMatthias Springer     rewriter.finalizeOpModification(affineFor.getOperation());
473d70938bbSJean Perier 
4745fcf907bSMatthias Springer     rewriter.startOpModification(loop.getOperation());
475d70938bbSJean Perier     loop.getInductionVar().replaceAllUsesWith(inductionVar);
4765fcf907bSMatthias Springer     rewriter.finalizeOpModification(loop.getOperation());
477d70938bbSJean Perier 
478d70938bbSJean Perier     rewriteMemoryOps(affineFor.getBody(), rewriter);
479d70938bbSJean Perier 
480d70938bbSJean Perier     LLVM_DEBUG(llvm::dbgs() << "AffineLoopConversion: loop rewriten to:\n";
481d70938bbSJean Perier                affineFor.dump(););
482d70938bbSJean Perier     rewriter.replaceOp(loop, affineFor.getOperation()->getResults());
483d70938bbSJean Perier     return success();
484d70938bbSJean Perier   }
485d70938bbSJean Perier 
486d70938bbSJean Perier private:
4874c48f016SMatthias Springer   std::pair<affine::AffineForOp, mlir::Value>
createAffineFor(fir::DoLoopOp op,mlir::PatternRewriter & rewriter) const488d70938bbSJean Perier   createAffineFor(fir::DoLoopOp op, mlir::PatternRewriter &rewriter) const {
489149ad3d5SShraiysh Vaishay     if (auto constantStep = constantIntegerLike(op.getStep()))
4903356d72aSKazu Hirata       if (*constantStep > 0)
4913356d72aSKazu Hirata         return positiveConstantStep(op, *constantStep, rewriter);
492d70938bbSJean Perier     return genericBounds(op, rewriter);
493d70938bbSJean Perier   }
494d70938bbSJean Perier 
495d70938bbSJean Perier   // when step for the loop is positive compile time constant
4964c48f016SMatthias Springer   std::pair<affine::AffineForOp, mlir::Value>
positiveConstantStep(fir::DoLoopOp op,int64_t step,mlir::PatternRewriter & rewriter) const497d70938bbSJean Perier   positiveConstantStep(fir::DoLoopOp op, int64_t step,
498d70938bbSJean Perier                        mlir::PatternRewriter &rewriter) const {
4994c48f016SMatthias Springer     auto affineFor = rewriter.create<affine::AffineForOp>(
500149ad3d5SShraiysh Vaishay         op.getLoc(), ValueRange(op.getLowerBound()),
501d70938bbSJean Perier         mlir::AffineMap::get(0, 1,
502d70938bbSJean Perier                              mlir::getAffineSymbolExpr(0, op.getContext())),
503149ad3d5SShraiysh Vaishay         ValueRange(op.getUpperBound()),
504d70938bbSJean Perier         mlir::AffineMap::get(0, 1,
505d70938bbSJean Perier                              1 + mlir::getAffineSymbolExpr(0, op.getContext())),
506d70938bbSJean Perier         step);
507d70938bbSJean Perier     return std::make_pair(affineFor, affineFor.getInductionVar());
508d70938bbSJean Perier   }
509d70938bbSJean Perier 
5104c48f016SMatthias Springer   std::pair<affine::AffineForOp, mlir::Value>
genericBounds(fir::DoLoopOp op,mlir::PatternRewriter & rewriter) const511d70938bbSJean Perier   genericBounds(fir::DoLoopOp op, mlir::PatternRewriter &rewriter) const {
512d70938bbSJean Perier     auto lowerBound = mlir::getAffineSymbolExpr(0, op.getContext());
513d70938bbSJean Perier     auto upperBound = mlir::getAffineSymbolExpr(1, op.getContext());
514d70938bbSJean Perier     auto step = mlir::getAffineSymbolExpr(2, op.getContext());
515d70938bbSJean Perier     mlir::AffineMap upperBoundMap = mlir::AffineMap::get(
516d70938bbSJean Perier         0, 3, (upperBound - lowerBound + step).floorDiv(step));
5174c48f016SMatthias Springer     auto genericUpperBound = rewriter.create<affine::AffineApplyOp>(
518d70938bbSJean Perier         op.getLoc(), upperBoundMap,
519149ad3d5SShraiysh Vaishay         ValueRange({op.getLowerBound(), op.getUpperBound(), op.getStep()}));
520d70938bbSJean Perier     auto actualIndexMap = mlir::AffineMap::get(
521d70938bbSJean Perier         1, 2,
522d70938bbSJean Perier         (lowerBound + mlir::getAffineDimExpr(0, op.getContext())) *
523d70938bbSJean Perier             mlir::getAffineSymbolExpr(1, op.getContext()));
524d70938bbSJean Perier 
5254c48f016SMatthias Springer     auto affineFor = rewriter.create<affine::AffineForOp>(
526d70938bbSJean Perier         op.getLoc(), ValueRange(),
527d70938bbSJean Perier         AffineMap::getConstantMap(0, op.getContext()),
528d70938bbSJean Perier         genericUpperBound.getResult(),
529d70938bbSJean Perier         mlir::AffineMap::get(0, 1,
530d70938bbSJean Perier                              1 + mlir::getAffineSymbolExpr(0, op.getContext())),
531d70938bbSJean Perier         1);
532d70938bbSJean Perier     rewriter.setInsertionPointToStart(affineFor.getBody());
5334c48f016SMatthias Springer     auto actualIndex = rewriter.create<affine::AffineApplyOp>(
534d70938bbSJean Perier         op.getLoc(), actualIndexMap,
535149ad3d5SShraiysh Vaishay         ValueRange(
536149ad3d5SShraiysh Vaishay             {affineFor.getInductionVar(), op.getLowerBound(), op.getStep()}));
537d70938bbSJean Perier     return std::make_pair(affineFor, actualIndex.getResult());
538d70938bbSJean Perier   }
539d70938bbSJean Perier 
540d70938bbSJean Perier   AffineFunctionAnalysis &functionAnalysis;
541d70938bbSJean Perier };
542d70938bbSJean Perier 
543d70938bbSJean Perier /// Convert `fir.if` to `affine.if`.
544d70938bbSJean Perier class AffineIfConversion : public mlir::OpRewritePattern<fir::IfOp> {
545d70938bbSJean Perier public:
546d70938bbSJean Perier   using OpRewritePattern::OpRewritePattern;
AffineIfConversion(mlir::MLIRContext * context,AffineFunctionAnalysis & afa)547d70938bbSJean Perier   AffineIfConversion(mlir::MLIRContext *context, AffineFunctionAnalysis &afa)
548d70938bbSJean Perier       : OpRewritePattern(context) {}
549*db791b27SRamkumar Ramachandra   llvm::LogicalResult
matchAndRewrite(fir::IfOp op,mlir::PatternRewriter & rewriter) const550d70938bbSJean Perier   matchAndRewrite(fir::IfOp op,
551d70938bbSJean Perier                   mlir::PatternRewriter &rewriter) const override {
552d70938bbSJean Perier     LLVM_DEBUG(llvm::dbgs() << "AffineIfConversion: rewriting if:\n";
553d70938bbSJean Perier                op.dump(););
554149ad3d5SShraiysh Vaishay     auto &ifOps = op.getThenRegion().front().getOperations();
555149ad3d5SShraiysh Vaishay     auto affineCondition = AffineIfCondition(op.getCondition());
556d70938bbSJean Perier     if (!affineCondition.hasIntegerSet()) {
557d70938bbSJean Perier       LLVM_DEBUG(
558d70938bbSJean Perier           llvm::dbgs()
559d70938bbSJean Perier               << "AffineIfConversion: couldn't calculate affine condition\n";);
560d70938bbSJean Perier       return failure();
561d70938bbSJean Perier     }
5624c48f016SMatthias Springer     auto affineIf = rewriter.create<affine::AffineIfOp>(
563d70938bbSJean Perier         op.getLoc(), affineCondition.getIntegerSet(),
564149ad3d5SShraiysh Vaishay         affineCondition.getAffineArgs(), !op.getElseRegion().empty());
5655fcf907bSMatthias Springer     rewriter.startOpModification(affineIf);
566d70938bbSJean Perier     affineIf.getThenBlock()->getOperations().splice(
567d70938bbSJean Perier         std::prev(affineIf.getThenBlock()->end()), ifOps, ifOps.begin(),
568d70938bbSJean Perier         std::prev(ifOps.end()));
569149ad3d5SShraiysh Vaishay     if (!op.getElseRegion().empty()) {
570149ad3d5SShraiysh Vaishay       auto &otherOps = op.getElseRegion().front().getOperations();
571d70938bbSJean Perier       affineIf.getElseBlock()->getOperations().splice(
572d70938bbSJean Perier           std::prev(affineIf.getElseBlock()->end()), otherOps, otherOps.begin(),
573d70938bbSJean Perier           std::prev(otherOps.end()));
574d70938bbSJean Perier     }
5755fcf907bSMatthias Springer     rewriter.finalizeOpModification(affineIf);
576d70938bbSJean Perier     rewriteMemoryOps(affineIf.getBody(), rewriter);
577d70938bbSJean Perier 
578d70938bbSJean Perier     LLVM_DEBUG(llvm::dbgs() << "AffineIfConversion: if converted to:\n";
579d70938bbSJean Perier                affineIf.dump(););
580d70938bbSJean Perier     rewriter.replaceOp(op, affineIf.getOperation()->getResults());
581d70938bbSJean Perier     return success();
582d70938bbSJean Perier   }
583d70938bbSJean Perier };
584d70938bbSJean Perier 
585d70938bbSJean Perier /// Promote fir.do_loop and fir.if to affine.for and affine.if, in the cases
586d70938bbSJean Perier /// where such a promotion is possible.
587d70938bbSJean Perier class AffineDialectPromotion
58867d0d7acSMichele Scuttari     : public fir::impl::AffineDialectPromotionBase<AffineDialectPromotion> {
589d70938bbSJean Perier public:
runOnOperation()590196c4279SRiver Riddle   void runOnOperation() override {
591d70938bbSJean Perier 
592d70938bbSJean Perier     auto *context = &getContext();
593196c4279SRiver Riddle     auto function = getOperation();
594d70938bbSJean Perier     markAllAnalysesPreserved();
595d70938bbSJean Perier     auto functionAnalysis = AffineFunctionAnalysis(function);
5969f85c198SRiver Riddle     mlir::RewritePatternSet patterns(context);
597d70938bbSJean Perier     patterns.insert<AffineIfConversion>(context, functionAnalysis);
598d70938bbSJean Perier     patterns.insert<AffineLoopConversion>(context, functionAnalysis);
599d70938bbSJean Perier     mlir::ConversionTarget target = *context;
6004c48f016SMatthias Springer     target.addLegalDialect<mlir::affine::AffineDialect, FIROpsDialect,
6016c8d8d10SJakub Kuderski                            mlir::scf::SCFDialect, mlir::arith::ArithDialect,
6026c8d8d10SJakub Kuderski                            mlir::func::FuncDialect>();
603d70938bbSJean Perier     target.addDynamicallyLegalOp<IfOp>([&functionAnalysis](fir::IfOp op) {
604d70938bbSJean Perier       return !(functionAnalysis.getChildIfAnalysis(op).canPromoteToAffine());
605d70938bbSJean Perier     });
606d70938bbSJean Perier     target.addDynamicallyLegalOp<DoLoopOp>([&functionAnalysis](
607d70938bbSJean Perier                                                fir::DoLoopOp op) {
608d70938bbSJean Perier       return !(functionAnalysis.getChildLoopAnalysis(op).canPromoteToAffine());
609d70938bbSJean Perier     });
610d70938bbSJean Perier 
611d70938bbSJean Perier     LLVM_DEBUG(llvm::dbgs()
612d70938bbSJean Perier                    << "AffineDialectPromotion: running promotion on: \n";
613d70938bbSJean Perier                function.print(llvm::dbgs()););
614d70938bbSJean Perier     // apply the patterns
615d70938bbSJean Perier     if (mlir::failed(mlir::applyPartialConversion(function, target,
616d70938bbSJean Perier                                                   std::move(patterns)))) {
617d70938bbSJean Perier       mlir::emitError(mlir::UnknownLoc::get(context),
618d70938bbSJean Perier                       "error in converting to affine dialect\n");
619d70938bbSJean Perier       signalPassFailure();
620d70938bbSJean Perier     }
621d70938bbSJean Perier   }
622d70938bbSJean Perier };
623d70938bbSJean Perier } // namespace
624d70938bbSJean Perier 
625d70938bbSJean Perier /// Convert FIR loop constructs to the Affine dialect
createPromoteToAffinePass()626d70938bbSJean Perier std::unique_ptr<mlir::Pass> fir::createPromoteToAffinePass() {
627d70938bbSJean Perier   return std::make_unique<AffineDialectPromotion>();
628d70938bbSJean Perier }
629