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"
15b6e44ecdSValentin Clement #include "flang/ISO_Fortran_binding.h"
1639f4ef81SValentin Clement #include "flang/Optimizer/Dialect/FIRAttr.h"
17044d5b5dSValentin Clement #include "flang/Optimizer/Dialect/FIROps.h"
18044d5b5dSValentin Clement #include "mlir/Conversion/ArithmeticToLLVM/ArithmeticToLLVM.h"
19044d5b5dSValentin Clement #include "mlir/Conversion/LLVMCommon/Pattern.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 
31b6e44ecdSValentin Clement /// `fir.box` attribute values as defined for CFI_attribute_t in
32b6e44ecdSValentin Clement /// flang/ISO_Fortran_binding.h.
33b6e44ecdSValentin Clement static constexpr unsigned kAttrPointer = CFI_attribute_pointer;
34b6e44ecdSValentin Clement static constexpr unsigned kAttrAllocatable = CFI_attribute_allocatable;
35b6e44ecdSValentin Clement 
361e6d9c06SDiana Picus static mlir::LLVM::ConstantOp
371e6d9c06SDiana Picus genConstantIndex(mlir::Location loc, mlir::Type ity,
381e6d9c06SDiana Picus                  mlir::ConversionPatternRewriter &rewriter,
391e6d9c06SDiana Picus                  std::int64_t offset) {
401e6d9c06SDiana Picus   auto cattr = rewriter.getI64IntegerAttr(offset);
411e6d9c06SDiana Picus   return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr);
421e6d9c06SDiana Picus }
431e6d9c06SDiana Picus 
4439f4ef81SValentin Clement static Block *createBlock(mlir::ConversionPatternRewriter &rewriter,
4539f4ef81SValentin Clement                           mlir::Block *insertBefore) {
4639f4ef81SValentin Clement   assert(insertBefore && "expected valid insertion block");
4739f4ef81SValentin Clement   return rewriter.createBlock(insertBefore->getParent(),
4839f4ef81SValentin Clement                               mlir::Region::iterator(insertBefore));
4939f4ef81SValentin Clement }
5039f4ef81SValentin Clement 
51044d5b5dSValentin Clement namespace {
52044d5b5dSValentin Clement /// FIR conversion pattern template
53044d5b5dSValentin Clement template <typename FromOp>
54044d5b5dSValentin Clement class FIROpConversion : public mlir::ConvertOpToLLVMPattern<FromOp> {
55044d5b5dSValentin Clement public:
56044d5b5dSValentin Clement   explicit FIROpConversion(fir::LLVMTypeConverter &lowering)
57044d5b5dSValentin Clement       : mlir::ConvertOpToLLVMPattern<FromOp>(lowering) {}
58044d5b5dSValentin Clement 
59044d5b5dSValentin Clement protected:
60044d5b5dSValentin Clement   mlir::Type convertType(mlir::Type ty) const {
61044d5b5dSValentin Clement     return lowerTy().convertType(ty);
62044d5b5dSValentin Clement   }
63044d5b5dSValentin Clement 
64df3b9810SValentin Clement   mlir::LLVM::ConstantOp
65df3b9810SValentin Clement   genConstantOffset(mlir::Location loc,
66df3b9810SValentin Clement                     mlir::ConversionPatternRewriter &rewriter,
67df3b9810SValentin Clement                     int offset) const {
68df3b9810SValentin Clement     auto ity = lowerTy().offsetType();
69df3b9810SValentin Clement     auto cattr = rewriter.getI32IntegerAttr(offset);
70df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr);
71df3b9810SValentin Clement   }
72df3b9810SValentin Clement 
73b6e44ecdSValentin Clement   /// Construct code sequence to extract the specifc value from a `fir.box`.
74b6e44ecdSValentin Clement   mlir::Value getValueFromBox(mlir::Location loc, mlir::Value box,
75df3b9810SValentin Clement                               mlir::Type resultTy,
76b6e44ecdSValentin Clement                               mlir::ConversionPatternRewriter &rewriter,
77b6e44ecdSValentin Clement                               unsigned boxValue) const {
78df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
79b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp cValuePos =
80b6e44ecdSValentin Clement         genConstantOffset(loc, rewriter, boxValue);
81df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(resultTy);
82df3b9810SValentin Clement     auto p = rewriter.create<mlir::LLVM::GEPOp>(
83b6e44ecdSValentin Clement         loc, pty, mlir::ValueRange{box, c0, cValuePos});
84df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, resultTy, p);
85df3b9810SValentin Clement   }
86df3b9810SValentin Clement 
87df3b9810SValentin Clement   /// Method to construct code sequence to get the triple for dimension `dim`
88df3b9810SValentin Clement   /// from a box.
89df3b9810SValentin Clement   SmallVector<mlir::Value, 3>
90df3b9810SValentin Clement   getDimsFromBox(mlir::Location loc, ArrayRef<mlir::Type> retTys,
91df3b9810SValentin Clement                  mlir::Value box, mlir::Value dim,
92df3b9810SValentin Clement                  mlir::ConversionPatternRewriter &rewriter) const {
93df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
94df3b9810SValentin Clement     mlir::LLVM::ConstantOp cDims =
95df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kDimsPosInBox);
96df3b9810SValentin Clement     mlir::LLVM::LoadOp l0 =
97df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 0, retTys[0], rewriter);
98df3b9810SValentin Clement     mlir::LLVM::LoadOp l1 =
99df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 1, retTys[1], rewriter);
100df3b9810SValentin Clement     mlir::LLVM::LoadOp l2 =
101df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 2, retTys[2], rewriter);
102df3b9810SValentin Clement     return {l0.getResult(), l1.getResult(), l2.getResult()};
103df3b9810SValentin Clement   }
104df3b9810SValentin Clement 
105df3b9810SValentin Clement   mlir::LLVM::LoadOp
106df3b9810SValentin Clement   loadFromOffset(mlir::Location loc, mlir::Value a, mlir::LLVM::ConstantOp c0,
107df3b9810SValentin Clement                  mlir::LLVM::ConstantOp cDims, mlir::Value dim, int off,
108df3b9810SValentin Clement                  mlir::Type ty,
109df3b9810SValentin Clement                  mlir::ConversionPatternRewriter &rewriter) const {
110df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
111df3b9810SValentin Clement     mlir::LLVM::ConstantOp c = genConstantOffset(loc, rewriter, off);
112df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, a, c0, cDims, dim, c);
113df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
114df3b9810SValentin Clement   }
115df3b9810SValentin Clement 
116df3b9810SValentin Clement   /// Read base address from a fir.box. Returned address has type ty.
117df3b9810SValentin Clement   mlir::Value
118df3b9810SValentin Clement   loadBaseAddrFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box,
119df3b9810SValentin Clement                       mlir::ConversionPatternRewriter &rewriter) const {
120df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
121df3b9810SValentin Clement     mlir::LLVM::ConstantOp cAddr =
122df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kAddrPosInBox);
123df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
124df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cAddr);
125df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
126df3b9810SValentin Clement   }
127df3b9810SValentin Clement 
128df3b9810SValentin Clement   mlir::Value
129df3b9810SValentin Clement   loadElementSizeFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box,
130df3b9810SValentin Clement                          mlir::ConversionPatternRewriter &rewriter) const {
131df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
132df3b9810SValentin Clement     mlir::LLVM::ConstantOp cElemLen =
133df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kElemLenPosInBox);
134df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
135df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cElemLen);
136df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
137df3b9810SValentin Clement   }
138df3b9810SValentin Clement 
139b6e44ecdSValentin Clement   // Load the attribute from the \p box and perform a check against \p maskValue
140b6e44ecdSValentin Clement   // The final comparison is implemented as `(attribute & maskValue) != 0`.
141b6e44ecdSValentin Clement   mlir::Value genBoxAttributeCheck(mlir::Location loc, mlir::Value box,
142b6e44ecdSValentin Clement                                    mlir::ConversionPatternRewriter &rewriter,
143b6e44ecdSValentin Clement                                    unsigned maskValue) const {
144b6e44ecdSValentin Clement     mlir::Type attrTy = rewriter.getI32Type();
145b6e44ecdSValentin Clement     mlir::Value attribute =
146b6e44ecdSValentin Clement         getValueFromBox(loc, box, attrTy, rewriter, kAttributePosInBox);
147b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp attrMask =
148b6e44ecdSValentin Clement         genConstantOffset(loc, rewriter, maskValue);
149b6e44ecdSValentin Clement     auto maskRes =
150b6e44ecdSValentin Clement         rewriter.create<mlir::LLVM::AndOp>(loc, attrTy, attribute, attrMask);
151b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
152b6e44ecdSValentin Clement     return rewriter.create<mlir::LLVM::ICmpOp>(
153b6e44ecdSValentin Clement         loc, mlir::LLVM::ICmpPredicate::ne, maskRes, c0);
154b6e44ecdSValentin Clement   }
155b6e44ecdSValentin Clement 
156df3b9810SValentin Clement   template <typename... ARGS>
157df3b9810SValentin Clement   mlir::LLVM::GEPOp genGEP(mlir::Location loc, mlir::Type ty,
158df3b9810SValentin Clement                            mlir::ConversionPatternRewriter &rewriter,
159df3b9810SValentin Clement                            mlir::Value base, ARGS... args) const {
160df3b9810SValentin Clement     SmallVector<mlir::Value> cv{args...};
161df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::GEPOp>(loc, ty, base, cv);
162df3b9810SValentin Clement   }
163df3b9810SValentin Clement 
1641e6d9c06SDiana Picus   /// Perform an extension or truncation as needed on an integer value. Lowering
1651e6d9c06SDiana Picus   /// to the specific target may involve some sign-extending or truncation of
1661e6d9c06SDiana Picus   /// values, particularly to fit them from abstract box types to the
1671e6d9c06SDiana Picus   /// appropriate reified structures.
1681e6d9c06SDiana Picus   mlir::Value integerCast(mlir::Location loc,
1691e6d9c06SDiana Picus                           mlir::ConversionPatternRewriter &rewriter,
1701e6d9c06SDiana Picus                           mlir::Type ty, mlir::Value val) const {
1711e6d9c06SDiana Picus     auto valTy = val.getType();
1721e6d9c06SDiana Picus     // If the value was not yet lowered, lower its type so that it can
1731e6d9c06SDiana Picus     // be used in getPrimitiveTypeSizeInBits.
1741e6d9c06SDiana Picus     if (!valTy.isa<mlir::IntegerType>())
1751e6d9c06SDiana Picus       valTy = convertType(valTy);
1761e6d9c06SDiana Picus     auto toSize = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
1771e6d9c06SDiana Picus     auto fromSize = mlir::LLVM::getPrimitiveTypeSizeInBits(valTy);
1781e6d9c06SDiana Picus     if (toSize < fromSize)
1791e6d9c06SDiana Picus       return rewriter.create<mlir::LLVM::TruncOp>(loc, ty, val);
1801e6d9c06SDiana Picus     if (toSize > fromSize)
1811e6d9c06SDiana Picus       return rewriter.create<mlir::LLVM::SExtOp>(loc, ty, val);
1821e6d9c06SDiana Picus     return val;
1831e6d9c06SDiana Picus   }
1841e6d9c06SDiana Picus 
185044d5b5dSValentin Clement   fir::LLVMTypeConverter &lowerTy() const {
186044d5b5dSValentin Clement     return *static_cast<fir::LLVMTypeConverter *>(this->getTypeConverter());
187044d5b5dSValentin Clement   }
188044d5b5dSValentin Clement };
189044d5b5dSValentin Clement 
1903ae8e442SValentin Clement /// FIR conversion pattern template
1913ae8e442SValentin Clement template <typename FromOp>
1923ae8e442SValentin Clement class FIROpAndTypeConversion : public FIROpConversion<FromOp> {
1933ae8e442SValentin Clement public:
1943ae8e442SValentin Clement   using FIROpConversion<FromOp>::FIROpConversion;
1953ae8e442SValentin Clement   using OpAdaptor = typename FromOp::Adaptor;
1963ae8e442SValentin Clement 
1973ae8e442SValentin Clement   mlir::LogicalResult
1983ae8e442SValentin Clement   matchAndRewrite(FromOp op, OpAdaptor adaptor,
1993ae8e442SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const final {
2003ae8e442SValentin Clement     mlir::Type ty = this->convertType(op.getType());
2013ae8e442SValentin Clement     return doRewrite(op, ty, adaptor, rewriter);
2023ae8e442SValentin Clement   }
2033ae8e442SValentin Clement 
2043ae8e442SValentin Clement   virtual mlir::LogicalResult
2053ae8e442SValentin Clement   doRewrite(FromOp addr, mlir::Type ty, OpAdaptor adaptor,
2063ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const = 0;
2073ae8e442SValentin Clement };
2083ae8e442SValentin Clement 
209420ad7ceSAndrzej Warzynski /// Create value signaling an absent optional argument in a call, e.g.
210420ad7ceSAndrzej Warzynski /// `fir.absent !fir.ref<i64>` -->  `llvm.mlir.null : !llvm.ptr<i64>`
211420ad7ceSAndrzej Warzynski struct AbsentOpConversion : public FIROpConversion<fir::AbsentOp> {
212420ad7ceSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
213420ad7ceSAndrzej Warzynski 
214420ad7ceSAndrzej Warzynski   mlir::LogicalResult
215420ad7ceSAndrzej Warzynski   matchAndRewrite(fir::AbsentOp absent, OpAdaptor,
216420ad7ceSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
217420ad7ceSAndrzej Warzynski     mlir::Type ty = convertType(absent.getType());
218420ad7ceSAndrzej Warzynski     mlir::Location loc = absent.getLoc();
219420ad7ceSAndrzej Warzynski 
220420ad7ceSAndrzej Warzynski     if (absent.getType().isa<fir::BoxCharType>()) {
221420ad7ceSAndrzej Warzynski       auto structTy = ty.cast<mlir::LLVM::LLVMStructType>();
222420ad7ceSAndrzej Warzynski       assert(!structTy.isOpaque() && !structTy.getBody().empty());
223420ad7ceSAndrzej Warzynski       auto undefStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
224420ad7ceSAndrzej Warzynski       auto nullField =
225420ad7ceSAndrzej Warzynski           rewriter.create<mlir::LLVM::NullOp>(loc, structTy.getBody()[0]);
226420ad7ceSAndrzej Warzynski       mlir::MLIRContext *ctx = absent.getContext();
227420ad7ceSAndrzej Warzynski       auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
228420ad7ceSAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
229420ad7ceSAndrzej Warzynski           absent, ty, undefStruct, nullField, c0);
230420ad7ceSAndrzej Warzynski     } else {
231420ad7ceSAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(absent, ty);
232420ad7ceSAndrzej Warzynski     }
233420ad7ceSAndrzej Warzynski     return success();
234420ad7ceSAndrzej Warzynski   }
235420ad7ceSAndrzej Warzynski };
236420ad7ceSAndrzej Warzynski 
2370c4a7a52SValentin Clement // Lower `fir.address_of` operation to `llvm.address_of` operation.
238044d5b5dSValentin Clement struct AddrOfOpConversion : public FIROpConversion<fir::AddrOfOp> {
239044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
240044d5b5dSValentin Clement 
241044d5b5dSValentin Clement   mlir::LogicalResult
242044d5b5dSValentin Clement   matchAndRewrite(fir::AddrOfOp addr, OpAdaptor adaptor,
243044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
244044d5b5dSValentin Clement     auto ty = convertType(addr.getType());
245044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::AddressOfOp>(
246044d5b5dSValentin Clement         addr, ty, addr.symbol().getRootReference().getValue());
247044d5b5dSValentin Clement     return success();
248044d5b5dSValentin Clement   }
249044d5b5dSValentin Clement };
2501e6d9c06SDiana Picus } // namespace
2511e6d9c06SDiana Picus 
2521e6d9c06SDiana Picus /// Lookup the function to compute the memory size of this parametric derived
2531e6d9c06SDiana Picus /// type. The size of the object may depend on the LEN type parameters of the
2541e6d9c06SDiana Picus /// derived type.
2551e6d9c06SDiana Picus static mlir::LLVM::LLVMFuncOp
2561e6d9c06SDiana Picus getDependentTypeMemSizeFn(fir::RecordType recTy, fir::AllocaOp op,
2571e6d9c06SDiana Picus                           mlir::ConversionPatternRewriter &rewriter) {
2581e6d9c06SDiana Picus   auto module = op->getParentOfType<mlir::ModuleOp>();
2591e6d9c06SDiana Picus   std::string name = recTy.getName().str() + "P.mem.size";
2601e6d9c06SDiana Picus   return module.lookupSymbol<mlir::LLVM::LLVMFuncOp>(name);
2611e6d9c06SDiana Picus }
2621e6d9c06SDiana Picus 
2631e6d9c06SDiana Picus namespace {
2641e6d9c06SDiana Picus /// convert to LLVM IR dialect `alloca`
2651e6d9c06SDiana Picus struct AllocaOpConversion : public FIROpConversion<fir::AllocaOp> {
2661e6d9c06SDiana Picus   using FIROpConversion::FIROpConversion;
2671e6d9c06SDiana Picus 
2681e6d9c06SDiana Picus   mlir::LogicalResult
2691e6d9c06SDiana Picus   matchAndRewrite(fir::AllocaOp alloc, OpAdaptor adaptor,
2701e6d9c06SDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
2711e6d9c06SDiana Picus     mlir::ValueRange operands = adaptor.getOperands();
2721e6d9c06SDiana Picus     auto loc = alloc.getLoc();
2731e6d9c06SDiana Picus     mlir::Type ity = lowerTy().indexType();
2741e6d9c06SDiana Picus     unsigned i = 0;
2751e6d9c06SDiana Picus     mlir::Value size = genConstantIndex(loc, ity, rewriter, 1).getResult();
2761e6d9c06SDiana Picus     mlir::Type ty = convertType(alloc.getType());
2771e6d9c06SDiana Picus     mlir::Type resultTy = ty;
2781e6d9c06SDiana Picus     if (alloc.hasLenParams()) {
2791e6d9c06SDiana Picus       unsigned end = alloc.numLenParams();
2801e6d9c06SDiana Picus       llvm::SmallVector<mlir::Value> lenParams;
2811e6d9c06SDiana Picus       for (; i < end; ++i)
2821e6d9c06SDiana Picus         lenParams.push_back(operands[i]);
2831e6d9c06SDiana Picus       mlir::Type scalarType = fir::unwrapSequenceType(alloc.getInType());
2841e6d9c06SDiana Picus       if (auto chrTy = scalarType.dyn_cast<fir::CharacterType>()) {
2851e6d9c06SDiana Picus         fir::CharacterType rawCharTy = fir::CharacterType::getUnknownLen(
2861e6d9c06SDiana Picus             chrTy.getContext(), chrTy.getFKind());
2871e6d9c06SDiana Picus         ty = mlir::LLVM::LLVMPointerType::get(convertType(rawCharTy));
2881e6d9c06SDiana Picus         assert(end == 1);
2891e6d9c06SDiana Picus         size = integerCast(loc, rewriter, ity, lenParams[0]);
2901e6d9c06SDiana Picus       } else if (auto recTy = scalarType.dyn_cast<fir::RecordType>()) {
2911e6d9c06SDiana Picus         mlir::LLVM::LLVMFuncOp memSizeFn =
2921e6d9c06SDiana Picus             getDependentTypeMemSizeFn(recTy, alloc, rewriter);
2931e6d9c06SDiana Picus         if (!memSizeFn)
2941e6d9c06SDiana Picus           emitError(loc, "did not find allocation function");
2951e6d9c06SDiana Picus         mlir::NamedAttribute attr = rewriter.getNamedAttr(
2961e6d9c06SDiana Picus             "callee", mlir::SymbolRefAttr::get(memSizeFn));
2971e6d9c06SDiana Picus         auto call = rewriter.create<mlir::LLVM::CallOp>(
2981e6d9c06SDiana Picus             loc, ity, lenParams, llvm::ArrayRef<mlir::NamedAttribute>{attr});
2991e6d9c06SDiana Picus         size = call.getResult(0);
3001e6d9c06SDiana Picus         ty = mlir::LLVM::LLVMPointerType::get(
3011e6d9c06SDiana Picus             mlir::IntegerType::get(alloc.getContext(), 8));
3021e6d9c06SDiana Picus       } else {
3031e6d9c06SDiana Picus         return emitError(loc, "unexpected type ")
3041e6d9c06SDiana Picus                << scalarType << " with type parameters";
3051e6d9c06SDiana Picus       }
3061e6d9c06SDiana Picus     }
3071e6d9c06SDiana Picus     if (alloc.hasShapeOperands()) {
3081e6d9c06SDiana Picus       mlir::Type allocEleTy = fir::unwrapRefType(alloc.getType());
3091e6d9c06SDiana Picus       // Scale the size by constant factors encoded in the array type.
3101e6d9c06SDiana Picus       if (auto seqTy = allocEleTy.dyn_cast<fir::SequenceType>()) {
3111e6d9c06SDiana Picus         fir::SequenceType::Extent constSize = 1;
3121e6d9c06SDiana Picus         for (auto extent : seqTy.getShape())
3131e6d9c06SDiana Picus           if (extent != fir::SequenceType::getUnknownExtent())
3141e6d9c06SDiana Picus             constSize *= extent;
3151e6d9c06SDiana Picus         mlir::Value constVal{
3161e6d9c06SDiana Picus             genConstantIndex(loc, ity, rewriter, constSize).getResult()};
3171e6d9c06SDiana Picus         size = rewriter.create<mlir::LLVM::MulOp>(loc, ity, size, constVal);
3181e6d9c06SDiana Picus       }
3191e6d9c06SDiana Picus       unsigned end = operands.size();
3201e6d9c06SDiana Picus       for (; i < end; ++i)
3211e6d9c06SDiana Picus         size = rewriter.create<mlir::LLVM::MulOp>(
3221e6d9c06SDiana Picus             loc, ity, size, integerCast(loc, rewriter, ity, operands[i]));
3231e6d9c06SDiana Picus     }
3241e6d9c06SDiana Picus     if (ty == resultTy) {
3251e6d9c06SDiana Picus       // Do not emit the bitcast if ty and resultTy are the same.
3261e6d9c06SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::AllocaOp>(alloc, ty, size,
3271e6d9c06SDiana Picus                                                         alloc->getAttrs());
3281e6d9c06SDiana Picus     } else {
3291e6d9c06SDiana Picus       auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, ty, size,
3301e6d9c06SDiana Picus                                                       alloc->getAttrs());
3311e6d9c06SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(alloc, resultTy, al);
3321e6d9c06SDiana Picus     }
3331e6d9c06SDiana Picus     return success();
3341e6d9c06SDiana Picus   }
3351e6d9c06SDiana Picus };
336044d5b5dSValentin Clement 
337df3b9810SValentin Clement /// Lower `fir.box_addr` to the sequence of operations to extract the first
338df3b9810SValentin Clement /// element of the box.
339df3b9810SValentin Clement struct BoxAddrOpConversion : public FIROpConversion<fir::BoxAddrOp> {
340df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
341df3b9810SValentin Clement 
342df3b9810SValentin Clement   mlir::LogicalResult
343df3b9810SValentin Clement   matchAndRewrite(fir::BoxAddrOp boxaddr, OpAdaptor adaptor,
344df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
345df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
346df3b9810SValentin Clement     auto loc = boxaddr.getLoc();
347df3b9810SValentin Clement     mlir::Type ty = convertType(boxaddr.getType());
348df3b9810SValentin Clement     if (auto argty = boxaddr.val().getType().dyn_cast<fir::BoxType>()) {
349df3b9810SValentin Clement       rewriter.replaceOp(boxaddr, loadBaseAddrFromBox(loc, ty, a, rewriter));
350df3b9810SValentin Clement     } else {
351df3b9810SValentin Clement       auto c0attr = rewriter.getI32IntegerAttr(0);
352df3b9810SValentin Clement       auto c0 = mlir::ArrayAttr::get(boxaddr.getContext(), c0attr);
353df3b9810SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(boxaddr, ty, a,
354df3b9810SValentin Clement                                                               c0);
355df3b9810SValentin Clement     }
356df3b9810SValentin Clement     return success();
357df3b9810SValentin Clement   }
358df3b9810SValentin Clement };
359df3b9810SValentin Clement 
360df3b9810SValentin Clement /// Lower `fir.box_dims` to a sequence of operations to extract the requested
361df3b9810SValentin Clement /// dimension infomartion from the boxed value.
362df3b9810SValentin Clement /// Result in a triple set of GEPs and loads.
363df3b9810SValentin Clement struct BoxDimsOpConversion : public FIROpConversion<fir::BoxDimsOp> {
364df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
365df3b9810SValentin Clement 
366df3b9810SValentin Clement   mlir::LogicalResult
367df3b9810SValentin Clement   matchAndRewrite(fir::BoxDimsOp boxdims, OpAdaptor adaptor,
368df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
369df3b9810SValentin Clement     SmallVector<mlir::Type, 3> resultTypes = {
370df3b9810SValentin Clement         convertType(boxdims.getResult(0).getType()),
371df3b9810SValentin Clement         convertType(boxdims.getResult(1).getType()),
372df3b9810SValentin Clement         convertType(boxdims.getResult(2).getType()),
373df3b9810SValentin Clement     };
374df3b9810SValentin Clement     auto results =
375df3b9810SValentin Clement         getDimsFromBox(boxdims.getLoc(), resultTypes, adaptor.getOperands()[0],
376df3b9810SValentin Clement                        adaptor.getOperands()[1], rewriter);
377df3b9810SValentin Clement     rewriter.replaceOp(boxdims, results);
378df3b9810SValentin Clement     return success();
379df3b9810SValentin Clement   }
380df3b9810SValentin Clement };
381df3b9810SValentin Clement 
382df3b9810SValentin Clement /// Lower `fir.box_elesize` to a sequence of operations ro extract the size of
383df3b9810SValentin Clement /// an element in the boxed value.
384df3b9810SValentin Clement struct BoxEleSizeOpConversion : public FIROpConversion<fir::BoxEleSizeOp> {
385df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
386df3b9810SValentin Clement 
387df3b9810SValentin Clement   mlir::LogicalResult
388df3b9810SValentin Clement   matchAndRewrite(fir::BoxEleSizeOp boxelesz, OpAdaptor adaptor,
389df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
390df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
391df3b9810SValentin Clement     auto loc = boxelesz.getLoc();
392df3b9810SValentin Clement     auto ty = convertType(boxelesz.getType());
393b6e44ecdSValentin Clement     auto elemSize = getValueFromBox(loc, a, ty, rewriter, kElemLenPosInBox);
394b6e44ecdSValentin Clement     rewriter.replaceOp(boxelesz, elemSize);
395b6e44ecdSValentin Clement     return success();
396b6e44ecdSValentin Clement   }
397b6e44ecdSValentin Clement };
398b6e44ecdSValentin Clement 
399b6e44ecdSValentin Clement /// Lower `fir.box_isalloc` to a sequence of operations to determine if the
400b6e44ecdSValentin Clement /// boxed value was from an ALLOCATABLE entity.
401b6e44ecdSValentin Clement struct BoxIsAllocOpConversion : public FIROpConversion<fir::BoxIsAllocOp> {
402b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
403b6e44ecdSValentin Clement 
404b6e44ecdSValentin Clement   mlir::LogicalResult
405b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsAllocOp boxisalloc, OpAdaptor adaptor,
406b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
407b6e44ecdSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
408b6e44ecdSValentin Clement     auto loc = boxisalloc.getLoc();
409b6e44ecdSValentin Clement     mlir::Value check =
410b6e44ecdSValentin Clement         genBoxAttributeCheck(loc, box, rewriter, kAttrAllocatable);
411b6e44ecdSValentin Clement     rewriter.replaceOp(boxisalloc, check);
412b6e44ecdSValentin Clement     return success();
413b6e44ecdSValentin Clement   }
414b6e44ecdSValentin Clement };
415b6e44ecdSValentin Clement 
416b6e44ecdSValentin Clement /// Lower `fir.box_isarray` to a sequence of operations to determine if the
417b6e44ecdSValentin Clement /// boxed is an array.
418b6e44ecdSValentin Clement struct BoxIsArrayOpConversion : public FIROpConversion<fir::BoxIsArrayOp> {
419b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
420b6e44ecdSValentin Clement 
421b6e44ecdSValentin Clement   mlir::LogicalResult
422b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsArrayOp boxisarray, OpAdaptor adaptor,
423b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
424b6e44ecdSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
425b6e44ecdSValentin Clement     auto loc = boxisarray.getLoc();
426b6e44ecdSValentin Clement     auto rank =
427b6e44ecdSValentin Clement         getValueFromBox(loc, a, rewriter.getI32Type(), rewriter, kRankPosInBox);
428b6e44ecdSValentin Clement     auto c0 = genConstantOffset(loc, rewriter, 0);
429b6e44ecdSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
430b6e44ecdSValentin Clement         boxisarray, mlir::LLVM::ICmpPredicate::ne, rank, c0);
431b6e44ecdSValentin Clement     return success();
432b6e44ecdSValentin Clement   }
433b6e44ecdSValentin Clement };
434b6e44ecdSValentin Clement 
435b6e44ecdSValentin Clement /// Lower `fir.box_isptr` to a sequence of operations to determined if the
436b6e44ecdSValentin Clement /// boxed value was from a POINTER entity.
437b6e44ecdSValentin Clement struct BoxIsPtrOpConversion : public FIROpConversion<fir::BoxIsPtrOp> {
438b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
439b6e44ecdSValentin Clement 
440b6e44ecdSValentin Clement   mlir::LogicalResult
441b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsPtrOp boxisptr, OpAdaptor adaptor,
442b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
443b6e44ecdSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
444b6e44ecdSValentin Clement     auto loc = boxisptr.getLoc();
445b6e44ecdSValentin Clement     mlir::Value check = genBoxAttributeCheck(loc, box, rewriter, kAttrPointer);
446b6e44ecdSValentin Clement     rewriter.replaceOp(boxisptr, check);
447df3b9810SValentin Clement     return success();
448df3b9810SValentin Clement   }
449df3b9810SValentin Clement };
450df3b9810SValentin Clement 
451df3b9810SValentin Clement /// Lower `fir.box_rank` to the sequence of operation to extract the rank from
452df3b9810SValentin Clement /// the box.
453df3b9810SValentin Clement struct BoxRankOpConversion : public FIROpConversion<fir::BoxRankOp> {
454df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
455df3b9810SValentin Clement 
456df3b9810SValentin Clement   mlir::LogicalResult
457df3b9810SValentin Clement   matchAndRewrite(fir::BoxRankOp boxrank, OpAdaptor adaptor,
458df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
459df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
460df3b9810SValentin Clement     auto loc = boxrank.getLoc();
461df3b9810SValentin Clement     mlir::Type ty = convertType(boxrank.getType());
462b6e44ecdSValentin Clement     auto result = getValueFromBox(loc, a, ty, rewriter, kRankPosInBox);
463df3b9810SValentin Clement     rewriter.replaceOp(boxrank, result);
464df3b9810SValentin Clement     return success();
465df3b9810SValentin Clement   }
466df3b9810SValentin Clement };
467df3b9810SValentin Clement 
468ddd11b9aSAndrzej Warzynski // `fir.call` -> `llvm.call`
469ddd11b9aSAndrzej Warzynski struct CallOpConversion : public FIROpConversion<fir::CallOp> {
470ddd11b9aSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
471ddd11b9aSAndrzej Warzynski 
472ddd11b9aSAndrzej Warzynski   mlir::LogicalResult
473ddd11b9aSAndrzej Warzynski   matchAndRewrite(fir::CallOp call, OpAdaptor adaptor,
474ddd11b9aSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
475ddd11b9aSAndrzej Warzynski     SmallVector<mlir::Type> resultTys;
476ddd11b9aSAndrzej Warzynski     for (auto r : call.getResults())
477ddd11b9aSAndrzej Warzynski       resultTys.push_back(convertType(r.getType()));
478ddd11b9aSAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
479ddd11b9aSAndrzej Warzynski         call, resultTys, adaptor.getOperands(), call->getAttrs());
480ddd11b9aSAndrzej Warzynski     return success();
481ddd11b9aSAndrzej Warzynski   }
482ddd11b9aSAndrzej Warzynski };
483ddd11b9aSAndrzej Warzynski 
484092cee5fSValentin Clement static mlir::Type getComplexEleTy(mlir::Type complex) {
485092cee5fSValentin Clement   if (auto cc = complex.dyn_cast<mlir::ComplexType>())
486092cee5fSValentin Clement     return cc.getElementType();
487092cee5fSValentin Clement   return complex.cast<fir::ComplexType>().getElementType();
488092cee5fSValentin Clement }
489092cee5fSValentin Clement 
490092cee5fSValentin Clement /// convert value of from-type to value of to-type
491092cee5fSValentin Clement struct ConvertOpConversion : public FIROpConversion<fir::ConvertOp> {
492092cee5fSValentin Clement   using FIROpConversion::FIROpConversion;
493092cee5fSValentin Clement 
494092cee5fSValentin Clement   static bool isFloatingPointTy(mlir::Type ty) {
495092cee5fSValentin Clement     return ty.isa<mlir::FloatType>();
496092cee5fSValentin Clement   }
497092cee5fSValentin Clement 
498092cee5fSValentin Clement   mlir::LogicalResult
499092cee5fSValentin Clement   matchAndRewrite(fir::ConvertOp convert, OpAdaptor adaptor,
500092cee5fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
501092cee5fSValentin Clement     auto fromTy = convertType(convert.value().getType());
502092cee5fSValentin Clement     auto toTy = convertType(convert.res().getType());
503092cee5fSValentin Clement     mlir::Value op0 = adaptor.getOperands()[0];
504092cee5fSValentin Clement     if (fromTy == toTy) {
505092cee5fSValentin Clement       rewriter.replaceOp(convert, op0);
506092cee5fSValentin Clement       return success();
507092cee5fSValentin Clement     }
508092cee5fSValentin Clement     auto loc = convert.getLoc();
509092cee5fSValentin Clement     auto convertFpToFp = [&](mlir::Value val, unsigned fromBits,
510092cee5fSValentin Clement                              unsigned toBits, mlir::Type toTy) -> mlir::Value {
511092cee5fSValentin Clement       if (fromBits == toBits) {
512092cee5fSValentin Clement         // TODO: Converting between two floating-point representations with the
513092cee5fSValentin Clement         // same bitwidth is not allowed for now.
514092cee5fSValentin Clement         mlir::emitError(loc,
515092cee5fSValentin Clement                         "cannot implicitly convert between two floating-point "
516092cee5fSValentin Clement                         "representations of the same bitwidth");
517092cee5fSValentin Clement         return {};
518092cee5fSValentin Clement       }
519092cee5fSValentin Clement       if (fromBits > toBits)
520092cee5fSValentin Clement         return rewriter.create<mlir::LLVM::FPTruncOp>(loc, toTy, val);
521092cee5fSValentin Clement       return rewriter.create<mlir::LLVM::FPExtOp>(loc, toTy, val);
522092cee5fSValentin Clement     };
523092cee5fSValentin Clement     // Complex to complex conversion.
524092cee5fSValentin Clement     if (fir::isa_complex(convert.value().getType()) &&
525092cee5fSValentin Clement         fir::isa_complex(convert.res().getType())) {
526092cee5fSValentin Clement       // Special case: handle the conversion of a complex such that both the
527092cee5fSValentin Clement       // real and imaginary parts are converted together.
528092cee5fSValentin Clement       auto zero = mlir::ArrayAttr::get(convert.getContext(),
529092cee5fSValentin Clement                                        rewriter.getI32IntegerAttr(0));
530092cee5fSValentin Clement       auto one = mlir::ArrayAttr::get(convert.getContext(),
531092cee5fSValentin Clement                                       rewriter.getI32IntegerAttr(1));
532092cee5fSValentin Clement       auto ty = convertType(getComplexEleTy(convert.value().getType()));
533092cee5fSValentin Clement       auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, zero);
534092cee5fSValentin Clement       auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, one);
535092cee5fSValentin Clement       auto nt = convertType(getComplexEleTy(convert.res().getType()));
536092cee5fSValentin Clement       auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
537092cee5fSValentin Clement       auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(nt);
538092cee5fSValentin Clement       auto rc = convertFpToFp(rp, fromBits, toBits, nt);
539092cee5fSValentin Clement       auto ic = convertFpToFp(ip, fromBits, toBits, nt);
540092cee5fSValentin Clement       auto un = rewriter.create<mlir::LLVM::UndefOp>(loc, toTy);
541092cee5fSValentin Clement       auto i1 =
542092cee5fSValentin Clement           rewriter.create<mlir::LLVM::InsertValueOp>(loc, toTy, un, rc, zero);
543092cee5fSValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(convert, toTy, i1,
544092cee5fSValentin Clement                                                              ic, one);
545092cee5fSValentin Clement       return mlir::success();
546092cee5fSValentin Clement     }
547092cee5fSValentin Clement     // Floating point to floating point conversion.
548092cee5fSValentin Clement     if (isFloatingPointTy(fromTy)) {
549092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
550092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
551092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
552092cee5fSValentin Clement         auto v = convertFpToFp(op0, fromBits, toBits, toTy);
553092cee5fSValentin Clement         rewriter.replaceOp(convert, v);
554092cee5fSValentin Clement         return mlir::success();
555092cee5fSValentin Clement       }
556092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
557092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::FPToSIOp>(convert, toTy, op0);
558092cee5fSValentin Clement         return mlir::success();
559092cee5fSValentin Clement       }
560092cee5fSValentin Clement     } else if (fromTy.isa<mlir::IntegerType>()) {
561092cee5fSValentin Clement       // Integer to integer conversion.
562092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
563092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
564092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
565092cee5fSValentin Clement         assert(fromBits != toBits);
566092cee5fSValentin Clement         if (fromBits > toBits) {
567092cee5fSValentin Clement           rewriter.replaceOpWithNewOp<mlir::LLVM::TruncOp>(convert, toTy, op0);
568092cee5fSValentin Clement           return mlir::success();
569092cee5fSValentin Clement         }
570092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SExtOp>(convert, toTy, op0);
571092cee5fSValentin Clement         return mlir::success();
572092cee5fSValentin Clement       }
573092cee5fSValentin Clement       // Integer to floating point conversion.
574092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
575092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SIToFPOp>(convert, toTy, op0);
576092cee5fSValentin Clement         return mlir::success();
577092cee5fSValentin Clement       }
578092cee5fSValentin Clement       // Integer to pointer conversion.
579092cee5fSValentin Clement       if (toTy.isa<mlir::LLVM::LLVMPointerType>()) {
580092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(convert, toTy, op0);
581092cee5fSValentin Clement         return mlir::success();
582092cee5fSValentin Clement       }
583092cee5fSValentin Clement     } else if (fromTy.isa<mlir::LLVM::LLVMPointerType>()) {
584092cee5fSValentin Clement       // Pointer to integer conversion.
585092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
586092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::PtrToIntOp>(convert, toTy, op0);
587092cee5fSValentin Clement         return mlir::success();
588092cee5fSValentin Clement       }
589092cee5fSValentin Clement       // Pointer to pointer conversion.
590092cee5fSValentin Clement       if (toTy.isa<mlir::LLVM::LLVMPointerType>()) {
591092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(convert, toTy, op0);
592092cee5fSValentin Clement         return mlir::success();
593092cee5fSValentin Clement       }
594092cee5fSValentin Clement     }
595092cee5fSValentin Clement     return emitError(loc) << "cannot convert " << fromTy << " to " << toTy;
596092cee5fSValentin Clement   }
597092cee5fSValentin Clement };
598092cee5fSValentin Clement 
5999534e361SValentin Clement /// Lower `fir.dispatch` operation. A virtual call to a method in a dispatch
6009534e361SValentin Clement /// table.
6019534e361SValentin Clement struct DispatchOpConversion : public FIROpConversion<fir::DispatchOp> {
6029534e361SValentin Clement   using FIROpConversion::FIROpConversion;
6039534e361SValentin Clement 
6049534e361SValentin Clement   mlir::LogicalResult
6059534e361SValentin Clement   matchAndRewrite(fir::DispatchOp dispatch, OpAdaptor adaptor,
6069534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
6079534e361SValentin Clement     return rewriter.notifyMatchFailure(
6089534e361SValentin Clement         dispatch, "fir.dispatch codegen is not implemented yet");
6099534e361SValentin Clement   }
6109534e361SValentin Clement };
6119534e361SValentin Clement 
6129534e361SValentin Clement /// Lower `fir.dispatch_table` operation. The dispatch table for a Fortran
6139534e361SValentin Clement /// derived type.
6149534e361SValentin Clement struct DispatchTableOpConversion
6159534e361SValentin Clement     : public FIROpConversion<fir::DispatchTableOp> {
6169534e361SValentin Clement   using FIROpConversion::FIROpConversion;
6179534e361SValentin Clement 
6189534e361SValentin Clement   mlir::LogicalResult
6199534e361SValentin Clement   matchAndRewrite(fir::DispatchTableOp dispTab, OpAdaptor adaptor,
6209534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
6219534e361SValentin Clement     return rewriter.notifyMatchFailure(
6229534e361SValentin Clement         dispTab, "fir.dispatch_table codegen is not implemented yet");
6239534e361SValentin Clement   }
6249534e361SValentin Clement };
6259534e361SValentin Clement 
6269534e361SValentin Clement /// Lower `fir.dt_entry` operation. An entry in a dispatch table; binds a
6279534e361SValentin Clement /// method-name to a function.
6289534e361SValentin Clement struct DTEntryOpConversion : public FIROpConversion<fir::DTEntryOp> {
6299534e361SValentin Clement   using FIROpConversion::FIROpConversion;
6309534e361SValentin Clement 
6319534e361SValentin Clement   mlir::LogicalResult
6329534e361SValentin Clement   matchAndRewrite(fir::DTEntryOp dtEnt, OpAdaptor adaptor,
6339534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
6349534e361SValentin Clement     return rewriter.notifyMatchFailure(
6359534e361SValentin Clement         dtEnt, "fir.dt_entry codegen is not implemented yet");
6369534e361SValentin Clement   }
6379534e361SValentin Clement };
6389534e361SValentin Clement 
6390c4a7a52SValentin Clement /// Lower `fir.has_value` operation to `llvm.return` operation.
640044d5b5dSValentin Clement struct HasValueOpConversion : public FIROpConversion<fir::HasValueOp> {
641044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
642044d5b5dSValentin Clement 
643044d5b5dSValentin Clement   mlir::LogicalResult
644044d5b5dSValentin Clement   matchAndRewrite(fir::HasValueOp op, OpAdaptor adaptor,
645044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
646044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, adaptor.getOperands());
647044d5b5dSValentin Clement     return success();
648044d5b5dSValentin Clement   }
649044d5b5dSValentin Clement };
650044d5b5dSValentin Clement 
6510c4a7a52SValentin Clement /// Lower `fir.global` operation to `llvm.global` operation.
6520c4a7a52SValentin Clement /// `fir.insert_on_range` operations are replaced with constant dense attribute
6530c4a7a52SValentin Clement /// if they are applied on the full range.
654044d5b5dSValentin Clement struct GlobalOpConversion : public FIROpConversion<fir::GlobalOp> {
655044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
656044d5b5dSValentin Clement 
657044d5b5dSValentin Clement   mlir::LogicalResult
658044d5b5dSValentin Clement   matchAndRewrite(fir::GlobalOp global, OpAdaptor adaptor,
659044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
660044d5b5dSValentin Clement     auto tyAttr = convertType(global.getType());
661044d5b5dSValentin Clement     if (global.getType().isa<fir::BoxType>())
662044d5b5dSValentin Clement       tyAttr = tyAttr.cast<mlir::LLVM::LLVMPointerType>().getElementType();
663044d5b5dSValentin Clement     auto loc = global.getLoc();
664044d5b5dSValentin Clement     mlir::Attribute initAttr{};
665044d5b5dSValentin Clement     if (global.initVal())
666044d5b5dSValentin Clement       initAttr = global.initVal().getValue();
667044d5b5dSValentin Clement     auto linkage = convertLinkage(global.linkName());
668044d5b5dSValentin Clement     auto isConst = global.constant().hasValue();
669044d5b5dSValentin Clement     auto g = rewriter.create<mlir::LLVM::GlobalOp>(
670044d5b5dSValentin Clement         loc, tyAttr, isConst, linkage, global.sym_name(), initAttr);
671044d5b5dSValentin Clement     auto &gr = g.getInitializerRegion();
672044d5b5dSValentin Clement     rewriter.inlineRegionBefore(global.region(), gr, gr.end());
673044d5b5dSValentin Clement     if (!gr.empty()) {
674044d5b5dSValentin Clement       // Replace insert_on_range with a constant dense attribute if the
675044d5b5dSValentin Clement       // initialization is on the full range.
676044d5b5dSValentin Clement       auto insertOnRangeOps = gr.front().getOps<fir::InsertOnRangeOp>();
677044d5b5dSValentin Clement       for (auto insertOp : insertOnRangeOps) {
678044d5b5dSValentin Clement         if (isFullRange(insertOp.coor(), insertOp.getType())) {
679044d5b5dSValentin Clement           auto seqTyAttr = convertType(insertOp.getType());
680044d5b5dSValentin Clement           auto *op = insertOp.val().getDefiningOp();
681044d5b5dSValentin Clement           auto constant = mlir::dyn_cast<mlir::arith::ConstantOp>(op);
682044d5b5dSValentin Clement           if (!constant) {
683044d5b5dSValentin Clement             auto convertOp = mlir::dyn_cast<fir::ConvertOp>(op);
684044d5b5dSValentin Clement             if (!convertOp)
685044d5b5dSValentin Clement               continue;
686044d5b5dSValentin Clement             constant = cast<mlir::arith::ConstantOp>(
687044d5b5dSValentin Clement                 convertOp.value().getDefiningOp());
688044d5b5dSValentin Clement           }
689044d5b5dSValentin Clement           mlir::Type vecType = mlir::VectorType::get(
690044d5b5dSValentin Clement               insertOp.getType().getShape(), constant.getType());
691044d5b5dSValentin Clement           auto denseAttr = mlir::DenseElementsAttr::get(
692044d5b5dSValentin Clement               vecType.cast<ShapedType>(), constant.value());
693044d5b5dSValentin Clement           rewriter.setInsertionPointAfter(insertOp);
694044d5b5dSValentin Clement           rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(
695044d5b5dSValentin Clement               insertOp, seqTyAttr, denseAttr);
696044d5b5dSValentin Clement         }
697044d5b5dSValentin Clement       }
698044d5b5dSValentin Clement     }
699044d5b5dSValentin Clement     rewriter.eraseOp(global);
700044d5b5dSValentin Clement     return success();
701044d5b5dSValentin Clement   }
702044d5b5dSValentin Clement 
703044d5b5dSValentin Clement   bool isFullRange(mlir::ArrayAttr indexes, fir::SequenceType seqTy) const {
704044d5b5dSValentin Clement     auto extents = seqTy.getShape();
705044d5b5dSValentin Clement     if (indexes.size() / 2 != extents.size())
706044d5b5dSValentin Clement       return false;
707044d5b5dSValentin Clement     for (unsigned i = 0; i < indexes.size(); i += 2) {
708044d5b5dSValentin Clement       if (indexes[i].cast<IntegerAttr>().getInt() != 0)
709044d5b5dSValentin Clement         return false;
710044d5b5dSValentin Clement       if (indexes[i + 1].cast<IntegerAttr>().getInt() != extents[i / 2] - 1)
711044d5b5dSValentin Clement         return false;
712044d5b5dSValentin Clement     }
713044d5b5dSValentin Clement     return true;
714044d5b5dSValentin Clement   }
715044d5b5dSValentin Clement 
7160c4a7a52SValentin Clement   // TODO: String comparaison should be avoided. Replace linkName with an
7170c4a7a52SValentin Clement   // enumeration.
718044d5b5dSValentin Clement   mlir::LLVM::Linkage convertLinkage(Optional<StringRef> optLinkage) const {
719044d5b5dSValentin Clement     if (optLinkage.hasValue()) {
720044d5b5dSValentin Clement       auto name = optLinkage.getValue();
721044d5b5dSValentin Clement       if (name == "internal")
722044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Internal;
723044d5b5dSValentin Clement       if (name == "linkonce")
724044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Linkonce;
725044d5b5dSValentin Clement       if (name == "common")
726044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Common;
727044d5b5dSValentin Clement       if (name == "weak")
728044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Weak;
729044d5b5dSValentin Clement     }
730044d5b5dSValentin Clement     return mlir::LLVM::Linkage::External;
731044d5b5dSValentin Clement   }
732044d5b5dSValentin Clement };
733044d5b5dSValentin Clement 
73439f4ef81SValentin Clement void genCondBrOp(mlir::Location loc, mlir::Value cmp, mlir::Block *dest,
73539f4ef81SValentin Clement                  Optional<mlir::ValueRange> destOps,
73639f4ef81SValentin Clement                  mlir::ConversionPatternRewriter &rewriter,
73739f4ef81SValentin Clement                  mlir::Block *newBlock) {
73839f4ef81SValentin Clement   if (destOps.hasValue())
73939f4ef81SValentin Clement     rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, destOps.getValue(),
74039f4ef81SValentin Clement                                           newBlock, mlir::ValueRange());
74139f4ef81SValentin Clement   else
74239f4ef81SValentin Clement     rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, newBlock);
74339f4ef81SValentin Clement }
74439f4ef81SValentin Clement 
74539f4ef81SValentin Clement template <typename A, typename B>
74639f4ef81SValentin Clement void genBrOp(A caseOp, mlir::Block *dest, Optional<B> destOps,
74739f4ef81SValentin Clement              mlir::ConversionPatternRewriter &rewriter) {
74839f4ef81SValentin Clement   if (destOps.hasValue())
74939f4ef81SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, destOps.getValue(),
75039f4ef81SValentin Clement                                                   dest);
75139f4ef81SValentin Clement   else
75239f4ef81SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, llvm::None, dest);
75339f4ef81SValentin Clement }
75439f4ef81SValentin Clement 
75539f4ef81SValentin Clement void genCaseLadderStep(mlir::Location loc, mlir::Value cmp, mlir::Block *dest,
75639f4ef81SValentin Clement                        Optional<mlir::ValueRange> destOps,
75739f4ef81SValentin Clement                        mlir::ConversionPatternRewriter &rewriter) {
75839f4ef81SValentin Clement   auto *thisBlock = rewriter.getInsertionBlock();
75939f4ef81SValentin Clement   auto *newBlock = createBlock(rewriter, dest);
76039f4ef81SValentin Clement   rewriter.setInsertionPointToEnd(thisBlock);
76139f4ef81SValentin Clement   genCondBrOp(loc, cmp, dest, destOps, rewriter, newBlock);
76239f4ef81SValentin Clement   rewriter.setInsertionPointToEnd(newBlock);
76339f4ef81SValentin Clement }
76439f4ef81SValentin Clement 
76539f4ef81SValentin Clement /// Conversion of `fir.select_case`
76639f4ef81SValentin Clement ///
76739f4ef81SValentin Clement /// The `fir.select_case` operation is converted to a if-then-else ladder.
76839f4ef81SValentin Clement /// Depending on the case condition type, one or several comparison and
76939f4ef81SValentin Clement /// conditional branching can be generated.
77039f4ef81SValentin Clement ///
77139f4ef81SValentin Clement /// A a point value case such as `case(4)`, a lower bound case such as
77239f4ef81SValentin Clement /// `case(5:)` or an upper bound case such as `case(:3)` are converted to a
77339f4ef81SValentin Clement /// simple comparison between the selector value and the constant value in the
77439f4ef81SValentin Clement /// case. The block associated with the case condition is then executed if
77539f4ef81SValentin Clement /// the comparison succeed otherwise it branch to the next block with the
77639f4ef81SValentin Clement /// comparison for the the next case conditon.
77739f4ef81SValentin Clement ///
77839f4ef81SValentin Clement /// A closed interval case condition such as `case(7:10)` is converted with a
77939f4ef81SValentin Clement /// first comparison and conditional branching for the lower bound. If
78039f4ef81SValentin Clement /// successful, it branch to a second block with the comparison for the
78139f4ef81SValentin Clement /// upper bound in the same case condition.
78239f4ef81SValentin Clement ///
78339f4ef81SValentin Clement /// TODO: lowering of CHARACTER type cases is not handled yet.
78439f4ef81SValentin Clement struct SelectCaseOpConversion : public FIROpConversion<fir::SelectCaseOp> {
78539f4ef81SValentin Clement   using FIROpConversion::FIROpConversion;
78639f4ef81SValentin Clement 
78739f4ef81SValentin Clement   mlir::LogicalResult
78839f4ef81SValentin Clement   matchAndRewrite(fir::SelectCaseOp caseOp, OpAdaptor adaptor,
78939f4ef81SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
79039f4ef81SValentin Clement     unsigned conds = caseOp.getNumConditions();
79139f4ef81SValentin Clement     llvm::ArrayRef<mlir::Attribute> cases = caseOp.getCases().getValue();
79239f4ef81SValentin Clement     // Type can be CHARACTER, INTEGER, or LOGICAL (C1145)
79339f4ef81SValentin Clement     LLVM_ATTRIBUTE_UNUSED auto ty = caseOp.getSelector().getType();
79439f4ef81SValentin Clement     if (ty.isa<fir::CharacterType>())
79539f4ef81SValentin Clement       return rewriter.notifyMatchFailure(caseOp,
79639f4ef81SValentin Clement                                          "conversion of fir.select_case with "
79739f4ef81SValentin Clement                                          "character type not implemented yet");
79839f4ef81SValentin Clement     mlir::Value selector = caseOp.getSelector(adaptor.getOperands());
79939f4ef81SValentin Clement     auto loc = caseOp.getLoc();
80039f4ef81SValentin Clement     for (unsigned t = 0; t != conds; ++t) {
80139f4ef81SValentin Clement       mlir::Block *dest = caseOp.getSuccessor(t);
80239f4ef81SValentin Clement       llvm::Optional<mlir::ValueRange> destOps =
80339f4ef81SValentin Clement           caseOp.getSuccessorOperands(adaptor.getOperands(), t);
80439f4ef81SValentin Clement       llvm::Optional<mlir::ValueRange> cmpOps =
80539f4ef81SValentin Clement           *caseOp.getCompareOperands(adaptor.getOperands(), t);
80639f4ef81SValentin Clement       mlir::Value caseArg = *(cmpOps.getValue().begin());
80739f4ef81SValentin Clement       mlir::Attribute attr = cases[t];
80839f4ef81SValentin Clement       if (attr.isa<fir::PointIntervalAttr>()) {
80939f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
81039f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::eq, selector, caseArg);
81139f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
81239f4ef81SValentin Clement         continue;
81339f4ef81SValentin Clement       }
81439f4ef81SValentin Clement       if (attr.isa<fir::LowerBoundAttr>()) {
81539f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
81639f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector);
81739f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
81839f4ef81SValentin Clement         continue;
81939f4ef81SValentin Clement       }
82039f4ef81SValentin Clement       if (attr.isa<fir::UpperBoundAttr>()) {
82139f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
82239f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg);
82339f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
82439f4ef81SValentin Clement         continue;
82539f4ef81SValentin Clement       }
82639f4ef81SValentin Clement       if (attr.isa<fir::ClosedIntervalAttr>()) {
82739f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
82839f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector);
82939f4ef81SValentin Clement         auto *thisBlock = rewriter.getInsertionBlock();
83039f4ef81SValentin Clement         auto *newBlock1 = createBlock(rewriter, dest);
83139f4ef81SValentin Clement         auto *newBlock2 = createBlock(rewriter, dest);
83239f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(thisBlock);
83339f4ef81SValentin Clement         rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, newBlock1, newBlock2);
83439f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(newBlock1);
83539f4ef81SValentin Clement         mlir::Value caseArg0 = *(cmpOps.getValue().begin() + 1);
83639f4ef81SValentin Clement         auto cmp0 = rewriter.create<mlir::LLVM::ICmpOp>(
83739f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg0);
83839f4ef81SValentin Clement         genCondBrOp(loc, cmp0, dest, destOps, rewriter, newBlock2);
83939f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(newBlock2);
84039f4ef81SValentin Clement         continue;
84139f4ef81SValentin Clement       }
84239f4ef81SValentin Clement       assert(attr.isa<mlir::UnitAttr>());
84339f4ef81SValentin Clement       assert((t + 1 == conds) && "unit must be last");
84439f4ef81SValentin Clement       genBrOp(caseOp, dest, destOps, rewriter);
84539f4ef81SValentin Clement     }
84639f4ef81SValentin Clement     return success();
84739f4ef81SValentin Clement   }
84839f4ef81SValentin Clement };
84939f4ef81SValentin Clement 
8508c239909SValentin Clement template <typename OP>
8518c239909SValentin Clement void selectMatchAndRewrite(fir::LLVMTypeConverter &lowering, OP select,
8528c239909SValentin Clement                            typename OP::Adaptor adaptor,
8538c239909SValentin Clement                            mlir::ConversionPatternRewriter &rewriter) {
8548c239909SValentin Clement   unsigned conds = select.getNumConditions();
8558c239909SValentin Clement   auto cases = select.getCases().getValue();
8568c239909SValentin Clement   mlir::Value selector = adaptor.selector();
8578c239909SValentin Clement   auto loc = select.getLoc();
8588c239909SValentin Clement   assert(conds > 0 && "select must have cases");
8598c239909SValentin Clement 
8608c239909SValentin Clement   llvm::SmallVector<mlir::Block *> destinations;
8618c239909SValentin Clement   llvm::SmallVector<mlir::ValueRange> destinationsOperands;
8628c239909SValentin Clement   mlir::Block *defaultDestination;
8638c239909SValentin Clement   mlir::ValueRange defaultOperands;
8648c239909SValentin Clement   llvm::SmallVector<int32_t> caseValues;
8658c239909SValentin Clement 
8668c239909SValentin Clement   for (unsigned t = 0; t != conds; ++t) {
8678c239909SValentin Clement     mlir::Block *dest = select.getSuccessor(t);
8688c239909SValentin Clement     auto destOps = select.getSuccessorOperands(adaptor.getOperands(), t);
8698c239909SValentin Clement     const mlir::Attribute &attr = cases[t];
8708c239909SValentin Clement     if (auto intAttr = attr.template dyn_cast<mlir::IntegerAttr>()) {
8718c239909SValentin Clement       destinations.push_back(dest);
8728c239909SValentin Clement       destinationsOperands.push_back(destOps.hasValue() ? *destOps
8738c239909SValentin Clement                                                         : ValueRange());
8748c239909SValentin Clement       caseValues.push_back(intAttr.getInt());
8758c239909SValentin Clement       continue;
8768c239909SValentin Clement     }
8778c239909SValentin Clement     assert(attr.template dyn_cast_or_null<mlir::UnitAttr>());
8788c239909SValentin Clement     assert((t + 1 == conds) && "unit must be last");
8798c239909SValentin Clement     defaultDestination = dest;
8808c239909SValentin Clement     defaultOperands = destOps.hasValue() ? *destOps : ValueRange();
8818c239909SValentin Clement   }
8828c239909SValentin Clement 
8838c239909SValentin Clement   // LLVM::SwitchOp takes a i32 type for the selector.
8848c239909SValentin Clement   if (select.getSelector().getType() != rewriter.getI32Type())
8858c239909SValentin Clement     selector =
8868c239909SValentin Clement         rewriter.create<LLVM::TruncOp>(loc, rewriter.getI32Type(), selector);
8878c239909SValentin Clement 
8888c239909SValentin Clement   rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>(
8898c239909SValentin Clement       select, selector,
8908c239909SValentin Clement       /*defaultDestination=*/defaultDestination,
8918c239909SValentin Clement       /*defaultOperands=*/defaultOperands,
8928c239909SValentin Clement       /*caseValues=*/caseValues,
8938c239909SValentin Clement       /*caseDestinations=*/destinations,
8948c239909SValentin Clement       /*caseOperands=*/destinationsOperands,
8958c239909SValentin Clement       /*branchWeights=*/ArrayRef<int32_t>());
8968c239909SValentin Clement }
8978c239909SValentin Clement 
8988c239909SValentin Clement /// conversion of fir::SelectOp to an if-then-else ladder
8998c239909SValentin Clement struct SelectOpConversion : public FIROpConversion<fir::SelectOp> {
9008c239909SValentin Clement   using FIROpConversion::FIROpConversion;
9018c239909SValentin Clement 
9028c239909SValentin Clement   mlir::LogicalResult
9038c239909SValentin Clement   matchAndRewrite(fir::SelectOp op, OpAdaptor adaptor,
9048c239909SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
9058c239909SValentin Clement     selectMatchAndRewrite<fir::SelectOp>(lowerTy(), op, adaptor, rewriter);
9068c239909SValentin Clement     return success();
9078c239909SValentin Clement   }
9088c239909SValentin Clement };
9098c239909SValentin Clement 
910e3349fa1SAndrzej Warzynski /// `fir.load` --> `llvm.load`
911e3349fa1SAndrzej Warzynski struct LoadOpConversion : public FIROpConversion<fir::LoadOp> {
912e3349fa1SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
913e3349fa1SAndrzej Warzynski 
914e3349fa1SAndrzej Warzynski   mlir::LogicalResult
915e3349fa1SAndrzej Warzynski   matchAndRewrite(fir::LoadOp load, OpAdaptor adaptor,
916e3349fa1SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
917e3349fa1SAndrzej Warzynski     // fir.box is a special case because it is considered as an ssa values in
918e3349fa1SAndrzej Warzynski     // fir, but it is lowered as a pointer to a descriptor. So fir.ref<fir.box>
919e3349fa1SAndrzej Warzynski     // and fir.box end up being the same llvm types and loading a
920e3349fa1SAndrzej Warzynski     // fir.ref<fir.box> is actually a no op in LLVM.
921e3349fa1SAndrzej Warzynski     if (load.getType().isa<fir::BoxType>()) {
922e3349fa1SAndrzej Warzynski       rewriter.replaceOp(load, adaptor.getOperands()[0]);
923e3349fa1SAndrzej Warzynski     } else {
924e3349fa1SAndrzej Warzynski       mlir::Type ty = convertType(load.getType());
925e3349fa1SAndrzej Warzynski       ArrayRef<NamedAttribute> at = load->getAttrs();
926e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::LoadOp>(
927e3349fa1SAndrzej Warzynski           load, ty, adaptor.getOperands(), at);
928e3349fa1SAndrzej Warzynski     }
929e3349fa1SAndrzej Warzynski     return success();
930e3349fa1SAndrzej Warzynski   }
931e3349fa1SAndrzej Warzynski };
932e3349fa1SAndrzej Warzynski 
9332a299e4fSValentin Clement /// Lower `fir.select_type` to LLVM IR dialect.
9342a299e4fSValentin Clement struct SelectTypeOpConversion : public FIROpConversion<fir::SelectTypeOp> {
9352a299e4fSValentin Clement   using FIROpConversion::FIROpConversion;
9362a299e4fSValentin Clement 
9372a299e4fSValentin Clement   mlir::LogicalResult
9382a299e4fSValentin Clement   matchAndRewrite(fir::SelectTypeOp select, OpAdaptor adaptor,
9392a299e4fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
9402a299e4fSValentin Clement     return rewriter.notifyMatchFailure(
9412a299e4fSValentin Clement         select, "fir.select_type codegen is not implemented yet");
9422a299e4fSValentin Clement   }
9432a299e4fSValentin Clement };
9442a299e4fSValentin Clement 
9458c239909SValentin Clement /// conversion of fir::SelectRankOp to an if-then-else ladder
9468c239909SValentin Clement struct SelectRankOpConversion : public FIROpConversion<fir::SelectRankOp> {
9478c239909SValentin Clement   using FIROpConversion::FIROpConversion;
9488c239909SValentin Clement 
9498c239909SValentin Clement   mlir::LogicalResult
9508c239909SValentin Clement   matchAndRewrite(fir::SelectRankOp op, OpAdaptor adaptor,
9518c239909SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
9528c239909SValentin Clement     selectMatchAndRewrite<fir::SelectRankOp>(lowerTy(), op, adaptor, rewriter);
9538c239909SValentin Clement     return success();
9548c239909SValentin Clement   }
9558c239909SValentin Clement };
9568c239909SValentin Clement 
957e3349fa1SAndrzej Warzynski /// `fir.store` --> `llvm.store`
958e3349fa1SAndrzej Warzynski struct StoreOpConversion : public FIROpConversion<fir::StoreOp> {
959e3349fa1SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
960e3349fa1SAndrzej Warzynski 
961e3349fa1SAndrzej Warzynski   mlir::LogicalResult
962e3349fa1SAndrzej Warzynski   matchAndRewrite(fir::StoreOp store, OpAdaptor adaptor,
963e3349fa1SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
964e3349fa1SAndrzej Warzynski     if (store.value().getType().isa<fir::BoxType>()) {
965e3349fa1SAndrzej Warzynski       // fir.box value is actually in memory, load it first before storing it.
966e3349fa1SAndrzej Warzynski       mlir::Location loc = store.getLoc();
967e3349fa1SAndrzej Warzynski       mlir::Type boxPtrTy = adaptor.getOperands()[0].getType();
968e3349fa1SAndrzej Warzynski       auto val = rewriter.create<mlir::LLVM::LoadOp>(
969e3349fa1SAndrzej Warzynski           loc, boxPtrTy.cast<mlir::LLVM::LLVMPointerType>().getElementType(),
970e3349fa1SAndrzej Warzynski           adaptor.getOperands()[0]);
971e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
972e3349fa1SAndrzej Warzynski           store, val, adaptor.getOperands()[1]);
973e3349fa1SAndrzej Warzynski     } else {
974e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
975e3349fa1SAndrzej Warzynski           store, adaptor.getOperands()[0], adaptor.getOperands()[1]);
976e3349fa1SAndrzej Warzynski     }
977e3349fa1SAndrzej Warzynski     return success();
978e3349fa1SAndrzej Warzynski   }
979e3349fa1SAndrzej Warzynski };
980e3349fa1SAndrzej Warzynski 
981e3349fa1SAndrzej Warzynski /// convert to LLVM IR dialect `undef`
982044d5b5dSValentin Clement struct UndefOpConversion : public FIROpConversion<fir::UndefOp> {
983044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
984044d5b5dSValentin Clement 
985044d5b5dSValentin Clement   mlir::LogicalResult
986044d5b5dSValentin Clement   matchAndRewrite(fir::UndefOp undef, OpAdaptor,
987044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
988044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::UndefOp>(
989044d5b5dSValentin Clement         undef, convertType(undef.getType()));
990044d5b5dSValentin Clement     return success();
991044d5b5dSValentin Clement   }
992044d5b5dSValentin Clement };
993a7a61359SValentin Clement 
994e3349fa1SAndrzej Warzynski /// `fir.unreachable` --> `llvm.unreachable`
99532e08248SAndrzej Warzynski struct UnreachableOpConversion : public FIROpConversion<fir::UnreachableOp> {
99632e08248SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
99732e08248SAndrzej Warzynski 
99832e08248SAndrzej Warzynski   mlir::LogicalResult
99932e08248SAndrzej Warzynski   matchAndRewrite(fir::UnreachableOp unreach, OpAdaptor adaptor,
100032e08248SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
100132e08248SAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(unreach);
100232e08248SAndrzej Warzynski     return success();
100332e08248SAndrzej Warzynski   }
100432e08248SAndrzej Warzynski };
100532e08248SAndrzej Warzynski 
1006a7a61359SValentin Clement struct ZeroOpConversion : public FIROpConversion<fir::ZeroOp> {
1007a7a61359SValentin Clement   using FIROpConversion::FIROpConversion;
1008a7a61359SValentin Clement 
1009a7a61359SValentin Clement   mlir::LogicalResult
1010a7a61359SValentin Clement   matchAndRewrite(fir::ZeroOp zero, OpAdaptor,
1011a7a61359SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1012a7a61359SValentin Clement     auto ty = convertType(zero.getType());
1013a7a61359SValentin Clement     if (ty.isa<mlir::LLVM::LLVMPointerType>()) {
1014a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(zero, ty);
1015a7a61359SValentin Clement     } else if (ty.isa<mlir::IntegerType>()) {
1016a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
1017a7a61359SValentin Clement           zero, ty, mlir::IntegerAttr::get(zero.getType(), 0));
1018a7a61359SValentin Clement     } else if (mlir::LLVM::isCompatibleFloatingPointType(ty)) {
1019a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
1020a7a61359SValentin Clement           zero, ty, mlir::FloatAttr::get(zero.getType(), 0.0));
1021a7a61359SValentin Clement     } else {
1022a7a61359SValentin Clement       // TODO: create ConstantAggregateZero for FIR aggregate/array types.
102352d813edSValentin Clement       return rewriter.notifyMatchFailure(
102452d813edSValentin Clement           zero,
1025a7a61359SValentin Clement           "conversion of fir.zero with aggregate type not implemented yet");
1026a7a61359SValentin Clement     }
1027a7a61359SValentin Clement     return success();
1028a7a61359SValentin Clement   }
1029a7a61359SValentin Clement };
103032e08248SAndrzej Warzynski 
103154c56347SValentin Clement // Code shared between insert_value and extract_value Ops.
103254c56347SValentin Clement struct ValueOpCommon {
103354c56347SValentin Clement   // Translate the arguments pertaining to any multidimensional array to
103454c56347SValentin Clement   // row-major order for LLVM-IR.
103554c56347SValentin Clement   static void toRowMajor(SmallVectorImpl<mlir::Attribute> &attrs,
103654c56347SValentin Clement                          mlir::Type ty) {
103754c56347SValentin Clement     assert(ty && "type is null");
103854c56347SValentin Clement     const auto end = attrs.size();
103954c56347SValentin Clement     for (std::remove_const_t<decltype(end)> i = 0; i < end; ++i) {
104054c56347SValentin Clement       if (auto seq = ty.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
104154c56347SValentin Clement         const auto dim = getDimension(seq);
104254c56347SValentin Clement         if (dim > 1) {
104354c56347SValentin Clement           auto ub = std::min(i + dim, end);
104454c56347SValentin Clement           std::reverse(attrs.begin() + i, attrs.begin() + ub);
104554c56347SValentin Clement           i += dim - 1;
104654c56347SValentin Clement         }
104754c56347SValentin Clement         ty = getArrayElementType(seq);
104854c56347SValentin Clement       } else if (auto st = ty.dyn_cast<mlir::LLVM::LLVMStructType>()) {
104954c56347SValentin Clement         ty = st.getBody()[attrs[i].cast<mlir::IntegerAttr>().getInt()];
105054c56347SValentin Clement       } else {
105154c56347SValentin Clement         llvm_unreachable("index into invalid type");
105254c56347SValentin Clement       }
105354c56347SValentin Clement     }
105454c56347SValentin Clement   }
105554c56347SValentin Clement 
105654c56347SValentin Clement   static llvm::SmallVector<mlir::Attribute>
105754c56347SValentin Clement   collectIndices(mlir::ConversionPatternRewriter &rewriter,
105854c56347SValentin Clement                  mlir::ArrayAttr arrAttr) {
105954c56347SValentin Clement     llvm::SmallVector<mlir::Attribute> attrs;
106054c56347SValentin Clement     for (auto i = arrAttr.begin(), e = arrAttr.end(); i != e; ++i) {
106154c56347SValentin Clement       if (i->isa<mlir::IntegerAttr>()) {
106254c56347SValentin Clement         attrs.push_back(*i);
106354c56347SValentin Clement       } else {
106454c56347SValentin Clement         auto fieldName = i->cast<mlir::StringAttr>().getValue();
106554c56347SValentin Clement         ++i;
106654c56347SValentin Clement         auto ty = i->cast<mlir::TypeAttr>().getValue();
106754c56347SValentin Clement         auto index = ty.cast<fir::RecordType>().getFieldIndex(fieldName);
106854c56347SValentin Clement         attrs.push_back(mlir::IntegerAttr::get(rewriter.getI32Type(), index));
106954c56347SValentin Clement       }
107054c56347SValentin Clement     }
107154c56347SValentin Clement     return attrs;
107254c56347SValentin Clement   }
107354c56347SValentin Clement 
107454c56347SValentin Clement private:
107554c56347SValentin Clement   static unsigned getDimension(mlir::LLVM::LLVMArrayType ty) {
107654c56347SValentin Clement     unsigned result = 1;
107754c56347SValentin Clement     for (auto eleTy = ty.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>();
107854c56347SValentin Clement          eleTy;
107954c56347SValentin Clement          eleTy = eleTy.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>())
108054c56347SValentin Clement       ++result;
108154c56347SValentin Clement     return result;
108254c56347SValentin Clement   }
108354c56347SValentin Clement 
108454c56347SValentin Clement   static mlir::Type getArrayElementType(mlir::LLVM::LLVMArrayType ty) {
108554c56347SValentin Clement     auto eleTy = ty.getElementType();
108654c56347SValentin Clement     while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>())
108754c56347SValentin Clement       eleTy = arrTy.getElementType();
108854c56347SValentin Clement     return eleTy;
108954c56347SValentin Clement   }
109054c56347SValentin Clement };
109154c56347SValentin Clement 
109254c56347SValentin Clement /// Extract a subobject value from an ssa-value of aggregate type
109354c56347SValentin Clement struct ExtractValueOpConversion
109454c56347SValentin Clement     : public FIROpAndTypeConversion<fir::ExtractValueOp>,
109554c56347SValentin Clement       public ValueOpCommon {
109654c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
109754c56347SValentin Clement 
109854c56347SValentin Clement   mlir::LogicalResult
109954c56347SValentin Clement   doRewrite(fir::ExtractValueOp extractVal, mlir::Type ty, OpAdaptor adaptor,
110054c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
110154c56347SValentin Clement     auto attrs = collectIndices(rewriter, extractVal.coor());
110254c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
110354c56347SValentin Clement     auto position = mlir::ArrayAttr::get(extractVal.getContext(), attrs);
110454c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(
110554c56347SValentin Clement         extractVal, ty, adaptor.getOperands()[0], position);
110654c56347SValentin Clement     return success();
110754c56347SValentin Clement   }
110854c56347SValentin Clement };
110954c56347SValentin Clement 
111054c56347SValentin Clement /// InsertValue is the generalized instruction for the composition of new
111154c56347SValentin Clement /// aggregate type values.
111254c56347SValentin Clement struct InsertValueOpConversion
111354c56347SValentin Clement     : public FIROpAndTypeConversion<fir::InsertValueOp>,
111454c56347SValentin Clement       public ValueOpCommon {
111554c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
111654c56347SValentin Clement 
111754c56347SValentin Clement   mlir::LogicalResult
111854c56347SValentin Clement   doRewrite(fir::InsertValueOp insertVal, mlir::Type ty, OpAdaptor adaptor,
111954c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
112054c56347SValentin Clement     auto attrs = collectIndices(rewriter, insertVal.coor());
112154c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
112254c56347SValentin Clement     auto position = mlir::ArrayAttr::get(insertVal.getContext(), attrs);
112354c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
112454c56347SValentin Clement         insertVal, ty, adaptor.getOperands()[0], adaptor.getOperands()[1],
112554c56347SValentin Clement         position);
112654c56347SValentin Clement     return success();
112754c56347SValentin Clement   }
112854c56347SValentin Clement };
112954c56347SValentin Clement 
11303ae8e442SValentin Clement /// InsertOnRange inserts a value into a sequence over a range of offsets.
11313ae8e442SValentin Clement struct InsertOnRangeOpConversion
11323ae8e442SValentin Clement     : public FIROpAndTypeConversion<fir::InsertOnRangeOp> {
11333ae8e442SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
11343ae8e442SValentin Clement 
11353ae8e442SValentin Clement   // Increments an array of subscripts in a row major fasion.
11363ae8e442SValentin Clement   void incrementSubscripts(const SmallVector<uint64_t> &dims,
11373ae8e442SValentin Clement                            SmallVector<uint64_t> &subscripts) const {
11383ae8e442SValentin Clement     for (size_t i = dims.size(); i > 0; --i) {
11393ae8e442SValentin Clement       if (++subscripts[i - 1] < dims[i - 1]) {
11403ae8e442SValentin Clement         return;
11413ae8e442SValentin Clement       }
11423ae8e442SValentin Clement       subscripts[i - 1] = 0;
11433ae8e442SValentin Clement     }
11443ae8e442SValentin Clement   }
11453ae8e442SValentin Clement 
11463ae8e442SValentin Clement   mlir::LogicalResult
11473ae8e442SValentin Clement   doRewrite(fir::InsertOnRangeOp range, mlir::Type ty, OpAdaptor adaptor,
11483ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
11493ae8e442SValentin Clement 
11503ae8e442SValentin Clement     llvm::SmallVector<uint64_t> dims;
11513ae8e442SValentin Clement     auto type = adaptor.getOperands()[0].getType();
11523ae8e442SValentin Clement 
11533ae8e442SValentin Clement     // Iteratively extract the array dimensions from the type.
11543ae8e442SValentin Clement     while (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
11553ae8e442SValentin Clement       dims.push_back(t.getNumElements());
11563ae8e442SValentin Clement       type = t.getElementType();
11573ae8e442SValentin Clement     }
11583ae8e442SValentin Clement 
11593ae8e442SValentin Clement     SmallVector<uint64_t> lBounds;
11603ae8e442SValentin Clement     SmallVector<uint64_t> uBounds;
11613ae8e442SValentin Clement 
11623ae8e442SValentin Clement     // Extract integer value from the attribute
11633ae8e442SValentin Clement     SmallVector<int64_t> coordinates = llvm::to_vector<4>(
11643ae8e442SValentin Clement         llvm::map_range(range.coor(), [](Attribute a) -> int64_t {
11653ae8e442SValentin Clement           return a.cast<IntegerAttr>().getInt();
11663ae8e442SValentin Clement         }));
11673ae8e442SValentin Clement 
11683ae8e442SValentin Clement     // Unzip the upper and lower bound and convert to a row major format.
11693ae8e442SValentin Clement     for (auto i = coordinates.rbegin(), e = coordinates.rend(); i != e; ++i) {
11703ae8e442SValentin Clement       uBounds.push_back(*i++);
11713ae8e442SValentin Clement       lBounds.push_back(*i);
11723ae8e442SValentin Clement     }
11733ae8e442SValentin Clement 
11743ae8e442SValentin Clement     auto &subscripts = lBounds;
11753ae8e442SValentin Clement     auto loc = range.getLoc();
11763ae8e442SValentin Clement     mlir::Value lastOp = adaptor.getOperands()[0];
11773ae8e442SValentin Clement     mlir::Value insertVal = adaptor.getOperands()[1];
11783ae8e442SValentin Clement 
11793ae8e442SValentin Clement     auto i64Ty = rewriter.getI64Type();
11803ae8e442SValentin Clement     while (subscripts != uBounds) {
11813ae8e442SValentin Clement       // Convert uint64_t's to Attribute's.
11823ae8e442SValentin Clement       SmallVector<mlir::Attribute> subscriptAttrs;
11833ae8e442SValentin Clement       for (const auto &subscript : subscripts)
11843ae8e442SValentin Clement         subscriptAttrs.push_back(IntegerAttr::get(i64Ty, subscript));
11853ae8e442SValentin Clement       lastOp = rewriter.create<mlir::LLVM::InsertValueOp>(
11863ae8e442SValentin Clement           loc, ty, lastOp, insertVal,
11873ae8e442SValentin Clement           ArrayAttr::get(range.getContext(), subscriptAttrs));
11883ae8e442SValentin Clement 
11893ae8e442SValentin Clement       incrementSubscripts(dims, subscripts);
11903ae8e442SValentin Clement     }
11913ae8e442SValentin Clement 
11923ae8e442SValentin Clement     // Convert uint64_t's to Attribute's.
11933ae8e442SValentin Clement     SmallVector<mlir::Attribute> subscriptAttrs;
11943ae8e442SValentin Clement     for (const auto &subscript : subscripts)
11953ae8e442SValentin Clement       subscriptAttrs.push_back(
11963ae8e442SValentin Clement           IntegerAttr::get(rewriter.getI64Type(), subscript));
11973ae8e442SValentin Clement     mlir::ArrayRef<mlir::Attribute> arrayRef(subscriptAttrs);
11983ae8e442SValentin Clement 
11993ae8e442SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
12003ae8e442SValentin Clement         range, ty, lastOp, insertVal,
12013ae8e442SValentin Clement         ArrayAttr::get(range.getContext(), arrayRef));
12023ae8e442SValentin Clement 
12033ae8e442SValentin Clement     return success();
12043ae8e442SValentin Clement   }
12053ae8e442SValentin Clement };
12067b5132daSValentin Clement 
12077b5132daSValentin Clement //
12087b5132daSValentin Clement // Primitive operations on Complex types
12097b5132daSValentin Clement //
12107b5132daSValentin Clement 
12117b5132daSValentin Clement /// Generate inline code for complex addition/subtraction
12127b5132daSValentin Clement template <typename LLVMOP, typename OPTY>
12137b5132daSValentin Clement mlir::LLVM::InsertValueOp complexSum(OPTY sumop, mlir::ValueRange opnds,
12147b5132daSValentin Clement                                      mlir::ConversionPatternRewriter &rewriter,
12157b5132daSValentin Clement                                      fir::LLVMTypeConverter &lowering) {
12167b5132daSValentin Clement   mlir::Value a = opnds[0];
12177b5132daSValentin Clement   mlir::Value b = opnds[1];
12187b5132daSValentin Clement   auto loc = sumop.getLoc();
12197b5132daSValentin Clement   auto ctx = sumop.getContext();
12207b5132daSValentin Clement   auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
12217b5132daSValentin Clement   auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
12227b5132daSValentin Clement   mlir::Type eleTy = lowering.convertType(getComplexEleTy(sumop.getType()));
12237b5132daSValentin Clement   mlir::Type ty = lowering.convertType(sumop.getType());
12247b5132daSValentin Clement   auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
12257b5132daSValentin Clement   auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
12267b5132daSValentin Clement   auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
12277b5132daSValentin Clement   auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
12287b5132daSValentin Clement   auto rx = rewriter.create<LLVMOP>(loc, eleTy, x0, x1);
12297b5132daSValentin Clement   auto ry = rewriter.create<LLVMOP>(loc, eleTy, y0, y1);
12307b5132daSValentin Clement   auto r0 = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
12317b5132daSValentin Clement   auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r0, rx, c0);
12327b5132daSValentin Clement   return rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ry, c1);
12337b5132daSValentin Clement }
12347b5132daSValentin Clement 
12357b5132daSValentin Clement struct AddcOpConversion : public FIROpConversion<fir::AddcOp> {
12367b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
12377b5132daSValentin Clement 
12387b5132daSValentin Clement   mlir::LogicalResult
12397b5132daSValentin Clement   matchAndRewrite(fir::AddcOp addc, OpAdaptor adaptor,
12407b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
12417b5132daSValentin Clement     // given: (x + iy) + (x' + iy')
12427b5132daSValentin Clement     // result: (x + x') + i(y + y')
12437b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FAddOp>(addc, adaptor.getOperands(),
12447b5132daSValentin Clement                                             rewriter, lowerTy());
12457b5132daSValentin Clement     rewriter.replaceOp(addc, r.getResult());
12467b5132daSValentin Clement     return success();
12477b5132daSValentin Clement   }
12487b5132daSValentin Clement };
12497b5132daSValentin Clement 
12507b5132daSValentin Clement struct SubcOpConversion : public FIROpConversion<fir::SubcOp> {
12517b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
12527b5132daSValentin Clement 
12537b5132daSValentin Clement   mlir::LogicalResult
12547b5132daSValentin Clement   matchAndRewrite(fir::SubcOp subc, OpAdaptor adaptor,
12557b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
12567b5132daSValentin Clement     // given: (x + iy) - (x' + iy')
12577b5132daSValentin Clement     // result: (x - x') + i(y - y')
12587b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FSubOp>(subc, adaptor.getOperands(),
12597b5132daSValentin Clement                                             rewriter, lowerTy());
12607b5132daSValentin Clement     rewriter.replaceOp(subc, r.getResult());
12617b5132daSValentin Clement     return success();
12627b5132daSValentin Clement   }
12637b5132daSValentin Clement };
12647b5132daSValentin Clement 
12657b5132daSValentin Clement /// Inlined complex multiply
12667b5132daSValentin Clement struct MulcOpConversion : public FIROpConversion<fir::MulcOp> {
12677b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
12687b5132daSValentin Clement 
12697b5132daSValentin Clement   mlir::LogicalResult
12707b5132daSValentin Clement   matchAndRewrite(fir::MulcOp mulc, OpAdaptor adaptor,
12717b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
12727b5132daSValentin Clement     // TODO: Can we use a call to __muldc3 ?
12737b5132daSValentin Clement     // given: (x + iy) * (x' + iy')
12747b5132daSValentin Clement     // result: (xx'-yy')+i(xy'+yx')
12757b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
12767b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
12777b5132daSValentin Clement     auto loc = mulc.getLoc();
12787b5132daSValentin Clement     auto *ctx = mulc.getContext();
12797b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
12807b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
12817b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(mulc.getType()));
12827b5132daSValentin Clement     mlir::Type ty = convertType(mulc.getType());
12837b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
12847b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
12857b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
12867b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
12877b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
12887b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
12897b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
12907b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xy, yx);
12917b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
12927b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, xx, yy);
12937b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
12947b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
12957b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
12967b5132daSValentin Clement     rewriter.replaceOp(mulc, r0.getResult());
12977b5132daSValentin Clement     return success();
12987b5132daSValentin Clement   }
12997b5132daSValentin Clement };
13007b5132daSValentin Clement 
13017b5132daSValentin Clement /// Inlined complex division
13027b5132daSValentin Clement struct DivcOpConversion : public FIROpConversion<fir::DivcOp> {
13037b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
13047b5132daSValentin Clement 
13057b5132daSValentin Clement   mlir::LogicalResult
13067b5132daSValentin Clement   matchAndRewrite(fir::DivcOp divc, OpAdaptor adaptor,
13077b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
13087b5132daSValentin Clement     // TODO: Can we use a call to __divdc3 instead?
13097b5132daSValentin Clement     // Just generate inline code for now.
13107b5132daSValentin Clement     // given: (x + iy) / (x' + iy')
13117b5132daSValentin Clement     // result: ((xx'+yy')/d) + i((yx'-xy')/d) where d = x'x' + y'y'
13127b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
13137b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
13147b5132daSValentin Clement     auto loc = divc.getLoc();
13157b5132daSValentin Clement     auto *ctx = divc.getContext();
13167b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
13177b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
13187b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(divc.getType()));
13197b5132daSValentin Clement     mlir::Type ty = convertType(divc.getType());
13207b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
13217b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
13227b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
13237b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
13247b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
13257b5132daSValentin Clement     auto x1x1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x1, x1);
13267b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
13277b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
13287b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
13297b5132daSValentin Clement     auto y1y1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y1, y1);
13307b5132daSValentin Clement     auto d = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, x1x1, y1y1);
13317b5132daSValentin Clement     auto rrn = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xx, yy);
13327b5132daSValentin Clement     auto rin = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, yx, xy);
13337b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rrn, d);
13347b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rin, d);
13357b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
13367b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
13377b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
13387b5132daSValentin Clement     rewriter.replaceOp(divc, r0.getResult());
13397b5132daSValentin Clement     return success();
13407b5132daSValentin Clement   }
13417b5132daSValentin Clement };
13427b5132daSValentin Clement 
13437b5132daSValentin Clement /// Inlined complex negation
13447b5132daSValentin Clement struct NegcOpConversion : public FIROpConversion<fir::NegcOp> {
13457b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
13467b5132daSValentin Clement 
13477b5132daSValentin Clement   mlir::LogicalResult
13487b5132daSValentin Clement   matchAndRewrite(fir::NegcOp neg, OpAdaptor adaptor,
13497b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
13507b5132daSValentin Clement     // given: -(x + iy)
13517b5132daSValentin Clement     // result: -x - iy
13527b5132daSValentin Clement     auto *ctxt = neg.getContext();
13537b5132daSValentin Clement     auto eleTy = convertType(getComplexEleTy(neg.getType()));
13547b5132daSValentin Clement     auto ty = convertType(neg.getType());
13557b5132daSValentin Clement     auto loc = neg.getLoc();
13567b5132daSValentin Clement     mlir::Value o0 = adaptor.getOperands()[0];
13577b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0));
13587b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1));
13597b5132daSValentin Clement     auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c0);
13607b5132daSValentin Clement     auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c1);
13617b5132daSValentin Clement     auto nrp = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, rp);
13627b5132daSValentin Clement     auto nip = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, ip);
13637b5132daSValentin Clement     auto r = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, o0, nrp, c0);
13647b5132daSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(neg, ty, r, nip, c1);
13657b5132daSValentin Clement     return success();
13667b5132daSValentin Clement   }
13677b5132daSValentin Clement };
13687b5132daSValentin Clement 
1369420ad7ceSAndrzej Warzynski /// `fir.is_present` -->
1370420ad7ceSAndrzej Warzynski /// ```
1371420ad7ceSAndrzej Warzynski ///  %0 = llvm.mlir.constant(0 : i64)
1372420ad7ceSAndrzej Warzynski ///  %1 = llvm.ptrtoint %0
1373420ad7ceSAndrzej Warzynski ///  %2 = llvm.icmp "ne" %1, %0 : i64
1374420ad7ceSAndrzej Warzynski /// ```
1375420ad7ceSAndrzej Warzynski struct IsPresentOpConversion : public FIROpConversion<fir::IsPresentOp> {
1376420ad7ceSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
1377420ad7ceSAndrzej Warzynski 
1378420ad7ceSAndrzej Warzynski   mlir::LogicalResult
1379420ad7ceSAndrzej Warzynski   matchAndRewrite(fir::IsPresentOp isPresent, OpAdaptor adaptor,
1380420ad7ceSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
1381420ad7ceSAndrzej Warzynski     mlir::Type idxTy = lowerTy().indexType();
1382420ad7ceSAndrzej Warzynski     mlir::Location loc = isPresent.getLoc();
1383420ad7ceSAndrzej Warzynski     auto ptr = adaptor.getOperands()[0];
1384420ad7ceSAndrzej Warzynski 
1385420ad7ceSAndrzej Warzynski     if (isPresent.val().getType().isa<fir::BoxCharType>()) {
1386420ad7ceSAndrzej Warzynski       auto structTy = ptr.getType().cast<mlir::LLVM::LLVMStructType>();
1387420ad7ceSAndrzej Warzynski       assert(!structTy.isOpaque() && !structTy.getBody().empty());
1388420ad7ceSAndrzej Warzynski 
1389420ad7ceSAndrzej Warzynski       mlir::Type ty = structTy.getBody()[0];
1390420ad7ceSAndrzej Warzynski       mlir::MLIRContext *ctx = isPresent.getContext();
1391420ad7ceSAndrzej Warzynski       auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
1392420ad7ceSAndrzej Warzynski       ptr = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, ptr, c0);
1393420ad7ceSAndrzej Warzynski     }
1394420ad7ceSAndrzej Warzynski     mlir::LLVM::ConstantOp c0 =
1395420ad7ceSAndrzej Warzynski         genConstantIndex(isPresent.getLoc(), idxTy, rewriter, 0);
1396420ad7ceSAndrzej Warzynski     auto addr = rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, ptr);
1397420ad7ceSAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
1398420ad7ceSAndrzej Warzynski         isPresent, mlir::LLVM::ICmpPredicate::ne, addr, c0);
1399420ad7ceSAndrzej Warzynski 
1400420ad7ceSAndrzej Warzynski     return success();
1401420ad7ceSAndrzej Warzynski   }
1402420ad7ceSAndrzej Warzynski };
14031e77b095SAndrzej Warzynski 
14041e77b095SAndrzej Warzynski /// Convert `!fir.emboxchar<!fir.char<KIND, ?>, #n>` into a sequence of
14051e77b095SAndrzej Warzynski /// instructions that generate `!llvm.struct<(ptr<ik>, i64)>`. The 1st element
14061e77b095SAndrzej Warzynski /// in this struct is a pointer. Its type is determined from `KIND`. The 2nd
14071e77b095SAndrzej Warzynski /// element is the length of the character buffer (`#n`).
14081e77b095SAndrzej Warzynski struct EmboxCharOpConversion : public FIROpConversion<fir::EmboxCharOp> {
14091e77b095SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
14101e77b095SAndrzej Warzynski 
14111e77b095SAndrzej Warzynski   mlir::LogicalResult
14121e77b095SAndrzej Warzynski   matchAndRewrite(fir::EmboxCharOp emboxChar, OpAdaptor adaptor,
14131e77b095SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
14141e77b095SAndrzej Warzynski     mlir::ValueRange operands = adaptor.getOperands();
14151e77b095SAndrzej Warzynski     MLIRContext *ctx = emboxChar.getContext();
14161e77b095SAndrzej Warzynski 
14171e77b095SAndrzej Warzynski     mlir::Value charBuffer = operands[0];
14181e77b095SAndrzej Warzynski     mlir::Value charBufferLen = operands[1];
14191e77b095SAndrzej Warzynski 
14201e77b095SAndrzej Warzynski     mlir::Location loc = emboxChar.getLoc();
14211e77b095SAndrzej Warzynski     mlir::Type llvmStructTy = convertType(emboxChar.getType());
14221e77b095SAndrzej Warzynski     auto llvmStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, llvmStructTy);
14231e77b095SAndrzej Warzynski 
14241e77b095SAndrzej Warzynski     mlir::Type lenTy =
14251e77b095SAndrzej Warzynski         llvmStructTy.cast<mlir::LLVM::LLVMStructType>().getBody()[1];
14261e77b095SAndrzej Warzynski     mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, charBufferLen);
14271e77b095SAndrzej Warzynski 
14281e77b095SAndrzej Warzynski     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
14291e77b095SAndrzej Warzynski     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
14301e77b095SAndrzej Warzynski     auto insertBufferOp = rewriter.create<mlir::LLVM::InsertValueOp>(
14311e77b095SAndrzej Warzynski         loc, llvmStructTy, llvmStruct, charBuffer, c0);
14321e77b095SAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
14331e77b095SAndrzej Warzynski         emboxChar, llvmStructTy, insertBufferOp, lenAfterCast, c1);
14341e77b095SAndrzej Warzynski 
14351e77b095SAndrzej Warzynski     return success();
14361e77b095SAndrzej Warzynski   }
14371e77b095SAndrzej Warzynski };
1438*14867ffcSAndrzej Warzynski 
1439*14867ffcSAndrzej Warzynski /// Construct an `llvm.extractvalue` instruction. It will return value at
1440*14867ffcSAndrzej Warzynski /// element \p x from  \p tuple.
1441*14867ffcSAndrzej Warzynski mlir::LLVM::ExtractValueOp
1442*14867ffcSAndrzej Warzynski genExtractValueWithIndex(mlir::Location loc, mlir::Value tuple, mlir::Type ty,
1443*14867ffcSAndrzej Warzynski                          mlir::ConversionPatternRewriter &rewriter,
1444*14867ffcSAndrzej Warzynski                          mlir::MLIRContext *ctx, int x) {
1445*14867ffcSAndrzej Warzynski   auto cx = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(x));
1446*14867ffcSAndrzej Warzynski   auto xty = ty.cast<mlir::LLVM::LLVMStructType>().getBody()[x];
1447*14867ffcSAndrzej Warzynski   return rewriter.create<mlir::LLVM::ExtractValueOp>(loc, xty, tuple, cx);
1448*14867ffcSAndrzej Warzynski }
1449*14867ffcSAndrzej Warzynski 
1450*14867ffcSAndrzej Warzynski /// Convert `fir.unboxchar` into two `llvm.extractvalue` instructions. One for
1451*14867ffcSAndrzej Warzynski /// the character buffer and one for the buffer length.
1452*14867ffcSAndrzej Warzynski struct UnboxCharOpConversion : public FIROpConversion<fir::UnboxCharOp> {
1453*14867ffcSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
1454*14867ffcSAndrzej Warzynski 
1455*14867ffcSAndrzej Warzynski   mlir::LogicalResult
1456*14867ffcSAndrzej Warzynski   matchAndRewrite(fir::UnboxCharOp unboxchar, OpAdaptor adaptor,
1457*14867ffcSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
1458*14867ffcSAndrzej Warzynski     MLIRContext *ctx = unboxchar.getContext();
1459*14867ffcSAndrzej Warzynski 
1460*14867ffcSAndrzej Warzynski     mlir::Type lenTy = convertType(unboxchar.getType(1));
1461*14867ffcSAndrzej Warzynski     mlir::Value tuple = adaptor.getOperands()[0];
1462*14867ffcSAndrzej Warzynski     mlir::Type tupleTy = tuple.getType();
1463*14867ffcSAndrzej Warzynski 
1464*14867ffcSAndrzej Warzynski     mlir::Location loc = unboxchar.getLoc();
1465*14867ffcSAndrzej Warzynski     mlir::Value ptrToBuffer =
1466*14867ffcSAndrzej Warzynski         genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 0);
1467*14867ffcSAndrzej Warzynski 
1468*14867ffcSAndrzej Warzynski     mlir::LLVM::ExtractValueOp len =
1469*14867ffcSAndrzej Warzynski         genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 1);
1470*14867ffcSAndrzej Warzynski     mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, len);
1471*14867ffcSAndrzej Warzynski 
1472*14867ffcSAndrzej Warzynski     rewriter.replaceOp(unboxchar,
1473*14867ffcSAndrzej Warzynski                        ArrayRef<mlir::Value>{ptrToBuffer, lenAfterCast});
1474*14867ffcSAndrzej Warzynski     return success();
1475*14867ffcSAndrzej Warzynski   }
1476*14867ffcSAndrzej Warzynski };
1477*14867ffcSAndrzej Warzynski 
1478044d5b5dSValentin Clement } // namespace
1479044d5b5dSValentin Clement 
1480044d5b5dSValentin Clement namespace {
1481044d5b5dSValentin Clement /// Convert FIR dialect to LLVM dialect
1482044d5b5dSValentin Clement ///
1483044d5b5dSValentin Clement /// This pass lowers all FIR dialect operations to LLVM IR dialect. An
1484044d5b5dSValentin Clement /// MLIR pass is used to lower residual Std dialect to LLVM IR dialect.
1485044d5b5dSValentin Clement ///
1486044d5b5dSValentin Clement /// This pass is not complete yet. We are upstreaming it in small patches.
1487044d5b5dSValentin Clement class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> {
1488044d5b5dSValentin Clement public:
1489044d5b5dSValentin Clement   mlir::ModuleOp getModule() { return getOperation(); }
1490044d5b5dSValentin Clement 
1491044d5b5dSValentin Clement   void runOnOperation() override final {
14927b5132daSValentin Clement     auto mod = getModule();
14937b5132daSValentin Clement     if (!forcedTargetTriple.empty()) {
14947b5132daSValentin Clement       fir::setTargetTriple(mod, forcedTargetTriple);
14957b5132daSValentin Clement     }
14967b5132daSValentin Clement 
1497044d5b5dSValentin Clement     auto *context = getModule().getContext();
1498044d5b5dSValentin Clement     fir::LLVMTypeConverter typeConverter{getModule()};
1499044d5b5dSValentin Clement     mlir::OwningRewritePatternList pattern(context);
1500df3b9810SValentin Clement     pattern.insert<
1501420ad7ceSAndrzej Warzynski         AbsentOpConversion, AddcOpConversion, AddrOfOpConversion,
1502420ad7ceSAndrzej Warzynski         AllocaOpConversion, BoxAddrOpConversion, BoxDimsOpConversion,
1503420ad7ceSAndrzej Warzynski         BoxEleSizeOpConversion, BoxIsAllocOpConversion, BoxIsArrayOpConversion,
1504420ad7ceSAndrzej Warzynski         BoxIsPtrOpConversion, BoxRankOpConversion, CallOpConversion,
1505420ad7ceSAndrzej Warzynski         ConvertOpConversion, DispatchOpConversion, DispatchTableOpConversion,
15061e77b095SAndrzej Warzynski         DTEntryOpConversion, DivcOpConversion, EmboxCharOpConversion,
15071e77b095SAndrzej Warzynski         ExtractValueOpConversion, HasValueOpConversion, GlobalOpConversion,
15081e77b095SAndrzej Warzynski         InsertOnRangeOpConversion, InsertValueOpConversion,
15091e77b095SAndrzej Warzynski         IsPresentOpConversion, LoadOpConversion, NegcOpConversion,
15101e77b095SAndrzej Warzynski         MulcOpConversion, SelectCaseOpConversion, SelectOpConversion,
15112a299e4fSValentin Clement         SelectRankOpConversion, SelectTypeOpConversion, StoreOpConversion,
1512*14867ffcSAndrzej Warzynski         SubcOpConversion, UnboxCharOpConversion, UndefOpConversion,
1513*14867ffcSAndrzej Warzynski         UnreachableOpConversion, ZeroOpConversion>(typeConverter);
1514044d5b5dSValentin Clement     mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern);
1515044d5b5dSValentin Clement     mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter,
1516044d5b5dSValentin Clement                                                             pattern);
1517044d5b5dSValentin Clement     mlir::ConversionTarget target{*context};
1518044d5b5dSValentin Clement     target.addLegalDialect<mlir::LLVM::LLVMDialect>();
1519044d5b5dSValentin Clement 
1520044d5b5dSValentin Clement     // required NOPs for applying a full conversion
1521044d5b5dSValentin Clement     target.addLegalOp<mlir::ModuleOp>();
1522044d5b5dSValentin Clement 
1523044d5b5dSValentin Clement     // apply the patterns
1524044d5b5dSValentin Clement     if (mlir::failed(mlir::applyFullConversion(getModule(), target,
1525044d5b5dSValentin Clement                                                std::move(pattern)))) {
1526044d5b5dSValentin Clement       signalPassFailure();
1527044d5b5dSValentin Clement     }
1528044d5b5dSValentin Clement   }
1529044d5b5dSValentin Clement };
1530044d5b5dSValentin Clement } // namespace
1531044d5b5dSValentin Clement 
1532044d5b5dSValentin Clement std::unique_ptr<mlir::Pass> fir::createFIRToLLVMPass() {
1533044d5b5dSValentin Clement   return std::make_unique<FIRToLLVMLowering>();
1534044d5b5dSValentin Clement }
1535