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 
35*1e6d9c06SDiana Picus static mlir::LLVM::ConstantOp
36*1e6d9c06SDiana Picus genConstantIndex(mlir::Location loc, mlir::Type ity,
37*1e6d9c06SDiana Picus                  mlir::ConversionPatternRewriter &rewriter,
38*1e6d9c06SDiana Picus                  std::int64_t offset) {
39*1e6d9c06SDiana Picus   auto cattr = rewriter.getI64IntegerAttr(offset);
40*1e6d9c06SDiana Picus   return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr);
41*1e6d9c06SDiana Picus }
42*1e6d9c06SDiana 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 
156*1e6d9c06SDiana Picus   /// Perform an extension or truncation as needed on an integer value. Lowering
157*1e6d9c06SDiana Picus   /// to the specific target may involve some sign-extending or truncation of
158*1e6d9c06SDiana Picus   /// values, particularly to fit them from abstract box types to the
159*1e6d9c06SDiana Picus   /// appropriate reified structures.
160*1e6d9c06SDiana Picus   mlir::Value integerCast(mlir::Location loc,
161*1e6d9c06SDiana Picus                           mlir::ConversionPatternRewriter &rewriter,
162*1e6d9c06SDiana Picus                           mlir::Type ty, mlir::Value val) const {
163*1e6d9c06SDiana Picus     auto valTy = val.getType();
164*1e6d9c06SDiana Picus     // If the value was not yet lowered, lower its type so that it can
165*1e6d9c06SDiana Picus     // be used in getPrimitiveTypeSizeInBits.
166*1e6d9c06SDiana Picus     if (!valTy.isa<mlir::IntegerType>())
167*1e6d9c06SDiana Picus       valTy = convertType(valTy);
168*1e6d9c06SDiana Picus     auto toSize = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
169*1e6d9c06SDiana Picus     auto fromSize = mlir::LLVM::getPrimitiveTypeSizeInBits(valTy);
170*1e6d9c06SDiana Picus     if (toSize < fromSize)
171*1e6d9c06SDiana Picus       return rewriter.create<mlir::LLVM::TruncOp>(loc, ty, val);
172*1e6d9c06SDiana Picus     if (toSize > fromSize)
173*1e6d9c06SDiana Picus       return rewriter.create<mlir::LLVM::SExtOp>(loc, ty, val);
174*1e6d9c06SDiana Picus     return val;
175*1e6d9c06SDiana Picus   }
176*1e6d9c06SDiana 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 };
214*1e6d9c06SDiana Picus } // namespace
215*1e6d9c06SDiana Picus 
216*1e6d9c06SDiana Picus /// Lookup the function to compute the memory size of this parametric derived
217*1e6d9c06SDiana Picus /// type. The size of the object may depend on the LEN type parameters of the
218*1e6d9c06SDiana Picus /// derived type.
219*1e6d9c06SDiana Picus static mlir::LLVM::LLVMFuncOp
220*1e6d9c06SDiana Picus getDependentTypeMemSizeFn(fir::RecordType recTy, fir::AllocaOp op,
221*1e6d9c06SDiana Picus                           mlir::ConversionPatternRewriter &rewriter) {
222*1e6d9c06SDiana Picus   auto module = op->getParentOfType<mlir::ModuleOp>();
223*1e6d9c06SDiana Picus   std::string name = recTy.getName().str() + "P.mem.size";
224*1e6d9c06SDiana Picus   return module.lookupSymbol<mlir::LLVM::LLVMFuncOp>(name);
225*1e6d9c06SDiana Picus }
226*1e6d9c06SDiana Picus 
227*1e6d9c06SDiana Picus namespace {
228*1e6d9c06SDiana Picus /// convert to LLVM IR dialect `alloca`
229*1e6d9c06SDiana Picus struct AllocaOpConversion : public FIROpConversion<fir::AllocaOp> {
230*1e6d9c06SDiana Picus   using FIROpConversion::FIROpConversion;
231*1e6d9c06SDiana Picus 
232*1e6d9c06SDiana Picus   mlir::LogicalResult
233*1e6d9c06SDiana Picus   matchAndRewrite(fir::AllocaOp alloc, OpAdaptor adaptor,
234*1e6d9c06SDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
235*1e6d9c06SDiana Picus     mlir::ValueRange operands = adaptor.getOperands();
236*1e6d9c06SDiana Picus     auto loc = alloc.getLoc();
237*1e6d9c06SDiana Picus     mlir::Type ity = lowerTy().indexType();
238*1e6d9c06SDiana Picus     unsigned i = 0;
239*1e6d9c06SDiana Picus     mlir::Value size = genConstantIndex(loc, ity, rewriter, 1).getResult();
240*1e6d9c06SDiana Picus     mlir::Type ty = convertType(alloc.getType());
241*1e6d9c06SDiana Picus     mlir::Type resultTy = ty;
242*1e6d9c06SDiana Picus     if (alloc.hasLenParams()) {
243*1e6d9c06SDiana Picus       unsigned end = alloc.numLenParams();
244*1e6d9c06SDiana Picus       llvm::SmallVector<mlir::Value> lenParams;
245*1e6d9c06SDiana Picus       for (; i < end; ++i)
246*1e6d9c06SDiana Picus         lenParams.push_back(operands[i]);
247*1e6d9c06SDiana Picus       mlir::Type scalarType = fir::unwrapSequenceType(alloc.getInType());
248*1e6d9c06SDiana Picus       if (auto chrTy = scalarType.dyn_cast<fir::CharacterType>()) {
249*1e6d9c06SDiana Picus         fir::CharacterType rawCharTy = fir::CharacterType::getUnknownLen(
250*1e6d9c06SDiana Picus             chrTy.getContext(), chrTy.getFKind());
251*1e6d9c06SDiana Picus         ty = mlir::LLVM::LLVMPointerType::get(convertType(rawCharTy));
252*1e6d9c06SDiana Picus         assert(end == 1);
253*1e6d9c06SDiana Picus         size = integerCast(loc, rewriter, ity, lenParams[0]);
254*1e6d9c06SDiana Picus       } else if (auto recTy = scalarType.dyn_cast<fir::RecordType>()) {
255*1e6d9c06SDiana Picus         mlir::LLVM::LLVMFuncOp memSizeFn =
256*1e6d9c06SDiana Picus             getDependentTypeMemSizeFn(recTy, alloc, rewriter);
257*1e6d9c06SDiana Picus         if (!memSizeFn)
258*1e6d9c06SDiana Picus           emitError(loc, "did not find allocation function");
259*1e6d9c06SDiana Picus         mlir::NamedAttribute attr = rewriter.getNamedAttr(
260*1e6d9c06SDiana Picus             "callee", mlir::SymbolRefAttr::get(memSizeFn));
261*1e6d9c06SDiana Picus         auto call = rewriter.create<mlir::LLVM::CallOp>(
262*1e6d9c06SDiana Picus             loc, ity, lenParams, llvm::ArrayRef<mlir::NamedAttribute>{attr});
263*1e6d9c06SDiana Picus         size = call.getResult(0);
264*1e6d9c06SDiana Picus         ty = mlir::LLVM::LLVMPointerType::get(
265*1e6d9c06SDiana Picus             mlir::IntegerType::get(alloc.getContext(), 8));
266*1e6d9c06SDiana Picus       } else {
267*1e6d9c06SDiana Picus         return emitError(loc, "unexpected type ")
268*1e6d9c06SDiana Picus                << scalarType << " with type parameters";
269*1e6d9c06SDiana Picus       }
270*1e6d9c06SDiana Picus     }
271*1e6d9c06SDiana Picus     if (alloc.hasShapeOperands()) {
272*1e6d9c06SDiana Picus       mlir::Type allocEleTy = fir::unwrapRefType(alloc.getType());
273*1e6d9c06SDiana Picus       // Scale the size by constant factors encoded in the array type.
274*1e6d9c06SDiana Picus       if (auto seqTy = allocEleTy.dyn_cast<fir::SequenceType>()) {
275*1e6d9c06SDiana Picus         fir::SequenceType::Extent constSize = 1;
276*1e6d9c06SDiana Picus         for (auto extent : seqTy.getShape())
277*1e6d9c06SDiana Picus           if (extent != fir::SequenceType::getUnknownExtent())
278*1e6d9c06SDiana Picus             constSize *= extent;
279*1e6d9c06SDiana Picus         mlir::Value constVal{
280*1e6d9c06SDiana Picus             genConstantIndex(loc, ity, rewriter, constSize).getResult()};
281*1e6d9c06SDiana Picus         size = rewriter.create<mlir::LLVM::MulOp>(loc, ity, size, constVal);
282*1e6d9c06SDiana Picus       }
283*1e6d9c06SDiana Picus       unsigned end = operands.size();
284*1e6d9c06SDiana Picus       for (; i < end; ++i)
285*1e6d9c06SDiana Picus         size = rewriter.create<mlir::LLVM::MulOp>(
286*1e6d9c06SDiana Picus             loc, ity, size, integerCast(loc, rewriter, ity, operands[i]));
287*1e6d9c06SDiana Picus     }
288*1e6d9c06SDiana Picus     if (ty == resultTy) {
289*1e6d9c06SDiana Picus       // Do not emit the bitcast if ty and resultTy are the same.
290*1e6d9c06SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::AllocaOp>(alloc, ty, size,
291*1e6d9c06SDiana Picus                                                         alloc->getAttrs());
292*1e6d9c06SDiana Picus     } else {
293*1e6d9c06SDiana Picus       auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, ty, size,
294*1e6d9c06SDiana Picus                                                       alloc->getAttrs());
295*1e6d9c06SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(alloc, resultTy, al);
296*1e6d9c06SDiana Picus     }
297*1e6d9c06SDiana Picus     return success();
298*1e6d9c06SDiana Picus   }
299*1e6d9c06SDiana 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 
5630c4a7a52SValentin Clement /// Lower `fir.has_value` operation to `llvm.return` operation.
564044d5b5dSValentin Clement struct HasValueOpConversion : public FIROpConversion<fir::HasValueOp> {
565044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
566044d5b5dSValentin Clement 
567044d5b5dSValentin Clement   mlir::LogicalResult
568044d5b5dSValentin Clement   matchAndRewrite(fir::HasValueOp op, OpAdaptor adaptor,
569044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
570044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, adaptor.getOperands());
571044d5b5dSValentin Clement     return success();
572044d5b5dSValentin Clement   }
573044d5b5dSValentin Clement };
574044d5b5dSValentin Clement 
5750c4a7a52SValentin Clement /// Lower `fir.global` operation to `llvm.global` operation.
5760c4a7a52SValentin Clement /// `fir.insert_on_range` operations are replaced with constant dense attribute
5770c4a7a52SValentin Clement /// if they are applied on the full range.
578044d5b5dSValentin Clement struct GlobalOpConversion : public FIROpConversion<fir::GlobalOp> {
579044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
580044d5b5dSValentin Clement 
581044d5b5dSValentin Clement   mlir::LogicalResult
582044d5b5dSValentin Clement   matchAndRewrite(fir::GlobalOp global, OpAdaptor adaptor,
583044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
584044d5b5dSValentin Clement     auto tyAttr = convertType(global.getType());
585044d5b5dSValentin Clement     if (global.getType().isa<fir::BoxType>())
586044d5b5dSValentin Clement       tyAttr = tyAttr.cast<mlir::LLVM::LLVMPointerType>().getElementType();
587044d5b5dSValentin Clement     auto loc = global.getLoc();
588044d5b5dSValentin Clement     mlir::Attribute initAttr{};
589044d5b5dSValentin Clement     if (global.initVal())
590044d5b5dSValentin Clement       initAttr = global.initVal().getValue();
591044d5b5dSValentin Clement     auto linkage = convertLinkage(global.linkName());
592044d5b5dSValentin Clement     auto isConst = global.constant().hasValue();
593044d5b5dSValentin Clement     auto g = rewriter.create<mlir::LLVM::GlobalOp>(
594044d5b5dSValentin Clement         loc, tyAttr, isConst, linkage, global.sym_name(), initAttr);
595044d5b5dSValentin Clement     auto &gr = g.getInitializerRegion();
596044d5b5dSValentin Clement     rewriter.inlineRegionBefore(global.region(), gr, gr.end());
597044d5b5dSValentin Clement     if (!gr.empty()) {
598044d5b5dSValentin Clement       // Replace insert_on_range with a constant dense attribute if the
599044d5b5dSValentin Clement       // initialization is on the full range.
600044d5b5dSValentin Clement       auto insertOnRangeOps = gr.front().getOps<fir::InsertOnRangeOp>();
601044d5b5dSValentin Clement       for (auto insertOp : insertOnRangeOps) {
602044d5b5dSValentin Clement         if (isFullRange(insertOp.coor(), insertOp.getType())) {
603044d5b5dSValentin Clement           auto seqTyAttr = convertType(insertOp.getType());
604044d5b5dSValentin Clement           auto *op = insertOp.val().getDefiningOp();
605044d5b5dSValentin Clement           auto constant = mlir::dyn_cast<mlir::arith::ConstantOp>(op);
606044d5b5dSValentin Clement           if (!constant) {
607044d5b5dSValentin Clement             auto convertOp = mlir::dyn_cast<fir::ConvertOp>(op);
608044d5b5dSValentin Clement             if (!convertOp)
609044d5b5dSValentin Clement               continue;
610044d5b5dSValentin Clement             constant = cast<mlir::arith::ConstantOp>(
611044d5b5dSValentin Clement                 convertOp.value().getDefiningOp());
612044d5b5dSValentin Clement           }
613044d5b5dSValentin Clement           mlir::Type vecType = mlir::VectorType::get(
614044d5b5dSValentin Clement               insertOp.getType().getShape(), constant.getType());
615044d5b5dSValentin Clement           auto denseAttr = mlir::DenseElementsAttr::get(
616044d5b5dSValentin Clement               vecType.cast<ShapedType>(), constant.value());
617044d5b5dSValentin Clement           rewriter.setInsertionPointAfter(insertOp);
618044d5b5dSValentin Clement           rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(
619044d5b5dSValentin Clement               insertOp, seqTyAttr, denseAttr);
620044d5b5dSValentin Clement         }
621044d5b5dSValentin Clement       }
622044d5b5dSValentin Clement     }
623044d5b5dSValentin Clement     rewriter.eraseOp(global);
624044d5b5dSValentin Clement     return success();
625044d5b5dSValentin Clement   }
626044d5b5dSValentin Clement 
627044d5b5dSValentin Clement   bool isFullRange(mlir::ArrayAttr indexes, fir::SequenceType seqTy) const {
628044d5b5dSValentin Clement     auto extents = seqTy.getShape();
629044d5b5dSValentin Clement     if (indexes.size() / 2 != extents.size())
630044d5b5dSValentin Clement       return false;
631044d5b5dSValentin Clement     for (unsigned i = 0; i < indexes.size(); i += 2) {
632044d5b5dSValentin Clement       if (indexes[i].cast<IntegerAttr>().getInt() != 0)
633044d5b5dSValentin Clement         return false;
634044d5b5dSValentin Clement       if (indexes[i + 1].cast<IntegerAttr>().getInt() != extents[i / 2] - 1)
635044d5b5dSValentin Clement         return false;
636044d5b5dSValentin Clement     }
637044d5b5dSValentin Clement     return true;
638044d5b5dSValentin Clement   }
639044d5b5dSValentin Clement 
6400c4a7a52SValentin Clement   // TODO: String comparaison should be avoided. Replace linkName with an
6410c4a7a52SValentin Clement   // enumeration.
642044d5b5dSValentin Clement   mlir::LLVM::Linkage convertLinkage(Optional<StringRef> optLinkage) const {
643044d5b5dSValentin Clement     if (optLinkage.hasValue()) {
644044d5b5dSValentin Clement       auto name = optLinkage.getValue();
645044d5b5dSValentin Clement       if (name == "internal")
646044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Internal;
647044d5b5dSValentin Clement       if (name == "linkonce")
648044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Linkonce;
649044d5b5dSValentin Clement       if (name == "common")
650044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Common;
651044d5b5dSValentin Clement       if (name == "weak")
652044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Weak;
653044d5b5dSValentin Clement     }
654044d5b5dSValentin Clement     return mlir::LLVM::Linkage::External;
655044d5b5dSValentin Clement   }
656044d5b5dSValentin Clement };
657044d5b5dSValentin Clement 
6588c239909SValentin Clement template <typename OP>
6598c239909SValentin Clement void selectMatchAndRewrite(fir::LLVMTypeConverter &lowering, OP select,
6608c239909SValentin Clement                            typename OP::Adaptor adaptor,
6618c239909SValentin Clement                            mlir::ConversionPatternRewriter &rewriter) {
6628c239909SValentin Clement   unsigned conds = select.getNumConditions();
6638c239909SValentin Clement   auto cases = select.getCases().getValue();
6648c239909SValentin Clement   mlir::Value selector = adaptor.selector();
6658c239909SValentin Clement   auto loc = select.getLoc();
6668c239909SValentin Clement   assert(conds > 0 && "select must have cases");
6678c239909SValentin Clement 
6688c239909SValentin Clement   llvm::SmallVector<mlir::Block *> destinations;
6698c239909SValentin Clement   llvm::SmallVector<mlir::ValueRange> destinationsOperands;
6708c239909SValentin Clement   mlir::Block *defaultDestination;
6718c239909SValentin Clement   mlir::ValueRange defaultOperands;
6728c239909SValentin Clement   llvm::SmallVector<int32_t> caseValues;
6738c239909SValentin Clement 
6748c239909SValentin Clement   for (unsigned t = 0; t != conds; ++t) {
6758c239909SValentin Clement     mlir::Block *dest = select.getSuccessor(t);
6768c239909SValentin Clement     auto destOps = select.getSuccessorOperands(adaptor.getOperands(), t);
6778c239909SValentin Clement     const mlir::Attribute &attr = cases[t];
6788c239909SValentin Clement     if (auto intAttr = attr.template dyn_cast<mlir::IntegerAttr>()) {
6798c239909SValentin Clement       destinations.push_back(dest);
6808c239909SValentin Clement       destinationsOperands.push_back(destOps.hasValue() ? *destOps
6818c239909SValentin Clement                                                         : ValueRange());
6828c239909SValentin Clement       caseValues.push_back(intAttr.getInt());
6838c239909SValentin Clement       continue;
6848c239909SValentin Clement     }
6858c239909SValentin Clement     assert(attr.template dyn_cast_or_null<mlir::UnitAttr>());
6868c239909SValentin Clement     assert((t + 1 == conds) && "unit must be last");
6878c239909SValentin Clement     defaultDestination = dest;
6888c239909SValentin Clement     defaultOperands = destOps.hasValue() ? *destOps : ValueRange();
6898c239909SValentin Clement   }
6908c239909SValentin Clement 
6918c239909SValentin Clement   // LLVM::SwitchOp takes a i32 type for the selector.
6928c239909SValentin Clement   if (select.getSelector().getType() != rewriter.getI32Type())
6938c239909SValentin Clement     selector =
6948c239909SValentin Clement         rewriter.create<LLVM::TruncOp>(loc, rewriter.getI32Type(), selector);
6958c239909SValentin Clement 
6968c239909SValentin Clement   rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>(
6978c239909SValentin Clement       select, selector,
6988c239909SValentin Clement       /*defaultDestination=*/defaultDestination,
6998c239909SValentin Clement       /*defaultOperands=*/defaultOperands,
7008c239909SValentin Clement       /*caseValues=*/caseValues,
7018c239909SValentin Clement       /*caseDestinations=*/destinations,
7028c239909SValentin Clement       /*caseOperands=*/destinationsOperands,
7038c239909SValentin Clement       /*branchWeights=*/ArrayRef<int32_t>());
7048c239909SValentin Clement }
7058c239909SValentin Clement 
7068c239909SValentin Clement /// conversion of fir::SelectOp to an if-then-else ladder
7078c239909SValentin Clement struct SelectOpConversion : public FIROpConversion<fir::SelectOp> {
7088c239909SValentin Clement   using FIROpConversion::FIROpConversion;
7098c239909SValentin Clement 
7108c239909SValentin Clement   mlir::LogicalResult
7118c239909SValentin Clement   matchAndRewrite(fir::SelectOp op, OpAdaptor adaptor,
7128c239909SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
7138c239909SValentin Clement     selectMatchAndRewrite<fir::SelectOp>(lowerTy(), op, adaptor, rewriter);
7148c239909SValentin Clement     return success();
7158c239909SValentin Clement   }
7168c239909SValentin Clement };
7178c239909SValentin Clement 
718e3349fa1SAndrzej Warzynski /// `fir.load` --> `llvm.load`
719e3349fa1SAndrzej Warzynski struct LoadOpConversion : public FIROpConversion<fir::LoadOp> {
720e3349fa1SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
721e3349fa1SAndrzej Warzynski 
722e3349fa1SAndrzej Warzynski   mlir::LogicalResult
723e3349fa1SAndrzej Warzynski   matchAndRewrite(fir::LoadOp load, OpAdaptor adaptor,
724e3349fa1SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
725e3349fa1SAndrzej Warzynski     // fir.box is a special case because it is considered as an ssa values in
726e3349fa1SAndrzej Warzynski     // fir, but it is lowered as a pointer to a descriptor. So fir.ref<fir.box>
727e3349fa1SAndrzej Warzynski     // and fir.box end up being the same llvm types and loading a
728e3349fa1SAndrzej Warzynski     // fir.ref<fir.box> is actually a no op in LLVM.
729e3349fa1SAndrzej Warzynski     if (load.getType().isa<fir::BoxType>()) {
730e3349fa1SAndrzej Warzynski       rewriter.replaceOp(load, adaptor.getOperands()[0]);
731e3349fa1SAndrzej Warzynski     } else {
732e3349fa1SAndrzej Warzynski       mlir::Type ty = convertType(load.getType());
733e3349fa1SAndrzej Warzynski       ArrayRef<NamedAttribute> at = load->getAttrs();
734e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::LoadOp>(
735e3349fa1SAndrzej Warzynski           load, ty, adaptor.getOperands(), at);
736e3349fa1SAndrzej Warzynski     }
737e3349fa1SAndrzej Warzynski     return success();
738e3349fa1SAndrzej Warzynski   }
739e3349fa1SAndrzej Warzynski };
740e3349fa1SAndrzej Warzynski 
7418c239909SValentin Clement /// conversion of fir::SelectRankOp to an if-then-else ladder
7428c239909SValentin Clement struct SelectRankOpConversion : public FIROpConversion<fir::SelectRankOp> {
7438c239909SValentin Clement   using FIROpConversion::FIROpConversion;
7448c239909SValentin Clement 
7458c239909SValentin Clement   mlir::LogicalResult
7468c239909SValentin Clement   matchAndRewrite(fir::SelectRankOp op, OpAdaptor adaptor,
7478c239909SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
7488c239909SValentin Clement     selectMatchAndRewrite<fir::SelectRankOp>(lowerTy(), op, adaptor, rewriter);
7498c239909SValentin Clement     return success();
7508c239909SValentin Clement   }
7518c239909SValentin Clement };
7528c239909SValentin Clement 
753e3349fa1SAndrzej Warzynski /// `fir.store` --> `llvm.store`
754e3349fa1SAndrzej Warzynski struct StoreOpConversion : public FIROpConversion<fir::StoreOp> {
755e3349fa1SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
756e3349fa1SAndrzej Warzynski 
757e3349fa1SAndrzej Warzynski   mlir::LogicalResult
758e3349fa1SAndrzej Warzynski   matchAndRewrite(fir::StoreOp store, OpAdaptor adaptor,
759e3349fa1SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
760e3349fa1SAndrzej Warzynski     if (store.value().getType().isa<fir::BoxType>()) {
761e3349fa1SAndrzej Warzynski       // fir.box value is actually in memory, load it first before storing it.
762e3349fa1SAndrzej Warzynski       mlir::Location loc = store.getLoc();
763e3349fa1SAndrzej Warzynski       mlir::Type boxPtrTy = adaptor.getOperands()[0].getType();
764e3349fa1SAndrzej Warzynski       auto val = rewriter.create<mlir::LLVM::LoadOp>(
765e3349fa1SAndrzej Warzynski           loc, boxPtrTy.cast<mlir::LLVM::LLVMPointerType>().getElementType(),
766e3349fa1SAndrzej Warzynski           adaptor.getOperands()[0]);
767e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
768e3349fa1SAndrzej Warzynski           store, val, adaptor.getOperands()[1]);
769e3349fa1SAndrzej Warzynski     } else {
770e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
771e3349fa1SAndrzej Warzynski           store, adaptor.getOperands()[0], adaptor.getOperands()[1]);
772e3349fa1SAndrzej Warzynski     }
773e3349fa1SAndrzej Warzynski     return success();
774e3349fa1SAndrzej Warzynski   }
775e3349fa1SAndrzej Warzynski };
776e3349fa1SAndrzej Warzynski 
777e3349fa1SAndrzej Warzynski /// convert to LLVM IR dialect `undef`
778044d5b5dSValentin Clement struct UndefOpConversion : public FIROpConversion<fir::UndefOp> {
779044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
780044d5b5dSValentin Clement 
781044d5b5dSValentin Clement   mlir::LogicalResult
782044d5b5dSValentin Clement   matchAndRewrite(fir::UndefOp undef, OpAdaptor,
783044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
784044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::UndefOp>(
785044d5b5dSValentin Clement         undef, convertType(undef.getType()));
786044d5b5dSValentin Clement     return success();
787044d5b5dSValentin Clement   }
788044d5b5dSValentin Clement };
789a7a61359SValentin Clement 
790e3349fa1SAndrzej Warzynski /// `fir.unreachable` --> `llvm.unreachable`
79132e08248SAndrzej Warzynski struct UnreachableOpConversion : public FIROpConversion<fir::UnreachableOp> {
79232e08248SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
79332e08248SAndrzej Warzynski 
79432e08248SAndrzej Warzynski   mlir::LogicalResult
79532e08248SAndrzej Warzynski   matchAndRewrite(fir::UnreachableOp unreach, OpAdaptor adaptor,
79632e08248SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
79732e08248SAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(unreach);
79832e08248SAndrzej Warzynski     return success();
79932e08248SAndrzej Warzynski   }
80032e08248SAndrzej Warzynski };
80132e08248SAndrzej Warzynski 
802a7a61359SValentin Clement struct ZeroOpConversion : public FIROpConversion<fir::ZeroOp> {
803a7a61359SValentin Clement   using FIROpConversion::FIROpConversion;
804a7a61359SValentin Clement 
805a7a61359SValentin Clement   mlir::LogicalResult
806a7a61359SValentin Clement   matchAndRewrite(fir::ZeroOp zero, OpAdaptor,
807a7a61359SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
808a7a61359SValentin Clement     auto ty = convertType(zero.getType());
809a7a61359SValentin Clement     if (ty.isa<mlir::LLVM::LLVMPointerType>()) {
810a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(zero, ty);
811a7a61359SValentin Clement     } else if (ty.isa<mlir::IntegerType>()) {
812a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
813a7a61359SValentin Clement           zero, ty, mlir::IntegerAttr::get(zero.getType(), 0));
814a7a61359SValentin Clement     } else if (mlir::LLVM::isCompatibleFloatingPointType(ty)) {
815a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
816a7a61359SValentin Clement           zero, ty, mlir::FloatAttr::get(zero.getType(), 0.0));
817a7a61359SValentin Clement     } else {
818a7a61359SValentin Clement       // TODO: create ConstantAggregateZero for FIR aggregate/array types.
81952d813edSValentin Clement       return rewriter.notifyMatchFailure(
82052d813edSValentin Clement           zero,
821a7a61359SValentin Clement           "conversion of fir.zero with aggregate type not implemented yet");
822a7a61359SValentin Clement     }
823a7a61359SValentin Clement     return success();
824a7a61359SValentin Clement   }
825a7a61359SValentin Clement };
82632e08248SAndrzej Warzynski 
82754c56347SValentin Clement // Code shared between insert_value and extract_value Ops.
82854c56347SValentin Clement struct ValueOpCommon {
82954c56347SValentin Clement   // Translate the arguments pertaining to any multidimensional array to
83054c56347SValentin Clement   // row-major order for LLVM-IR.
83154c56347SValentin Clement   static void toRowMajor(SmallVectorImpl<mlir::Attribute> &attrs,
83254c56347SValentin Clement                          mlir::Type ty) {
83354c56347SValentin Clement     assert(ty && "type is null");
83454c56347SValentin Clement     const auto end = attrs.size();
83554c56347SValentin Clement     for (std::remove_const_t<decltype(end)> i = 0; i < end; ++i) {
83654c56347SValentin Clement       if (auto seq = ty.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
83754c56347SValentin Clement         const auto dim = getDimension(seq);
83854c56347SValentin Clement         if (dim > 1) {
83954c56347SValentin Clement           auto ub = std::min(i + dim, end);
84054c56347SValentin Clement           std::reverse(attrs.begin() + i, attrs.begin() + ub);
84154c56347SValentin Clement           i += dim - 1;
84254c56347SValentin Clement         }
84354c56347SValentin Clement         ty = getArrayElementType(seq);
84454c56347SValentin Clement       } else if (auto st = ty.dyn_cast<mlir::LLVM::LLVMStructType>()) {
84554c56347SValentin Clement         ty = st.getBody()[attrs[i].cast<mlir::IntegerAttr>().getInt()];
84654c56347SValentin Clement       } else {
84754c56347SValentin Clement         llvm_unreachable("index into invalid type");
84854c56347SValentin Clement       }
84954c56347SValentin Clement     }
85054c56347SValentin Clement   }
85154c56347SValentin Clement 
85254c56347SValentin Clement   static llvm::SmallVector<mlir::Attribute>
85354c56347SValentin Clement   collectIndices(mlir::ConversionPatternRewriter &rewriter,
85454c56347SValentin Clement                  mlir::ArrayAttr arrAttr) {
85554c56347SValentin Clement     llvm::SmallVector<mlir::Attribute> attrs;
85654c56347SValentin Clement     for (auto i = arrAttr.begin(), e = arrAttr.end(); i != e; ++i) {
85754c56347SValentin Clement       if (i->isa<mlir::IntegerAttr>()) {
85854c56347SValentin Clement         attrs.push_back(*i);
85954c56347SValentin Clement       } else {
86054c56347SValentin Clement         auto fieldName = i->cast<mlir::StringAttr>().getValue();
86154c56347SValentin Clement         ++i;
86254c56347SValentin Clement         auto ty = i->cast<mlir::TypeAttr>().getValue();
86354c56347SValentin Clement         auto index = ty.cast<fir::RecordType>().getFieldIndex(fieldName);
86454c56347SValentin Clement         attrs.push_back(mlir::IntegerAttr::get(rewriter.getI32Type(), index));
86554c56347SValentin Clement       }
86654c56347SValentin Clement     }
86754c56347SValentin Clement     return attrs;
86854c56347SValentin Clement   }
86954c56347SValentin Clement 
87054c56347SValentin Clement private:
87154c56347SValentin Clement   static unsigned getDimension(mlir::LLVM::LLVMArrayType ty) {
87254c56347SValentin Clement     unsigned result = 1;
87354c56347SValentin Clement     for (auto eleTy = ty.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>();
87454c56347SValentin Clement          eleTy;
87554c56347SValentin Clement          eleTy = eleTy.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>())
87654c56347SValentin Clement       ++result;
87754c56347SValentin Clement     return result;
87854c56347SValentin Clement   }
87954c56347SValentin Clement 
88054c56347SValentin Clement   static mlir::Type getArrayElementType(mlir::LLVM::LLVMArrayType ty) {
88154c56347SValentin Clement     auto eleTy = ty.getElementType();
88254c56347SValentin Clement     while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>())
88354c56347SValentin Clement       eleTy = arrTy.getElementType();
88454c56347SValentin Clement     return eleTy;
88554c56347SValentin Clement   }
88654c56347SValentin Clement };
88754c56347SValentin Clement 
88854c56347SValentin Clement /// Extract a subobject value from an ssa-value of aggregate type
88954c56347SValentin Clement struct ExtractValueOpConversion
89054c56347SValentin Clement     : public FIROpAndTypeConversion<fir::ExtractValueOp>,
89154c56347SValentin Clement       public ValueOpCommon {
89254c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
89354c56347SValentin Clement 
89454c56347SValentin Clement   mlir::LogicalResult
89554c56347SValentin Clement   doRewrite(fir::ExtractValueOp extractVal, mlir::Type ty, OpAdaptor adaptor,
89654c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
89754c56347SValentin Clement     auto attrs = collectIndices(rewriter, extractVal.coor());
89854c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
89954c56347SValentin Clement     auto position = mlir::ArrayAttr::get(extractVal.getContext(), attrs);
90054c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(
90154c56347SValentin Clement         extractVal, ty, adaptor.getOperands()[0], position);
90254c56347SValentin Clement     return success();
90354c56347SValentin Clement   }
90454c56347SValentin Clement };
90554c56347SValentin Clement 
90654c56347SValentin Clement /// InsertValue is the generalized instruction for the composition of new
90754c56347SValentin Clement /// aggregate type values.
90854c56347SValentin Clement struct InsertValueOpConversion
90954c56347SValentin Clement     : public FIROpAndTypeConversion<fir::InsertValueOp>,
91054c56347SValentin Clement       public ValueOpCommon {
91154c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
91254c56347SValentin Clement 
91354c56347SValentin Clement   mlir::LogicalResult
91454c56347SValentin Clement   doRewrite(fir::InsertValueOp insertVal, mlir::Type ty, OpAdaptor adaptor,
91554c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
91654c56347SValentin Clement     auto attrs = collectIndices(rewriter, insertVal.coor());
91754c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
91854c56347SValentin Clement     auto position = mlir::ArrayAttr::get(insertVal.getContext(), attrs);
91954c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
92054c56347SValentin Clement         insertVal, ty, adaptor.getOperands()[0], adaptor.getOperands()[1],
92154c56347SValentin Clement         position);
92254c56347SValentin Clement     return success();
92354c56347SValentin Clement   }
92454c56347SValentin Clement };
92554c56347SValentin Clement 
9263ae8e442SValentin Clement /// InsertOnRange inserts a value into a sequence over a range of offsets.
9273ae8e442SValentin Clement struct InsertOnRangeOpConversion
9283ae8e442SValentin Clement     : public FIROpAndTypeConversion<fir::InsertOnRangeOp> {
9293ae8e442SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
9303ae8e442SValentin Clement 
9313ae8e442SValentin Clement   // Increments an array of subscripts in a row major fasion.
9323ae8e442SValentin Clement   void incrementSubscripts(const SmallVector<uint64_t> &dims,
9333ae8e442SValentin Clement                            SmallVector<uint64_t> &subscripts) const {
9343ae8e442SValentin Clement     for (size_t i = dims.size(); i > 0; --i) {
9353ae8e442SValentin Clement       if (++subscripts[i - 1] < dims[i - 1]) {
9363ae8e442SValentin Clement         return;
9373ae8e442SValentin Clement       }
9383ae8e442SValentin Clement       subscripts[i - 1] = 0;
9393ae8e442SValentin Clement     }
9403ae8e442SValentin Clement   }
9413ae8e442SValentin Clement 
9423ae8e442SValentin Clement   mlir::LogicalResult
9433ae8e442SValentin Clement   doRewrite(fir::InsertOnRangeOp range, mlir::Type ty, OpAdaptor adaptor,
9443ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
9453ae8e442SValentin Clement 
9463ae8e442SValentin Clement     llvm::SmallVector<uint64_t> dims;
9473ae8e442SValentin Clement     auto type = adaptor.getOperands()[0].getType();
9483ae8e442SValentin Clement 
9493ae8e442SValentin Clement     // Iteratively extract the array dimensions from the type.
9503ae8e442SValentin Clement     while (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
9513ae8e442SValentin Clement       dims.push_back(t.getNumElements());
9523ae8e442SValentin Clement       type = t.getElementType();
9533ae8e442SValentin Clement     }
9543ae8e442SValentin Clement 
9553ae8e442SValentin Clement     SmallVector<uint64_t> lBounds;
9563ae8e442SValentin Clement     SmallVector<uint64_t> uBounds;
9573ae8e442SValentin Clement 
9583ae8e442SValentin Clement     // Extract integer value from the attribute
9593ae8e442SValentin Clement     SmallVector<int64_t> coordinates = llvm::to_vector<4>(
9603ae8e442SValentin Clement         llvm::map_range(range.coor(), [](Attribute a) -> int64_t {
9613ae8e442SValentin Clement           return a.cast<IntegerAttr>().getInt();
9623ae8e442SValentin Clement         }));
9633ae8e442SValentin Clement 
9643ae8e442SValentin Clement     // Unzip the upper and lower bound and convert to a row major format.
9653ae8e442SValentin Clement     for (auto i = coordinates.rbegin(), e = coordinates.rend(); i != e; ++i) {
9663ae8e442SValentin Clement       uBounds.push_back(*i++);
9673ae8e442SValentin Clement       lBounds.push_back(*i);
9683ae8e442SValentin Clement     }
9693ae8e442SValentin Clement 
9703ae8e442SValentin Clement     auto &subscripts = lBounds;
9713ae8e442SValentin Clement     auto loc = range.getLoc();
9723ae8e442SValentin Clement     mlir::Value lastOp = adaptor.getOperands()[0];
9733ae8e442SValentin Clement     mlir::Value insertVal = adaptor.getOperands()[1];
9743ae8e442SValentin Clement 
9753ae8e442SValentin Clement     auto i64Ty = rewriter.getI64Type();
9763ae8e442SValentin Clement     while (subscripts != uBounds) {
9773ae8e442SValentin Clement       // Convert uint64_t's to Attribute's.
9783ae8e442SValentin Clement       SmallVector<mlir::Attribute> subscriptAttrs;
9793ae8e442SValentin Clement       for (const auto &subscript : subscripts)
9803ae8e442SValentin Clement         subscriptAttrs.push_back(IntegerAttr::get(i64Ty, subscript));
9813ae8e442SValentin Clement       lastOp = rewriter.create<mlir::LLVM::InsertValueOp>(
9823ae8e442SValentin Clement           loc, ty, lastOp, insertVal,
9833ae8e442SValentin Clement           ArrayAttr::get(range.getContext(), subscriptAttrs));
9843ae8e442SValentin Clement 
9853ae8e442SValentin Clement       incrementSubscripts(dims, subscripts);
9863ae8e442SValentin Clement     }
9873ae8e442SValentin Clement 
9883ae8e442SValentin Clement     // Convert uint64_t's to Attribute's.
9893ae8e442SValentin Clement     SmallVector<mlir::Attribute> subscriptAttrs;
9903ae8e442SValentin Clement     for (const auto &subscript : subscripts)
9913ae8e442SValentin Clement       subscriptAttrs.push_back(
9923ae8e442SValentin Clement           IntegerAttr::get(rewriter.getI64Type(), subscript));
9933ae8e442SValentin Clement     mlir::ArrayRef<mlir::Attribute> arrayRef(subscriptAttrs);
9943ae8e442SValentin Clement 
9953ae8e442SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
9963ae8e442SValentin Clement         range, ty, lastOp, insertVal,
9973ae8e442SValentin Clement         ArrayAttr::get(range.getContext(), arrayRef));
9983ae8e442SValentin Clement 
9993ae8e442SValentin Clement     return success();
10003ae8e442SValentin Clement   }
10013ae8e442SValentin Clement };
10027b5132daSValentin Clement 
10037b5132daSValentin Clement //
10047b5132daSValentin Clement // Primitive operations on Complex types
10057b5132daSValentin Clement //
10067b5132daSValentin Clement 
10077b5132daSValentin Clement /// Generate inline code for complex addition/subtraction
10087b5132daSValentin Clement template <typename LLVMOP, typename OPTY>
10097b5132daSValentin Clement mlir::LLVM::InsertValueOp complexSum(OPTY sumop, mlir::ValueRange opnds,
10107b5132daSValentin Clement                                      mlir::ConversionPatternRewriter &rewriter,
10117b5132daSValentin Clement                                      fir::LLVMTypeConverter &lowering) {
10127b5132daSValentin Clement   mlir::Value a = opnds[0];
10137b5132daSValentin Clement   mlir::Value b = opnds[1];
10147b5132daSValentin Clement   auto loc = sumop.getLoc();
10157b5132daSValentin Clement   auto ctx = sumop.getContext();
10167b5132daSValentin Clement   auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
10177b5132daSValentin Clement   auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
10187b5132daSValentin Clement   mlir::Type eleTy = lowering.convertType(getComplexEleTy(sumop.getType()));
10197b5132daSValentin Clement   mlir::Type ty = lowering.convertType(sumop.getType());
10207b5132daSValentin Clement   auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
10217b5132daSValentin Clement   auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
10227b5132daSValentin Clement   auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
10237b5132daSValentin Clement   auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
10247b5132daSValentin Clement   auto rx = rewriter.create<LLVMOP>(loc, eleTy, x0, x1);
10257b5132daSValentin Clement   auto ry = rewriter.create<LLVMOP>(loc, eleTy, y0, y1);
10267b5132daSValentin Clement   auto r0 = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
10277b5132daSValentin Clement   auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r0, rx, c0);
10287b5132daSValentin Clement   return rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ry, c1);
10297b5132daSValentin Clement }
10307b5132daSValentin Clement 
10317b5132daSValentin Clement struct AddcOpConversion : public FIROpConversion<fir::AddcOp> {
10327b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
10337b5132daSValentin Clement 
10347b5132daSValentin Clement   mlir::LogicalResult
10357b5132daSValentin Clement   matchAndRewrite(fir::AddcOp addc, OpAdaptor adaptor,
10367b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
10377b5132daSValentin Clement     // given: (x + iy) + (x' + iy')
10387b5132daSValentin Clement     // result: (x + x') + i(y + y')
10397b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FAddOp>(addc, adaptor.getOperands(),
10407b5132daSValentin Clement                                             rewriter, lowerTy());
10417b5132daSValentin Clement     rewriter.replaceOp(addc, r.getResult());
10427b5132daSValentin Clement     return success();
10437b5132daSValentin Clement   }
10447b5132daSValentin Clement };
10457b5132daSValentin Clement 
10467b5132daSValentin Clement struct SubcOpConversion : public FIROpConversion<fir::SubcOp> {
10477b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
10487b5132daSValentin Clement 
10497b5132daSValentin Clement   mlir::LogicalResult
10507b5132daSValentin Clement   matchAndRewrite(fir::SubcOp subc, OpAdaptor adaptor,
10517b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
10527b5132daSValentin Clement     // given: (x + iy) - (x' + iy')
10537b5132daSValentin Clement     // result: (x - x') + i(y - y')
10547b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FSubOp>(subc, adaptor.getOperands(),
10557b5132daSValentin Clement                                             rewriter, lowerTy());
10567b5132daSValentin Clement     rewriter.replaceOp(subc, r.getResult());
10577b5132daSValentin Clement     return success();
10587b5132daSValentin Clement   }
10597b5132daSValentin Clement };
10607b5132daSValentin Clement 
10617b5132daSValentin Clement /// Inlined complex multiply
10627b5132daSValentin Clement struct MulcOpConversion : public FIROpConversion<fir::MulcOp> {
10637b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
10647b5132daSValentin Clement 
10657b5132daSValentin Clement   mlir::LogicalResult
10667b5132daSValentin Clement   matchAndRewrite(fir::MulcOp mulc, OpAdaptor adaptor,
10677b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
10687b5132daSValentin Clement     // TODO: Can we use a call to __muldc3 ?
10697b5132daSValentin Clement     // given: (x + iy) * (x' + iy')
10707b5132daSValentin Clement     // result: (xx'-yy')+i(xy'+yx')
10717b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
10727b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
10737b5132daSValentin Clement     auto loc = mulc.getLoc();
10747b5132daSValentin Clement     auto *ctx = mulc.getContext();
10757b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
10767b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
10777b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(mulc.getType()));
10787b5132daSValentin Clement     mlir::Type ty = convertType(mulc.getType());
10797b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
10807b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
10817b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
10827b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
10837b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
10847b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
10857b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
10867b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xy, yx);
10877b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
10887b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, xx, yy);
10897b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
10907b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
10917b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
10927b5132daSValentin Clement     rewriter.replaceOp(mulc, r0.getResult());
10937b5132daSValentin Clement     return success();
10947b5132daSValentin Clement   }
10957b5132daSValentin Clement };
10967b5132daSValentin Clement 
10977b5132daSValentin Clement /// Inlined complex division
10987b5132daSValentin Clement struct DivcOpConversion : public FIROpConversion<fir::DivcOp> {
10997b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
11007b5132daSValentin Clement 
11017b5132daSValentin Clement   mlir::LogicalResult
11027b5132daSValentin Clement   matchAndRewrite(fir::DivcOp divc, OpAdaptor adaptor,
11037b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
11047b5132daSValentin Clement     // TODO: Can we use a call to __divdc3 instead?
11057b5132daSValentin Clement     // Just generate inline code for now.
11067b5132daSValentin Clement     // given: (x + iy) / (x' + iy')
11077b5132daSValentin Clement     // result: ((xx'+yy')/d) + i((yx'-xy')/d) where d = x'x' + y'y'
11087b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
11097b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
11107b5132daSValentin Clement     auto loc = divc.getLoc();
11117b5132daSValentin Clement     auto *ctx = divc.getContext();
11127b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
11137b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
11147b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(divc.getType()));
11157b5132daSValentin Clement     mlir::Type ty = convertType(divc.getType());
11167b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
11177b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
11187b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
11197b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
11207b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
11217b5132daSValentin Clement     auto x1x1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x1, x1);
11227b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
11237b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
11247b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
11257b5132daSValentin Clement     auto y1y1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y1, y1);
11267b5132daSValentin Clement     auto d = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, x1x1, y1y1);
11277b5132daSValentin Clement     auto rrn = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xx, yy);
11287b5132daSValentin Clement     auto rin = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, yx, xy);
11297b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rrn, d);
11307b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rin, d);
11317b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
11327b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
11337b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
11347b5132daSValentin Clement     rewriter.replaceOp(divc, r0.getResult());
11357b5132daSValentin Clement     return success();
11367b5132daSValentin Clement   }
11377b5132daSValentin Clement };
11387b5132daSValentin Clement 
11397b5132daSValentin Clement /// Inlined complex negation
11407b5132daSValentin Clement struct NegcOpConversion : public FIROpConversion<fir::NegcOp> {
11417b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
11427b5132daSValentin Clement 
11437b5132daSValentin Clement   mlir::LogicalResult
11447b5132daSValentin Clement   matchAndRewrite(fir::NegcOp neg, OpAdaptor adaptor,
11457b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
11467b5132daSValentin Clement     // given: -(x + iy)
11477b5132daSValentin Clement     // result: -x - iy
11487b5132daSValentin Clement     auto *ctxt = neg.getContext();
11497b5132daSValentin Clement     auto eleTy = convertType(getComplexEleTy(neg.getType()));
11507b5132daSValentin Clement     auto ty = convertType(neg.getType());
11517b5132daSValentin Clement     auto loc = neg.getLoc();
11527b5132daSValentin Clement     mlir::Value o0 = adaptor.getOperands()[0];
11537b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0));
11547b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1));
11557b5132daSValentin Clement     auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c0);
11567b5132daSValentin Clement     auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c1);
11577b5132daSValentin Clement     auto nrp = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, rp);
11587b5132daSValentin Clement     auto nip = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, ip);
11597b5132daSValentin Clement     auto r = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, o0, nrp, c0);
11607b5132daSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(neg, ty, r, nip, c1);
11617b5132daSValentin Clement     return success();
11627b5132daSValentin Clement   }
11637b5132daSValentin Clement };
11647b5132daSValentin Clement 
1165044d5b5dSValentin Clement } // namespace
1166044d5b5dSValentin Clement 
1167044d5b5dSValentin Clement namespace {
1168044d5b5dSValentin Clement /// Convert FIR dialect to LLVM dialect
1169044d5b5dSValentin Clement ///
1170044d5b5dSValentin Clement /// This pass lowers all FIR dialect operations to LLVM IR dialect. An
1171044d5b5dSValentin Clement /// MLIR pass is used to lower residual Std dialect to LLVM IR dialect.
1172044d5b5dSValentin Clement ///
1173044d5b5dSValentin Clement /// This pass is not complete yet. We are upstreaming it in small patches.
1174044d5b5dSValentin Clement class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> {
1175044d5b5dSValentin Clement public:
1176044d5b5dSValentin Clement   mlir::ModuleOp getModule() { return getOperation(); }
1177044d5b5dSValentin Clement 
1178044d5b5dSValentin Clement   void runOnOperation() override final {
11797b5132daSValentin Clement     auto mod = getModule();
11807b5132daSValentin Clement     if (!forcedTargetTriple.empty()) {
11817b5132daSValentin Clement       fir::setTargetTriple(mod, forcedTargetTriple);
11827b5132daSValentin Clement     }
11837b5132daSValentin Clement 
1184044d5b5dSValentin Clement     auto *context = getModule().getContext();
1185044d5b5dSValentin Clement     fir::LLVMTypeConverter typeConverter{getModule()};
1186044d5b5dSValentin Clement     mlir::OwningRewritePatternList pattern(context);
1187df3b9810SValentin Clement     pattern.insert<
1188*1e6d9c06SDiana Picus         AddcOpConversion, AddrOfOpConversion, AllocaOpConversion,
1189*1e6d9c06SDiana Picus         BoxAddrOpConversion, BoxDimsOpConversion, BoxEleSizeOpConversion,
1190*1e6d9c06SDiana Picus         BoxIsAllocOpConversion, BoxIsArrayOpConversion, BoxIsPtrOpConversion,
1191*1e6d9c06SDiana Picus         BoxRankOpConversion, CallOpConversion, ConvertOpConversion,
1192*1e6d9c06SDiana Picus         DivcOpConversion, ExtractValueOpConversion, HasValueOpConversion,
1193*1e6d9c06SDiana Picus         GlobalOpConversion, InsertOnRangeOpConversion, InsertValueOpConversion,
1194*1e6d9c06SDiana Picus         LoadOpConversion, NegcOpConversion, MulcOpConversion,
1195*1e6d9c06SDiana Picus         SelectOpConversion, SelectRankOpConversion, StoreOpConversion,
1196*1e6d9c06SDiana Picus         SubcOpConversion, UndefOpConversion, UnreachableOpConversion,
1197*1e6d9c06SDiana Picus         ZeroOpConversion>(typeConverter);
1198044d5b5dSValentin Clement     mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern);
1199044d5b5dSValentin Clement     mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter,
1200044d5b5dSValentin Clement                                                             pattern);
1201044d5b5dSValentin Clement     mlir::ConversionTarget target{*context};
1202044d5b5dSValentin Clement     target.addLegalDialect<mlir::LLVM::LLVMDialect>();
1203044d5b5dSValentin Clement 
1204044d5b5dSValentin Clement     // required NOPs for applying a full conversion
1205044d5b5dSValentin Clement     target.addLegalOp<mlir::ModuleOp>();
1206044d5b5dSValentin Clement 
1207044d5b5dSValentin Clement     // apply the patterns
1208044d5b5dSValentin Clement     if (mlir::failed(mlir::applyFullConversion(getModule(), target,
1209044d5b5dSValentin Clement                                                std::move(pattern)))) {
1210044d5b5dSValentin Clement       signalPassFailure();
1211044d5b5dSValentin Clement     }
1212044d5b5dSValentin Clement   }
1213044d5b5dSValentin Clement };
1214044d5b5dSValentin Clement } // namespace
1215044d5b5dSValentin Clement 
1216044d5b5dSValentin Clement std::unique_ptr<mlir::Pass> fir::createFIRToLLVMPass() {
1217044d5b5dSValentin Clement   return std::make_unique<FIRToLLVMLowering>();
1218044d5b5dSValentin Clement }
1219