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"
16044d5b5dSValentin Clement #include "flang/Optimizer/Dialect/FIROps.h"
17044d5b5dSValentin Clement #include "mlir/Conversion/ArithmeticToLLVM/ArithmeticToLLVM.h"
18044d5b5dSValentin Clement #include "mlir/Conversion/LLVMCommon/Pattern.h"
19044d5b5dSValentin Clement #include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h"
20044d5b5dSValentin Clement #include "mlir/IR/BuiltinTypes.h"
213ae8e442SValentin Clement #include "mlir/IR/Matchers.h"
22044d5b5dSValentin Clement #include "mlir/Pass/Pass.h"
23044d5b5dSValentin Clement #include "llvm/ADT/ArrayRef.h"
24044d5b5dSValentin Clement 
25044d5b5dSValentin Clement #define DEBUG_TYPE "flang-codegen"
26044d5b5dSValentin Clement 
27044d5b5dSValentin Clement // fir::LLVMTypeConverter for converting to LLVM IR dialect types.
28044d5b5dSValentin Clement #include "TypeConverter.h"
29044d5b5dSValentin Clement 
30b6e44ecdSValentin Clement /// `fir.box` attribute values as defined for CFI_attribute_t in
31b6e44ecdSValentin Clement /// flang/ISO_Fortran_binding.h.
32b6e44ecdSValentin Clement static constexpr unsigned kAttrPointer = CFI_attribute_pointer;
33b6e44ecdSValentin Clement static constexpr unsigned kAttrAllocatable = CFI_attribute_allocatable;
34b6e44ecdSValentin Clement 
351e6d9c06SDiana Picus static mlir::LLVM::ConstantOp
361e6d9c06SDiana Picus genConstantIndex(mlir::Location loc, mlir::Type ity,
371e6d9c06SDiana Picus                  mlir::ConversionPatternRewriter &rewriter,
381e6d9c06SDiana Picus                  std::int64_t offset) {
391e6d9c06SDiana Picus   auto cattr = rewriter.getI64IntegerAttr(offset);
401e6d9c06SDiana Picus   return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr);
411e6d9c06SDiana Picus }
421e6d9c06SDiana Picus 
43044d5b5dSValentin Clement namespace {
44044d5b5dSValentin Clement /// FIR conversion pattern template
45044d5b5dSValentin Clement template <typename FromOp>
46044d5b5dSValentin Clement class FIROpConversion : public mlir::ConvertOpToLLVMPattern<FromOp> {
47044d5b5dSValentin Clement public:
48044d5b5dSValentin Clement   explicit FIROpConversion(fir::LLVMTypeConverter &lowering)
49044d5b5dSValentin Clement       : mlir::ConvertOpToLLVMPattern<FromOp>(lowering) {}
50044d5b5dSValentin Clement 
51044d5b5dSValentin Clement protected:
52044d5b5dSValentin Clement   mlir::Type convertType(mlir::Type ty) const {
53044d5b5dSValentin Clement     return lowerTy().convertType(ty);
54044d5b5dSValentin Clement   }
55044d5b5dSValentin Clement 
56df3b9810SValentin Clement   mlir::LLVM::ConstantOp
57df3b9810SValentin Clement   genConstantOffset(mlir::Location loc,
58df3b9810SValentin Clement                     mlir::ConversionPatternRewriter &rewriter,
59df3b9810SValentin Clement                     int offset) const {
60df3b9810SValentin Clement     auto ity = lowerTy().offsetType();
61df3b9810SValentin Clement     auto cattr = rewriter.getI32IntegerAttr(offset);
62df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr);
63df3b9810SValentin Clement   }
64df3b9810SValentin Clement 
65b6e44ecdSValentin Clement   /// Construct code sequence to extract the specifc value from a `fir.box`.
66b6e44ecdSValentin Clement   mlir::Value getValueFromBox(mlir::Location loc, mlir::Value box,
67df3b9810SValentin Clement                               mlir::Type resultTy,
68b6e44ecdSValentin Clement                               mlir::ConversionPatternRewriter &rewriter,
69b6e44ecdSValentin Clement                               unsigned boxValue) const {
70df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
71b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp cValuePos =
72b6e44ecdSValentin Clement         genConstantOffset(loc, rewriter, boxValue);
73df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(resultTy);
74df3b9810SValentin Clement     auto p = rewriter.create<mlir::LLVM::GEPOp>(
75b6e44ecdSValentin Clement         loc, pty, mlir::ValueRange{box, c0, cValuePos});
76df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, resultTy, p);
77df3b9810SValentin Clement   }
78df3b9810SValentin Clement 
79df3b9810SValentin Clement   /// Method to construct code sequence to get the triple for dimension `dim`
80df3b9810SValentin Clement   /// from a box.
81df3b9810SValentin Clement   SmallVector<mlir::Value, 3>
82df3b9810SValentin Clement   getDimsFromBox(mlir::Location loc, ArrayRef<mlir::Type> retTys,
83df3b9810SValentin Clement                  mlir::Value box, mlir::Value dim,
84df3b9810SValentin Clement                  mlir::ConversionPatternRewriter &rewriter) const {
85df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
86df3b9810SValentin Clement     mlir::LLVM::ConstantOp cDims =
87df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kDimsPosInBox);
88df3b9810SValentin Clement     mlir::LLVM::LoadOp l0 =
89df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 0, retTys[0], rewriter);
90df3b9810SValentin Clement     mlir::LLVM::LoadOp l1 =
91df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 1, retTys[1], rewriter);
92df3b9810SValentin Clement     mlir::LLVM::LoadOp l2 =
93df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 2, retTys[2], rewriter);
94df3b9810SValentin Clement     return {l0.getResult(), l1.getResult(), l2.getResult()};
95df3b9810SValentin Clement   }
96df3b9810SValentin Clement 
97df3b9810SValentin Clement   mlir::LLVM::LoadOp
98df3b9810SValentin Clement   loadFromOffset(mlir::Location loc, mlir::Value a, mlir::LLVM::ConstantOp c0,
99df3b9810SValentin Clement                  mlir::LLVM::ConstantOp cDims, mlir::Value dim, int off,
100df3b9810SValentin Clement                  mlir::Type ty,
101df3b9810SValentin Clement                  mlir::ConversionPatternRewriter &rewriter) const {
102df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
103df3b9810SValentin Clement     mlir::LLVM::ConstantOp c = genConstantOffset(loc, rewriter, off);
104df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, a, c0, cDims, dim, c);
105df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
106df3b9810SValentin Clement   }
107df3b9810SValentin Clement 
108df3b9810SValentin Clement   /// Read base address from a fir.box. Returned address has type ty.
109df3b9810SValentin Clement   mlir::Value
110df3b9810SValentin Clement   loadBaseAddrFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box,
111df3b9810SValentin Clement                       mlir::ConversionPatternRewriter &rewriter) const {
112df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
113df3b9810SValentin Clement     mlir::LLVM::ConstantOp cAddr =
114df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kAddrPosInBox);
115df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
116df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cAddr);
117df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
118df3b9810SValentin Clement   }
119df3b9810SValentin Clement 
120df3b9810SValentin Clement   mlir::Value
121df3b9810SValentin Clement   loadElementSizeFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box,
122df3b9810SValentin Clement                          mlir::ConversionPatternRewriter &rewriter) const {
123df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
124df3b9810SValentin Clement     mlir::LLVM::ConstantOp cElemLen =
125df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kElemLenPosInBox);
126df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
127df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cElemLen);
128df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
129df3b9810SValentin Clement   }
130df3b9810SValentin Clement 
131b6e44ecdSValentin Clement   // Load the attribute from the \p box and perform a check against \p maskValue
132b6e44ecdSValentin Clement   // The final comparison is implemented as `(attribute & maskValue) != 0`.
133b6e44ecdSValentin Clement   mlir::Value genBoxAttributeCheck(mlir::Location loc, mlir::Value box,
134b6e44ecdSValentin Clement                                    mlir::ConversionPatternRewriter &rewriter,
135b6e44ecdSValentin Clement                                    unsigned maskValue) const {
136b6e44ecdSValentin Clement     mlir::Type attrTy = rewriter.getI32Type();
137b6e44ecdSValentin Clement     mlir::Value attribute =
138b6e44ecdSValentin Clement         getValueFromBox(loc, box, attrTy, rewriter, kAttributePosInBox);
139b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp attrMask =
140b6e44ecdSValentin Clement         genConstantOffset(loc, rewriter, maskValue);
141b6e44ecdSValentin Clement     auto maskRes =
142b6e44ecdSValentin Clement         rewriter.create<mlir::LLVM::AndOp>(loc, attrTy, attribute, attrMask);
143b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
144b6e44ecdSValentin Clement     return rewriter.create<mlir::LLVM::ICmpOp>(
145b6e44ecdSValentin Clement         loc, mlir::LLVM::ICmpPredicate::ne, maskRes, c0);
146b6e44ecdSValentin Clement   }
147b6e44ecdSValentin Clement 
148df3b9810SValentin Clement   template <typename... ARGS>
149df3b9810SValentin Clement   mlir::LLVM::GEPOp genGEP(mlir::Location loc, mlir::Type ty,
150df3b9810SValentin Clement                            mlir::ConversionPatternRewriter &rewriter,
151df3b9810SValentin Clement                            mlir::Value base, ARGS... args) const {
152df3b9810SValentin Clement     SmallVector<mlir::Value> cv{args...};
153df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::GEPOp>(loc, ty, base, cv);
154df3b9810SValentin Clement   }
155df3b9810SValentin Clement 
1561e6d9c06SDiana Picus   /// Perform an extension or truncation as needed on an integer value. Lowering
1571e6d9c06SDiana Picus   /// to the specific target may involve some sign-extending or truncation of
1581e6d9c06SDiana Picus   /// values, particularly to fit them from abstract box types to the
1591e6d9c06SDiana Picus   /// appropriate reified structures.
1601e6d9c06SDiana Picus   mlir::Value integerCast(mlir::Location loc,
1611e6d9c06SDiana Picus                           mlir::ConversionPatternRewriter &rewriter,
1621e6d9c06SDiana Picus                           mlir::Type ty, mlir::Value val) const {
1631e6d9c06SDiana Picus     auto valTy = val.getType();
1641e6d9c06SDiana Picus     // If the value was not yet lowered, lower its type so that it can
1651e6d9c06SDiana Picus     // be used in getPrimitiveTypeSizeInBits.
1661e6d9c06SDiana Picus     if (!valTy.isa<mlir::IntegerType>())
1671e6d9c06SDiana Picus       valTy = convertType(valTy);
1681e6d9c06SDiana Picus     auto toSize = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
1691e6d9c06SDiana Picus     auto fromSize = mlir::LLVM::getPrimitiveTypeSizeInBits(valTy);
1701e6d9c06SDiana Picus     if (toSize < fromSize)
1711e6d9c06SDiana Picus       return rewriter.create<mlir::LLVM::TruncOp>(loc, ty, val);
1721e6d9c06SDiana Picus     if (toSize > fromSize)
1731e6d9c06SDiana Picus       return rewriter.create<mlir::LLVM::SExtOp>(loc, ty, val);
1741e6d9c06SDiana Picus     return val;
1751e6d9c06SDiana Picus   }
1761e6d9c06SDiana Picus 
177044d5b5dSValentin Clement   fir::LLVMTypeConverter &lowerTy() const {
178044d5b5dSValentin Clement     return *static_cast<fir::LLVMTypeConverter *>(this->getTypeConverter());
179044d5b5dSValentin Clement   }
180044d5b5dSValentin Clement };
181044d5b5dSValentin Clement 
1823ae8e442SValentin Clement /// FIR conversion pattern template
1833ae8e442SValentin Clement template <typename FromOp>
1843ae8e442SValentin Clement class FIROpAndTypeConversion : public FIROpConversion<FromOp> {
1853ae8e442SValentin Clement public:
1863ae8e442SValentin Clement   using FIROpConversion<FromOp>::FIROpConversion;
1873ae8e442SValentin Clement   using OpAdaptor = typename FromOp::Adaptor;
1883ae8e442SValentin Clement 
1893ae8e442SValentin Clement   mlir::LogicalResult
1903ae8e442SValentin Clement   matchAndRewrite(FromOp op, OpAdaptor adaptor,
1913ae8e442SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const final {
1923ae8e442SValentin Clement     mlir::Type ty = this->convertType(op.getType());
1933ae8e442SValentin Clement     return doRewrite(op, ty, adaptor, rewriter);
1943ae8e442SValentin Clement   }
1953ae8e442SValentin Clement 
1963ae8e442SValentin Clement   virtual mlir::LogicalResult
1973ae8e442SValentin Clement   doRewrite(FromOp addr, mlir::Type ty, OpAdaptor adaptor,
1983ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const = 0;
1993ae8e442SValentin Clement };
2003ae8e442SValentin Clement 
2010c4a7a52SValentin Clement // Lower `fir.address_of` operation to `llvm.address_of` operation.
202044d5b5dSValentin Clement struct AddrOfOpConversion : public FIROpConversion<fir::AddrOfOp> {
203044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
204044d5b5dSValentin Clement 
205044d5b5dSValentin Clement   mlir::LogicalResult
206044d5b5dSValentin Clement   matchAndRewrite(fir::AddrOfOp addr, OpAdaptor adaptor,
207044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
208044d5b5dSValentin Clement     auto ty = convertType(addr.getType());
209044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::AddressOfOp>(
210044d5b5dSValentin Clement         addr, ty, addr.symbol().getRootReference().getValue());
211044d5b5dSValentin Clement     return success();
212044d5b5dSValentin Clement   }
213044d5b5dSValentin Clement };
2141e6d9c06SDiana Picus } // namespace
2151e6d9c06SDiana Picus 
2161e6d9c06SDiana Picus /// Lookup the function to compute the memory size of this parametric derived
2171e6d9c06SDiana Picus /// type. The size of the object may depend on the LEN type parameters of the
2181e6d9c06SDiana Picus /// derived type.
2191e6d9c06SDiana Picus static mlir::LLVM::LLVMFuncOp
2201e6d9c06SDiana Picus getDependentTypeMemSizeFn(fir::RecordType recTy, fir::AllocaOp op,
2211e6d9c06SDiana Picus                           mlir::ConversionPatternRewriter &rewriter) {
2221e6d9c06SDiana Picus   auto module = op->getParentOfType<mlir::ModuleOp>();
2231e6d9c06SDiana Picus   std::string name = recTy.getName().str() + "P.mem.size";
2241e6d9c06SDiana Picus   return module.lookupSymbol<mlir::LLVM::LLVMFuncOp>(name);
2251e6d9c06SDiana Picus }
2261e6d9c06SDiana Picus 
2271e6d9c06SDiana Picus namespace {
2281e6d9c06SDiana Picus /// convert to LLVM IR dialect `alloca`
2291e6d9c06SDiana Picus struct AllocaOpConversion : public FIROpConversion<fir::AllocaOp> {
2301e6d9c06SDiana Picus   using FIROpConversion::FIROpConversion;
2311e6d9c06SDiana Picus 
2321e6d9c06SDiana Picus   mlir::LogicalResult
2331e6d9c06SDiana Picus   matchAndRewrite(fir::AllocaOp alloc, OpAdaptor adaptor,
2341e6d9c06SDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
2351e6d9c06SDiana Picus     mlir::ValueRange operands = adaptor.getOperands();
2361e6d9c06SDiana Picus     auto loc = alloc.getLoc();
2371e6d9c06SDiana Picus     mlir::Type ity = lowerTy().indexType();
2381e6d9c06SDiana Picus     unsigned i = 0;
2391e6d9c06SDiana Picus     mlir::Value size = genConstantIndex(loc, ity, rewriter, 1).getResult();
2401e6d9c06SDiana Picus     mlir::Type ty = convertType(alloc.getType());
2411e6d9c06SDiana Picus     mlir::Type resultTy = ty;
2421e6d9c06SDiana Picus     if (alloc.hasLenParams()) {
2431e6d9c06SDiana Picus       unsigned end = alloc.numLenParams();
2441e6d9c06SDiana Picus       llvm::SmallVector<mlir::Value> lenParams;
2451e6d9c06SDiana Picus       for (; i < end; ++i)
2461e6d9c06SDiana Picus         lenParams.push_back(operands[i]);
2471e6d9c06SDiana Picus       mlir::Type scalarType = fir::unwrapSequenceType(alloc.getInType());
2481e6d9c06SDiana Picus       if (auto chrTy = scalarType.dyn_cast<fir::CharacterType>()) {
2491e6d9c06SDiana Picus         fir::CharacterType rawCharTy = fir::CharacterType::getUnknownLen(
2501e6d9c06SDiana Picus             chrTy.getContext(), chrTy.getFKind());
2511e6d9c06SDiana Picus         ty = mlir::LLVM::LLVMPointerType::get(convertType(rawCharTy));
2521e6d9c06SDiana Picus         assert(end == 1);
2531e6d9c06SDiana Picus         size = integerCast(loc, rewriter, ity, lenParams[0]);
2541e6d9c06SDiana Picus       } else if (auto recTy = scalarType.dyn_cast<fir::RecordType>()) {
2551e6d9c06SDiana Picus         mlir::LLVM::LLVMFuncOp memSizeFn =
2561e6d9c06SDiana Picus             getDependentTypeMemSizeFn(recTy, alloc, rewriter);
2571e6d9c06SDiana Picus         if (!memSizeFn)
2581e6d9c06SDiana Picus           emitError(loc, "did not find allocation function");
2591e6d9c06SDiana Picus         mlir::NamedAttribute attr = rewriter.getNamedAttr(
2601e6d9c06SDiana Picus             "callee", mlir::SymbolRefAttr::get(memSizeFn));
2611e6d9c06SDiana Picus         auto call = rewriter.create<mlir::LLVM::CallOp>(
2621e6d9c06SDiana Picus             loc, ity, lenParams, llvm::ArrayRef<mlir::NamedAttribute>{attr});
2631e6d9c06SDiana Picus         size = call.getResult(0);
2641e6d9c06SDiana Picus         ty = mlir::LLVM::LLVMPointerType::get(
2651e6d9c06SDiana Picus             mlir::IntegerType::get(alloc.getContext(), 8));
2661e6d9c06SDiana Picus       } else {
2671e6d9c06SDiana Picus         return emitError(loc, "unexpected type ")
2681e6d9c06SDiana Picus                << scalarType << " with type parameters";
2691e6d9c06SDiana Picus       }
2701e6d9c06SDiana Picus     }
2711e6d9c06SDiana Picus     if (alloc.hasShapeOperands()) {
2721e6d9c06SDiana Picus       mlir::Type allocEleTy = fir::unwrapRefType(alloc.getType());
2731e6d9c06SDiana Picus       // Scale the size by constant factors encoded in the array type.
2741e6d9c06SDiana Picus       if (auto seqTy = allocEleTy.dyn_cast<fir::SequenceType>()) {
2751e6d9c06SDiana Picus         fir::SequenceType::Extent constSize = 1;
2761e6d9c06SDiana Picus         for (auto extent : seqTy.getShape())
2771e6d9c06SDiana Picus           if (extent != fir::SequenceType::getUnknownExtent())
2781e6d9c06SDiana Picus             constSize *= extent;
2791e6d9c06SDiana Picus         mlir::Value constVal{
2801e6d9c06SDiana Picus             genConstantIndex(loc, ity, rewriter, constSize).getResult()};
2811e6d9c06SDiana Picus         size = rewriter.create<mlir::LLVM::MulOp>(loc, ity, size, constVal);
2821e6d9c06SDiana Picus       }
2831e6d9c06SDiana Picus       unsigned end = operands.size();
2841e6d9c06SDiana Picus       for (; i < end; ++i)
2851e6d9c06SDiana Picus         size = rewriter.create<mlir::LLVM::MulOp>(
2861e6d9c06SDiana Picus             loc, ity, size, integerCast(loc, rewriter, ity, operands[i]));
2871e6d9c06SDiana Picus     }
2881e6d9c06SDiana Picus     if (ty == resultTy) {
2891e6d9c06SDiana Picus       // Do not emit the bitcast if ty and resultTy are the same.
2901e6d9c06SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::AllocaOp>(alloc, ty, size,
2911e6d9c06SDiana Picus                                                         alloc->getAttrs());
2921e6d9c06SDiana Picus     } else {
2931e6d9c06SDiana Picus       auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, ty, size,
2941e6d9c06SDiana Picus                                                       alloc->getAttrs());
2951e6d9c06SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(alloc, resultTy, al);
2961e6d9c06SDiana Picus     }
2971e6d9c06SDiana Picus     return success();
2981e6d9c06SDiana Picus   }
2991e6d9c06SDiana Picus };
300044d5b5dSValentin Clement 
301df3b9810SValentin Clement /// Lower `fir.box_addr` to the sequence of operations to extract the first
302df3b9810SValentin Clement /// element of the box.
303df3b9810SValentin Clement struct BoxAddrOpConversion : public FIROpConversion<fir::BoxAddrOp> {
304df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
305df3b9810SValentin Clement 
306df3b9810SValentin Clement   mlir::LogicalResult
307df3b9810SValentin Clement   matchAndRewrite(fir::BoxAddrOp boxaddr, OpAdaptor adaptor,
308df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
309df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
310df3b9810SValentin Clement     auto loc = boxaddr.getLoc();
311df3b9810SValentin Clement     mlir::Type ty = convertType(boxaddr.getType());
312df3b9810SValentin Clement     if (auto argty = boxaddr.val().getType().dyn_cast<fir::BoxType>()) {
313df3b9810SValentin Clement       rewriter.replaceOp(boxaddr, loadBaseAddrFromBox(loc, ty, a, rewriter));
314df3b9810SValentin Clement     } else {
315df3b9810SValentin Clement       auto c0attr = rewriter.getI32IntegerAttr(0);
316df3b9810SValentin Clement       auto c0 = mlir::ArrayAttr::get(boxaddr.getContext(), c0attr);
317df3b9810SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(boxaddr, ty, a,
318df3b9810SValentin Clement                                                               c0);
319df3b9810SValentin Clement     }
320df3b9810SValentin Clement     return success();
321df3b9810SValentin Clement   }
322df3b9810SValentin Clement };
323df3b9810SValentin Clement 
324df3b9810SValentin Clement /// Lower `fir.box_dims` to a sequence of operations to extract the requested
325df3b9810SValentin Clement /// dimension infomartion from the boxed value.
326df3b9810SValentin Clement /// Result in a triple set of GEPs and loads.
327df3b9810SValentin Clement struct BoxDimsOpConversion : public FIROpConversion<fir::BoxDimsOp> {
328df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
329df3b9810SValentin Clement 
330df3b9810SValentin Clement   mlir::LogicalResult
331df3b9810SValentin Clement   matchAndRewrite(fir::BoxDimsOp boxdims, OpAdaptor adaptor,
332df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
333df3b9810SValentin Clement     SmallVector<mlir::Type, 3> resultTypes = {
334df3b9810SValentin Clement         convertType(boxdims.getResult(0).getType()),
335df3b9810SValentin Clement         convertType(boxdims.getResult(1).getType()),
336df3b9810SValentin Clement         convertType(boxdims.getResult(2).getType()),
337df3b9810SValentin Clement     };
338df3b9810SValentin Clement     auto results =
339df3b9810SValentin Clement         getDimsFromBox(boxdims.getLoc(), resultTypes, adaptor.getOperands()[0],
340df3b9810SValentin Clement                        adaptor.getOperands()[1], rewriter);
341df3b9810SValentin Clement     rewriter.replaceOp(boxdims, results);
342df3b9810SValentin Clement     return success();
343df3b9810SValentin Clement   }
344df3b9810SValentin Clement };
345df3b9810SValentin Clement 
346df3b9810SValentin Clement /// Lower `fir.box_elesize` to a sequence of operations ro extract the size of
347df3b9810SValentin Clement /// an element in the boxed value.
348df3b9810SValentin Clement struct BoxEleSizeOpConversion : public FIROpConversion<fir::BoxEleSizeOp> {
349df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
350df3b9810SValentin Clement 
351df3b9810SValentin Clement   mlir::LogicalResult
352df3b9810SValentin Clement   matchAndRewrite(fir::BoxEleSizeOp boxelesz, OpAdaptor adaptor,
353df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
354df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
355df3b9810SValentin Clement     auto loc = boxelesz.getLoc();
356df3b9810SValentin Clement     auto ty = convertType(boxelesz.getType());
357b6e44ecdSValentin Clement     auto elemSize = getValueFromBox(loc, a, ty, rewriter, kElemLenPosInBox);
358b6e44ecdSValentin Clement     rewriter.replaceOp(boxelesz, elemSize);
359b6e44ecdSValentin Clement     return success();
360b6e44ecdSValentin Clement   }
361b6e44ecdSValentin Clement };
362b6e44ecdSValentin Clement 
363b6e44ecdSValentin Clement /// Lower `fir.box_isalloc` to a sequence of operations to determine if the
364b6e44ecdSValentin Clement /// boxed value was from an ALLOCATABLE entity.
365b6e44ecdSValentin Clement struct BoxIsAllocOpConversion : public FIROpConversion<fir::BoxIsAllocOp> {
366b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
367b6e44ecdSValentin Clement 
368b6e44ecdSValentin Clement   mlir::LogicalResult
369b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsAllocOp boxisalloc, OpAdaptor adaptor,
370b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
371b6e44ecdSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
372b6e44ecdSValentin Clement     auto loc = boxisalloc.getLoc();
373b6e44ecdSValentin Clement     mlir::Value check =
374b6e44ecdSValentin Clement         genBoxAttributeCheck(loc, box, rewriter, kAttrAllocatable);
375b6e44ecdSValentin Clement     rewriter.replaceOp(boxisalloc, check);
376b6e44ecdSValentin Clement     return success();
377b6e44ecdSValentin Clement   }
378b6e44ecdSValentin Clement };
379b6e44ecdSValentin Clement 
380b6e44ecdSValentin Clement /// Lower `fir.box_isarray` to a sequence of operations to determine if the
381b6e44ecdSValentin Clement /// boxed is an array.
382b6e44ecdSValentin Clement struct BoxIsArrayOpConversion : public FIROpConversion<fir::BoxIsArrayOp> {
383b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
384b6e44ecdSValentin Clement 
385b6e44ecdSValentin Clement   mlir::LogicalResult
386b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsArrayOp boxisarray, OpAdaptor adaptor,
387b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
388b6e44ecdSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
389b6e44ecdSValentin Clement     auto loc = boxisarray.getLoc();
390b6e44ecdSValentin Clement     auto rank =
391b6e44ecdSValentin Clement         getValueFromBox(loc, a, rewriter.getI32Type(), rewriter, kRankPosInBox);
392b6e44ecdSValentin Clement     auto c0 = genConstantOffset(loc, rewriter, 0);
393b6e44ecdSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
394b6e44ecdSValentin Clement         boxisarray, mlir::LLVM::ICmpPredicate::ne, rank, c0);
395b6e44ecdSValentin Clement     return success();
396b6e44ecdSValentin Clement   }
397b6e44ecdSValentin Clement };
398b6e44ecdSValentin Clement 
399b6e44ecdSValentin Clement /// Lower `fir.box_isptr` to a sequence of operations to determined if the
400b6e44ecdSValentin Clement /// boxed value was from a POINTER entity.
401b6e44ecdSValentin Clement struct BoxIsPtrOpConversion : public FIROpConversion<fir::BoxIsPtrOp> {
402b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
403b6e44ecdSValentin Clement 
404b6e44ecdSValentin Clement   mlir::LogicalResult
405b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsPtrOp boxisptr, OpAdaptor adaptor,
406b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
407b6e44ecdSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
408b6e44ecdSValentin Clement     auto loc = boxisptr.getLoc();
409b6e44ecdSValentin Clement     mlir::Value check = genBoxAttributeCheck(loc, box, rewriter, kAttrPointer);
410b6e44ecdSValentin Clement     rewriter.replaceOp(boxisptr, check);
411df3b9810SValentin Clement     return success();
412df3b9810SValentin Clement   }
413df3b9810SValentin Clement };
414df3b9810SValentin Clement 
415df3b9810SValentin Clement /// Lower `fir.box_rank` to the sequence of operation to extract the rank from
416df3b9810SValentin Clement /// the box.
417df3b9810SValentin Clement struct BoxRankOpConversion : public FIROpConversion<fir::BoxRankOp> {
418df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
419df3b9810SValentin Clement 
420df3b9810SValentin Clement   mlir::LogicalResult
421df3b9810SValentin Clement   matchAndRewrite(fir::BoxRankOp boxrank, OpAdaptor adaptor,
422df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
423df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
424df3b9810SValentin Clement     auto loc = boxrank.getLoc();
425df3b9810SValentin Clement     mlir::Type ty = convertType(boxrank.getType());
426b6e44ecdSValentin Clement     auto result = getValueFromBox(loc, a, ty, rewriter, kRankPosInBox);
427df3b9810SValentin Clement     rewriter.replaceOp(boxrank, result);
428df3b9810SValentin Clement     return success();
429df3b9810SValentin Clement   }
430df3b9810SValentin Clement };
431df3b9810SValentin Clement 
432ddd11b9aSAndrzej Warzynski // `fir.call` -> `llvm.call`
433ddd11b9aSAndrzej Warzynski struct CallOpConversion : public FIROpConversion<fir::CallOp> {
434ddd11b9aSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
435ddd11b9aSAndrzej Warzynski 
436ddd11b9aSAndrzej Warzynski   mlir::LogicalResult
437ddd11b9aSAndrzej Warzynski   matchAndRewrite(fir::CallOp call, OpAdaptor adaptor,
438ddd11b9aSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
439ddd11b9aSAndrzej Warzynski     SmallVector<mlir::Type> resultTys;
440ddd11b9aSAndrzej Warzynski     for (auto r : call.getResults())
441ddd11b9aSAndrzej Warzynski       resultTys.push_back(convertType(r.getType()));
442ddd11b9aSAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
443ddd11b9aSAndrzej Warzynski         call, resultTys, adaptor.getOperands(), call->getAttrs());
444ddd11b9aSAndrzej Warzynski     return success();
445ddd11b9aSAndrzej Warzynski   }
446ddd11b9aSAndrzej Warzynski };
447ddd11b9aSAndrzej Warzynski 
448092cee5fSValentin Clement static mlir::Type getComplexEleTy(mlir::Type complex) {
449092cee5fSValentin Clement   if (auto cc = complex.dyn_cast<mlir::ComplexType>())
450092cee5fSValentin Clement     return cc.getElementType();
451092cee5fSValentin Clement   return complex.cast<fir::ComplexType>().getElementType();
452092cee5fSValentin Clement }
453092cee5fSValentin Clement 
454092cee5fSValentin Clement /// convert value of from-type to value of to-type
455092cee5fSValentin Clement struct ConvertOpConversion : public FIROpConversion<fir::ConvertOp> {
456092cee5fSValentin Clement   using FIROpConversion::FIROpConversion;
457092cee5fSValentin Clement 
458092cee5fSValentin Clement   static bool isFloatingPointTy(mlir::Type ty) {
459092cee5fSValentin Clement     return ty.isa<mlir::FloatType>();
460092cee5fSValentin Clement   }
461092cee5fSValentin Clement 
462092cee5fSValentin Clement   mlir::LogicalResult
463092cee5fSValentin Clement   matchAndRewrite(fir::ConvertOp convert, OpAdaptor adaptor,
464092cee5fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
465092cee5fSValentin Clement     auto fromTy = convertType(convert.value().getType());
466092cee5fSValentin Clement     auto toTy = convertType(convert.res().getType());
467092cee5fSValentin Clement     mlir::Value op0 = adaptor.getOperands()[0];
468092cee5fSValentin Clement     if (fromTy == toTy) {
469092cee5fSValentin Clement       rewriter.replaceOp(convert, op0);
470092cee5fSValentin Clement       return success();
471092cee5fSValentin Clement     }
472092cee5fSValentin Clement     auto loc = convert.getLoc();
473092cee5fSValentin Clement     auto convertFpToFp = [&](mlir::Value val, unsigned fromBits,
474092cee5fSValentin Clement                              unsigned toBits, mlir::Type toTy) -> mlir::Value {
475092cee5fSValentin Clement       if (fromBits == toBits) {
476092cee5fSValentin Clement         // TODO: Converting between two floating-point representations with the
477092cee5fSValentin Clement         // same bitwidth is not allowed for now.
478092cee5fSValentin Clement         mlir::emitError(loc,
479092cee5fSValentin Clement                         "cannot implicitly convert between two floating-point "
480092cee5fSValentin Clement                         "representations of the same bitwidth");
481092cee5fSValentin Clement         return {};
482092cee5fSValentin Clement       }
483092cee5fSValentin Clement       if (fromBits > toBits)
484092cee5fSValentin Clement         return rewriter.create<mlir::LLVM::FPTruncOp>(loc, toTy, val);
485092cee5fSValentin Clement       return rewriter.create<mlir::LLVM::FPExtOp>(loc, toTy, val);
486092cee5fSValentin Clement     };
487092cee5fSValentin Clement     // Complex to complex conversion.
488092cee5fSValentin Clement     if (fir::isa_complex(convert.value().getType()) &&
489092cee5fSValentin Clement         fir::isa_complex(convert.res().getType())) {
490092cee5fSValentin Clement       // Special case: handle the conversion of a complex such that both the
491092cee5fSValentin Clement       // real and imaginary parts are converted together.
492092cee5fSValentin Clement       auto zero = mlir::ArrayAttr::get(convert.getContext(),
493092cee5fSValentin Clement                                        rewriter.getI32IntegerAttr(0));
494092cee5fSValentin Clement       auto one = mlir::ArrayAttr::get(convert.getContext(),
495092cee5fSValentin Clement                                       rewriter.getI32IntegerAttr(1));
496092cee5fSValentin Clement       auto ty = convertType(getComplexEleTy(convert.value().getType()));
497092cee5fSValentin Clement       auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, zero);
498092cee5fSValentin Clement       auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, one);
499092cee5fSValentin Clement       auto nt = convertType(getComplexEleTy(convert.res().getType()));
500092cee5fSValentin Clement       auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
501092cee5fSValentin Clement       auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(nt);
502092cee5fSValentin Clement       auto rc = convertFpToFp(rp, fromBits, toBits, nt);
503092cee5fSValentin Clement       auto ic = convertFpToFp(ip, fromBits, toBits, nt);
504092cee5fSValentin Clement       auto un = rewriter.create<mlir::LLVM::UndefOp>(loc, toTy);
505092cee5fSValentin Clement       auto i1 =
506092cee5fSValentin Clement           rewriter.create<mlir::LLVM::InsertValueOp>(loc, toTy, un, rc, zero);
507092cee5fSValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(convert, toTy, i1,
508092cee5fSValentin Clement                                                              ic, one);
509092cee5fSValentin Clement       return mlir::success();
510092cee5fSValentin Clement     }
511092cee5fSValentin Clement     // Floating point to floating point conversion.
512092cee5fSValentin Clement     if (isFloatingPointTy(fromTy)) {
513092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
514092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
515092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
516092cee5fSValentin Clement         auto v = convertFpToFp(op0, fromBits, toBits, toTy);
517092cee5fSValentin Clement         rewriter.replaceOp(convert, v);
518092cee5fSValentin Clement         return mlir::success();
519092cee5fSValentin Clement       }
520092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
521092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::FPToSIOp>(convert, toTy, op0);
522092cee5fSValentin Clement         return mlir::success();
523092cee5fSValentin Clement       }
524092cee5fSValentin Clement     } else if (fromTy.isa<mlir::IntegerType>()) {
525092cee5fSValentin Clement       // Integer to integer conversion.
526092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
527092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
528092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
529092cee5fSValentin Clement         assert(fromBits != toBits);
530092cee5fSValentin Clement         if (fromBits > toBits) {
531092cee5fSValentin Clement           rewriter.replaceOpWithNewOp<mlir::LLVM::TruncOp>(convert, toTy, op0);
532092cee5fSValentin Clement           return mlir::success();
533092cee5fSValentin Clement         }
534092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SExtOp>(convert, toTy, op0);
535092cee5fSValentin Clement         return mlir::success();
536092cee5fSValentin Clement       }
537092cee5fSValentin Clement       // Integer to floating point conversion.
538092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
539092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SIToFPOp>(convert, toTy, op0);
540092cee5fSValentin Clement         return mlir::success();
541092cee5fSValentin Clement       }
542092cee5fSValentin Clement       // Integer to pointer conversion.
543092cee5fSValentin Clement       if (toTy.isa<mlir::LLVM::LLVMPointerType>()) {
544092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(convert, toTy, op0);
545092cee5fSValentin Clement         return mlir::success();
546092cee5fSValentin Clement       }
547092cee5fSValentin Clement     } else if (fromTy.isa<mlir::LLVM::LLVMPointerType>()) {
548092cee5fSValentin Clement       // Pointer to integer conversion.
549092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
550092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::PtrToIntOp>(convert, toTy, op0);
551092cee5fSValentin Clement         return mlir::success();
552092cee5fSValentin Clement       }
553092cee5fSValentin Clement       // Pointer to pointer conversion.
554092cee5fSValentin Clement       if (toTy.isa<mlir::LLVM::LLVMPointerType>()) {
555092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(convert, toTy, op0);
556092cee5fSValentin Clement         return mlir::success();
557092cee5fSValentin Clement       }
558092cee5fSValentin Clement     }
559092cee5fSValentin Clement     return emitError(loc) << "cannot convert " << fromTy << " to " << toTy;
560092cee5fSValentin Clement   }
561092cee5fSValentin Clement };
562092cee5fSValentin Clement 
563*9534e361SValentin Clement /// Lower `fir.dispatch` operation. A virtual call to a method in a dispatch
564*9534e361SValentin Clement /// table.
565*9534e361SValentin Clement struct DispatchOpConversion : public FIROpConversion<fir::DispatchOp> {
566*9534e361SValentin Clement   using FIROpConversion::FIROpConversion;
567*9534e361SValentin Clement 
568*9534e361SValentin Clement   mlir::LogicalResult
569*9534e361SValentin Clement   matchAndRewrite(fir::DispatchOp dispatch, OpAdaptor adaptor,
570*9534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
571*9534e361SValentin Clement     return rewriter.notifyMatchFailure(
572*9534e361SValentin Clement         dispatch, "fir.dispatch codegen is not implemented yet");
573*9534e361SValentin Clement   }
574*9534e361SValentin Clement };
575*9534e361SValentin Clement 
576*9534e361SValentin Clement /// Lower `fir.dispatch_table` operation. The dispatch table for a Fortran
577*9534e361SValentin Clement /// derived type.
578*9534e361SValentin Clement struct DispatchTableOpConversion
579*9534e361SValentin Clement     : public FIROpConversion<fir::DispatchTableOp> {
580*9534e361SValentin Clement   using FIROpConversion::FIROpConversion;
581*9534e361SValentin Clement 
582*9534e361SValentin Clement   mlir::LogicalResult
583*9534e361SValentin Clement   matchAndRewrite(fir::DispatchTableOp dispTab, OpAdaptor adaptor,
584*9534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
585*9534e361SValentin Clement     return rewriter.notifyMatchFailure(
586*9534e361SValentin Clement         dispTab, "fir.dispatch_table codegen is not implemented yet");
587*9534e361SValentin Clement   }
588*9534e361SValentin Clement };
589*9534e361SValentin Clement 
590*9534e361SValentin Clement /// Lower `fir.dt_entry` operation. An entry in a dispatch table; binds a
591*9534e361SValentin Clement /// method-name to a function.
592*9534e361SValentin Clement struct DTEntryOpConversion : public FIROpConversion<fir::DTEntryOp> {
593*9534e361SValentin Clement   using FIROpConversion::FIROpConversion;
594*9534e361SValentin Clement 
595*9534e361SValentin Clement   mlir::LogicalResult
596*9534e361SValentin Clement   matchAndRewrite(fir::DTEntryOp dtEnt, OpAdaptor adaptor,
597*9534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
598*9534e361SValentin Clement     return rewriter.notifyMatchFailure(
599*9534e361SValentin Clement         dtEnt, "fir.dt_entry codegen is not implemented yet");
600*9534e361SValentin Clement   }
601*9534e361SValentin Clement };
602*9534e361SValentin Clement 
6030c4a7a52SValentin Clement /// Lower `fir.has_value` operation to `llvm.return` operation.
604044d5b5dSValentin Clement struct HasValueOpConversion : public FIROpConversion<fir::HasValueOp> {
605044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
606044d5b5dSValentin Clement 
607044d5b5dSValentin Clement   mlir::LogicalResult
608044d5b5dSValentin Clement   matchAndRewrite(fir::HasValueOp op, OpAdaptor adaptor,
609044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
610044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, adaptor.getOperands());
611044d5b5dSValentin Clement     return success();
612044d5b5dSValentin Clement   }
613044d5b5dSValentin Clement };
614044d5b5dSValentin Clement 
6150c4a7a52SValentin Clement /// Lower `fir.global` operation to `llvm.global` operation.
6160c4a7a52SValentin Clement /// `fir.insert_on_range` operations are replaced with constant dense attribute
6170c4a7a52SValentin Clement /// if they are applied on the full range.
618044d5b5dSValentin Clement struct GlobalOpConversion : public FIROpConversion<fir::GlobalOp> {
619044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
620044d5b5dSValentin Clement 
621044d5b5dSValentin Clement   mlir::LogicalResult
622044d5b5dSValentin Clement   matchAndRewrite(fir::GlobalOp global, OpAdaptor adaptor,
623044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
624044d5b5dSValentin Clement     auto tyAttr = convertType(global.getType());
625044d5b5dSValentin Clement     if (global.getType().isa<fir::BoxType>())
626044d5b5dSValentin Clement       tyAttr = tyAttr.cast<mlir::LLVM::LLVMPointerType>().getElementType();
627044d5b5dSValentin Clement     auto loc = global.getLoc();
628044d5b5dSValentin Clement     mlir::Attribute initAttr{};
629044d5b5dSValentin Clement     if (global.initVal())
630044d5b5dSValentin Clement       initAttr = global.initVal().getValue();
631044d5b5dSValentin Clement     auto linkage = convertLinkage(global.linkName());
632044d5b5dSValentin Clement     auto isConst = global.constant().hasValue();
633044d5b5dSValentin Clement     auto g = rewriter.create<mlir::LLVM::GlobalOp>(
634044d5b5dSValentin Clement         loc, tyAttr, isConst, linkage, global.sym_name(), initAttr);
635044d5b5dSValentin Clement     auto &gr = g.getInitializerRegion();
636044d5b5dSValentin Clement     rewriter.inlineRegionBefore(global.region(), gr, gr.end());
637044d5b5dSValentin Clement     if (!gr.empty()) {
638044d5b5dSValentin Clement       // Replace insert_on_range with a constant dense attribute if the
639044d5b5dSValentin Clement       // initialization is on the full range.
640044d5b5dSValentin Clement       auto insertOnRangeOps = gr.front().getOps<fir::InsertOnRangeOp>();
641044d5b5dSValentin Clement       for (auto insertOp : insertOnRangeOps) {
642044d5b5dSValentin Clement         if (isFullRange(insertOp.coor(), insertOp.getType())) {
643044d5b5dSValentin Clement           auto seqTyAttr = convertType(insertOp.getType());
644044d5b5dSValentin Clement           auto *op = insertOp.val().getDefiningOp();
645044d5b5dSValentin Clement           auto constant = mlir::dyn_cast<mlir::arith::ConstantOp>(op);
646044d5b5dSValentin Clement           if (!constant) {
647044d5b5dSValentin Clement             auto convertOp = mlir::dyn_cast<fir::ConvertOp>(op);
648044d5b5dSValentin Clement             if (!convertOp)
649044d5b5dSValentin Clement               continue;
650044d5b5dSValentin Clement             constant = cast<mlir::arith::ConstantOp>(
651044d5b5dSValentin Clement                 convertOp.value().getDefiningOp());
652044d5b5dSValentin Clement           }
653044d5b5dSValentin Clement           mlir::Type vecType = mlir::VectorType::get(
654044d5b5dSValentin Clement               insertOp.getType().getShape(), constant.getType());
655044d5b5dSValentin Clement           auto denseAttr = mlir::DenseElementsAttr::get(
656044d5b5dSValentin Clement               vecType.cast<ShapedType>(), constant.value());
657044d5b5dSValentin Clement           rewriter.setInsertionPointAfter(insertOp);
658044d5b5dSValentin Clement           rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(
659044d5b5dSValentin Clement               insertOp, seqTyAttr, denseAttr);
660044d5b5dSValentin Clement         }
661044d5b5dSValentin Clement       }
662044d5b5dSValentin Clement     }
663044d5b5dSValentin Clement     rewriter.eraseOp(global);
664044d5b5dSValentin Clement     return success();
665044d5b5dSValentin Clement   }
666044d5b5dSValentin Clement 
667044d5b5dSValentin Clement   bool isFullRange(mlir::ArrayAttr indexes, fir::SequenceType seqTy) const {
668044d5b5dSValentin Clement     auto extents = seqTy.getShape();
669044d5b5dSValentin Clement     if (indexes.size() / 2 != extents.size())
670044d5b5dSValentin Clement       return false;
671044d5b5dSValentin Clement     for (unsigned i = 0; i < indexes.size(); i += 2) {
672044d5b5dSValentin Clement       if (indexes[i].cast<IntegerAttr>().getInt() != 0)
673044d5b5dSValentin Clement         return false;
674044d5b5dSValentin Clement       if (indexes[i + 1].cast<IntegerAttr>().getInt() != extents[i / 2] - 1)
675044d5b5dSValentin Clement         return false;
676044d5b5dSValentin Clement     }
677044d5b5dSValentin Clement     return true;
678044d5b5dSValentin Clement   }
679044d5b5dSValentin Clement 
6800c4a7a52SValentin Clement   // TODO: String comparaison should be avoided. Replace linkName with an
6810c4a7a52SValentin Clement   // enumeration.
682044d5b5dSValentin Clement   mlir::LLVM::Linkage convertLinkage(Optional<StringRef> optLinkage) const {
683044d5b5dSValentin Clement     if (optLinkage.hasValue()) {
684044d5b5dSValentin Clement       auto name = optLinkage.getValue();
685044d5b5dSValentin Clement       if (name == "internal")
686044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Internal;
687044d5b5dSValentin Clement       if (name == "linkonce")
688044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Linkonce;
689044d5b5dSValentin Clement       if (name == "common")
690044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Common;
691044d5b5dSValentin Clement       if (name == "weak")
692044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Weak;
693044d5b5dSValentin Clement     }
694044d5b5dSValentin Clement     return mlir::LLVM::Linkage::External;
695044d5b5dSValentin Clement   }
696044d5b5dSValentin Clement };
697044d5b5dSValentin Clement 
6988c239909SValentin Clement template <typename OP>
6998c239909SValentin Clement void selectMatchAndRewrite(fir::LLVMTypeConverter &lowering, OP select,
7008c239909SValentin Clement                            typename OP::Adaptor adaptor,
7018c239909SValentin Clement                            mlir::ConversionPatternRewriter &rewriter) {
7028c239909SValentin Clement   unsigned conds = select.getNumConditions();
7038c239909SValentin Clement   auto cases = select.getCases().getValue();
7048c239909SValentin Clement   mlir::Value selector = adaptor.selector();
7058c239909SValentin Clement   auto loc = select.getLoc();
7068c239909SValentin Clement   assert(conds > 0 && "select must have cases");
7078c239909SValentin Clement 
7088c239909SValentin Clement   llvm::SmallVector<mlir::Block *> destinations;
7098c239909SValentin Clement   llvm::SmallVector<mlir::ValueRange> destinationsOperands;
7108c239909SValentin Clement   mlir::Block *defaultDestination;
7118c239909SValentin Clement   mlir::ValueRange defaultOperands;
7128c239909SValentin Clement   llvm::SmallVector<int32_t> caseValues;
7138c239909SValentin Clement 
7148c239909SValentin Clement   for (unsigned t = 0; t != conds; ++t) {
7158c239909SValentin Clement     mlir::Block *dest = select.getSuccessor(t);
7168c239909SValentin Clement     auto destOps = select.getSuccessorOperands(adaptor.getOperands(), t);
7178c239909SValentin Clement     const mlir::Attribute &attr = cases[t];
7188c239909SValentin Clement     if (auto intAttr = attr.template dyn_cast<mlir::IntegerAttr>()) {
7198c239909SValentin Clement       destinations.push_back(dest);
7208c239909SValentin Clement       destinationsOperands.push_back(destOps.hasValue() ? *destOps
7218c239909SValentin Clement                                                         : ValueRange());
7228c239909SValentin Clement       caseValues.push_back(intAttr.getInt());
7238c239909SValentin Clement       continue;
7248c239909SValentin Clement     }
7258c239909SValentin Clement     assert(attr.template dyn_cast_or_null<mlir::UnitAttr>());
7268c239909SValentin Clement     assert((t + 1 == conds) && "unit must be last");
7278c239909SValentin Clement     defaultDestination = dest;
7288c239909SValentin Clement     defaultOperands = destOps.hasValue() ? *destOps : ValueRange();
7298c239909SValentin Clement   }
7308c239909SValentin Clement 
7318c239909SValentin Clement   // LLVM::SwitchOp takes a i32 type for the selector.
7328c239909SValentin Clement   if (select.getSelector().getType() != rewriter.getI32Type())
7338c239909SValentin Clement     selector =
7348c239909SValentin Clement         rewriter.create<LLVM::TruncOp>(loc, rewriter.getI32Type(), selector);
7358c239909SValentin Clement 
7368c239909SValentin Clement   rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>(
7378c239909SValentin Clement       select, selector,
7388c239909SValentin Clement       /*defaultDestination=*/defaultDestination,
7398c239909SValentin Clement       /*defaultOperands=*/defaultOperands,
7408c239909SValentin Clement       /*caseValues=*/caseValues,
7418c239909SValentin Clement       /*caseDestinations=*/destinations,
7428c239909SValentin Clement       /*caseOperands=*/destinationsOperands,
7438c239909SValentin Clement       /*branchWeights=*/ArrayRef<int32_t>());
7448c239909SValentin Clement }
7458c239909SValentin Clement 
7468c239909SValentin Clement /// conversion of fir::SelectOp to an if-then-else ladder
7478c239909SValentin Clement struct SelectOpConversion : public FIROpConversion<fir::SelectOp> {
7488c239909SValentin Clement   using FIROpConversion::FIROpConversion;
7498c239909SValentin Clement 
7508c239909SValentin Clement   mlir::LogicalResult
7518c239909SValentin Clement   matchAndRewrite(fir::SelectOp op, OpAdaptor adaptor,
7528c239909SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
7538c239909SValentin Clement     selectMatchAndRewrite<fir::SelectOp>(lowerTy(), op, adaptor, rewriter);
7548c239909SValentin Clement     return success();
7558c239909SValentin Clement   }
7568c239909SValentin Clement };
7578c239909SValentin Clement 
758e3349fa1SAndrzej Warzynski /// `fir.load` --> `llvm.load`
759e3349fa1SAndrzej Warzynski struct LoadOpConversion : public FIROpConversion<fir::LoadOp> {
760e3349fa1SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
761e3349fa1SAndrzej Warzynski 
762e3349fa1SAndrzej Warzynski   mlir::LogicalResult
763e3349fa1SAndrzej Warzynski   matchAndRewrite(fir::LoadOp load, OpAdaptor adaptor,
764e3349fa1SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
765e3349fa1SAndrzej Warzynski     // fir.box is a special case because it is considered as an ssa values in
766e3349fa1SAndrzej Warzynski     // fir, but it is lowered as a pointer to a descriptor. So fir.ref<fir.box>
767e3349fa1SAndrzej Warzynski     // and fir.box end up being the same llvm types and loading a
768e3349fa1SAndrzej Warzynski     // fir.ref<fir.box> is actually a no op in LLVM.
769e3349fa1SAndrzej Warzynski     if (load.getType().isa<fir::BoxType>()) {
770e3349fa1SAndrzej Warzynski       rewriter.replaceOp(load, adaptor.getOperands()[0]);
771e3349fa1SAndrzej Warzynski     } else {
772e3349fa1SAndrzej Warzynski       mlir::Type ty = convertType(load.getType());
773e3349fa1SAndrzej Warzynski       ArrayRef<NamedAttribute> at = load->getAttrs();
774e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::LoadOp>(
775e3349fa1SAndrzej Warzynski           load, ty, adaptor.getOperands(), at);
776e3349fa1SAndrzej Warzynski     }
777e3349fa1SAndrzej Warzynski     return success();
778e3349fa1SAndrzej Warzynski   }
779e3349fa1SAndrzej Warzynski };
780e3349fa1SAndrzej Warzynski 
7818c239909SValentin Clement /// conversion of fir::SelectRankOp to an if-then-else ladder
7828c239909SValentin Clement struct SelectRankOpConversion : public FIROpConversion<fir::SelectRankOp> {
7838c239909SValentin Clement   using FIROpConversion::FIROpConversion;
7848c239909SValentin Clement 
7858c239909SValentin Clement   mlir::LogicalResult
7868c239909SValentin Clement   matchAndRewrite(fir::SelectRankOp op, OpAdaptor adaptor,
7878c239909SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
7888c239909SValentin Clement     selectMatchAndRewrite<fir::SelectRankOp>(lowerTy(), op, adaptor, rewriter);
7898c239909SValentin Clement     return success();
7908c239909SValentin Clement   }
7918c239909SValentin Clement };
7928c239909SValentin Clement 
793e3349fa1SAndrzej Warzynski /// `fir.store` --> `llvm.store`
794e3349fa1SAndrzej Warzynski struct StoreOpConversion : public FIROpConversion<fir::StoreOp> {
795e3349fa1SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
796e3349fa1SAndrzej Warzynski 
797e3349fa1SAndrzej Warzynski   mlir::LogicalResult
798e3349fa1SAndrzej Warzynski   matchAndRewrite(fir::StoreOp store, OpAdaptor adaptor,
799e3349fa1SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
800e3349fa1SAndrzej Warzynski     if (store.value().getType().isa<fir::BoxType>()) {
801e3349fa1SAndrzej Warzynski       // fir.box value is actually in memory, load it first before storing it.
802e3349fa1SAndrzej Warzynski       mlir::Location loc = store.getLoc();
803e3349fa1SAndrzej Warzynski       mlir::Type boxPtrTy = adaptor.getOperands()[0].getType();
804e3349fa1SAndrzej Warzynski       auto val = rewriter.create<mlir::LLVM::LoadOp>(
805e3349fa1SAndrzej Warzynski           loc, boxPtrTy.cast<mlir::LLVM::LLVMPointerType>().getElementType(),
806e3349fa1SAndrzej Warzynski           adaptor.getOperands()[0]);
807e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
808e3349fa1SAndrzej Warzynski           store, val, adaptor.getOperands()[1]);
809e3349fa1SAndrzej Warzynski     } else {
810e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
811e3349fa1SAndrzej Warzynski           store, adaptor.getOperands()[0], adaptor.getOperands()[1]);
812e3349fa1SAndrzej Warzynski     }
813e3349fa1SAndrzej Warzynski     return success();
814e3349fa1SAndrzej Warzynski   }
815e3349fa1SAndrzej Warzynski };
816e3349fa1SAndrzej Warzynski 
817e3349fa1SAndrzej Warzynski /// convert to LLVM IR dialect `undef`
818044d5b5dSValentin Clement struct UndefOpConversion : public FIROpConversion<fir::UndefOp> {
819044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
820044d5b5dSValentin Clement 
821044d5b5dSValentin Clement   mlir::LogicalResult
822044d5b5dSValentin Clement   matchAndRewrite(fir::UndefOp undef, OpAdaptor,
823044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
824044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::UndefOp>(
825044d5b5dSValentin Clement         undef, convertType(undef.getType()));
826044d5b5dSValentin Clement     return success();
827044d5b5dSValentin Clement   }
828044d5b5dSValentin Clement };
829a7a61359SValentin Clement 
830e3349fa1SAndrzej Warzynski /// `fir.unreachable` --> `llvm.unreachable`
83132e08248SAndrzej Warzynski struct UnreachableOpConversion : public FIROpConversion<fir::UnreachableOp> {
83232e08248SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
83332e08248SAndrzej Warzynski 
83432e08248SAndrzej Warzynski   mlir::LogicalResult
83532e08248SAndrzej Warzynski   matchAndRewrite(fir::UnreachableOp unreach, OpAdaptor adaptor,
83632e08248SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
83732e08248SAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(unreach);
83832e08248SAndrzej Warzynski     return success();
83932e08248SAndrzej Warzynski   }
84032e08248SAndrzej Warzynski };
84132e08248SAndrzej Warzynski 
842a7a61359SValentin Clement struct ZeroOpConversion : public FIROpConversion<fir::ZeroOp> {
843a7a61359SValentin Clement   using FIROpConversion::FIROpConversion;
844a7a61359SValentin Clement 
845a7a61359SValentin Clement   mlir::LogicalResult
846a7a61359SValentin Clement   matchAndRewrite(fir::ZeroOp zero, OpAdaptor,
847a7a61359SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
848a7a61359SValentin Clement     auto ty = convertType(zero.getType());
849a7a61359SValentin Clement     if (ty.isa<mlir::LLVM::LLVMPointerType>()) {
850a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(zero, ty);
851a7a61359SValentin Clement     } else if (ty.isa<mlir::IntegerType>()) {
852a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
853a7a61359SValentin Clement           zero, ty, mlir::IntegerAttr::get(zero.getType(), 0));
854a7a61359SValentin Clement     } else if (mlir::LLVM::isCompatibleFloatingPointType(ty)) {
855a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
856a7a61359SValentin Clement           zero, ty, mlir::FloatAttr::get(zero.getType(), 0.0));
857a7a61359SValentin Clement     } else {
858a7a61359SValentin Clement       // TODO: create ConstantAggregateZero for FIR aggregate/array types.
85952d813edSValentin Clement       return rewriter.notifyMatchFailure(
86052d813edSValentin Clement           zero,
861a7a61359SValentin Clement           "conversion of fir.zero with aggregate type not implemented yet");
862a7a61359SValentin Clement     }
863a7a61359SValentin Clement     return success();
864a7a61359SValentin Clement   }
865a7a61359SValentin Clement };
86632e08248SAndrzej Warzynski 
86754c56347SValentin Clement // Code shared between insert_value and extract_value Ops.
86854c56347SValentin Clement struct ValueOpCommon {
86954c56347SValentin Clement   // Translate the arguments pertaining to any multidimensional array to
87054c56347SValentin Clement   // row-major order for LLVM-IR.
87154c56347SValentin Clement   static void toRowMajor(SmallVectorImpl<mlir::Attribute> &attrs,
87254c56347SValentin Clement                          mlir::Type ty) {
87354c56347SValentin Clement     assert(ty && "type is null");
87454c56347SValentin Clement     const auto end = attrs.size();
87554c56347SValentin Clement     for (std::remove_const_t<decltype(end)> i = 0; i < end; ++i) {
87654c56347SValentin Clement       if (auto seq = ty.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
87754c56347SValentin Clement         const auto dim = getDimension(seq);
87854c56347SValentin Clement         if (dim > 1) {
87954c56347SValentin Clement           auto ub = std::min(i + dim, end);
88054c56347SValentin Clement           std::reverse(attrs.begin() + i, attrs.begin() + ub);
88154c56347SValentin Clement           i += dim - 1;
88254c56347SValentin Clement         }
88354c56347SValentin Clement         ty = getArrayElementType(seq);
88454c56347SValentin Clement       } else if (auto st = ty.dyn_cast<mlir::LLVM::LLVMStructType>()) {
88554c56347SValentin Clement         ty = st.getBody()[attrs[i].cast<mlir::IntegerAttr>().getInt()];
88654c56347SValentin Clement       } else {
88754c56347SValentin Clement         llvm_unreachable("index into invalid type");
88854c56347SValentin Clement       }
88954c56347SValentin Clement     }
89054c56347SValentin Clement   }
89154c56347SValentin Clement 
89254c56347SValentin Clement   static llvm::SmallVector<mlir::Attribute>
89354c56347SValentin Clement   collectIndices(mlir::ConversionPatternRewriter &rewriter,
89454c56347SValentin Clement                  mlir::ArrayAttr arrAttr) {
89554c56347SValentin Clement     llvm::SmallVector<mlir::Attribute> attrs;
89654c56347SValentin Clement     for (auto i = arrAttr.begin(), e = arrAttr.end(); i != e; ++i) {
89754c56347SValentin Clement       if (i->isa<mlir::IntegerAttr>()) {
89854c56347SValentin Clement         attrs.push_back(*i);
89954c56347SValentin Clement       } else {
90054c56347SValentin Clement         auto fieldName = i->cast<mlir::StringAttr>().getValue();
90154c56347SValentin Clement         ++i;
90254c56347SValentin Clement         auto ty = i->cast<mlir::TypeAttr>().getValue();
90354c56347SValentin Clement         auto index = ty.cast<fir::RecordType>().getFieldIndex(fieldName);
90454c56347SValentin Clement         attrs.push_back(mlir::IntegerAttr::get(rewriter.getI32Type(), index));
90554c56347SValentin Clement       }
90654c56347SValentin Clement     }
90754c56347SValentin Clement     return attrs;
90854c56347SValentin Clement   }
90954c56347SValentin Clement 
91054c56347SValentin Clement private:
91154c56347SValentin Clement   static unsigned getDimension(mlir::LLVM::LLVMArrayType ty) {
91254c56347SValentin Clement     unsigned result = 1;
91354c56347SValentin Clement     for (auto eleTy = ty.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>();
91454c56347SValentin Clement          eleTy;
91554c56347SValentin Clement          eleTy = eleTy.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>())
91654c56347SValentin Clement       ++result;
91754c56347SValentin Clement     return result;
91854c56347SValentin Clement   }
91954c56347SValentin Clement 
92054c56347SValentin Clement   static mlir::Type getArrayElementType(mlir::LLVM::LLVMArrayType ty) {
92154c56347SValentin Clement     auto eleTy = ty.getElementType();
92254c56347SValentin Clement     while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>())
92354c56347SValentin Clement       eleTy = arrTy.getElementType();
92454c56347SValentin Clement     return eleTy;
92554c56347SValentin Clement   }
92654c56347SValentin Clement };
92754c56347SValentin Clement 
92854c56347SValentin Clement /// Extract a subobject value from an ssa-value of aggregate type
92954c56347SValentin Clement struct ExtractValueOpConversion
93054c56347SValentin Clement     : public FIROpAndTypeConversion<fir::ExtractValueOp>,
93154c56347SValentin Clement       public ValueOpCommon {
93254c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
93354c56347SValentin Clement 
93454c56347SValentin Clement   mlir::LogicalResult
93554c56347SValentin Clement   doRewrite(fir::ExtractValueOp extractVal, mlir::Type ty, OpAdaptor adaptor,
93654c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
93754c56347SValentin Clement     auto attrs = collectIndices(rewriter, extractVal.coor());
93854c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
93954c56347SValentin Clement     auto position = mlir::ArrayAttr::get(extractVal.getContext(), attrs);
94054c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(
94154c56347SValentin Clement         extractVal, ty, adaptor.getOperands()[0], position);
94254c56347SValentin Clement     return success();
94354c56347SValentin Clement   }
94454c56347SValentin Clement };
94554c56347SValentin Clement 
94654c56347SValentin Clement /// InsertValue is the generalized instruction for the composition of new
94754c56347SValentin Clement /// aggregate type values.
94854c56347SValentin Clement struct InsertValueOpConversion
94954c56347SValentin Clement     : public FIROpAndTypeConversion<fir::InsertValueOp>,
95054c56347SValentin Clement       public ValueOpCommon {
95154c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
95254c56347SValentin Clement 
95354c56347SValentin Clement   mlir::LogicalResult
95454c56347SValentin Clement   doRewrite(fir::InsertValueOp insertVal, mlir::Type ty, OpAdaptor adaptor,
95554c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
95654c56347SValentin Clement     auto attrs = collectIndices(rewriter, insertVal.coor());
95754c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
95854c56347SValentin Clement     auto position = mlir::ArrayAttr::get(insertVal.getContext(), attrs);
95954c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
96054c56347SValentin Clement         insertVal, ty, adaptor.getOperands()[0], adaptor.getOperands()[1],
96154c56347SValentin Clement         position);
96254c56347SValentin Clement     return success();
96354c56347SValentin Clement   }
96454c56347SValentin Clement };
96554c56347SValentin Clement 
9663ae8e442SValentin Clement /// InsertOnRange inserts a value into a sequence over a range of offsets.
9673ae8e442SValentin Clement struct InsertOnRangeOpConversion
9683ae8e442SValentin Clement     : public FIROpAndTypeConversion<fir::InsertOnRangeOp> {
9693ae8e442SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
9703ae8e442SValentin Clement 
9713ae8e442SValentin Clement   // Increments an array of subscripts in a row major fasion.
9723ae8e442SValentin Clement   void incrementSubscripts(const SmallVector<uint64_t> &dims,
9733ae8e442SValentin Clement                            SmallVector<uint64_t> &subscripts) const {
9743ae8e442SValentin Clement     for (size_t i = dims.size(); i > 0; --i) {
9753ae8e442SValentin Clement       if (++subscripts[i - 1] < dims[i - 1]) {
9763ae8e442SValentin Clement         return;
9773ae8e442SValentin Clement       }
9783ae8e442SValentin Clement       subscripts[i - 1] = 0;
9793ae8e442SValentin Clement     }
9803ae8e442SValentin Clement   }
9813ae8e442SValentin Clement 
9823ae8e442SValentin Clement   mlir::LogicalResult
9833ae8e442SValentin Clement   doRewrite(fir::InsertOnRangeOp range, mlir::Type ty, OpAdaptor adaptor,
9843ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
9853ae8e442SValentin Clement 
9863ae8e442SValentin Clement     llvm::SmallVector<uint64_t> dims;
9873ae8e442SValentin Clement     auto type = adaptor.getOperands()[0].getType();
9883ae8e442SValentin Clement 
9893ae8e442SValentin Clement     // Iteratively extract the array dimensions from the type.
9903ae8e442SValentin Clement     while (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
9913ae8e442SValentin Clement       dims.push_back(t.getNumElements());
9923ae8e442SValentin Clement       type = t.getElementType();
9933ae8e442SValentin Clement     }
9943ae8e442SValentin Clement 
9953ae8e442SValentin Clement     SmallVector<uint64_t> lBounds;
9963ae8e442SValentin Clement     SmallVector<uint64_t> uBounds;
9973ae8e442SValentin Clement 
9983ae8e442SValentin Clement     // Extract integer value from the attribute
9993ae8e442SValentin Clement     SmallVector<int64_t> coordinates = llvm::to_vector<4>(
10003ae8e442SValentin Clement         llvm::map_range(range.coor(), [](Attribute a) -> int64_t {
10013ae8e442SValentin Clement           return a.cast<IntegerAttr>().getInt();
10023ae8e442SValentin Clement         }));
10033ae8e442SValentin Clement 
10043ae8e442SValentin Clement     // Unzip the upper and lower bound and convert to a row major format.
10053ae8e442SValentin Clement     for (auto i = coordinates.rbegin(), e = coordinates.rend(); i != e; ++i) {
10063ae8e442SValentin Clement       uBounds.push_back(*i++);
10073ae8e442SValentin Clement       lBounds.push_back(*i);
10083ae8e442SValentin Clement     }
10093ae8e442SValentin Clement 
10103ae8e442SValentin Clement     auto &subscripts = lBounds;
10113ae8e442SValentin Clement     auto loc = range.getLoc();
10123ae8e442SValentin Clement     mlir::Value lastOp = adaptor.getOperands()[0];
10133ae8e442SValentin Clement     mlir::Value insertVal = adaptor.getOperands()[1];
10143ae8e442SValentin Clement 
10153ae8e442SValentin Clement     auto i64Ty = rewriter.getI64Type();
10163ae8e442SValentin Clement     while (subscripts != uBounds) {
10173ae8e442SValentin Clement       // Convert uint64_t's to Attribute's.
10183ae8e442SValentin Clement       SmallVector<mlir::Attribute> subscriptAttrs;
10193ae8e442SValentin Clement       for (const auto &subscript : subscripts)
10203ae8e442SValentin Clement         subscriptAttrs.push_back(IntegerAttr::get(i64Ty, subscript));
10213ae8e442SValentin Clement       lastOp = rewriter.create<mlir::LLVM::InsertValueOp>(
10223ae8e442SValentin Clement           loc, ty, lastOp, insertVal,
10233ae8e442SValentin Clement           ArrayAttr::get(range.getContext(), subscriptAttrs));
10243ae8e442SValentin Clement 
10253ae8e442SValentin Clement       incrementSubscripts(dims, subscripts);
10263ae8e442SValentin Clement     }
10273ae8e442SValentin Clement 
10283ae8e442SValentin Clement     // Convert uint64_t's to Attribute's.
10293ae8e442SValentin Clement     SmallVector<mlir::Attribute> subscriptAttrs;
10303ae8e442SValentin Clement     for (const auto &subscript : subscripts)
10313ae8e442SValentin Clement       subscriptAttrs.push_back(
10323ae8e442SValentin Clement           IntegerAttr::get(rewriter.getI64Type(), subscript));
10333ae8e442SValentin Clement     mlir::ArrayRef<mlir::Attribute> arrayRef(subscriptAttrs);
10343ae8e442SValentin Clement 
10353ae8e442SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
10363ae8e442SValentin Clement         range, ty, lastOp, insertVal,
10373ae8e442SValentin Clement         ArrayAttr::get(range.getContext(), arrayRef));
10383ae8e442SValentin Clement 
10393ae8e442SValentin Clement     return success();
10403ae8e442SValentin Clement   }
10413ae8e442SValentin Clement };
10427b5132daSValentin Clement 
10437b5132daSValentin Clement //
10447b5132daSValentin Clement // Primitive operations on Complex types
10457b5132daSValentin Clement //
10467b5132daSValentin Clement 
10477b5132daSValentin Clement /// Generate inline code for complex addition/subtraction
10487b5132daSValentin Clement template <typename LLVMOP, typename OPTY>
10497b5132daSValentin Clement mlir::LLVM::InsertValueOp complexSum(OPTY sumop, mlir::ValueRange opnds,
10507b5132daSValentin Clement                                      mlir::ConversionPatternRewriter &rewriter,
10517b5132daSValentin Clement                                      fir::LLVMTypeConverter &lowering) {
10527b5132daSValentin Clement   mlir::Value a = opnds[0];
10537b5132daSValentin Clement   mlir::Value b = opnds[1];
10547b5132daSValentin Clement   auto loc = sumop.getLoc();
10557b5132daSValentin Clement   auto ctx = sumop.getContext();
10567b5132daSValentin Clement   auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
10577b5132daSValentin Clement   auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
10587b5132daSValentin Clement   mlir::Type eleTy = lowering.convertType(getComplexEleTy(sumop.getType()));
10597b5132daSValentin Clement   mlir::Type ty = lowering.convertType(sumop.getType());
10607b5132daSValentin Clement   auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
10617b5132daSValentin Clement   auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
10627b5132daSValentin Clement   auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
10637b5132daSValentin Clement   auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
10647b5132daSValentin Clement   auto rx = rewriter.create<LLVMOP>(loc, eleTy, x0, x1);
10657b5132daSValentin Clement   auto ry = rewriter.create<LLVMOP>(loc, eleTy, y0, y1);
10667b5132daSValentin Clement   auto r0 = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
10677b5132daSValentin Clement   auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r0, rx, c0);
10687b5132daSValentin Clement   return rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ry, c1);
10697b5132daSValentin Clement }
10707b5132daSValentin Clement 
10717b5132daSValentin Clement struct AddcOpConversion : public FIROpConversion<fir::AddcOp> {
10727b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
10737b5132daSValentin Clement 
10747b5132daSValentin Clement   mlir::LogicalResult
10757b5132daSValentin Clement   matchAndRewrite(fir::AddcOp addc, OpAdaptor adaptor,
10767b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
10777b5132daSValentin Clement     // given: (x + iy) + (x' + iy')
10787b5132daSValentin Clement     // result: (x + x') + i(y + y')
10797b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FAddOp>(addc, adaptor.getOperands(),
10807b5132daSValentin Clement                                             rewriter, lowerTy());
10817b5132daSValentin Clement     rewriter.replaceOp(addc, r.getResult());
10827b5132daSValentin Clement     return success();
10837b5132daSValentin Clement   }
10847b5132daSValentin Clement };
10857b5132daSValentin Clement 
10867b5132daSValentin Clement struct SubcOpConversion : public FIROpConversion<fir::SubcOp> {
10877b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
10887b5132daSValentin Clement 
10897b5132daSValentin Clement   mlir::LogicalResult
10907b5132daSValentin Clement   matchAndRewrite(fir::SubcOp subc, OpAdaptor adaptor,
10917b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
10927b5132daSValentin Clement     // given: (x + iy) - (x' + iy')
10937b5132daSValentin Clement     // result: (x - x') + i(y - y')
10947b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FSubOp>(subc, adaptor.getOperands(),
10957b5132daSValentin Clement                                             rewriter, lowerTy());
10967b5132daSValentin Clement     rewriter.replaceOp(subc, r.getResult());
10977b5132daSValentin Clement     return success();
10987b5132daSValentin Clement   }
10997b5132daSValentin Clement };
11007b5132daSValentin Clement 
11017b5132daSValentin Clement /// Inlined complex multiply
11027b5132daSValentin Clement struct MulcOpConversion : public FIROpConversion<fir::MulcOp> {
11037b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
11047b5132daSValentin Clement 
11057b5132daSValentin Clement   mlir::LogicalResult
11067b5132daSValentin Clement   matchAndRewrite(fir::MulcOp mulc, OpAdaptor adaptor,
11077b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
11087b5132daSValentin Clement     // TODO: Can we use a call to __muldc3 ?
11097b5132daSValentin Clement     // given: (x + iy) * (x' + iy')
11107b5132daSValentin Clement     // result: (xx'-yy')+i(xy'+yx')
11117b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
11127b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
11137b5132daSValentin Clement     auto loc = mulc.getLoc();
11147b5132daSValentin Clement     auto *ctx = mulc.getContext();
11157b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
11167b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
11177b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(mulc.getType()));
11187b5132daSValentin Clement     mlir::Type ty = convertType(mulc.getType());
11197b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
11207b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
11217b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
11227b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
11237b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
11247b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
11257b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
11267b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xy, yx);
11277b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
11287b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, xx, yy);
11297b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
11307b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
11317b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
11327b5132daSValentin Clement     rewriter.replaceOp(mulc, r0.getResult());
11337b5132daSValentin Clement     return success();
11347b5132daSValentin Clement   }
11357b5132daSValentin Clement };
11367b5132daSValentin Clement 
11377b5132daSValentin Clement /// Inlined complex division
11387b5132daSValentin Clement struct DivcOpConversion : public FIROpConversion<fir::DivcOp> {
11397b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
11407b5132daSValentin Clement 
11417b5132daSValentin Clement   mlir::LogicalResult
11427b5132daSValentin Clement   matchAndRewrite(fir::DivcOp divc, OpAdaptor adaptor,
11437b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
11447b5132daSValentin Clement     // TODO: Can we use a call to __divdc3 instead?
11457b5132daSValentin Clement     // Just generate inline code for now.
11467b5132daSValentin Clement     // given: (x + iy) / (x' + iy')
11477b5132daSValentin Clement     // result: ((xx'+yy')/d) + i((yx'-xy')/d) where d = x'x' + y'y'
11487b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
11497b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
11507b5132daSValentin Clement     auto loc = divc.getLoc();
11517b5132daSValentin Clement     auto *ctx = divc.getContext();
11527b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
11537b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
11547b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(divc.getType()));
11557b5132daSValentin Clement     mlir::Type ty = convertType(divc.getType());
11567b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
11577b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
11587b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
11597b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
11607b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
11617b5132daSValentin Clement     auto x1x1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x1, x1);
11627b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
11637b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
11647b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
11657b5132daSValentin Clement     auto y1y1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y1, y1);
11667b5132daSValentin Clement     auto d = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, x1x1, y1y1);
11677b5132daSValentin Clement     auto rrn = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xx, yy);
11687b5132daSValentin Clement     auto rin = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, yx, xy);
11697b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rrn, d);
11707b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rin, d);
11717b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
11727b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
11737b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
11747b5132daSValentin Clement     rewriter.replaceOp(divc, r0.getResult());
11757b5132daSValentin Clement     return success();
11767b5132daSValentin Clement   }
11777b5132daSValentin Clement };
11787b5132daSValentin Clement 
11797b5132daSValentin Clement /// Inlined complex negation
11807b5132daSValentin Clement struct NegcOpConversion : public FIROpConversion<fir::NegcOp> {
11817b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
11827b5132daSValentin Clement 
11837b5132daSValentin Clement   mlir::LogicalResult
11847b5132daSValentin Clement   matchAndRewrite(fir::NegcOp neg, OpAdaptor adaptor,
11857b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
11867b5132daSValentin Clement     // given: -(x + iy)
11877b5132daSValentin Clement     // result: -x - iy
11887b5132daSValentin Clement     auto *ctxt = neg.getContext();
11897b5132daSValentin Clement     auto eleTy = convertType(getComplexEleTy(neg.getType()));
11907b5132daSValentin Clement     auto ty = convertType(neg.getType());
11917b5132daSValentin Clement     auto loc = neg.getLoc();
11927b5132daSValentin Clement     mlir::Value o0 = adaptor.getOperands()[0];
11937b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0));
11947b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1));
11957b5132daSValentin Clement     auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c0);
11967b5132daSValentin Clement     auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c1);
11977b5132daSValentin Clement     auto nrp = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, rp);
11987b5132daSValentin Clement     auto nip = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, ip);
11997b5132daSValentin Clement     auto r = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, o0, nrp, c0);
12007b5132daSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(neg, ty, r, nip, c1);
12017b5132daSValentin Clement     return success();
12027b5132daSValentin Clement   }
12037b5132daSValentin Clement };
12047b5132daSValentin Clement 
1205044d5b5dSValentin Clement } // namespace
1206044d5b5dSValentin Clement 
1207044d5b5dSValentin Clement namespace {
1208044d5b5dSValentin Clement /// Convert FIR dialect to LLVM dialect
1209044d5b5dSValentin Clement ///
1210044d5b5dSValentin Clement /// This pass lowers all FIR dialect operations to LLVM IR dialect. An
1211044d5b5dSValentin Clement /// MLIR pass is used to lower residual Std dialect to LLVM IR dialect.
1212044d5b5dSValentin Clement ///
1213044d5b5dSValentin Clement /// This pass is not complete yet. We are upstreaming it in small patches.
1214044d5b5dSValentin Clement class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> {
1215044d5b5dSValentin Clement public:
1216044d5b5dSValentin Clement   mlir::ModuleOp getModule() { return getOperation(); }
1217044d5b5dSValentin Clement 
1218044d5b5dSValentin Clement   void runOnOperation() override final {
12197b5132daSValentin Clement     auto mod = getModule();
12207b5132daSValentin Clement     if (!forcedTargetTriple.empty()) {
12217b5132daSValentin Clement       fir::setTargetTriple(mod, forcedTargetTriple);
12227b5132daSValentin Clement     }
12237b5132daSValentin Clement 
1224044d5b5dSValentin Clement     auto *context = getModule().getContext();
1225044d5b5dSValentin Clement     fir::LLVMTypeConverter typeConverter{getModule()};
1226044d5b5dSValentin Clement     mlir::OwningRewritePatternList pattern(context);
1227df3b9810SValentin Clement     pattern.insert<
12281e6d9c06SDiana Picus         AddcOpConversion, AddrOfOpConversion, AllocaOpConversion,
12291e6d9c06SDiana Picus         BoxAddrOpConversion, BoxDimsOpConversion, BoxEleSizeOpConversion,
12301e6d9c06SDiana Picus         BoxIsAllocOpConversion, BoxIsArrayOpConversion, BoxIsPtrOpConversion,
12311e6d9c06SDiana Picus         BoxRankOpConversion, CallOpConversion, ConvertOpConversion,
1232*9534e361SValentin Clement         DispatchOpConversion, DispatchTableOpConversion, DTEntryOpConversion,
12331e6d9c06SDiana Picus         DivcOpConversion, ExtractValueOpConversion, HasValueOpConversion,
12341e6d9c06SDiana Picus         GlobalOpConversion, InsertOnRangeOpConversion, InsertValueOpConversion,
12351e6d9c06SDiana Picus         LoadOpConversion, NegcOpConversion, MulcOpConversion,
12361e6d9c06SDiana Picus         SelectOpConversion, SelectRankOpConversion, StoreOpConversion,
12371e6d9c06SDiana Picus         SubcOpConversion, UndefOpConversion, UnreachableOpConversion,
12381e6d9c06SDiana Picus         ZeroOpConversion>(typeConverter);
1239044d5b5dSValentin Clement     mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern);
1240044d5b5dSValentin Clement     mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter,
1241044d5b5dSValentin Clement                                                             pattern);
1242044d5b5dSValentin Clement     mlir::ConversionTarget target{*context};
1243044d5b5dSValentin Clement     target.addLegalDialect<mlir::LLVM::LLVMDialect>();
1244044d5b5dSValentin Clement 
1245044d5b5dSValentin Clement     // required NOPs for applying a full conversion
1246044d5b5dSValentin Clement     target.addLegalOp<mlir::ModuleOp>();
1247044d5b5dSValentin Clement 
1248044d5b5dSValentin Clement     // apply the patterns
1249044d5b5dSValentin Clement     if (mlir::failed(mlir::applyFullConversion(getModule(), target,
1250044d5b5dSValentin Clement                                                std::move(pattern)))) {
1251044d5b5dSValentin Clement       signalPassFailure();
1252044d5b5dSValentin Clement     }
1253044d5b5dSValentin Clement   }
1254044d5b5dSValentin Clement };
1255044d5b5dSValentin Clement } // namespace
1256044d5b5dSValentin Clement 
1257044d5b5dSValentin Clement std::unique_ptr<mlir::Pass> fir::createFIRToLLVMPass() {
1258044d5b5dSValentin Clement   return std::make_unique<FIRToLLVMLowering>();
1259044d5b5dSValentin Clement }
1260