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 
4681a2ec667SValentin Clement /// Lower `fir.string_lit` to LLVM IR dialect operation.
4691a2ec667SValentin Clement struct StringLitOpConversion : public FIROpConversion<fir::StringLitOp> {
4701a2ec667SValentin Clement   using FIROpConversion::FIROpConversion;
4711a2ec667SValentin Clement 
4721a2ec667SValentin Clement   mlir::LogicalResult
4731a2ec667SValentin Clement   matchAndRewrite(fir::StringLitOp constop, OpAdaptor adaptor,
4741a2ec667SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
4751a2ec667SValentin Clement     auto ty = convertType(constop.getType());
4761a2ec667SValentin Clement     auto attr = constop.getValue();
4771a2ec667SValentin Clement     if (attr.isa<mlir::StringAttr>()) {
4781a2ec667SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(constop, ty, attr);
4791a2ec667SValentin Clement       return success();
4801a2ec667SValentin Clement     }
4811a2ec667SValentin Clement 
4821a2ec667SValentin Clement     auto arr = attr.cast<mlir::ArrayAttr>();
4831a2ec667SValentin Clement     auto charTy = constop.getType().cast<fir::CharacterType>();
4841a2ec667SValentin Clement     unsigned bits = lowerTy().characterBitsize(charTy);
4851a2ec667SValentin Clement     mlir::Type intTy = rewriter.getIntegerType(bits);
4861a2ec667SValentin Clement     auto attrs = llvm::map_range(
4871a2ec667SValentin Clement         arr.getValue(), [intTy, bits](mlir::Attribute attr) -> Attribute {
4881a2ec667SValentin Clement           return mlir::IntegerAttr::get(
4891a2ec667SValentin Clement               intTy,
4901a2ec667SValentin Clement               attr.cast<mlir::IntegerAttr>().getValue().sextOrTrunc(bits));
4911a2ec667SValentin Clement         });
4921a2ec667SValentin Clement     mlir::Type vecType = mlir::VectorType::get(arr.size(), intTy);
4931a2ec667SValentin Clement     auto denseAttr = mlir::DenseElementsAttr::get(
4941a2ec667SValentin Clement         vecType.cast<mlir::ShapedType>(), llvm::to_vector<8>(attrs));
4951a2ec667SValentin Clement     rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(constop, ty,
4961a2ec667SValentin Clement                                                          denseAttr);
4971a2ec667SValentin Clement     return success();
4981a2ec667SValentin Clement   }
4991a2ec667SValentin Clement };
5001a2ec667SValentin Clement 
501e38ef2ffSValentin Clement /// Lower `fir.box_tdesc` to the sequence of operations to extract the type
502e38ef2ffSValentin Clement /// descriptor from the box.
503e38ef2ffSValentin Clement struct BoxTypeDescOpConversion : public FIROpConversion<fir::BoxTypeDescOp> {
504e38ef2ffSValentin Clement   using FIROpConversion::FIROpConversion;
505e38ef2ffSValentin Clement 
506e38ef2ffSValentin Clement   mlir::LogicalResult
507e38ef2ffSValentin Clement   matchAndRewrite(fir::BoxTypeDescOp boxtypedesc, OpAdaptor adaptor,
508e38ef2ffSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
509e38ef2ffSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
510e38ef2ffSValentin Clement     auto loc = boxtypedesc.getLoc();
511e38ef2ffSValentin Clement     mlir::Type typeTy =
512e38ef2ffSValentin Clement         fir::getDescFieldTypeModel<kTypePosInBox>()(boxtypedesc.getContext());
513e38ef2ffSValentin Clement     auto result = getValueFromBox(loc, box, typeTy, rewriter, kTypePosInBox);
514e38ef2ffSValentin Clement     auto typePtrTy = mlir::LLVM::LLVMPointerType::get(typeTy);
515e38ef2ffSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(boxtypedesc, typePtrTy,
516e38ef2ffSValentin Clement                                                         result);
517e38ef2ffSValentin Clement     return success();
518e38ef2ffSValentin Clement   }
519e38ef2ffSValentin Clement };
520e38ef2ffSValentin Clement 
521ddd11b9aSAndrzej Warzynski // `fir.call` -> `llvm.call`
522ddd11b9aSAndrzej Warzynski struct CallOpConversion : public FIROpConversion<fir::CallOp> {
523ddd11b9aSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
524ddd11b9aSAndrzej Warzynski 
525ddd11b9aSAndrzej Warzynski   mlir::LogicalResult
526ddd11b9aSAndrzej Warzynski   matchAndRewrite(fir::CallOp call, OpAdaptor adaptor,
527ddd11b9aSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
528ddd11b9aSAndrzej Warzynski     SmallVector<mlir::Type> resultTys;
529ddd11b9aSAndrzej Warzynski     for (auto r : call.getResults())
530ddd11b9aSAndrzej Warzynski       resultTys.push_back(convertType(r.getType()));
531ddd11b9aSAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
532ddd11b9aSAndrzej Warzynski         call, resultTys, adaptor.getOperands(), call->getAttrs());
533ddd11b9aSAndrzej Warzynski     return success();
534ddd11b9aSAndrzej Warzynski   }
535ddd11b9aSAndrzej Warzynski };
536ddd11b9aSAndrzej Warzynski 
537092cee5fSValentin Clement static mlir::Type getComplexEleTy(mlir::Type complex) {
538092cee5fSValentin Clement   if (auto cc = complex.dyn_cast<mlir::ComplexType>())
539092cee5fSValentin Clement     return cc.getElementType();
540092cee5fSValentin Clement   return complex.cast<fir::ComplexType>().getElementType();
541092cee5fSValentin Clement }
542092cee5fSValentin Clement 
543f1dfc027SDiana Picus /// Compare complex values
544f1dfc027SDiana Picus ///
545f1dfc027SDiana Picus /// Per 10.1, the only comparisons available are .EQ. (oeq) and .NE. (une).
546f1dfc027SDiana Picus ///
547f1dfc027SDiana Picus /// For completeness, all other comparison are done on the real component only.
548f1dfc027SDiana Picus struct CmpcOpConversion : public FIROpConversion<fir::CmpcOp> {
549f1dfc027SDiana Picus   using FIROpConversion::FIROpConversion;
550f1dfc027SDiana Picus 
551f1dfc027SDiana Picus   mlir::LogicalResult
552f1dfc027SDiana Picus   matchAndRewrite(fir::CmpcOp cmp, OpAdaptor adaptor,
553f1dfc027SDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
554f1dfc027SDiana Picus     mlir::ValueRange operands = adaptor.getOperands();
555f1dfc027SDiana Picus     mlir::MLIRContext *ctxt = cmp.getContext();
556f1dfc027SDiana Picus     mlir::Type eleTy = convertType(getComplexEleTy(cmp.lhs().getType()));
557f1dfc027SDiana Picus     mlir::Type resTy = convertType(cmp.getType());
558f1dfc027SDiana Picus     mlir::Location loc = cmp.getLoc();
559f1dfc027SDiana Picus     auto pos0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0));
560f1dfc027SDiana Picus     SmallVector<mlir::Value, 2> rp{rewriter.create<mlir::LLVM::ExtractValueOp>(
561f1dfc027SDiana Picus                                        loc, eleTy, operands[0], pos0),
562f1dfc027SDiana Picus                                    rewriter.create<mlir::LLVM::ExtractValueOp>(
563f1dfc027SDiana Picus                                        loc, eleTy, operands[1], pos0)};
564f1dfc027SDiana Picus     auto rcp =
565f1dfc027SDiana Picus         rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, rp, cmp->getAttrs());
566f1dfc027SDiana Picus     auto pos1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1));
567f1dfc027SDiana Picus     SmallVector<mlir::Value, 2> ip{rewriter.create<mlir::LLVM::ExtractValueOp>(
568f1dfc027SDiana Picus                                        loc, eleTy, operands[0], pos1),
569f1dfc027SDiana Picus                                    rewriter.create<mlir::LLVM::ExtractValueOp>(
570f1dfc027SDiana Picus                                        loc, eleTy, operands[1], pos1)};
571f1dfc027SDiana Picus     auto icp =
572f1dfc027SDiana Picus         rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, ip, cmp->getAttrs());
573f1dfc027SDiana Picus     SmallVector<mlir::Value, 2> cp{rcp, icp};
574f1dfc027SDiana Picus     switch (cmp.getPredicate()) {
575f1dfc027SDiana Picus     case mlir::arith::CmpFPredicate::OEQ: // .EQ.
576f1dfc027SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(cmp, resTy, cp);
577f1dfc027SDiana Picus       break;
578f1dfc027SDiana Picus     case mlir::arith::CmpFPredicate::UNE: // .NE.
579f1dfc027SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(cmp, resTy, cp);
580f1dfc027SDiana Picus       break;
581f1dfc027SDiana Picus     default:
582f1dfc027SDiana Picus       rewriter.replaceOp(cmp, rcp.getResult());
583f1dfc027SDiana Picus       break;
584f1dfc027SDiana Picus     }
585f1dfc027SDiana Picus     return success();
586f1dfc027SDiana Picus   }
587f1dfc027SDiana Picus };
588f1dfc027SDiana Picus 
589*e81d73edSDiana Picus /// Lower complex constants
590*e81d73edSDiana Picus struct ConstcOpConversion : public FIROpConversion<fir::ConstcOp> {
591*e81d73edSDiana Picus   using FIROpConversion::FIROpConversion;
592*e81d73edSDiana Picus 
593*e81d73edSDiana Picus   mlir::LogicalResult
594*e81d73edSDiana Picus   matchAndRewrite(fir::ConstcOp conc, OpAdaptor,
595*e81d73edSDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
596*e81d73edSDiana Picus     mlir::Location loc = conc.getLoc();
597*e81d73edSDiana Picus     mlir::MLIRContext *ctx = conc.getContext();
598*e81d73edSDiana Picus     mlir::Type ty = convertType(conc.getType());
599*e81d73edSDiana Picus     mlir::Type ety = convertType(getComplexEleTy(conc.getType()));
600*e81d73edSDiana Picus     auto realFloatAttr = mlir::FloatAttr::get(ety, getValue(conc.getReal()));
601*e81d73edSDiana Picus     auto realPart =
602*e81d73edSDiana Picus         rewriter.create<mlir::LLVM::ConstantOp>(loc, ety, realFloatAttr);
603*e81d73edSDiana Picus     auto imFloatAttr = mlir::FloatAttr::get(ety, getValue(conc.getImaginary()));
604*e81d73edSDiana Picus     auto imPart =
605*e81d73edSDiana Picus         rewriter.create<mlir::LLVM::ConstantOp>(loc, ety, imFloatAttr);
606*e81d73edSDiana Picus     auto realIndex = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
607*e81d73edSDiana Picus     auto imIndex = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
608*e81d73edSDiana Picus     auto undef = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
609*e81d73edSDiana Picus     auto setReal = rewriter.create<mlir::LLVM::InsertValueOp>(
610*e81d73edSDiana Picus         loc, ty, undef, realPart, realIndex);
611*e81d73edSDiana Picus     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(conc, ty, setReal,
612*e81d73edSDiana Picus                                                            imPart, imIndex);
613*e81d73edSDiana Picus     return success();
614*e81d73edSDiana Picus   }
615*e81d73edSDiana Picus 
616*e81d73edSDiana Picus   inline APFloat getValue(mlir::Attribute attr) const {
617*e81d73edSDiana Picus     return attr.cast<fir::RealAttr>().getValue();
618*e81d73edSDiana Picus   }
619*e81d73edSDiana Picus };
620*e81d73edSDiana Picus 
621092cee5fSValentin Clement /// convert value of from-type to value of to-type
622092cee5fSValentin Clement struct ConvertOpConversion : public FIROpConversion<fir::ConvertOp> {
623092cee5fSValentin Clement   using FIROpConversion::FIROpConversion;
624092cee5fSValentin Clement 
625092cee5fSValentin Clement   static bool isFloatingPointTy(mlir::Type ty) {
626092cee5fSValentin Clement     return ty.isa<mlir::FloatType>();
627092cee5fSValentin Clement   }
628092cee5fSValentin Clement 
629092cee5fSValentin Clement   mlir::LogicalResult
630092cee5fSValentin Clement   matchAndRewrite(fir::ConvertOp convert, OpAdaptor adaptor,
631092cee5fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
632092cee5fSValentin Clement     auto fromTy = convertType(convert.value().getType());
633092cee5fSValentin Clement     auto toTy = convertType(convert.res().getType());
634092cee5fSValentin Clement     mlir::Value op0 = adaptor.getOperands()[0];
635092cee5fSValentin Clement     if (fromTy == toTy) {
636092cee5fSValentin Clement       rewriter.replaceOp(convert, op0);
637092cee5fSValentin Clement       return success();
638092cee5fSValentin Clement     }
639092cee5fSValentin Clement     auto loc = convert.getLoc();
640092cee5fSValentin Clement     auto convertFpToFp = [&](mlir::Value val, unsigned fromBits,
641092cee5fSValentin Clement                              unsigned toBits, mlir::Type toTy) -> mlir::Value {
642092cee5fSValentin Clement       if (fromBits == toBits) {
643092cee5fSValentin Clement         // TODO: Converting between two floating-point representations with the
644092cee5fSValentin Clement         // same bitwidth is not allowed for now.
645092cee5fSValentin Clement         mlir::emitError(loc,
646092cee5fSValentin Clement                         "cannot implicitly convert between two floating-point "
647092cee5fSValentin Clement                         "representations of the same bitwidth");
648092cee5fSValentin Clement         return {};
649092cee5fSValentin Clement       }
650092cee5fSValentin Clement       if (fromBits > toBits)
651092cee5fSValentin Clement         return rewriter.create<mlir::LLVM::FPTruncOp>(loc, toTy, val);
652092cee5fSValentin Clement       return rewriter.create<mlir::LLVM::FPExtOp>(loc, toTy, val);
653092cee5fSValentin Clement     };
654092cee5fSValentin Clement     // Complex to complex conversion.
655092cee5fSValentin Clement     if (fir::isa_complex(convert.value().getType()) &&
656092cee5fSValentin Clement         fir::isa_complex(convert.res().getType())) {
657092cee5fSValentin Clement       // Special case: handle the conversion of a complex such that both the
658092cee5fSValentin Clement       // real and imaginary parts are converted together.
659092cee5fSValentin Clement       auto zero = mlir::ArrayAttr::get(convert.getContext(),
660092cee5fSValentin Clement                                        rewriter.getI32IntegerAttr(0));
661092cee5fSValentin Clement       auto one = mlir::ArrayAttr::get(convert.getContext(),
662092cee5fSValentin Clement                                       rewriter.getI32IntegerAttr(1));
663092cee5fSValentin Clement       auto ty = convertType(getComplexEleTy(convert.value().getType()));
664092cee5fSValentin Clement       auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, zero);
665092cee5fSValentin Clement       auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, one);
666092cee5fSValentin Clement       auto nt = convertType(getComplexEleTy(convert.res().getType()));
667092cee5fSValentin Clement       auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
668092cee5fSValentin Clement       auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(nt);
669092cee5fSValentin Clement       auto rc = convertFpToFp(rp, fromBits, toBits, nt);
670092cee5fSValentin Clement       auto ic = convertFpToFp(ip, fromBits, toBits, nt);
671092cee5fSValentin Clement       auto un = rewriter.create<mlir::LLVM::UndefOp>(loc, toTy);
672092cee5fSValentin Clement       auto i1 =
673092cee5fSValentin Clement           rewriter.create<mlir::LLVM::InsertValueOp>(loc, toTy, un, rc, zero);
674092cee5fSValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(convert, toTy, i1,
675092cee5fSValentin Clement                                                              ic, one);
676092cee5fSValentin Clement       return mlir::success();
677092cee5fSValentin Clement     }
678092cee5fSValentin Clement     // Floating point to floating point conversion.
679092cee5fSValentin Clement     if (isFloatingPointTy(fromTy)) {
680092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
681092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
682092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
683092cee5fSValentin Clement         auto v = convertFpToFp(op0, fromBits, toBits, toTy);
684092cee5fSValentin Clement         rewriter.replaceOp(convert, v);
685092cee5fSValentin Clement         return mlir::success();
686092cee5fSValentin Clement       }
687092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
688092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::FPToSIOp>(convert, toTy, op0);
689092cee5fSValentin Clement         return mlir::success();
690092cee5fSValentin Clement       }
691092cee5fSValentin Clement     } else if (fromTy.isa<mlir::IntegerType>()) {
692092cee5fSValentin Clement       // Integer to integer conversion.
693092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
694092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
695092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
696092cee5fSValentin Clement         assert(fromBits != toBits);
697092cee5fSValentin Clement         if (fromBits > toBits) {
698092cee5fSValentin Clement           rewriter.replaceOpWithNewOp<mlir::LLVM::TruncOp>(convert, toTy, op0);
699092cee5fSValentin Clement           return mlir::success();
700092cee5fSValentin Clement         }
701092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SExtOp>(convert, toTy, op0);
702092cee5fSValentin Clement         return mlir::success();
703092cee5fSValentin Clement       }
704092cee5fSValentin Clement       // Integer to floating point conversion.
705092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
706092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SIToFPOp>(convert, toTy, op0);
707092cee5fSValentin Clement         return mlir::success();
708092cee5fSValentin Clement       }
709092cee5fSValentin Clement       // Integer to pointer conversion.
710092cee5fSValentin Clement       if (toTy.isa<mlir::LLVM::LLVMPointerType>()) {
711092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(convert, toTy, op0);
712092cee5fSValentin Clement         return mlir::success();
713092cee5fSValentin Clement       }
714092cee5fSValentin Clement     } else if (fromTy.isa<mlir::LLVM::LLVMPointerType>()) {
715092cee5fSValentin Clement       // Pointer to integer conversion.
716092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
717092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::PtrToIntOp>(convert, toTy, op0);
718092cee5fSValentin Clement         return mlir::success();
719092cee5fSValentin Clement       }
720092cee5fSValentin Clement       // Pointer to pointer conversion.
721092cee5fSValentin Clement       if (toTy.isa<mlir::LLVM::LLVMPointerType>()) {
722092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(convert, toTy, op0);
723092cee5fSValentin Clement         return mlir::success();
724092cee5fSValentin Clement       }
725092cee5fSValentin Clement     }
726092cee5fSValentin Clement     return emitError(loc) << "cannot convert " << fromTy << " to " << toTy;
727092cee5fSValentin Clement   }
728092cee5fSValentin Clement };
729092cee5fSValentin Clement 
7309534e361SValentin Clement /// Lower `fir.dispatch` operation. A virtual call to a method in a dispatch
7319534e361SValentin Clement /// table.
7329534e361SValentin Clement struct DispatchOpConversion : public FIROpConversion<fir::DispatchOp> {
7339534e361SValentin Clement   using FIROpConversion::FIROpConversion;
7349534e361SValentin Clement 
7359534e361SValentin Clement   mlir::LogicalResult
7369534e361SValentin Clement   matchAndRewrite(fir::DispatchOp dispatch, OpAdaptor adaptor,
7379534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
7389534e361SValentin Clement     return rewriter.notifyMatchFailure(
7399534e361SValentin Clement         dispatch, "fir.dispatch codegen is not implemented yet");
7409534e361SValentin Clement   }
7419534e361SValentin Clement };
7429534e361SValentin Clement 
7439534e361SValentin Clement /// Lower `fir.dispatch_table` operation. The dispatch table for a Fortran
7449534e361SValentin Clement /// derived type.
7459534e361SValentin Clement struct DispatchTableOpConversion
7469534e361SValentin Clement     : public FIROpConversion<fir::DispatchTableOp> {
7479534e361SValentin Clement   using FIROpConversion::FIROpConversion;
7489534e361SValentin Clement 
7499534e361SValentin Clement   mlir::LogicalResult
7509534e361SValentin Clement   matchAndRewrite(fir::DispatchTableOp dispTab, OpAdaptor adaptor,
7519534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
7529534e361SValentin Clement     return rewriter.notifyMatchFailure(
7539534e361SValentin Clement         dispTab, "fir.dispatch_table codegen is not implemented yet");
7549534e361SValentin Clement   }
7559534e361SValentin Clement };
7569534e361SValentin Clement 
7579534e361SValentin Clement /// Lower `fir.dt_entry` operation. An entry in a dispatch table; binds a
7589534e361SValentin Clement /// method-name to a function.
7599534e361SValentin Clement struct DTEntryOpConversion : public FIROpConversion<fir::DTEntryOp> {
7609534e361SValentin Clement   using FIROpConversion::FIROpConversion;
7619534e361SValentin Clement 
7629534e361SValentin Clement   mlir::LogicalResult
7639534e361SValentin Clement   matchAndRewrite(fir::DTEntryOp dtEnt, OpAdaptor adaptor,
7649534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
7659534e361SValentin Clement     return rewriter.notifyMatchFailure(
7669534e361SValentin Clement         dtEnt, "fir.dt_entry codegen is not implemented yet");
7679534e361SValentin Clement   }
7689534e361SValentin Clement };
7699534e361SValentin Clement 
770677df8c7SValentin Clement /// Lower `fir.global_len` operation.
771677df8c7SValentin Clement struct GlobalLenOpConversion : public FIROpConversion<fir::GlobalLenOp> {
772677df8c7SValentin Clement   using FIROpConversion::FIROpConversion;
773677df8c7SValentin Clement 
774677df8c7SValentin Clement   mlir::LogicalResult
775677df8c7SValentin Clement   matchAndRewrite(fir::GlobalLenOp globalLen, OpAdaptor adaptor,
776677df8c7SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
777677df8c7SValentin Clement     return rewriter.notifyMatchFailure(
778677df8c7SValentin Clement         globalLen, "fir.global_len codegen is not implemented yet");
779677df8c7SValentin Clement   }
780677df8c7SValentin Clement };
781677df8c7SValentin Clement 
78231246187SValentin Clement /// Lower `fir.gentypedesc` to a global constant.
78331246187SValentin Clement struct GenTypeDescOpConversion : public FIROpConversion<fir::GenTypeDescOp> {
78431246187SValentin Clement   using FIROpConversion::FIROpConversion;
78531246187SValentin Clement 
78631246187SValentin Clement   mlir::LogicalResult
78731246187SValentin Clement   matchAndRewrite(fir::GenTypeDescOp gentypedesc, OpAdaptor adaptor,
78831246187SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
78931246187SValentin Clement     return rewriter.notifyMatchFailure(
79031246187SValentin Clement         gentypedesc, "fir.fir.gentypedesc codegen is not implemented yet");
79131246187SValentin Clement   }
79231246187SValentin Clement };
79331246187SValentin Clement 
7940c4a7a52SValentin Clement /// Lower `fir.has_value` operation to `llvm.return` operation.
795044d5b5dSValentin Clement struct HasValueOpConversion : public FIROpConversion<fir::HasValueOp> {
796044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
797044d5b5dSValentin Clement 
798044d5b5dSValentin Clement   mlir::LogicalResult
799044d5b5dSValentin Clement   matchAndRewrite(fir::HasValueOp op, OpAdaptor adaptor,
800044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
801044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, adaptor.getOperands());
802044d5b5dSValentin Clement     return success();
803044d5b5dSValentin Clement   }
804044d5b5dSValentin Clement };
805044d5b5dSValentin Clement 
8060c4a7a52SValentin Clement /// Lower `fir.global` operation to `llvm.global` operation.
8070c4a7a52SValentin Clement /// `fir.insert_on_range` operations are replaced with constant dense attribute
8080c4a7a52SValentin Clement /// if they are applied on the full range.
809044d5b5dSValentin Clement struct GlobalOpConversion : public FIROpConversion<fir::GlobalOp> {
810044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
811044d5b5dSValentin Clement 
812044d5b5dSValentin Clement   mlir::LogicalResult
813044d5b5dSValentin Clement   matchAndRewrite(fir::GlobalOp global, OpAdaptor adaptor,
814044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
815044d5b5dSValentin Clement     auto tyAttr = convertType(global.getType());
816044d5b5dSValentin Clement     if (global.getType().isa<fir::BoxType>())
817044d5b5dSValentin Clement       tyAttr = tyAttr.cast<mlir::LLVM::LLVMPointerType>().getElementType();
818044d5b5dSValentin Clement     auto loc = global.getLoc();
819044d5b5dSValentin Clement     mlir::Attribute initAttr{};
820044d5b5dSValentin Clement     if (global.initVal())
821044d5b5dSValentin Clement       initAttr = global.initVal().getValue();
822044d5b5dSValentin Clement     auto linkage = convertLinkage(global.linkName());
823044d5b5dSValentin Clement     auto isConst = global.constant().hasValue();
824044d5b5dSValentin Clement     auto g = rewriter.create<mlir::LLVM::GlobalOp>(
825044d5b5dSValentin Clement         loc, tyAttr, isConst, linkage, global.sym_name(), initAttr);
826044d5b5dSValentin Clement     auto &gr = g.getInitializerRegion();
827044d5b5dSValentin Clement     rewriter.inlineRegionBefore(global.region(), gr, gr.end());
828044d5b5dSValentin Clement     if (!gr.empty()) {
829044d5b5dSValentin Clement       // Replace insert_on_range with a constant dense attribute if the
830044d5b5dSValentin Clement       // initialization is on the full range.
831044d5b5dSValentin Clement       auto insertOnRangeOps = gr.front().getOps<fir::InsertOnRangeOp>();
832044d5b5dSValentin Clement       for (auto insertOp : insertOnRangeOps) {
833044d5b5dSValentin Clement         if (isFullRange(insertOp.coor(), insertOp.getType())) {
834044d5b5dSValentin Clement           auto seqTyAttr = convertType(insertOp.getType());
835044d5b5dSValentin Clement           auto *op = insertOp.val().getDefiningOp();
836044d5b5dSValentin Clement           auto constant = mlir::dyn_cast<mlir::arith::ConstantOp>(op);
837044d5b5dSValentin Clement           if (!constant) {
838044d5b5dSValentin Clement             auto convertOp = mlir::dyn_cast<fir::ConvertOp>(op);
839044d5b5dSValentin Clement             if (!convertOp)
840044d5b5dSValentin Clement               continue;
841044d5b5dSValentin Clement             constant = cast<mlir::arith::ConstantOp>(
842044d5b5dSValentin Clement                 convertOp.value().getDefiningOp());
843044d5b5dSValentin Clement           }
844044d5b5dSValentin Clement           mlir::Type vecType = mlir::VectorType::get(
845044d5b5dSValentin Clement               insertOp.getType().getShape(), constant.getType());
846044d5b5dSValentin Clement           auto denseAttr = mlir::DenseElementsAttr::get(
847044d5b5dSValentin Clement               vecType.cast<ShapedType>(), constant.value());
848044d5b5dSValentin Clement           rewriter.setInsertionPointAfter(insertOp);
849044d5b5dSValentin Clement           rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(
850044d5b5dSValentin Clement               insertOp, seqTyAttr, denseAttr);
851044d5b5dSValentin Clement         }
852044d5b5dSValentin Clement       }
853044d5b5dSValentin Clement     }
854044d5b5dSValentin Clement     rewriter.eraseOp(global);
855044d5b5dSValentin Clement     return success();
856044d5b5dSValentin Clement   }
857044d5b5dSValentin Clement 
858044d5b5dSValentin Clement   bool isFullRange(mlir::ArrayAttr indexes, fir::SequenceType seqTy) const {
859044d5b5dSValentin Clement     auto extents = seqTy.getShape();
860044d5b5dSValentin Clement     if (indexes.size() / 2 != extents.size())
861044d5b5dSValentin Clement       return false;
862044d5b5dSValentin Clement     for (unsigned i = 0; i < indexes.size(); i += 2) {
863044d5b5dSValentin Clement       if (indexes[i].cast<IntegerAttr>().getInt() != 0)
864044d5b5dSValentin Clement         return false;
865044d5b5dSValentin Clement       if (indexes[i + 1].cast<IntegerAttr>().getInt() != extents[i / 2] - 1)
866044d5b5dSValentin Clement         return false;
867044d5b5dSValentin Clement     }
868044d5b5dSValentin Clement     return true;
869044d5b5dSValentin Clement   }
870044d5b5dSValentin Clement 
8710c4a7a52SValentin Clement   // TODO: String comparaison should be avoided. Replace linkName with an
8720c4a7a52SValentin Clement   // enumeration.
873044d5b5dSValentin Clement   mlir::LLVM::Linkage convertLinkage(Optional<StringRef> optLinkage) const {
874044d5b5dSValentin Clement     if (optLinkage.hasValue()) {
875044d5b5dSValentin Clement       auto name = optLinkage.getValue();
876044d5b5dSValentin Clement       if (name == "internal")
877044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Internal;
878044d5b5dSValentin Clement       if (name == "linkonce")
879044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Linkonce;
880044d5b5dSValentin Clement       if (name == "common")
881044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Common;
882044d5b5dSValentin Clement       if (name == "weak")
883044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Weak;
884044d5b5dSValentin Clement     }
885044d5b5dSValentin Clement     return mlir::LLVM::Linkage::External;
886044d5b5dSValentin Clement   }
887044d5b5dSValentin Clement };
888044d5b5dSValentin Clement 
88939f4ef81SValentin Clement void genCondBrOp(mlir::Location loc, mlir::Value cmp, mlir::Block *dest,
89039f4ef81SValentin Clement                  Optional<mlir::ValueRange> destOps,
89139f4ef81SValentin Clement                  mlir::ConversionPatternRewriter &rewriter,
89239f4ef81SValentin Clement                  mlir::Block *newBlock) {
89339f4ef81SValentin Clement   if (destOps.hasValue())
89439f4ef81SValentin Clement     rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, destOps.getValue(),
89539f4ef81SValentin Clement                                           newBlock, mlir::ValueRange());
89639f4ef81SValentin Clement   else
89739f4ef81SValentin Clement     rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, newBlock);
89839f4ef81SValentin Clement }
89939f4ef81SValentin Clement 
90039f4ef81SValentin Clement template <typename A, typename B>
90139f4ef81SValentin Clement void genBrOp(A caseOp, mlir::Block *dest, Optional<B> destOps,
90239f4ef81SValentin Clement              mlir::ConversionPatternRewriter &rewriter) {
90339f4ef81SValentin Clement   if (destOps.hasValue())
90439f4ef81SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, destOps.getValue(),
90539f4ef81SValentin Clement                                                   dest);
90639f4ef81SValentin Clement   else
90739f4ef81SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, llvm::None, dest);
90839f4ef81SValentin Clement }
90939f4ef81SValentin Clement 
91039f4ef81SValentin Clement void genCaseLadderStep(mlir::Location loc, mlir::Value cmp, mlir::Block *dest,
91139f4ef81SValentin Clement                        Optional<mlir::ValueRange> destOps,
91239f4ef81SValentin Clement                        mlir::ConversionPatternRewriter &rewriter) {
91339f4ef81SValentin Clement   auto *thisBlock = rewriter.getInsertionBlock();
91439f4ef81SValentin Clement   auto *newBlock = createBlock(rewriter, dest);
91539f4ef81SValentin Clement   rewriter.setInsertionPointToEnd(thisBlock);
91639f4ef81SValentin Clement   genCondBrOp(loc, cmp, dest, destOps, rewriter, newBlock);
91739f4ef81SValentin Clement   rewriter.setInsertionPointToEnd(newBlock);
91839f4ef81SValentin Clement }
91939f4ef81SValentin Clement 
92039f4ef81SValentin Clement /// Conversion of `fir.select_case`
92139f4ef81SValentin Clement ///
92239f4ef81SValentin Clement /// The `fir.select_case` operation is converted to a if-then-else ladder.
92339f4ef81SValentin Clement /// Depending on the case condition type, one or several comparison and
92439f4ef81SValentin Clement /// conditional branching can be generated.
92539f4ef81SValentin Clement ///
92639f4ef81SValentin Clement /// A a point value case such as `case(4)`, a lower bound case such as
92739f4ef81SValentin Clement /// `case(5:)` or an upper bound case such as `case(:3)` are converted to a
92839f4ef81SValentin Clement /// simple comparison between the selector value and the constant value in the
92939f4ef81SValentin Clement /// case. The block associated with the case condition is then executed if
93039f4ef81SValentin Clement /// the comparison succeed otherwise it branch to the next block with the
93139f4ef81SValentin Clement /// comparison for the the next case conditon.
93239f4ef81SValentin Clement ///
93339f4ef81SValentin Clement /// A closed interval case condition such as `case(7:10)` is converted with a
93439f4ef81SValentin Clement /// first comparison and conditional branching for the lower bound. If
93539f4ef81SValentin Clement /// successful, it branch to a second block with the comparison for the
93639f4ef81SValentin Clement /// upper bound in the same case condition.
93739f4ef81SValentin Clement ///
93839f4ef81SValentin Clement /// TODO: lowering of CHARACTER type cases is not handled yet.
93939f4ef81SValentin Clement struct SelectCaseOpConversion : public FIROpConversion<fir::SelectCaseOp> {
94039f4ef81SValentin Clement   using FIROpConversion::FIROpConversion;
94139f4ef81SValentin Clement 
94239f4ef81SValentin Clement   mlir::LogicalResult
94339f4ef81SValentin Clement   matchAndRewrite(fir::SelectCaseOp caseOp, OpAdaptor adaptor,
94439f4ef81SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
94539f4ef81SValentin Clement     unsigned conds = caseOp.getNumConditions();
94639f4ef81SValentin Clement     llvm::ArrayRef<mlir::Attribute> cases = caseOp.getCases().getValue();
94739f4ef81SValentin Clement     // Type can be CHARACTER, INTEGER, or LOGICAL (C1145)
94839f4ef81SValentin Clement     LLVM_ATTRIBUTE_UNUSED auto ty = caseOp.getSelector().getType();
94939f4ef81SValentin Clement     if (ty.isa<fir::CharacterType>())
95039f4ef81SValentin Clement       return rewriter.notifyMatchFailure(caseOp,
95139f4ef81SValentin Clement                                          "conversion of fir.select_case with "
95239f4ef81SValentin Clement                                          "character type not implemented yet");
95339f4ef81SValentin Clement     mlir::Value selector = caseOp.getSelector(adaptor.getOperands());
95439f4ef81SValentin Clement     auto loc = caseOp.getLoc();
95539f4ef81SValentin Clement     for (unsigned t = 0; t != conds; ++t) {
95639f4ef81SValentin Clement       mlir::Block *dest = caseOp.getSuccessor(t);
95739f4ef81SValentin Clement       llvm::Optional<mlir::ValueRange> destOps =
95839f4ef81SValentin Clement           caseOp.getSuccessorOperands(adaptor.getOperands(), t);
95939f4ef81SValentin Clement       llvm::Optional<mlir::ValueRange> cmpOps =
96039f4ef81SValentin Clement           *caseOp.getCompareOperands(adaptor.getOperands(), t);
96139f4ef81SValentin Clement       mlir::Value caseArg = *(cmpOps.getValue().begin());
96239f4ef81SValentin Clement       mlir::Attribute attr = cases[t];
96339f4ef81SValentin Clement       if (attr.isa<fir::PointIntervalAttr>()) {
96439f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
96539f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::eq, selector, caseArg);
96639f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
96739f4ef81SValentin Clement         continue;
96839f4ef81SValentin Clement       }
96939f4ef81SValentin Clement       if (attr.isa<fir::LowerBoundAttr>()) {
97039f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
97139f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector);
97239f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
97339f4ef81SValentin Clement         continue;
97439f4ef81SValentin Clement       }
97539f4ef81SValentin Clement       if (attr.isa<fir::UpperBoundAttr>()) {
97639f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
97739f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg);
97839f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
97939f4ef81SValentin Clement         continue;
98039f4ef81SValentin Clement       }
98139f4ef81SValentin Clement       if (attr.isa<fir::ClosedIntervalAttr>()) {
98239f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
98339f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector);
98439f4ef81SValentin Clement         auto *thisBlock = rewriter.getInsertionBlock();
98539f4ef81SValentin Clement         auto *newBlock1 = createBlock(rewriter, dest);
98639f4ef81SValentin Clement         auto *newBlock2 = createBlock(rewriter, dest);
98739f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(thisBlock);
98839f4ef81SValentin Clement         rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, newBlock1, newBlock2);
98939f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(newBlock1);
99039f4ef81SValentin Clement         mlir::Value caseArg0 = *(cmpOps.getValue().begin() + 1);
99139f4ef81SValentin Clement         auto cmp0 = rewriter.create<mlir::LLVM::ICmpOp>(
99239f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg0);
99339f4ef81SValentin Clement         genCondBrOp(loc, cmp0, dest, destOps, rewriter, newBlock2);
99439f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(newBlock2);
99539f4ef81SValentin Clement         continue;
99639f4ef81SValentin Clement       }
99739f4ef81SValentin Clement       assert(attr.isa<mlir::UnitAttr>());
99839f4ef81SValentin Clement       assert((t + 1 == conds) && "unit must be last");
99939f4ef81SValentin Clement       genBrOp(caseOp, dest, destOps, rewriter);
100039f4ef81SValentin Clement     }
100139f4ef81SValentin Clement     return success();
100239f4ef81SValentin Clement   }
100339f4ef81SValentin Clement };
100439f4ef81SValentin Clement 
10058c239909SValentin Clement template <typename OP>
10068c239909SValentin Clement void selectMatchAndRewrite(fir::LLVMTypeConverter &lowering, OP select,
10078c239909SValentin Clement                            typename OP::Adaptor adaptor,
10088c239909SValentin Clement                            mlir::ConversionPatternRewriter &rewriter) {
10098c239909SValentin Clement   unsigned conds = select.getNumConditions();
10108c239909SValentin Clement   auto cases = select.getCases().getValue();
10118c239909SValentin Clement   mlir::Value selector = adaptor.selector();
10128c239909SValentin Clement   auto loc = select.getLoc();
10138c239909SValentin Clement   assert(conds > 0 && "select must have cases");
10148c239909SValentin Clement 
10158c239909SValentin Clement   llvm::SmallVector<mlir::Block *> destinations;
10168c239909SValentin Clement   llvm::SmallVector<mlir::ValueRange> destinationsOperands;
10178c239909SValentin Clement   mlir::Block *defaultDestination;
10188c239909SValentin Clement   mlir::ValueRange defaultOperands;
10198c239909SValentin Clement   llvm::SmallVector<int32_t> caseValues;
10208c239909SValentin Clement 
10218c239909SValentin Clement   for (unsigned t = 0; t != conds; ++t) {
10228c239909SValentin Clement     mlir::Block *dest = select.getSuccessor(t);
10238c239909SValentin Clement     auto destOps = select.getSuccessorOperands(adaptor.getOperands(), t);
10248c239909SValentin Clement     const mlir::Attribute &attr = cases[t];
10258c239909SValentin Clement     if (auto intAttr = attr.template dyn_cast<mlir::IntegerAttr>()) {
10268c239909SValentin Clement       destinations.push_back(dest);
10278c239909SValentin Clement       destinationsOperands.push_back(destOps.hasValue() ? *destOps
10288c239909SValentin Clement                                                         : ValueRange());
10298c239909SValentin Clement       caseValues.push_back(intAttr.getInt());
10308c239909SValentin Clement       continue;
10318c239909SValentin Clement     }
10328c239909SValentin Clement     assert(attr.template dyn_cast_or_null<mlir::UnitAttr>());
10338c239909SValentin Clement     assert((t + 1 == conds) && "unit must be last");
10348c239909SValentin Clement     defaultDestination = dest;
10358c239909SValentin Clement     defaultOperands = destOps.hasValue() ? *destOps : ValueRange();
10368c239909SValentin Clement   }
10378c239909SValentin Clement 
10388c239909SValentin Clement   // LLVM::SwitchOp takes a i32 type for the selector.
10398c239909SValentin Clement   if (select.getSelector().getType() != rewriter.getI32Type())
10408c239909SValentin Clement     selector =
10418c239909SValentin Clement         rewriter.create<LLVM::TruncOp>(loc, rewriter.getI32Type(), selector);
10428c239909SValentin Clement 
10438c239909SValentin Clement   rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>(
10448c239909SValentin Clement       select, selector,
10458c239909SValentin Clement       /*defaultDestination=*/defaultDestination,
10468c239909SValentin Clement       /*defaultOperands=*/defaultOperands,
10478c239909SValentin Clement       /*caseValues=*/caseValues,
10488c239909SValentin Clement       /*caseDestinations=*/destinations,
10498c239909SValentin Clement       /*caseOperands=*/destinationsOperands,
10508c239909SValentin Clement       /*branchWeights=*/ArrayRef<int32_t>());
10518c239909SValentin Clement }
10528c239909SValentin Clement 
10538c239909SValentin Clement /// conversion of fir::SelectOp to an if-then-else ladder
10548c239909SValentin Clement struct SelectOpConversion : public FIROpConversion<fir::SelectOp> {
10558c239909SValentin Clement   using FIROpConversion::FIROpConversion;
10568c239909SValentin Clement 
10578c239909SValentin Clement   mlir::LogicalResult
10588c239909SValentin Clement   matchAndRewrite(fir::SelectOp op, OpAdaptor adaptor,
10598c239909SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
10608c239909SValentin Clement     selectMatchAndRewrite<fir::SelectOp>(lowerTy(), op, adaptor, rewriter);
10618c239909SValentin Clement     return success();
10628c239909SValentin Clement   }
10638c239909SValentin Clement };
10648c239909SValentin Clement 
1065e3349fa1SAndrzej Warzynski /// `fir.load` --> `llvm.load`
1066e3349fa1SAndrzej Warzynski struct LoadOpConversion : public FIROpConversion<fir::LoadOp> {
1067e3349fa1SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
1068e3349fa1SAndrzej Warzynski 
1069e3349fa1SAndrzej Warzynski   mlir::LogicalResult
1070e3349fa1SAndrzej Warzynski   matchAndRewrite(fir::LoadOp load, OpAdaptor adaptor,
1071e3349fa1SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
1072e3349fa1SAndrzej Warzynski     // fir.box is a special case because it is considered as an ssa values in
1073e3349fa1SAndrzej Warzynski     // fir, but it is lowered as a pointer to a descriptor. So fir.ref<fir.box>
1074e3349fa1SAndrzej Warzynski     // and fir.box end up being the same llvm types and loading a
1075e3349fa1SAndrzej Warzynski     // fir.ref<fir.box> is actually a no op in LLVM.
1076e3349fa1SAndrzej Warzynski     if (load.getType().isa<fir::BoxType>()) {
1077e3349fa1SAndrzej Warzynski       rewriter.replaceOp(load, adaptor.getOperands()[0]);
1078e3349fa1SAndrzej Warzynski     } else {
1079e3349fa1SAndrzej Warzynski       mlir::Type ty = convertType(load.getType());
1080e3349fa1SAndrzej Warzynski       ArrayRef<NamedAttribute> at = load->getAttrs();
1081e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::LoadOp>(
1082e3349fa1SAndrzej Warzynski           load, ty, adaptor.getOperands(), at);
1083e3349fa1SAndrzej Warzynski     }
1084e3349fa1SAndrzej Warzynski     return success();
1085e3349fa1SAndrzej Warzynski   }
1086e3349fa1SAndrzej Warzynski };
1087e3349fa1SAndrzej Warzynski 
10882a299e4fSValentin Clement /// Lower `fir.select_type` to LLVM IR dialect.
10892a299e4fSValentin Clement struct SelectTypeOpConversion : public FIROpConversion<fir::SelectTypeOp> {
10902a299e4fSValentin Clement   using FIROpConversion::FIROpConversion;
10912a299e4fSValentin Clement 
10922a299e4fSValentin Clement   mlir::LogicalResult
10932a299e4fSValentin Clement   matchAndRewrite(fir::SelectTypeOp select, OpAdaptor adaptor,
10942a299e4fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
10952a299e4fSValentin Clement     return rewriter.notifyMatchFailure(
10962a299e4fSValentin Clement         select, "fir.select_type codegen is not implemented yet");
10972a299e4fSValentin Clement   }
10982a299e4fSValentin Clement };
10992a299e4fSValentin Clement 
11008c239909SValentin Clement /// conversion of fir::SelectRankOp to an if-then-else ladder
11018c239909SValentin Clement struct SelectRankOpConversion : public FIROpConversion<fir::SelectRankOp> {
11028c239909SValentin Clement   using FIROpConversion::FIROpConversion;
11038c239909SValentin Clement 
11048c239909SValentin Clement   mlir::LogicalResult
11058c239909SValentin Clement   matchAndRewrite(fir::SelectRankOp op, OpAdaptor adaptor,
11068c239909SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
11078c239909SValentin Clement     selectMatchAndRewrite<fir::SelectRankOp>(lowerTy(), op, adaptor, rewriter);
11088c239909SValentin Clement     return success();
11098c239909SValentin Clement   }
11108c239909SValentin Clement };
11118c239909SValentin Clement 
1112e3349fa1SAndrzej Warzynski /// `fir.store` --> `llvm.store`
1113e3349fa1SAndrzej Warzynski struct StoreOpConversion : public FIROpConversion<fir::StoreOp> {
1114e3349fa1SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
1115e3349fa1SAndrzej Warzynski 
1116e3349fa1SAndrzej Warzynski   mlir::LogicalResult
1117e3349fa1SAndrzej Warzynski   matchAndRewrite(fir::StoreOp store, OpAdaptor adaptor,
1118e3349fa1SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
1119e3349fa1SAndrzej Warzynski     if (store.value().getType().isa<fir::BoxType>()) {
1120e3349fa1SAndrzej Warzynski       // fir.box value is actually in memory, load it first before storing it.
1121e3349fa1SAndrzej Warzynski       mlir::Location loc = store.getLoc();
1122e3349fa1SAndrzej Warzynski       mlir::Type boxPtrTy = adaptor.getOperands()[0].getType();
1123e3349fa1SAndrzej Warzynski       auto val = rewriter.create<mlir::LLVM::LoadOp>(
1124e3349fa1SAndrzej Warzynski           loc, boxPtrTy.cast<mlir::LLVM::LLVMPointerType>().getElementType(),
1125e3349fa1SAndrzej Warzynski           adaptor.getOperands()[0]);
1126e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
1127e3349fa1SAndrzej Warzynski           store, val, adaptor.getOperands()[1]);
1128e3349fa1SAndrzej Warzynski     } else {
1129e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
1130e3349fa1SAndrzej Warzynski           store, adaptor.getOperands()[0], adaptor.getOperands()[1]);
1131e3349fa1SAndrzej Warzynski     }
1132e3349fa1SAndrzej Warzynski     return success();
1133e3349fa1SAndrzej Warzynski   }
1134e3349fa1SAndrzej Warzynski };
1135e3349fa1SAndrzej Warzynski 
1136e3349fa1SAndrzej Warzynski /// convert to LLVM IR dialect `undef`
1137044d5b5dSValentin Clement struct UndefOpConversion : public FIROpConversion<fir::UndefOp> {
1138044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
1139044d5b5dSValentin Clement 
1140044d5b5dSValentin Clement   mlir::LogicalResult
1141044d5b5dSValentin Clement   matchAndRewrite(fir::UndefOp undef, OpAdaptor,
1142044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1143044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::UndefOp>(
1144044d5b5dSValentin Clement         undef, convertType(undef.getType()));
1145044d5b5dSValentin Clement     return success();
1146044d5b5dSValentin Clement   }
1147044d5b5dSValentin Clement };
1148a7a61359SValentin Clement 
1149e3349fa1SAndrzej Warzynski /// `fir.unreachable` --> `llvm.unreachable`
115032e08248SAndrzej Warzynski struct UnreachableOpConversion : public FIROpConversion<fir::UnreachableOp> {
115132e08248SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
115232e08248SAndrzej Warzynski 
115332e08248SAndrzej Warzynski   mlir::LogicalResult
115432e08248SAndrzej Warzynski   matchAndRewrite(fir::UnreachableOp unreach, OpAdaptor adaptor,
115532e08248SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
115632e08248SAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(unreach);
115732e08248SAndrzej Warzynski     return success();
115832e08248SAndrzej Warzynski   }
115932e08248SAndrzej Warzynski };
116032e08248SAndrzej Warzynski 
1161a7a61359SValentin Clement struct ZeroOpConversion : public FIROpConversion<fir::ZeroOp> {
1162a7a61359SValentin Clement   using FIROpConversion::FIROpConversion;
1163a7a61359SValentin Clement 
1164a7a61359SValentin Clement   mlir::LogicalResult
1165a7a61359SValentin Clement   matchAndRewrite(fir::ZeroOp zero, OpAdaptor,
1166a7a61359SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1167a7a61359SValentin Clement     auto ty = convertType(zero.getType());
1168a7a61359SValentin Clement     if (ty.isa<mlir::LLVM::LLVMPointerType>()) {
1169a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(zero, ty);
1170a7a61359SValentin Clement     } else if (ty.isa<mlir::IntegerType>()) {
1171a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
1172a7a61359SValentin Clement           zero, ty, mlir::IntegerAttr::get(zero.getType(), 0));
1173a7a61359SValentin Clement     } else if (mlir::LLVM::isCompatibleFloatingPointType(ty)) {
1174a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
1175a7a61359SValentin Clement           zero, ty, mlir::FloatAttr::get(zero.getType(), 0.0));
1176a7a61359SValentin Clement     } else {
1177a7a61359SValentin Clement       // TODO: create ConstantAggregateZero for FIR aggregate/array types.
117852d813edSValentin Clement       return rewriter.notifyMatchFailure(
117952d813edSValentin Clement           zero,
1180a7a61359SValentin Clement           "conversion of fir.zero with aggregate type not implemented yet");
1181a7a61359SValentin Clement     }
1182a7a61359SValentin Clement     return success();
1183a7a61359SValentin Clement   }
1184a7a61359SValentin Clement };
118532e08248SAndrzej Warzynski 
118654c56347SValentin Clement // Code shared between insert_value and extract_value Ops.
118754c56347SValentin Clement struct ValueOpCommon {
118854c56347SValentin Clement   // Translate the arguments pertaining to any multidimensional array to
118954c56347SValentin Clement   // row-major order for LLVM-IR.
119054c56347SValentin Clement   static void toRowMajor(SmallVectorImpl<mlir::Attribute> &attrs,
119154c56347SValentin Clement                          mlir::Type ty) {
119254c56347SValentin Clement     assert(ty && "type is null");
119354c56347SValentin Clement     const auto end = attrs.size();
119454c56347SValentin Clement     for (std::remove_const_t<decltype(end)> i = 0; i < end; ++i) {
119554c56347SValentin Clement       if (auto seq = ty.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
119654c56347SValentin Clement         const auto dim = getDimension(seq);
119754c56347SValentin Clement         if (dim > 1) {
119854c56347SValentin Clement           auto ub = std::min(i + dim, end);
119954c56347SValentin Clement           std::reverse(attrs.begin() + i, attrs.begin() + ub);
120054c56347SValentin Clement           i += dim - 1;
120154c56347SValentin Clement         }
120254c56347SValentin Clement         ty = getArrayElementType(seq);
120354c56347SValentin Clement       } else if (auto st = ty.dyn_cast<mlir::LLVM::LLVMStructType>()) {
120454c56347SValentin Clement         ty = st.getBody()[attrs[i].cast<mlir::IntegerAttr>().getInt()];
120554c56347SValentin Clement       } else {
120654c56347SValentin Clement         llvm_unreachable("index into invalid type");
120754c56347SValentin Clement       }
120854c56347SValentin Clement     }
120954c56347SValentin Clement   }
121054c56347SValentin Clement 
121154c56347SValentin Clement   static llvm::SmallVector<mlir::Attribute>
121254c56347SValentin Clement   collectIndices(mlir::ConversionPatternRewriter &rewriter,
121354c56347SValentin Clement                  mlir::ArrayAttr arrAttr) {
121454c56347SValentin Clement     llvm::SmallVector<mlir::Attribute> attrs;
121554c56347SValentin Clement     for (auto i = arrAttr.begin(), e = arrAttr.end(); i != e; ++i) {
121654c56347SValentin Clement       if (i->isa<mlir::IntegerAttr>()) {
121754c56347SValentin Clement         attrs.push_back(*i);
121854c56347SValentin Clement       } else {
121954c56347SValentin Clement         auto fieldName = i->cast<mlir::StringAttr>().getValue();
122054c56347SValentin Clement         ++i;
122154c56347SValentin Clement         auto ty = i->cast<mlir::TypeAttr>().getValue();
122254c56347SValentin Clement         auto index = ty.cast<fir::RecordType>().getFieldIndex(fieldName);
122354c56347SValentin Clement         attrs.push_back(mlir::IntegerAttr::get(rewriter.getI32Type(), index));
122454c56347SValentin Clement       }
122554c56347SValentin Clement     }
122654c56347SValentin Clement     return attrs;
122754c56347SValentin Clement   }
122854c56347SValentin Clement 
122954c56347SValentin Clement private:
123054c56347SValentin Clement   static unsigned getDimension(mlir::LLVM::LLVMArrayType ty) {
123154c56347SValentin Clement     unsigned result = 1;
123254c56347SValentin Clement     for (auto eleTy = ty.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>();
123354c56347SValentin Clement          eleTy;
123454c56347SValentin Clement          eleTy = eleTy.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>())
123554c56347SValentin Clement       ++result;
123654c56347SValentin Clement     return result;
123754c56347SValentin Clement   }
123854c56347SValentin Clement 
123954c56347SValentin Clement   static mlir::Type getArrayElementType(mlir::LLVM::LLVMArrayType ty) {
124054c56347SValentin Clement     auto eleTy = ty.getElementType();
124154c56347SValentin Clement     while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>())
124254c56347SValentin Clement       eleTy = arrTy.getElementType();
124354c56347SValentin Clement     return eleTy;
124454c56347SValentin Clement   }
124554c56347SValentin Clement };
124654c56347SValentin Clement 
124754c56347SValentin Clement /// Extract a subobject value from an ssa-value of aggregate type
124854c56347SValentin Clement struct ExtractValueOpConversion
124954c56347SValentin Clement     : public FIROpAndTypeConversion<fir::ExtractValueOp>,
125054c56347SValentin Clement       public ValueOpCommon {
125154c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
125254c56347SValentin Clement 
125354c56347SValentin Clement   mlir::LogicalResult
125454c56347SValentin Clement   doRewrite(fir::ExtractValueOp extractVal, mlir::Type ty, OpAdaptor adaptor,
125554c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
125654c56347SValentin Clement     auto attrs = collectIndices(rewriter, extractVal.coor());
125754c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
125854c56347SValentin Clement     auto position = mlir::ArrayAttr::get(extractVal.getContext(), attrs);
125954c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(
126054c56347SValentin Clement         extractVal, ty, adaptor.getOperands()[0], position);
126154c56347SValentin Clement     return success();
126254c56347SValentin Clement   }
126354c56347SValentin Clement };
126454c56347SValentin Clement 
126554c56347SValentin Clement /// InsertValue is the generalized instruction for the composition of new
126654c56347SValentin Clement /// aggregate type values.
126754c56347SValentin Clement struct InsertValueOpConversion
126854c56347SValentin Clement     : public FIROpAndTypeConversion<fir::InsertValueOp>,
126954c56347SValentin Clement       public ValueOpCommon {
127054c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
127154c56347SValentin Clement 
127254c56347SValentin Clement   mlir::LogicalResult
127354c56347SValentin Clement   doRewrite(fir::InsertValueOp insertVal, mlir::Type ty, OpAdaptor adaptor,
127454c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
127554c56347SValentin Clement     auto attrs = collectIndices(rewriter, insertVal.coor());
127654c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
127754c56347SValentin Clement     auto position = mlir::ArrayAttr::get(insertVal.getContext(), attrs);
127854c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
127954c56347SValentin Clement         insertVal, ty, adaptor.getOperands()[0], adaptor.getOperands()[1],
128054c56347SValentin Clement         position);
128154c56347SValentin Clement     return success();
128254c56347SValentin Clement   }
128354c56347SValentin Clement };
128454c56347SValentin Clement 
12853ae8e442SValentin Clement /// InsertOnRange inserts a value into a sequence over a range of offsets.
12863ae8e442SValentin Clement struct InsertOnRangeOpConversion
12873ae8e442SValentin Clement     : public FIROpAndTypeConversion<fir::InsertOnRangeOp> {
12883ae8e442SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
12893ae8e442SValentin Clement 
12903ae8e442SValentin Clement   // Increments an array of subscripts in a row major fasion.
12913ae8e442SValentin Clement   void incrementSubscripts(const SmallVector<uint64_t> &dims,
12923ae8e442SValentin Clement                            SmallVector<uint64_t> &subscripts) const {
12933ae8e442SValentin Clement     for (size_t i = dims.size(); i > 0; --i) {
12943ae8e442SValentin Clement       if (++subscripts[i - 1] < dims[i - 1]) {
12953ae8e442SValentin Clement         return;
12963ae8e442SValentin Clement       }
12973ae8e442SValentin Clement       subscripts[i - 1] = 0;
12983ae8e442SValentin Clement     }
12993ae8e442SValentin Clement   }
13003ae8e442SValentin Clement 
13013ae8e442SValentin Clement   mlir::LogicalResult
13023ae8e442SValentin Clement   doRewrite(fir::InsertOnRangeOp range, mlir::Type ty, OpAdaptor adaptor,
13033ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
13043ae8e442SValentin Clement 
13053ae8e442SValentin Clement     llvm::SmallVector<uint64_t> dims;
13063ae8e442SValentin Clement     auto type = adaptor.getOperands()[0].getType();
13073ae8e442SValentin Clement 
13083ae8e442SValentin Clement     // Iteratively extract the array dimensions from the type.
13093ae8e442SValentin Clement     while (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
13103ae8e442SValentin Clement       dims.push_back(t.getNumElements());
13113ae8e442SValentin Clement       type = t.getElementType();
13123ae8e442SValentin Clement     }
13133ae8e442SValentin Clement 
13143ae8e442SValentin Clement     SmallVector<uint64_t> lBounds;
13153ae8e442SValentin Clement     SmallVector<uint64_t> uBounds;
13163ae8e442SValentin Clement 
13173ae8e442SValentin Clement     // Extract integer value from the attribute
13183ae8e442SValentin Clement     SmallVector<int64_t> coordinates = llvm::to_vector<4>(
13193ae8e442SValentin Clement         llvm::map_range(range.coor(), [](Attribute a) -> int64_t {
13203ae8e442SValentin Clement           return a.cast<IntegerAttr>().getInt();
13213ae8e442SValentin Clement         }));
13223ae8e442SValentin Clement 
13233ae8e442SValentin Clement     // Unzip the upper and lower bound and convert to a row major format.
13243ae8e442SValentin Clement     for (auto i = coordinates.rbegin(), e = coordinates.rend(); i != e; ++i) {
13253ae8e442SValentin Clement       uBounds.push_back(*i++);
13263ae8e442SValentin Clement       lBounds.push_back(*i);
13273ae8e442SValentin Clement     }
13283ae8e442SValentin Clement 
13293ae8e442SValentin Clement     auto &subscripts = lBounds;
13303ae8e442SValentin Clement     auto loc = range.getLoc();
13313ae8e442SValentin Clement     mlir::Value lastOp = adaptor.getOperands()[0];
13323ae8e442SValentin Clement     mlir::Value insertVal = adaptor.getOperands()[1];
13333ae8e442SValentin Clement 
13343ae8e442SValentin Clement     auto i64Ty = rewriter.getI64Type();
13353ae8e442SValentin Clement     while (subscripts != uBounds) {
13363ae8e442SValentin Clement       // Convert uint64_t's to Attribute's.
13373ae8e442SValentin Clement       SmallVector<mlir::Attribute> subscriptAttrs;
13383ae8e442SValentin Clement       for (const auto &subscript : subscripts)
13393ae8e442SValentin Clement         subscriptAttrs.push_back(IntegerAttr::get(i64Ty, subscript));
13403ae8e442SValentin Clement       lastOp = rewriter.create<mlir::LLVM::InsertValueOp>(
13413ae8e442SValentin Clement           loc, ty, lastOp, insertVal,
13423ae8e442SValentin Clement           ArrayAttr::get(range.getContext(), subscriptAttrs));
13433ae8e442SValentin Clement 
13443ae8e442SValentin Clement       incrementSubscripts(dims, subscripts);
13453ae8e442SValentin Clement     }
13463ae8e442SValentin Clement 
13473ae8e442SValentin Clement     // Convert uint64_t's to Attribute's.
13483ae8e442SValentin Clement     SmallVector<mlir::Attribute> subscriptAttrs;
13493ae8e442SValentin Clement     for (const auto &subscript : subscripts)
13503ae8e442SValentin Clement       subscriptAttrs.push_back(
13513ae8e442SValentin Clement           IntegerAttr::get(rewriter.getI64Type(), subscript));
13523ae8e442SValentin Clement     mlir::ArrayRef<mlir::Attribute> arrayRef(subscriptAttrs);
13533ae8e442SValentin Clement 
13543ae8e442SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
13553ae8e442SValentin Clement         range, ty, lastOp, insertVal,
13563ae8e442SValentin Clement         ArrayAttr::get(range.getContext(), arrayRef));
13573ae8e442SValentin Clement 
13583ae8e442SValentin Clement     return success();
13593ae8e442SValentin Clement   }
13603ae8e442SValentin Clement };
13617b5132daSValentin Clement 
13627b5132daSValentin Clement //
13637b5132daSValentin Clement // Primitive operations on Complex types
13647b5132daSValentin Clement //
13657b5132daSValentin Clement 
13667b5132daSValentin Clement /// Generate inline code for complex addition/subtraction
13677b5132daSValentin Clement template <typename LLVMOP, typename OPTY>
13687b5132daSValentin Clement mlir::LLVM::InsertValueOp complexSum(OPTY sumop, mlir::ValueRange opnds,
13697b5132daSValentin Clement                                      mlir::ConversionPatternRewriter &rewriter,
13707b5132daSValentin Clement                                      fir::LLVMTypeConverter &lowering) {
13717b5132daSValentin Clement   mlir::Value a = opnds[0];
13727b5132daSValentin Clement   mlir::Value b = opnds[1];
13737b5132daSValentin Clement   auto loc = sumop.getLoc();
13747b5132daSValentin Clement   auto ctx = sumop.getContext();
13757b5132daSValentin Clement   auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
13767b5132daSValentin Clement   auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
13777b5132daSValentin Clement   mlir::Type eleTy = lowering.convertType(getComplexEleTy(sumop.getType()));
13787b5132daSValentin Clement   mlir::Type ty = lowering.convertType(sumop.getType());
13797b5132daSValentin Clement   auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
13807b5132daSValentin Clement   auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
13817b5132daSValentin Clement   auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
13827b5132daSValentin Clement   auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
13837b5132daSValentin Clement   auto rx = rewriter.create<LLVMOP>(loc, eleTy, x0, x1);
13847b5132daSValentin Clement   auto ry = rewriter.create<LLVMOP>(loc, eleTy, y0, y1);
13857b5132daSValentin Clement   auto r0 = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
13867b5132daSValentin Clement   auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r0, rx, c0);
13877b5132daSValentin Clement   return rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ry, c1);
13887b5132daSValentin Clement }
13897b5132daSValentin Clement 
13907b5132daSValentin Clement struct AddcOpConversion : public FIROpConversion<fir::AddcOp> {
13917b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
13927b5132daSValentin Clement 
13937b5132daSValentin Clement   mlir::LogicalResult
13947b5132daSValentin Clement   matchAndRewrite(fir::AddcOp addc, OpAdaptor adaptor,
13957b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
13967b5132daSValentin Clement     // given: (x + iy) + (x' + iy')
13977b5132daSValentin Clement     // result: (x + x') + i(y + y')
13987b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FAddOp>(addc, adaptor.getOperands(),
13997b5132daSValentin Clement                                             rewriter, lowerTy());
14007b5132daSValentin Clement     rewriter.replaceOp(addc, r.getResult());
14017b5132daSValentin Clement     return success();
14027b5132daSValentin Clement   }
14037b5132daSValentin Clement };
14047b5132daSValentin Clement 
14057b5132daSValentin Clement struct SubcOpConversion : public FIROpConversion<fir::SubcOp> {
14067b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
14077b5132daSValentin Clement 
14087b5132daSValentin Clement   mlir::LogicalResult
14097b5132daSValentin Clement   matchAndRewrite(fir::SubcOp subc, OpAdaptor adaptor,
14107b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
14117b5132daSValentin Clement     // given: (x + iy) - (x' + iy')
14127b5132daSValentin Clement     // result: (x - x') + i(y - y')
14137b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FSubOp>(subc, adaptor.getOperands(),
14147b5132daSValentin Clement                                             rewriter, lowerTy());
14157b5132daSValentin Clement     rewriter.replaceOp(subc, r.getResult());
14167b5132daSValentin Clement     return success();
14177b5132daSValentin Clement   }
14187b5132daSValentin Clement };
14197b5132daSValentin Clement 
14207b5132daSValentin Clement /// Inlined complex multiply
14217b5132daSValentin Clement struct MulcOpConversion : public FIROpConversion<fir::MulcOp> {
14227b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
14237b5132daSValentin Clement 
14247b5132daSValentin Clement   mlir::LogicalResult
14257b5132daSValentin Clement   matchAndRewrite(fir::MulcOp mulc, OpAdaptor adaptor,
14267b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
14277b5132daSValentin Clement     // TODO: Can we use a call to __muldc3 ?
14287b5132daSValentin Clement     // given: (x + iy) * (x' + iy')
14297b5132daSValentin Clement     // result: (xx'-yy')+i(xy'+yx')
14307b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
14317b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
14327b5132daSValentin Clement     auto loc = mulc.getLoc();
14337b5132daSValentin Clement     auto *ctx = mulc.getContext();
14347b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
14357b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
14367b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(mulc.getType()));
14377b5132daSValentin Clement     mlir::Type ty = convertType(mulc.getType());
14387b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
14397b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
14407b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
14417b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
14427b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
14437b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
14447b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
14457b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xy, yx);
14467b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
14477b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, xx, yy);
14487b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
14497b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
14507b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
14517b5132daSValentin Clement     rewriter.replaceOp(mulc, r0.getResult());
14527b5132daSValentin Clement     return success();
14537b5132daSValentin Clement   }
14547b5132daSValentin Clement };
14557b5132daSValentin Clement 
14567b5132daSValentin Clement /// Inlined complex division
14577b5132daSValentin Clement struct DivcOpConversion : public FIROpConversion<fir::DivcOp> {
14587b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
14597b5132daSValentin Clement 
14607b5132daSValentin Clement   mlir::LogicalResult
14617b5132daSValentin Clement   matchAndRewrite(fir::DivcOp divc, OpAdaptor adaptor,
14627b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
14637b5132daSValentin Clement     // TODO: Can we use a call to __divdc3 instead?
14647b5132daSValentin Clement     // Just generate inline code for now.
14657b5132daSValentin Clement     // given: (x + iy) / (x' + iy')
14667b5132daSValentin Clement     // result: ((xx'+yy')/d) + i((yx'-xy')/d) where d = x'x' + y'y'
14677b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
14687b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
14697b5132daSValentin Clement     auto loc = divc.getLoc();
14707b5132daSValentin Clement     auto *ctx = divc.getContext();
14717b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
14727b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
14737b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(divc.getType()));
14747b5132daSValentin Clement     mlir::Type ty = convertType(divc.getType());
14757b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
14767b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
14777b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
14787b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
14797b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
14807b5132daSValentin Clement     auto x1x1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x1, x1);
14817b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
14827b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
14837b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
14847b5132daSValentin Clement     auto y1y1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y1, y1);
14857b5132daSValentin Clement     auto d = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, x1x1, y1y1);
14867b5132daSValentin Clement     auto rrn = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xx, yy);
14877b5132daSValentin Clement     auto rin = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, yx, xy);
14887b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rrn, d);
14897b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rin, d);
14907b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
14917b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
14927b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
14937b5132daSValentin Clement     rewriter.replaceOp(divc, r0.getResult());
14947b5132daSValentin Clement     return success();
14957b5132daSValentin Clement   }
14967b5132daSValentin Clement };
14977b5132daSValentin Clement 
14987b5132daSValentin Clement /// Inlined complex negation
14997b5132daSValentin Clement struct NegcOpConversion : public FIROpConversion<fir::NegcOp> {
15007b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
15017b5132daSValentin Clement 
15027b5132daSValentin Clement   mlir::LogicalResult
15037b5132daSValentin Clement   matchAndRewrite(fir::NegcOp neg, OpAdaptor adaptor,
15047b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
15057b5132daSValentin Clement     // given: -(x + iy)
15067b5132daSValentin Clement     // result: -x - iy
15077b5132daSValentin Clement     auto *ctxt = neg.getContext();
15087b5132daSValentin Clement     auto eleTy = convertType(getComplexEleTy(neg.getType()));
15097b5132daSValentin Clement     auto ty = convertType(neg.getType());
15107b5132daSValentin Clement     auto loc = neg.getLoc();
15117b5132daSValentin Clement     mlir::Value o0 = adaptor.getOperands()[0];
15127b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0));
15137b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1));
15147b5132daSValentin Clement     auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c0);
15157b5132daSValentin Clement     auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c1);
15167b5132daSValentin Clement     auto nrp = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, rp);
15177b5132daSValentin Clement     auto nip = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, ip);
15187b5132daSValentin Clement     auto r = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, o0, nrp, c0);
15197b5132daSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(neg, ty, r, nip, c1);
15207b5132daSValentin Clement     return success();
15217b5132daSValentin Clement   }
15227b5132daSValentin Clement };
15237b5132daSValentin Clement 
15241ed5a90fSValentin Clement /// Conversion pattern for operation that must be dead. The information in these
15251ed5a90fSValentin Clement /// operations is used by other operation. At this point they should not have
15261ed5a90fSValentin Clement /// anymore uses.
15271ed5a90fSValentin Clement /// These operations are normally dead after the pre-codegen pass.
15281ed5a90fSValentin Clement template <typename FromOp>
15291ed5a90fSValentin Clement struct MustBeDeadConversion : public FIROpConversion<FromOp> {
15301ed5a90fSValentin Clement   explicit MustBeDeadConversion(fir::LLVMTypeConverter &lowering)
15311ed5a90fSValentin Clement       : FIROpConversion<FromOp>(lowering) {}
15321ed5a90fSValentin Clement   using OpAdaptor = typename FromOp::Adaptor;
15331ed5a90fSValentin Clement 
15341ed5a90fSValentin Clement   mlir::LogicalResult
15351ed5a90fSValentin Clement   matchAndRewrite(FromOp op, OpAdaptor adaptor,
15361ed5a90fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const final {
15371ed5a90fSValentin Clement     if (!op->getUses().empty())
15381ed5a90fSValentin Clement       return rewriter.notifyMatchFailure(op, "op must be dead");
15391ed5a90fSValentin Clement     rewriter.eraseOp(op);
15401ed5a90fSValentin Clement     return success();
15411ed5a90fSValentin Clement   }
15421ed5a90fSValentin Clement };
15431ed5a90fSValentin Clement 
15441ed5a90fSValentin Clement struct ShapeOpConversion : public MustBeDeadConversion<fir::ShapeOp> {
15451ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
15461ed5a90fSValentin Clement };
15471ed5a90fSValentin Clement 
15481ed5a90fSValentin Clement struct ShapeShiftOpConversion : public MustBeDeadConversion<fir::ShapeShiftOp> {
15491ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
15501ed5a90fSValentin Clement };
15511ed5a90fSValentin Clement 
15521ed5a90fSValentin Clement struct ShiftOpConversion : public MustBeDeadConversion<fir::ShiftOp> {
15531ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
15541ed5a90fSValentin Clement };
15551ed5a90fSValentin Clement 
15561ed5a90fSValentin Clement struct SliceOpConversion : public MustBeDeadConversion<fir::SliceOp> {
15571ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
15581ed5a90fSValentin Clement };
15591ed5a90fSValentin Clement 
1560420ad7ceSAndrzej Warzynski /// `fir.is_present` -->
1561420ad7ceSAndrzej Warzynski /// ```
1562420ad7ceSAndrzej Warzynski ///  %0 = llvm.mlir.constant(0 : i64)
1563420ad7ceSAndrzej Warzynski ///  %1 = llvm.ptrtoint %0
1564420ad7ceSAndrzej Warzynski ///  %2 = llvm.icmp "ne" %1, %0 : i64
1565420ad7ceSAndrzej Warzynski /// ```
1566420ad7ceSAndrzej Warzynski struct IsPresentOpConversion : public FIROpConversion<fir::IsPresentOp> {
1567420ad7ceSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
1568420ad7ceSAndrzej Warzynski 
1569420ad7ceSAndrzej Warzynski   mlir::LogicalResult
1570420ad7ceSAndrzej Warzynski   matchAndRewrite(fir::IsPresentOp isPresent, OpAdaptor adaptor,
1571420ad7ceSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
1572420ad7ceSAndrzej Warzynski     mlir::Type idxTy = lowerTy().indexType();
1573420ad7ceSAndrzej Warzynski     mlir::Location loc = isPresent.getLoc();
1574420ad7ceSAndrzej Warzynski     auto ptr = adaptor.getOperands()[0];
1575420ad7ceSAndrzej Warzynski 
1576420ad7ceSAndrzej Warzynski     if (isPresent.val().getType().isa<fir::BoxCharType>()) {
1577420ad7ceSAndrzej Warzynski       auto structTy = ptr.getType().cast<mlir::LLVM::LLVMStructType>();
1578420ad7ceSAndrzej Warzynski       assert(!structTy.isOpaque() && !structTy.getBody().empty());
1579420ad7ceSAndrzej Warzynski 
1580420ad7ceSAndrzej Warzynski       mlir::Type ty = structTy.getBody()[0];
1581420ad7ceSAndrzej Warzynski       mlir::MLIRContext *ctx = isPresent.getContext();
1582420ad7ceSAndrzej Warzynski       auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
1583420ad7ceSAndrzej Warzynski       ptr = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, ptr, c0);
1584420ad7ceSAndrzej Warzynski     }
1585420ad7ceSAndrzej Warzynski     mlir::LLVM::ConstantOp c0 =
1586420ad7ceSAndrzej Warzynski         genConstantIndex(isPresent.getLoc(), idxTy, rewriter, 0);
1587420ad7ceSAndrzej Warzynski     auto addr = rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, ptr);
1588420ad7ceSAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
1589420ad7ceSAndrzej Warzynski         isPresent, mlir::LLVM::ICmpPredicate::ne, addr, c0);
1590420ad7ceSAndrzej Warzynski 
1591420ad7ceSAndrzej Warzynski     return success();
1592420ad7ceSAndrzej Warzynski   }
1593420ad7ceSAndrzej Warzynski };
15941e77b095SAndrzej Warzynski 
15951e77b095SAndrzej Warzynski /// Convert `!fir.emboxchar<!fir.char<KIND, ?>, #n>` into a sequence of
15961e77b095SAndrzej Warzynski /// instructions that generate `!llvm.struct<(ptr<ik>, i64)>`. The 1st element
15971e77b095SAndrzej Warzynski /// in this struct is a pointer. Its type is determined from `KIND`. The 2nd
15981e77b095SAndrzej Warzynski /// element is the length of the character buffer (`#n`).
15991e77b095SAndrzej Warzynski struct EmboxCharOpConversion : public FIROpConversion<fir::EmboxCharOp> {
16001e77b095SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
16011e77b095SAndrzej Warzynski 
16021e77b095SAndrzej Warzynski   mlir::LogicalResult
16031e77b095SAndrzej Warzynski   matchAndRewrite(fir::EmboxCharOp emboxChar, OpAdaptor adaptor,
16041e77b095SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
16051e77b095SAndrzej Warzynski     mlir::ValueRange operands = adaptor.getOperands();
16061e77b095SAndrzej Warzynski     MLIRContext *ctx = emboxChar.getContext();
16071e77b095SAndrzej Warzynski 
16081e77b095SAndrzej Warzynski     mlir::Value charBuffer = operands[0];
16091e77b095SAndrzej Warzynski     mlir::Value charBufferLen = operands[1];
16101e77b095SAndrzej Warzynski 
16111e77b095SAndrzej Warzynski     mlir::Location loc = emboxChar.getLoc();
16121e77b095SAndrzej Warzynski     mlir::Type llvmStructTy = convertType(emboxChar.getType());
16131e77b095SAndrzej Warzynski     auto llvmStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, llvmStructTy);
16141e77b095SAndrzej Warzynski 
16151e77b095SAndrzej Warzynski     mlir::Type lenTy =
16161e77b095SAndrzej Warzynski         llvmStructTy.cast<mlir::LLVM::LLVMStructType>().getBody()[1];
16171e77b095SAndrzej Warzynski     mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, charBufferLen);
16181e77b095SAndrzej Warzynski 
16191e77b095SAndrzej Warzynski     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
16201e77b095SAndrzej Warzynski     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
16211e77b095SAndrzej Warzynski     auto insertBufferOp = rewriter.create<mlir::LLVM::InsertValueOp>(
16221e77b095SAndrzej Warzynski         loc, llvmStructTy, llvmStruct, charBuffer, c0);
16231e77b095SAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
16241e77b095SAndrzej Warzynski         emboxChar, llvmStructTy, insertBufferOp, lenAfterCast, c1);
16251e77b095SAndrzej Warzynski 
16261e77b095SAndrzej Warzynski     return success();
16271e77b095SAndrzej Warzynski   }
16281e77b095SAndrzej Warzynski };
162914867ffcSAndrzej Warzynski 
163014867ffcSAndrzej Warzynski /// Construct an `llvm.extractvalue` instruction. It will return value at
163114867ffcSAndrzej Warzynski /// element \p x from  \p tuple.
163214867ffcSAndrzej Warzynski mlir::LLVM::ExtractValueOp
163314867ffcSAndrzej Warzynski genExtractValueWithIndex(mlir::Location loc, mlir::Value tuple, mlir::Type ty,
163414867ffcSAndrzej Warzynski                          mlir::ConversionPatternRewriter &rewriter,
163514867ffcSAndrzej Warzynski                          mlir::MLIRContext *ctx, int x) {
163614867ffcSAndrzej Warzynski   auto cx = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(x));
163714867ffcSAndrzej Warzynski   auto xty = ty.cast<mlir::LLVM::LLVMStructType>().getBody()[x];
163814867ffcSAndrzej Warzynski   return rewriter.create<mlir::LLVM::ExtractValueOp>(loc, xty, tuple, cx);
163914867ffcSAndrzej Warzynski }
164014867ffcSAndrzej Warzynski 
16416c3d7fd4SAndrzej Warzynski /// Convert `!fir.boxchar_len` to  `!llvm.extractvalue` for the 2nd part of the
16426c3d7fd4SAndrzej Warzynski /// boxchar.
16436c3d7fd4SAndrzej Warzynski struct BoxCharLenOpConversion : public FIROpConversion<fir::BoxCharLenOp> {
16446c3d7fd4SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
16456c3d7fd4SAndrzej Warzynski 
16466c3d7fd4SAndrzej Warzynski   mlir::LogicalResult
16476c3d7fd4SAndrzej Warzynski   matchAndRewrite(fir::BoxCharLenOp boxCharLen, OpAdaptor adaptor,
16486c3d7fd4SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
16496c3d7fd4SAndrzej Warzynski     mlir::Value boxChar = adaptor.getOperands()[0];
16506c3d7fd4SAndrzej Warzynski     mlir::Location loc = boxChar.getLoc();
16516c3d7fd4SAndrzej Warzynski     mlir::MLIRContext *ctx = boxChar.getContext();
16526c3d7fd4SAndrzej Warzynski     mlir::Type returnValTy = boxCharLen.getResult().getType();
16536c3d7fd4SAndrzej Warzynski 
16546c3d7fd4SAndrzej Warzynski     constexpr int boxcharLenIdx = 1;
16556c3d7fd4SAndrzej Warzynski     mlir::LLVM::ExtractValueOp len = genExtractValueWithIndex(
16566c3d7fd4SAndrzej Warzynski         loc, boxChar, boxChar.getType(), rewriter, ctx, boxcharLenIdx);
16576c3d7fd4SAndrzej Warzynski     mlir::Value lenAfterCast = integerCast(loc, rewriter, returnValTy, len);
16586c3d7fd4SAndrzej Warzynski     rewriter.replaceOp(boxCharLen, lenAfterCast);
16596c3d7fd4SAndrzej Warzynski 
16606c3d7fd4SAndrzej Warzynski     return success();
16616c3d7fd4SAndrzej Warzynski   }
16626c3d7fd4SAndrzej Warzynski };
16636c3d7fd4SAndrzej Warzynski 
166414867ffcSAndrzej Warzynski /// Convert `fir.unboxchar` into two `llvm.extractvalue` instructions. One for
166514867ffcSAndrzej Warzynski /// the character buffer and one for the buffer length.
166614867ffcSAndrzej Warzynski struct UnboxCharOpConversion : public FIROpConversion<fir::UnboxCharOp> {
166714867ffcSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
166814867ffcSAndrzej Warzynski 
166914867ffcSAndrzej Warzynski   mlir::LogicalResult
167014867ffcSAndrzej Warzynski   matchAndRewrite(fir::UnboxCharOp unboxchar, OpAdaptor adaptor,
167114867ffcSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
167214867ffcSAndrzej Warzynski     MLIRContext *ctx = unboxchar.getContext();
167314867ffcSAndrzej Warzynski 
167414867ffcSAndrzej Warzynski     mlir::Type lenTy = convertType(unboxchar.getType(1));
167514867ffcSAndrzej Warzynski     mlir::Value tuple = adaptor.getOperands()[0];
167614867ffcSAndrzej Warzynski     mlir::Type tupleTy = tuple.getType();
167714867ffcSAndrzej Warzynski 
167814867ffcSAndrzej Warzynski     mlir::Location loc = unboxchar.getLoc();
167914867ffcSAndrzej Warzynski     mlir::Value ptrToBuffer =
168014867ffcSAndrzej Warzynski         genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 0);
168114867ffcSAndrzej Warzynski 
168214867ffcSAndrzej Warzynski     mlir::LLVM::ExtractValueOp len =
168314867ffcSAndrzej Warzynski         genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 1);
168414867ffcSAndrzej Warzynski     mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, len);
168514867ffcSAndrzej Warzynski 
168614867ffcSAndrzej Warzynski     rewriter.replaceOp(unboxchar,
168714867ffcSAndrzej Warzynski                        ArrayRef<mlir::Value>{ptrToBuffer, lenAfterCast});
168814867ffcSAndrzej Warzynski     return success();
168914867ffcSAndrzej Warzynski   }
169014867ffcSAndrzej Warzynski };
169114867ffcSAndrzej Warzynski 
1692044d5b5dSValentin Clement } // namespace
1693044d5b5dSValentin Clement 
1694044d5b5dSValentin Clement namespace {
1695044d5b5dSValentin Clement /// Convert FIR dialect to LLVM dialect
1696044d5b5dSValentin Clement ///
1697044d5b5dSValentin Clement /// This pass lowers all FIR dialect operations to LLVM IR dialect. An
1698044d5b5dSValentin Clement /// MLIR pass is used to lower residual Std dialect to LLVM IR dialect.
1699044d5b5dSValentin Clement ///
1700044d5b5dSValentin Clement /// This pass is not complete yet. We are upstreaming it in small patches.
1701044d5b5dSValentin Clement class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> {
1702044d5b5dSValentin Clement public:
1703044d5b5dSValentin Clement   mlir::ModuleOp getModule() { return getOperation(); }
1704044d5b5dSValentin Clement 
1705044d5b5dSValentin Clement   void runOnOperation() override final {
17067b5132daSValentin Clement     auto mod = getModule();
17077b5132daSValentin Clement     if (!forcedTargetTriple.empty()) {
17087b5132daSValentin Clement       fir::setTargetTriple(mod, forcedTargetTriple);
17097b5132daSValentin Clement     }
17107b5132daSValentin Clement 
1711044d5b5dSValentin Clement     auto *context = getModule().getContext();
1712044d5b5dSValentin Clement     fir::LLVMTypeConverter typeConverter{getModule()};
1713044d5b5dSValentin Clement     mlir::OwningRewritePatternList pattern(context);
1714df3b9810SValentin Clement     pattern.insert<
1715420ad7ceSAndrzej Warzynski         AbsentOpConversion, AddcOpConversion, AddrOfOpConversion,
17161a2ec667SValentin Clement         AllocaOpConversion, BoxAddrOpConversion, BoxCharLenOpConversion,
17171a2ec667SValentin Clement         BoxDimsOpConversion, BoxEleSizeOpConversion, BoxIsAllocOpConversion,
17181a2ec667SValentin Clement         BoxIsArrayOpConversion, BoxIsPtrOpConversion, BoxRankOpConversion,
1719e38ef2ffSValentin Clement         BoxTypeDescOpConversion, CallOpConversion, CmpcOpConversion,
1720*e81d73edSDiana Picus         ConstcOpConversion, ConvertOpConversion, DispatchOpConversion,
1721*e81d73edSDiana Picus         DispatchTableOpConversion, DTEntryOpConversion, DivcOpConversion,
1722*e81d73edSDiana Picus         EmboxCharOpConversion, ExtractValueOpConversion, HasValueOpConversion,
1723*e81d73edSDiana Picus         GenTypeDescOpConversion, GlobalLenOpConversion, GlobalOpConversion,
1724*e81d73edSDiana Picus         InsertOnRangeOpConversion, InsertValueOpConversion,
1725*e81d73edSDiana Picus         IsPresentOpConversion, LoadOpConversion, NegcOpConversion,
1726*e81d73edSDiana Picus         MulcOpConversion, SelectCaseOpConversion, SelectOpConversion,
1727*e81d73edSDiana Picus         SelectRankOpConversion, SelectTypeOpConversion, ShapeOpConversion,
1728*e81d73edSDiana Picus         ShapeShiftOpConversion, ShiftOpConversion, SliceOpConversion,
1729*e81d73edSDiana Picus         StoreOpConversion, StringLitOpConversion, SubcOpConversion,
1730*e81d73edSDiana Picus         UnboxCharOpConversion, UndefOpConversion, UnreachableOpConversion,
1731*e81d73edSDiana Picus         ZeroOpConversion>(typeConverter);
1732044d5b5dSValentin Clement     mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern);
1733044d5b5dSValentin Clement     mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter,
1734044d5b5dSValentin Clement                                                             pattern);
1735044d5b5dSValentin Clement     mlir::ConversionTarget target{*context};
1736044d5b5dSValentin Clement     target.addLegalDialect<mlir::LLVM::LLVMDialect>();
1737044d5b5dSValentin Clement 
1738044d5b5dSValentin Clement     // required NOPs for applying a full conversion
1739044d5b5dSValentin Clement     target.addLegalOp<mlir::ModuleOp>();
1740044d5b5dSValentin Clement 
1741044d5b5dSValentin Clement     // apply the patterns
1742044d5b5dSValentin Clement     if (mlir::failed(mlir::applyFullConversion(getModule(), target,
1743044d5b5dSValentin Clement                                                std::move(pattern)))) {
1744044d5b5dSValentin Clement       signalPassFailure();
1745044d5b5dSValentin Clement     }
1746044d5b5dSValentin Clement   }
1747044d5b5dSValentin Clement };
1748044d5b5dSValentin Clement } // namespace
1749044d5b5dSValentin Clement 
1750044d5b5dSValentin Clement std::unique_ptr<mlir::Pass> fir::createFIRToLLVMPass() {
1751044d5b5dSValentin Clement   return std::make_unique<FIRToLLVMLowering>();
1752044d5b5dSValentin Clement }
1753