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 
501ddd11b9aSAndrzej Warzynski // `fir.call` -> `llvm.call`
502ddd11b9aSAndrzej Warzynski struct CallOpConversion : public FIROpConversion<fir::CallOp> {
503ddd11b9aSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
504ddd11b9aSAndrzej Warzynski 
505ddd11b9aSAndrzej Warzynski   mlir::LogicalResult
506ddd11b9aSAndrzej Warzynski   matchAndRewrite(fir::CallOp call, OpAdaptor adaptor,
507ddd11b9aSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
508ddd11b9aSAndrzej Warzynski     SmallVector<mlir::Type> resultTys;
509ddd11b9aSAndrzej Warzynski     for (auto r : call.getResults())
510ddd11b9aSAndrzej Warzynski       resultTys.push_back(convertType(r.getType()));
511ddd11b9aSAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
512ddd11b9aSAndrzej Warzynski         call, resultTys, adaptor.getOperands(), call->getAttrs());
513ddd11b9aSAndrzej Warzynski     return success();
514ddd11b9aSAndrzej Warzynski   }
515ddd11b9aSAndrzej Warzynski };
516ddd11b9aSAndrzej Warzynski 
517092cee5fSValentin Clement static mlir::Type getComplexEleTy(mlir::Type complex) {
518092cee5fSValentin Clement   if (auto cc = complex.dyn_cast<mlir::ComplexType>())
519092cee5fSValentin Clement     return cc.getElementType();
520092cee5fSValentin Clement   return complex.cast<fir::ComplexType>().getElementType();
521092cee5fSValentin Clement }
522092cee5fSValentin Clement 
523f1dfc027SDiana Picus /// Compare complex values
524f1dfc027SDiana Picus ///
525f1dfc027SDiana Picus /// Per 10.1, the only comparisons available are .EQ. (oeq) and .NE. (une).
526f1dfc027SDiana Picus ///
527f1dfc027SDiana Picus /// For completeness, all other comparison are done on the real component only.
528f1dfc027SDiana Picus struct CmpcOpConversion : public FIROpConversion<fir::CmpcOp> {
529f1dfc027SDiana Picus   using FIROpConversion::FIROpConversion;
530f1dfc027SDiana Picus 
531f1dfc027SDiana Picus   mlir::LogicalResult
532f1dfc027SDiana Picus   matchAndRewrite(fir::CmpcOp cmp, OpAdaptor adaptor,
533f1dfc027SDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
534f1dfc027SDiana Picus     mlir::ValueRange operands = adaptor.getOperands();
535f1dfc027SDiana Picus     mlir::MLIRContext *ctxt = cmp.getContext();
536f1dfc027SDiana Picus     mlir::Type eleTy = convertType(getComplexEleTy(cmp.lhs().getType()));
537f1dfc027SDiana Picus     mlir::Type resTy = convertType(cmp.getType());
538f1dfc027SDiana Picus     mlir::Location loc = cmp.getLoc();
539f1dfc027SDiana Picus     auto pos0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0));
540f1dfc027SDiana Picus     SmallVector<mlir::Value, 2> rp{rewriter.create<mlir::LLVM::ExtractValueOp>(
541f1dfc027SDiana Picus                                        loc, eleTy, operands[0], pos0),
542f1dfc027SDiana Picus                                    rewriter.create<mlir::LLVM::ExtractValueOp>(
543f1dfc027SDiana Picus                                        loc, eleTy, operands[1], pos0)};
544f1dfc027SDiana Picus     auto rcp =
545f1dfc027SDiana Picus         rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, rp, cmp->getAttrs());
546f1dfc027SDiana Picus     auto pos1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1));
547f1dfc027SDiana Picus     SmallVector<mlir::Value, 2> ip{rewriter.create<mlir::LLVM::ExtractValueOp>(
548f1dfc027SDiana Picus                                        loc, eleTy, operands[0], pos1),
549f1dfc027SDiana Picus                                    rewriter.create<mlir::LLVM::ExtractValueOp>(
550f1dfc027SDiana Picus                                        loc, eleTy, operands[1], pos1)};
551f1dfc027SDiana Picus     auto icp =
552f1dfc027SDiana Picus         rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, ip, cmp->getAttrs());
553f1dfc027SDiana Picus     SmallVector<mlir::Value, 2> cp{rcp, icp};
554f1dfc027SDiana Picus     switch (cmp.getPredicate()) {
555f1dfc027SDiana Picus     case mlir::arith::CmpFPredicate::OEQ: // .EQ.
556f1dfc027SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(cmp, resTy, cp);
557f1dfc027SDiana Picus       break;
558f1dfc027SDiana Picus     case mlir::arith::CmpFPredicate::UNE: // .NE.
559f1dfc027SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(cmp, resTy, cp);
560f1dfc027SDiana Picus       break;
561f1dfc027SDiana Picus     default:
562f1dfc027SDiana Picus       rewriter.replaceOp(cmp, rcp.getResult());
563f1dfc027SDiana Picus       break;
564f1dfc027SDiana Picus     }
565f1dfc027SDiana Picus     return success();
566f1dfc027SDiana Picus   }
567f1dfc027SDiana Picus };
568f1dfc027SDiana Picus 
569092cee5fSValentin Clement /// convert value of from-type to value of to-type
570092cee5fSValentin Clement struct ConvertOpConversion : public FIROpConversion<fir::ConvertOp> {
571092cee5fSValentin Clement   using FIROpConversion::FIROpConversion;
572092cee5fSValentin Clement 
573092cee5fSValentin Clement   static bool isFloatingPointTy(mlir::Type ty) {
574092cee5fSValentin Clement     return ty.isa<mlir::FloatType>();
575092cee5fSValentin Clement   }
576092cee5fSValentin Clement 
577092cee5fSValentin Clement   mlir::LogicalResult
578092cee5fSValentin Clement   matchAndRewrite(fir::ConvertOp convert, OpAdaptor adaptor,
579092cee5fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
580092cee5fSValentin Clement     auto fromTy = convertType(convert.value().getType());
581092cee5fSValentin Clement     auto toTy = convertType(convert.res().getType());
582092cee5fSValentin Clement     mlir::Value op0 = adaptor.getOperands()[0];
583092cee5fSValentin Clement     if (fromTy == toTy) {
584092cee5fSValentin Clement       rewriter.replaceOp(convert, op0);
585092cee5fSValentin Clement       return success();
586092cee5fSValentin Clement     }
587092cee5fSValentin Clement     auto loc = convert.getLoc();
588092cee5fSValentin Clement     auto convertFpToFp = [&](mlir::Value val, unsigned fromBits,
589092cee5fSValentin Clement                              unsigned toBits, mlir::Type toTy) -> mlir::Value {
590092cee5fSValentin Clement       if (fromBits == toBits) {
591092cee5fSValentin Clement         // TODO: Converting between two floating-point representations with the
592092cee5fSValentin Clement         // same bitwidth is not allowed for now.
593092cee5fSValentin Clement         mlir::emitError(loc,
594092cee5fSValentin Clement                         "cannot implicitly convert between two floating-point "
595092cee5fSValentin Clement                         "representations of the same bitwidth");
596092cee5fSValentin Clement         return {};
597092cee5fSValentin Clement       }
598092cee5fSValentin Clement       if (fromBits > toBits)
599092cee5fSValentin Clement         return rewriter.create<mlir::LLVM::FPTruncOp>(loc, toTy, val);
600092cee5fSValentin Clement       return rewriter.create<mlir::LLVM::FPExtOp>(loc, toTy, val);
601092cee5fSValentin Clement     };
602092cee5fSValentin Clement     // Complex to complex conversion.
603092cee5fSValentin Clement     if (fir::isa_complex(convert.value().getType()) &&
604092cee5fSValentin Clement         fir::isa_complex(convert.res().getType())) {
605092cee5fSValentin Clement       // Special case: handle the conversion of a complex such that both the
606092cee5fSValentin Clement       // real and imaginary parts are converted together.
607092cee5fSValentin Clement       auto zero = mlir::ArrayAttr::get(convert.getContext(),
608092cee5fSValentin Clement                                        rewriter.getI32IntegerAttr(0));
609092cee5fSValentin Clement       auto one = mlir::ArrayAttr::get(convert.getContext(),
610092cee5fSValentin Clement                                       rewriter.getI32IntegerAttr(1));
611092cee5fSValentin Clement       auto ty = convertType(getComplexEleTy(convert.value().getType()));
612092cee5fSValentin Clement       auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, zero);
613092cee5fSValentin Clement       auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, one);
614092cee5fSValentin Clement       auto nt = convertType(getComplexEleTy(convert.res().getType()));
615092cee5fSValentin Clement       auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
616092cee5fSValentin Clement       auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(nt);
617092cee5fSValentin Clement       auto rc = convertFpToFp(rp, fromBits, toBits, nt);
618092cee5fSValentin Clement       auto ic = convertFpToFp(ip, fromBits, toBits, nt);
619092cee5fSValentin Clement       auto un = rewriter.create<mlir::LLVM::UndefOp>(loc, toTy);
620092cee5fSValentin Clement       auto i1 =
621092cee5fSValentin Clement           rewriter.create<mlir::LLVM::InsertValueOp>(loc, toTy, un, rc, zero);
622092cee5fSValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(convert, toTy, i1,
623092cee5fSValentin Clement                                                              ic, one);
624092cee5fSValentin Clement       return mlir::success();
625092cee5fSValentin Clement     }
626092cee5fSValentin Clement     // Floating point to floating point conversion.
627092cee5fSValentin Clement     if (isFloatingPointTy(fromTy)) {
628092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
629092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
630092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
631092cee5fSValentin Clement         auto v = convertFpToFp(op0, fromBits, toBits, toTy);
632092cee5fSValentin Clement         rewriter.replaceOp(convert, v);
633092cee5fSValentin Clement         return mlir::success();
634092cee5fSValentin Clement       }
635092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
636092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::FPToSIOp>(convert, toTy, op0);
637092cee5fSValentin Clement         return mlir::success();
638092cee5fSValentin Clement       }
639092cee5fSValentin Clement     } else if (fromTy.isa<mlir::IntegerType>()) {
640092cee5fSValentin Clement       // Integer to integer conversion.
641092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
642092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
643092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
644092cee5fSValentin Clement         assert(fromBits != toBits);
645092cee5fSValentin Clement         if (fromBits > toBits) {
646092cee5fSValentin Clement           rewriter.replaceOpWithNewOp<mlir::LLVM::TruncOp>(convert, toTy, op0);
647092cee5fSValentin Clement           return mlir::success();
648092cee5fSValentin Clement         }
649092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SExtOp>(convert, toTy, op0);
650092cee5fSValentin Clement         return mlir::success();
651092cee5fSValentin Clement       }
652092cee5fSValentin Clement       // Integer to floating point conversion.
653092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
654092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SIToFPOp>(convert, toTy, op0);
655092cee5fSValentin Clement         return mlir::success();
656092cee5fSValentin Clement       }
657092cee5fSValentin Clement       // Integer to pointer conversion.
658092cee5fSValentin Clement       if (toTy.isa<mlir::LLVM::LLVMPointerType>()) {
659092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(convert, toTy, op0);
660092cee5fSValentin Clement         return mlir::success();
661092cee5fSValentin Clement       }
662092cee5fSValentin Clement     } else if (fromTy.isa<mlir::LLVM::LLVMPointerType>()) {
663092cee5fSValentin Clement       // Pointer to integer conversion.
664092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
665092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::PtrToIntOp>(convert, toTy, op0);
666092cee5fSValentin Clement         return mlir::success();
667092cee5fSValentin Clement       }
668092cee5fSValentin Clement       // Pointer to pointer conversion.
669092cee5fSValentin Clement       if (toTy.isa<mlir::LLVM::LLVMPointerType>()) {
670092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(convert, toTy, op0);
671092cee5fSValentin Clement         return mlir::success();
672092cee5fSValentin Clement       }
673092cee5fSValentin Clement     }
674092cee5fSValentin Clement     return emitError(loc) << "cannot convert " << fromTy << " to " << toTy;
675092cee5fSValentin Clement   }
676092cee5fSValentin Clement };
677092cee5fSValentin Clement 
6789534e361SValentin Clement /// Lower `fir.dispatch` operation. A virtual call to a method in a dispatch
6799534e361SValentin Clement /// table.
6809534e361SValentin Clement struct DispatchOpConversion : public FIROpConversion<fir::DispatchOp> {
6819534e361SValentin Clement   using FIROpConversion::FIROpConversion;
6829534e361SValentin Clement 
6839534e361SValentin Clement   mlir::LogicalResult
6849534e361SValentin Clement   matchAndRewrite(fir::DispatchOp dispatch, OpAdaptor adaptor,
6859534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
6869534e361SValentin Clement     return rewriter.notifyMatchFailure(
6879534e361SValentin Clement         dispatch, "fir.dispatch codegen is not implemented yet");
6889534e361SValentin Clement   }
6899534e361SValentin Clement };
6909534e361SValentin Clement 
6919534e361SValentin Clement /// Lower `fir.dispatch_table` operation. The dispatch table for a Fortran
6929534e361SValentin Clement /// derived type.
6939534e361SValentin Clement struct DispatchTableOpConversion
6949534e361SValentin Clement     : public FIROpConversion<fir::DispatchTableOp> {
6959534e361SValentin Clement   using FIROpConversion::FIROpConversion;
6969534e361SValentin Clement 
6979534e361SValentin Clement   mlir::LogicalResult
6989534e361SValentin Clement   matchAndRewrite(fir::DispatchTableOp dispTab, OpAdaptor adaptor,
6999534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
7009534e361SValentin Clement     return rewriter.notifyMatchFailure(
7019534e361SValentin Clement         dispTab, "fir.dispatch_table codegen is not implemented yet");
7029534e361SValentin Clement   }
7039534e361SValentin Clement };
7049534e361SValentin Clement 
7059534e361SValentin Clement /// Lower `fir.dt_entry` operation. An entry in a dispatch table; binds a
7069534e361SValentin Clement /// method-name to a function.
7079534e361SValentin Clement struct DTEntryOpConversion : public FIROpConversion<fir::DTEntryOp> {
7089534e361SValentin Clement   using FIROpConversion::FIROpConversion;
7099534e361SValentin Clement 
7109534e361SValentin Clement   mlir::LogicalResult
7119534e361SValentin Clement   matchAndRewrite(fir::DTEntryOp dtEnt, OpAdaptor adaptor,
7129534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
7139534e361SValentin Clement     return rewriter.notifyMatchFailure(
7149534e361SValentin Clement         dtEnt, "fir.dt_entry codegen is not implemented yet");
7159534e361SValentin Clement   }
7169534e361SValentin Clement };
7179534e361SValentin Clement 
718677df8c7SValentin Clement /// Lower `fir.global_len` operation.
719677df8c7SValentin Clement struct GlobalLenOpConversion : public FIROpConversion<fir::GlobalLenOp> {
720677df8c7SValentin Clement   using FIROpConversion::FIROpConversion;
721677df8c7SValentin Clement 
722677df8c7SValentin Clement   mlir::LogicalResult
723677df8c7SValentin Clement   matchAndRewrite(fir::GlobalLenOp globalLen, OpAdaptor adaptor,
724677df8c7SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
725677df8c7SValentin Clement     return rewriter.notifyMatchFailure(
726677df8c7SValentin Clement         globalLen, "fir.global_len codegen is not implemented yet");
727677df8c7SValentin Clement   }
728677df8c7SValentin Clement };
729677df8c7SValentin Clement 
73031246187SValentin Clement /// Lower `fir.gentypedesc` to a global constant.
73131246187SValentin Clement struct GenTypeDescOpConversion : public FIROpConversion<fir::GenTypeDescOp> {
73231246187SValentin Clement   using FIROpConversion::FIROpConversion;
73331246187SValentin Clement 
73431246187SValentin Clement   mlir::LogicalResult
73531246187SValentin Clement   matchAndRewrite(fir::GenTypeDescOp gentypedesc, OpAdaptor adaptor,
73631246187SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
73731246187SValentin Clement     return rewriter.notifyMatchFailure(
73831246187SValentin Clement         gentypedesc, "fir.fir.gentypedesc codegen is not implemented yet");
73931246187SValentin Clement   }
74031246187SValentin Clement };
74131246187SValentin Clement 
7420c4a7a52SValentin Clement /// Lower `fir.has_value` operation to `llvm.return` operation.
743044d5b5dSValentin Clement struct HasValueOpConversion : public FIROpConversion<fir::HasValueOp> {
744044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
745044d5b5dSValentin Clement 
746044d5b5dSValentin Clement   mlir::LogicalResult
747044d5b5dSValentin Clement   matchAndRewrite(fir::HasValueOp op, OpAdaptor adaptor,
748044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
749044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, adaptor.getOperands());
750044d5b5dSValentin Clement     return success();
751044d5b5dSValentin Clement   }
752044d5b5dSValentin Clement };
753044d5b5dSValentin Clement 
7540c4a7a52SValentin Clement /// Lower `fir.global` operation to `llvm.global` operation.
7550c4a7a52SValentin Clement /// `fir.insert_on_range` operations are replaced with constant dense attribute
7560c4a7a52SValentin Clement /// if they are applied on the full range.
757044d5b5dSValentin Clement struct GlobalOpConversion : public FIROpConversion<fir::GlobalOp> {
758044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
759044d5b5dSValentin Clement 
760044d5b5dSValentin Clement   mlir::LogicalResult
761044d5b5dSValentin Clement   matchAndRewrite(fir::GlobalOp global, OpAdaptor adaptor,
762044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
763044d5b5dSValentin Clement     auto tyAttr = convertType(global.getType());
764044d5b5dSValentin Clement     if (global.getType().isa<fir::BoxType>())
765044d5b5dSValentin Clement       tyAttr = tyAttr.cast<mlir::LLVM::LLVMPointerType>().getElementType();
766044d5b5dSValentin Clement     auto loc = global.getLoc();
767044d5b5dSValentin Clement     mlir::Attribute initAttr{};
768044d5b5dSValentin Clement     if (global.initVal())
769044d5b5dSValentin Clement       initAttr = global.initVal().getValue();
770044d5b5dSValentin Clement     auto linkage = convertLinkage(global.linkName());
771044d5b5dSValentin Clement     auto isConst = global.constant().hasValue();
772044d5b5dSValentin Clement     auto g = rewriter.create<mlir::LLVM::GlobalOp>(
773044d5b5dSValentin Clement         loc, tyAttr, isConst, linkage, global.sym_name(), initAttr);
774044d5b5dSValentin Clement     auto &gr = g.getInitializerRegion();
775044d5b5dSValentin Clement     rewriter.inlineRegionBefore(global.region(), gr, gr.end());
776044d5b5dSValentin Clement     if (!gr.empty()) {
777044d5b5dSValentin Clement       // Replace insert_on_range with a constant dense attribute if the
778044d5b5dSValentin Clement       // initialization is on the full range.
779044d5b5dSValentin Clement       auto insertOnRangeOps = gr.front().getOps<fir::InsertOnRangeOp>();
780044d5b5dSValentin Clement       for (auto insertOp : insertOnRangeOps) {
781044d5b5dSValentin Clement         if (isFullRange(insertOp.coor(), insertOp.getType())) {
782044d5b5dSValentin Clement           auto seqTyAttr = convertType(insertOp.getType());
783044d5b5dSValentin Clement           auto *op = insertOp.val().getDefiningOp();
784044d5b5dSValentin Clement           auto constant = mlir::dyn_cast<mlir::arith::ConstantOp>(op);
785044d5b5dSValentin Clement           if (!constant) {
786044d5b5dSValentin Clement             auto convertOp = mlir::dyn_cast<fir::ConvertOp>(op);
787044d5b5dSValentin Clement             if (!convertOp)
788044d5b5dSValentin Clement               continue;
789044d5b5dSValentin Clement             constant = cast<mlir::arith::ConstantOp>(
790044d5b5dSValentin Clement                 convertOp.value().getDefiningOp());
791044d5b5dSValentin Clement           }
792044d5b5dSValentin Clement           mlir::Type vecType = mlir::VectorType::get(
793044d5b5dSValentin Clement               insertOp.getType().getShape(), constant.getType());
794044d5b5dSValentin Clement           auto denseAttr = mlir::DenseElementsAttr::get(
795044d5b5dSValentin Clement               vecType.cast<ShapedType>(), constant.value());
796044d5b5dSValentin Clement           rewriter.setInsertionPointAfter(insertOp);
797044d5b5dSValentin Clement           rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(
798044d5b5dSValentin Clement               insertOp, seqTyAttr, denseAttr);
799044d5b5dSValentin Clement         }
800044d5b5dSValentin Clement       }
801044d5b5dSValentin Clement     }
802044d5b5dSValentin Clement     rewriter.eraseOp(global);
803044d5b5dSValentin Clement     return success();
804044d5b5dSValentin Clement   }
805044d5b5dSValentin Clement 
806044d5b5dSValentin Clement   bool isFullRange(mlir::ArrayAttr indexes, fir::SequenceType seqTy) const {
807044d5b5dSValentin Clement     auto extents = seqTy.getShape();
808044d5b5dSValentin Clement     if (indexes.size() / 2 != extents.size())
809044d5b5dSValentin Clement       return false;
810044d5b5dSValentin Clement     for (unsigned i = 0; i < indexes.size(); i += 2) {
811044d5b5dSValentin Clement       if (indexes[i].cast<IntegerAttr>().getInt() != 0)
812044d5b5dSValentin Clement         return false;
813044d5b5dSValentin Clement       if (indexes[i + 1].cast<IntegerAttr>().getInt() != extents[i / 2] - 1)
814044d5b5dSValentin Clement         return false;
815044d5b5dSValentin Clement     }
816044d5b5dSValentin Clement     return true;
817044d5b5dSValentin Clement   }
818044d5b5dSValentin Clement 
8190c4a7a52SValentin Clement   // TODO: String comparaison should be avoided. Replace linkName with an
8200c4a7a52SValentin Clement   // enumeration.
821044d5b5dSValentin Clement   mlir::LLVM::Linkage convertLinkage(Optional<StringRef> optLinkage) const {
822044d5b5dSValentin Clement     if (optLinkage.hasValue()) {
823044d5b5dSValentin Clement       auto name = optLinkage.getValue();
824044d5b5dSValentin Clement       if (name == "internal")
825044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Internal;
826044d5b5dSValentin Clement       if (name == "linkonce")
827044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Linkonce;
828044d5b5dSValentin Clement       if (name == "common")
829044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Common;
830044d5b5dSValentin Clement       if (name == "weak")
831044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Weak;
832044d5b5dSValentin Clement     }
833044d5b5dSValentin Clement     return mlir::LLVM::Linkage::External;
834044d5b5dSValentin Clement   }
835044d5b5dSValentin Clement };
836044d5b5dSValentin Clement 
83739f4ef81SValentin Clement void genCondBrOp(mlir::Location loc, mlir::Value cmp, mlir::Block *dest,
83839f4ef81SValentin Clement                  Optional<mlir::ValueRange> destOps,
83939f4ef81SValentin Clement                  mlir::ConversionPatternRewriter &rewriter,
84039f4ef81SValentin Clement                  mlir::Block *newBlock) {
84139f4ef81SValentin Clement   if (destOps.hasValue())
84239f4ef81SValentin Clement     rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, destOps.getValue(),
84339f4ef81SValentin Clement                                           newBlock, mlir::ValueRange());
84439f4ef81SValentin Clement   else
84539f4ef81SValentin Clement     rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, newBlock);
84639f4ef81SValentin Clement }
84739f4ef81SValentin Clement 
84839f4ef81SValentin Clement template <typename A, typename B>
84939f4ef81SValentin Clement void genBrOp(A caseOp, mlir::Block *dest, Optional<B> destOps,
85039f4ef81SValentin Clement              mlir::ConversionPatternRewriter &rewriter) {
85139f4ef81SValentin Clement   if (destOps.hasValue())
85239f4ef81SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, destOps.getValue(),
85339f4ef81SValentin Clement                                                   dest);
85439f4ef81SValentin Clement   else
85539f4ef81SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, llvm::None, dest);
85639f4ef81SValentin Clement }
85739f4ef81SValentin Clement 
85839f4ef81SValentin Clement void genCaseLadderStep(mlir::Location loc, mlir::Value cmp, mlir::Block *dest,
85939f4ef81SValentin Clement                        Optional<mlir::ValueRange> destOps,
86039f4ef81SValentin Clement                        mlir::ConversionPatternRewriter &rewriter) {
86139f4ef81SValentin Clement   auto *thisBlock = rewriter.getInsertionBlock();
86239f4ef81SValentin Clement   auto *newBlock = createBlock(rewriter, dest);
86339f4ef81SValentin Clement   rewriter.setInsertionPointToEnd(thisBlock);
86439f4ef81SValentin Clement   genCondBrOp(loc, cmp, dest, destOps, rewriter, newBlock);
86539f4ef81SValentin Clement   rewriter.setInsertionPointToEnd(newBlock);
86639f4ef81SValentin Clement }
86739f4ef81SValentin Clement 
86839f4ef81SValentin Clement /// Conversion of `fir.select_case`
86939f4ef81SValentin Clement ///
87039f4ef81SValentin Clement /// The `fir.select_case` operation is converted to a if-then-else ladder.
87139f4ef81SValentin Clement /// Depending on the case condition type, one or several comparison and
87239f4ef81SValentin Clement /// conditional branching can be generated.
87339f4ef81SValentin Clement ///
87439f4ef81SValentin Clement /// A a point value case such as `case(4)`, a lower bound case such as
87539f4ef81SValentin Clement /// `case(5:)` or an upper bound case such as `case(:3)` are converted to a
87639f4ef81SValentin Clement /// simple comparison between the selector value and the constant value in the
87739f4ef81SValentin Clement /// case. The block associated with the case condition is then executed if
87839f4ef81SValentin Clement /// the comparison succeed otherwise it branch to the next block with the
87939f4ef81SValentin Clement /// comparison for the the next case conditon.
88039f4ef81SValentin Clement ///
88139f4ef81SValentin Clement /// A closed interval case condition such as `case(7:10)` is converted with a
88239f4ef81SValentin Clement /// first comparison and conditional branching for the lower bound. If
88339f4ef81SValentin Clement /// successful, it branch to a second block with the comparison for the
88439f4ef81SValentin Clement /// upper bound in the same case condition.
88539f4ef81SValentin Clement ///
88639f4ef81SValentin Clement /// TODO: lowering of CHARACTER type cases is not handled yet.
88739f4ef81SValentin Clement struct SelectCaseOpConversion : public FIROpConversion<fir::SelectCaseOp> {
88839f4ef81SValentin Clement   using FIROpConversion::FIROpConversion;
88939f4ef81SValentin Clement 
89039f4ef81SValentin Clement   mlir::LogicalResult
89139f4ef81SValentin Clement   matchAndRewrite(fir::SelectCaseOp caseOp, OpAdaptor adaptor,
89239f4ef81SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
89339f4ef81SValentin Clement     unsigned conds = caseOp.getNumConditions();
89439f4ef81SValentin Clement     llvm::ArrayRef<mlir::Attribute> cases = caseOp.getCases().getValue();
89539f4ef81SValentin Clement     // Type can be CHARACTER, INTEGER, or LOGICAL (C1145)
89639f4ef81SValentin Clement     LLVM_ATTRIBUTE_UNUSED auto ty = caseOp.getSelector().getType();
89739f4ef81SValentin Clement     if (ty.isa<fir::CharacterType>())
89839f4ef81SValentin Clement       return rewriter.notifyMatchFailure(caseOp,
89939f4ef81SValentin Clement                                          "conversion of fir.select_case with "
90039f4ef81SValentin Clement                                          "character type not implemented yet");
90139f4ef81SValentin Clement     mlir::Value selector = caseOp.getSelector(adaptor.getOperands());
90239f4ef81SValentin Clement     auto loc = caseOp.getLoc();
90339f4ef81SValentin Clement     for (unsigned t = 0; t != conds; ++t) {
90439f4ef81SValentin Clement       mlir::Block *dest = caseOp.getSuccessor(t);
90539f4ef81SValentin Clement       llvm::Optional<mlir::ValueRange> destOps =
90639f4ef81SValentin Clement           caseOp.getSuccessorOperands(adaptor.getOperands(), t);
90739f4ef81SValentin Clement       llvm::Optional<mlir::ValueRange> cmpOps =
90839f4ef81SValentin Clement           *caseOp.getCompareOperands(adaptor.getOperands(), t);
90939f4ef81SValentin Clement       mlir::Value caseArg = *(cmpOps.getValue().begin());
91039f4ef81SValentin Clement       mlir::Attribute attr = cases[t];
91139f4ef81SValentin Clement       if (attr.isa<fir::PointIntervalAttr>()) {
91239f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
91339f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::eq, selector, caseArg);
91439f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
91539f4ef81SValentin Clement         continue;
91639f4ef81SValentin Clement       }
91739f4ef81SValentin Clement       if (attr.isa<fir::LowerBoundAttr>()) {
91839f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
91939f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector);
92039f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
92139f4ef81SValentin Clement         continue;
92239f4ef81SValentin Clement       }
92339f4ef81SValentin Clement       if (attr.isa<fir::UpperBoundAttr>()) {
92439f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
92539f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg);
92639f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
92739f4ef81SValentin Clement         continue;
92839f4ef81SValentin Clement       }
92939f4ef81SValentin Clement       if (attr.isa<fir::ClosedIntervalAttr>()) {
93039f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
93139f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector);
93239f4ef81SValentin Clement         auto *thisBlock = rewriter.getInsertionBlock();
93339f4ef81SValentin Clement         auto *newBlock1 = createBlock(rewriter, dest);
93439f4ef81SValentin Clement         auto *newBlock2 = createBlock(rewriter, dest);
93539f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(thisBlock);
93639f4ef81SValentin Clement         rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, newBlock1, newBlock2);
93739f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(newBlock1);
93839f4ef81SValentin Clement         mlir::Value caseArg0 = *(cmpOps.getValue().begin() + 1);
93939f4ef81SValentin Clement         auto cmp0 = rewriter.create<mlir::LLVM::ICmpOp>(
94039f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg0);
94139f4ef81SValentin Clement         genCondBrOp(loc, cmp0, dest, destOps, rewriter, newBlock2);
94239f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(newBlock2);
94339f4ef81SValentin Clement         continue;
94439f4ef81SValentin Clement       }
94539f4ef81SValentin Clement       assert(attr.isa<mlir::UnitAttr>());
94639f4ef81SValentin Clement       assert((t + 1 == conds) && "unit must be last");
94739f4ef81SValentin Clement       genBrOp(caseOp, dest, destOps, rewriter);
94839f4ef81SValentin Clement     }
94939f4ef81SValentin Clement     return success();
95039f4ef81SValentin Clement   }
95139f4ef81SValentin Clement };
95239f4ef81SValentin Clement 
9538c239909SValentin Clement template <typename OP>
9548c239909SValentin Clement void selectMatchAndRewrite(fir::LLVMTypeConverter &lowering, OP select,
9558c239909SValentin Clement                            typename OP::Adaptor adaptor,
9568c239909SValentin Clement                            mlir::ConversionPatternRewriter &rewriter) {
9578c239909SValentin Clement   unsigned conds = select.getNumConditions();
9588c239909SValentin Clement   auto cases = select.getCases().getValue();
9598c239909SValentin Clement   mlir::Value selector = adaptor.selector();
9608c239909SValentin Clement   auto loc = select.getLoc();
9618c239909SValentin Clement   assert(conds > 0 && "select must have cases");
9628c239909SValentin Clement 
9638c239909SValentin Clement   llvm::SmallVector<mlir::Block *> destinations;
9648c239909SValentin Clement   llvm::SmallVector<mlir::ValueRange> destinationsOperands;
9658c239909SValentin Clement   mlir::Block *defaultDestination;
9668c239909SValentin Clement   mlir::ValueRange defaultOperands;
9678c239909SValentin Clement   llvm::SmallVector<int32_t> caseValues;
9688c239909SValentin Clement 
9698c239909SValentin Clement   for (unsigned t = 0; t != conds; ++t) {
9708c239909SValentin Clement     mlir::Block *dest = select.getSuccessor(t);
9718c239909SValentin Clement     auto destOps = select.getSuccessorOperands(adaptor.getOperands(), t);
9728c239909SValentin Clement     const mlir::Attribute &attr = cases[t];
9738c239909SValentin Clement     if (auto intAttr = attr.template dyn_cast<mlir::IntegerAttr>()) {
9748c239909SValentin Clement       destinations.push_back(dest);
9758c239909SValentin Clement       destinationsOperands.push_back(destOps.hasValue() ? *destOps
9768c239909SValentin Clement                                                         : ValueRange());
9778c239909SValentin Clement       caseValues.push_back(intAttr.getInt());
9788c239909SValentin Clement       continue;
9798c239909SValentin Clement     }
9808c239909SValentin Clement     assert(attr.template dyn_cast_or_null<mlir::UnitAttr>());
9818c239909SValentin Clement     assert((t + 1 == conds) && "unit must be last");
9828c239909SValentin Clement     defaultDestination = dest;
9838c239909SValentin Clement     defaultOperands = destOps.hasValue() ? *destOps : ValueRange();
9848c239909SValentin Clement   }
9858c239909SValentin Clement 
9868c239909SValentin Clement   // LLVM::SwitchOp takes a i32 type for the selector.
9878c239909SValentin Clement   if (select.getSelector().getType() != rewriter.getI32Type())
9888c239909SValentin Clement     selector =
9898c239909SValentin Clement         rewriter.create<LLVM::TruncOp>(loc, rewriter.getI32Type(), selector);
9908c239909SValentin Clement 
9918c239909SValentin Clement   rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>(
9928c239909SValentin Clement       select, selector,
9938c239909SValentin Clement       /*defaultDestination=*/defaultDestination,
9948c239909SValentin Clement       /*defaultOperands=*/defaultOperands,
9958c239909SValentin Clement       /*caseValues=*/caseValues,
9968c239909SValentin Clement       /*caseDestinations=*/destinations,
9978c239909SValentin Clement       /*caseOperands=*/destinationsOperands,
9988c239909SValentin Clement       /*branchWeights=*/ArrayRef<int32_t>());
9998c239909SValentin Clement }
10008c239909SValentin Clement 
10018c239909SValentin Clement /// conversion of fir::SelectOp to an if-then-else ladder
10028c239909SValentin Clement struct SelectOpConversion : public FIROpConversion<fir::SelectOp> {
10038c239909SValentin Clement   using FIROpConversion::FIROpConversion;
10048c239909SValentin Clement 
10058c239909SValentin Clement   mlir::LogicalResult
10068c239909SValentin Clement   matchAndRewrite(fir::SelectOp op, OpAdaptor adaptor,
10078c239909SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
10088c239909SValentin Clement     selectMatchAndRewrite<fir::SelectOp>(lowerTy(), op, adaptor, rewriter);
10098c239909SValentin Clement     return success();
10108c239909SValentin Clement   }
10118c239909SValentin Clement };
10128c239909SValentin Clement 
1013e3349fa1SAndrzej Warzynski /// `fir.load` --> `llvm.load`
1014e3349fa1SAndrzej Warzynski struct LoadOpConversion : public FIROpConversion<fir::LoadOp> {
1015e3349fa1SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
1016e3349fa1SAndrzej Warzynski 
1017e3349fa1SAndrzej Warzynski   mlir::LogicalResult
1018e3349fa1SAndrzej Warzynski   matchAndRewrite(fir::LoadOp load, OpAdaptor adaptor,
1019e3349fa1SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
1020e3349fa1SAndrzej Warzynski     // fir.box is a special case because it is considered as an ssa values in
1021e3349fa1SAndrzej Warzynski     // fir, but it is lowered as a pointer to a descriptor. So fir.ref<fir.box>
1022e3349fa1SAndrzej Warzynski     // and fir.box end up being the same llvm types and loading a
1023e3349fa1SAndrzej Warzynski     // fir.ref<fir.box> is actually a no op in LLVM.
1024e3349fa1SAndrzej Warzynski     if (load.getType().isa<fir::BoxType>()) {
1025e3349fa1SAndrzej Warzynski       rewriter.replaceOp(load, adaptor.getOperands()[0]);
1026e3349fa1SAndrzej Warzynski     } else {
1027e3349fa1SAndrzej Warzynski       mlir::Type ty = convertType(load.getType());
1028e3349fa1SAndrzej Warzynski       ArrayRef<NamedAttribute> at = load->getAttrs();
1029e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::LoadOp>(
1030e3349fa1SAndrzej Warzynski           load, ty, adaptor.getOperands(), at);
1031e3349fa1SAndrzej Warzynski     }
1032e3349fa1SAndrzej Warzynski     return success();
1033e3349fa1SAndrzej Warzynski   }
1034e3349fa1SAndrzej Warzynski };
1035e3349fa1SAndrzej Warzynski 
10362a299e4fSValentin Clement /// Lower `fir.select_type` to LLVM IR dialect.
10372a299e4fSValentin Clement struct SelectTypeOpConversion : public FIROpConversion<fir::SelectTypeOp> {
10382a299e4fSValentin Clement   using FIROpConversion::FIROpConversion;
10392a299e4fSValentin Clement 
10402a299e4fSValentin Clement   mlir::LogicalResult
10412a299e4fSValentin Clement   matchAndRewrite(fir::SelectTypeOp select, OpAdaptor adaptor,
10422a299e4fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
10432a299e4fSValentin Clement     return rewriter.notifyMatchFailure(
10442a299e4fSValentin Clement         select, "fir.select_type codegen is not implemented yet");
10452a299e4fSValentin Clement   }
10462a299e4fSValentin Clement };
10472a299e4fSValentin Clement 
10488c239909SValentin Clement /// conversion of fir::SelectRankOp to an if-then-else ladder
10498c239909SValentin Clement struct SelectRankOpConversion : public FIROpConversion<fir::SelectRankOp> {
10508c239909SValentin Clement   using FIROpConversion::FIROpConversion;
10518c239909SValentin Clement 
10528c239909SValentin Clement   mlir::LogicalResult
10538c239909SValentin Clement   matchAndRewrite(fir::SelectRankOp op, OpAdaptor adaptor,
10548c239909SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
10558c239909SValentin Clement     selectMatchAndRewrite<fir::SelectRankOp>(lowerTy(), op, adaptor, rewriter);
10568c239909SValentin Clement     return success();
10578c239909SValentin Clement   }
10588c239909SValentin Clement };
10598c239909SValentin Clement 
1060e3349fa1SAndrzej Warzynski /// `fir.store` --> `llvm.store`
1061e3349fa1SAndrzej Warzynski struct StoreOpConversion : public FIROpConversion<fir::StoreOp> {
1062e3349fa1SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
1063e3349fa1SAndrzej Warzynski 
1064e3349fa1SAndrzej Warzynski   mlir::LogicalResult
1065e3349fa1SAndrzej Warzynski   matchAndRewrite(fir::StoreOp store, OpAdaptor adaptor,
1066e3349fa1SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
1067e3349fa1SAndrzej Warzynski     if (store.value().getType().isa<fir::BoxType>()) {
1068e3349fa1SAndrzej Warzynski       // fir.box value is actually in memory, load it first before storing it.
1069e3349fa1SAndrzej Warzynski       mlir::Location loc = store.getLoc();
1070e3349fa1SAndrzej Warzynski       mlir::Type boxPtrTy = adaptor.getOperands()[0].getType();
1071e3349fa1SAndrzej Warzynski       auto val = rewriter.create<mlir::LLVM::LoadOp>(
1072e3349fa1SAndrzej Warzynski           loc, boxPtrTy.cast<mlir::LLVM::LLVMPointerType>().getElementType(),
1073e3349fa1SAndrzej Warzynski           adaptor.getOperands()[0]);
1074e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
1075e3349fa1SAndrzej Warzynski           store, val, adaptor.getOperands()[1]);
1076e3349fa1SAndrzej Warzynski     } else {
1077e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
1078e3349fa1SAndrzej Warzynski           store, adaptor.getOperands()[0], adaptor.getOperands()[1]);
1079e3349fa1SAndrzej Warzynski     }
1080e3349fa1SAndrzej Warzynski     return success();
1081e3349fa1SAndrzej Warzynski   }
1082e3349fa1SAndrzej Warzynski };
1083e3349fa1SAndrzej Warzynski 
1084e3349fa1SAndrzej Warzynski /// convert to LLVM IR dialect `undef`
1085044d5b5dSValentin Clement struct UndefOpConversion : public FIROpConversion<fir::UndefOp> {
1086044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
1087044d5b5dSValentin Clement 
1088044d5b5dSValentin Clement   mlir::LogicalResult
1089044d5b5dSValentin Clement   matchAndRewrite(fir::UndefOp undef, OpAdaptor,
1090044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1091044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::UndefOp>(
1092044d5b5dSValentin Clement         undef, convertType(undef.getType()));
1093044d5b5dSValentin Clement     return success();
1094044d5b5dSValentin Clement   }
1095044d5b5dSValentin Clement };
1096a7a61359SValentin Clement 
1097e3349fa1SAndrzej Warzynski /// `fir.unreachable` --> `llvm.unreachable`
109832e08248SAndrzej Warzynski struct UnreachableOpConversion : public FIROpConversion<fir::UnreachableOp> {
109932e08248SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
110032e08248SAndrzej Warzynski 
110132e08248SAndrzej Warzynski   mlir::LogicalResult
110232e08248SAndrzej Warzynski   matchAndRewrite(fir::UnreachableOp unreach, OpAdaptor adaptor,
110332e08248SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
110432e08248SAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(unreach);
110532e08248SAndrzej Warzynski     return success();
110632e08248SAndrzej Warzynski   }
110732e08248SAndrzej Warzynski };
110832e08248SAndrzej Warzynski 
1109a7a61359SValentin Clement struct ZeroOpConversion : public FIROpConversion<fir::ZeroOp> {
1110a7a61359SValentin Clement   using FIROpConversion::FIROpConversion;
1111a7a61359SValentin Clement 
1112a7a61359SValentin Clement   mlir::LogicalResult
1113a7a61359SValentin Clement   matchAndRewrite(fir::ZeroOp zero, OpAdaptor,
1114a7a61359SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1115a7a61359SValentin Clement     auto ty = convertType(zero.getType());
1116a7a61359SValentin Clement     if (ty.isa<mlir::LLVM::LLVMPointerType>()) {
1117a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(zero, ty);
1118a7a61359SValentin Clement     } else if (ty.isa<mlir::IntegerType>()) {
1119a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
1120a7a61359SValentin Clement           zero, ty, mlir::IntegerAttr::get(zero.getType(), 0));
1121a7a61359SValentin Clement     } else if (mlir::LLVM::isCompatibleFloatingPointType(ty)) {
1122a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
1123a7a61359SValentin Clement           zero, ty, mlir::FloatAttr::get(zero.getType(), 0.0));
1124a7a61359SValentin Clement     } else {
1125a7a61359SValentin Clement       // TODO: create ConstantAggregateZero for FIR aggregate/array types.
112652d813edSValentin Clement       return rewriter.notifyMatchFailure(
112752d813edSValentin Clement           zero,
1128a7a61359SValentin Clement           "conversion of fir.zero with aggregate type not implemented yet");
1129a7a61359SValentin Clement     }
1130a7a61359SValentin Clement     return success();
1131a7a61359SValentin Clement   }
1132a7a61359SValentin Clement };
113332e08248SAndrzej Warzynski 
113454c56347SValentin Clement // Code shared between insert_value and extract_value Ops.
113554c56347SValentin Clement struct ValueOpCommon {
113654c56347SValentin Clement   // Translate the arguments pertaining to any multidimensional array to
113754c56347SValentin Clement   // row-major order for LLVM-IR.
113854c56347SValentin Clement   static void toRowMajor(SmallVectorImpl<mlir::Attribute> &attrs,
113954c56347SValentin Clement                          mlir::Type ty) {
114054c56347SValentin Clement     assert(ty && "type is null");
114154c56347SValentin Clement     const auto end = attrs.size();
114254c56347SValentin Clement     for (std::remove_const_t<decltype(end)> i = 0; i < end; ++i) {
114354c56347SValentin Clement       if (auto seq = ty.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
114454c56347SValentin Clement         const auto dim = getDimension(seq);
114554c56347SValentin Clement         if (dim > 1) {
114654c56347SValentin Clement           auto ub = std::min(i + dim, end);
114754c56347SValentin Clement           std::reverse(attrs.begin() + i, attrs.begin() + ub);
114854c56347SValentin Clement           i += dim - 1;
114954c56347SValentin Clement         }
115054c56347SValentin Clement         ty = getArrayElementType(seq);
115154c56347SValentin Clement       } else if (auto st = ty.dyn_cast<mlir::LLVM::LLVMStructType>()) {
115254c56347SValentin Clement         ty = st.getBody()[attrs[i].cast<mlir::IntegerAttr>().getInt()];
115354c56347SValentin Clement       } else {
115454c56347SValentin Clement         llvm_unreachable("index into invalid type");
115554c56347SValentin Clement       }
115654c56347SValentin Clement     }
115754c56347SValentin Clement   }
115854c56347SValentin Clement 
115954c56347SValentin Clement   static llvm::SmallVector<mlir::Attribute>
116054c56347SValentin Clement   collectIndices(mlir::ConversionPatternRewriter &rewriter,
116154c56347SValentin Clement                  mlir::ArrayAttr arrAttr) {
116254c56347SValentin Clement     llvm::SmallVector<mlir::Attribute> attrs;
116354c56347SValentin Clement     for (auto i = arrAttr.begin(), e = arrAttr.end(); i != e; ++i) {
116454c56347SValentin Clement       if (i->isa<mlir::IntegerAttr>()) {
116554c56347SValentin Clement         attrs.push_back(*i);
116654c56347SValentin Clement       } else {
116754c56347SValentin Clement         auto fieldName = i->cast<mlir::StringAttr>().getValue();
116854c56347SValentin Clement         ++i;
116954c56347SValentin Clement         auto ty = i->cast<mlir::TypeAttr>().getValue();
117054c56347SValentin Clement         auto index = ty.cast<fir::RecordType>().getFieldIndex(fieldName);
117154c56347SValentin Clement         attrs.push_back(mlir::IntegerAttr::get(rewriter.getI32Type(), index));
117254c56347SValentin Clement       }
117354c56347SValentin Clement     }
117454c56347SValentin Clement     return attrs;
117554c56347SValentin Clement   }
117654c56347SValentin Clement 
117754c56347SValentin Clement private:
117854c56347SValentin Clement   static unsigned getDimension(mlir::LLVM::LLVMArrayType ty) {
117954c56347SValentin Clement     unsigned result = 1;
118054c56347SValentin Clement     for (auto eleTy = ty.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>();
118154c56347SValentin Clement          eleTy;
118254c56347SValentin Clement          eleTy = eleTy.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>())
118354c56347SValentin Clement       ++result;
118454c56347SValentin Clement     return result;
118554c56347SValentin Clement   }
118654c56347SValentin Clement 
118754c56347SValentin Clement   static mlir::Type getArrayElementType(mlir::LLVM::LLVMArrayType ty) {
118854c56347SValentin Clement     auto eleTy = ty.getElementType();
118954c56347SValentin Clement     while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>())
119054c56347SValentin Clement       eleTy = arrTy.getElementType();
119154c56347SValentin Clement     return eleTy;
119254c56347SValentin Clement   }
119354c56347SValentin Clement };
119454c56347SValentin Clement 
119554c56347SValentin Clement /// Extract a subobject value from an ssa-value of aggregate type
119654c56347SValentin Clement struct ExtractValueOpConversion
119754c56347SValentin Clement     : public FIROpAndTypeConversion<fir::ExtractValueOp>,
119854c56347SValentin Clement       public ValueOpCommon {
119954c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
120054c56347SValentin Clement 
120154c56347SValentin Clement   mlir::LogicalResult
120254c56347SValentin Clement   doRewrite(fir::ExtractValueOp extractVal, mlir::Type ty, OpAdaptor adaptor,
120354c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
120454c56347SValentin Clement     auto attrs = collectIndices(rewriter, extractVal.coor());
120554c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
120654c56347SValentin Clement     auto position = mlir::ArrayAttr::get(extractVal.getContext(), attrs);
120754c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(
120854c56347SValentin Clement         extractVal, ty, adaptor.getOperands()[0], position);
120954c56347SValentin Clement     return success();
121054c56347SValentin Clement   }
121154c56347SValentin Clement };
121254c56347SValentin Clement 
121354c56347SValentin Clement /// InsertValue is the generalized instruction for the composition of new
121454c56347SValentin Clement /// aggregate type values.
121554c56347SValentin Clement struct InsertValueOpConversion
121654c56347SValentin Clement     : public FIROpAndTypeConversion<fir::InsertValueOp>,
121754c56347SValentin Clement       public ValueOpCommon {
121854c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
121954c56347SValentin Clement 
122054c56347SValentin Clement   mlir::LogicalResult
122154c56347SValentin Clement   doRewrite(fir::InsertValueOp insertVal, mlir::Type ty, OpAdaptor adaptor,
122254c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
122354c56347SValentin Clement     auto attrs = collectIndices(rewriter, insertVal.coor());
122454c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
122554c56347SValentin Clement     auto position = mlir::ArrayAttr::get(insertVal.getContext(), attrs);
122654c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
122754c56347SValentin Clement         insertVal, ty, adaptor.getOperands()[0], adaptor.getOperands()[1],
122854c56347SValentin Clement         position);
122954c56347SValentin Clement     return success();
123054c56347SValentin Clement   }
123154c56347SValentin Clement };
123254c56347SValentin Clement 
12333ae8e442SValentin Clement /// InsertOnRange inserts a value into a sequence over a range of offsets.
12343ae8e442SValentin Clement struct InsertOnRangeOpConversion
12353ae8e442SValentin Clement     : public FIROpAndTypeConversion<fir::InsertOnRangeOp> {
12363ae8e442SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
12373ae8e442SValentin Clement 
12383ae8e442SValentin Clement   // Increments an array of subscripts in a row major fasion.
12393ae8e442SValentin Clement   void incrementSubscripts(const SmallVector<uint64_t> &dims,
12403ae8e442SValentin Clement                            SmallVector<uint64_t> &subscripts) const {
12413ae8e442SValentin Clement     for (size_t i = dims.size(); i > 0; --i) {
12423ae8e442SValentin Clement       if (++subscripts[i - 1] < dims[i - 1]) {
12433ae8e442SValentin Clement         return;
12443ae8e442SValentin Clement       }
12453ae8e442SValentin Clement       subscripts[i - 1] = 0;
12463ae8e442SValentin Clement     }
12473ae8e442SValentin Clement   }
12483ae8e442SValentin Clement 
12493ae8e442SValentin Clement   mlir::LogicalResult
12503ae8e442SValentin Clement   doRewrite(fir::InsertOnRangeOp range, mlir::Type ty, OpAdaptor adaptor,
12513ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
12523ae8e442SValentin Clement 
12533ae8e442SValentin Clement     llvm::SmallVector<uint64_t> dims;
12543ae8e442SValentin Clement     auto type = adaptor.getOperands()[0].getType();
12553ae8e442SValentin Clement 
12563ae8e442SValentin Clement     // Iteratively extract the array dimensions from the type.
12573ae8e442SValentin Clement     while (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
12583ae8e442SValentin Clement       dims.push_back(t.getNumElements());
12593ae8e442SValentin Clement       type = t.getElementType();
12603ae8e442SValentin Clement     }
12613ae8e442SValentin Clement 
12623ae8e442SValentin Clement     SmallVector<uint64_t> lBounds;
12633ae8e442SValentin Clement     SmallVector<uint64_t> uBounds;
12643ae8e442SValentin Clement 
12653ae8e442SValentin Clement     // Extract integer value from the attribute
12663ae8e442SValentin Clement     SmallVector<int64_t> coordinates = llvm::to_vector<4>(
12673ae8e442SValentin Clement         llvm::map_range(range.coor(), [](Attribute a) -> int64_t {
12683ae8e442SValentin Clement           return a.cast<IntegerAttr>().getInt();
12693ae8e442SValentin Clement         }));
12703ae8e442SValentin Clement 
12713ae8e442SValentin Clement     // Unzip the upper and lower bound and convert to a row major format.
12723ae8e442SValentin Clement     for (auto i = coordinates.rbegin(), e = coordinates.rend(); i != e; ++i) {
12733ae8e442SValentin Clement       uBounds.push_back(*i++);
12743ae8e442SValentin Clement       lBounds.push_back(*i);
12753ae8e442SValentin Clement     }
12763ae8e442SValentin Clement 
12773ae8e442SValentin Clement     auto &subscripts = lBounds;
12783ae8e442SValentin Clement     auto loc = range.getLoc();
12793ae8e442SValentin Clement     mlir::Value lastOp = adaptor.getOperands()[0];
12803ae8e442SValentin Clement     mlir::Value insertVal = adaptor.getOperands()[1];
12813ae8e442SValentin Clement 
12823ae8e442SValentin Clement     auto i64Ty = rewriter.getI64Type();
12833ae8e442SValentin Clement     while (subscripts != uBounds) {
12843ae8e442SValentin Clement       // Convert uint64_t's to Attribute's.
12853ae8e442SValentin Clement       SmallVector<mlir::Attribute> subscriptAttrs;
12863ae8e442SValentin Clement       for (const auto &subscript : subscripts)
12873ae8e442SValentin Clement         subscriptAttrs.push_back(IntegerAttr::get(i64Ty, subscript));
12883ae8e442SValentin Clement       lastOp = rewriter.create<mlir::LLVM::InsertValueOp>(
12893ae8e442SValentin Clement           loc, ty, lastOp, insertVal,
12903ae8e442SValentin Clement           ArrayAttr::get(range.getContext(), subscriptAttrs));
12913ae8e442SValentin Clement 
12923ae8e442SValentin Clement       incrementSubscripts(dims, subscripts);
12933ae8e442SValentin Clement     }
12943ae8e442SValentin Clement 
12953ae8e442SValentin Clement     // Convert uint64_t's to Attribute's.
12963ae8e442SValentin Clement     SmallVector<mlir::Attribute> subscriptAttrs;
12973ae8e442SValentin Clement     for (const auto &subscript : subscripts)
12983ae8e442SValentin Clement       subscriptAttrs.push_back(
12993ae8e442SValentin Clement           IntegerAttr::get(rewriter.getI64Type(), subscript));
13003ae8e442SValentin Clement     mlir::ArrayRef<mlir::Attribute> arrayRef(subscriptAttrs);
13013ae8e442SValentin Clement 
13023ae8e442SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
13033ae8e442SValentin Clement         range, ty, lastOp, insertVal,
13043ae8e442SValentin Clement         ArrayAttr::get(range.getContext(), arrayRef));
13053ae8e442SValentin Clement 
13063ae8e442SValentin Clement     return success();
13073ae8e442SValentin Clement   }
13083ae8e442SValentin Clement };
13097b5132daSValentin Clement 
13107b5132daSValentin Clement //
13117b5132daSValentin Clement // Primitive operations on Complex types
13127b5132daSValentin Clement //
13137b5132daSValentin Clement 
13147b5132daSValentin Clement /// Generate inline code for complex addition/subtraction
13157b5132daSValentin Clement template <typename LLVMOP, typename OPTY>
13167b5132daSValentin Clement mlir::LLVM::InsertValueOp complexSum(OPTY sumop, mlir::ValueRange opnds,
13177b5132daSValentin Clement                                      mlir::ConversionPatternRewriter &rewriter,
13187b5132daSValentin Clement                                      fir::LLVMTypeConverter &lowering) {
13197b5132daSValentin Clement   mlir::Value a = opnds[0];
13207b5132daSValentin Clement   mlir::Value b = opnds[1];
13217b5132daSValentin Clement   auto loc = sumop.getLoc();
13227b5132daSValentin Clement   auto ctx = sumop.getContext();
13237b5132daSValentin Clement   auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
13247b5132daSValentin Clement   auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
13257b5132daSValentin Clement   mlir::Type eleTy = lowering.convertType(getComplexEleTy(sumop.getType()));
13267b5132daSValentin Clement   mlir::Type ty = lowering.convertType(sumop.getType());
13277b5132daSValentin Clement   auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
13287b5132daSValentin Clement   auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
13297b5132daSValentin Clement   auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
13307b5132daSValentin Clement   auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
13317b5132daSValentin Clement   auto rx = rewriter.create<LLVMOP>(loc, eleTy, x0, x1);
13327b5132daSValentin Clement   auto ry = rewriter.create<LLVMOP>(loc, eleTy, y0, y1);
13337b5132daSValentin Clement   auto r0 = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
13347b5132daSValentin Clement   auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r0, rx, c0);
13357b5132daSValentin Clement   return rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ry, c1);
13367b5132daSValentin Clement }
13377b5132daSValentin Clement 
13387b5132daSValentin Clement struct AddcOpConversion : public FIROpConversion<fir::AddcOp> {
13397b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
13407b5132daSValentin Clement 
13417b5132daSValentin Clement   mlir::LogicalResult
13427b5132daSValentin Clement   matchAndRewrite(fir::AddcOp addc, OpAdaptor adaptor,
13437b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
13447b5132daSValentin Clement     // given: (x + iy) + (x' + iy')
13457b5132daSValentin Clement     // result: (x + x') + i(y + y')
13467b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FAddOp>(addc, adaptor.getOperands(),
13477b5132daSValentin Clement                                             rewriter, lowerTy());
13487b5132daSValentin Clement     rewriter.replaceOp(addc, r.getResult());
13497b5132daSValentin Clement     return success();
13507b5132daSValentin Clement   }
13517b5132daSValentin Clement };
13527b5132daSValentin Clement 
13537b5132daSValentin Clement struct SubcOpConversion : public FIROpConversion<fir::SubcOp> {
13547b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
13557b5132daSValentin Clement 
13567b5132daSValentin Clement   mlir::LogicalResult
13577b5132daSValentin Clement   matchAndRewrite(fir::SubcOp subc, OpAdaptor adaptor,
13587b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
13597b5132daSValentin Clement     // given: (x + iy) - (x' + iy')
13607b5132daSValentin Clement     // result: (x - x') + i(y - y')
13617b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FSubOp>(subc, adaptor.getOperands(),
13627b5132daSValentin Clement                                             rewriter, lowerTy());
13637b5132daSValentin Clement     rewriter.replaceOp(subc, r.getResult());
13647b5132daSValentin Clement     return success();
13657b5132daSValentin Clement   }
13667b5132daSValentin Clement };
13677b5132daSValentin Clement 
13687b5132daSValentin Clement /// Inlined complex multiply
13697b5132daSValentin Clement struct MulcOpConversion : public FIROpConversion<fir::MulcOp> {
13707b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
13717b5132daSValentin Clement 
13727b5132daSValentin Clement   mlir::LogicalResult
13737b5132daSValentin Clement   matchAndRewrite(fir::MulcOp mulc, OpAdaptor adaptor,
13747b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
13757b5132daSValentin Clement     // TODO: Can we use a call to __muldc3 ?
13767b5132daSValentin Clement     // given: (x + iy) * (x' + iy')
13777b5132daSValentin Clement     // result: (xx'-yy')+i(xy'+yx')
13787b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
13797b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
13807b5132daSValentin Clement     auto loc = mulc.getLoc();
13817b5132daSValentin Clement     auto *ctx = mulc.getContext();
13827b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
13837b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
13847b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(mulc.getType()));
13857b5132daSValentin Clement     mlir::Type ty = convertType(mulc.getType());
13867b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
13877b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
13887b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
13897b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
13907b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
13917b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
13927b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
13937b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xy, yx);
13947b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
13957b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, xx, yy);
13967b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
13977b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
13987b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
13997b5132daSValentin Clement     rewriter.replaceOp(mulc, r0.getResult());
14007b5132daSValentin Clement     return success();
14017b5132daSValentin Clement   }
14027b5132daSValentin Clement };
14037b5132daSValentin Clement 
14047b5132daSValentin Clement /// Inlined complex division
14057b5132daSValentin Clement struct DivcOpConversion : public FIROpConversion<fir::DivcOp> {
14067b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
14077b5132daSValentin Clement 
14087b5132daSValentin Clement   mlir::LogicalResult
14097b5132daSValentin Clement   matchAndRewrite(fir::DivcOp divc, OpAdaptor adaptor,
14107b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
14117b5132daSValentin Clement     // TODO: Can we use a call to __divdc3 instead?
14127b5132daSValentin Clement     // Just generate inline code for now.
14137b5132daSValentin Clement     // given: (x + iy) / (x' + iy')
14147b5132daSValentin Clement     // result: ((xx'+yy')/d) + i((yx'-xy')/d) where d = x'x' + y'y'
14157b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
14167b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
14177b5132daSValentin Clement     auto loc = divc.getLoc();
14187b5132daSValentin Clement     auto *ctx = divc.getContext();
14197b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
14207b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
14217b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(divc.getType()));
14227b5132daSValentin Clement     mlir::Type ty = convertType(divc.getType());
14237b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
14247b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
14257b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
14267b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
14277b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
14287b5132daSValentin Clement     auto x1x1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x1, x1);
14297b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
14307b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
14317b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
14327b5132daSValentin Clement     auto y1y1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y1, y1);
14337b5132daSValentin Clement     auto d = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, x1x1, y1y1);
14347b5132daSValentin Clement     auto rrn = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xx, yy);
14357b5132daSValentin Clement     auto rin = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, yx, xy);
14367b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rrn, d);
14377b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rin, d);
14387b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
14397b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
14407b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
14417b5132daSValentin Clement     rewriter.replaceOp(divc, r0.getResult());
14427b5132daSValentin Clement     return success();
14437b5132daSValentin Clement   }
14447b5132daSValentin Clement };
14457b5132daSValentin Clement 
14467b5132daSValentin Clement /// Inlined complex negation
14477b5132daSValentin Clement struct NegcOpConversion : public FIROpConversion<fir::NegcOp> {
14487b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
14497b5132daSValentin Clement 
14507b5132daSValentin Clement   mlir::LogicalResult
14517b5132daSValentin Clement   matchAndRewrite(fir::NegcOp neg, OpAdaptor adaptor,
14527b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
14537b5132daSValentin Clement     // given: -(x + iy)
14547b5132daSValentin Clement     // result: -x - iy
14557b5132daSValentin Clement     auto *ctxt = neg.getContext();
14567b5132daSValentin Clement     auto eleTy = convertType(getComplexEleTy(neg.getType()));
14577b5132daSValentin Clement     auto ty = convertType(neg.getType());
14587b5132daSValentin Clement     auto loc = neg.getLoc();
14597b5132daSValentin Clement     mlir::Value o0 = adaptor.getOperands()[0];
14607b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0));
14617b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1));
14627b5132daSValentin Clement     auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c0);
14637b5132daSValentin Clement     auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c1);
14647b5132daSValentin Clement     auto nrp = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, rp);
14657b5132daSValentin Clement     auto nip = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, ip);
14667b5132daSValentin Clement     auto r = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, o0, nrp, c0);
14677b5132daSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(neg, ty, r, nip, c1);
14687b5132daSValentin Clement     return success();
14697b5132daSValentin Clement   }
14707b5132daSValentin Clement };
14717b5132daSValentin Clement 
1472*1ed5a90fSValentin Clement /// Conversion pattern for operation that must be dead. The information in these
1473*1ed5a90fSValentin Clement /// operations is used by other operation. At this point they should not have
1474*1ed5a90fSValentin Clement /// anymore uses.
1475*1ed5a90fSValentin Clement /// These operations are normally dead after the pre-codegen pass.
1476*1ed5a90fSValentin Clement template <typename FromOp>
1477*1ed5a90fSValentin Clement struct MustBeDeadConversion : public FIROpConversion<FromOp> {
1478*1ed5a90fSValentin Clement   explicit MustBeDeadConversion(fir::LLVMTypeConverter &lowering)
1479*1ed5a90fSValentin Clement       : FIROpConversion<FromOp>(lowering) {}
1480*1ed5a90fSValentin Clement   using OpAdaptor = typename FromOp::Adaptor;
1481*1ed5a90fSValentin Clement 
1482*1ed5a90fSValentin Clement   mlir::LogicalResult
1483*1ed5a90fSValentin Clement   matchAndRewrite(FromOp op, OpAdaptor adaptor,
1484*1ed5a90fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const final {
1485*1ed5a90fSValentin Clement     if (!op->getUses().empty())
1486*1ed5a90fSValentin Clement       return rewriter.notifyMatchFailure(op, "op must be dead");
1487*1ed5a90fSValentin Clement     rewriter.eraseOp(op);
1488*1ed5a90fSValentin Clement     return success();
1489*1ed5a90fSValentin Clement   }
1490*1ed5a90fSValentin Clement };
1491*1ed5a90fSValentin Clement 
1492*1ed5a90fSValentin Clement struct ShapeOpConversion : public MustBeDeadConversion<fir::ShapeOp> {
1493*1ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
1494*1ed5a90fSValentin Clement };
1495*1ed5a90fSValentin Clement 
1496*1ed5a90fSValentin Clement struct ShapeShiftOpConversion : public MustBeDeadConversion<fir::ShapeShiftOp> {
1497*1ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
1498*1ed5a90fSValentin Clement };
1499*1ed5a90fSValentin Clement 
1500*1ed5a90fSValentin Clement struct ShiftOpConversion : public MustBeDeadConversion<fir::ShiftOp> {
1501*1ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
1502*1ed5a90fSValentin Clement };
1503*1ed5a90fSValentin Clement 
1504*1ed5a90fSValentin Clement struct SliceOpConversion : public MustBeDeadConversion<fir::SliceOp> {
1505*1ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
1506*1ed5a90fSValentin Clement };
1507*1ed5a90fSValentin Clement 
1508420ad7ceSAndrzej Warzynski /// `fir.is_present` -->
1509420ad7ceSAndrzej Warzynski /// ```
1510420ad7ceSAndrzej Warzynski ///  %0 = llvm.mlir.constant(0 : i64)
1511420ad7ceSAndrzej Warzynski ///  %1 = llvm.ptrtoint %0
1512420ad7ceSAndrzej Warzynski ///  %2 = llvm.icmp "ne" %1, %0 : i64
1513420ad7ceSAndrzej Warzynski /// ```
1514420ad7ceSAndrzej Warzynski struct IsPresentOpConversion : public FIROpConversion<fir::IsPresentOp> {
1515420ad7ceSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
1516420ad7ceSAndrzej Warzynski 
1517420ad7ceSAndrzej Warzynski   mlir::LogicalResult
1518420ad7ceSAndrzej Warzynski   matchAndRewrite(fir::IsPresentOp isPresent, OpAdaptor adaptor,
1519420ad7ceSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
1520420ad7ceSAndrzej Warzynski     mlir::Type idxTy = lowerTy().indexType();
1521420ad7ceSAndrzej Warzynski     mlir::Location loc = isPresent.getLoc();
1522420ad7ceSAndrzej Warzynski     auto ptr = adaptor.getOperands()[0];
1523420ad7ceSAndrzej Warzynski 
1524420ad7ceSAndrzej Warzynski     if (isPresent.val().getType().isa<fir::BoxCharType>()) {
1525420ad7ceSAndrzej Warzynski       auto structTy = ptr.getType().cast<mlir::LLVM::LLVMStructType>();
1526420ad7ceSAndrzej Warzynski       assert(!structTy.isOpaque() && !structTy.getBody().empty());
1527420ad7ceSAndrzej Warzynski 
1528420ad7ceSAndrzej Warzynski       mlir::Type ty = structTy.getBody()[0];
1529420ad7ceSAndrzej Warzynski       mlir::MLIRContext *ctx = isPresent.getContext();
1530420ad7ceSAndrzej Warzynski       auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
1531420ad7ceSAndrzej Warzynski       ptr = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, ptr, c0);
1532420ad7ceSAndrzej Warzynski     }
1533420ad7ceSAndrzej Warzynski     mlir::LLVM::ConstantOp c0 =
1534420ad7ceSAndrzej Warzynski         genConstantIndex(isPresent.getLoc(), idxTy, rewriter, 0);
1535420ad7ceSAndrzej Warzynski     auto addr = rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, ptr);
1536420ad7ceSAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
1537420ad7ceSAndrzej Warzynski         isPresent, mlir::LLVM::ICmpPredicate::ne, addr, c0);
1538420ad7ceSAndrzej Warzynski 
1539420ad7ceSAndrzej Warzynski     return success();
1540420ad7ceSAndrzej Warzynski   }
1541420ad7ceSAndrzej Warzynski };
15421e77b095SAndrzej Warzynski 
15431e77b095SAndrzej Warzynski /// Convert `!fir.emboxchar<!fir.char<KIND, ?>, #n>` into a sequence of
15441e77b095SAndrzej Warzynski /// instructions that generate `!llvm.struct<(ptr<ik>, i64)>`. The 1st element
15451e77b095SAndrzej Warzynski /// in this struct is a pointer. Its type is determined from `KIND`. The 2nd
15461e77b095SAndrzej Warzynski /// element is the length of the character buffer (`#n`).
15471e77b095SAndrzej Warzynski struct EmboxCharOpConversion : public FIROpConversion<fir::EmboxCharOp> {
15481e77b095SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
15491e77b095SAndrzej Warzynski 
15501e77b095SAndrzej Warzynski   mlir::LogicalResult
15511e77b095SAndrzej Warzynski   matchAndRewrite(fir::EmboxCharOp emboxChar, OpAdaptor adaptor,
15521e77b095SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
15531e77b095SAndrzej Warzynski     mlir::ValueRange operands = adaptor.getOperands();
15541e77b095SAndrzej Warzynski     MLIRContext *ctx = emboxChar.getContext();
15551e77b095SAndrzej Warzynski 
15561e77b095SAndrzej Warzynski     mlir::Value charBuffer = operands[0];
15571e77b095SAndrzej Warzynski     mlir::Value charBufferLen = operands[1];
15581e77b095SAndrzej Warzynski 
15591e77b095SAndrzej Warzynski     mlir::Location loc = emboxChar.getLoc();
15601e77b095SAndrzej Warzynski     mlir::Type llvmStructTy = convertType(emboxChar.getType());
15611e77b095SAndrzej Warzynski     auto llvmStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, llvmStructTy);
15621e77b095SAndrzej Warzynski 
15631e77b095SAndrzej Warzynski     mlir::Type lenTy =
15641e77b095SAndrzej Warzynski         llvmStructTy.cast<mlir::LLVM::LLVMStructType>().getBody()[1];
15651e77b095SAndrzej Warzynski     mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, charBufferLen);
15661e77b095SAndrzej Warzynski 
15671e77b095SAndrzej Warzynski     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
15681e77b095SAndrzej Warzynski     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
15691e77b095SAndrzej Warzynski     auto insertBufferOp = rewriter.create<mlir::LLVM::InsertValueOp>(
15701e77b095SAndrzej Warzynski         loc, llvmStructTy, llvmStruct, charBuffer, c0);
15711e77b095SAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
15721e77b095SAndrzej Warzynski         emboxChar, llvmStructTy, insertBufferOp, lenAfterCast, c1);
15731e77b095SAndrzej Warzynski 
15741e77b095SAndrzej Warzynski     return success();
15751e77b095SAndrzej Warzynski   }
15761e77b095SAndrzej Warzynski };
157714867ffcSAndrzej Warzynski 
157814867ffcSAndrzej Warzynski /// Construct an `llvm.extractvalue` instruction. It will return value at
157914867ffcSAndrzej Warzynski /// element \p x from  \p tuple.
158014867ffcSAndrzej Warzynski mlir::LLVM::ExtractValueOp
158114867ffcSAndrzej Warzynski genExtractValueWithIndex(mlir::Location loc, mlir::Value tuple, mlir::Type ty,
158214867ffcSAndrzej Warzynski                          mlir::ConversionPatternRewriter &rewriter,
158314867ffcSAndrzej Warzynski                          mlir::MLIRContext *ctx, int x) {
158414867ffcSAndrzej Warzynski   auto cx = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(x));
158514867ffcSAndrzej Warzynski   auto xty = ty.cast<mlir::LLVM::LLVMStructType>().getBody()[x];
158614867ffcSAndrzej Warzynski   return rewriter.create<mlir::LLVM::ExtractValueOp>(loc, xty, tuple, cx);
158714867ffcSAndrzej Warzynski }
158814867ffcSAndrzej Warzynski 
15896c3d7fd4SAndrzej Warzynski /// Convert `!fir.boxchar_len` to  `!llvm.extractvalue` for the 2nd part of the
15906c3d7fd4SAndrzej Warzynski /// boxchar.
15916c3d7fd4SAndrzej Warzynski struct BoxCharLenOpConversion : public FIROpConversion<fir::BoxCharLenOp> {
15926c3d7fd4SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
15936c3d7fd4SAndrzej Warzynski 
15946c3d7fd4SAndrzej Warzynski   mlir::LogicalResult
15956c3d7fd4SAndrzej Warzynski   matchAndRewrite(fir::BoxCharLenOp boxCharLen, OpAdaptor adaptor,
15966c3d7fd4SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
15976c3d7fd4SAndrzej Warzynski     mlir::Value boxChar = adaptor.getOperands()[0];
15986c3d7fd4SAndrzej Warzynski     mlir::Location loc = boxChar.getLoc();
15996c3d7fd4SAndrzej Warzynski     mlir::MLIRContext *ctx = boxChar.getContext();
16006c3d7fd4SAndrzej Warzynski     mlir::Type returnValTy = boxCharLen.getResult().getType();
16016c3d7fd4SAndrzej Warzynski 
16026c3d7fd4SAndrzej Warzynski     constexpr int boxcharLenIdx = 1;
16036c3d7fd4SAndrzej Warzynski     mlir::LLVM::ExtractValueOp len = genExtractValueWithIndex(
16046c3d7fd4SAndrzej Warzynski         loc, boxChar, boxChar.getType(), rewriter, ctx, boxcharLenIdx);
16056c3d7fd4SAndrzej Warzynski     mlir::Value lenAfterCast = integerCast(loc, rewriter, returnValTy, len);
16066c3d7fd4SAndrzej Warzynski     rewriter.replaceOp(boxCharLen, lenAfterCast);
16076c3d7fd4SAndrzej Warzynski 
16086c3d7fd4SAndrzej Warzynski     return success();
16096c3d7fd4SAndrzej Warzynski   }
16106c3d7fd4SAndrzej Warzynski };
16116c3d7fd4SAndrzej Warzynski 
161214867ffcSAndrzej Warzynski /// Convert `fir.unboxchar` into two `llvm.extractvalue` instructions. One for
161314867ffcSAndrzej Warzynski /// the character buffer and one for the buffer length.
161414867ffcSAndrzej Warzynski struct UnboxCharOpConversion : public FIROpConversion<fir::UnboxCharOp> {
161514867ffcSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
161614867ffcSAndrzej Warzynski 
161714867ffcSAndrzej Warzynski   mlir::LogicalResult
161814867ffcSAndrzej Warzynski   matchAndRewrite(fir::UnboxCharOp unboxchar, OpAdaptor adaptor,
161914867ffcSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
162014867ffcSAndrzej Warzynski     MLIRContext *ctx = unboxchar.getContext();
162114867ffcSAndrzej Warzynski 
162214867ffcSAndrzej Warzynski     mlir::Type lenTy = convertType(unboxchar.getType(1));
162314867ffcSAndrzej Warzynski     mlir::Value tuple = adaptor.getOperands()[0];
162414867ffcSAndrzej Warzynski     mlir::Type tupleTy = tuple.getType();
162514867ffcSAndrzej Warzynski 
162614867ffcSAndrzej Warzynski     mlir::Location loc = unboxchar.getLoc();
162714867ffcSAndrzej Warzynski     mlir::Value ptrToBuffer =
162814867ffcSAndrzej Warzynski         genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 0);
162914867ffcSAndrzej Warzynski 
163014867ffcSAndrzej Warzynski     mlir::LLVM::ExtractValueOp len =
163114867ffcSAndrzej Warzynski         genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 1);
163214867ffcSAndrzej Warzynski     mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, len);
163314867ffcSAndrzej Warzynski 
163414867ffcSAndrzej Warzynski     rewriter.replaceOp(unboxchar,
163514867ffcSAndrzej Warzynski                        ArrayRef<mlir::Value>{ptrToBuffer, lenAfterCast});
163614867ffcSAndrzej Warzynski     return success();
163714867ffcSAndrzej Warzynski   }
163814867ffcSAndrzej Warzynski };
163914867ffcSAndrzej Warzynski 
1640044d5b5dSValentin Clement } // namespace
1641044d5b5dSValentin Clement 
1642044d5b5dSValentin Clement namespace {
1643044d5b5dSValentin Clement /// Convert FIR dialect to LLVM dialect
1644044d5b5dSValentin Clement ///
1645044d5b5dSValentin Clement /// This pass lowers all FIR dialect operations to LLVM IR dialect. An
1646044d5b5dSValentin Clement /// MLIR pass is used to lower residual Std dialect to LLVM IR dialect.
1647044d5b5dSValentin Clement ///
1648044d5b5dSValentin Clement /// This pass is not complete yet. We are upstreaming it in small patches.
1649044d5b5dSValentin Clement class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> {
1650044d5b5dSValentin Clement public:
1651044d5b5dSValentin Clement   mlir::ModuleOp getModule() { return getOperation(); }
1652044d5b5dSValentin Clement 
1653044d5b5dSValentin Clement   void runOnOperation() override final {
16547b5132daSValentin Clement     auto mod = getModule();
16557b5132daSValentin Clement     if (!forcedTargetTriple.empty()) {
16567b5132daSValentin Clement       fir::setTargetTriple(mod, forcedTargetTriple);
16577b5132daSValentin Clement     }
16587b5132daSValentin Clement 
1659044d5b5dSValentin Clement     auto *context = getModule().getContext();
1660044d5b5dSValentin Clement     fir::LLVMTypeConverter typeConverter{getModule()};
1661044d5b5dSValentin Clement     mlir::OwningRewritePatternList pattern(context);
1662df3b9810SValentin Clement     pattern.insert<
1663420ad7ceSAndrzej Warzynski         AbsentOpConversion, AddcOpConversion, AddrOfOpConversion,
16641a2ec667SValentin Clement         AllocaOpConversion, BoxAddrOpConversion, BoxCharLenOpConversion,
16651a2ec667SValentin Clement         BoxDimsOpConversion, BoxEleSizeOpConversion, BoxIsAllocOpConversion,
16661a2ec667SValentin Clement         BoxIsArrayOpConversion, BoxIsPtrOpConversion, BoxRankOpConversion,
16671a2ec667SValentin Clement         CallOpConversion, CmpcOpConversion, ConvertOpConversion,
16681a2ec667SValentin Clement         DispatchOpConversion, DispatchTableOpConversion, DTEntryOpConversion,
16691a2ec667SValentin Clement         DivcOpConversion, EmboxCharOpConversion, ExtractValueOpConversion,
16701a2ec667SValentin Clement         HasValueOpConversion, GenTypeDescOpConversion, GlobalLenOpConversion,
16711a2ec667SValentin Clement         GlobalOpConversion, InsertOnRangeOpConversion, InsertValueOpConversion,
167231246187SValentin Clement         IsPresentOpConversion, LoadOpConversion, NegcOpConversion,
167331246187SValentin Clement         MulcOpConversion, SelectCaseOpConversion, SelectOpConversion,
1674*1ed5a90fSValentin Clement         SelectRankOpConversion, SelectTypeOpConversion, ShapeOpConversion,
1675*1ed5a90fSValentin Clement         ShapeShiftOpConversion, ShiftOpConversion, SliceOpConversion,
1676*1ed5a90fSValentin Clement         StoreOpConversion, StringLitOpConversion, SubcOpConversion,
1677*1ed5a90fSValentin Clement         UnboxCharOpConversion, UndefOpConversion, UnreachableOpConversion,
1678*1ed5a90fSValentin Clement         ZeroOpConversion>(typeConverter);
1679044d5b5dSValentin Clement     mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern);
1680044d5b5dSValentin Clement     mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter,
1681044d5b5dSValentin Clement                                                             pattern);
1682044d5b5dSValentin Clement     mlir::ConversionTarget target{*context};
1683044d5b5dSValentin Clement     target.addLegalDialect<mlir::LLVM::LLVMDialect>();
1684044d5b5dSValentin Clement 
1685044d5b5dSValentin Clement     // required NOPs for applying a full conversion
1686044d5b5dSValentin Clement     target.addLegalOp<mlir::ModuleOp>();
1687044d5b5dSValentin Clement 
1688044d5b5dSValentin Clement     // apply the patterns
1689044d5b5dSValentin Clement     if (mlir::failed(mlir::applyFullConversion(getModule(), target,
1690044d5b5dSValentin Clement                                                std::move(pattern)))) {
1691044d5b5dSValentin Clement       signalPassFailure();
1692044d5b5dSValentin Clement     }
1693044d5b5dSValentin Clement   }
1694044d5b5dSValentin Clement };
1695044d5b5dSValentin Clement } // namespace
1696044d5b5dSValentin Clement 
1697044d5b5dSValentin Clement std::unique_ptr<mlir::Pass> fir::createFIRToLLVMPass() {
1698044d5b5dSValentin Clement   return std::make_unique<FIRToLLVMLowering>();
1699044d5b5dSValentin Clement }
1700