1044d5b5dSValentin Clement //===-- CodeGen.cpp -- bridge to lower to LLVM ----------------------------===//
2044d5b5dSValentin Clement //
3044d5b5dSValentin Clement // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4044d5b5dSValentin Clement // See https://llvm.org/LICENSE.txt for license information.
5044d5b5dSValentin Clement // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6044d5b5dSValentin Clement //
7044d5b5dSValentin Clement //===----------------------------------------------------------------------===//
8044d5b5dSValentin Clement //
9044d5b5dSValentin Clement // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10044d5b5dSValentin Clement //
11044d5b5dSValentin Clement //===----------------------------------------------------------------------===//
12044d5b5dSValentin Clement 
13044d5b5dSValentin Clement #include "flang/Optimizer/CodeGen/CodeGen.h"
14044d5b5dSValentin Clement #include "PassDetail.h"
15b6e44ecdSValentin Clement #include "flang/ISO_Fortran_binding.h"
1639f4ef81SValentin Clement #include "flang/Optimizer/Dialect/FIRAttr.h"
17044d5b5dSValentin Clement #include "flang/Optimizer/Dialect/FIROps.h"
18*af6ee580SValentin Clement #include "flang/Optimizer/Support/TypeCode.h"
19044d5b5dSValentin Clement #include "mlir/Conversion/ArithmeticToLLVM/ArithmeticToLLVM.h"
20044d5b5dSValentin Clement #include "mlir/Conversion/LLVMCommon/Pattern.h"
21044d5b5dSValentin Clement #include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h"
22044d5b5dSValentin Clement #include "mlir/IR/BuiltinTypes.h"
233ae8e442SValentin Clement #include "mlir/IR/Matchers.h"
24044d5b5dSValentin Clement #include "mlir/Pass/Pass.h"
25044d5b5dSValentin Clement #include "llvm/ADT/ArrayRef.h"
26044d5b5dSValentin Clement 
27044d5b5dSValentin Clement #define DEBUG_TYPE "flang-codegen"
28044d5b5dSValentin Clement 
29044d5b5dSValentin Clement // fir::LLVMTypeConverter for converting to LLVM IR dialect types.
30044d5b5dSValentin Clement #include "TypeConverter.h"
31044d5b5dSValentin Clement 
32*af6ee580SValentin Clement // TODO: This should really be recovered from the specified target.
33*af6ee580SValentin Clement static constexpr unsigned defaultAlign = 8;
34*af6ee580SValentin Clement 
35b6e44ecdSValentin Clement /// `fir.box` attribute values as defined for CFI_attribute_t in
36b6e44ecdSValentin Clement /// flang/ISO_Fortran_binding.h.
37b6e44ecdSValentin Clement static constexpr unsigned kAttrPointer = CFI_attribute_pointer;
38b6e44ecdSValentin Clement static constexpr unsigned kAttrAllocatable = CFI_attribute_allocatable;
39b6e44ecdSValentin Clement 
401e6d9c06SDiana Picus static mlir::LLVM::ConstantOp
411e6d9c06SDiana Picus genConstantIndex(mlir::Location loc, mlir::Type ity,
421e6d9c06SDiana Picus                  mlir::ConversionPatternRewriter &rewriter,
431e6d9c06SDiana Picus                  std::int64_t offset) {
441e6d9c06SDiana Picus   auto cattr = rewriter.getI64IntegerAttr(offset);
451e6d9c06SDiana Picus   return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr);
461e6d9c06SDiana Picus }
471e6d9c06SDiana Picus 
4839f4ef81SValentin Clement static Block *createBlock(mlir::ConversionPatternRewriter &rewriter,
4939f4ef81SValentin Clement                           mlir::Block *insertBefore) {
5039f4ef81SValentin Clement   assert(insertBefore && "expected valid insertion block");
5139f4ef81SValentin Clement   return rewriter.createBlock(insertBefore->getParent(),
5239f4ef81SValentin Clement                               mlir::Region::iterator(insertBefore));
5339f4ef81SValentin Clement }
5439f4ef81SValentin Clement 
55044d5b5dSValentin Clement namespace {
56044d5b5dSValentin Clement /// FIR conversion pattern template
57044d5b5dSValentin Clement template <typename FromOp>
58044d5b5dSValentin Clement class FIROpConversion : public mlir::ConvertOpToLLVMPattern<FromOp> {
59044d5b5dSValentin Clement public:
60044d5b5dSValentin Clement   explicit FIROpConversion(fir::LLVMTypeConverter &lowering)
61044d5b5dSValentin Clement       : mlir::ConvertOpToLLVMPattern<FromOp>(lowering) {}
62044d5b5dSValentin Clement 
63044d5b5dSValentin Clement protected:
64044d5b5dSValentin Clement   mlir::Type convertType(mlir::Type ty) const {
65044d5b5dSValentin Clement     return lowerTy().convertType(ty);
66044d5b5dSValentin Clement   }
67044d5b5dSValentin Clement 
68df3b9810SValentin Clement   mlir::LLVM::ConstantOp
69*af6ee580SValentin Clement   genI32Constant(mlir::Location loc, mlir::ConversionPatternRewriter &rewriter,
70*af6ee580SValentin Clement                  int value) const {
71*af6ee580SValentin Clement     mlir::Type i32Ty = rewriter.getI32Type();
72*af6ee580SValentin Clement     mlir::IntegerAttr attr = rewriter.getI32IntegerAttr(value);
73*af6ee580SValentin Clement     return rewriter.create<mlir::LLVM::ConstantOp>(loc, i32Ty, attr);
74*af6ee580SValentin Clement   }
75*af6ee580SValentin Clement 
76*af6ee580SValentin Clement   mlir::LLVM::ConstantOp
77df3b9810SValentin Clement   genConstantOffset(mlir::Location loc,
78df3b9810SValentin Clement                     mlir::ConversionPatternRewriter &rewriter,
79df3b9810SValentin Clement                     int offset) const {
80*af6ee580SValentin Clement     mlir::Type ity = lowerTy().offsetType();
81*af6ee580SValentin Clement     mlir::IntegerAttr cattr = rewriter.getI32IntegerAttr(offset);
82df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr);
83df3b9810SValentin Clement   }
84df3b9810SValentin Clement 
85b6e44ecdSValentin Clement   /// Construct code sequence to extract the specifc value from a `fir.box`.
86b6e44ecdSValentin Clement   mlir::Value getValueFromBox(mlir::Location loc, mlir::Value box,
87df3b9810SValentin Clement                               mlir::Type resultTy,
88b6e44ecdSValentin Clement                               mlir::ConversionPatternRewriter &rewriter,
89b6e44ecdSValentin Clement                               unsigned boxValue) const {
90df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
91b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp cValuePos =
92b6e44ecdSValentin Clement         genConstantOffset(loc, rewriter, boxValue);
93df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(resultTy);
94df3b9810SValentin Clement     auto p = rewriter.create<mlir::LLVM::GEPOp>(
95b6e44ecdSValentin Clement         loc, pty, mlir::ValueRange{box, c0, cValuePos});
96df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, resultTy, p);
97df3b9810SValentin Clement   }
98df3b9810SValentin Clement 
99df3b9810SValentin Clement   /// Method to construct code sequence to get the triple for dimension `dim`
100df3b9810SValentin Clement   /// from a box.
101df3b9810SValentin Clement   SmallVector<mlir::Value, 3>
102df3b9810SValentin Clement   getDimsFromBox(mlir::Location loc, ArrayRef<mlir::Type> retTys,
103df3b9810SValentin Clement                  mlir::Value box, mlir::Value dim,
104df3b9810SValentin Clement                  mlir::ConversionPatternRewriter &rewriter) const {
105df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
106df3b9810SValentin Clement     mlir::LLVM::ConstantOp cDims =
107df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kDimsPosInBox);
108df3b9810SValentin Clement     mlir::LLVM::LoadOp l0 =
109df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 0, retTys[0], rewriter);
110df3b9810SValentin Clement     mlir::LLVM::LoadOp l1 =
111df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 1, retTys[1], rewriter);
112df3b9810SValentin Clement     mlir::LLVM::LoadOp l2 =
113df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 2, retTys[2], rewriter);
114df3b9810SValentin Clement     return {l0.getResult(), l1.getResult(), l2.getResult()};
115df3b9810SValentin Clement   }
116df3b9810SValentin Clement 
117df3b9810SValentin Clement   mlir::LLVM::LoadOp
118df3b9810SValentin Clement   loadFromOffset(mlir::Location loc, mlir::Value a, mlir::LLVM::ConstantOp c0,
119df3b9810SValentin Clement                  mlir::LLVM::ConstantOp cDims, mlir::Value dim, int off,
120df3b9810SValentin Clement                  mlir::Type ty,
121df3b9810SValentin Clement                  mlir::ConversionPatternRewriter &rewriter) const {
122df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
123df3b9810SValentin Clement     mlir::LLVM::ConstantOp c = genConstantOffset(loc, rewriter, off);
124df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, a, c0, cDims, dim, c);
125df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
126df3b9810SValentin Clement   }
127df3b9810SValentin Clement 
128df3b9810SValentin Clement   /// Read base address from a fir.box. Returned address has type ty.
129df3b9810SValentin Clement   mlir::Value
130df3b9810SValentin Clement   loadBaseAddrFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box,
131df3b9810SValentin Clement                       mlir::ConversionPatternRewriter &rewriter) const {
132df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
133df3b9810SValentin Clement     mlir::LLVM::ConstantOp cAddr =
134df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kAddrPosInBox);
135df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
136df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cAddr);
137df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
138df3b9810SValentin Clement   }
139df3b9810SValentin Clement 
140df3b9810SValentin Clement   mlir::Value
141df3b9810SValentin Clement   loadElementSizeFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box,
142df3b9810SValentin Clement                          mlir::ConversionPatternRewriter &rewriter) const {
143df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
144df3b9810SValentin Clement     mlir::LLVM::ConstantOp cElemLen =
145df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kElemLenPosInBox);
146df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
147df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cElemLen);
148df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
149df3b9810SValentin Clement   }
150df3b9810SValentin Clement 
151b6e44ecdSValentin Clement   // Load the attribute from the \p box and perform a check against \p maskValue
152b6e44ecdSValentin Clement   // The final comparison is implemented as `(attribute & maskValue) != 0`.
153b6e44ecdSValentin Clement   mlir::Value genBoxAttributeCheck(mlir::Location loc, mlir::Value box,
154b6e44ecdSValentin Clement                                    mlir::ConversionPatternRewriter &rewriter,
155b6e44ecdSValentin Clement                                    unsigned maskValue) const {
156b6e44ecdSValentin Clement     mlir::Type attrTy = rewriter.getI32Type();
157b6e44ecdSValentin Clement     mlir::Value attribute =
158b6e44ecdSValentin Clement         getValueFromBox(loc, box, attrTy, rewriter, kAttributePosInBox);
159b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp attrMask =
160b6e44ecdSValentin Clement         genConstantOffset(loc, rewriter, maskValue);
161b6e44ecdSValentin Clement     auto maskRes =
162b6e44ecdSValentin Clement         rewriter.create<mlir::LLVM::AndOp>(loc, attrTy, attribute, attrMask);
163b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
164b6e44ecdSValentin Clement     return rewriter.create<mlir::LLVM::ICmpOp>(
165b6e44ecdSValentin Clement         loc, mlir::LLVM::ICmpPredicate::ne, maskRes, c0);
166b6e44ecdSValentin Clement   }
167b6e44ecdSValentin Clement 
168*af6ee580SValentin Clement   // Get the element type given an LLVM type that is of the form
169*af6ee580SValentin Clement   // [llvm.ptr](array|struct|vector)+ and the provided indexes.
170*af6ee580SValentin Clement   static mlir::Type getBoxEleTy(mlir::Type type,
171*af6ee580SValentin Clement                                 llvm::ArrayRef<unsigned> indexes) {
172*af6ee580SValentin Clement     if (auto t = type.dyn_cast<mlir::LLVM::LLVMPointerType>())
173*af6ee580SValentin Clement       type = t.getElementType();
174*af6ee580SValentin Clement     for (auto i : indexes) {
175*af6ee580SValentin Clement       if (auto t = type.dyn_cast<mlir::LLVM::LLVMStructType>()) {
176*af6ee580SValentin Clement         assert(!t.isOpaque() && i < t.getBody().size());
177*af6ee580SValentin Clement         type = t.getBody()[i];
178*af6ee580SValentin Clement       } else if (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
179*af6ee580SValentin Clement         type = t.getElementType();
180*af6ee580SValentin Clement       } else if (auto t = type.dyn_cast<mlir::VectorType>()) {
181*af6ee580SValentin Clement         type = t.getElementType();
182*af6ee580SValentin Clement       } else {
183*af6ee580SValentin Clement         fir::emitFatalError(mlir::UnknownLoc::get(type.getContext()),
184*af6ee580SValentin Clement                             "request for invalid box element type");
185*af6ee580SValentin Clement       }
186*af6ee580SValentin Clement     }
187*af6ee580SValentin Clement     return type;
188*af6ee580SValentin Clement   }
189*af6ee580SValentin Clement 
190df3b9810SValentin Clement   template <typename... ARGS>
191df3b9810SValentin Clement   mlir::LLVM::GEPOp genGEP(mlir::Location loc, mlir::Type ty,
192df3b9810SValentin Clement                            mlir::ConversionPatternRewriter &rewriter,
193df3b9810SValentin Clement                            mlir::Value base, ARGS... args) const {
194df3b9810SValentin Clement     SmallVector<mlir::Value> cv{args...};
195df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::GEPOp>(loc, ty, base, cv);
196df3b9810SValentin Clement   }
197df3b9810SValentin Clement 
1981e6d9c06SDiana Picus   /// Perform an extension or truncation as needed on an integer value. Lowering
1991e6d9c06SDiana Picus   /// to the specific target may involve some sign-extending or truncation of
2001e6d9c06SDiana Picus   /// values, particularly to fit them from abstract box types to the
2011e6d9c06SDiana Picus   /// appropriate reified structures.
2021e6d9c06SDiana Picus   mlir::Value integerCast(mlir::Location loc,
2031e6d9c06SDiana Picus                           mlir::ConversionPatternRewriter &rewriter,
2041e6d9c06SDiana Picus                           mlir::Type ty, mlir::Value val) const {
2051e6d9c06SDiana Picus     auto valTy = val.getType();
2061e6d9c06SDiana Picus     // If the value was not yet lowered, lower its type so that it can
2071e6d9c06SDiana Picus     // be used in getPrimitiveTypeSizeInBits.
2081e6d9c06SDiana Picus     if (!valTy.isa<mlir::IntegerType>())
2091e6d9c06SDiana Picus       valTy = convertType(valTy);
2101e6d9c06SDiana Picus     auto toSize = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
2111e6d9c06SDiana Picus     auto fromSize = mlir::LLVM::getPrimitiveTypeSizeInBits(valTy);
2121e6d9c06SDiana Picus     if (toSize < fromSize)
2131e6d9c06SDiana Picus       return rewriter.create<mlir::LLVM::TruncOp>(loc, ty, val);
2141e6d9c06SDiana Picus     if (toSize > fromSize)
2151e6d9c06SDiana Picus       return rewriter.create<mlir::LLVM::SExtOp>(loc, ty, val);
2161e6d9c06SDiana Picus     return val;
2171e6d9c06SDiana Picus   }
2181e6d9c06SDiana Picus 
219044d5b5dSValentin Clement   fir::LLVMTypeConverter &lowerTy() const {
220044d5b5dSValentin Clement     return *static_cast<fir::LLVMTypeConverter *>(this->getTypeConverter());
221044d5b5dSValentin Clement   }
222044d5b5dSValentin Clement };
223044d5b5dSValentin Clement 
2243ae8e442SValentin Clement /// FIR conversion pattern template
2253ae8e442SValentin Clement template <typename FromOp>
2263ae8e442SValentin Clement class FIROpAndTypeConversion : public FIROpConversion<FromOp> {
2273ae8e442SValentin Clement public:
2283ae8e442SValentin Clement   using FIROpConversion<FromOp>::FIROpConversion;
2293ae8e442SValentin Clement   using OpAdaptor = typename FromOp::Adaptor;
2303ae8e442SValentin Clement 
2313ae8e442SValentin Clement   mlir::LogicalResult
2323ae8e442SValentin Clement   matchAndRewrite(FromOp op, OpAdaptor adaptor,
2333ae8e442SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const final {
2343ae8e442SValentin Clement     mlir::Type ty = this->convertType(op.getType());
2353ae8e442SValentin Clement     return doRewrite(op, ty, adaptor, rewriter);
2363ae8e442SValentin Clement   }
2373ae8e442SValentin Clement 
2383ae8e442SValentin Clement   virtual mlir::LogicalResult
2393ae8e442SValentin Clement   doRewrite(FromOp addr, mlir::Type ty, OpAdaptor adaptor,
2403ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const = 0;
2413ae8e442SValentin Clement };
2423ae8e442SValentin Clement 
243420ad7ceSAndrzej Warzynski /// Create value signaling an absent optional argument in a call, e.g.
244420ad7ceSAndrzej Warzynski /// `fir.absent !fir.ref<i64>` -->  `llvm.mlir.null : !llvm.ptr<i64>`
245420ad7ceSAndrzej Warzynski struct AbsentOpConversion : public FIROpConversion<fir::AbsentOp> {
246420ad7ceSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
247420ad7ceSAndrzej Warzynski 
248420ad7ceSAndrzej Warzynski   mlir::LogicalResult
249420ad7ceSAndrzej Warzynski   matchAndRewrite(fir::AbsentOp absent, OpAdaptor,
250420ad7ceSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
251420ad7ceSAndrzej Warzynski     mlir::Type ty = convertType(absent.getType());
252420ad7ceSAndrzej Warzynski     mlir::Location loc = absent.getLoc();
253420ad7ceSAndrzej Warzynski 
254420ad7ceSAndrzej Warzynski     if (absent.getType().isa<fir::BoxCharType>()) {
255420ad7ceSAndrzej Warzynski       auto structTy = ty.cast<mlir::LLVM::LLVMStructType>();
256420ad7ceSAndrzej Warzynski       assert(!structTy.isOpaque() && !structTy.getBody().empty());
257420ad7ceSAndrzej Warzynski       auto undefStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
258420ad7ceSAndrzej Warzynski       auto nullField =
259420ad7ceSAndrzej Warzynski           rewriter.create<mlir::LLVM::NullOp>(loc, structTy.getBody()[0]);
260420ad7ceSAndrzej Warzynski       mlir::MLIRContext *ctx = absent.getContext();
261420ad7ceSAndrzej Warzynski       auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
262420ad7ceSAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
263420ad7ceSAndrzej Warzynski           absent, ty, undefStruct, nullField, c0);
264420ad7ceSAndrzej Warzynski     } else {
265420ad7ceSAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(absent, ty);
266420ad7ceSAndrzej Warzynski     }
267420ad7ceSAndrzej Warzynski     return success();
268420ad7ceSAndrzej Warzynski   }
269420ad7ceSAndrzej Warzynski };
270420ad7ceSAndrzej Warzynski 
2710c4a7a52SValentin Clement // Lower `fir.address_of` operation to `llvm.address_of` operation.
272044d5b5dSValentin Clement struct AddrOfOpConversion : public FIROpConversion<fir::AddrOfOp> {
273044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
274044d5b5dSValentin Clement 
275044d5b5dSValentin Clement   mlir::LogicalResult
276044d5b5dSValentin Clement   matchAndRewrite(fir::AddrOfOp addr, OpAdaptor adaptor,
277044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
278044d5b5dSValentin Clement     auto ty = convertType(addr.getType());
279044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::AddressOfOp>(
280044d5b5dSValentin Clement         addr, ty, addr.symbol().getRootReference().getValue());
281044d5b5dSValentin Clement     return success();
282044d5b5dSValentin Clement   }
283044d5b5dSValentin Clement };
2841e6d9c06SDiana Picus } // namespace
2851e6d9c06SDiana Picus 
2861e6d9c06SDiana Picus /// Lookup the function to compute the memory size of this parametric derived
2871e6d9c06SDiana Picus /// type. The size of the object may depend on the LEN type parameters of the
2881e6d9c06SDiana Picus /// derived type.
2891e6d9c06SDiana Picus static mlir::LLVM::LLVMFuncOp
2901e6d9c06SDiana Picus getDependentTypeMemSizeFn(fir::RecordType recTy, fir::AllocaOp op,
2911e6d9c06SDiana Picus                           mlir::ConversionPatternRewriter &rewriter) {
2921e6d9c06SDiana Picus   auto module = op->getParentOfType<mlir::ModuleOp>();
2931e6d9c06SDiana Picus   std::string name = recTy.getName().str() + "P.mem.size";
2941e6d9c06SDiana Picus   return module.lookupSymbol<mlir::LLVM::LLVMFuncOp>(name);
2951e6d9c06SDiana Picus }
2961e6d9c06SDiana Picus 
2971e6d9c06SDiana Picus namespace {
2981e6d9c06SDiana Picus /// convert to LLVM IR dialect `alloca`
2991e6d9c06SDiana Picus struct AllocaOpConversion : public FIROpConversion<fir::AllocaOp> {
3001e6d9c06SDiana Picus   using FIROpConversion::FIROpConversion;
3011e6d9c06SDiana Picus 
3021e6d9c06SDiana Picus   mlir::LogicalResult
3031e6d9c06SDiana Picus   matchAndRewrite(fir::AllocaOp alloc, OpAdaptor adaptor,
3041e6d9c06SDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
3051e6d9c06SDiana Picus     mlir::ValueRange operands = adaptor.getOperands();
3061e6d9c06SDiana Picus     auto loc = alloc.getLoc();
3071e6d9c06SDiana Picus     mlir::Type ity = lowerTy().indexType();
3081e6d9c06SDiana Picus     unsigned i = 0;
3091e6d9c06SDiana Picus     mlir::Value size = genConstantIndex(loc, ity, rewriter, 1).getResult();
3101e6d9c06SDiana Picus     mlir::Type ty = convertType(alloc.getType());
3111e6d9c06SDiana Picus     mlir::Type resultTy = ty;
3121e6d9c06SDiana Picus     if (alloc.hasLenParams()) {
3131e6d9c06SDiana Picus       unsigned end = alloc.numLenParams();
3141e6d9c06SDiana Picus       llvm::SmallVector<mlir::Value> lenParams;
3151e6d9c06SDiana Picus       for (; i < end; ++i)
3161e6d9c06SDiana Picus         lenParams.push_back(operands[i]);
3171e6d9c06SDiana Picus       mlir::Type scalarType = fir::unwrapSequenceType(alloc.getInType());
3181e6d9c06SDiana Picus       if (auto chrTy = scalarType.dyn_cast<fir::CharacterType>()) {
3191e6d9c06SDiana Picus         fir::CharacterType rawCharTy = fir::CharacterType::getUnknownLen(
3201e6d9c06SDiana Picus             chrTy.getContext(), chrTy.getFKind());
3211e6d9c06SDiana Picus         ty = mlir::LLVM::LLVMPointerType::get(convertType(rawCharTy));
3221e6d9c06SDiana Picus         assert(end == 1);
3231e6d9c06SDiana Picus         size = integerCast(loc, rewriter, ity, lenParams[0]);
3241e6d9c06SDiana Picus       } else if (auto recTy = scalarType.dyn_cast<fir::RecordType>()) {
3251e6d9c06SDiana Picus         mlir::LLVM::LLVMFuncOp memSizeFn =
3261e6d9c06SDiana Picus             getDependentTypeMemSizeFn(recTy, alloc, rewriter);
3271e6d9c06SDiana Picus         if (!memSizeFn)
3281e6d9c06SDiana Picus           emitError(loc, "did not find allocation function");
3291e6d9c06SDiana Picus         mlir::NamedAttribute attr = rewriter.getNamedAttr(
3301e6d9c06SDiana Picus             "callee", mlir::SymbolRefAttr::get(memSizeFn));
3311e6d9c06SDiana Picus         auto call = rewriter.create<mlir::LLVM::CallOp>(
3321e6d9c06SDiana Picus             loc, ity, lenParams, llvm::ArrayRef<mlir::NamedAttribute>{attr});
3331e6d9c06SDiana Picus         size = call.getResult(0);
3341e6d9c06SDiana Picus         ty = mlir::LLVM::LLVMPointerType::get(
3351e6d9c06SDiana Picus             mlir::IntegerType::get(alloc.getContext(), 8));
3361e6d9c06SDiana Picus       } else {
3371e6d9c06SDiana Picus         return emitError(loc, "unexpected type ")
3381e6d9c06SDiana Picus                << scalarType << " with type parameters";
3391e6d9c06SDiana Picus       }
3401e6d9c06SDiana Picus     }
3411e6d9c06SDiana Picus     if (alloc.hasShapeOperands()) {
3421e6d9c06SDiana Picus       mlir::Type allocEleTy = fir::unwrapRefType(alloc.getType());
3431e6d9c06SDiana Picus       // Scale the size by constant factors encoded in the array type.
3441e6d9c06SDiana Picus       if (auto seqTy = allocEleTy.dyn_cast<fir::SequenceType>()) {
3451e6d9c06SDiana Picus         fir::SequenceType::Extent constSize = 1;
3461e6d9c06SDiana Picus         for (auto extent : seqTy.getShape())
3471e6d9c06SDiana Picus           if (extent != fir::SequenceType::getUnknownExtent())
3481e6d9c06SDiana Picus             constSize *= extent;
3491e6d9c06SDiana Picus         mlir::Value constVal{
3501e6d9c06SDiana Picus             genConstantIndex(loc, ity, rewriter, constSize).getResult()};
3511e6d9c06SDiana Picus         size = rewriter.create<mlir::LLVM::MulOp>(loc, ity, size, constVal);
3521e6d9c06SDiana Picus       }
3531e6d9c06SDiana Picus       unsigned end = operands.size();
3541e6d9c06SDiana Picus       for (; i < end; ++i)
3551e6d9c06SDiana Picus         size = rewriter.create<mlir::LLVM::MulOp>(
3561e6d9c06SDiana Picus             loc, ity, size, integerCast(loc, rewriter, ity, operands[i]));
3571e6d9c06SDiana Picus     }
3581e6d9c06SDiana Picus     if (ty == resultTy) {
3591e6d9c06SDiana Picus       // Do not emit the bitcast if ty and resultTy are the same.
3601e6d9c06SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::AllocaOp>(alloc, ty, size,
3611e6d9c06SDiana Picus                                                         alloc->getAttrs());
3621e6d9c06SDiana Picus     } else {
3631e6d9c06SDiana Picus       auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, ty, size,
3641e6d9c06SDiana Picus                                                       alloc->getAttrs());
3651e6d9c06SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(alloc, resultTy, al);
3661e6d9c06SDiana Picus     }
3671e6d9c06SDiana Picus     return success();
3681e6d9c06SDiana Picus   }
3691e6d9c06SDiana Picus };
370044d5b5dSValentin Clement 
371df3b9810SValentin Clement /// Lower `fir.box_addr` to the sequence of operations to extract the first
372df3b9810SValentin Clement /// element of the box.
373df3b9810SValentin Clement struct BoxAddrOpConversion : public FIROpConversion<fir::BoxAddrOp> {
374df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
375df3b9810SValentin Clement 
376df3b9810SValentin Clement   mlir::LogicalResult
377df3b9810SValentin Clement   matchAndRewrite(fir::BoxAddrOp boxaddr, OpAdaptor adaptor,
378df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
379df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
380df3b9810SValentin Clement     auto loc = boxaddr.getLoc();
381df3b9810SValentin Clement     mlir::Type ty = convertType(boxaddr.getType());
382df3b9810SValentin Clement     if (auto argty = boxaddr.val().getType().dyn_cast<fir::BoxType>()) {
383df3b9810SValentin Clement       rewriter.replaceOp(boxaddr, loadBaseAddrFromBox(loc, ty, a, rewriter));
384df3b9810SValentin Clement     } else {
385df3b9810SValentin Clement       auto c0attr = rewriter.getI32IntegerAttr(0);
386df3b9810SValentin Clement       auto c0 = mlir::ArrayAttr::get(boxaddr.getContext(), c0attr);
387df3b9810SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(boxaddr, ty, a,
388df3b9810SValentin Clement                                                               c0);
389df3b9810SValentin Clement     }
390df3b9810SValentin Clement     return success();
391df3b9810SValentin Clement   }
392df3b9810SValentin Clement };
393df3b9810SValentin Clement 
394df3b9810SValentin Clement /// Lower `fir.box_dims` to a sequence of operations to extract the requested
395df3b9810SValentin Clement /// dimension infomartion from the boxed value.
396df3b9810SValentin Clement /// Result in a triple set of GEPs and loads.
397df3b9810SValentin Clement struct BoxDimsOpConversion : public FIROpConversion<fir::BoxDimsOp> {
398df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
399df3b9810SValentin Clement 
400df3b9810SValentin Clement   mlir::LogicalResult
401df3b9810SValentin Clement   matchAndRewrite(fir::BoxDimsOp boxdims, OpAdaptor adaptor,
402df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
403df3b9810SValentin Clement     SmallVector<mlir::Type, 3> resultTypes = {
404df3b9810SValentin Clement         convertType(boxdims.getResult(0).getType()),
405df3b9810SValentin Clement         convertType(boxdims.getResult(1).getType()),
406df3b9810SValentin Clement         convertType(boxdims.getResult(2).getType()),
407df3b9810SValentin Clement     };
408df3b9810SValentin Clement     auto results =
409df3b9810SValentin Clement         getDimsFromBox(boxdims.getLoc(), resultTypes, adaptor.getOperands()[0],
410df3b9810SValentin Clement                        adaptor.getOperands()[1], rewriter);
411df3b9810SValentin Clement     rewriter.replaceOp(boxdims, results);
412df3b9810SValentin Clement     return success();
413df3b9810SValentin Clement   }
414df3b9810SValentin Clement };
415df3b9810SValentin Clement 
416df3b9810SValentin Clement /// Lower `fir.box_elesize` to a sequence of operations ro extract the size of
417df3b9810SValentin Clement /// an element in the boxed value.
418df3b9810SValentin Clement struct BoxEleSizeOpConversion : public FIROpConversion<fir::BoxEleSizeOp> {
419df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
420df3b9810SValentin Clement 
421df3b9810SValentin Clement   mlir::LogicalResult
422df3b9810SValentin Clement   matchAndRewrite(fir::BoxEleSizeOp boxelesz, OpAdaptor adaptor,
423df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
424df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
425df3b9810SValentin Clement     auto loc = boxelesz.getLoc();
426df3b9810SValentin Clement     auto ty = convertType(boxelesz.getType());
427b6e44ecdSValentin Clement     auto elemSize = getValueFromBox(loc, a, ty, rewriter, kElemLenPosInBox);
428b6e44ecdSValentin Clement     rewriter.replaceOp(boxelesz, elemSize);
429b6e44ecdSValentin Clement     return success();
430b6e44ecdSValentin Clement   }
431b6e44ecdSValentin Clement };
432b6e44ecdSValentin Clement 
433b6e44ecdSValentin Clement /// Lower `fir.box_isalloc` to a sequence of operations to determine if the
434b6e44ecdSValentin Clement /// boxed value was from an ALLOCATABLE entity.
435b6e44ecdSValentin Clement struct BoxIsAllocOpConversion : public FIROpConversion<fir::BoxIsAllocOp> {
436b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
437b6e44ecdSValentin Clement 
438b6e44ecdSValentin Clement   mlir::LogicalResult
439b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsAllocOp boxisalloc, OpAdaptor adaptor,
440b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
441b6e44ecdSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
442b6e44ecdSValentin Clement     auto loc = boxisalloc.getLoc();
443b6e44ecdSValentin Clement     mlir::Value check =
444b6e44ecdSValentin Clement         genBoxAttributeCheck(loc, box, rewriter, kAttrAllocatable);
445b6e44ecdSValentin Clement     rewriter.replaceOp(boxisalloc, check);
446b6e44ecdSValentin Clement     return success();
447b6e44ecdSValentin Clement   }
448b6e44ecdSValentin Clement };
449b6e44ecdSValentin Clement 
450b6e44ecdSValentin Clement /// Lower `fir.box_isarray` to a sequence of operations to determine if the
451b6e44ecdSValentin Clement /// boxed is an array.
452b6e44ecdSValentin Clement struct BoxIsArrayOpConversion : public FIROpConversion<fir::BoxIsArrayOp> {
453b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
454b6e44ecdSValentin Clement 
455b6e44ecdSValentin Clement   mlir::LogicalResult
456b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsArrayOp boxisarray, OpAdaptor adaptor,
457b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
458b6e44ecdSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
459b6e44ecdSValentin Clement     auto loc = boxisarray.getLoc();
460b6e44ecdSValentin Clement     auto rank =
461b6e44ecdSValentin Clement         getValueFromBox(loc, a, rewriter.getI32Type(), rewriter, kRankPosInBox);
462b6e44ecdSValentin Clement     auto c0 = genConstantOffset(loc, rewriter, 0);
463b6e44ecdSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
464b6e44ecdSValentin Clement         boxisarray, mlir::LLVM::ICmpPredicate::ne, rank, c0);
465b6e44ecdSValentin Clement     return success();
466b6e44ecdSValentin Clement   }
467b6e44ecdSValentin Clement };
468b6e44ecdSValentin Clement 
469b6e44ecdSValentin Clement /// Lower `fir.box_isptr` to a sequence of operations to determined if the
470b6e44ecdSValentin Clement /// boxed value was from a POINTER entity.
471b6e44ecdSValentin Clement struct BoxIsPtrOpConversion : public FIROpConversion<fir::BoxIsPtrOp> {
472b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
473b6e44ecdSValentin Clement 
474b6e44ecdSValentin Clement   mlir::LogicalResult
475b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsPtrOp boxisptr, OpAdaptor adaptor,
476b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
477b6e44ecdSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
478b6e44ecdSValentin Clement     auto loc = boxisptr.getLoc();
479b6e44ecdSValentin Clement     mlir::Value check = genBoxAttributeCheck(loc, box, rewriter, kAttrPointer);
480b6e44ecdSValentin Clement     rewriter.replaceOp(boxisptr, check);
481df3b9810SValentin Clement     return success();
482df3b9810SValentin Clement   }
483df3b9810SValentin Clement };
484df3b9810SValentin Clement 
485df3b9810SValentin Clement /// Lower `fir.box_rank` to the sequence of operation to extract the rank from
486df3b9810SValentin Clement /// the box.
487df3b9810SValentin Clement struct BoxRankOpConversion : public FIROpConversion<fir::BoxRankOp> {
488df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
489df3b9810SValentin Clement 
490df3b9810SValentin Clement   mlir::LogicalResult
491df3b9810SValentin Clement   matchAndRewrite(fir::BoxRankOp boxrank, OpAdaptor adaptor,
492df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
493df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
494df3b9810SValentin Clement     auto loc = boxrank.getLoc();
495df3b9810SValentin Clement     mlir::Type ty = convertType(boxrank.getType());
496b6e44ecdSValentin Clement     auto result = getValueFromBox(loc, a, ty, rewriter, kRankPosInBox);
497df3b9810SValentin Clement     rewriter.replaceOp(boxrank, result);
498df3b9810SValentin Clement     return success();
499df3b9810SValentin Clement   }
500df3b9810SValentin Clement };
501df3b9810SValentin Clement 
5021a2ec667SValentin Clement /// Lower `fir.string_lit` to LLVM IR dialect operation.
5031a2ec667SValentin Clement struct StringLitOpConversion : public FIROpConversion<fir::StringLitOp> {
5041a2ec667SValentin Clement   using FIROpConversion::FIROpConversion;
5051a2ec667SValentin Clement 
5061a2ec667SValentin Clement   mlir::LogicalResult
5071a2ec667SValentin Clement   matchAndRewrite(fir::StringLitOp constop, OpAdaptor adaptor,
5081a2ec667SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
5091a2ec667SValentin Clement     auto ty = convertType(constop.getType());
5101a2ec667SValentin Clement     auto attr = constop.getValue();
5111a2ec667SValentin Clement     if (attr.isa<mlir::StringAttr>()) {
5121a2ec667SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(constop, ty, attr);
5131a2ec667SValentin Clement       return success();
5141a2ec667SValentin Clement     }
5151a2ec667SValentin Clement 
5161a2ec667SValentin Clement     auto arr = attr.cast<mlir::ArrayAttr>();
5171a2ec667SValentin Clement     auto charTy = constop.getType().cast<fir::CharacterType>();
5181a2ec667SValentin Clement     unsigned bits = lowerTy().characterBitsize(charTy);
5191a2ec667SValentin Clement     mlir::Type intTy = rewriter.getIntegerType(bits);
5201a2ec667SValentin Clement     auto attrs = llvm::map_range(
5211a2ec667SValentin Clement         arr.getValue(), [intTy, bits](mlir::Attribute attr) -> Attribute {
5221a2ec667SValentin Clement           return mlir::IntegerAttr::get(
5231a2ec667SValentin Clement               intTy,
5241a2ec667SValentin Clement               attr.cast<mlir::IntegerAttr>().getValue().sextOrTrunc(bits));
5251a2ec667SValentin Clement         });
5261a2ec667SValentin Clement     mlir::Type vecType = mlir::VectorType::get(arr.size(), intTy);
5271a2ec667SValentin Clement     auto denseAttr = mlir::DenseElementsAttr::get(
5281a2ec667SValentin Clement         vecType.cast<mlir::ShapedType>(), llvm::to_vector<8>(attrs));
5291a2ec667SValentin Clement     rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(constop, ty,
5301a2ec667SValentin Clement                                                          denseAttr);
5311a2ec667SValentin Clement     return success();
5321a2ec667SValentin Clement   }
5331a2ec667SValentin Clement };
5341a2ec667SValentin Clement 
535e38ef2ffSValentin Clement /// Lower `fir.box_tdesc` to the sequence of operations to extract the type
536e38ef2ffSValentin Clement /// descriptor from the box.
537e38ef2ffSValentin Clement struct BoxTypeDescOpConversion : public FIROpConversion<fir::BoxTypeDescOp> {
538e38ef2ffSValentin Clement   using FIROpConversion::FIROpConversion;
539e38ef2ffSValentin Clement 
540e38ef2ffSValentin Clement   mlir::LogicalResult
541e38ef2ffSValentin Clement   matchAndRewrite(fir::BoxTypeDescOp boxtypedesc, OpAdaptor adaptor,
542e38ef2ffSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
543e38ef2ffSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
544e38ef2ffSValentin Clement     auto loc = boxtypedesc.getLoc();
545e38ef2ffSValentin Clement     mlir::Type typeTy =
546e38ef2ffSValentin Clement         fir::getDescFieldTypeModel<kTypePosInBox>()(boxtypedesc.getContext());
547e38ef2ffSValentin Clement     auto result = getValueFromBox(loc, box, typeTy, rewriter, kTypePosInBox);
548e38ef2ffSValentin Clement     auto typePtrTy = mlir::LLVM::LLVMPointerType::get(typeTy);
549e38ef2ffSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(boxtypedesc, typePtrTy,
550e38ef2ffSValentin Clement                                                         result);
551e38ef2ffSValentin Clement     return success();
552e38ef2ffSValentin Clement   }
553e38ef2ffSValentin Clement };
554e38ef2ffSValentin Clement 
555ddd11b9aSAndrzej Warzynski // `fir.call` -> `llvm.call`
556ddd11b9aSAndrzej Warzynski struct CallOpConversion : public FIROpConversion<fir::CallOp> {
557ddd11b9aSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
558ddd11b9aSAndrzej Warzynski 
559ddd11b9aSAndrzej Warzynski   mlir::LogicalResult
560ddd11b9aSAndrzej Warzynski   matchAndRewrite(fir::CallOp call, OpAdaptor adaptor,
561ddd11b9aSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
562ddd11b9aSAndrzej Warzynski     SmallVector<mlir::Type> resultTys;
563ddd11b9aSAndrzej Warzynski     for (auto r : call.getResults())
564ddd11b9aSAndrzej Warzynski       resultTys.push_back(convertType(r.getType()));
565ddd11b9aSAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
566ddd11b9aSAndrzej Warzynski         call, resultTys, adaptor.getOperands(), call->getAttrs());
567ddd11b9aSAndrzej Warzynski     return success();
568ddd11b9aSAndrzej Warzynski   }
569ddd11b9aSAndrzej Warzynski };
570ddd11b9aSAndrzej Warzynski 
571092cee5fSValentin Clement static mlir::Type getComplexEleTy(mlir::Type complex) {
572092cee5fSValentin Clement   if (auto cc = complex.dyn_cast<mlir::ComplexType>())
573092cee5fSValentin Clement     return cc.getElementType();
574092cee5fSValentin Clement   return complex.cast<fir::ComplexType>().getElementType();
575092cee5fSValentin Clement }
576092cee5fSValentin Clement 
577f1dfc027SDiana Picus /// Compare complex values
578f1dfc027SDiana Picus ///
579f1dfc027SDiana Picus /// Per 10.1, the only comparisons available are .EQ. (oeq) and .NE. (une).
580f1dfc027SDiana Picus ///
581f1dfc027SDiana Picus /// For completeness, all other comparison are done on the real component only.
582f1dfc027SDiana Picus struct CmpcOpConversion : public FIROpConversion<fir::CmpcOp> {
583f1dfc027SDiana Picus   using FIROpConversion::FIROpConversion;
584f1dfc027SDiana Picus 
585f1dfc027SDiana Picus   mlir::LogicalResult
586f1dfc027SDiana Picus   matchAndRewrite(fir::CmpcOp cmp, OpAdaptor adaptor,
587f1dfc027SDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
588f1dfc027SDiana Picus     mlir::ValueRange operands = adaptor.getOperands();
589f1dfc027SDiana Picus     mlir::MLIRContext *ctxt = cmp.getContext();
590f1dfc027SDiana Picus     mlir::Type eleTy = convertType(getComplexEleTy(cmp.lhs().getType()));
591f1dfc027SDiana Picus     mlir::Type resTy = convertType(cmp.getType());
592f1dfc027SDiana Picus     mlir::Location loc = cmp.getLoc();
593f1dfc027SDiana Picus     auto pos0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0));
594f1dfc027SDiana Picus     SmallVector<mlir::Value, 2> rp{rewriter.create<mlir::LLVM::ExtractValueOp>(
595f1dfc027SDiana Picus                                        loc, eleTy, operands[0], pos0),
596f1dfc027SDiana Picus                                    rewriter.create<mlir::LLVM::ExtractValueOp>(
597f1dfc027SDiana Picus                                        loc, eleTy, operands[1], pos0)};
598f1dfc027SDiana Picus     auto rcp =
599f1dfc027SDiana Picus         rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, rp, cmp->getAttrs());
600f1dfc027SDiana Picus     auto pos1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1));
601f1dfc027SDiana Picus     SmallVector<mlir::Value, 2> ip{rewriter.create<mlir::LLVM::ExtractValueOp>(
602f1dfc027SDiana Picus                                        loc, eleTy, operands[0], pos1),
603f1dfc027SDiana Picus                                    rewriter.create<mlir::LLVM::ExtractValueOp>(
604f1dfc027SDiana Picus                                        loc, eleTy, operands[1], pos1)};
605f1dfc027SDiana Picus     auto icp =
606f1dfc027SDiana Picus         rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, ip, cmp->getAttrs());
607f1dfc027SDiana Picus     SmallVector<mlir::Value, 2> cp{rcp, icp};
608f1dfc027SDiana Picus     switch (cmp.getPredicate()) {
609f1dfc027SDiana Picus     case mlir::arith::CmpFPredicate::OEQ: // .EQ.
610f1dfc027SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(cmp, resTy, cp);
611f1dfc027SDiana Picus       break;
612f1dfc027SDiana Picus     case mlir::arith::CmpFPredicate::UNE: // .NE.
613f1dfc027SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(cmp, resTy, cp);
614f1dfc027SDiana Picus       break;
615f1dfc027SDiana Picus     default:
616f1dfc027SDiana Picus       rewriter.replaceOp(cmp, rcp.getResult());
617f1dfc027SDiana Picus       break;
618f1dfc027SDiana Picus     }
619f1dfc027SDiana Picus     return success();
620f1dfc027SDiana Picus   }
621f1dfc027SDiana Picus };
622f1dfc027SDiana Picus 
623e81d73edSDiana Picus /// Lower complex constants
624e81d73edSDiana Picus struct ConstcOpConversion : public FIROpConversion<fir::ConstcOp> {
625e81d73edSDiana Picus   using FIROpConversion::FIROpConversion;
626e81d73edSDiana Picus 
627e81d73edSDiana Picus   mlir::LogicalResult
628e81d73edSDiana Picus   matchAndRewrite(fir::ConstcOp conc, OpAdaptor,
629e81d73edSDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
630e81d73edSDiana Picus     mlir::Location loc = conc.getLoc();
631e81d73edSDiana Picus     mlir::MLIRContext *ctx = conc.getContext();
632e81d73edSDiana Picus     mlir::Type ty = convertType(conc.getType());
633e81d73edSDiana Picus     mlir::Type ety = convertType(getComplexEleTy(conc.getType()));
634e81d73edSDiana Picus     auto realFloatAttr = mlir::FloatAttr::get(ety, getValue(conc.getReal()));
635e81d73edSDiana Picus     auto realPart =
636e81d73edSDiana Picus         rewriter.create<mlir::LLVM::ConstantOp>(loc, ety, realFloatAttr);
637e81d73edSDiana Picus     auto imFloatAttr = mlir::FloatAttr::get(ety, getValue(conc.getImaginary()));
638e81d73edSDiana Picus     auto imPart =
639e81d73edSDiana Picus         rewriter.create<mlir::LLVM::ConstantOp>(loc, ety, imFloatAttr);
640e81d73edSDiana Picus     auto realIndex = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
641e81d73edSDiana Picus     auto imIndex = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
642e81d73edSDiana Picus     auto undef = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
643e81d73edSDiana Picus     auto setReal = rewriter.create<mlir::LLVM::InsertValueOp>(
644e81d73edSDiana Picus         loc, ty, undef, realPart, realIndex);
645e81d73edSDiana Picus     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(conc, ty, setReal,
646e81d73edSDiana Picus                                                            imPart, imIndex);
647e81d73edSDiana Picus     return success();
648e81d73edSDiana Picus   }
649e81d73edSDiana Picus 
650e81d73edSDiana Picus   inline APFloat getValue(mlir::Attribute attr) const {
651e81d73edSDiana Picus     return attr.cast<fir::RealAttr>().getValue();
652e81d73edSDiana Picus   }
653e81d73edSDiana Picus };
654e81d73edSDiana Picus 
655092cee5fSValentin Clement /// convert value of from-type to value of to-type
656092cee5fSValentin Clement struct ConvertOpConversion : public FIROpConversion<fir::ConvertOp> {
657092cee5fSValentin Clement   using FIROpConversion::FIROpConversion;
658092cee5fSValentin Clement 
659092cee5fSValentin Clement   static bool isFloatingPointTy(mlir::Type ty) {
660092cee5fSValentin Clement     return ty.isa<mlir::FloatType>();
661092cee5fSValentin Clement   }
662092cee5fSValentin Clement 
663092cee5fSValentin Clement   mlir::LogicalResult
664092cee5fSValentin Clement   matchAndRewrite(fir::ConvertOp convert, OpAdaptor adaptor,
665092cee5fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
666092cee5fSValentin Clement     auto fromTy = convertType(convert.value().getType());
667092cee5fSValentin Clement     auto toTy = convertType(convert.res().getType());
668092cee5fSValentin Clement     mlir::Value op0 = adaptor.getOperands()[0];
669092cee5fSValentin Clement     if (fromTy == toTy) {
670092cee5fSValentin Clement       rewriter.replaceOp(convert, op0);
671092cee5fSValentin Clement       return success();
672092cee5fSValentin Clement     }
673092cee5fSValentin Clement     auto loc = convert.getLoc();
674092cee5fSValentin Clement     auto convertFpToFp = [&](mlir::Value val, unsigned fromBits,
675092cee5fSValentin Clement                              unsigned toBits, mlir::Type toTy) -> mlir::Value {
676092cee5fSValentin Clement       if (fromBits == toBits) {
677092cee5fSValentin Clement         // TODO: Converting between two floating-point representations with the
678092cee5fSValentin Clement         // same bitwidth is not allowed for now.
679092cee5fSValentin Clement         mlir::emitError(loc,
680092cee5fSValentin Clement                         "cannot implicitly convert between two floating-point "
681092cee5fSValentin Clement                         "representations of the same bitwidth");
682092cee5fSValentin Clement         return {};
683092cee5fSValentin Clement       }
684092cee5fSValentin Clement       if (fromBits > toBits)
685092cee5fSValentin Clement         return rewriter.create<mlir::LLVM::FPTruncOp>(loc, toTy, val);
686092cee5fSValentin Clement       return rewriter.create<mlir::LLVM::FPExtOp>(loc, toTy, val);
687092cee5fSValentin Clement     };
688092cee5fSValentin Clement     // Complex to complex conversion.
689092cee5fSValentin Clement     if (fir::isa_complex(convert.value().getType()) &&
690092cee5fSValentin Clement         fir::isa_complex(convert.res().getType())) {
691092cee5fSValentin Clement       // Special case: handle the conversion of a complex such that both the
692092cee5fSValentin Clement       // real and imaginary parts are converted together.
693092cee5fSValentin Clement       auto zero = mlir::ArrayAttr::get(convert.getContext(),
694092cee5fSValentin Clement                                        rewriter.getI32IntegerAttr(0));
695092cee5fSValentin Clement       auto one = mlir::ArrayAttr::get(convert.getContext(),
696092cee5fSValentin Clement                                       rewriter.getI32IntegerAttr(1));
697092cee5fSValentin Clement       auto ty = convertType(getComplexEleTy(convert.value().getType()));
698092cee5fSValentin Clement       auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, zero);
699092cee5fSValentin Clement       auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, one);
700092cee5fSValentin Clement       auto nt = convertType(getComplexEleTy(convert.res().getType()));
701092cee5fSValentin Clement       auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
702092cee5fSValentin Clement       auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(nt);
703092cee5fSValentin Clement       auto rc = convertFpToFp(rp, fromBits, toBits, nt);
704092cee5fSValentin Clement       auto ic = convertFpToFp(ip, fromBits, toBits, nt);
705092cee5fSValentin Clement       auto un = rewriter.create<mlir::LLVM::UndefOp>(loc, toTy);
706092cee5fSValentin Clement       auto i1 =
707092cee5fSValentin Clement           rewriter.create<mlir::LLVM::InsertValueOp>(loc, toTy, un, rc, zero);
708092cee5fSValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(convert, toTy, i1,
709092cee5fSValentin Clement                                                              ic, one);
710092cee5fSValentin Clement       return mlir::success();
711092cee5fSValentin Clement     }
712092cee5fSValentin Clement     // Floating point to floating point conversion.
713092cee5fSValentin Clement     if (isFloatingPointTy(fromTy)) {
714092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
715092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
716092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
717092cee5fSValentin Clement         auto v = convertFpToFp(op0, fromBits, toBits, toTy);
718092cee5fSValentin Clement         rewriter.replaceOp(convert, v);
719092cee5fSValentin Clement         return mlir::success();
720092cee5fSValentin Clement       }
721092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
722092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::FPToSIOp>(convert, toTy, op0);
723092cee5fSValentin Clement         return mlir::success();
724092cee5fSValentin Clement       }
725092cee5fSValentin Clement     } else if (fromTy.isa<mlir::IntegerType>()) {
726092cee5fSValentin Clement       // Integer to integer conversion.
727092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
728092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
729092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
730092cee5fSValentin Clement         assert(fromBits != toBits);
731092cee5fSValentin Clement         if (fromBits > toBits) {
732092cee5fSValentin Clement           rewriter.replaceOpWithNewOp<mlir::LLVM::TruncOp>(convert, toTy, op0);
733092cee5fSValentin Clement           return mlir::success();
734092cee5fSValentin Clement         }
735092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SExtOp>(convert, toTy, op0);
736092cee5fSValentin Clement         return mlir::success();
737092cee5fSValentin Clement       }
738092cee5fSValentin Clement       // Integer to floating point conversion.
739092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
740092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SIToFPOp>(convert, toTy, op0);
741092cee5fSValentin Clement         return mlir::success();
742092cee5fSValentin Clement       }
743092cee5fSValentin Clement       // Integer to pointer conversion.
744092cee5fSValentin Clement       if (toTy.isa<mlir::LLVM::LLVMPointerType>()) {
745092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(convert, toTy, op0);
746092cee5fSValentin Clement         return mlir::success();
747092cee5fSValentin Clement       }
748092cee5fSValentin Clement     } else if (fromTy.isa<mlir::LLVM::LLVMPointerType>()) {
749092cee5fSValentin Clement       // Pointer to integer conversion.
750092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
751092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::PtrToIntOp>(convert, toTy, op0);
752092cee5fSValentin Clement         return mlir::success();
753092cee5fSValentin Clement       }
754092cee5fSValentin Clement       // Pointer to pointer conversion.
755092cee5fSValentin Clement       if (toTy.isa<mlir::LLVM::LLVMPointerType>()) {
756092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(convert, toTy, op0);
757092cee5fSValentin Clement         return mlir::success();
758092cee5fSValentin Clement       }
759092cee5fSValentin Clement     }
760092cee5fSValentin Clement     return emitError(loc) << "cannot convert " << fromTy << " to " << toTy;
761092cee5fSValentin Clement   }
762092cee5fSValentin Clement };
763092cee5fSValentin Clement 
7649534e361SValentin Clement /// Lower `fir.dispatch` operation. A virtual call to a method in a dispatch
7659534e361SValentin Clement /// table.
7669534e361SValentin Clement struct DispatchOpConversion : public FIROpConversion<fir::DispatchOp> {
7679534e361SValentin Clement   using FIROpConversion::FIROpConversion;
7689534e361SValentin Clement 
7699534e361SValentin Clement   mlir::LogicalResult
7709534e361SValentin Clement   matchAndRewrite(fir::DispatchOp dispatch, OpAdaptor adaptor,
7719534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
7729534e361SValentin Clement     return rewriter.notifyMatchFailure(
7739534e361SValentin Clement         dispatch, "fir.dispatch codegen is not implemented yet");
7749534e361SValentin Clement   }
7759534e361SValentin Clement };
7769534e361SValentin Clement 
7779534e361SValentin Clement /// Lower `fir.dispatch_table` operation. The dispatch table for a Fortran
7789534e361SValentin Clement /// derived type.
7799534e361SValentin Clement struct DispatchTableOpConversion
7809534e361SValentin Clement     : public FIROpConversion<fir::DispatchTableOp> {
7819534e361SValentin Clement   using FIROpConversion::FIROpConversion;
7829534e361SValentin Clement 
7839534e361SValentin Clement   mlir::LogicalResult
7849534e361SValentin Clement   matchAndRewrite(fir::DispatchTableOp dispTab, OpAdaptor adaptor,
7859534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
7869534e361SValentin Clement     return rewriter.notifyMatchFailure(
7879534e361SValentin Clement         dispTab, "fir.dispatch_table codegen is not implemented yet");
7889534e361SValentin Clement   }
7899534e361SValentin Clement };
7909534e361SValentin Clement 
7919534e361SValentin Clement /// Lower `fir.dt_entry` operation. An entry in a dispatch table; binds a
7929534e361SValentin Clement /// method-name to a function.
7939534e361SValentin Clement struct DTEntryOpConversion : public FIROpConversion<fir::DTEntryOp> {
7949534e361SValentin Clement   using FIROpConversion::FIROpConversion;
7959534e361SValentin Clement 
7969534e361SValentin Clement   mlir::LogicalResult
7979534e361SValentin Clement   matchAndRewrite(fir::DTEntryOp dtEnt, OpAdaptor adaptor,
7989534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
7999534e361SValentin Clement     return rewriter.notifyMatchFailure(
8009534e361SValentin Clement         dtEnt, "fir.dt_entry codegen is not implemented yet");
8019534e361SValentin Clement   }
8029534e361SValentin Clement };
8039534e361SValentin Clement 
804677df8c7SValentin Clement /// Lower `fir.global_len` operation.
805677df8c7SValentin Clement struct GlobalLenOpConversion : public FIROpConversion<fir::GlobalLenOp> {
806677df8c7SValentin Clement   using FIROpConversion::FIROpConversion;
807677df8c7SValentin Clement 
808677df8c7SValentin Clement   mlir::LogicalResult
809677df8c7SValentin Clement   matchAndRewrite(fir::GlobalLenOp globalLen, OpAdaptor adaptor,
810677df8c7SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
811677df8c7SValentin Clement     return rewriter.notifyMatchFailure(
812677df8c7SValentin Clement         globalLen, "fir.global_len codegen is not implemented yet");
813677df8c7SValentin Clement   }
814677df8c7SValentin Clement };
815677df8c7SValentin Clement 
81631246187SValentin Clement /// Lower `fir.gentypedesc` to a global constant.
81731246187SValentin Clement struct GenTypeDescOpConversion : public FIROpConversion<fir::GenTypeDescOp> {
81831246187SValentin Clement   using FIROpConversion::FIROpConversion;
81931246187SValentin Clement 
82031246187SValentin Clement   mlir::LogicalResult
82131246187SValentin Clement   matchAndRewrite(fir::GenTypeDescOp gentypedesc, OpAdaptor adaptor,
82231246187SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
82331246187SValentin Clement     return rewriter.notifyMatchFailure(
82431246187SValentin Clement         gentypedesc, "fir.fir.gentypedesc codegen is not implemented yet");
82531246187SValentin Clement   }
82631246187SValentin Clement };
82731246187SValentin Clement 
8280c4a7a52SValentin Clement /// Lower `fir.has_value` operation to `llvm.return` operation.
829044d5b5dSValentin Clement struct HasValueOpConversion : public FIROpConversion<fir::HasValueOp> {
830044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
831044d5b5dSValentin Clement 
832044d5b5dSValentin Clement   mlir::LogicalResult
833044d5b5dSValentin Clement   matchAndRewrite(fir::HasValueOp op, OpAdaptor adaptor,
834044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
835044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, adaptor.getOperands());
836044d5b5dSValentin Clement     return success();
837044d5b5dSValentin Clement   }
838044d5b5dSValentin Clement };
839044d5b5dSValentin Clement 
8400c4a7a52SValentin Clement /// Lower `fir.global` operation to `llvm.global` operation.
8410c4a7a52SValentin Clement /// `fir.insert_on_range` operations are replaced with constant dense attribute
8420c4a7a52SValentin Clement /// if they are applied on the full range.
843044d5b5dSValentin Clement struct GlobalOpConversion : public FIROpConversion<fir::GlobalOp> {
844044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
845044d5b5dSValentin Clement 
846044d5b5dSValentin Clement   mlir::LogicalResult
847044d5b5dSValentin Clement   matchAndRewrite(fir::GlobalOp global, OpAdaptor adaptor,
848044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
849044d5b5dSValentin Clement     auto tyAttr = convertType(global.getType());
850044d5b5dSValentin Clement     if (global.getType().isa<fir::BoxType>())
851044d5b5dSValentin Clement       tyAttr = tyAttr.cast<mlir::LLVM::LLVMPointerType>().getElementType();
852044d5b5dSValentin Clement     auto loc = global.getLoc();
853044d5b5dSValentin Clement     mlir::Attribute initAttr{};
854044d5b5dSValentin Clement     if (global.initVal())
855044d5b5dSValentin Clement       initAttr = global.initVal().getValue();
856044d5b5dSValentin Clement     auto linkage = convertLinkage(global.linkName());
857044d5b5dSValentin Clement     auto isConst = global.constant().hasValue();
858044d5b5dSValentin Clement     auto g = rewriter.create<mlir::LLVM::GlobalOp>(
859044d5b5dSValentin Clement         loc, tyAttr, isConst, linkage, global.sym_name(), initAttr);
860044d5b5dSValentin Clement     auto &gr = g.getInitializerRegion();
861044d5b5dSValentin Clement     rewriter.inlineRegionBefore(global.region(), gr, gr.end());
862044d5b5dSValentin Clement     if (!gr.empty()) {
863044d5b5dSValentin Clement       // Replace insert_on_range with a constant dense attribute if the
864044d5b5dSValentin Clement       // initialization is on the full range.
865044d5b5dSValentin Clement       auto insertOnRangeOps = gr.front().getOps<fir::InsertOnRangeOp>();
866044d5b5dSValentin Clement       for (auto insertOp : insertOnRangeOps) {
867044d5b5dSValentin Clement         if (isFullRange(insertOp.coor(), insertOp.getType())) {
868044d5b5dSValentin Clement           auto seqTyAttr = convertType(insertOp.getType());
869044d5b5dSValentin Clement           auto *op = insertOp.val().getDefiningOp();
870044d5b5dSValentin Clement           auto constant = mlir::dyn_cast<mlir::arith::ConstantOp>(op);
871044d5b5dSValentin Clement           if (!constant) {
872044d5b5dSValentin Clement             auto convertOp = mlir::dyn_cast<fir::ConvertOp>(op);
873044d5b5dSValentin Clement             if (!convertOp)
874044d5b5dSValentin Clement               continue;
875044d5b5dSValentin Clement             constant = cast<mlir::arith::ConstantOp>(
876044d5b5dSValentin Clement                 convertOp.value().getDefiningOp());
877044d5b5dSValentin Clement           }
878044d5b5dSValentin Clement           mlir::Type vecType = mlir::VectorType::get(
879044d5b5dSValentin Clement               insertOp.getType().getShape(), constant.getType());
880044d5b5dSValentin Clement           auto denseAttr = mlir::DenseElementsAttr::get(
881044d5b5dSValentin Clement               vecType.cast<ShapedType>(), constant.value());
882044d5b5dSValentin Clement           rewriter.setInsertionPointAfter(insertOp);
883044d5b5dSValentin Clement           rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(
884044d5b5dSValentin Clement               insertOp, seqTyAttr, denseAttr);
885044d5b5dSValentin Clement         }
886044d5b5dSValentin Clement       }
887044d5b5dSValentin Clement     }
888044d5b5dSValentin Clement     rewriter.eraseOp(global);
889044d5b5dSValentin Clement     return success();
890044d5b5dSValentin Clement   }
891044d5b5dSValentin Clement 
892044d5b5dSValentin Clement   bool isFullRange(mlir::ArrayAttr indexes, fir::SequenceType seqTy) const {
893044d5b5dSValentin Clement     auto extents = seqTy.getShape();
894044d5b5dSValentin Clement     if (indexes.size() / 2 != extents.size())
895044d5b5dSValentin Clement       return false;
896044d5b5dSValentin Clement     for (unsigned i = 0; i < indexes.size(); i += 2) {
897044d5b5dSValentin Clement       if (indexes[i].cast<IntegerAttr>().getInt() != 0)
898044d5b5dSValentin Clement         return false;
899044d5b5dSValentin Clement       if (indexes[i + 1].cast<IntegerAttr>().getInt() != extents[i / 2] - 1)
900044d5b5dSValentin Clement         return false;
901044d5b5dSValentin Clement     }
902044d5b5dSValentin Clement     return true;
903044d5b5dSValentin Clement   }
904044d5b5dSValentin Clement 
9050c4a7a52SValentin Clement   // TODO: String comparaison should be avoided. Replace linkName with an
9060c4a7a52SValentin Clement   // enumeration.
907044d5b5dSValentin Clement   mlir::LLVM::Linkage convertLinkage(Optional<StringRef> optLinkage) const {
908044d5b5dSValentin Clement     if (optLinkage.hasValue()) {
909044d5b5dSValentin Clement       auto name = optLinkage.getValue();
910044d5b5dSValentin Clement       if (name == "internal")
911044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Internal;
912044d5b5dSValentin Clement       if (name == "linkonce")
913044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Linkonce;
914044d5b5dSValentin Clement       if (name == "common")
915044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Common;
916044d5b5dSValentin Clement       if (name == "weak")
917044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Weak;
918044d5b5dSValentin Clement     }
919044d5b5dSValentin Clement     return mlir::LLVM::Linkage::External;
920044d5b5dSValentin Clement   }
921044d5b5dSValentin Clement };
922044d5b5dSValentin Clement 
92339f4ef81SValentin Clement void genCondBrOp(mlir::Location loc, mlir::Value cmp, mlir::Block *dest,
92439f4ef81SValentin Clement                  Optional<mlir::ValueRange> destOps,
92539f4ef81SValentin Clement                  mlir::ConversionPatternRewriter &rewriter,
92639f4ef81SValentin Clement                  mlir::Block *newBlock) {
92739f4ef81SValentin Clement   if (destOps.hasValue())
92839f4ef81SValentin Clement     rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, destOps.getValue(),
92939f4ef81SValentin Clement                                           newBlock, mlir::ValueRange());
93039f4ef81SValentin Clement   else
93139f4ef81SValentin Clement     rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, newBlock);
93239f4ef81SValentin Clement }
93339f4ef81SValentin Clement 
93439f4ef81SValentin Clement template <typename A, typename B>
93539f4ef81SValentin Clement void genBrOp(A caseOp, mlir::Block *dest, Optional<B> destOps,
93639f4ef81SValentin Clement              mlir::ConversionPatternRewriter &rewriter) {
93739f4ef81SValentin Clement   if (destOps.hasValue())
93839f4ef81SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, destOps.getValue(),
93939f4ef81SValentin Clement                                                   dest);
94039f4ef81SValentin Clement   else
94139f4ef81SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, llvm::None, dest);
94239f4ef81SValentin Clement }
94339f4ef81SValentin Clement 
94439f4ef81SValentin Clement void genCaseLadderStep(mlir::Location loc, mlir::Value cmp, mlir::Block *dest,
94539f4ef81SValentin Clement                        Optional<mlir::ValueRange> destOps,
94639f4ef81SValentin Clement                        mlir::ConversionPatternRewriter &rewriter) {
94739f4ef81SValentin Clement   auto *thisBlock = rewriter.getInsertionBlock();
94839f4ef81SValentin Clement   auto *newBlock = createBlock(rewriter, dest);
94939f4ef81SValentin Clement   rewriter.setInsertionPointToEnd(thisBlock);
95039f4ef81SValentin Clement   genCondBrOp(loc, cmp, dest, destOps, rewriter, newBlock);
95139f4ef81SValentin Clement   rewriter.setInsertionPointToEnd(newBlock);
95239f4ef81SValentin Clement }
95339f4ef81SValentin Clement 
95439f4ef81SValentin Clement /// Conversion of `fir.select_case`
95539f4ef81SValentin Clement ///
95639f4ef81SValentin Clement /// The `fir.select_case` operation is converted to a if-then-else ladder.
95739f4ef81SValentin Clement /// Depending on the case condition type, one or several comparison and
95839f4ef81SValentin Clement /// conditional branching can be generated.
95939f4ef81SValentin Clement ///
96039f4ef81SValentin Clement /// A a point value case such as `case(4)`, a lower bound case such as
96139f4ef81SValentin Clement /// `case(5:)` or an upper bound case such as `case(:3)` are converted to a
96239f4ef81SValentin Clement /// simple comparison between the selector value and the constant value in the
96339f4ef81SValentin Clement /// case. The block associated with the case condition is then executed if
96439f4ef81SValentin Clement /// the comparison succeed otherwise it branch to the next block with the
96539f4ef81SValentin Clement /// comparison for the the next case conditon.
96639f4ef81SValentin Clement ///
96739f4ef81SValentin Clement /// A closed interval case condition such as `case(7:10)` is converted with a
96839f4ef81SValentin Clement /// first comparison and conditional branching for the lower bound. If
96939f4ef81SValentin Clement /// successful, it branch to a second block with the comparison for the
97039f4ef81SValentin Clement /// upper bound in the same case condition.
97139f4ef81SValentin Clement ///
97239f4ef81SValentin Clement /// TODO: lowering of CHARACTER type cases is not handled yet.
97339f4ef81SValentin Clement struct SelectCaseOpConversion : public FIROpConversion<fir::SelectCaseOp> {
97439f4ef81SValentin Clement   using FIROpConversion::FIROpConversion;
97539f4ef81SValentin Clement 
97639f4ef81SValentin Clement   mlir::LogicalResult
97739f4ef81SValentin Clement   matchAndRewrite(fir::SelectCaseOp caseOp, OpAdaptor adaptor,
97839f4ef81SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
97939f4ef81SValentin Clement     unsigned conds = caseOp.getNumConditions();
98039f4ef81SValentin Clement     llvm::ArrayRef<mlir::Attribute> cases = caseOp.getCases().getValue();
98139f4ef81SValentin Clement     // Type can be CHARACTER, INTEGER, or LOGICAL (C1145)
98239f4ef81SValentin Clement     LLVM_ATTRIBUTE_UNUSED auto ty = caseOp.getSelector().getType();
98339f4ef81SValentin Clement     if (ty.isa<fir::CharacterType>())
98439f4ef81SValentin Clement       return rewriter.notifyMatchFailure(caseOp,
98539f4ef81SValentin Clement                                          "conversion of fir.select_case with "
98639f4ef81SValentin Clement                                          "character type not implemented yet");
98739f4ef81SValentin Clement     mlir::Value selector = caseOp.getSelector(adaptor.getOperands());
98839f4ef81SValentin Clement     auto loc = caseOp.getLoc();
98939f4ef81SValentin Clement     for (unsigned t = 0; t != conds; ++t) {
99039f4ef81SValentin Clement       mlir::Block *dest = caseOp.getSuccessor(t);
99139f4ef81SValentin Clement       llvm::Optional<mlir::ValueRange> destOps =
99239f4ef81SValentin Clement           caseOp.getSuccessorOperands(adaptor.getOperands(), t);
99339f4ef81SValentin Clement       llvm::Optional<mlir::ValueRange> cmpOps =
99439f4ef81SValentin Clement           *caseOp.getCompareOperands(adaptor.getOperands(), t);
99539f4ef81SValentin Clement       mlir::Value caseArg = *(cmpOps.getValue().begin());
99639f4ef81SValentin Clement       mlir::Attribute attr = cases[t];
99739f4ef81SValentin Clement       if (attr.isa<fir::PointIntervalAttr>()) {
99839f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
99939f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::eq, selector, caseArg);
100039f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
100139f4ef81SValentin Clement         continue;
100239f4ef81SValentin Clement       }
100339f4ef81SValentin Clement       if (attr.isa<fir::LowerBoundAttr>()) {
100439f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
100539f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector);
100639f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
100739f4ef81SValentin Clement         continue;
100839f4ef81SValentin Clement       }
100939f4ef81SValentin Clement       if (attr.isa<fir::UpperBoundAttr>()) {
101039f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
101139f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg);
101239f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
101339f4ef81SValentin Clement         continue;
101439f4ef81SValentin Clement       }
101539f4ef81SValentin Clement       if (attr.isa<fir::ClosedIntervalAttr>()) {
101639f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
101739f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector);
101839f4ef81SValentin Clement         auto *thisBlock = rewriter.getInsertionBlock();
101939f4ef81SValentin Clement         auto *newBlock1 = createBlock(rewriter, dest);
102039f4ef81SValentin Clement         auto *newBlock2 = createBlock(rewriter, dest);
102139f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(thisBlock);
102239f4ef81SValentin Clement         rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, newBlock1, newBlock2);
102339f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(newBlock1);
102439f4ef81SValentin Clement         mlir::Value caseArg0 = *(cmpOps.getValue().begin() + 1);
102539f4ef81SValentin Clement         auto cmp0 = rewriter.create<mlir::LLVM::ICmpOp>(
102639f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg0);
102739f4ef81SValentin Clement         genCondBrOp(loc, cmp0, dest, destOps, rewriter, newBlock2);
102839f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(newBlock2);
102939f4ef81SValentin Clement         continue;
103039f4ef81SValentin Clement       }
103139f4ef81SValentin Clement       assert(attr.isa<mlir::UnitAttr>());
103239f4ef81SValentin Clement       assert((t + 1 == conds) && "unit must be last");
103339f4ef81SValentin Clement       genBrOp(caseOp, dest, destOps, rewriter);
103439f4ef81SValentin Clement     }
103539f4ef81SValentin Clement     return success();
103639f4ef81SValentin Clement   }
103739f4ef81SValentin Clement };
103839f4ef81SValentin Clement 
10398c239909SValentin Clement template <typename OP>
10408c239909SValentin Clement void selectMatchAndRewrite(fir::LLVMTypeConverter &lowering, OP select,
10418c239909SValentin Clement                            typename OP::Adaptor adaptor,
10428c239909SValentin Clement                            mlir::ConversionPatternRewriter &rewriter) {
10438c239909SValentin Clement   unsigned conds = select.getNumConditions();
10448c239909SValentin Clement   auto cases = select.getCases().getValue();
10458c239909SValentin Clement   mlir::Value selector = adaptor.selector();
10468c239909SValentin Clement   auto loc = select.getLoc();
10478c239909SValentin Clement   assert(conds > 0 && "select must have cases");
10488c239909SValentin Clement 
10498c239909SValentin Clement   llvm::SmallVector<mlir::Block *> destinations;
10508c239909SValentin Clement   llvm::SmallVector<mlir::ValueRange> destinationsOperands;
10518c239909SValentin Clement   mlir::Block *defaultDestination;
10528c239909SValentin Clement   mlir::ValueRange defaultOperands;
10538c239909SValentin Clement   llvm::SmallVector<int32_t> caseValues;
10548c239909SValentin Clement 
10558c239909SValentin Clement   for (unsigned t = 0; t != conds; ++t) {
10568c239909SValentin Clement     mlir::Block *dest = select.getSuccessor(t);
10578c239909SValentin Clement     auto destOps = select.getSuccessorOperands(adaptor.getOperands(), t);
10588c239909SValentin Clement     const mlir::Attribute &attr = cases[t];
10598c239909SValentin Clement     if (auto intAttr = attr.template dyn_cast<mlir::IntegerAttr>()) {
10608c239909SValentin Clement       destinations.push_back(dest);
10618c239909SValentin Clement       destinationsOperands.push_back(destOps.hasValue() ? *destOps
10628c239909SValentin Clement                                                         : ValueRange());
10638c239909SValentin Clement       caseValues.push_back(intAttr.getInt());
10648c239909SValentin Clement       continue;
10658c239909SValentin Clement     }
10668c239909SValentin Clement     assert(attr.template dyn_cast_or_null<mlir::UnitAttr>());
10678c239909SValentin Clement     assert((t + 1 == conds) && "unit must be last");
10688c239909SValentin Clement     defaultDestination = dest;
10698c239909SValentin Clement     defaultOperands = destOps.hasValue() ? *destOps : ValueRange();
10708c239909SValentin Clement   }
10718c239909SValentin Clement 
10728c239909SValentin Clement   // LLVM::SwitchOp takes a i32 type for the selector.
10738c239909SValentin Clement   if (select.getSelector().getType() != rewriter.getI32Type())
10748c239909SValentin Clement     selector =
10758c239909SValentin Clement         rewriter.create<LLVM::TruncOp>(loc, rewriter.getI32Type(), selector);
10768c239909SValentin Clement 
10778c239909SValentin Clement   rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>(
10788c239909SValentin Clement       select, selector,
10798c239909SValentin Clement       /*defaultDestination=*/defaultDestination,
10808c239909SValentin Clement       /*defaultOperands=*/defaultOperands,
10818c239909SValentin Clement       /*caseValues=*/caseValues,
10828c239909SValentin Clement       /*caseDestinations=*/destinations,
10838c239909SValentin Clement       /*caseOperands=*/destinationsOperands,
10848c239909SValentin Clement       /*branchWeights=*/ArrayRef<int32_t>());
10858c239909SValentin Clement }
10868c239909SValentin Clement 
10878c239909SValentin Clement /// conversion of fir::SelectOp to an if-then-else ladder
10888c239909SValentin Clement struct SelectOpConversion : public FIROpConversion<fir::SelectOp> {
10898c239909SValentin Clement   using FIROpConversion::FIROpConversion;
10908c239909SValentin Clement 
10918c239909SValentin Clement   mlir::LogicalResult
10928c239909SValentin Clement   matchAndRewrite(fir::SelectOp op, OpAdaptor adaptor,
10938c239909SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
10948c239909SValentin Clement     selectMatchAndRewrite<fir::SelectOp>(lowerTy(), op, adaptor, rewriter);
10958c239909SValentin Clement     return success();
10968c239909SValentin Clement   }
10978c239909SValentin Clement };
10988c239909SValentin Clement 
1099e3349fa1SAndrzej Warzynski /// `fir.load` --> `llvm.load`
1100e3349fa1SAndrzej Warzynski struct LoadOpConversion : public FIROpConversion<fir::LoadOp> {
1101e3349fa1SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
1102e3349fa1SAndrzej Warzynski 
1103e3349fa1SAndrzej Warzynski   mlir::LogicalResult
1104e3349fa1SAndrzej Warzynski   matchAndRewrite(fir::LoadOp load, OpAdaptor adaptor,
1105e3349fa1SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
1106e3349fa1SAndrzej Warzynski     // fir.box is a special case because it is considered as an ssa values in
1107e3349fa1SAndrzej Warzynski     // fir, but it is lowered as a pointer to a descriptor. So fir.ref<fir.box>
1108e3349fa1SAndrzej Warzynski     // and fir.box end up being the same llvm types and loading a
1109e3349fa1SAndrzej Warzynski     // fir.ref<fir.box> is actually a no op in LLVM.
1110e3349fa1SAndrzej Warzynski     if (load.getType().isa<fir::BoxType>()) {
1111e3349fa1SAndrzej Warzynski       rewriter.replaceOp(load, adaptor.getOperands()[0]);
1112e3349fa1SAndrzej Warzynski     } else {
1113e3349fa1SAndrzej Warzynski       mlir::Type ty = convertType(load.getType());
1114e3349fa1SAndrzej Warzynski       ArrayRef<NamedAttribute> at = load->getAttrs();
1115e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::LoadOp>(
1116e3349fa1SAndrzej Warzynski           load, ty, adaptor.getOperands(), at);
1117e3349fa1SAndrzej Warzynski     }
1118e3349fa1SAndrzej Warzynski     return success();
1119e3349fa1SAndrzej Warzynski   }
1120e3349fa1SAndrzej Warzynski };
1121e3349fa1SAndrzej Warzynski 
11222a299e4fSValentin Clement /// Lower `fir.select_type` to LLVM IR dialect.
11232a299e4fSValentin Clement struct SelectTypeOpConversion : public FIROpConversion<fir::SelectTypeOp> {
11242a299e4fSValentin Clement   using FIROpConversion::FIROpConversion;
11252a299e4fSValentin Clement 
11262a299e4fSValentin Clement   mlir::LogicalResult
11272a299e4fSValentin Clement   matchAndRewrite(fir::SelectTypeOp select, OpAdaptor adaptor,
11282a299e4fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
11292a299e4fSValentin Clement     return rewriter.notifyMatchFailure(
11302a299e4fSValentin Clement         select, "fir.select_type codegen is not implemented yet");
11312a299e4fSValentin Clement   }
11322a299e4fSValentin Clement };
11332a299e4fSValentin Clement 
11348c239909SValentin Clement /// conversion of fir::SelectRankOp to an if-then-else ladder
11358c239909SValentin Clement struct SelectRankOpConversion : public FIROpConversion<fir::SelectRankOp> {
11368c239909SValentin Clement   using FIROpConversion::FIROpConversion;
11378c239909SValentin Clement 
11388c239909SValentin Clement   mlir::LogicalResult
11398c239909SValentin Clement   matchAndRewrite(fir::SelectRankOp op, OpAdaptor adaptor,
11408c239909SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
11418c239909SValentin Clement     selectMatchAndRewrite<fir::SelectRankOp>(lowerTy(), op, adaptor, rewriter);
11428c239909SValentin Clement     return success();
11438c239909SValentin Clement   }
11448c239909SValentin Clement };
11458c239909SValentin Clement 
1146e3349fa1SAndrzej Warzynski /// `fir.store` --> `llvm.store`
1147e3349fa1SAndrzej Warzynski struct StoreOpConversion : public FIROpConversion<fir::StoreOp> {
1148e3349fa1SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
1149e3349fa1SAndrzej Warzynski 
1150e3349fa1SAndrzej Warzynski   mlir::LogicalResult
1151e3349fa1SAndrzej Warzynski   matchAndRewrite(fir::StoreOp store, OpAdaptor adaptor,
1152e3349fa1SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
1153e3349fa1SAndrzej Warzynski     if (store.value().getType().isa<fir::BoxType>()) {
1154e3349fa1SAndrzej Warzynski       // fir.box value is actually in memory, load it first before storing it.
1155e3349fa1SAndrzej Warzynski       mlir::Location loc = store.getLoc();
1156e3349fa1SAndrzej Warzynski       mlir::Type boxPtrTy = adaptor.getOperands()[0].getType();
1157e3349fa1SAndrzej Warzynski       auto val = rewriter.create<mlir::LLVM::LoadOp>(
1158e3349fa1SAndrzej Warzynski           loc, boxPtrTy.cast<mlir::LLVM::LLVMPointerType>().getElementType(),
1159e3349fa1SAndrzej Warzynski           adaptor.getOperands()[0]);
1160e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
1161e3349fa1SAndrzej Warzynski           store, val, adaptor.getOperands()[1]);
1162e3349fa1SAndrzej Warzynski     } else {
1163e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
1164e3349fa1SAndrzej Warzynski           store, adaptor.getOperands()[0], adaptor.getOperands()[1]);
1165e3349fa1SAndrzej Warzynski     }
1166e3349fa1SAndrzej Warzynski     return success();
1167e3349fa1SAndrzej Warzynski   }
1168e3349fa1SAndrzej Warzynski };
1169e3349fa1SAndrzej Warzynski 
1170e3349fa1SAndrzej Warzynski /// convert to LLVM IR dialect `undef`
1171044d5b5dSValentin Clement struct UndefOpConversion : public FIROpConversion<fir::UndefOp> {
1172044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
1173044d5b5dSValentin Clement 
1174044d5b5dSValentin Clement   mlir::LogicalResult
1175044d5b5dSValentin Clement   matchAndRewrite(fir::UndefOp undef, OpAdaptor,
1176044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1177044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::UndefOp>(
1178044d5b5dSValentin Clement         undef, convertType(undef.getType()));
1179044d5b5dSValentin Clement     return success();
1180044d5b5dSValentin Clement   }
1181044d5b5dSValentin Clement };
1182a7a61359SValentin Clement 
1183e3349fa1SAndrzej Warzynski /// `fir.unreachable` --> `llvm.unreachable`
118432e08248SAndrzej Warzynski struct UnreachableOpConversion : public FIROpConversion<fir::UnreachableOp> {
118532e08248SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
118632e08248SAndrzej Warzynski 
118732e08248SAndrzej Warzynski   mlir::LogicalResult
118832e08248SAndrzej Warzynski   matchAndRewrite(fir::UnreachableOp unreach, OpAdaptor adaptor,
118932e08248SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
119032e08248SAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(unreach);
119132e08248SAndrzej Warzynski     return success();
119232e08248SAndrzej Warzynski   }
119332e08248SAndrzej Warzynski };
119432e08248SAndrzej Warzynski 
1195a7a61359SValentin Clement struct ZeroOpConversion : public FIROpConversion<fir::ZeroOp> {
1196a7a61359SValentin Clement   using FIROpConversion::FIROpConversion;
1197a7a61359SValentin Clement 
1198a7a61359SValentin Clement   mlir::LogicalResult
1199a7a61359SValentin Clement   matchAndRewrite(fir::ZeroOp zero, OpAdaptor,
1200a7a61359SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1201a7a61359SValentin Clement     auto ty = convertType(zero.getType());
1202a7a61359SValentin Clement     if (ty.isa<mlir::LLVM::LLVMPointerType>()) {
1203a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(zero, ty);
1204a7a61359SValentin Clement     } else if (ty.isa<mlir::IntegerType>()) {
1205a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
1206a7a61359SValentin Clement           zero, ty, mlir::IntegerAttr::get(zero.getType(), 0));
1207a7a61359SValentin Clement     } else if (mlir::LLVM::isCompatibleFloatingPointType(ty)) {
1208a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
1209a7a61359SValentin Clement           zero, ty, mlir::FloatAttr::get(zero.getType(), 0.0));
1210a7a61359SValentin Clement     } else {
1211a7a61359SValentin Clement       // TODO: create ConstantAggregateZero for FIR aggregate/array types.
121252d813edSValentin Clement       return rewriter.notifyMatchFailure(
121352d813edSValentin Clement           zero,
1214a7a61359SValentin Clement           "conversion of fir.zero with aggregate type not implemented yet");
1215a7a61359SValentin Clement     }
1216a7a61359SValentin Clement     return success();
1217a7a61359SValentin Clement   }
1218a7a61359SValentin Clement };
121932e08248SAndrzej Warzynski 
1220*af6ee580SValentin Clement /// Common base class for embox to descriptor conversion.
1221*af6ee580SValentin Clement template <typename OP>
1222*af6ee580SValentin Clement struct EmboxCommonConversion : public FIROpConversion<OP> {
1223*af6ee580SValentin Clement   using FIROpConversion<OP>::FIROpConversion;
1224*af6ee580SValentin Clement 
1225*af6ee580SValentin Clement   // Find the LLVMFuncOp in whose entry block the alloca should be inserted.
1226*af6ee580SValentin Clement   // The order to find the LLVMFuncOp is as follows:
1227*af6ee580SValentin Clement   // 1. The parent operation of the current block if it is a LLVMFuncOp.
1228*af6ee580SValentin Clement   // 2. The first ancestor that is a LLVMFuncOp.
1229*af6ee580SValentin Clement   mlir::LLVM::LLVMFuncOp
1230*af6ee580SValentin Clement   getFuncForAllocaInsert(mlir::ConversionPatternRewriter &rewriter) const {
1231*af6ee580SValentin Clement     mlir::Operation *parentOp = rewriter.getInsertionBlock()->getParentOp();
1232*af6ee580SValentin Clement     return mlir::isa<mlir::LLVM::LLVMFuncOp>(parentOp)
1233*af6ee580SValentin Clement                ? mlir::cast<mlir::LLVM::LLVMFuncOp>(parentOp)
1234*af6ee580SValentin Clement                : parentOp->getParentOfType<mlir::LLVM::LLVMFuncOp>();
1235*af6ee580SValentin Clement   }
1236*af6ee580SValentin Clement 
1237*af6ee580SValentin Clement   // Generate an alloca of size 1 and type \p toTy.
1238*af6ee580SValentin Clement   mlir::LLVM::AllocaOp
1239*af6ee580SValentin Clement   genAllocaWithType(mlir::Location loc, mlir::Type toTy, unsigned alignment,
1240*af6ee580SValentin Clement                     mlir::ConversionPatternRewriter &rewriter) const {
1241*af6ee580SValentin Clement     auto thisPt = rewriter.saveInsertionPoint();
1242*af6ee580SValentin Clement     mlir::LLVM::LLVMFuncOp func = getFuncForAllocaInsert(rewriter);
1243*af6ee580SValentin Clement     rewriter.setInsertionPointToStart(&func.front());
1244*af6ee580SValentin Clement     auto size = this->genI32Constant(loc, rewriter, 1);
1245*af6ee580SValentin Clement     auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, toTy, size, alignment);
1246*af6ee580SValentin Clement     rewriter.restoreInsertionPoint(thisPt);
1247*af6ee580SValentin Clement     return al;
1248*af6ee580SValentin Clement   }
1249*af6ee580SValentin Clement 
1250*af6ee580SValentin Clement   static int getCFIAttr(fir::BoxType boxTy) {
1251*af6ee580SValentin Clement     auto eleTy = boxTy.getEleTy();
1252*af6ee580SValentin Clement     if (eleTy.isa<fir::PointerType>())
1253*af6ee580SValentin Clement       return CFI_attribute_pointer;
1254*af6ee580SValentin Clement     if (eleTy.isa<fir::HeapType>())
1255*af6ee580SValentin Clement       return CFI_attribute_allocatable;
1256*af6ee580SValentin Clement     return CFI_attribute_other;
1257*af6ee580SValentin Clement   }
1258*af6ee580SValentin Clement 
1259*af6ee580SValentin Clement   static fir::RecordType unwrapIfDerived(fir::BoxType boxTy) {
1260*af6ee580SValentin Clement     return fir::unwrapSequenceType(fir::dyn_cast_ptrOrBoxEleTy(boxTy))
1261*af6ee580SValentin Clement         .template dyn_cast<fir::RecordType>();
1262*af6ee580SValentin Clement   }
1263*af6ee580SValentin Clement   static bool isDerivedTypeWithLenParams(fir::BoxType boxTy) {
1264*af6ee580SValentin Clement     auto recTy = unwrapIfDerived(boxTy);
1265*af6ee580SValentin Clement     return recTy && recTy.getNumLenParams() > 0;
1266*af6ee580SValentin Clement   }
1267*af6ee580SValentin Clement   static bool isDerivedType(fir::BoxType boxTy) {
1268*af6ee580SValentin Clement     return unwrapIfDerived(boxTy) != nullptr;
1269*af6ee580SValentin Clement   }
1270*af6ee580SValentin Clement 
1271*af6ee580SValentin Clement   // Get the element size and CFI type code of the boxed value.
1272*af6ee580SValentin Clement   std::tuple<mlir::Value, mlir::Value> getSizeAndTypeCode(
1273*af6ee580SValentin Clement       mlir::Location loc, mlir::ConversionPatternRewriter &rewriter,
1274*af6ee580SValentin Clement       mlir::Type boxEleTy, mlir::ValueRange lenParams = {}) const {
1275*af6ee580SValentin Clement     auto doInteger =
1276*af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1277*af6ee580SValentin Clement       int typeCode = fir::integerBitsToTypeCode(width);
1278*af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1279*af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1280*af6ee580SValentin Clement     };
1281*af6ee580SValentin Clement     auto doLogical =
1282*af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1283*af6ee580SValentin Clement       int typeCode = fir::logicalBitsToTypeCode(width);
1284*af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1285*af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1286*af6ee580SValentin Clement     };
1287*af6ee580SValentin Clement     auto doFloat = [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1288*af6ee580SValentin Clement       int typeCode = fir::realBitsToTypeCode(width);
1289*af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1290*af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1291*af6ee580SValentin Clement     };
1292*af6ee580SValentin Clement     auto doComplex =
1293*af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1294*af6ee580SValentin Clement       auto typeCode = fir::complexBitsToTypeCode(width);
1295*af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8 * 2),
1296*af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1297*af6ee580SValentin Clement     };
1298*af6ee580SValentin Clement     auto doCharacter =
1299*af6ee580SValentin Clement         [&](unsigned width,
1300*af6ee580SValentin Clement             mlir::Value len) -> std::tuple<mlir::Value, mlir::Value> {
1301*af6ee580SValentin Clement       auto typeCode = fir::characterBitsToTypeCode(width);
1302*af6ee580SValentin Clement       auto typeCodeVal = this->genConstantOffset(loc, rewriter, typeCode);
1303*af6ee580SValentin Clement       if (width == 8)
1304*af6ee580SValentin Clement         return {len, typeCodeVal};
1305*af6ee580SValentin Clement       auto byteWidth = this->genConstantOffset(loc, rewriter, width / 8);
1306*af6ee580SValentin Clement       auto i64Ty = mlir::IntegerType::get(&this->lowerTy().getContext(), 64);
1307*af6ee580SValentin Clement       auto size =
1308*af6ee580SValentin Clement           rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, byteWidth, len);
1309*af6ee580SValentin Clement       return {size, typeCodeVal};
1310*af6ee580SValentin Clement     };
1311*af6ee580SValentin Clement     auto getKindMap = [&]() -> fir::KindMapping & {
1312*af6ee580SValentin Clement       return this->lowerTy().getKindMap();
1313*af6ee580SValentin Clement     };
1314*af6ee580SValentin Clement     // Pointer-like types.
1315*af6ee580SValentin Clement     if (auto eleTy = fir::dyn_cast_ptrEleTy(boxEleTy))
1316*af6ee580SValentin Clement       boxEleTy = eleTy;
1317*af6ee580SValentin Clement     // Integer types.
1318*af6ee580SValentin Clement     if (fir::isa_integer(boxEleTy)) {
1319*af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::IntegerType>())
1320*af6ee580SValentin Clement         return doInteger(ty.getWidth());
1321*af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::IntegerType>();
1322*af6ee580SValentin Clement       return doInteger(getKindMap().getIntegerBitsize(ty.getFKind()));
1323*af6ee580SValentin Clement     }
1324*af6ee580SValentin Clement     // Floating point types.
1325*af6ee580SValentin Clement     if (fir::isa_real(boxEleTy)) {
1326*af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::FloatType>())
1327*af6ee580SValentin Clement         return doFloat(ty.getWidth());
1328*af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::RealType>();
1329*af6ee580SValentin Clement       return doFloat(getKindMap().getRealBitsize(ty.getFKind()));
1330*af6ee580SValentin Clement     }
1331*af6ee580SValentin Clement     // Complex types.
1332*af6ee580SValentin Clement     if (fir::isa_complex(boxEleTy)) {
1333*af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::ComplexType>())
1334*af6ee580SValentin Clement         return doComplex(
1335*af6ee580SValentin Clement             ty.getElementType().cast<mlir::FloatType>().getWidth());
1336*af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::ComplexType>();
1337*af6ee580SValentin Clement       return doComplex(getKindMap().getRealBitsize(ty.getFKind()));
1338*af6ee580SValentin Clement     }
1339*af6ee580SValentin Clement     // Character types.
1340*af6ee580SValentin Clement     if (auto ty = boxEleTy.dyn_cast<fir::CharacterType>()) {
1341*af6ee580SValentin Clement       auto charWidth = getKindMap().getCharacterBitsize(ty.getFKind());
1342*af6ee580SValentin Clement       if (ty.getLen() != fir::CharacterType::unknownLen()) {
1343*af6ee580SValentin Clement         auto len = this->genConstantOffset(loc, rewriter, ty.getLen());
1344*af6ee580SValentin Clement         return doCharacter(charWidth, len);
1345*af6ee580SValentin Clement       }
1346*af6ee580SValentin Clement       assert(!lenParams.empty());
1347*af6ee580SValentin Clement       return doCharacter(charWidth, lenParams.back());
1348*af6ee580SValentin Clement     }
1349*af6ee580SValentin Clement     // Logical type.
1350*af6ee580SValentin Clement     if (auto ty = boxEleTy.dyn_cast<fir::LogicalType>())
1351*af6ee580SValentin Clement       return doLogical(getKindMap().getLogicalBitsize(ty.getFKind()));
1352*af6ee580SValentin Clement     // Array types.
1353*af6ee580SValentin Clement     if (auto seqTy = boxEleTy.dyn_cast<fir::SequenceType>())
1354*af6ee580SValentin Clement       return getSizeAndTypeCode(loc, rewriter, seqTy.getEleTy(), lenParams);
1355*af6ee580SValentin Clement     // Derived-type types.
1356*af6ee580SValentin Clement     if (boxEleTy.isa<fir::RecordType>()) {
1357*af6ee580SValentin Clement       auto ptrTy = mlir::LLVM::LLVMPointerType::get(
1358*af6ee580SValentin Clement           this->lowerTy().convertType(boxEleTy));
1359*af6ee580SValentin Clement       auto nullPtr = rewriter.create<mlir::LLVM::NullOp>(loc, ptrTy);
1360*af6ee580SValentin Clement       auto one =
1361*af6ee580SValentin Clement           genConstantIndex(loc, this->lowerTy().offsetType(), rewriter, 1);
1362*af6ee580SValentin Clement       auto gep = rewriter.create<mlir::LLVM::GEPOp>(
1363*af6ee580SValentin Clement           loc, ptrTy, mlir::ValueRange{nullPtr, one});
1364*af6ee580SValentin Clement       auto eleSize = rewriter.create<mlir::LLVM::PtrToIntOp>(
1365*af6ee580SValentin Clement           loc, this->lowerTy().indexType(), gep);
1366*af6ee580SValentin Clement       return {eleSize,
1367*af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, fir::derivedToTypeCode())};
1368*af6ee580SValentin Clement     }
1369*af6ee580SValentin Clement     // Reference type.
1370*af6ee580SValentin Clement     if (fir::isa_ref_type(boxEleTy)) {
1371*af6ee580SValentin Clement       // FIXME: use the target pointer size rather than sizeof(void*)
1372*af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, sizeof(void *)),
1373*af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, CFI_type_cptr)};
1374*af6ee580SValentin Clement     }
1375*af6ee580SValentin Clement     fir::emitFatalError(loc, "unhandled type in fir.box code generation");
1376*af6ee580SValentin Clement   }
1377*af6ee580SValentin Clement 
1378*af6ee580SValentin Clement   /// Basic pattern to write a field in the descriptor
1379*af6ee580SValentin Clement   mlir::Value insertField(mlir::ConversionPatternRewriter &rewriter,
1380*af6ee580SValentin Clement                           mlir::Location loc, mlir::Value dest,
1381*af6ee580SValentin Clement                           ArrayRef<unsigned> fldIndexes, mlir::Value value,
1382*af6ee580SValentin Clement                           bool bitcast = false) const {
1383*af6ee580SValentin Clement     auto boxTy = dest.getType();
1384*af6ee580SValentin Clement     auto fldTy = this->getBoxEleTy(boxTy, fldIndexes);
1385*af6ee580SValentin Clement     if (bitcast)
1386*af6ee580SValentin Clement       value = rewriter.create<mlir::LLVM::BitcastOp>(loc, fldTy, value);
1387*af6ee580SValentin Clement     else
1388*af6ee580SValentin Clement       value = this->integerCast(loc, rewriter, fldTy, value);
1389*af6ee580SValentin Clement     SmallVector<mlir::Attribute, 2> attrs;
1390*af6ee580SValentin Clement     for (auto i : fldIndexes)
1391*af6ee580SValentin Clement       attrs.push_back(rewriter.getI32IntegerAttr(i));
1392*af6ee580SValentin Clement     auto indexesAttr = mlir::ArrayAttr::get(rewriter.getContext(), attrs);
1393*af6ee580SValentin Clement     return rewriter.create<mlir::LLVM::InsertValueOp>(loc, boxTy, dest, value,
1394*af6ee580SValentin Clement                                                       indexesAttr);
1395*af6ee580SValentin Clement   }
1396*af6ee580SValentin Clement 
1397*af6ee580SValentin Clement   inline mlir::Value
1398*af6ee580SValentin Clement   insertBaseAddress(mlir::ConversionPatternRewriter &rewriter,
1399*af6ee580SValentin Clement                     mlir::Location loc, mlir::Value dest,
1400*af6ee580SValentin Clement                     mlir::Value base) const {
1401*af6ee580SValentin Clement     return insertField(rewriter, loc, dest, {0}, base, /*bitCast=*/true);
1402*af6ee580SValentin Clement   }
1403*af6ee580SValentin Clement 
1404*af6ee580SValentin Clement   /// Get the address of the type descriptor global variable that was created by
1405*af6ee580SValentin Clement   /// lowering for derived type \p recType.
1406*af6ee580SValentin Clement   template <typename BOX>
1407*af6ee580SValentin Clement   mlir::Value
1408*af6ee580SValentin Clement   getTypeDescriptor(BOX box, mlir::ConversionPatternRewriter &rewriter,
1409*af6ee580SValentin Clement                     mlir::Location loc, fir::RecordType recType) const {
1410*af6ee580SValentin Clement     std::string name = recType.getLoweredName();
1411*af6ee580SValentin Clement     auto module = box->template getParentOfType<mlir::ModuleOp>();
1412*af6ee580SValentin Clement     if (auto global = module.template lookupSymbol<fir::GlobalOp>(name)) {
1413*af6ee580SValentin Clement       auto ty = mlir::LLVM::LLVMPointerType::get(
1414*af6ee580SValentin Clement           this->lowerTy().convertType(global.getType()));
1415*af6ee580SValentin Clement       return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty,
1416*af6ee580SValentin Clement                                                       global.sym_name());
1417*af6ee580SValentin Clement     }
1418*af6ee580SValentin Clement     if (auto global =
1419*af6ee580SValentin Clement             module.template lookupSymbol<mlir::LLVM::GlobalOp>(name)) {
1420*af6ee580SValentin Clement       // The global may have already been translated to LLVM.
1421*af6ee580SValentin Clement       auto ty = mlir::LLVM::LLVMPointerType::get(global.getType());
1422*af6ee580SValentin Clement       return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty,
1423*af6ee580SValentin Clement                                                       global.sym_name());
1424*af6ee580SValentin Clement     }
1425*af6ee580SValentin Clement     // The global does not exist in the current translation unit, but may be
1426*af6ee580SValentin Clement     // defined elsewhere (e.g., type defined in a module).
1427*af6ee580SValentin Clement     // For now, create a extern_weak symbol (will become nullptr if unresolved)
1428*af6ee580SValentin Clement     // to support generating code without the front-end generated symbols.
1429*af6ee580SValentin Clement     // These could be made available_externally to require the symbols to be
1430*af6ee580SValentin Clement     // defined elsewhere and to cause link-time failure otherwise.
1431*af6ee580SValentin Clement     auto i8Ty = rewriter.getIntegerType(8);
1432*af6ee580SValentin Clement     mlir::OpBuilder modBuilder(module.getBodyRegion());
1433*af6ee580SValentin Clement     // TODO: The symbol should be lowered to constant in lowering, they are read
1434*af6ee580SValentin Clement     // only.
1435*af6ee580SValentin Clement     modBuilder.create<mlir::LLVM::GlobalOp>(loc, i8Ty, /*isConstant=*/false,
1436*af6ee580SValentin Clement                                             mlir::LLVM::Linkage::ExternWeak,
1437*af6ee580SValentin Clement                                             name, mlir::Attribute{});
1438*af6ee580SValentin Clement     auto ty = mlir::LLVM::LLVMPointerType::get(i8Ty);
1439*af6ee580SValentin Clement     return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty, name);
1440*af6ee580SValentin Clement   }
1441*af6ee580SValentin Clement 
1442*af6ee580SValentin Clement   template <typename BOX>
1443*af6ee580SValentin Clement   std::tuple<fir::BoxType, mlir::Value, mlir::Value>
1444*af6ee580SValentin Clement   consDescriptorPrefix(BOX box, mlir::ConversionPatternRewriter &rewriter,
1445*af6ee580SValentin Clement                        unsigned rank, mlir::ValueRange lenParams) const {
1446*af6ee580SValentin Clement     auto loc = box.getLoc();
1447*af6ee580SValentin Clement     auto boxTy = box.getType().template dyn_cast<fir::BoxType>();
1448*af6ee580SValentin Clement     auto convTy = this->lowerTy().convertBoxType(boxTy, rank);
1449*af6ee580SValentin Clement     auto llvmBoxPtrTy = convTy.template cast<mlir::LLVM::LLVMPointerType>();
1450*af6ee580SValentin Clement     auto llvmBoxTy = llvmBoxPtrTy.getElementType();
1451*af6ee580SValentin Clement     mlir::Value descriptor =
1452*af6ee580SValentin Clement         rewriter.create<mlir::LLVM::UndefOp>(loc, llvmBoxTy);
1453*af6ee580SValentin Clement 
1454*af6ee580SValentin Clement     llvm::SmallVector<mlir::Value> typeparams = lenParams;
1455*af6ee580SValentin Clement     if constexpr (!std::is_same_v<BOX, fir::EmboxOp>) {
1456*af6ee580SValentin Clement       if (!box.substr().empty() && fir::hasDynamicSize(boxTy.getEleTy()))
1457*af6ee580SValentin Clement         typeparams.push_back(box.substr()[1]);
1458*af6ee580SValentin Clement     }
1459*af6ee580SValentin Clement 
1460*af6ee580SValentin Clement     // Write each of the fields with the appropriate values
1461*af6ee580SValentin Clement     auto [eleSize, cfiTy] =
1462*af6ee580SValentin Clement         getSizeAndTypeCode(loc, rewriter, boxTy.getEleTy(), typeparams);
1463*af6ee580SValentin Clement     descriptor =
1464*af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kElemLenPosInBox}, eleSize);
1465*af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kVersionPosInBox},
1466*af6ee580SValentin Clement                              this->genI32Constant(loc, rewriter, CFI_VERSION));
1467*af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kRankPosInBox},
1468*af6ee580SValentin Clement                              this->genI32Constant(loc, rewriter, rank));
1469*af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kTypePosInBox}, cfiTy);
1470*af6ee580SValentin Clement     descriptor =
1471*af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kAttributePosInBox},
1472*af6ee580SValentin Clement                     this->genI32Constant(loc, rewriter, getCFIAttr(boxTy)));
1473*af6ee580SValentin Clement     const bool hasAddendum = isDerivedType(boxTy);
1474*af6ee580SValentin Clement     descriptor =
1475*af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kF18AddendumPosInBox},
1476*af6ee580SValentin Clement                     this->genI32Constant(loc, rewriter, hasAddendum ? 1 : 0));
1477*af6ee580SValentin Clement 
1478*af6ee580SValentin Clement     if (hasAddendum) {
1479*af6ee580SValentin Clement       auto isArray =
1480*af6ee580SValentin Clement           fir::dyn_cast_ptrOrBoxEleTy(boxTy).template isa<fir::SequenceType>();
1481*af6ee580SValentin Clement       unsigned typeDescFieldId = isArray ? kOptTypePtrPosInBox : kDimsPosInBox;
1482*af6ee580SValentin Clement       auto typeDesc =
1483*af6ee580SValentin Clement           getTypeDescriptor(box, rewriter, loc, unwrapIfDerived(boxTy));
1484*af6ee580SValentin Clement       descriptor =
1485*af6ee580SValentin Clement           insertField(rewriter, loc, descriptor, {typeDescFieldId}, typeDesc,
1486*af6ee580SValentin Clement                       /*bitCast=*/true);
1487*af6ee580SValentin Clement     }
1488*af6ee580SValentin Clement 
1489*af6ee580SValentin Clement     return {boxTy, descriptor, eleSize};
1490*af6ee580SValentin Clement   }
1491*af6ee580SValentin Clement 
1492*af6ee580SValentin Clement   /// If the embox is not in a globalOp body, allocate storage for the box;
1493*af6ee580SValentin Clement   /// store the value inside and return the generated alloca. Return the input
1494*af6ee580SValentin Clement   /// value otherwise.
1495*af6ee580SValentin Clement   mlir::Value
1496*af6ee580SValentin Clement   placeInMemoryIfNotGlobalInit(mlir::ConversionPatternRewriter &rewriter,
1497*af6ee580SValentin Clement                                mlir::Location loc, mlir::Value boxValue) const {
1498*af6ee580SValentin Clement     auto *thisBlock = rewriter.getInsertionBlock();
1499*af6ee580SValentin Clement     if (thisBlock && mlir::isa<mlir::LLVM::GlobalOp>(thisBlock->getParentOp()))
1500*af6ee580SValentin Clement       return boxValue;
1501*af6ee580SValentin Clement     auto boxPtrTy = mlir::LLVM::LLVMPointerType::get(boxValue.getType());
1502*af6ee580SValentin Clement     auto alloca = genAllocaWithType(loc, boxPtrTy, defaultAlign, rewriter);
1503*af6ee580SValentin Clement     rewriter.create<mlir::LLVM::StoreOp>(loc, boxValue, alloca);
1504*af6ee580SValentin Clement     return alloca;
1505*af6ee580SValentin Clement   }
1506*af6ee580SValentin Clement };
1507*af6ee580SValentin Clement 
1508*af6ee580SValentin Clement /// Create a generic box on a memory reference. This conversions lowers the
1509*af6ee580SValentin Clement /// abstract box to the appropriate, initialized descriptor.
1510*af6ee580SValentin Clement struct EmboxOpConversion : public EmboxCommonConversion<fir::EmboxOp> {
1511*af6ee580SValentin Clement   using EmboxCommonConversion::EmboxCommonConversion;
1512*af6ee580SValentin Clement 
1513*af6ee580SValentin Clement   mlir::LogicalResult
1514*af6ee580SValentin Clement   matchAndRewrite(fir::EmboxOp embox, OpAdaptor adaptor,
1515*af6ee580SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1516*af6ee580SValentin Clement     assert(!embox.getShape() && "There should be no dims on this embox op");
1517*af6ee580SValentin Clement     auto [boxTy, dest, eleSize] =
1518*af6ee580SValentin Clement         consDescriptorPrefix(embox, rewriter, /*rank=*/0,
1519*af6ee580SValentin Clement                              /*lenParams=*/adaptor.getOperands().drop_front(1));
1520*af6ee580SValentin Clement     dest = insertBaseAddress(rewriter, embox.getLoc(), dest,
1521*af6ee580SValentin Clement                              adaptor.getOperands()[0]);
1522*af6ee580SValentin Clement     if (isDerivedTypeWithLenParams(boxTy))
1523*af6ee580SValentin Clement       return rewriter.notifyMatchFailure(
1524*af6ee580SValentin Clement           embox, "fir.embox codegen of derived with length parameters not "
1525*af6ee580SValentin Clement                  "implemented yet");
1526*af6ee580SValentin Clement     auto result = placeInMemoryIfNotGlobalInit(rewriter, embox.getLoc(), dest);
1527*af6ee580SValentin Clement     rewriter.replaceOp(embox, result);
1528*af6ee580SValentin Clement     return success();
1529*af6ee580SValentin Clement   }
1530*af6ee580SValentin Clement };
1531*af6ee580SValentin Clement 
153254c56347SValentin Clement // Code shared between insert_value and extract_value Ops.
153354c56347SValentin Clement struct ValueOpCommon {
153454c56347SValentin Clement   // Translate the arguments pertaining to any multidimensional array to
153554c56347SValentin Clement   // row-major order for LLVM-IR.
153654c56347SValentin Clement   static void toRowMajor(SmallVectorImpl<mlir::Attribute> &attrs,
153754c56347SValentin Clement                          mlir::Type ty) {
153854c56347SValentin Clement     assert(ty && "type is null");
153954c56347SValentin Clement     const auto end = attrs.size();
154054c56347SValentin Clement     for (std::remove_const_t<decltype(end)> i = 0; i < end; ++i) {
154154c56347SValentin Clement       if (auto seq = ty.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
154254c56347SValentin Clement         const auto dim = getDimension(seq);
154354c56347SValentin Clement         if (dim > 1) {
154454c56347SValentin Clement           auto ub = std::min(i + dim, end);
154554c56347SValentin Clement           std::reverse(attrs.begin() + i, attrs.begin() + ub);
154654c56347SValentin Clement           i += dim - 1;
154754c56347SValentin Clement         }
154854c56347SValentin Clement         ty = getArrayElementType(seq);
154954c56347SValentin Clement       } else if (auto st = ty.dyn_cast<mlir::LLVM::LLVMStructType>()) {
155054c56347SValentin Clement         ty = st.getBody()[attrs[i].cast<mlir::IntegerAttr>().getInt()];
155154c56347SValentin Clement       } else {
155254c56347SValentin Clement         llvm_unreachable("index into invalid type");
155354c56347SValentin Clement       }
155454c56347SValentin Clement     }
155554c56347SValentin Clement   }
155654c56347SValentin Clement 
155754c56347SValentin Clement   static llvm::SmallVector<mlir::Attribute>
155854c56347SValentin Clement   collectIndices(mlir::ConversionPatternRewriter &rewriter,
155954c56347SValentin Clement                  mlir::ArrayAttr arrAttr) {
156054c56347SValentin Clement     llvm::SmallVector<mlir::Attribute> attrs;
156154c56347SValentin Clement     for (auto i = arrAttr.begin(), e = arrAttr.end(); i != e; ++i) {
156254c56347SValentin Clement       if (i->isa<mlir::IntegerAttr>()) {
156354c56347SValentin Clement         attrs.push_back(*i);
156454c56347SValentin Clement       } else {
156554c56347SValentin Clement         auto fieldName = i->cast<mlir::StringAttr>().getValue();
156654c56347SValentin Clement         ++i;
156754c56347SValentin Clement         auto ty = i->cast<mlir::TypeAttr>().getValue();
156854c56347SValentin Clement         auto index = ty.cast<fir::RecordType>().getFieldIndex(fieldName);
156954c56347SValentin Clement         attrs.push_back(mlir::IntegerAttr::get(rewriter.getI32Type(), index));
157054c56347SValentin Clement       }
157154c56347SValentin Clement     }
157254c56347SValentin Clement     return attrs;
157354c56347SValentin Clement   }
157454c56347SValentin Clement 
157554c56347SValentin Clement private:
157654c56347SValentin Clement   static unsigned getDimension(mlir::LLVM::LLVMArrayType ty) {
157754c56347SValentin Clement     unsigned result = 1;
157854c56347SValentin Clement     for (auto eleTy = ty.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>();
157954c56347SValentin Clement          eleTy;
158054c56347SValentin Clement          eleTy = eleTy.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>())
158154c56347SValentin Clement       ++result;
158254c56347SValentin Clement     return result;
158354c56347SValentin Clement   }
158454c56347SValentin Clement 
158554c56347SValentin Clement   static mlir::Type getArrayElementType(mlir::LLVM::LLVMArrayType ty) {
158654c56347SValentin Clement     auto eleTy = ty.getElementType();
158754c56347SValentin Clement     while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>())
158854c56347SValentin Clement       eleTy = arrTy.getElementType();
158954c56347SValentin Clement     return eleTy;
159054c56347SValentin Clement   }
159154c56347SValentin Clement };
159254c56347SValentin Clement 
159354c56347SValentin Clement /// Extract a subobject value from an ssa-value of aggregate type
159454c56347SValentin Clement struct ExtractValueOpConversion
159554c56347SValentin Clement     : public FIROpAndTypeConversion<fir::ExtractValueOp>,
159654c56347SValentin Clement       public ValueOpCommon {
159754c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
159854c56347SValentin Clement 
159954c56347SValentin Clement   mlir::LogicalResult
160054c56347SValentin Clement   doRewrite(fir::ExtractValueOp extractVal, mlir::Type ty, OpAdaptor adaptor,
160154c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
160254c56347SValentin Clement     auto attrs = collectIndices(rewriter, extractVal.coor());
160354c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
160454c56347SValentin Clement     auto position = mlir::ArrayAttr::get(extractVal.getContext(), attrs);
160554c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(
160654c56347SValentin Clement         extractVal, ty, adaptor.getOperands()[0], position);
160754c56347SValentin Clement     return success();
160854c56347SValentin Clement   }
160954c56347SValentin Clement };
161054c56347SValentin Clement 
161154c56347SValentin Clement /// InsertValue is the generalized instruction for the composition of new
161254c56347SValentin Clement /// aggregate type values.
161354c56347SValentin Clement struct InsertValueOpConversion
161454c56347SValentin Clement     : public FIROpAndTypeConversion<fir::InsertValueOp>,
161554c56347SValentin Clement       public ValueOpCommon {
161654c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
161754c56347SValentin Clement 
161854c56347SValentin Clement   mlir::LogicalResult
161954c56347SValentin Clement   doRewrite(fir::InsertValueOp insertVal, mlir::Type ty, OpAdaptor adaptor,
162054c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
162154c56347SValentin Clement     auto attrs = collectIndices(rewriter, insertVal.coor());
162254c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
162354c56347SValentin Clement     auto position = mlir::ArrayAttr::get(insertVal.getContext(), attrs);
162454c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
162554c56347SValentin Clement         insertVal, ty, adaptor.getOperands()[0], adaptor.getOperands()[1],
162654c56347SValentin Clement         position);
162754c56347SValentin Clement     return success();
162854c56347SValentin Clement   }
162954c56347SValentin Clement };
163054c56347SValentin Clement 
16313ae8e442SValentin Clement /// InsertOnRange inserts a value into a sequence over a range of offsets.
16323ae8e442SValentin Clement struct InsertOnRangeOpConversion
16333ae8e442SValentin Clement     : public FIROpAndTypeConversion<fir::InsertOnRangeOp> {
16343ae8e442SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
16353ae8e442SValentin Clement 
16363ae8e442SValentin Clement   // Increments an array of subscripts in a row major fasion.
16373ae8e442SValentin Clement   void incrementSubscripts(const SmallVector<uint64_t> &dims,
16383ae8e442SValentin Clement                            SmallVector<uint64_t> &subscripts) const {
16393ae8e442SValentin Clement     for (size_t i = dims.size(); i > 0; --i) {
16403ae8e442SValentin Clement       if (++subscripts[i - 1] < dims[i - 1]) {
16413ae8e442SValentin Clement         return;
16423ae8e442SValentin Clement       }
16433ae8e442SValentin Clement       subscripts[i - 1] = 0;
16443ae8e442SValentin Clement     }
16453ae8e442SValentin Clement   }
16463ae8e442SValentin Clement 
16473ae8e442SValentin Clement   mlir::LogicalResult
16483ae8e442SValentin Clement   doRewrite(fir::InsertOnRangeOp range, mlir::Type ty, OpAdaptor adaptor,
16493ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
16503ae8e442SValentin Clement 
16513ae8e442SValentin Clement     llvm::SmallVector<uint64_t> dims;
16523ae8e442SValentin Clement     auto type = adaptor.getOperands()[0].getType();
16533ae8e442SValentin Clement 
16543ae8e442SValentin Clement     // Iteratively extract the array dimensions from the type.
16553ae8e442SValentin Clement     while (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
16563ae8e442SValentin Clement       dims.push_back(t.getNumElements());
16573ae8e442SValentin Clement       type = t.getElementType();
16583ae8e442SValentin Clement     }
16593ae8e442SValentin Clement 
16603ae8e442SValentin Clement     SmallVector<uint64_t> lBounds;
16613ae8e442SValentin Clement     SmallVector<uint64_t> uBounds;
16623ae8e442SValentin Clement 
16633ae8e442SValentin Clement     // Extract integer value from the attribute
16643ae8e442SValentin Clement     SmallVector<int64_t> coordinates = llvm::to_vector<4>(
16653ae8e442SValentin Clement         llvm::map_range(range.coor(), [](Attribute a) -> int64_t {
16663ae8e442SValentin Clement           return a.cast<IntegerAttr>().getInt();
16673ae8e442SValentin Clement         }));
16683ae8e442SValentin Clement 
16693ae8e442SValentin Clement     // Unzip the upper and lower bound and convert to a row major format.
16703ae8e442SValentin Clement     for (auto i = coordinates.rbegin(), e = coordinates.rend(); i != e; ++i) {
16713ae8e442SValentin Clement       uBounds.push_back(*i++);
16723ae8e442SValentin Clement       lBounds.push_back(*i);
16733ae8e442SValentin Clement     }
16743ae8e442SValentin Clement 
16753ae8e442SValentin Clement     auto &subscripts = lBounds;
16763ae8e442SValentin Clement     auto loc = range.getLoc();
16773ae8e442SValentin Clement     mlir::Value lastOp = adaptor.getOperands()[0];
16783ae8e442SValentin Clement     mlir::Value insertVal = adaptor.getOperands()[1];
16793ae8e442SValentin Clement 
16803ae8e442SValentin Clement     auto i64Ty = rewriter.getI64Type();
16813ae8e442SValentin Clement     while (subscripts != uBounds) {
16823ae8e442SValentin Clement       // Convert uint64_t's to Attribute's.
16833ae8e442SValentin Clement       SmallVector<mlir::Attribute> subscriptAttrs;
16843ae8e442SValentin Clement       for (const auto &subscript : subscripts)
16853ae8e442SValentin Clement         subscriptAttrs.push_back(IntegerAttr::get(i64Ty, subscript));
16863ae8e442SValentin Clement       lastOp = rewriter.create<mlir::LLVM::InsertValueOp>(
16873ae8e442SValentin Clement           loc, ty, lastOp, insertVal,
16883ae8e442SValentin Clement           ArrayAttr::get(range.getContext(), subscriptAttrs));
16893ae8e442SValentin Clement 
16903ae8e442SValentin Clement       incrementSubscripts(dims, subscripts);
16913ae8e442SValentin Clement     }
16923ae8e442SValentin Clement 
16933ae8e442SValentin Clement     // Convert uint64_t's to Attribute's.
16943ae8e442SValentin Clement     SmallVector<mlir::Attribute> subscriptAttrs;
16953ae8e442SValentin Clement     for (const auto &subscript : subscripts)
16963ae8e442SValentin Clement       subscriptAttrs.push_back(
16973ae8e442SValentin Clement           IntegerAttr::get(rewriter.getI64Type(), subscript));
16983ae8e442SValentin Clement     mlir::ArrayRef<mlir::Attribute> arrayRef(subscriptAttrs);
16993ae8e442SValentin Clement 
17003ae8e442SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
17013ae8e442SValentin Clement         range, ty, lastOp, insertVal,
17023ae8e442SValentin Clement         ArrayAttr::get(range.getContext(), arrayRef));
17033ae8e442SValentin Clement 
17043ae8e442SValentin Clement     return success();
17053ae8e442SValentin Clement   }
17063ae8e442SValentin Clement };
17077b5132daSValentin Clement 
17087b5132daSValentin Clement //
17097b5132daSValentin Clement // Primitive operations on Complex types
17107b5132daSValentin Clement //
17117b5132daSValentin Clement 
17127b5132daSValentin Clement /// Generate inline code for complex addition/subtraction
17137b5132daSValentin Clement template <typename LLVMOP, typename OPTY>
17147b5132daSValentin Clement mlir::LLVM::InsertValueOp complexSum(OPTY sumop, mlir::ValueRange opnds,
17157b5132daSValentin Clement                                      mlir::ConversionPatternRewriter &rewriter,
17167b5132daSValentin Clement                                      fir::LLVMTypeConverter &lowering) {
17177b5132daSValentin Clement   mlir::Value a = opnds[0];
17187b5132daSValentin Clement   mlir::Value b = opnds[1];
17197b5132daSValentin Clement   auto loc = sumop.getLoc();
17207b5132daSValentin Clement   auto ctx = sumop.getContext();
17217b5132daSValentin Clement   auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
17227b5132daSValentin Clement   auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
17237b5132daSValentin Clement   mlir::Type eleTy = lowering.convertType(getComplexEleTy(sumop.getType()));
17247b5132daSValentin Clement   mlir::Type ty = lowering.convertType(sumop.getType());
17257b5132daSValentin Clement   auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
17267b5132daSValentin Clement   auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
17277b5132daSValentin Clement   auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
17287b5132daSValentin Clement   auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
17297b5132daSValentin Clement   auto rx = rewriter.create<LLVMOP>(loc, eleTy, x0, x1);
17307b5132daSValentin Clement   auto ry = rewriter.create<LLVMOP>(loc, eleTy, y0, y1);
17317b5132daSValentin Clement   auto r0 = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
17327b5132daSValentin Clement   auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r0, rx, c0);
17337b5132daSValentin Clement   return rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ry, c1);
17347b5132daSValentin Clement }
17357b5132daSValentin Clement 
17367b5132daSValentin Clement struct AddcOpConversion : public FIROpConversion<fir::AddcOp> {
17377b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
17387b5132daSValentin Clement 
17397b5132daSValentin Clement   mlir::LogicalResult
17407b5132daSValentin Clement   matchAndRewrite(fir::AddcOp addc, OpAdaptor adaptor,
17417b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
17427b5132daSValentin Clement     // given: (x + iy) + (x' + iy')
17437b5132daSValentin Clement     // result: (x + x') + i(y + y')
17447b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FAddOp>(addc, adaptor.getOperands(),
17457b5132daSValentin Clement                                             rewriter, lowerTy());
17467b5132daSValentin Clement     rewriter.replaceOp(addc, r.getResult());
17477b5132daSValentin Clement     return success();
17487b5132daSValentin Clement   }
17497b5132daSValentin Clement };
17507b5132daSValentin Clement 
17517b5132daSValentin Clement struct SubcOpConversion : public FIROpConversion<fir::SubcOp> {
17527b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
17537b5132daSValentin Clement 
17547b5132daSValentin Clement   mlir::LogicalResult
17557b5132daSValentin Clement   matchAndRewrite(fir::SubcOp subc, OpAdaptor adaptor,
17567b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
17577b5132daSValentin Clement     // given: (x + iy) - (x' + iy')
17587b5132daSValentin Clement     // result: (x - x') + i(y - y')
17597b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FSubOp>(subc, adaptor.getOperands(),
17607b5132daSValentin Clement                                             rewriter, lowerTy());
17617b5132daSValentin Clement     rewriter.replaceOp(subc, r.getResult());
17627b5132daSValentin Clement     return success();
17637b5132daSValentin Clement   }
17647b5132daSValentin Clement };
17657b5132daSValentin Clement 
17667b5132daSValentin Clement /// Inlined complex multiply
17677b5132daSValentin Clement struct MulcOpConversion : public FIROpConversion<fir::MulcOp> {
17687b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
17697b5132daSValentin Clement 
17707b5132daSValentin Clement   mlir::LogicalResult
17717b5132daSValentin Clement   matchAndRewrite(fir::MulcOp mulc, OpAdaptor adaptor,
17727b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
17737b5132daSValentin Clement     // TODO: Can we use a call to __muldc3 ?
17747b5132daSValentin Clement     // given: (x + iy) * (x' + iy')
17757b5132daSValentin Clement     // result: (xx'-yy')+i(xy'+yx')
17767b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
17777b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
17787b5132daSValentin Clement     auto loc = mulc.getLoc();
17797b5132daSValentin Clement     auto *ctx = mulc.getContext();
17807b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
17817b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
17827b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(mulc.getType()));
17837b5132daSValentin Clement     mlir::Type ty = convertType(mulc.getType());
17847b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
17857b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
17867b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
17877b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
17887b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
17897b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
17907b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
17917b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xy, yx);
17927b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
17937b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, xx, yy);
17947b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
17957b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
17967b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
17977b5132daSValentin Clement     rewriter.replaceOp(mulc, r0.getResult());
17987b5132daSValentin Clement     return success();
17997b5132daSValentin Clement   }
18007b5132daSValentin Clement };
18017b5132daSValentin Clement 
18027b5132daSValentin Clement /// Inlined complex division
18037b5132daSValentin Clement struct DivcOpConversion : public FIROpConversion<fir::DivcOp> {
18047b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
18057b5132daSValentin Clement 
18067b5132daSValentin Clement   mlir::LogicalResult
18077b5132daSValentin Clement   matchAndRewrite(fir::DivcOp divc, OpAdaptor adaptor,
18087b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
18097b5132daSValentin Clement     // TODO: Can we use a call to __divdc3 instead?
18107b5132daSValentin Clement     // Just generate inline code for now.
18117b5132daSValentin Clement     // given: (x + iy) / (x' + iy')
18127b5132daSValentin Clement     // result: ((xx'+yy')/d) + i((yx'-xy')/d) where d = x'x' + y'y'
18137b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
18147b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
18157b5132daSValentin Clement     auto loc = divc.getLoc();
18167b5132daSValentin Clement     auto *ctx = divc.getContext();
18177b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
18187b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
18197b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(divc.getType()));
18207b5132daSValentin Clement     mlir::Type ty = convertType(divc.getType());
18217b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
18227b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
18237b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
18247b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
18257b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
18267b5132daSValentin Clement     auto x1x1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x1, x1);
18277b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
18287b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
18297b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
18307b5132daSValentin Clement     auto y1y1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y1, y1);
18317b5132daSValentin Clement     auto d = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, x1x1, y1y1);
18327b5132daSValentin Clement     auto rrn = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xx, yy);
18337b5132daSValentin Clement     auto rin = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, yx, xy);
18347b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rrn, d);
18357b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rin, d);
18367b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
18377b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
18387b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
18397b5132daSValentin Clement     rewriter.replaceOp(divc, r0.getResult());
18407b5132daSValentin Clement     return success();
18417b5132daSValentin Clement   }
18427b5132daSValentin Clement };
18437b5132daSValentin Clement 
18447b5132daSValentin Clement /// Inlined complex negation
18457b5132daSValentin Clement struct NegcOpConversion : public FIROpConversion<fir::NegcOp> {
18467b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
18477b5132daSValentin Clement 
18487b5132daSValentin Clement   mlir::LogicalResult
18497b5132daSValentin Clement   matchAndRewrite(fir::NegcOp neg, OpAdaptor adaptor,
18507b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
18517b5132daSValentin Clement     // given: -(x + iy)
18527b5132daSValentin Clement     // result: -x - iy
18537b5132daSValentin Clement     auto *ctxt = neg.getContext();
18547b5132daSValentin Clement     auto eleTy = convertType(getComplexEleTy(neg.getType()));
18557b5132daSValentin Clement     auto ty = convertType(neg.getType());
18567b5132daSValentin Clement     auto loc = neg.getLoc();
18577b5132daSValentin Clement     mlir::Value o0 = adaptor.getOperands()[0];
18587b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0));
18597b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1));
18607b5132daSValentin Clement     auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c0);
18617b5132daSValentin Clement     auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c1);
18627b5132daSValentin Clement     auto nrp = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, rp);
18637b5132daSValentin Clement     auto nip = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, ip);
18647b5132daSValentin Clement     auto r = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, o0, nrp, c0);
18657b5132daSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(neg, ty, r, nip, c1);
18667b5132daSValentin Clement     return success();
18677b5132daSValentin Clement   }
18687b5132daSValentin Clement };
18697b5132daSValentin Clement 
18701ed5a90fSValentin Clement /// Conversion pattern for operation that must be dead. The information in these
18711ed5a90fSValentin Clement /// operations is used by other operation. At this point they should not have
18721ed5a90fSValentin Clement /// anymore uses.
18731ed5a90fSValentin Clement /// These operations are normally dead after the pre-codegen pass.
18741ed5a90fSValentin Clement template <typename FromOp>
18751ed5a90fSValentin Clement struct MustBeDeadConversion : public FIROpConversion<FromOp> {
18761ed5a90fSValentin Clement   explicit MustBeDeadConversion(fir::LLVMTypeConverter &lowering)
18771ed5a90fSValentin Clement       : FIROpConversion<FromOp>(lowering) {}
18781ed5a90fSValentin Clement   using OpAdaptor = typename FromOp::Adaptor;
18791ed5a90fSValentin Clement 
18801ed5a90fSValentin Clement   mlir::LogicalResult
18811ed5a90fSValentin Clement   matchAndRewrite(FromOp op, OpAdaptor adaptor,
18821ed5a90fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const final {
18831ed5a90fSValentin Clement     if (!op->getUses().empty())
18841ed5a90fSValentin Clement       return rewriter.notifyMatchFailure(op, "op must be dead");
18851ed5a90fSValentin Clement     rewriter.eraseOp(op);
18861ed5a90fSValentin Clement     return success();
18871ed5a90fSValentin Clement   }
18881ed5a90fSValentin Clement };
18891ed5a90fSValentin Clement 
18901ed5a90fSValentin Clement struct ShapeOpConversion : public MustBeDeadConversion<fir::ShapeOp> {
18911ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
18921ed5a90fSValentin Clement };
18931ed5a90fSValentin Clement 
18941ed5a90fSValentin Clement struct ShapeShiftOpConversion : public MustBeDeadConversion<fir::ShapeShiftOp> {
18951ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
18961ed5a90fSValentin Clement };
18971ed5a90fSValentin Clement 
18981ed5a90fSValentin Clement struct ShiftOpConversion : public MustBeDeadConversion<fir::ShiftOp> {
18991ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
19001ed5a90fSValentin Clement };
19011ed5a90fSValentin Clement 
19021ed5a90fSValentin Clement struct SliceOpConversion : public MustBeDeadConversion<fir::SliceOp> {
19031ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
19041ed5a90fSValentin Clement };
19051ed5a90fSValentin Clement 
1906420ad7ceSAndrzej Warzynski /// `fir.is_present` -->
1907420ad7ceSAndrzej Warzynski /// ```
1908420ad7ceSAndrzej Warzynski ///  %0 = llvm.mlir.constant(0 : i64)
1909420ad7ceSAndrzej Warzynski ///  %1 = llvm.ptrtoint %0
1910420ad7ceSAndrzej Warzynski ///  %2 = llvm.icmp "ne" %1, %0 : i64
1911420ad7ceSAndrzej Warzynski /// ```
1912420ad7ceSAndrzej Warzynski struct IsPresentOpConversion : public FIROpConversion<fir::IsPresentOp> {
1913420ad7ceSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
1914420ad7ceSAndrzej Warzynski 
1915420ad7ceSAndrzej Warzynski   mlir::LogicalResult
1916420ad7ceSAndrzej Warzynski   matchAndRewrite(fir::IsPresentOp isPresent, OpAdaptor adaptor,
1917420ad7ceSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
1918420ad7ceSAndrzej Warzynski     mlir::Type idxTy = lowerTy().indexType();
1919420ad7ceSAndrzej Warzynski     mlir::Location loc = isPresent.getLoc();
1920420ad7ceSAndrzej Warzynski     auto ptr = adaptor.getOperands()[0];
1921420ad7ceSAndrzej Warzynski 
1922420ad7ceSAndrzej Warzynski     if (isPresent.val().getType().isa<fir::BoxCharType>()) {
1923420ad7ceSAndrzej Warzynski       auto structTy = ptr.getType().cast<mlir::LLVM::LLVMStructType>();
1924420ad7ceSAndrzej Warzynski       assert(!structTy.isOpaque() && !structTy.getBody().empty());
1925420ad7ceSAndrzej Warzynski 
1926420ad7ceSAndrzej Warzynski       mlir::Type ty = structTy.getBody()[0];
1927420ad7ceSAndrzej Warzynski       mlir::MLIRContext *ctx = isPresent.getContext();
1928420ad7ceSAndrzej Warzynski       auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
1929420ad7ceSAndrzej Warzynski       ptr = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, ptr, c0);
1930420ad7ceSAndrzej Warzynski     }
1931420ad7ceSAndrzej Warzynski     mlir::LLVM::ConstantOp c0 =
1932420ad7ceSAndrzej Warzynski         genConstantIndex(isPresent.getLoc(), idxTy, rewriter, 0);
1933420ad7ceSAndrzej Warzynski     auto addr = rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, ptr);
1934420ad7ceSAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
1935420ad7ceSAndrzej Warzynski         isPresent, mlir::LLVM::ICmpPredicate::ne, addr, c0);
1936420ad7ceSAndrzej Warzynski 
1937420ad7ceSAndrzej Warzynski     return success();
1938420ad7ceSAndrzej Warzynski   }
1939420ad7ceSAndrzej Warzynski };
19401e77b095SAndrzej Warzynski 
19411e77b095SAndrzej Warzynski /// Convert `!fir.emboxchar<!fir.char<KIND, ?>, #n>` into a sequence of
19421e77b095SAndrzej Warzynski /// instructions that generate `!llvm.struct<(ptr<ik>, i64)>`. The 1st element
19431e77b095SAndrzej Warzynski /// in this struct is a pointer. Its type is determined from `KIND`. The 2nd
19441e77b095SAndrzej Warzynski /// element is the length of the character buffer (`#n`).
19451e77b095SAndrzej Warzynski struct EmboxCharOpConversion : public FIROpConversion<fir::EmboxCharOp> {
19461e77b095SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
19471e77b095SAndrzej Warzynski 
19481e77b095SAndrzej Warzynski   mlir::LogicalResult
19491e77b095SAndrzej Warzynski   matchAndRewrite(fir::EmboxCharOp emboxChar, OpAdaptor adaptor,
19501e77b095SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
19511e77b095SAndrzej Warzynski     mlir::ValueRange operands = adaptor.getOperands();
19521e77b095SAndrzej Warzynski     MLIRContext *ctx = emboxChar.getContext();
19531e77b095SAndrzej Warzynski 
19541e77b095SAndrzej Warzynski     mlir::Value charBuffer = operands[0];
19551e77b095SAndrzej Warzynski     mlir::Value charBufferLen = operands[1];
19561e77b095SAndrzej Warzynski 
19571e77b095SAndrzej Warzynski     mlir::Location loc = emboxChar.getLoc();
19581e77b095SAndrzej Warzynski     mlir::Type llvmStructTy = convertType(emboxChar.getType());
19591e77b095SAndrzej Warzynski     auto llvmStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, llvmStructTy);
19601e77b095SAndrzej Warzynski 
19611e77b095SAndrzej Warzynski     mlir::Type lenTy =
19621e77b095SAndrzej Warzynski         llvmStructTy.cast<mlir::LLVM::LLVMStructType>().getBody()[1];
19631e77b095SAndrzej Warzynski     mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, charBufferLen);
19641e77b095SAndrzej Warzynski 
19651e77b095SAndrzej Warzynski     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
19661e77b095SAndrzej Warzynski     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
19671e77b095SAndrzej Warzynski     auto insertBufferOp = rewriter.create<mlir::LLVM::InsertValueOp>(
19681e77b095SAndrzej Warzynski         loc, llvmStructTy, llvmStruct, charBuffer, c0);
19691e77b095SAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
19701e77b095SAndrzej Warzynski         emboxChar, llvmStructTy, insertBufferOp, lenAfterCast, c1);
19711e77b095SAndrzej Warzynski 
19721e77b095SAndrzej Warzynski     return success();
19731e77b095SAndrzej Warzynski   }
19741e77b095SAndrzej Warzynski };
197514867ffcSAndrzej Warzynski 
197614867ffcSAndrzej Warzynski /// Construct an `llvm.extractvalue` instruction. It will return value at
197714867ffcSAndrzej Warzynski /// element \p x from  \p tuple.
197814867ffcSAndrzej Warzynski mlir::LLVM::ExtractValueOp
197914867ffcSAndrzej Warzynski genExtractValueWithIndex(mlir::Location loc, mlir::Value tuple, mlir::Type ty,
198014867ffcSAndrzej Warzynski                          mlir::ConversionPatternRewriter &rewriter,
198114867ffcSAndrzej Warzynski                          mlir::MLIRContext *ctx, int x) {
198214867ffcSAndrzej Warzynski   auto cx = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(x));
198314867ffcSAndrzej Warzynski   auto xty = ty.cast<mlir::LLVM::LLVMStructType>().getBody()[x];
198414867ffcSAndrzej Warzynski   return rewriter.create<mlir::LLVM::ExtractValueOp>(loc, xty, tuple, cx);
198514867ffcSAndrzej Warzynski }
198614867ffcSAndrzej Warzynski 
19876c3d7fd4SAndrzej Warzynski /// Convert `!fir.boxchar_len` to  `!llvm.extractvalue` for the 2nd part of the
19886c3d7fd4SAndrzej Warzynski /// boxchar.
19896c3d7fd4SAndrzej Warzynski struct BoxCharLenOpConversion : public FIROpConversion<fir::BoxCharLenOp> {
19906c3d7fd4SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
19916c3d7fd4SAndrzej Warzynski 
19926c3d7fd4SAndrzej Warzynski   mlir::LogicalResult
19936c3d7fd4SAndrzej Warzynski   matchAndRewrite(fir::BoxCharLenOp boxCharLen, OpAdaptor adaptor,
19946c3d7fd4SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
19956c3d7fd4SAndrzej Warzynski     mlir::Value boxChar = adaptor.getOperands()[0];
19966c3d7fd4SAndrzej Warzynski     mlir::Location loc = boxChar.getLoc();
19976c3d7fd4SAndrzej Warzynski     mlir::MLIRContext *ctx = boxChar.getContext();
19986c3d7fd4SAndrzej Warzynski     mlir::Type returnValTy = boxCharLen.getResult().getType();
19996c3d7fd4SAndrzej Warzynski 
20006c3d7fd4SAndrzej Warzynski     constexpr int boxcharLenIdx = 1;
20016c3d7fd4SAndrzej Warzynski     mlir::LLVM::ExtractValueOp len = genExtractValueWithIndex(
20026c3d7fd4SAndrzej Warzynski         loc, boxChar, boxChar.getType(), rewriter, ctx, boxcharLenIdx);
20036c3d7fd4SAndrzej Warzynski     mlir::Value lenAfterCast = integerCast(loc, rewriter, returnValTy, len);
20046c3d7fd4SAndrzej Warzynski     rewriter.replaceOp(boxCharLen, lenAfterCast);
20056c3d7fd4SAndrzej Warzynski 
20066c3d7fd4SAndrzej Warzynski     return success();
20076c3d7fd4SAndrzej Warzynski   }
20086c3d7fd4SAndrzej Warzynski };
20096c3d7fd4SAndrzej Warzynski 
201014867ffcSAndrzej Warzynski /// Convert `fir.unboxchar` into two `llvm.extractvalue` instructions. One for
201114867ffcSAndrzej Warzynski /// the character buffer and one for the buffer length.
201214867ffcSAndrzej Warzynski struct UnboxCharOpConversion : public FIROpConversion<fir::UnboxCharOp> {
201314867ffcSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
201414867ffcSAndrzej Warzynski 
201514867ffcSAndrzej Warzynski   mlir::LogicalResult
201614867ffcSAndrzej Warzynski   matchAndRewrite(fir::UnboxCharOp unboxchar, OpAdaptor adaptor,
201714867ffcSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
201814867ffcSAndrzej Warzynski     MLIRContext *ctx = unboxchar.getContext();
201914867ffcSAndrzej Warzynski 
202014867ffcSAndrzej Warzynski     mlir::Type lenTy = convertType(unboxchar.getType(1));
202114867ffcSAndrzej Warzynski     mlir::Value tuple = adaptor.getOperands()[0];
202214867ffcSAndrzej Warzynski     mlir::Type tupleTy = tuple.getType();
202314867ffcSAndrzej Warzynski 
202414867ffcSAndrzej Warzynski     mlir::Location loc = unboxchar.getLoc();
202514867ffcSAndrzej Warzynski     mlir::Value ptrToBuffer =
202614867ffcSAndrzej Warzynski         genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 0);
202714867ffcSAndrzej Warzynski 
202814867ffcSAndrzej Warzynski     mlir::LLVM::ExtractValueOp len =
202914867ffcSAndrzej Warzynski         genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 1);
203014867ffcSAndrzej Warzynski     mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, len);
203114867ffcSAndrzej Warzynski 
203214867ffcSAndrzej Warzynski     rewriter.replaceOp(unboxchar,
203314867ffcSAndrzej Warzynski                        ArrayRef<mlir::Value>{ptrToBuffer, lenAfterCast});
203414867ffcSAndrzej Warzynski     return success();
203514867ffcSAndrzej Warzynski   }
203614867ffcSAndrzej Warzynski };
203714867ffcSAndrzej Warzynski 
2038044d5b5dSValentin Clement } // namespace
2039044d5b5dSValentin Clement 
2040044d5b5dSValentin Clement namespace {
2041044d5b5dSValentin Clement /// Convert FIR dialect to LLVM dialect
2042044d5b5dSValentin Clement ///
2043044d5b5dSValentin Clement /// This pass lowers all FIR dialect operations to LLVM IR dialect. An
2044044d5b5dSValentin Clement /// MLIR pass is used to lower residual Std dialect to LLVM IR dialect.
2045044d5b5dSValentin Clement ///
2046044d5b5dSValentin Clement /// This pass is not complete yet. We are upstreaming it in small patches.
2047044d5b5dSValentin Clement class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> {
2048044d5b5dSValentin Clement public:
2049044d5b5dSValentin Clement   mlir::ModuleOp getModule() { return getOperation(); }
2050044d5b5dSValentin Clement 
2051044d5b5dSValentin Clement   void runOnOperation() override final {
20527b5132daSValentin Clement     auto mod = getModule();
20537b5132daSValentin Clement     if (!forcedTargetTriple.empty()) {
20547b5132daSValentin Clement       fir::setTargetTriple(mod, forcedTargetTriple);
20557b5132daSValentin Clement     }
20567b5132daSValentin Clement 
2057044d5b5dSValentin Clement     auto *context = getModule().getContext();
2058044d5b5dSValentin Clement     fir::LLVMTypeConverter typeConverter{getModule()};
2059044d5b5dSValentin Clement     mlir::OwningRewritePatternList pattern(context);
2060df3b9810SValentin Clement     pattern.insert<
2061420ad7ceSAndrzej Warzynski         AbsentOpConversion, AddcOpConversion, AddrOfOpConversion,
20621a2ec667SValentin Clement         AllocaOpConversion, BoxAddrOpConversion, BoxCharLenOpConversion,
20631a2ec667SValentin Clement         BoxDimsOpConversion, BoxEleSizeOpConversion, BoxIsAllocOpConversion,
20641a2ec667SValentin Clement         BoxIsArrayOpConversion, BoxIsPtrOpConversion, BoxRankOpConversion,
2065e38ef2ffSValentin Clement         BoxTypeDescOpConversion, CallOpConversion, CmpcOpConversion,
2066e81d73edSDiana Picus         ConstcOpConversion, ConvertOpConversion, DispatchOpConversion,
2067e81d73edSDiana Picus         DispatchTableOpConversion, DTEntryOpConversion, DivcOpConversion,
2068*af6ee580SValentin Clement         EmboxOpConversion, EmboxCharOpConversion, ExtractValueOpConversion,
2069*af6ee580SValentin Clement         HasValueOpConversion, GenTypeDescOpConversion, GlobalLenOpConversion,
2070*af6ee580SValentin Clement         GlobalOpConversion, InsertOnRangeOpConversion, InsertValueOpConversion,
2071e81d73edSDiana Picus         IsPresentOpConversion, LoadOpConversion, NegcOpConversion,
2072e81d73edSDiana Picus         MulcOpConversion, SelectCaseOpConversion, SelectOpConversion,
2073e81d73edSDiana Picus         SelectRankOpConversion, SelectTypeOpConversion, ShapeOpConversion,
2074e81d73edSDiana Picus         ShapeShiftOpConversion, ShiftOpConversion, SliceOpConversion,
2075e81d73edSDiana Picus         StoreOpConversion, StringLitOpConversion, SubcOpConversion,
2076e81d73edSDiana Picus         UnboxCharOpConversion, UndefOpConversion, UnreachableOpConversion,
2077e81d73edSDiana Picus         ZeroOpConversion>(typeConverter);
2078044d5b5dSValentin Clement     mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern);
2079044d5b5dSValentin Clement     mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter,
2080044d5b5dSValentin Clement                                                             pattern);
2081044d5b5dSValentin Clement     mlir::ConversionTarget target{*context};
2082044d5b5dSValentin Clement     target.addLegalDialect<mlir::LLVM::LLVMDialect>();
2083044d5b5dSValentin Clement 
2084044d5b5dSValentin Clement     // required NOPs for applying a full conversion
2085044d5b5dSValentin Clement     target.addLegalOp<mlir::ModuleOp>();
2086044d5b5dSValentin Clement 
2087044d5b5dSValentin Clement     // apply the patterns
2088044d5b5dSValentin Clement     if (mlir::failed(mlir::applyFullConversion(getModule(), target,
2089044d5b5dSValentin Clement                                                std::move(pattern)))) {
2090044d5b5dSValentin Clement       signalPassFailure();
2091044d5b5dSValentin Clement     }
2092044d5b5dSValentin Clement   }
2093044d5b5dSValentin Clement };
2094044d5b5dSValentin Clement } // namespace
2095044d5b5dSValentin Clement 
2096044d5b5dSValentin Clement std::unique_ptr<mlir::Pass> fir::createFIRToLLVMPass() {
2097044d5b5dSValentin Clement   return std::make_unique<FIRToLLVMLowering>();
2098044d5b5dSValentin Clement }
2099