1044d5b5dSValentin Clement //===-- CodeGen.cpp -- bridge to lower to LLVM ----------------------------===//
2044d5b5dSValentin Clement //
3044d5b5dSValentin Clement // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4044d5b5dSValentin Clement // See https://llvm.org/LICENSE.txt for license information.
5044d5b5dSValentin Clement // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6044d5b5dSValentin Clement //
7044d5b5dSValentin Clement //===----------------------------------------------------------------------===//
8044d5b5dSValentin Clement //
9044d5b5dSValentin Clement // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10044d5b5dSValentin Clement //
11044d5b5dSValentin Clement //===----------------------------------------------------------------------===//
12044d5b5dSValentin Clement 
13044d5b5dSValentin Clement #include "flang/Optimizer/CodeGen/CodeGen.h"
14044d5b5dSValentin Clement #include "PassDetail.h"
15044d5b5dSValentin Clement #include "flang/Optimizer/Dialect/FIROps.h"
16044d5b5dSValentin Clement #include "flang/Optimizer/Dialect/FIRType.h"
17044d5b5dSValentin Clement #include "mlir/Conversion/ArithmeticToLLVM/ArithmeticToLLVM.h"
18044d5b5dSValentin Clement #include "mlir/Conversion/LLVMCommon/Pattern.h"
19044d5b5dSValentin Clement #include "mlir/Conversion/LLVMCommon/TypeConverter.h"
20044d5b5dSValentin Clement #include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h"
21044d5b5dSValentin Clement #include "mlir/IR/BuiltinTypes.h"
223ae8e442SValentin Clement #include "mlir/IR/Matchers.h"
23044d5b5dSValentin Clement #include "mlir/Pass/Pass.h"
24044d5b5dSValentin Clement #include "llvm/ADT/ArrayRef.h"
25044d5b5dSValentin Clement 
26044d5b5dSValentin Clement #define DEBUG_TYPE "flang-codegen"
27044d5b5dSValentin Clement 
28044d5b5dSValentin Clement // fir::LLVMTypeConverter for converting to LLVM IR dialect types.
29044d5b5dSValentin Clement #include "TypeConverter.h"
30044d5b5dSValentin Clement 
31044d5b5dSValentin Clement namespace {
32044d5b5dSValentin Clement /// FIR conversion pattern template
33044d5b5dSValentin Clement template <typename FromOp>
34044d5b5dSValentin Clement class FIROpConversion : public mlir::ConvertOpToLLVMPattern<FromOp> {
35044d5b5dSValentin Clement public:
36044d5b5dSValentin Clement   explicit FIROpConversion(fir::LLVMTypeConverter &lowering)
37044d5b5dSValentin Clement       : mlir::ConvertOpToLLVMPattern<FromOp>(lowering) {}
38044d5b5dSValentin Clement 
39044d5b5dSValentin Clement protected:
40044d5b5dSValentin Clement   mlir::Type convertType(mlir::Type ty) const {
41044d5b5dSValentin Clement     return lowerTy().convertType(ty);
42044d5b5dSValentin Clement   }
43044d5b5dSValentin Clement 
44044d5b5dSValentin Clement   fir::LLVMTypeConverter &lowerTy() const {
45044d5b5dSValentin Clement     return *static_cast<fir::LLVMTypeConverter *>(this->getTypeConverter());
46044d5b5dSValentin Clement   }
47044d5b5dSValentin Clement };
48044d5b5dSValentin Clement 
493ae8e442SValentin Clement /// FIR conversion pattern template
503ae8e442SValentin Clement template <typename FromOp>
513ae8e442SValentin Clement class FIROpAndTypeConversion : public FIROpConversion<FromOp> {
523ae8e442SValentin Clement public:
533ae8e442SValentin Clement   using FIROpConversion<FromOp>::FIROpConversion;
543ae8e442SValentin Clement   using OpAdaptor = typename FromOp::Adaptor;
553ae8e442SValentin Clement 
563ae8e442SValentin Clement   mlir::LogicalResult
573ae8e442SValentin Clement   matchAndRewrite(FromOp op, OpAdaptor adaptor,
583ae8e442SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const final {
593ae8e442SValentin Clement     mlir::Type ty = this->convertType(op.getType());
603ae8e442SValentin Clement     return doRewrite(op, ty, adaptor, rewriter);
613ae8e442SValentin Clement   }
623ae8e442SValentin Clement 
633ae8e442SValentin Clement   virtual mlir::LogicalResult
643ae8e442SValentin Clement   doRewrite(FromOp addr, mlir::Type ty, OpAdaptor adaptor,
653ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const = 0;
663ae8e442SValentin Clement };
673ae8e442SValentin Clement 
680c4a7a52SValentin Clement // Lower `fir.address_of` operation to `llvm.address_of` operation.
69044d5b5dSValentin Clement struct AddrOfOpConversion : public FIROpConversion<fir::AddrOfOp> {
70044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
71044d5b5dSValentin Clement 
72044d5b5dSValentin Clement   mlir::LogicalResult
73044d5b5dSValentin Clement   matchAndRewrite(fir::AddrOfOp addr, OpAdaptor adaptor,
74044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
75044d5b5dSValentin Clement     auto ty = convertType(addr.getType());
76044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::AddressOfOp>(
77044d5b5dSValentin Clement         addr, ty, addr.symbol().getRootReference().getValue());
78044d5b5dSValentin Clement     return success();
79044d5b5dSValentin Clement   }
80044d5b5dSValentin Clement };
81044d5b5dSValentin Clement 
820c4a7a52SValentin Clement /// Lower `fir.has_value` operation to `llvm.return` operation.
83044d5b5dSValentin Clement struct HasValueOpConversion : public FIROpConversion<fir::HasValueOp> {
84044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
85044d5b5dSValentin Clement 
86044d5b5dSValentin Clement   mlir::LogicalResult
87044d5b5dSValentin Clement   matchAndRewrite(fir::HasValueOp op, OpAdaptor adaptor,
88044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
89044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, adaptor.getOperands());
90044d5b5dSValentin Clement     return success();
91044d5b5dSValentin Clement   }
92044d5b5dSValentin Clement };
93044d5b5dSValentin Clement 
940c4a7a52SValentin Clement /// Lower `fir.global` operation to `llvm.global` operation.
950c4a7a52SValentin Clement /// `fir.insert_on_range` operations are replaced with constant dense attribute
960c4a7a52SValentin Clement /// if they are applied on the full range.
97044d5b5dSValentin Clement struct GlobalOpConversion : public FIROpConversion<fir::GlobalOp> {
98044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
99044d5b5dSValentin Clement 
100044d5b5dSValentin Clement   mlir::LogicalResult
101044d5b5dSValentin Clement   matchAndRewrite(fir::GlobalOp global, OpAdaptor adaptor,
102044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
103044d5b5dSValentin Clement     auto tyAttr = convertType(global.getType());
104044d5b5dSValentin Clement     if (global.getType().isa<fir::BoxType>())
105044d5b5dSValentin Clement       tyAttr = tyAttr.cast<mlir::LLVM::LLVMPointerType>().getElementType();
106044d5b5dSValentin Clement     auto loc = global.getLoc();
107044d5b5dSValentin Clement     mlir::Attribute initAttr{};
108044d5b5dSValentin Clement     if (global.initVal())
109044d5b5dSValentin Clement       initAttr = global.initVal().getValue();
110044d5b5dSValentin Clement     auto linkage = convertLinkage(global.linkName());
111044d5b5dSValentin Clement     auto isConst = global.constant().hasValue();
112044d5b5dSValentin Clement     auto g = rewriter.create<mlir::LLVM::GlobalOp>(
113044d5b5dSValentin Clement         loc, tyAttr, isConst, linkage, global.sym_name(), initAttr);
114044d5b5dSValentin Clement     auto &gr = g.getInitializerRegion();
115044d5b5dSValentin Clement     rewriter.inlineRegionBefore(global.region(), gr, gr.end());
116044d5b5dSValentin Clement     if (!gr.empty()) {
117044d5b5dSValentin Clement       // Replace insert_on_range with a constant dense attribute if the
118044d5b5dSValentin Clement       // initialization is on the full range.
119044d5b5dSValentin Clement       auto insertOnRangeOps = gr.front().getOps<fir::InsertOnRangeOp>();
120044d5b5dSValentin Clement       for (auto insertOp : insertOnRangeOps) {
121044d5b5dSValentin Clement         if (isFullRange(insertOp.coor(), insertOp.getType())) {
122044d5b5dSValentin Clement           auto seqTyAttr = convertType(insertOp.getType());
123044d5b5dSValentin Clement           auto *op = insertOp.val().getDefiningOp();
124044d5b5dSValentin Clement           auto constant = mlir::dyn_cast<mlir::arith::ConstantOp>(op);
125044d5b5dSValentin Clement           if (!constant) {
126044d5b5dSValentin Clement             auto convertOp = mlir::dyn_cast<fir::ConvertOp>(op);
127044d5b5dSValentin Clement             if (!convertOp)
128044d5b5dSValentin Clement               continue;
129044d5b5dSValentin Clement             constant = cast<mlir::arith::ConstantOp>(
130044d5b5dSValentin Clement                 convertOp.value().getDefiningOp());
131044d5b5dSValentin Clement           }
132044d5b5dSValentin Clement           mlir::Type vecType = mlir::VectorType::get(
133044d5b5dSValentin Clement               insertOp.getType().getShape(), constant.getType());
134044d5b5dSValentin Clement           auto denseAttr = mlir::DenseElementsAttr::get(
135044d5b5dSValentin Clement               vecType.cast<ShapedType>(), constant.value());
136044d5b5dSValentin Clement           rewriter.setInsertionPointAfter(insertOp);
137044d5b5dSValentin Clement           rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(
138044d5b5dSValentin Clement               insertOp, seqTyAttr, denseAttr);
139044d5b5dSValentin Clement         }
140044d5b5dSValentin Clement       }
141044d5b5dSValentin Clement     }
142044d5b5dSValentin Clement     rewriter.eraseOp(global);
143044d5b5dSValentin Clement     return success();
144044d5b5dSValentin Clement   }
145044d5b5dSValentin Clement 
146044d5b5dSValentin Clement   bool isFullRange(mlir::ArrayAttr indexes, fir::SequenceType seqTy) const {
147044d5b5dSValentin Clement     auto extents = seqTy.getShape();
148044d5b5dSValentin Clement     if (indexes.size() / 2 != extents.size())
149044d5b5dSValentin Clement       return false;
150044d5b5dSValentin Clement     for (unsigned i = 0; i < indexes.size(); i += 2) {
151044d5b5dSValentin Clement       if (indexes[i].cast<IntegerAttr>().getInt() != 0)
152044d5b5dSValentin Clement         return false;
153044d5b5dSValentin Clement       if (indexes[i + 1].cast<IntegerAttr>().getInt() != extents[i / 2] - 1)
154044d5b5dSValentin Clement         return false;
155044d5b5dSValentin Clement     }
156044d5b5dSValentin Clement     return true;
157044d5b5dSValentin Clement   }
158044d5b5dSValentin Clement 
1590c4a7a52SValentin Clement   // TODO: String comparaison should be avoided. Replace linkName with an
1600c4a7a52SValentin Clement   // enumeration.
161044d5b5dSValentin Clement   mlir::LLVM::Linkage convertLinkage(Optional<StringRef> optLinkage) const {
162044d5b5dSValentin Clement     if (optLinkage.hasValue()) {
163044d5b5dSValentin Clement       auto name = optLinkage.getValue();
164044d5b5dSValentin Clement       if (name == "internal")
165044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Internal;
166044d5b5dSValentin Clement       if (name == "linkonce")
167044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Linkonce;
168044d5b5dSValentin Clement       if (name == "common")
169044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Common;
170044d5b5dSValentin Clement       if (name == "weak")
171044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Weak;
172044d5b5dSValentin Clement     }
173044d5b5dSValentin Clement     return mlir::LLVM::Linkage::External;
174044d5b5dSValentin Clement   }
175044d5b5dSValentin Clement };
176044d5b5dSValentin Clement 
177*8c239909SValentin Clement template <typename OP>
178*8c239909SValentin Clement void selectMatchAndRewrite(fir::LLVMTypeConverter &lowering, OP select,
179*8c239909SValentin Clement                            typename OP::Adaptor adaptor,
180*8c239909SValentin Clement                            mlir::ConversionPatternRewriter &rewriter) {
181*8c239909SValentin Clement   unsigned conds = select.getNumConditions();
182*8c239909SValentin Clement   auto cases = select.getCases().getValue();
183*8c239909SValentin Clement   mlir::Value selector = adaptor.selector();
184*8c239909SValentin Clement   auto loc = select.getLoc();
185*8c239909SValentin Clement   assert(conds > 0 && "select must have cases");
186*8c239909SValentin Clement 
187*8c239909SValentin Clement   llvm::SmallVector<mlir::Block *> destinations;
188*8c239909SValentin Clement   llvm::SmallVector<mlir::ValueRange> destinationsOperands;
189*8c239909SValentin Clement   mlir::Block *defaultDestination;
190*8c239909SValentin Clement   mlir::ValueRange defaultOperands;
191*8c239909SValentin Clement   llvm::SmallVector<int32_t> caseValues;
192*8c239909SValentin Clement 
193*8c239909SValentin Clement   for (unsigned t = 0; t != conds; ++t) {
194*8c239909SValentin Clement     mlir::Block *dest = select.getSuccessor(t);
195*8c239909SValentin Clement     auto destOps = select.getSuccessorOperands(adaptor.getOperands(), t);
196*8c239909SValentin Clement     const mlir::Attribute &attr = cases[t];
197*8c239909SValentin Clement     if (auto intAttr = attr.template dyn_cast<mlir::IntegerAttr>()) {
198*8c239909SValentin Clement       destinations.push_back(dest);
199*8c239909SValentin Clement       destinationsOperands.push_back(destOps.hasValue() ? *destOps
200*8c239909SValentin Clement                                                         : ValueRange());
201*8c239909SValentin Clement       caseValues.push_back(intAttr.getInt());
202*8c239909SValentin Clement       continue;
203*8c239909SValentin Clement     }
204*8c239909SValentin Clement     assert(attr.template dyn_cast_or_null<mlir::UnitAttr>());
205*8c239909SValentin Clement     assert((t + 1 == conds) && "unit must be last");
206*8c239909SValentin Clement     defaultDestination = dest;
207*8c239909SValentin Clement     defaultOperands = destOps.hasValue() ? *destOps : ValueRange();
208*8c239909SValentin Clement   }
209*8c239909SValentin Clement 
210*8c239909SValentin Clement   // LLVM::SwitchOp takes a i32 type for the selector.
211*8c239909SValentin Clement   if (select.getSelector().getType() != rewriter.getI32Type())
212*8c239909SValentin Clement     selector =
213*8c239909SValentin Clement         rewriter.create<LLVM::TruncOp>(loc, rewriter.getI32Type(), selector);
214*8c239909SValentin Clement 
215*8c239909SValentin Clement   rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>(
216*8c239909SValentin Clement       select, selector,
217*8c239909SValentin Clement       /*defaultDestination=*/defaultDestination,
218*8c239909SValentin Clement       /*defaultOperands=*/defaultOperands,
219*8c239909SValentin Clement       /*caseValues=*/caseValues,
220*8c239909SValentin Clement       /*caseDestinations=*/destinations,
221*8c239909SValentin Clement       /*caseOperands=*/destinationsOperands,
222*8c239909SValentin Clement       /*branchWeights=*/ArrayRef<int32_t>());
223*8c239909SValentin Clement }
224*8c239909SValentin Clement 
225*8c239909SValentin Clement /// conversion of fir::SelectOp to an if-then-else ladder
226*8c239909SValentin Clement struct SelectOpConversion : public FIROpConversion<fir::SelectOp> {
227*8c239909SValentin Clement   using FIROpConversion::FIROpConversion;
228*8c239909SValentin Clement 
229*8c239909SValentin Clement   mlir::LogicalResult
230*8c239909SValentin Clement   matchAndRewrite(fir::SelectOp op, OpAdaptor adaptor,
231*8c239909SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
232*8c239909SValentin Clement     selectMatchAndRewrite<fir::SelectOp>(lowerTy(), op, adaptor, rewriter);
233*8c239909SValentin Clement     return success();
234*8c239909SValentin Clement   }
235*8c239909SValentin Clement };
236*8c239909SValentin Clement 
237*8c239909SValentin Clement /// conversion of fir::SelectRankOp to an if-then-else ladder
238*8c239909SValentin Clement struct SelectRankOpConversion : public FIROpConversion<fir::SelectRankOp> {
239*8c239909SValentin Clement   using FIROpConversion::FIROpConversion;
240*8c239909SValentin Clement 
241*8c239909SValentin Clement   mlir::LogicalResult
242*8c239909SValentin Clement   matchAndRewrite(fir::SelectRankOp op, OpAdaptor adaptor,
243*8c239909SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
244*8c239909SValentin Clement     selectMatchAndRewrite<fir::SelectRankOp>(lowerTy(), op, adaptor, rewriter);
245*8c239909SValentin Clement     return success();
246*8c239909SValentin Clement   }
247*8c239909SValentin Clement };
248*8c239909SValentin Clement 
249044d5b5dSValentin Clement // convert to LLVM IR dialect `undef`
250044d5b5dSValentin Clement struct UndefOpConversion : public FIROpConversion<fir::UndefOp> {
251044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
252044d5b5dSValentin Clement 
253044d5b5dSValentin Clement   mlir::LogicalResult
254044d5b5dSValentin Clement   matchAndRewrite(fir::UndefOp undef, OpAdaptor,
255044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
256044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::UndefOp>(
257044d5b5dSValentin Clement         undef, convertType(undef.getType()));
258044d5b5dSValentin Clement     return success();
259044d5b5dSValentin Clement   }
260044d5b5dSValentin Clement };
261a7a61359SValentin Clement 
26232e08248SAndrzej Warzynski // convert to LLVM IR dialect `unreachable`
26332e08248SAndrzej Warzynski struct UnreachableOpConversion : public FIROpConversion<fir::UnreachableOp> {
26432e08248SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
26532e08248SAndrzej Warzynski 
26632e08248SAndrzej Warzynski   mlir::LogicalResult
26732e08248SAndrzej Warzynski   matchAndRewrite(fir::UnreachableOp unreach, OpAdaptor adaptor,
26832e08248SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
26932e08248SAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(unreach);
27032e08248SAndrzej Warzynski     return success();
27132e08248SAndrzej Warzynski   }
27232e08248SAndrzej Warzynski };
27332e08248SAndrzej Warzynski 
274a7a61359SValentin Clement struct ZeroOpConversion : public FIROpConversion<fir::ZeroOp> {
275a7a61359SValentin Clement   using FIROpConversion::FIROpConversion;
276a7a61359SValentin Clement 
277a7a61359SValentin Clement   mlir::LogicalResult
278a7a61359SValentin Clement   matchAndRewrite(fir::ZeroOp zero, OpAdaptor,
279a7a61359SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
280a7a61359SValentin Clement     auto ty = convertType(zero.getType());
281a7a61359SValentin Clement     if (ty.isa<mlir::LLVM::LLVMPointerType>()) {
282a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(zero, ty);
283a7a61359SValentin Clement     } else if (ty.isa<mlir::IntegerType>()) {
284a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
285a7a61359SValentin Clement           zero, ty, mlir::IntegerAttr::get(zero.getType(), 0));
286a7a61359SValentin Clement     } else if (mlir::LLVM::isCompatibleFloatingPointType(ty)) {
287a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
288a7a61359SValentin Clement           zero, ty, mlir::FloatAttr::get(zero.getType(), 0.0));
289a7a61359SValentin Clement     } else {
290a7a61359SValentin Clement       // TODO: create ConstantAggregateZero for FIR aggregate/array types.
29152d813edSValentin Clement       return rewriter.notifyMatchFailure(
29252d813edSValentin Clement           zero,
293a7a61359SValentin Clement           "conversion of fir.zero with aggregate type not implemented yet");
294a7a61359SValentin Clement     }
295a7a61359SValentin Clement     return success();
296a7a61359SValentin Clement   }
297a7a61359SValentin Clement };
29832e08248SAndrzej Warzynski 
2993ae8e442SValentin Clement /// InsertOnRange inserts a value into a sequence over a range of offsets.
3003ae8e442SValentin Clement struct InsertOnRangeOpConversion
3013ae8e442SValentin Clement     : public FIROpAndTypeConversion<fir::InsertOnRangeOp> {
3023ae8e442SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
3033ae8e442SValentin Clement 
3043ae8e442SValentin Clement   // Increments an array of subscripts in a row major fasion.
3053ae8e442SValentin Clement   void incrementSubscripts(const SmallVector<uint64_t> &dims,
3063ae8e442SValentin Clement                            SmallVector<uint64_t> &subscripts) const {
3073ae8e442SValentin Clement     for (size_t i = dims.size(); i > 0; --i) {
3083ae8e442SValentin Clement       if (++subscripts[i - 1] < dims[i - 1]) {
3093ae8e442SValentin Clement         return;
3103ae8e442SValentin Clement       }
3113ae8e442SValentin Clement       subscripts[i - 1] = 0;
3123ae8e442SValentin Clement     }
3133ae8e442SValentin Clement   }
3143ae8e442SValentin Clement 
3153ae8e442SValentin Clement   mlir::LogicalResult
3163ae8e442SValentin Clement   doRewrite(fir::InsertOnRangeOp range, mlir::Type ty, OpAdaptor adaptor,
3173ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
3183ae8e442SValentin Clement 
3193ae8e442SValentin Clement     llvm::SmallVector<uint64_t> dims;
3203ae8e442SValentin Clement     auto type = adaptor.getOperands()[0].getType();
3213ae8e442SValentin Clement 
3223ae8e442SValentin Clement     // Iteratively extract the array dimensions from the type.
3233ae8e442SValentin Clement     while (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
3243ae8e442SValentin Clement       dims.push_back(t.getNumElements());
3253ae8e442SValentin Clement       type = t.getElementType();
3263ae8e442SValentin Clement     }
3273ae8e442SValentin Clement 
3283ae8e442SValentin Clement     SmallVector<uint64_t> lBounds;
3293ae8e442SValentin Clement     SmallVector<uint64_t> uBounds;
3303ae8e442SValentin Clement 
3313ae8e442SValentin Clement     // Extract integer value from the attribute
3323ae8e442SValentin Clement     SmallVector<int64_t> coordinates = llvm::to_vector<4>(
3333ae8e442SValentin Clement         llvm::map_range(range.coor(), [](Attribute a) -> int64_t {
3343ae8e442SValentin Clement           return a.cast<IntegerAttr>().getInt();
3353ae8e442SValentin Clement         }));
3363ae8e442SValentin Clement 
3373ae8e442SValentin Clement     // Unzip the upper and lower bound and convert to a row major format.
3383ae8e442SValentin Clement     for (auto i = coordinates.rbegin(), e = coordinates.rend(); i != e; ++i) {
3393ae8e442SValentin Clement       uBounds.push_back(*i++);
3403ae8e442SValentin Clement       lBounds.push_back(*i);
3413ae8e442SValentin Clement     }
3423ae8e442SValentin Clement 
3433ae8e442SValentin Clement     auto &subscripts = lBounds;
3443ae8e442SValentin Clement     auto loc = range.getLoc();
3453ae8e442SValentin Clement     mlir::Value lastOp = adaptor.getOperands()[0];
3463ae8e442SValentin Clement     mlir::Value insertVal = adaptor.getOperands()[1];
3473ae8e442SValentin Clement 
3483ae8e442SValentin Clement     auto i64Ty = rewriter.getI64Type();
3493ae8e442SValentin Clement     while (subscripts != uBounds) {
3503ae8e442SValentin Clement       // Convert uint64_t's to Attribute's.
3513ae8e442SValentin Clement       SmallVector<mlir::Attribute> subscriptAttrs;
3523ae8e442SValentin Clement       for (const auto &subscript : subscripts)
3533ae8e442SValentin Clement         subscriptAttrs.push_back(IntegerAttr::get(i64Ty, subscript));
3543ae8e442SValentin Clement       lastOp = rewriter.create<mlir::LLVM::InsertValueOp>(
3553ae8e442SValentin Clement           loc, ty, lastOp, insertVal,
3563ae8e442SValentin Clement           ArrayAttr::get(range.getContext(), subscriptAttrs));
3573ae8e442SValentin Clement 
3583ae8e442SValentin Clement       incrementSubscripts(dims, subscripts);
3593ae8e442SValentin Clement     }
3603ae8e442SValentin Clement 
3613ae8e442SValentin Clement     // Convert uint64_t's to Attribute's.
3623ae8e442SValentin Clement     SmallVector<mlir::Attribute> subscriptAttrs;
3633ae8e442SValentin Clement     for (const auto &subscript : subscripts)
3643ae8e442SValentin Clement       subscriptAttrs.push_back(
3653ae8e442SValentin Clement           IntegerAttr::get(rewriter.getI64Type(), subscript));
3663ae8e442SValentin Clement     mlir::ArrayRef<mlir::Attribute> arrayRef(subscriptAttrs);
3673ae8e442SValentin Clement 
3683ae8e442SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
3693ae8e442SValentin Clement         range, ty, lastOp, insertVal,
3703ae8e442SValentin Clement         ArrayAttr::get(range.getContext(), arrayRef));
3713ae8e442SValentin Clement 
3723ae8e442SValentin Clement     return success();
3733ae8e442SValentin Clement   }
3743ae8e442SValentin Clement };
375044d5b5dSValentin Clement } // namespace
376044d5b5dSValentin Clement 
377044d5b5dSValentin Clement namespace {
378044d5b5dSValentin Clement /// Convert FIR dialect to LLVM dialect
379044d5b5dSValentin Clement ///
380044d5b5dSValentin Clement /// This pass lowers all FIR dialect operations to LLVM IR dialect. An
381044d5b5dSValentin Clement /// MLIR pass is used to lower residual Std dialect to LLVM IR dialect.
382044d5b5dSValentin Clement ///
383044d5b5dSValentin Clement /// This pass is not complete yet. We are upstreaming it in small patches.
384044d5b5dSValentin Clement class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> {
385044d5b5dSValentin Clement public:
386044d5b5dSValentin Clement   mlir::ModuleOp getModule() { return getOperation(); }
387044d5b5dSValentin Clement 
388044d5b5dSValentin Clement   void runOnOperation() override final {
389044d5b5dSValentin Clement     auto *context = getModule().getContext();
390044d5b5dSValentin Clement     fir::LLVMTypeConverter typeConverter{getModule()};
391044d5b5dSValentin Clement     mlir::OwningRewritePatternList pattern(context);
3923ae8e442SValentin Clement     pattern.insert<AddrOfOpConversion, HasValueOpConversion, GlobalOpConversion,
393*8c239909SValentin Clement                    InsertOnRangeOpConversion, SelectOpConversion,
394*8c239909SValentin Clement                    SelectRankOpConversion, UnreachableOpConversion,
395*8c239909SValentin Clement                    ZeroOpConversion, UndefOpConversion>(typeConverter);
396044d5b5dSValentin Clement     mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern);
397044d5b5dSValentin Clement     mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter,
398044d5b5dSValentin Clement                                                             pattern);
399044d5b5dSValentin Clement     mlir::ConversionTarget target{*context};
400044d5b5dSValentin Clement     target.addLegalDialect<mlir::LLVM::LLVMDialect>();
401044d5b5dSValentin Clement 
402044d5b5dSValentin Clement     // required NOPs for applying a full conversion
403044d5b5dSValentin Clement     target.addLegalOp<mlir::ModuleOp>();
404044d5b5dSValentin Clement 
405044d5b5dSValentin Clement     // apply the patterns
406044d5b5dSValentin Clement     if (mlir::failed(mlir::applyFullConversion(getModule(), target,
407044d5b5dSValentin Clement                                                std::move(pattern)))) {
408044d5b5dSValentin Clement       signalPassFailure();
409044d5b5dSValentin Clement     }
410044d5b5dSValentin Clement   }
411044d5b5dSValentin Clement };
412044d5b5dSValentin Clement } // namespace
413044d5b5dSValentin Clement 
414044d5b5dSValentin Clement std::unique_ptr<mlir::Pass> fir::createFIRToLLVMPass() {
415044d5b5dSValentin Clement   return std::make_unique<FIRToLLVMLowering>();
416044d5b5dSValentin Clement }
417