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"
14*1f551032SValentin Clement #include "CGOps.h"
15044d5b5dSValentin Clement #include "PassDetail.h"
16b6e44ecdSValentin Clement #include "flang/ISO_Fortran_binding.h"
1739f4ef81SValentin Clement #include "flang/Optimizer/Dialect/FIRAttr.h"
18044d5b5dSValentin Clement #include "flang/Optimizer/Dialect/FIROps.h"
19af6ee580SValentin Clement #include "flang/Optimizer/Support/TypeCode.h"
20044d5b5dSValentin Clement #include "mlir/Conversion/ArithmeticToLLVM/ArithmeticToLLVM.h"
21044d5b5dSValentin Clement #include "mlir/Conversion/LLVMCommon/Pattern.h"
22044d5b5dSValentin Clement #include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h"
23044d5b5dSValentin Clement #include "mlir/IR/BuiltinTypes.h"
243ae8e442SValentin Clement #include "mlir/IR/Matchers.h"
25044d5b5dSValentin Clement #include "mlir/Pass/Pass.h"
26044d5b5dSValentin Clement #include "llvm/ADT/ArrayRef.h"
27044d5b5dSValentin Clement 
28044d5b5dSValentin Clement #define DEBUG_TYPE "flang-codegen"
29044d5b5dSValentin Clement 
30044d5b5dSValentin Clement // fir::LLVMTypeConverter for converting to LLVM IR dialect types.
31044d5b5dSValentin Clement #include "TypeConverter.h"
32044d5b5dSValentin Clement 
33af6ee580SValentin Clement // TODO: This should really be recovered from the specified target.
34af6ee580SValentin Clement static constexpr unsigned defaultAlign = 8;
35af6ee580SValentin Clement 
36b6e44ecdSValentin Clement /// `fir.box` attribute values as defined for CFI_attribute_t in
37b6e44ecdSValentin Clement /// flang/ISO_Fortran_binding.h.
38b6e44ecdSValentin Clement static constexpr unsigned kAttrPointer = CFI_attribute_pointer;
39b6e44ecdSValentin Clement static constexpr unsigned kAttrAllocatable = CFI_attribute_allocatable;
40b6e44ecdSValentin Clement 
411e6d9c06SDiana Picus static mlir::LLVM::ConstantOp
421e6d9c06SDiana Picus genConstantIndex(mlir::Location loc, mlir::Type ity,
431e6d9c06SDiana Picus                  mlir::ConversionPatternRewriter &rewriter,
441e6d9c06SDiana Picus                  std::int64_t offset) {
451e6d9c06SDiana Picus   auto cattr = rewriter.getI64IntegerAttr(offset);
461e6d9c06SDiana Picus   return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr);
471e6d9c06SDiana Picus }
481e6d9c06SDiana Picus 
4939f4ef81SValentin Clement static Block *createBlock(mlir::ConversionPatternRewriter &rewriter,
5039f4ef81SValentin Clement                           mlir::Block *insertBefore) {
5139f4ef81SValentin Clement   assert(insertBefore && "expected valid insertion block");
5239f4ef81SValentin Clement   return rewriter.createBlock(insertBefore->getParent(),
5339f4ef81SValentin Clement                               mlir::Region::iterator(insertBefore));
5439f4ef81SValentin Clement }
5539f4ef81SValentin Clement 
56044d5b5dSValentin Clement namespace {
57044d5b5dSValentin Clement /// FIR conversion pattern template
58044d5b5dSValentin Clement template <typename FromOp>
59044d5b5dSValentin Clement class FIROpConversion : public mlir::ConvertOpToLLVMPattern<FromOp> {
60044d5b5dSValentin Clement public:
61044d5b5dSValentin Clement   explicit FIROpConversion(fir::LLVMTypeConverter &lowering)
62044d5b5dSValentin Clement       : mlir::ConvertOpToLLVMPattern<FromOp>(lowering) {}
63044d5b5dSValentin Clement 
64044d5b5dSValentin Clement protected:
65044d5b5dSValentin Clement   mlir::Type convertType(mlir::Type ty) const {
66044d5b5dSValentin Clement     return lowerTy().convertType(ty);
67044d5b5dSValentin Clement   }
68044d5b5dSValentin Clement 
69df3b9810SValentin Clement   mlir::LLVM::ConstantOp
70af6ee580SValentin Clement   genI32Constant(mlir::Location loc, mlir::ConversionPatternRewriter &rewriter,
71af6ee580SValentin Clement                  int value) const {
72af6ee580SValentin Clement     mlir::Type i32Ty = rewriter.getI32Type();
73af6ee580SValentin Clement     mlir::IntegerAttr attr = rewriter.getI32IntegerAttr(value);
74af6ee580SValentin Clement     return rewriter.create<mlir::LLVM::ConstantOp>(loc, i32Ty, attr);
75af6ee580SValentin Clement   }
76af6ee580SValentin Clement 
77af6ee580SValentin Clement   mlir::LLVM::ConstantOp
78df3b9810SValentin Clement   genConstantOffset(mlir::Location loc,
79df3b9810SValentin Clement                     mlir::ConversionPatternRewriter &rewriter,
80df3b9810SValentin Clement                     int offset) const {
81af6ee580SValentin Clement     mlir::Type ity = lowerTy().offsetType();
82af6ee580SValentin Clement     mlir::IntegerAttr cattr = rewriter.getI32IntegerAttr(offset);
83df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr);
84df3b9810SValentin Clement   }
85df3b9810SValentin Clement 
86b6e44ecdSValentin Clement   /// Construct code sequence to extract the specifc value from a `fir.box`.
87b6e44ecdSValentin Clement   mlir::Value getValueFromBox(mlir::Location loc, mlir::Value box,
88df3b9810SValentin Clement                               mlir::Type resultTy,
89b6e44ecdSValentin Clement                               mlir::ConversionPatternRewriter &rewriter,
90b6e44ecdSValentin Clement                               unsigned boxValue) const {
91df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
92b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp cValuePos =
93b6e44ecdSValentin Clement         genConstantOffset(loc, rewriter, boxValue);
94df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(resultTy);
95df3b9810SValentin Clement     auto p = rewriter.create<mlir::LLVM::GEPOp>(
96b6e44ecdSValentin Clement         loc, pty, mlir::ValueRange{box, c0, cValuePos});
97df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, resultTy, p);
98df3b9810SValentin Clement   }
99df3b9810SValentin Clement 
100df3b9810SValentin Clement   /// Method to construct code sequence to get the triple for dimension `dim`
101df3b9810SValentin Clement   /// from a box.
102df3b9810SValentin Clement   SmallVector<mlir::Value, 3>
103df3b9810SValentin Clement   getDimsFromBox(mlir::Location loc, ArrayRef<mlir::Type> retTys,
104df3b9810SValentin Clement                  mlir::Value box, mlir::Value dim,
105df3b9810SValentin Clement                  mlir::ConversionPatternRewriter &rewriter) const {
106df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
107df3b9810SValentin Clement     mlir::LLVM::ConstantOp cDims =
108df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kDimsPosInBox);
109df3b9810SValentin Clement     mlir::LLVM::LoadOp l0 =
110df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 0, retTys[0], rewriter);
111df3b9810SValentin Clement     mlir::LLVM::LoadOp l1 =
112df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 1, retTys[1], rewriter);
113df3b9810SValentin Clement     mlir::LLVM::LoadOp l2 =
114df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 2, retTys[2], rewriter);
115df3b9810SValentin Clement     return {l0.getResult(), l1.getResult(), l2.getResult()};
116df3b9810SValentin Clement   }
117df3b9810SValentin Clement 
118df3b9810SValentin Clement   mlir::LLVM::LoadOp
119df3b9810SValentin Clement   loadFromOffset(mlir::Location loc, mlir::Value a, mlir::LLVM::ConstantOp c0,
120df3b9810SValentin Clement                  mlir::LLVM::ConstantOp cDims, mlir::Value dim, int off,
121df3b9810SValentin Clement                  mlir::Type ty,
122df3b9810SValentin Clement                  mlir::ConversionPatternRewriter &rewriter) const {
123df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
124df3b9810SValentin Clement     mlir::LLVM::ConstantOp c = genConstantOffset(loc, rewriter, off);
125df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, a, c0, cDims, dim, c);
126df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
127df3b9810SValentin Clement   }
128df3b9810SValentin Clement 
129df3b9810SValentin Clement   /// Read base address from a fir.box. Returned address has type ty.
130df3b9810SValentin Clement   mlir::Value
131df3b9810SValentin Clement   loadBaseAddrFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box,
132df3b9810SValentin Clement                       mlir::ConversionPatternRewriter &rewriter) const {
133df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
134df3b9810SValentin Clement     mlir::LLVM::ConstantOp cAddr =
135df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kAddrPosInBox);
136df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
137df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cAddr);
138df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
139df3b9810SValentin Clement   }
140df3b9810SValentin Clement 
141df3b9810SValentin Clement   mlir::Value
142df3b9810SValentin Clement   loadElementSizeFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box,
143df3b9810SValentin Clement                          mlir::ConversionPatternRewriter &rewriter) const {
144df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
145df3b9810SValentin Clement     mlir::LLVM::ConstantOp cElemLen =
146df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kElemLenPosInBox);
147df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
148df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cElemLen);
149df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
150df3b9810SValentin Clement   }
151df3b9810SValentin Clement 
152b6e44ecdSValentin Clement   // Load the attribute from the \p box and perform a check against \p maskValue
153b6e44ecdSValentin Clement   // The final comparison is implemented as `(attribute & maskValue) != 0`.
154b6e44ecdSValentin Clement   mlir::Value genBoxAttributeCheck(mlir::Location loc, mlir::Value box,
155b6e44ecdSValentin Clement                                    mlir::ConversionPatternRewriter &rewriter,
156b6e44ecdSValentin Clement                                    unsigned maskValue) const {
157b6e44ecdSValentin Clement     mlir::Type attrTy = rewriter.getI32Type();
158b6e44ecdSValentin Clement     mlir::Value attribute =
159b6e44ecdSValentin Clement         getValueFromBox(loc, box, attrTy, rewriter, kAttributePosInBox);
160b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp attrMask =
161b6e44ecdSValentin Clement         genConstantOffset(loc, rewriter, maskValue);
162b6e44ecdSValentin Clement     auto maskRes =
163b6e44ecdSValentin Clement         rewriter.create<mlir::LLVM::AndOp>(loc, attrTy, attribute, attrMask);
164b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
165b6e44ecdSValentin Clement     return rewriter.create<mlir::LLVM::ICmpOp>(
166b6e44ecdSValentin Clement         loc, mlir::LLVM::ICmpPredicate::ne, maskRes, c0);
167b6e44ecdSValentin Clement   }
168b6e44ecdSValentin Clement 
169af6ee580SValentin Clement   // Get the element type given an LLVM type that is of the form
170af6ee580SValentin Clement   // [llvm.ptr](array|struct|vector)+ and the provided indexes.
171af6ee580SValentin Clement   static mlir::Type getBoxEleTy(mlir::Type type,
172af6ee580SValentin Clement                                 llvm::ArrayRef<unsigned> indexes) {
173af6ee580SValentin Clement     if (auto t = type.dyn_cast<mlir::LLVM::LLVMPointerType>())
174af6ee580SValentin Clement       type = t.getElementType();
175af6ee580SValentin Clement     for (auto i : indexes) {
176af6ee580SValentin Clement       if (auto t = type.dyn_cast<mlir::LLVM::LLVMStructType>()) {
177af6ee580SValentin Clement         assert(!t.isOpaque() && i < t.getBody().size());
178af6ee580SValentin Clement         type = t.getBody()[i];
179af6ee580SValentin Clement       } else if (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
180af6ee580SValentin Clement         type = t.getElementType();
181af6ee580SValentin Clement       } else if (auto t = type.dyn_cast<mlir::VectorType>()) {
182af6ee580SValentin Clement         type = t.getElementType();
183af6ee580SValentin Clement       } else {
184af6ee580SValentin Clement         fir::emitFatalError(mlir::UnknownLoc::get(type.getContext()),
185af6ee580SValentin Clement                             "request for invalid box element type");
186af6ee580SValentin Clement       }
187af6ee580SValentin Clement     }
188af6ee580SValentin Clement     return type;
189af6ee580SValentin Clement   }
190af6ee580SValentin Clement 
191df3b9810SValentin Clement   template <typename... ARGS>
192df3b9810SValentin Clement   mlir::LLVM::GEPOp genGEP(mlir::Location loc, mlir::Type ty,
193df3b9810SValentin Clement                            mlir::ConversionPatternRewriter &rewriter,
194df3b9810SValentin Clement                            mlir::Value base, ARGS... args) const {
195df3b9810SValentin Clement     SmallVector<mlir::Value> cv{args...};
196df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::GEPOp>(loc, ty, base, cv);
197df3b9810SValentin Clement   }
198df3b9810SValentin Clement 
1991e6d9c06SDiana Picus   /// Perform an extension or truncation as needed on an integer value. Lowering
2001e6d9c06SDiana Picus   /// to the specific target may involve some sign-extending or truncation of
2011e6d9c06SDiana Picus   /// values, particularly to fit them from abstract box types to the
2021e6d9c06SDiana Picus   /// appropriate reified structures.
2031e6d9c06SDiana Picus   mlir::Value integerCast(mlir::Location loc,
2041e6d9c06SDiana Picus                           mlir::ConversionPatternRewriter &rewriter,
2051e6d9c06SDiana Picus                           mlir::Type ty, mlir::Value val) const {
2061e6d9c06SDiana Picus     auto valTy = val.getType();
2071e6d9c06SDiana Picus     // If the value was not yet lowered, lower its type so that it can
2081e6d9c06SDiana Picus     // be used in getPrimitiveTypeSizeInBits.
2091e6d9c06SDiana Picus     if (!valTy.isa<mlir::IntegerType>())
2101e6d9c06SDiana Picus       valTy = convertType(valTy);
2111e6d9c06SDiana Picus     auto toSize = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
2121e6d9c06SDiana Picus     auto fromSize = mlir::LLVM::getPrimitiveTypeSizeInBits(valTy);
2131e6d9c06SDiana Picus     if (toSize < fromSize)
2141e6d9c06SDiana Picus       return rewriter.create<mlir::LLVM::TruncOp>(loc, ty, val);
2151e6d9c06SDiana Picus     if (toSize > fromSize)
2161e6d9c06SDiana Picus       return rewriter.create<mlir::LLVM::SExtOp>(loc, ty, val);
2171e6d9c06SDiana Picus     return val;
2181e6d9c06SDiana Picus   }
2191e6d9c06SDiana Picus 
220044d5b5dSValentin Clement   fir::LLVMTypeConverter &lowerTy() const {
221044d5b5dSValentin Clement     return *static_cast<fir::LLVMTypeConverter *>(this->getTypeConverter());
222044d5b5dSValentin Clement   }
223044d5b5dSValentin Clement };
224044d5b5dSValentin Clement 
2253ae8e442SValentin Clement /// FIR conversion pattern template
2263ae8e442SValentin Clement template <typename FromOp>
2273ae8e442SValentin Clement class FIROpAndTypeConversion : public FIROpConversion<FromOp> {
2283ae8e442SValentin Clement public:
2293ae8e442SValentin Clement   using FIROpConversion<FromOp>::FIROpConversion;
2303ae8e442SValentin Clement   using OpAdaptor = typename FromOp::Adaptor;
2313ae8e442SValentin Clement 
2323ae8e442SValentin Clement   mlir::LogicalResult
2333ae8e442SValentin Clement   matchAndRewrite(FromOp op, OpAdaptor adaptor,
2343ae8e442SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const final {
2353ae8e442SValentin Clement     mlir::Type ty = this->convertType(op.getType());
2363ae8e442SValentin Clement     return doRewrite(op, ty, adaptor, rewriter);
2373ae8e442SValentin Clement   }
2383ae8e442SValentin Clement 
2393ae8e442SValentin Clement   virtual mlir::LogicalResult
2403ae8e442SValentin Clement   doRewrite(FromOp addr, mlir::Type ty, OpAdaptor adaptor,
2413ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const = 0;
2423ae8e442SValentin Clement };
2433ae8e442SValentin Clement 
244420ad7ceSAndrzej Warzynski /// Create value signaling an absent optional argument in a call, e.g.
245420ad7ceSAndrzej Warzynski /// `fir.absent !fir.ref<i64>` -->  `llvm.mlir.null : !llvm.ptr<i64>`
246420ad7ceSAndrzej Warzynski struct AbsentOpConversion : public FIROpConversion<fir::AbsentOp> {
247420ad7ceSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
248420ad7ceSAndrzej Warzynski 
249420ad7ceSAndrzej Warzynski   mlir::LogicalResult
250420ad7ceSAndrzej Warzynski   matchAndRewrite(fir::AbsentOp absent, OpAdaptor,
251420ad7ceSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
252420ad7ceSAndrzej Warzynski     mlir::Type ty = convertType(absent.getType());
253420ad7ceSAndrzej Warzynski     mlir::Location loc = absent.getLoc();
254420ad7ceSAndrzej Warzynski 
255420ad7ceSAndrzej Warzynski     if (absent.getType().isa<fir::BoxCharType>()) {
256420ad7ceSAndrzej Warzynski       auto structTy = ty.cast<mlir::LLVM::LLVMStructType>();
257420ad7ceSAndrzej Warzynski       assert(!structTy.isOpaque() && !structTy.getBody().empty());
258420ad7ceSAndrzej Warzynski       auto undefStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
259420ad7ceSAndrzej Warzynski       auto nullField =
260420ad7ceSAndrzej Warzynski           rewriter.create<mlir::LLVM::NullOp>(loc, structTy.getBody()[0]);
261420ad7ceSAndrzej Warzynski       mlir::MLIRContext *ctx = absent.getContext();
262420ad7ceSAndrzej Warzynski       auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
263420ad7ceSAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
264420ad7ceSAndrzej Warzynski           absent, ty, undefStruct, nullField, c0);
265420ad7ceSAndrzej Warzynski     } else {
266420ad7ceSAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(absent, ty);
267420ad7ceSAndrzej Warzynski     }
268420ad7ceSAndrzej Warzynski     return success();
269420ad7ceSAndrzej Warzynski   }
270420ad7ceSAndrzej Warzynski };
271420ad7ceSAndrzej Warzynski 
2720c4a7a52SValentin Clement // Lower `fir.address_of` operation to `llvm.address_of` operation.
273044d5b5dSValentin Clement struct AddrOfOpConversion : public FIROpConversion<fir::AddrOfOp> {
274044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
275044d5b5dSValentin Clement 
276044d5b5dSValentin Clement   mlir::LogicalResult
277044d5b5dSValentin Clement   matchAndRewrite(fir::AddrOfOp addr, OpAdaptor adaptor,
278044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
279044d5b5dSValentin Clement     auto ty = convertType(addr.getType());
280044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::AddressOfOp>(
281044d5b5dSValentin Clement         addr, ty, addr.symbol().getRootReference().getValue());
282044d5b5dSValentin Clement     return success();
283044d5b5dSValentin Clement   }
284044d5b5dSValentin Clement };
2851e6d9c06SDiana Picus } // namespace
2861e6d9c06SDiana Picus 
2871e6d9c06SDiana Picus /// Lookup the function to compute the memory size of this parametric derived
2881e6d9c06SDiana Picus /// type. The size of the object may depend on the LEN type parameters of the
2891e6d9c06SDiana Picus /// derived type.
2901e6d9c06SDiana Picus static mlir::LLVM::LLVMFuncOp
2911e6d9c06SDiana Picus getDependentTypeMemSizeFn(fir::RecordType recTy, fir::AllocaOp op,
2921e6d9c06SDiana Picus                           mlir::ConversionPatternRewriter &rewriter) {
2931e6d9c06SDiana Picus   auto module = op->getParentOfType<mlir::ModuleOp>();
2941e6d9c06SDiana Picus   std::string name = recTy.getName().str() + "P.mem.size";
2951e6d9c06SDiana Picus   return module.lookupSymbol<mlir::LLVM::LLVMFuncOp>(name);
2961e6d9c06SDiana Picus }
2971e6d9c06SDiana Picus 
2981e6d9c06SDiana Picus namespace {
2991e6d9c06SDiana Picus /// convert to LLVM IR dialect `alloca`
3001e6d9c06SDiana Picus struct AllocaOpConversion : public FIROpConversion<fir::AllocaOp> {
3011e6d9c06SDiana Picus   using FIROpConversion::FIROpConversion;
3021e6d9c06SDiana Picus 
3031e6d9c06SDiana Picus   mlir::LogicalResult
3041e6d9c06SDiana Picus   matchAndRewrite(fir::AllocaOp alloc, OpAdaptor adaptor,
3051e6d9c06SDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
3061e6d9c06SDiana Picus     mlir::ValueRange operands = adaptor.getOperands();
3071e6d9c06SDiana Picus     auto loc = alloc.getLoc();
3081e6d9c06SDiana Picus     mlir::Type ity = lowerTy().indexType();
3091e6d9c06SDiana Picus     unsigned i = 0;
3101e6d9c06SDiana Picus     mlir::Value size = genConstantIndex(loc, ity, rewriter, 1).getResult();
3111e6d9c06SDiana Picus     mlir::Type ty = convertType(alloc.getType());
3121e6d9c06SDiana Picus     mlir::Type resultTy = ty;
3131e6d9c06SDiana Picus     if (alloc.hasLenParams()) {
3141e6d9c06SDiana Picus       unsigned end = alloc.numLenParams();
3151e6d9c06SDiana Picus       llvm::SmallVector<mlir::Value> lenParams;
3161e6d9c06SDiana Picus       for (; i < end; ++i)
3171e6d9c06SDiana Picus         lenParams.push_back(operands[i]);
3181e6d9c06SDiana Picus       mlir::Type scalarType = fir::unwrapSequenceType(alloc.getInType());
3191e6d9c06SDiana Picus       if (auto chrTy = scalarType.dyn_cast<fir::CharacterType>()) {
3201e6d9c06SDiana Picus         fir::CharacterType rawCharTy = fir::CharacterType::getUnknownLen(
3211e6d9c06SDiana Picus             chrTy.getContext(), chrTy.getFKind());
3221e6d9c06SDiana Picus         ty = mlir::LLVM::LLVMPointerType::get(convertType(rawCharTy));
3231e6d9c06SDiana Picus         assert(end == 1);
3241e6d9c06SDiana Picus         size = integerCast(loc, rewriter, ity, lenParams[0]);
3251e6d9c06SDiana Picus       } else if (auto recTy = scalarType.dyn_cast<fir::RecordType>()) {
3261e6d9c06SDiana Picus         mlir::LLVM::LLVMFuncOp memSizeFn =
3271e6d9c06SDiana Picus             getDependentTypeMemSizeFn(recTy, alloc, rewriter);
3281e6d9c06SDiana Picus         if (!memSizeFn)
3291e6d9c06SDiana Picus           emitError(loc, "did not find allocation function");
3301e6d9c06SDiana Picus         mlir::NamedAttribute attr = rewriter.getNamedAttr(
3311e6d9c06SDiana Picus             "callee", mlir::SymbolRefAttr::get(memSizeFn));
3321e6d9c06SDiana Picus         auto call = rewriter.create<mlir::LLVM::CallOp>(
3331e6d9c06SDiana Picus             loc, ity, lenParams, llvm::ArrayRef<mlir::NamedAttribute>{attr});
3341e6d9c06SDiana Picus         size = call.getResult(0);
3351e6d9c06SDiana Picus         ty = mlir::LLVM::LLVMPointerType::get(
3361e6d9c06SDiana Picus             mlir::IntegerType::get(alloc.getContext(), 8));
3371e6d9c06SDiana Picus       } else {
3381e6d9c06SDiana Picus         return emitError(loc, "unexpected type ")
3391e6d9c06SDiana Picus                << scalarType << " with type parameters";
3401e6d9c06SDiana Picus       }
3411e6d9c06SDiana Picus     }
3421e6d9c06SDiana Picus     if (alloc.hasShapeOperands()) {
3431e6d9c06SDiana Picus       mlir::Type allocEleTy = fir::unwrapRefType(alloc.getType());
3441e6d9c06SDiana Picus       // Scale the size by constant factors encoded in the array type.
3451e6d9c06SDiana Picus       if (auto seqTy = allocEleTy.dyn_cast<fir::SequenceType>()) {
3461e6d9c06SDiana Picus         fir::SequenceType::Extent constSize = 1;
3471e6d9c06SDiana Picus         for (auto extent : seqTy.getShape())
3481e6d9c06SDiana Picus           if (extent != fir::SequenceType::getUnknownExtent())
3491e6d9c06SDiana Picus             constSize *= extent;
3501e6d9c06SDiana Picus         mlir::Value constVal{
3511e6d9c06SDiana Picus             genConstantIndex(loc, ity, rewriter, constSize).getResult()};
3521e6d9c06SDiana Picus         size = rewriter.create<mlir::LLVM::MulOp>(loc, ity, size, constVal);
3531e6d9c06SDiana Picus       }
3541e6d9c06SDiana Picus       unsigned end = operands.size();
3551e6d9c06SDiana Picus       for (; i < end; ++i)
3561e6d9c06SDiana Picus         size = rewriter.create<mlir::LLVM::MulOp>(
3571e6d9c06SDiana Picus             loc, ity, size, integerCast(loc, rewriter, ity, operands[i]));
3581e6d9c06SDiana Picus     }
3591e6d9c06SDiana Picus     if (ty == resultTy) {
3601e6d9c06SDiana Picus       // Do not emit the bitcast if ty and resultTy are the same.
3611e6d9c06SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::AllocaOp>(alloc, ty, size,
3621e6d9c06SDiana Picus                                                         alloc->getAttrs());
3631e6d9c06SDiana Picus     } else {
3641e6d9c06SDiana Picus       auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, ty, size,
3651e6d9c06SDiana Picus                                                       alloc->getAttrs());
3661e6d9c06SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(alloc, resultTy, al);
3671e6d9c06SDiana Picus     }
3681e6d9c06SDiana Picus     return success();
3691e6d9c06SDiana Picus   }
3701e6d9c06SDiana Picus };
371044d5b5dSValentin Clement 
372df3b9810SValentin Clement /// Lower `fir.box_addr` to the sequence of operations to extract the first
373df3b9810SValentin Clement /// element of the box.
374df3b9810SValentin Clement struct BoxAddrOpConversion : public FIROpConversion<fir::BoxAddrOp> {
375df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
376df3b9810SValentin Clement 
377df3b9810SValentin Clement   mlir::LogicalResult
378df3b9810SValentin Clement   matchAndRewrite(fir::BoxAddrOp boxaddr, OpAdaptor adaptor,
379df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
380df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
381df3b9810SValentin Clement     auto loc = boxaddr.getLoc();
382df3b9810SValentin Clement     mlir::Type ty = convertType(boxaddr.getType());
383df3b9810SValentin Clement     if (auto argty = boxaddr.val().getType().dyn_cast<fir::BoxType>()) {
384df3b9810SValentin Clement       rewriter.replaceOp(boxaddr, loadBaseAddrFromBox(loc, ty, a, rewriter));
385df3b9810SValentin Clement     } else {
386df3b9810SValentin Clement       auto c0attr = rewriter.getI32IntegerAttr(0);
387df3b9810SValentin Clement       auto c0 = mlir::ArrayAttr::get(boxaddr.getContext(), c0attr);
388df3b9810SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(boxaddr, ty, a,
389df3b9810SValentin Clement                                                               c0);
390df3b9810SValentin Clement     }
391df3b9810SValentin Clement     return success();
392df3b9810SValentin Clement   }
393df3b9810SValentin Clement };
394df3b9810SValentin Clement 
395df3b9810SValentin Clement /// Lower `fir.box_dims` to a sequence of operations to extract the requested
396df3b9810SValentin Clement /// dimension infomartion from the boxed value.
397df3b9810SValentin Clement /// Result in a triple set of GEPs and loads.
398df3b9810SValentin Clement struct BoxDimsOpConversion : public FIROpConversion<fir::BoxDimsOp> {
399df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
400df3b9810SValentin Clement 
401df3b9810SValentin Clement   mlir::LogicalResult
402df3b9810SValentin Clement   matchAndRewrite(fir::BoxDimsOp boxdims, OpAdaptor adaptor,
403df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
404df3b9810SValentin Clement     SmallVector<mlir::Type, 3> resultTypes = {
405df3b9810SValentin Clement         convertType(boxdims.getResult(0).getType()),
406df3b9810SValentin Clement         convertType(boxdims.getResult(1).getType()),
407df3b9810SValentin Clement         convertType(boxdims.getResult(2).getType()),
408df3b9810SValentin Clement     };
409df3b9810SValentin Clement     auto results =
410df3b9810SValentin Clement         getDimsFromBox(boxdims.getLoc(), resultTypes, adaptor.getOperands()[0],
411df3b9810SValentin Clement                        adaptor.getOperands()[1], rewriter);
412df3b9810SValentin Clement     rewriter.replaceOp(boxdims, results);
413df3b9810SValentin Clement     return success();
414df3b9810SValentin Clement   }
415df3b9810SValentin Clement };
416df3b9810SValentin Clement 
417df3b9810SValentin Clement /// Lower `fir.box_elesize` to a sequence of operations ro extract the size of
418df3b9810SValentin Clement /// an element in the boxed value.
419df3b9810SValentin Clement struct BoxEleSizeOpConversion : public FIROpConversion<fir::BoxEleSizeOp> {
420df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
421df3b9810SValentin Clement 
422df3b9810SValentin Clement   mlir::LogicalResult
423df3b9810SValentin Clement   matchAndRewrite(fir::BoxEleSizeOp boxelesz, OpAdaptor adaptor,
424df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
425df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
426df3b9810SValentin Clement     auto loc = boxelesz.getLoc();
427df3b9810SValentin Clement     auto ty = convertType(boxelesz.getType());
428b6e44ecdSValentin Clement     auto elemSize = getValueFromBox(loc, a, ty, rewriter, kElemLenPosInBox);
429b6e44ecdSValentin Clement     rewriter.replaceOp(boxelesz, elemSize);
430b6e44ecdSValentin Clement     return success();
431b6e44ecdSValentin Clement   }
432b6e44ecdSValentin Clement };
433b6e44ecdSValentin Clement 
434b6e44ecdSValentin Clement /// Lower `fir.box_isalloc` to a sequence of operations to determine if the
435b6e44ecdSValentin Clement /// boxed value was from an ALLOCATABLE entity.
436b6e44ecdSValentin Clement struct BoxIsAllocOpConversion : public FIROpConversion<fir::BoxIsAllocOp> {
437b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
438b6e44ecdSValentin Clement 
439b6e44ecdSValentin Clement   mlir::LogicalResult
440b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsAllocOp boxisalloc, OpAdaptor adaptor,
441b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
442b6e44ecdSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
443b6e44ecdSValentin Clement     auto loc = boxisalloc.getLoc();
444b6e44ecdSValentin Clement     mlir::Value check =
445b6e44ecdSValentin Clement         genBoxAttributeCheck(loc, box, rewriter, kAttrAllocatable);
446b6e44ecdSValentin Clement     rewriter.replaceOp(boxisalloc, check);
447b6e44ecdSValentin Clement     return success();
448b6e44ecdSValentin Clement   }
449b6e44ecdSValentin Clement };
450b6e44ecdSValentin Clement 
451b6e44ecdSValentin Clement /// Lower `fir.box_isarray` to a sequence of operations to determine if the
452b6e44ecdSValentin Clement /// boxed is an array.
453b6e44ecdSValentin Clement struct BoxIsArrayOpConversion : public FIROpConversion<fir::BoxIsArrayOp> {
454b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
455b6e44ecdSValentin Clement 
456b6e44ecdSValentin Clement   mlir::LogicalResult
457b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsArrayOp boxisarray, OpAdaptor adaptor,
458b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
459b6e44ecdSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
460b6e44ecdSValentin Clement     auto loc = boxisarray.getLoc();
461b6e44ecdSValentin Clement     auto rank =
462b6e44ecdSValentin Clement         getValueFromBox(loc, a, rewriter.getI32Type(), rewriter, kRankPosInBox);
463b6e44ecdSValentin Clement     auto c0 = genConstantOffset(loc, rewriter, 0);
464b6e44ecdSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
465b6e44ecdSValentin Clement         boxisarray, mlir::LLVM::ICmpPredicate::ne, rank, c0);
466b6e44ecdSValentin Clement     return success();
467b6e44ecdSValentin Clement   }
468b6e44ecdSValentin Clement };
469b6e44ecdSValentin Clement 
470b6e44ecdSValentin Clement /// Lower `fir.box_isptr` to a sequence of operations to determined if the
471b6e44ecdSValentin Clement /// boxed value was from a POINTER entity.
472b6e44ecdSValentin Clement struct BoxIsPtrOpConversion : public FIROpConversion<fir::BoxIsPtrOp> {
473b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
474b6e44ecdSValentin Clement 
475b6e44ecdSValentin Clement   mlir::LogicalResult
476b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsPtrOp boxisptr, OpAdaptor adaptor,
477b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
478b6e44ecdSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
479b6e44ecdSValentin Clement     auto loc = boxisptr.getLoc();
480b6e44ecdSValentin Clement     mlir::Value check = genBoxAttributeCheck(loc, box, rewriter, kAttrPointer);
481b6e44ecdSValentin Clement     rewriter.replaceOp(boxisptr, check);
482df3b9810SValentin Clement     return success();
483df3b9810SValentin Clement   }
484df3b9810SValentin Clement };
485df3b9810SValentin Clement 
486df3b9810SValentin Clement /// Lower `fir.box_rank` to the sequence of operation to extract the rank from
487df3b9810SValentin Clement /// the box.
488df3b9810SValentin Clement struct BoxRankOpConversion : public FIROpConversion<fir::BoxRankOp> {
489df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
490df3b9810SValentin Clement 
491df3b9810SValentin Clement   mlir::LogicalResult
492df3b9810SValentin Clement   matchAndRewrite(fir::BoxRankOp boxrank, OpAdaptor adaptor,
493df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
494df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
495df3b9810SValentin Clement     auto loc = boxrank.getLoc();
496df3b9810SValentin Clement     mlir::Type ty = convertType(boxrank.getType());
497b6e44ecdSValentin Clement     auto result = getValueFromBox(loc, a, ty, rewriter, kRankPosInBox);
498df3b9810SValentin Clement     rewriter.replaceOp(boxrank, result);
499df3b9810SValentin Clement     return success();
500df3b9810SValentin Clement   }
501df3b9810SValentin Clement };
502df3b9810SValentin Clement 
5031a2ec667SValentin Clement /// Lower `fir.string_lit` to LLVM IR dialect operation.
5041a2ec667SValentin Clement struct StringLitOpConversion : public FIROpConversion<fir::StringLitOp> {
5051a2ec667SValentin Clement   using FIROpConversion::FIROpConversion;
5061a2ec667SValentin Clement 
5071a2ec667SValentin Clement   mlir::LogicalResult
5081a2ec667SValentin Clement   matchAndRewrite(fir::StringLitOp constop, OpAdaptor adaptor,
5091a2ec667SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
5101a2ec667SValentin Clement     auto ty = convertType(constop.getType());
5111a2ec667SValentin Clement     auto attr = constop.getValue();
5121a2ec667SValentin Clement     if (attr.isa<mlir::StringAttr>()) {
5131a2ec667SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(constop, ty, attr);
5141a2ec667SValentin Clement       return success();
5151a2ec667SValentin Clement     }
5161a2ec667SValentin Clement 
5171a2ec667SValentin Clement     auto arr = attr.cast<mlir::ArrayAttr>();
5181a2ec667SValentin Clement     auto charTy = constop.getType().cast<fir::CharacterType>();
5191a2ec667SValentin Clement     unsigned bits = lowerTy().characterBitsize(charTy);
5201a2ec667SValentin Clement     mlir::Type intTy = rewriter.getIntegerType(bits);
5211a2ec667SValentin Clement     auto attrs = llvm::map_range(
5221a2ec667SValentin Clement         arr.getValue(), [intTy, bits](mlir::Attribute attr) -> Attribute {
5231a2ec667SValentin Clement           return mlir::IntegerAttr::get(
5241a2ec667SValentin Clement               intTy,
5251a2ec667SValentin Clement               attr.cast<mlir::IntegerAttr>().getValue().sextOrTrunc(bits));
5261a2ec667SValentin Clement         });
5271a2ec667SValentin Clement     mlir::Type vecType = mlir::VectorType::get(arr.size(), intTy);
5281a2ec667SValentin Clement     auto denseAttr = mlir::DenseElementsAttr::get(
5291a2ec667SValentin Clement         vecType.cast<mlir::ShapedType>(), llvm::to_vector<8>(attrs));
5301a2ec667SValentin Clement     rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(constop, ty,
5311a2ec667SValentin Clement                                                          denseAttr);
5321a2ec667SValentin Clement     return success();
5331a2ec667SValentin Clement   }
5341a2ec667SValentin Clement };
5351a2ec667SValentin Clement 
536cc505c0bSKiran Chandramohan /// Lower `fir.boxproc_host` operation. Extracts the host pointer from the
537cc505c0bSKiran Chandramohan /// boxproc.
538cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
539cc505c0bSKiran Chandramohan struct BoxProcHostOpConversion : public FIROpConversion<fir::BoxProcHostOp> {
540cc505c0bSKiran Chandramohan   using FIROpConversion::FIROpConversion;
541cc505c0bSKiran Chandramohan 
542cc505c0bSKiran Chandramohan   mlir::LogicalResult
543cc505c0bSKiran Chandramohan   matchAndRewrite(fir::BoxProcHostOp boxprochost, OpAdaptor adaptor,
544cc505c0bSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
5457ce8c6fcSKiran Chandramohan     TODO(boxprochost.getLoc(), "fir.boxproc_host codegen");
5467ce8c6fcSKiran Chandramohan     return failure();
547cc505c0bSKiran Chandramohan   }
548cc505c0bSKiran Chandramohan };
549cc505c0bSKiran Chandramohan 
550e38ef2ffSValentin Clement /// Lower `fir.box_tdesc` to the sequence of operations to extract the type
551e38ef2ffSValentin Clement /// descriptor from the box.
552e38ef2ffSValentin Clement struct BoxTypeDescOpConversion : public FIROpConversion<fir::BoxTypeDescOp> {
553e38ef2ffSValentin Clement   using FIROpConversion::FIROpConversion;
554e38ef2ffSValentin Clement 
555e38ef2ffSValentin Clement   mlir::LogicalResult
556e38ef2ffSValentin Clement   matchAndRewrite(fir::BoxTypeDescOp boxtypedesc, OpAdaptor adaptor,
557e38ef2ffSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
558e38ef2ffSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
559e38ef2ffSValentin Clement     auto loc = boxtypedesc.getLoc();
560e38ef2ffSValentin Clement     mlir::Type typeTy =
561e38ef2ffSValentin Clement         fir::getDescFieldTypeModel<kTypePosInBox>()(boxtypedesc.getContext());
562e38ef2ffSValentin Clement     auto result = getValueFromBox(loc, box, typeTy, rewriter, kTypePosInBox);
563e38ef2ffSValentin Clement     auto typePtrTy = mlir::LLVM::LLVMPointerType::get(typeTy);
564e38ef2ffSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(boxtypedesc, typePtrTy,
565e38ef2ffSValentin Clement                                                         result);
566e38ef2ffSValentin Clement     return success();
567e38ef2ffSValentin Clement   }
568e38ef2ffSValentin Clement };
569e38ef2ffSValentin Clement 
570ddd11b9aSAndrzej Warzynski // `fir.call` -> `llvm.call`
571ddd11b9aSAndrzej Warzynski struct CallOpConversion : public FIROpConversion<fir::CallOp> {
572ddd11b9aSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
573ddd11b9aSAndrzej Warzynski 
574ddd11b9aSAndrzej Warzynski   mlir::LogicalResult
575ddd11b9aSAndrzej Warzynski   matchAndRewrite(fir::CallOp call, OpAdaptor adaptor,
576ddd11b9aSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
577ddd11b9aSAndrzej Warzynski     SmallVector<mlir::Type> resultTys;
578ddd11b9aSAndrzej Warzynski     for (auto r : call.getResults())
579ddd11b9aSAndrzej Warzynski       resultTys.push_back(convertType(r.getType()));
580ddd11b9aSAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
581ddd11b9aSAndrzej Warzynski         call, resultTys, adaptor.getOperands(), call->getAttrs());
582ddd11b9aSAndrzej Warzynski     return success();
583ddd11b9aSAndrzej Warzynski   }
584ddd11b9aSAndrzej Warzynski };
585ddd11b9aSAndrzej Warzynski 
586092cee5fSValentin Clement static mlir::Type getComplexEleTy(mlir::Type complex) {
587092cee5fSValentin Clement   if (auto cc = complex.dyn_cast<mlir::ComplexType>())
588092cee5fSValentin Clement     return cc.getElementType();
589092cee5fSValentin Clement   return complex.cast<fir::ComplexType>().getElementType();
590092cee5fSValentin Clement }
591092cee5fSValentin Clement 
592f1dfc027SDiana Picus /// Compare complex values
593f1dfc027SDiana Picus ///
594f1dfc027SDiana Picus /// Per 10.1, the only comparisons available are .EQ. (oeq) and .NE. (une).
595f1dfc027SDiana Picus ///
596f1dfc027SDiana Picus /// For completeness, all other comparison are done on the real component only.
597f1dfc027SDiana Picus struct CmpcOpConversion : public FIROpConversion<fir::CmpcOp> {
598f1dfc027SDiana Picus   using FIROpConversion::FIROpConversion;
599f1dfc027SDiana Picus 
600f1dfc027SDiana Picus   mlir::LogicalResult
601f1dfc027SDiana Picus   matchAndRewrite(fir::CmpcOp cmp, OpAdaptor adaptor,
602f1dfc027SDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
603f1dfc027SDiana Picus     mlir::ValueRange operands = adaptor.getOperands();
604f1dfc027SDiana Picus     mlir::MLIRContext *ctxt = cmp.getContext();
605f1dfc027SDiana Picus     mlir::Type eleTy = convertType(getComplexEleTy(cmp.lhs().getType()));
606f1dfc027SDiana Picus     mlir::Type resTy = convertType(cmp.getType());
607f1dfc027SDiana Picus     mlir::Location loc = cmp.getLoc();
608f1dfc027SDiana Picus     auto pos0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0));
609f1dfc027SDiana Picus     SmallVector<mlir::Value, 2> rp{rewriter.create<mlir::LLVM::ExtractValueOp>(
610f1dfc027SDiana Picus                                        loc, eleTy, operands[0], pos0),
611f1dfc027SDiana Picus                                    rewriter.create<mlir::LLVM::ExtractValueOp>(
612f1dfc027SDiana Picus                                        loc, eleTy, operands[1], pos0)};
613f1dfc027SDiana Picus     auto rcp =
614f1dfc027SDiana Picus         rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, rp, cmp->getAttrs());
615f1dfc027SDiana Picus     auto pos1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1));
616f1dfc027SDiana Picus     SmallVector<mlir::Value, 2> ip{rewriter.create<mlir::LLVM::ExtractValueOp>(
617f1dfc027SDiana Picus                                        loc, eleTy, operands[0], pos1),
618f1dfc027SDiana Picus                                    rewriter.create<mlir::LLVM::ExtractValueOp>(
619f1dfc027SDiana Picus                                        loc, eleTy, operands[1], pos1)};
620f1dfc027SDiana Picus     auto icp =
621f1dfc027SDiana Picus         rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, ip, cmp->getAttrs());
622f1dfc027SDiana Picus     SmallVector<mlir::Value, 2> cp{rcp, icp};
623f1dfc027SDiana Picus     switch (cmp.getPredicate()) {
624f1dfc027SDiana Picus     case mlir::arith::CmpFPredicate::OEQ: // .EQ.
625f1dfc027SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(cmp, resTy, cp);
626f1dfc027SDiana Picus       break;
627f1dfc027SDiana Picus     case mlir::arith::CmpFPredicate::UNE: // .NE.
628f1dfc027SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(cmp, resTy, cp);
629f1dfc027SDiana Picus       break;
630f1dfc027SDiana Picus     default:
631f1dfc027SDiana Picus       rewriter.replaceOp(cmp, rcp.getResult());
632f1dfc027SDiana Picus       break;
633f1dfc027SDiana Picus     }
634f1dfc027SDiana Picus     return success();
635f1dfc027SDiana Picus   }
636f1dfc027SDiana Picus };
637f1dfc027SDiana Picus 
638e81d73edSDiana Picus /// Lower complex constants
639e81d73edSDiana Picus struct ConstcOpConversion : public FIROpConversion<fir::ConstcOp> {
640e81d73edSDiana Picus   using FIROpConversion::FIROpConversion;
641e81d73edSDiana Picus 
642e81d73edSDiana Picus   mlir::LogicalResult
643e81d73edSDiana Picus   matchAndRewrite(fir::ConstcOp conc, OpAdaptor,
644e81d73edSDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
645e81d73edSDiana Picus     mlir::Location loc = conc.getLoc();
646e81d73edSDiana Picus     mlir::MLIRContext *ctx = conc.getContext();
647e81d73edSDiana Picus     mlir::Type ty = convertType(conc.getType());
648e81d73edSDiana Picus     mlir::Type ety = convertType(getComplexEleTy(conc.getType()));
649e81d73edSDiana Picus     auto realFloatAttr = mlir::FloatAttr::get(ety, getValue(conc.getReal()));
650e81d73edSDiana Picus     auto realPart =
651e81d73edSDiana Picus         rewriter.create<mlir::LLVM::ConstantOp>(loc, ety, realFloatAttr);
652e81d73edSDiana Picus     auto imFloatAttr = mlir::FloatAttr::get(ety, getValue(conc.getImaginary()));
653e81d73edSDiana Picus     auto imPart =
654e81d73edSDiana Picus         rewriter.create<mlir::LLVM::ConstantOp>(loc, ety, imFloatAttr);
655e81d73edSDiana Picus     auto realIndex = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
656e81d73edSDiana Picus     auto imIndex = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
657e81d73edSDiana Picus     auto undef = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
658e81d73edSDiana Picus     auto setReal = rewriter.create<mlir::LLVM::InsertValueOp>(
659e81d73edSDiana Picus         loc, ty, undef, realPart, realIndex);
660e81d73edSDiana Picus     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(conc, ty, setReal,
661e81d73edSDiana Picus                                                            imPart, imIndex);
662e81d73edSDiana Picus     return success();
663e81d73edSDiana Picus   }
664e81d73edSDiana Picus 
665e81d73edSDiana Picus   inline APFloat getValue(mlir::Attribute attr) const {
666e81d73edSDiana Picus     return attr.cast<fir::RealAttr>().getValue();
667e81d73edSDiana Picus   }
668e81d73edSDiana Picus };
669e81d73edSDiana Picus 
670092cee5fSValentin Clement /// convert value of from-type to value of to-type
671092cee5fSValentin Clement struct ConvertOpConversion : public FIROpConversion<fir::ConvertOp> {
672092cee5fSValentin Clement   using FIROpConversion::FIROpConversion;
673092cee5fSValentin Clement 
674092cee5fSValentin Clement   static bool isFloatingPointTy(mlir::Type ty) {
675092cee5fSValentin Clement     return ty.isa<mlir::FloatType>();
676092cee5fSValentin Clement   }
677092cee5fSValentin Clement 
678092cee5fSValentin Clement   mlir::LogicalResult
679092cee5fSValentin Clement   matchAndRewrite(fir::ConvertOp convert, OpAdaptor adaptor,
680092cee5fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
681092cee5fSValentin Clement     auto fromTy = convertType(convert.value().getType());
682092cee5fSValentin Clement     auto toTy = convertType(convert.res().getType());
683092cee5fSValentin Clement     mlir::Value op0 = adaptor.getOperands()[0];
684092cee5fSValentin Clement     if (fromTy == toTy) {
685092cee5fSValentin Clement       rewriter.replaceOp(convert, op0);
686092cee5fSValentin Clement       return success();
687092cee5fSValentin Clement     }
688092cee5fSValentin Clement     auto loc = convert.getLoc();
689092cee5fSValentin Clement     auto convertFpToFp = [&](mlir::Value val, unsigned fromBits,
690092cee5fSValentin Clement                              unsigned toBits, mlir::Type toTy) -> mlir::Value {
691092cee5fSValentin Clement       if (fromBits == toBits) {
692092cee5fSValentin Clement         // TODO: Converting between two floating-point representations with the
693092cee5fSValentin Clement         // same bitwidth is not allowed for now.
694092cee5fSValentin Clement         mlir::emitError(loc,
695092cee5fSValentin Clement                         "cannot implicitly convert between two floating-point "
696092cee5fSValentin Clement                         "representations of the same bitwidth");
697092cee5fSValentin Clement         return {};
698092cee5fSValentin Clement       }
699092cee5fSValentin Clement       if (fromBits > toBits)
700092cee5fSValentin Clement         return rewriter.create<mlir::LLVM::FPTruncOp>(loc, toTy, val);
701092cee5fSValentin Clement       return rewriter.create<mlir::LLVM::FPExtOp>(loc, toTy, val);
702092cee5fSValentin Clement     };
703092cee5fSValentin Clement     // Complex to complex conversion.
704092cee5fSValentin Clement     if (fir::isa_complex(convert.value().getType()) &&
705092cee5fSValentin Clement         fir::isa_complex(convert.res().getType())) {
706092cee5fSValentin Clement       // Special case: handle the conversion of a complex such that both the
707092cee5fSValentin Clement       // real and imaginary parts are converted together.
708092cee5fSValentin Clement       auto zero = mlir::ArrayAttr::get(convert.getContext(),
709092cee5fSValentin Clement                                        rewriter.getI32IntegerAttr(0));
710092cee5fSValentin Clement       auto one = mlir::ArrayAttr::get(convert.getContext(),
711092cee5fSValentin Clement                                       rewriter.getI32IntegerAttr(1));
712092cee5fSValentin Clement       auto ty = convertType(getComplexEleTy(convert.value().getType()));
713092cee5fSValentin Clement       auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, zero);
714092cee5fSValentin Clement       auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, one);
715092cee5fSValentin Clement       auto nt = convertType(getComplexEleTy(convert.res().getType()));
716092cee5fSValentin Clement       auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
717092cee5fSValentin Clement       auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(nt);
718092cee5fSValentin Clement       auto rc = convertFpToFp(rp, fromBits, toBits, nt);
719092cee5fSValentin Clement       auto ic = convertFpToFp(ip, fromBits, toBits, nt);
720092cee5fSValentin Clement       auto un = rewriter.create<mlir::LLVM::UndefOp>(loc, toTy);
721092cee5fSValentin Clement       auto i1 =
722092cee5fSValentin Clement           rewriter.create<mlir::LLVM::InsertValueOp>(loc, toTy, un, rc, zero);
723092cee5fSValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(convert, toTy, i1,
724092cee5fSValentin Clement                                                              ic, one);
725092cee5fSValentin Clement       return mlir::success();
726092cee5fSValentin Clement     }
727092cee5fSValentin Clement     // Floating point to floating point conversion.
728092cee5fSValentin Clement     if (isFloatingPointTy(fromTy)) {
729092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
730092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
731092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
732092cee5fSValentin Clement         auto v = convertFpToFp(op0, fromBits, toBits, toTy);
733092cee5fSValentin Clement         rewriter.replaceOp(convert, v);
734092cee5fSValentin Clement         return mlir::success();
735092cee5fSValentin Clement       }
736092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
737092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::FPToSIOp>(convert, toTy, op0);
738092cee5fSValentin Clement         return mlir::success();
739092cee5fSValentin Clement       }
740092cee5fSValentin Clement     } else if (fromTy.isa<mlir::IntegerType>()) {
741092cee5fSValentin Clement       // Integer to integer conversion.
742092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
743092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
744092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
745092cee5fSValentin Clement         assert(fromBits != toBits);
746092cee5fSValentin Clement         if (fromBits > toBits) {
747092cee5fSValentin Clement           rewriter.replaceOpWithNewOp<mlir::LLVM::TruncOp>(convert, toTy, op0);
748092cee5fSValentin Clement           return mlir::success();
749092cee5fSValentin Clement         }
750092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SExtOp>(convert, toTy, op0);
751092cee5fSValentin Clement         return mlir::success();
752092cee5fSValentin Clement       }
753092cee5fSValentin Clement       // Integer to floating point conversion.
754092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
755092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SIToFPOp>(convert, toTy, op0);
756092cee5fSValentin Clement         return mlir::success();
757092cee5fSValentin Clement       }
758092cee5fSValentin Clement       // Integer to pointer conversion.
759092cee5fSValentin Clement       if (toTy.isa<mlir::LLVM::LLVMPointerType>()) {
760092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(convert, toTy, op0);
761092cee5fSValentin Clement         return mlir::success();
762092cee5fSValentin Clement       }
763092cee5fSValentin Clement     } else if (fromTy.isa<mlir::LLVM::LLVMPointerType>()) {
764092cee5fSValentin Clement       // Pointer to integer conversion.
765092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
766092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::PtrToIntOp>(convert, toTy, op0);
767092cee5fSValentin Clement         return mlir::success();
768092cee5fSValentin Clement       }
769092cee5fSValentin Clement       // Pointer to pointer conversion.
770092cee5fSValentin Clement       if (toTy.isa<mlir::LLVM::LLVMPointerType>()) {
771092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(convert, toTy, op0);
772092cee5fSValentin Clement         return mlir::success();
773092cee5fSValentin Clement       }
774092cee5fSValentin Clement     }
775092cee5fSValentin Clement     return emitError(loc) << "cannot convert " << fromTy << " to " << toTy;
776092cee5fSValentin Clement   }
777092cee5fSValentin Clement };
778092cee5fSValentin Clement 
7799534e361SValentin Clement /// Lower `fir.dispatch` operation. A virtual call to a method in a dispatch
7809534e361SValentin Clement /// table.
7819534e361SValentin Clement struct DispatchOpConversion : public FIROpConversion<fir::DispatchOp> {
7829534e361SValentin Clement   using FIROpConversion::FIROpConversion;
7839534e361SValentin Clement 
7849534e361SValentin Clement   mlir::LogicalResult
7859534e361SValentin Clement   matchAndRewrite(fir::DispatchOp dispatch, OpAdaptor adaptor,
7869534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
7877ce8c6fcSKiran Chandramohan     TODO(dispatch.getLoc(), "fir.dispatch codegen");
7887ce8c6fcSKiran Chandramohan     return failure();
7899534e361SValentin Clement   }
7909534e361SValentin Clement };
7919534e361SValentin Clement 
7929534e361SValentin Clement /// Lower `fir.dispatch_table` operation. The dispatch table for a Fortran
7939534e361SValentin Clement /// derived type.
7949534e361SValentin Clement struct DispatchTableOpConversion
7959534e361SValentin Clement     : public FIROpConversion<fir::DispatchTableOp> {
7969534e361SValentin Clement   using FIROpConversion::FIROpConversion;
7979534e361SValentin Clement 
7989534e361SValentin Clement   mlir::LogicalResult
7999534e361SValentin Clement   matchAndRewrite(fir::DispatchTableOp dispTab, OpAdaptor adaptor,
8009534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8017ce8c6fcSKiran Chandramohan     TODO(dispTab.getLoc(), "fir.dispatch_table codegen");
8027ce8c6fcSKiran Chandramohan     return failure();
8039534e361SValentin Clement   }
8049534e361SValentin Clement };
8059534e361SValentin Clement 
8069534e361SValentin Clement /// Lower `fir.dt_entry` operation. An entry in a dispatch table; binds a
8079534e361SValentin Clement /// method-name to a function.
8089534e361SValentin Clement struct DTEntryOpConversion : public FIROpConversion<fir::DTEntryOp> {
8099534e361SValentin Clement   using FIROpConversion::FIROpConversion;
8109534e361SValentin Clement 
8119534e361SValentin Clement   mlir::LogicalResult
8129534e361SValentin Clement   matchAndRewrite(fir::DTEntryOp dtEnt, OpAdaptor adaptor,
8139534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8147ce8c6fcSKiran Chandramohan     TODO(dtEnt.getLoc(), "fir.dt_entry codegen");
8157ce8c6fcSKiran Chandramohan     return failure();
8169534e361SValentin Clement   }
8179534e361SValentin Clement };
8189534e361SValentin Clement 
819677df8c7SValentin Clement /// Lower `fir.global_len` operation.
820677df8c7SValentin Clement struct GlobalLenOpConversion : public FIROpConversion<fir::GlobalLenOp> {
821677df8c7SValentin Clement   using FIROpConversion::FIROpConversion;
822677df8c7SValentin Clement 
823677df8c7SValentin Clement   mlir::LogicalResult
824677df8c7SValentin Clement   matchAndRewrite(fir::GlobalLenOp globalLen, OpAdaptor adaptor,
825677df8c7SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8267ce8c6fcSKiran Chandramohan     TODO(globalLen.getLoc(), "fir.global_len codegen");
8277ce8c6fcSKiran Chandramohan     return failure();
828677df8c7SValentin Clement   }
829677df8c7SValentin Clement };
830677df8c7SValentin Clement 
831cdc476abSDiana Picus /// Lower fir.len_param_index
832cdc476abSDiana Picus struct LenParamIndexOpConversion
833cdc476abSDiana Picus     : public FIROpConversion<fir::LenParamIndexOp> {
834cdc476abSDiana Picus   using FIROpConversion::FIROpConversion;
835cdc476abSDiana Picus 
836cdc476abSDiana Picus   // FIXME: this should be specialized by the runtime target
837cdc476abSDiana Picus   mlir::LogicalResult
838cdc476abSDiana Picus   matchAndRewrite(fir::LenParamIndexOp lenp, OpAdaptor,
839cdc476abSDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
8407ce8c6fcSKiran Chandramohan     TODO(lenp.getLoc(), "fir.len_param_index codegen");
841cdc476abSDiana Picus   }
842cdc476abSDiana Picus };
843cdc476abSDiana Picus 
84431246187SValentin Clement /// Lower `fir.gentypedesc` to a global constant.
84531246187SValentin Clement struct GenTypeDescOpConversion : public FIROpConversion<fir::GenTypeDescOp> {
84631246187SValentin Clement   using FIROpConversion::FIROpConversion;
84731246187SValentin Clement 
84831246187SValentin Clement   mlir::LogicalResult
84931246187SValentin Clement   matchAndRewrite(fir::GenTypeDescOp gentypedesc, OpAdaptor adaptor,
85031246187SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8517ce8c6fcSKiran Chandramohan     TODO(gentypedesc.getLoc(), "fir.gentypedesc codegen");
8527ce8c6fcSKiran Chandramohan     return failure();
85331246187SValentin Clement   }
85431246187SValentin Clement };
85531246187SValentin Clement 
85622d332a0SAndrzej Warzynski /// Convert `fir.end`
85722d332a0SAndrzej Warzynski struct FirEndOpConversion : public FIROpConversion<fir::FirEndOp> {
85822d332a0SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
85922d332a0SAndrzej Warzynski 
86022d332a0SAndrzej Warzynski   mlir::LogicalResult
86122d332a0SAndrzej Warzynski   matchAndRewrite(fir::FirEndOp firEnd, OpAdaptor,
86222d332a0SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
8637ce8c6fcSKiran Chandramohan     TODO(firEnd.getLoc(), "fir.end codegen");
8647ce8c6fcSKiran Chandramohan     return failure();
86522d332a0SAndrzej Warzynski   }
86622d332a0SAndrzej Warzynski };
86722d332a0SAndrzej Warzynski 
8680c4a7a52SValentin Clement /// Lower `fir.has_value` operation to `llvm.return` operation.
869044d5b5dSValentin Clement struct HasValueOpConversion : public FIROpConversion<fir::HasValueOp> {
870044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
871044d5b5dSValentin Clement 
872044d5b5dSValentin Clement   mlir::LogicalResult
873044d5b5dSValentin Clement   matchAndRewrite(fir::HasValueOp op, OpAdaptor adaptor,
874044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
875044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, adaptor.getOperands());
876044d5b5dSValentin Clement     return success();
877044d5b5dSValentin Clement   }
878044d5b5dSValentin Clement };
879044d5b5dSValentin Clement 
8800c4a7a52SValentin Clement /// Lower `fir.global` operation to `llvm.global` operation.
8810c4a7a52SValentin Clement /// `fir.insert_on_range` operations are replaced with constant dense attribute
8820c4a7a52SValentin Clement /// if they are applied on the full range.
883044d5b5dSValentin Clement struct GlobalOpConversion : public FIROpConversion<fir::GlobalOp> {
884044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
885044d5b5dSValentin Clement 
886044d5b5dSValentin Clement   mlir::LogicalResult
887044d5b5dSValentin Clement   matchAndRewrite(fir::GlobalOp global, OpAdaptor adaptor,
888044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
889044d5b5dSValentin Clement     auto tyAttr = convertType(global.getType());
890044d5b5dSValentin Clement     if (global.getType().isa<fir::BoxType>())
891044d5b5dSValentin Clement       tyAttr = tyAttr.cast<mlir::LLVM::LLVMPointerType>().getElementType();
892044d5b5dSValentin Clement     auto loc = global.getLoc();
893044d5b5dSValentin Clement     mlir::Attribute initAttr{};
894044d5b5dSValentin Clement     if (global.initVal())
895044d5b5dSValentin Clement       initAttr = global.initVal().getValue();
896044d5b5dSValentin Clement     auto linkage = convertLinkage(global.linkName());
897044d5b5dSValentin Clement     auto isConst = global.constant().hasValue();
898044d5b5dSValentin Clement     auto g = rewriter.create<mlir::LLVM::GlobalOp>(
899044d5b5dSValentin Clement         loc, tyAttr, isConst, linkage, global.sym_name(), initAttr);
900044d5b5dSValentin Clement     auto &gr = g.getInitializerRegion();
901044d5b5dSValentin Clement     rewriter.inlineRegionBefore(global.region(), gr, gr.end());
902044d5b5dSValentin Clement     if (!gr.empty()) {
903044d5b5dSValentin Clement       // Replace insert_on_range with a constant dense attribute if the
904044d5b5dSValentin Clement       // initialization is on the full range.
905044d5b5dSValentin Clement       auto insertOnRangeOps = gr.front().getOps<fir::InsertOnRangeOp>();
906044d5b5dSValentin Clement       for (auto insertOp : insertOnRangeOps) {
907044d5b5dSValentin Clement         if (isFullRange(insertOp.coor(), insertOp.getType())) {
908044d5b5dSValentin Clement           auto seqTyAttr = convertType(insertOp.getType());
909044d5b5dSValentin Clement           auto *op = insertOp.val().getDefiningOp();
910044d5b5dSValentin Clement           auto constant = mlir::dyn_cast<mlir::arith::ConstantOp>(op);
911044d5b5dSValentin Clement           if (!constant) {
912044d5b5dSValentin Clement             auto convertOp = mlir::dyn_cast<fir::ConvertOp>(op);
913044d5b5dSValentin Clement             if (!convertOp)
914044d5b5dSValentin Clement               continue;
915044d5b5dSValentin Clement             constant = cast<mlir::arith::ConstantOp>(
916044d5b5dSValentin Clement                 convertOp.value().getDefiningOp());
917044d5b5dSValentin Clement           }
918044d5b5dSValentin Clement           mlir::Type vecType = mlir::VectorType::get(
919044d5b5dSValentin Clement               insertOp.getType().getShape(), constant.getType());
920044d5b5dSValentin Clement           auto denseAttr = mlir::DenseElementsAttr::get(
921044d5b5dSValentin Clement               vecType.cast<ShapedType>(), constant.value());
922044d5b5dSValentin Clement           rewriter.setInsertionPointAfter(insertOp);
923044d5b5dSValentin Clement           rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(
924044d5b5dSValentin Clement               insertOp, seqTyAttr, denseAttr);
925044d5b5dSValentin Clement         }
926044d5b5dSValentin Clement       }
927044d5b5dSValentin Clement     }
928044d5b5dSValentin Clement     rewriter.eraseOp(global);
929044d5b5dSValentin Clement     return success();
930044d5b5dSValentin Clement   }
931044d5b5dSValentin Clement 
9328ec0f221SMehdi Amini   bool isFullRange(mlir::DenseIntElementsAttr indexes,
9338ec0f221SMehdi Amini                    fir::SequenceType seqTy) const {
934044d5b5dSValentin Clement     auto extents = seqTy.getShape();
9358ec0f221SMehdi Amini     if (indexes.size() / 2 != static_cast<int64_t>(extents.size()))
936044d5b5dSValentin Clement       return false;
9378ec0f221SMehdi Amini     auto cur_index = indexes.value_begin<int64_t>();
938044d5b5dSValentin Clement     for (unsigned i = 0; i < indexes.size(); i += 2) {
9398ec0f221SMehdi Amini       if (*(cur_index++) != 0)
940044d5b5dSValentin Clement         return false;
9418ec0f221SMehdi Amini       if (*(cur_index++) != extents[i / 2] - 1)
942044d5b5dSValentin Clement         return false;
943044d5b5dSValentin Clement     }
944044d5b5dSValentin Clement     return true;
945044d5b5dSValentin Clement   }
946044d5b5dSValentin Clement 
9470c4a7a52SValentin Clement   // TODO: String comparaison should be avoided. Replace linkName with an
9480c4a7a52SValentin Clement   // enumeration.
949044d5b5dSValentin Clement   mlir::LLVM::Linkage convertLinkage(Optional<StringRef> optLinkage) const {
950044d5b5dSValentin Clement     if (optLinkage.hasValue()) {
951044d5b5dSValentin Clement       auto name = optLinkage.getValue();
952044d5b5dSValentin Clement       if (name == "internal")
953044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Internal;
954044d5b5dSValentin Clement       if (name == "linkonce")
955044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Linkonce;
956044d5b5dSValentin Clement       if (name == "common")
957044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Common;
958044d5b5dSValentin Clement       if (name == "weak")
959044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Weak;
960044d5b5dSValentin Clement     }
961044d5b5dSValentin Clement     return mlir::LLVM::Linkage::External;
962044d5b5dSValentin Clement   }
963044d5b5dSValentin Clement };
964044d5b5dSValentin Clement 
96539f4ef81SValentin Clement void genCondBrOp(mlir::Location loc, mlir::Value cmp, mlir::Block *dest,
96639f4ef81SValentin Clement                  Optional<mlir::ValueRange> destOps,
96739f4ef81SValentin Clement                  mlir::ConversionPatternRewriter &rewriter,
96839f4ef81SValentin Clement                  mlir::Block *newBlock) {
96939f4ef81SValentin Clement   if (destOps.hasValue())
97039f4ef81SValentin Clement     rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, destOps.getValue(),
97139f4ef81SValentin Clement                                           newBlock, mlir::ValueRange());
97239f4ef81SValentin Clement   else
97339f4ef81SValentin Clement     rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, newBlock);
97439f4ef81SValentin Clement }
97539f4ef81SValentin Clement 
97639f4ef81SValentin Clement template <typename A, typename B>
97739f4ef81SValentin Clement void genBrOp(A caseOp, mlir::Block *dest, Optional<B> destOps,
97839f4ef81SValentin Clement              mlir::ConversionPatternRewriter &rewriter) {
97939f4ef81SValentin Clement   if (destOps.hasValue())
98039f4ef81SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, destOps.getValue(),
98139f4ef81SValentin Clement                                                   dest);
98239f4ef81SValentin Clement   else
98339f4ef81SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, llvm::None, dest);
98439f4ef81SValentin Clement }
98539f4ef81SValentin Clement 
98639f4ef81SValentin Clement void genCaseLadderStep(mlir::Location loc, mlir::Value cmp, mlir::Block *dest,
98739f4ef81SValentin Clement                        Optional<mlir::ValueRange> destOps,
98839f4ef81SValentin Clement                        mlir::ConversionPatternRewriter &rewriter) {
98939f4ef81SValentin Clement   auto *thisBlock = rewriter.getInsertionBlock();
99039f4ef81SValentin Clement   auto *newBlock = createBlock(rewriter, dest);
99139f4ef81SValentin Clement   rewriter.setInsertionPointToEnd(thisBlock);
99239f4ef81SValentin Clement   genCondBrOp(loc, cmp, dest, destOps, rewriter, newBlock);
99339f4ef81SValentin Clement   rewriter.setInsertionPointToEnd(newBlock);
99439f4ef81SValentin Clement }
99539f4ef81SValentin Clement 
99639f4ef81SValentin Clement /// Conversion of `fir.select_case`
99739f4ef81SValentin Clement ///
99839f4ef81SValentin Clement /// The `fir.select_case` operation is converted to a if-then-else ladder.
99939f4ef81SValentin Clement /// Depending on the case condition type, one or several comparison and
100039f4ef81SValentin Clement /// conditional branching can be generated.
100139f4ef81SValentin Clement ///
100239f4ef81SValentin Clement /// A a point value case such as `case(4)`, a lower bound case such as
100339f4ef81SValentin Clement /// `case(5:)` or an upper bound case such as `case(:3)` are converted to a
100439f4ef81SValentin Clement /// simple comparison between the selector value and the constant value in the
100539f4ef81SValentin Clement /// case. The block associated with the case condition is then executed if
100639f4ef81SValentin Clement /// the comparison succeed otherwise it branch to the next block with the
100739f4ef81SValentin Clement /// comparison for the the next case conditon.
100839f4ef81SValentin Clement ///
100939f4ef81SValentin Clement /// A closed interval case condition such as `case(7:10)` is converted with a
101039f4ef81SValentin Clement /// first comparison and conditional branching for the lower bound. If
101139f4ef81SValentin Clement /// successful, it branch to a second block with the comparison for the
101239f4ef81SValentin Clement /// upper bound in the same case condition.
101339f4ef81SValentin Clement ///
101439f4ef81SValentin Clement /// TODO: lowering of CHARACTER type cases is not handled yet.
101539f4ef81SValentin Clement struct SelectCaseOpConversion : public FIROpConversion<fir::SelectCaseOp> {
101639f4ef81SValentin Clement   using FIROpConversion::FIROpConversion;
101739f4ef81SValentin Clement 
101839f4ef81SValentin Clement   mlir::LogicalResult
101939f4ef81SValentin Clement   matchAndRewrite(fir::SelectCaseOp caseOp, OpAdaptor adaptor,
102039f4ef81SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
102139f4ef81SValentin Clement     unsigned conds = caseOp.getNumConditions();
102239f4ef81SValentin Clement     llvm::ArrayRef<mlir::Attribute> cases = caseOp.getCases().getValue();
102339f4ef81SValentin Clement     // Type can be CHARACTER, INTEGER, or LOGICAL (C1145)
10247ce8c6fcSKiran Chandramohan     auto ty = caseOp.getSelector().getType();
10257ce8c6fcSKiran Chandramohan     if (ty.isa<fir::CharacterType>()) {
10267ce8c6fcSKiran Chandramohan       TODO(caseOp.getLoc(), "fir.select_case codegen with character type");
10277ce8c6fcSKiran Chandramohan       return failure();
10287ce8c6fcSKiran Chandramohan     }
102939f4ef81SValentin Clement     mlir::Value selector = caseOp.getSelector(adaptor.getOperands());
103039f4ef81SValentin Clement     auto loc = caseOp.getLoc();
103139f4ef81SValentin Clement     for (unsigned t = 0; t != conds; ++t) {
103239f4ef81SValentin Clement       mlir::Block *dest = caseOp.getSuccessor(t);
103339f4ef81SValentin Clement       llvm::Optional<mlir::ValueRange> destOps =
103439f4ef81SValentin Clement           caseOp.getSuccessorOperands(adaptor.getOperands(), t);
103539f4ef81SValentin Clement       llvm::Optional<mlir::ValueRange> cmpOps =
103639f4ef81SValentin Clement           *caseOp.getCompareOperands(adaptor.getOperands(), t);
103739f4ef81SValentin Clement       mlir::Value caseArg = *(cmpOps.getValue().begin());
103839f4ef81SValentin Clement       mlir::Attribute attr = cases[t];
103939f4ef81SValentin Clement       if (attr.isa<fir::PointIntervalAttr>()) {
104039f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
104139f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::eq, selector, caseArg);
104239f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
104339f4ef81SValentin Clement         continue;
104439f4ef81SValentin Clement       }
104539f4ef81SValentin Clement       if (attr.isa<fir::LowerBoundAttr>()) {
104639f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
104739f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector);
104839f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
104939f4ef81SValentin Clement         continue;
105039f4ef81SValentin Clement       }
105139f4ef81SValentin Clement       if (attr.isa<fir::UpperBoundAttr>()) {
105239f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
105339f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg);
105439f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
105539f4ef81SValentin Clement         continue;
105639f4ef81SValentin Clement       }
105739f4ef81SValentin Clement       if (attr.isa<fir::ClosedIntervalAttr>()) {
105839f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
105939f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector);
106039f4ef81SValentin Clement         auto *thisBlock = rewriter.getInsertionBlock();
106139f4ef81SValentin Clement         auto *newBlock1 = createBlock(rewriter, dest);
106239f4ef81SValentin Clement         auto *newBlock2 = createBlock(rewriter, dest);
106339f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(thisBlock);
106439f4ef81SValentin Clement         rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, newBlock1, newBlock2);
106539f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(newBlock1);
106639f4ef81SValentin Clement         mlir::Value caseArg0 = *(cmpOps.getValue().begin() + 1);
106739f4ef81SValentin Clement         auto cmp0 = rewriter.create<mlir::LLVM::ICmpOp>(
106839f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg0);
106939f4ef81SValentin Clement         genCondBrOp(loc, cmp0, dest, destOps, rewriter, newBlock2);
107039f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(newBlock2);
107139f4ef81SValentin Clement         continue;
107239f4ef81SValentin Clement       }
107339f4ef81SValentin Clement       assert(attr.isa<mlir::UnitAttr>());
107439f4ef81SValentin Clement       assert((t + 1 == conds) && "unit must be last");
107539f4ef81SValentin Clement       genBrOp(caseOp, dest, destOps, rewriter);
107639f4ef81SValentin Clement     }
107739f4ef81SValentin Clement     return success();
107839f4ef81SValentin Clement   }
107939f4ef81SValentin Clement };
108039f4ef81SValentin Clement 
10818c239909SValentin Clement template <typename OP>
10828c239909SValentin Clement void selectMatchAndRewrite(fir::LLVMTypeConverter &lowering, OP select,
10838c239909SValentin Clement                            typename OP::Adaptor adaptor,
10848c239909SValentin Clement                            mlir::ConversionPatternRewriter &rewriter) {
10858c239909SValentin Clement   unsigned conds = select.getNumConditions();
10868c239909SValentin Clement   auto cases = select.getCases().getValue();
10878c239909SValentin Clement   mlir::Value selector = adaptor.selector();
10888c239909SValentin Clement   auto loc = select.getLoc();
10898c239909SValentin Clement   assert(conds > 0 && "select must have cases");
10908c239909SValentin Clement 
10918c239909SValentin Clement   llvm::SmallVector<mlir::Block *> destinations;
10928c239909SValentin Clement   llvm::SmallVector<mlir::ValueRange> destinationsOperands;
10938c239909SValentin Clement   mlir::Block *defaultDestination;
10948c239909SValentin Clement   mlir::ValueRange defaultOperands;
10958c239909SValentin Clement   llvm::SmallVector<int32_t> caseValues;
10968c239909SValentin Clement 
10978c239909SValentin Clement   for (unsigned t = 0; t != conds; ++t) {
10988c239909SValentin Clement     mlir::Block *dest = select.getSuccessor(t);
10998c239909SValentin Clement     auto destOps = select.getSuccessorOperands(adaptor.getOperands(), t);
11008c239909SValentin Clement     const mlir::Attribute &attr = cases[t];
11018c239909SValentin Clement     if (auto intAttr = attr.template dyn_cast<mlir::IntegerAttr>()) {
11028c239909SValentin Clement       destinations.push_back(dest);
11038c239909SValentin Clement       destinationsOperands.push_back(destOps.hasValue() ? *destOps
11048c239909SValentin Clement                                                         : ValueRange());
11058c239909SValentin Clement       caseValues.push_back(intAttr.getInt());
11068c239909SValentin Clement       continue;
11078c239909SValentin Clement     }
11088c239909SValentin Clement     assert(attr.template dyn_cast_or_null<mlir::UnitAttr>());
11098c239909SValentin Clement     assert((t + 1 == conds) && "unit must be last");
11108c239909SValentin Clement     defaultDestination = dest;
11118c239909SValentin Clement     defaultOperands = destOps.hasValue() ? *destOps : ValueRange();
11128c239909SValentin Clement   }
11138c239909SValentin Clement 
11148c239909SValentin Clement   // LLVM::SwitchOp takes a i32 type for the selector.
11158c239909SValentin Clement   if (select.getSelector().getType() != rewriter.getI32Type())
11168c239909SValentin Clement     selector =
11178c239909SValentin Clement         rewriter.create<LLVM::TruncOp>(loc, rewriter.getI32Type(), selector);
11188c239909SValentin Clement 
11198c239909SValentin Clement   rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>(
11208c239909SValentin Clement       select, selector,
11218c239909SValentin Clement       /*defaultDestination=*/defaultDestination,
11228c239909SValentin Clement       /*defaultOperands=*/defaultOperands,
11238c239909SValentin Clement       /*caseValues=*/caseValues,
11248c239909SValentin Clement       /*caseDestinations=*/destinations,
11258c239909SValentin Clement       /*caseOperands=*/destinationsOperands,
11268c239909SValentin Clement       /*branchWeights=*/ArrayRef<int32_t>());
11278c239909SValentin Clement }
11288c239909SValentin Clement 
11298c239909SValentin Clement /// conversion of fir::SelectOp to an if-then-else ladder
11308c239909SValentin Clement struct SelectOpConversion : public FIROpConversion<fir::SelectOp> {
11318c239909SValentin Clement   using FIROpConversion::FIROpConversion;
11328c239909SValentin Clement 
11338c239909SValentin Clement   mlir::LogicalResult
11348c239909SValentin Clement   matchAndRewrite(fir::SelectOp op, OpAdaptor adaptor,
11358c239909SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
11368c239909SValentin Clement     selectMatchAndRewrite<fir::SelectOp>(lowerTy(), op, adaptor, rewriter);
11378c239909SValentin Clement     return success();
11388c239909SValentin Clement   }
11398c239909SValentin Clement };
11408c239909SValentin Clement 
1141e3349fa1SAndrzej Warzynski /// `fir.load` --> `llvm.load`
1142e3349fa1SAndrzej Warzynski struct LoadOpConversion : public FIROpConversion<fir::LoadOp> {
1143e3349fa1SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
1144e3349fa1SAndrzej Warzynski 
1145e3349fa1SAndrzej Warzynski   mlir::LogicalResult
1146e3349fa1SAndrzej Warzynski   matchAndRewrite(fir::LoadOp load, OpAdaptor adaptor,
1147e3349fa1SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
1148e3349fa1SAndrzej Warzynski     // fir.box is a special case because it is considered as an ssa values in
1149e3349fa1SAndrzej Warzynski     // fir, but it is lowered as a pointer to a descriptor. So fir.ref<fir.box>
1150e3349fa1SAndrzej Warzynski     // and fir.box end up being the same llvm types and loading a
1151e3349fa1SAndrzej Warzynski     // fir.ref<fir.box> is actually a no op in LLVM.
1152e3349fa1SAndrzej Warzynski     if (load.getType().isa<fir::BoxType>()) {
1153e3349fa1SAndrzej Warzynski       rewriter.replaceOp(load, adaptor.getOperands()[0]);
1154e3349fa1SAndrzej Warzynski     } else {
1155e3349fa1SAndrzej Warzynski       mlir::Type ty = convertType(load.getType());
1156e3349fa1SAndrzej Warzynski       ArrayRef<NamedAttribute> at = load->getAttrs();
1157e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::LoadOp>(
1158e3349fa1SAndrzej Warzynski           load, ty, adaptor.getOperands(), at);
1159e3349fa1SAndrzej Warzynski     }
1160e3349fa1SAndrzej Warzynski     return success();
1161e3349fa1SAndrzej Warzynski   }
1162e3349fa1SAndrzej Warzynski };
1163e3349fa1SAndrzej Warzynski 
1164b8207db7SValentin Clement /// Lower `fir.no_reassoc` to LLVM IR dialect.
1165b8207db7SValentin Clement /// TODO: how do we want to enforce this in LLVM-IR? Can we manipulate the fast
1166b8207db7SValentin Clement /// math flags?
1167b8207db7SValentin Clement struct NoReassocOpConversion : public FIROpConversion<fir::NoReassocOp> {
1168b8207db7SValentin Clement   using FIROpConversion::FIROpConversion;
1169b8207db7SValentin Clement 
1170b8207db7SValentin Clement   mlir::LogicalResult
1171b8207db7SValentin Clement   matchAndRewrite(fir::NoReassocOp noreassoc, OpAdaptor adaptor,
1172b8207db7SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1173b8207db7SValentin Clement     rewriter.replaceOp(noreassoc, adaptor.getOperands()[0]);
1174b8207db7SValentin Clement     return success();
1175b8207db7SValentin Clement   }
1176b8207db7SValentin Clement };
1177b8207db7SValentin Clement 
11782a299e4fSValentin Clement /// Lower `fir.select_type` to LLVM IR dialect.
11792a299e4fSValentin Clement struct SelectTypeOpConversion : public FIROpConversion<fir::SelectTypeOp> {
11802a299e4fSValentin Clement   using FIROpConversion::FIROpConversion;
11812a299e4fSValentin Clement 
11822a299e4fSValentin Clement   mlir::LogicalResult
11832a299e4fSValentin Clement   matchAndRewrite(fir::SelectTypeOp select, OpAdaptor adaptor,
11842a299e4fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
11857ce8c6fcSKiran Chandramohan     mlir::emitError(select.getLoc(),
11867ce8c6fcSKiran Chandramohan                     "fir.select_type should have already been converted");
11877ce8c6fcSKiran Chandramohan     return failure();
11882a299e4fSValentin Clement   }
11892a299e4fSValentin Clement };
11902a299e4fSValentin Clement 
11918c239909SValentin Clement /// conversion of fir::SelectRankOp to an if-then-else ladder
11928c239909SValentin Clement struct SelectRankOpConversion : public FIROpConversion<fir::SelectRankOp> {
11938c239909SValentin Clement   using FIROpConversion::FIROpConversion;
11948c239909SValentin Clement 
11958c239909SValentin Clement   mlir::LogicalResult
11968c239909SValentin Clement   matchAndRewrite(fir::SelectRankOp op, OpAdaptor adaptor,
11978c239909SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
11988c239909SValentin Clement     selectMatchAndRewrite<fir::SelectRankOp>(lowerTy(), op, adaptor, rewriter);
11998c239909SValentin Clement     return success();
12008c239909SValentin Clement   }
12018c239909SValentin Clement };
12028c239909SValentin Clement 
1203e3349fa1SAndrzej Warzynski /// `fir.store` --> `llvm.store`
1204e3349fa1SAndrzej Warzynski struct StoreOpConversion : public FIROpConversion<fir::StoreOp> {
1205e3349fa1SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
1206e3349fa1SAndrzej Warzynski 
1207e3349fa1SAndrzej Warzynski   mlir::LogicalResult
1208e3349fa1SAndrzej Warzynski   matchAndRewrite(fir::StoreOp store, OpAdaptor adaptor,
1209e3349fa1SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
1210e3349fa1SAndrzej Warzynski     if (store.value().getType().isa<fir::BoxType>()) {
1211e3349fa1SAndrzej Warzynski       // fir.box value is actually in memory, load it first before storing it.
1212e3349fa1SAndrzej Warzynski       mlir::Location loc = store.getLoc();
1213e3349fa1SAndrzej Warzynski       mlir::Type boxPtrTy = adaptor.getOperands()[0].getType();
1214e3349fa1SAndrzej Warzynski       auto val = rewriter.create<mlir::LLVM::LoadOp>(
1215e3349fa1SAndrzej Warzynski           loc, boxPtrTy.cast<mlir::LLVM::LLVMPointerType>().getElementType(),
1216e3349fa1SAndrzej Warzynski           adaptor.getOperands()[0]);
1217e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
1218e3349fa1SAndrzej Warzynski           store, val, adaptor.getOperands()[1]);
1219e3349fa1SAndrzej Warzynski     } else {
1220e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
1221e3349fa1SAndrzej Warzynski           store, adaptor.getOperands()[0], adaptor.getOperands()[1]);
1222e3349fa1SAndrzej Warzynski     }
1223e3349fa1SAndrzej Warzynski     return success();
1224e3349fa1SAndrzej Warzynski   }
1225e3349fa1SAndrzej Warzynski };
1226e3349fa1SAndrzej Warzynski 
1227e3349fa1SAndrzej Warzynski /// convert to LLVM IR dialect `undef`
1228044d5b5dSValentin Clement struct UndefOpConversion : public FIROpConversion<fir::UndefOp> {
1229044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
1230044d5b5dSValentin Clement 
1231044d5b5dSValentin Clement   mlir::LogicalResult
1232044d5b5dSValentin Clement   matchAndRewrite(fir::UndefOp undef, OpAdaptor,
1233044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1234044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::UndefOp>(
1235044d5b5dSValentin Clement         undef, convertType(undef.getType()));
1236044d5b5dSValentin Clement     return success();
1237044d5b5dSValentin Clement   }
1238044d5b5dSValentin Clement };
1239a7a61359SValentin Clement 
1240e3349fa1SAndrzej Warzynski /// `fir.unreachable` --> `llvm.unreachable`
124132e08248SAndrzej Warzynski struct UnreachableOpConversion : public FIROpConversion<fir::UnreachableOp> {
124232e08248SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
124332e08248SAndrzej Warzynski 
124432e08248SAndrzej Warzynski   mlir::LogicalResult
124532e08248SAndrzej Warzynski   matchAndRewrite(fir::UnreachableOp unreach, OpAdaptor adaptor,
124632e08248SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
124732e08248SAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(unreach);
124832e08248SAndrzej Warzynski     return success();
124932e08248SAndrzej Warzynski   }
125032e08248SAndrzej Warzynski };
125132e08248SAndrzej Warzynski 
1252a7a61359SValentin Clement struct ZeroOpConversion : public FIROpConversion<fir::ZeroOp> {
1253a7a61359SValentin Clement   using FIROpConversion::FIROpConversion;
1254a7a61359SValentin Clement 
1255a7a61359SValentin Clement   mlir::LogicalResult
1256a7a61359SValentin Clement   matchAndRewrite(fir::ZeroOp zero, OpAdaptor,
1257a7a61359SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
12587ce8c6fcSKiran Chandramohan     mlir::Type ty = convertType(zero.getType());
1259a7a61359SValentin Clement     if (ty.isa<mlir::LLVM::LLVMPointerType>()) {
1260a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(zero, ty);
1261a7a61359SValentin Clement     } else if (ty.isa<mlir::IntegerType>()) {
1262a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
1263a7a61359SValentin Clement           zero, ty, mlir::IntegerAttr::get(zero.getType(), 0));
1264a7a61359SValentin Clement     } else if (mlir::LLVM::isCompatibleFloatingPointType(ty)) {
1265a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
1266a7a61359SValentin Clement           zero, ty, mlir::FloatAttr::get(zero.getType(), 0.0));
1267a7a61359SValentin Clement     } else {
1268a7a61359SValentin Clement       // TODO: create ConstantAggregateZero for FIR aggregate/array types.
126952d813edSValentin Clement       return rewriter.notifyMatchFailure(
127052d813edSValentin Clement           zero,
1271a7a61359SValentin Clement           "conversion of fir.zero with aggregate type not implemented yet");
1272a7a61359SValentin Clement     }
1273a7a61359SValentin Clement     return success();
1274a7a61359SValentin Clement   }
1275a7a61359SValentin Clement };
127632e08248SAndrzej Warzynski 
1277af6ee580SValentin Clement /// Common base class for embox to descriptor conversion.
1278af6ee580SValentin Clement template <typename OP>
1279af6ee580SValentin Clement struct EmboxCommonConversion : public FIROpConversion<OP> {
1280af6ee580SValentin Clement   using FIROpConversion<OP>::FIROpConversion;
1281af6ee580SValentin Clement 
1282af6ee580SValentin Clement   // Find the LLVMFuncOp in whose entry block the alloca should be inserted.
1283af6ee580SValentin Clement   // The order to find the LLVMFuncOp is as follows:
1284af6ee580SValentin Clement   // 1. The parent operation of the current block if it is a LLVMFuncOp.
1285af6ee580SValentin Clement   // 2. The first ancestor that is a LLVMFuncOp.
1286af6ee580SValentin Clement   mlir::LLVM::LLVMFuncOp
1287af6ee580SValentin Clement   getFuncForAllocaInsert(mlir::ConversionPatternRewriter &rewriter) const {
1288af6ee580SValentin Clement     mlir::Operation *parentOp = rewriter.getInsertionBlock()->getParentOp();
1289af6ee580SValentin Clement     return mlir::isa<mlir::LLVM::LLVMFuncOp>(parentOp)
1290af6ee580SValentin Clement                ? mlir::cast<mlir::LLVM::LLVMFuncOp>(parentOp)
1291af6ee580SValentin Clement                : parentOp->getParentOfType<mlir::LLVM::LLVMFuncOp>();
1292af6ee580SValentin Clement   }
1293af6ee580SValentin Clement 
1294af6ee580SValentin Clement   // Generate an alloca of size 1 and type \p toTy.
1295af6ee580SValentin Clement   mlir::LLVM::AllocaOp
1296af6ee580SValentin Clement   genAllocaWithType(mlir::Location loc, mlir::Type toTy, unsigned alignment,
1297af6ee580SValentin Clement                     mlir::ConversionPatternRewriter &rewriter) const {
1298af6ee580SValentin Clement     auto thisPt = rewriter.saveInsertionPoint();
1299af6ee580SValentin Clement     mlir::LLVM::LLVMFuncOp func = getFuncForAllocaInsert(rewriter);
1300af6ee580SValentin Clement     rewriter.setInsertionPointToStart(&func.front());
1301af6ee580SValentin Clement     auto size = this->genI32Constant(loc, rewriter, 1);
1302af6ee580SValentin Clement     auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, toTy, size, alignment);
1303af6ee580SValentin Clement     rewriter.restoreInsertionPoint(thisPt);
1304af6ee580SValentin Clement     return al;
1305af6ee580SValentin Clement   }
1306af6ee580SValentin Clement 
1307af6ee580SValentin Clement   static int getCFIAttr(fir::BoxType boxTy) {
1308af6ee580SValentin Clement     auto eleTy = boxTy.getEleTy();
1309af6ee580SValentin Clement     if (eleTy.isa<fir::PointerType>())
1310af6ee580SValentin Clement       return CFI_attribute_pointer;
1311af6ee580SValentin Clement     if (eleTy.isa<fir::HeapType>())
1312af6ee580SValentin Clement       return CFI_attribute_allocatable;
1313af6ee580SValentin Clement     return CFI_attribute_other;
1314af6ee580SValentin Clement   }
1315af6ee580SValentin Clement 
1316af6ee580SValentin Clement   static fir::RecordType unwrapIfDerived(fir::BoxType boxTy) {
1317af6ee580SValentin Clement     return fir::unwrapSequenceType(fir::dyn_cast_ptrOrBoxEleTy(boxTy))
1318af6ee580SValentin Clement         .template dyn_cast<fir::RecordType>();
1319af6ee580SValentin Clement   }
1320af6ee580SValentin Clement   static bool isDerivedTypeWithLenParams(fir::BoxType boxTy) {
1321af6ee580SValentin Clement     auto recTy = unwrapIfDerived(boxTy);
1322af6ee580SValentin Clement     return recTy && recTy.getNumLenParams() > 0;
1323af6ee580SValentin Clement   }
1324af6ee580SValentin Clement   static bool isDerivedType(fir::BoxType boxTy) {
1325af6ee580SValentin Clement     return unwrapIfDerived(boxTy) != nullptr;
1326af6ee580SValentin Clement   }
1327af6ee580SValentin Clement 
1328af6ee580SValentin Clement   // Get the element size and CFI type code of the boxed value.
1329af6ee580SValentin Clement   std::tuple<mlir::Value, mlir::Value> getSizeAndTypeCode(
1330af6ee580SValentin Clement       mlir::Location loc, mlir::ConversionPatternRewriter &rewriter,
1331af6ee580SValentin Clement       mlir::Type boxEleTy, mlir::ValueRange lenParams = {}) const {
1332af6ee580SValentin Clement     auto doInteger =
1333af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1334af6ee580SValentin Clement       int typeCode = fir::integerBitsToTypeCode(width);
1335af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1336af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1337af6ee580SValentin Clement     };
1338af6ee580SValentin Clement     auto doLogical =
1339af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1340af6ee580SValentin Clement       int typeCode = fir::logicalBitsToTypeCode(width);
1341af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1342af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1343af6ee580SValentin Clement     };
1344af6ee580SValentin Clement     auto doFloat = [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1345af6ee580SValentin Clement       int typeCode = fir::realBitsToTypeCode(width);
1346af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1347af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1348af6ee580SValentin Clement     };
1349af6ee580SValentin Clement     auto doComplex =
1350af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1351af6ee580SValentin Clement       auto typeCode = fir::complexBitsToTypeCode(width);
1352af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8 * 2),
1353af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1354af6ee580SValentin Clement     };
1355af6ee580SValentin Clement     auto doCharacter =
1356af6ee580SValentin Clement         [&](unsigned width,
1357af6ee580SValentin Clement             mlir::Value len) -> std::tuple<mlir::Value, mlir::Value> {
1358af6ee580SValentin Clement       auto typeCode = fir::characterBitsToTypeCode(width);
1359af6ee580SValentin Clement       auto typeCodeVal = this->genConstantOffset(loc, rewriter, typeCode);
1360af6ee580SValentin Clement       if (width == 8)
1361af6ee580SValentin Clement         return {len, typeCodeVal};
1362af6ee580SValentin Clement       auto byteWidth = this->genConstantOffset(loc, rewriter, width / 8);
1363af6ee580SValentin Clement       auto i64Ty = mlir::IntegerType::get(&this->lowerTy().getContext(), 64);
1364af6ee580SValentin Clement       auto size =
1365af6ee580SValentin Clement           rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, byteWidth, len);
1366af6ee580SValentin Clement       return {size, typeCodeVal};
1367af6ee580SValentin Clement     };
1368af6ee580SValentin Clement     auto getKindMap = [&]() -> fir::KindMapping & {
1369af6ee580SValentin Clement       return this->lowerTy().getKindMap();
1370af6ee580SValentin Clement     };
1371af6ee580SValentin Clement     // Pointer-like types.
1372af6ee580SValentin Clement     if (auto eleTy = fir::dyn_cast_ptrEleTy(boxEleTy))
1373af6ee580SValentin Clement       boxEleTy = eleTy;
1374af6ee580SValentin Clement     // Integer types.
1375af6ee580SValentin Clement     if (fir::isa_integer(boxEleTy)) {
1376af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::IntegerType>())
1377af6ee580SValentin Clement         return doInteger(ty.getWidth());
1378af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::IntegerType>();
1379af6ee580SValentin Clement       return doInteger(getKindMap().getIntegerBitsize(ty.getFKind()));
1380af6ee580SValentin Clement     }
1381af6ee580SValentin Clement     // Floating point types.
1382af6ee580SValentin Clement     if (fir::isa_real(boxEleTy)) {
1383af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::FloatType>())
1384af6ee580SValentin Clement         return doFloat(ty.getWidth());
1385af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::RealType>();
1386af6ee580SValentin Clement       return doFloat(getKindMap().getRealBitsize(ty.getFKind()));
1387af6ee580SValentin Clement     }
1388af6ee580SValentin Clement     // Complex types.
1389af6ee580SValentin Clement     if (fir::isa_complex(boxEleTy)) {
1390af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::ComplexType>())
1391af6ee580SValentin Clement         return doComplex(
1392af6ee580SValentin Clement             ty.getElementType().cast<mlir::FloatType>().getWidth());
1393af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::ComplexType>();
1394af6ee580SValentin Clement       return doComplex(getKindMap().getRealBitsize(ty.getFKind()));
1395af6ee580SValentin Clement     }
1396af6ee580SValentin Clement     // Character types.
1397af6ee580SValentin Clement     if (auto ty = boxEleTy.dyn_cast<fir::CharacterType>()) {
1398af6ee580SValentin Clement       auto charWidth = getKindMap().getCharacterBitsize(ty.getFKind());
1399af6ee580SValentin Clement       if (ty.getLen() != fir::CharacterType::unknownLen()) {
1400af6ee580SValentin Clement         auto len = this->genConstantOffset(loc, rewriter, ty.getLen());
1401af6ee580SValentin Clement         return doCharacter(charWidth, len);
1402af6ee580SValentin Clement       }
1403af6ee580SValentin Clement       assert(!lenParams.empty());
1404af6ee580SValentin Clement       return doCharacter(charWidth, lenParams.back());
1405af6ee580SValentin Clement     }
1406af6ee580SValentin Clement     // Logical type.
1407af6ee580SValentin Clement     if (auto ty = boxEleTy.dyn_cast<fir::LogicalType>())
1408af6ee580SValentin Clement       return doLogical(getKindMap().getLogicalBitsize(ty.getFKind()));
1409af6ee580SValentin Clement     // Array types.
1410af6ee580SValentin Clement     if (auto seqTy = boxEleTy.dyn_cast<fir::SequenceType>())
1411af6ee580SValentin Clement       return getSizeAndTypeCode(loc, rewriter, seqTy.getEleTy(), lenParams);
1412af6ee580SValentin Clement     // Derived-type types.
1413af6ee580SValentin Clement     if (boxEleTy.isa<fir::RecordType>()) {
1414af6ee580SValentin Clement       auto ptrTy = mlir::LLVM::LLVMPointerType::get(
1415af6ee580SValentin Clement           this->lowerTy().convertType(boxEleTy));
1416af6ee580SValentin Clement       auto nullPtr = rewriter.create<mlir::LLVM::NullOp>(loc, ptrTy);
1417af6ee580SValentin Clement       auto one =
1418af6ee580SValentin Clement           genConstantIndex(loc, this->lowerTy().offsetType(), rewriter, 1);
1419af6ee580SValentin Clement       auto gep = rewriter.create<mlir::LLVM::GEPOp>(
1420af6ee580SValentin Clement           loc, ptrTy, mlir::ValueRange{nullPtr, one});
1421af6ee580SValentin Clement       auto eleSize = rewriter.create<mlir::LLVM::PtrToIntOp>(
1422af6ee580SValentin Clement           loc, this->lowerTy().indexType(), gep);
1423af6ee580SValentin Clement       return {eleSize,
1424af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, fir::derivedToTypeCode())};
1425af6ee580SValentin Clement     }
1426af6ee580SValentin Clement     // Reference type.
1427af6ee580SValentin Clement     if (fir::isa_ref_type(boxEleTy)) {
1428af6ee580SValentin Clement       // FIXME: use the target pointer size rather than sizeof(void*)
1429af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, sizeof(void *)),
1430af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, CFI_type_cptr)};
1431af6ee580SValentin Clement     }
1432af6ee580SValentin Clement     fir::emitFatalError(loc, "unhandled type in fir.box code generation");
1433af6ee580SValentin Clement   }
1434af6ee580SValentin Clement 
1435af6ee580SValentin Clement   /// Basic pattern to write a field in the descriptor
1436af6ee580SValentin Clement   mlir::Value insertField(mlir::ConversionPatternRewriter &rewriter,
1437af6ee580SValentin Clement                           mlir::Location loc, mlir::Value dest,
1438af6ee580SValentin Clement                           ArrayRef<unsigned> fldIndexes, mlir::Value value,
1439af6ee580SValentin Clement                           bool bitcast = false) const {
1440af6ee580SValentin Clement     auto boxTy = dest.getType();
1441af6ee580SValentin Clement     auto fldTy = this->getBoxEleTy(boxTy, fldIndexes);
1442af6ee580SValentin Clement     if (bitcast)
1443af6ee580SValentin Clement       value = rewriter.create<mlir::LLVM::BitcastOp>(loc, fldTy, value);
1444af6ee580SValentin Clement     else
1445af6ee580SValentin Clement       value = this->integerCast(loc, rewriter, fldTy, value);
1446af6ee580SValentin Clement     SmallVector<mlir::Attribute, 2> attrs;
1447af6ee580SValentin Clement     for (auto i : fldIndexes)
1448af6ee580SValentin Clement       attrs.push_back(rewriter.getI32IntegerAttr(i));
1449af6ee580SValentin Clement     auto indexesAttr = mlir::ArrayAttr::get(rewriter.getContext(), attrs);
1450af6ee580SValentin Clement     return rewriter.create<mlir::LLVM::InsertValueOp>(loc, boxTy, dest, value,
1451af6ee580SValentin Clement                                                       indexesAttr);
1452af6ee580SValentin Clement   }
1453af6ee580SValentin Clement 
1454af6ee580SValentin Clement   inline mlir::Value
1455af6ee580SValentin Clement   insertBaseAddress(mlir::ConversionPatternRewriter &rewriter,
1456af6ee580SValentin Clement                     mlir::Location loc, mlir::Value dest,
1457af6ee580SValentin Clement                     mlir::Value base) const {
1458*1f551032SValentin Clement     return insertField(rewriter, loc, dest, {kAddrPosInBox}, base,
1459*1f551032SValentin Clement                        /*bitCast=*/true);
1460*1f551032SValentin Clement   }
1461*1f551032SValentin Clement 
1462*1f551032SValentin Clement   inline mlir::Value insertLowerBound(mlir::ConversionPatternRewriter &rewriter,
1463*1f551032SValentin Clement                                       mlir::Location loc, mlir::Value dest,
1464*1f551032SValentin Clement                                       unsigned dim, mlir::Value lb) const {
1465*1f551032SValentin Clement     return insertField(rewriter, loc, dest,
1466*1f551032SValentin Clement                        {kDimsPosInBox, dim, kDimLowerBoundPos}, lb);
1467*1f551032SValentin Clement   }
1468*1f551032SValentin Clement 
1469*1f551032SValentin Clement   inline mlir::Value insertExtent(mlir::ConversionPatternRewriter &rewriter,
1470*1f551032SValentin Clement                                   mlir::Location loc, mlir::Value dest,
1471*1f551032SValentin Clement                                   unsigned dim, mlir::Value extent) const {
1472*1f551032SValentin Clement     return insertField(rewriter, loc, dest, {kDimsPosInBox, dim, kDimExtentPos},
1473*1f551032SValentin Clement                        extent);
1474*1f551032SValentin Clement   }
1475*1f551032SValentin Clement 
1476*1f551032SValentin Clement   inline mlir::Value insertStride(mlir::ConversionPatternRewriter &rewriter,
1477*1f551032SValentin Clement                                   mlir::Location loc, mlir::Value dest,
1478*1f551032SValentin Clement                                   unsigned dim, mlir::Value stride) const {
1479*1f551032SValentin Clement     return insertField(rewriter, loc, dest, {kDimsPosInBox, dim, kDimStridePos},
1480*1f551032SValentin Clement                        stride);
1481af6ee580SValentin Clement   }
1482af6ee580SValentin Clement 
1483af6ee580SValentin Clement   /// Get the address of the type descriptor global variable that was created by
1484af6ee580SValentin Clement   /// lowering for derived type \p recType.
1485af6ee580SValentin Clement   template <typename BOX>
1486af6ee580SValentin Clement   mlir::Value
1487af6ee580SValentin Clement   getTypeDescriptor(BOX box, mlir::ConversionPatternRewriter &rewriter,
1488af6ee580SValentin Clement                     mlir::Location loc, fir::RecordType recType) const {
1489af6ee580SValentin Clement     std::string name = recType.getLoweredName();
1490af6ee580SValentin Clement     auto module = box->template getParentOfType<mlir::ModuleOp>();
1491af6ee580SValentin Clement     if (auto global = module.template lookupSymbol<fir::GlobalOp>(name)) {
1492af6ee580SValentin Clement       auto ty = mlir::LLVM::LLVMPointerType::get(
1493af6ee580SValentin Clement           this->lowerTy().convertType(global.getType()));
1494af6ee580SValentin Clement       return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty,
1495af6ee580SValentin Clement                                                       global.sym_name());
1496af6ee580SValentin Clement     }
1497af6ee580SValentin Clement     if (auto global =
1498af6ee580SValentin Clement             module.template lookupSymbol<mlir::LLVM::GlobalOp>(name)) {
1499af6ee580SValentin Clement       // The global may have already been translated to LLVM.
1500af6ee580SValentin Clement       auto ty = mlir::LLVM::LLVMPointerType::get(global.getType());
1501af6ee580SValentin Clement       return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty,
1502af6ee580SValentin Clement                                                       global.sym_name());
1503af6ee580SValentin Clement     }
1504af6ee580SValentin Clement     // The global does not exist in the current translation unit, but may be
1505af6ee580SValentin Clement     // defined elsewhere (e.g., type defined in a module).
1506af6ee580SValentin Clement     // For now, create a extern_weak symbol (will become nullptr if unresolved)
1507af6ee580SValentin Clement     // to support generating code without the front-end generated symbols.
1508af6ee580SValentin Clement     // These could be made available_externally to require the symbols to be
1509af6ee580SValentin Clement     // defined elsewhere and to cause link-time failure otherwise.
1510af6ee580SValentin Clement     auto i8Ty = rewriter.getIntegerType(8);
1511af6ee580SValentin Clement     mlir::OpBuilder modBuilder(module.getBodyRegion());
1512af6ee580SValentin Clement     // TODO: The symbol should be lowered to constant in lowering, they are read
1513af6ee580SValentin Clement     // only.
1514af6ee580SValentin Clement     modBuilder.create<mlir::LLVM::GlobalOp>(loc, i8Ty, /*isConstant=*/false,
1515af6ee580SValentin Clement                                             mlir::LLVM::Linkage::ExternWeak,
1516af6ee580SValentin Clement                                             name, mlir::Attribute{});
1517af6ee580SValentin Clement     auto ty = mlir::LLVM::LLVMPointerType::get(i8Ty);
1518af6ee580SValentin Clement     return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty, name);
1519af6ee580SValentin Clement   }
1520af6ee580SValentin Clement 
1521af6ee580SValentin Clement   template <typename BOX>
1522af6ee580SValentin Clement   std::tuple<fir::BoxType, mlir::Value, mlir::Value>
1523af6ee580SValentin Clement   consDescriptorPrefix(BOX box, mlir::ConversionPatternRewriter &rewriter,
1524af6ee580SValentin Clement                        unsigned rank, mlir::ValueRange lenParams) const {
1525af6ee580SValentin Clement     auto loc = box.getLoc();
1526af6ee580SValentin Clement     auto boxTy = box.getType().template dyn_cast<fir::BoxType>();
1527af6ee580SValentin Clement     auto convTy = this->lowerTy().convertBoxType(boxTy, rank);
1528af6ee580SValentin Clement     auto llvmBoxPtrTy = convTy.template cast<mlir::LLVM::LLVMPointerType>();
1529af6ee580SValentin Clement     auto llvmBoxTy = llvmBoxPtrTy.getElementType();
1530af6ee580SValentin Clement     mlir::Value descriptor =
1531af6ee580SValentin Clement         rewriter.create<mlir::LLVM::UndefOp>(loc, llvmBoxTy);
1532af6ee580SValentin Clement 
1533af6ee580SValentin Clement     llvm::SmallVector<mlir::Value> typeparams = lenParams;
1534af6ee580SValentin Clement     if constexpr (!std::is_same_v<BOX, fir::EmboxOp>) {
1535af6ee580SValentin Clement       if (!box.substr().empty() && fir::hasDynamicSize(boxTy.getEleTy()))
1536af6ee580SValentin Clement         typeparams.push_back(box.substr()[1]);
1537af6ee580SValentin Clement     }
1538af6ee580SValentin Clement 
1539af6ee580SValentin Clement     // Write each of the fields with the appropriate values
1540af6ee580SValentin Clement     auto [eleSize, cfiTy] =
1541af6ee580SValentin Clement         getSizeAndTypeCode(loc, rewriter, boxTy.getEleTy(), typeparams);
1542af6ee580SValentin Clement     descriptor =
1543af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kElemLenPosInBox}, eleSize);
1544af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kVersionPosInBox},
1545af6ee580SValentin Clement                              this->genI32Constant(loc, rewriter, CFI_VERSION));
1546af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kRankPosInBox},
1547af6ee580SValentin Clement                              this->genI32Constant(loc, rewriter, rank));
1548af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kTypePosInBox}, cfiTy);
1549af6ee580SValentin Clement     descriptor =
1550af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kAttributePosInBox},
1551af6ee580SValentin Clement                     this->genI32Constant(loc, rewriter, getCFIAttr(boxTy)));
1552af6ee580SValentin Clement     const bool hasAddendum = isDerivedType(boxTy);
1553af6ee580SValentin Clement     descriptor =
1554af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kF18AddendumPosInBox},
1555af6ee580SValentin Clement                     this->genI32Constant(loc, rewriter, hasAddendum ? 1 : 0));
1556af6ee580SValentin Clement 
1557af6ee580SValentin Clement     if (hasAddendum) {
1558af6ee580SValentin Clement       auto isArray =
1559af6ee580SValentin Clement           fir::dyn_cast_ptrOrBoxEleTy(boxTy).template isa<fir::SequenceType>();
1560af6ee580SValentin Clement       unsigned typeDescFieldId = isArray ? kOptTypePtrPosInBox : kDimsPosInBox;
1561af6ee580SValentin Clement       auto typeDesc =
1562af6ee580SValentin Clement           getTypeDescriptor(box, rewriter, loc, unwrapIfDerived(boxTy));
1563af6ee580SValentin Clement       descriptor =
1564af6ee580SValentin Clement           insertField(rewriter, loc, descriptor, {typeDescFieldId}, typeDesc,
1565af6ee580SValentin Clement                       /*bitCast=*/true);
1566af6ee580SValentin Clement     }
1567af6ee580SValentin Clement 
1568af6ee580SValentin Clement     return {boxTy, descriptor, eleSize};
1569af6ee580SValentin Clement   }
1570af6ee580SValentin Clement 
1571*1f551032SValentin Clement   /// Compute the base address of a substring given the base address of a scalar
1572*1f551032SValentin Clement   /// string and the zero based string lower bound.
1573*1f551032SValentin Clement   mlir::Value shiftSubstringBase(mlir::ConversionPatternRewriter &rewriter,
1574*1f551032SValentin Clement                                  mlir::Location loc, mlir::Value base,
1575*1f551032SValentin Clement                                  mlir::Value lowerBound) const {
1576*1f551032SValentin Clement     llvm::SmallVector<mlir::Value> gepOperands;
1577*1f551032SValentin Clement     auto baseType =
1578*1f551032SValentin Clement         base.getType().cast<mlir::LLVM::LLVMPointerType>().getElementType();
1579*1f551032SValentin Clement     if (baseType.isa<mlir::LLVM::LLVMArrayType>()) {
1580*1f551032SValentin Clement       auto idxTy = this->lowerTy().indexType();
1581*1f551032SValentin Clement       mlir::Value zero = genConstantIndex(loc, idxTy, rewriter, 0);
1582*1f551032SValentin Clement       gepOperands.push_back(zero);
1583*1f551032SValentin Clement     }
1584*1f551032SValentin Clement     gepOperands.push_back(lowerBound);
1585*1f551032SValentin Clement     return this->genGEP(loc, base.getType(), rewriter, base, gepOperands);
1586*1f551032SValentin Clement   }
1587*1f551032SValentin Clement 
1588af6ee580SValentin Clement   /// If the embox is not in a globalOp body, allocate storage for the box;
1589af6ee580SValentin Clement   /// store the value inside and return the generated alloca. Return the input
1590af6ee580SValentin Clement   /// value otherwise.
1591af6ee580SValentin Clement   mlir::Value
1592af6ee580SValentin Clement   placeInMemoryIfNotGlobalInit(mlir::ConversionPatternRewriter &rewriter,
1593af6ee580SValentin Clement                                mlir::Location loc, mlir::Value boxValue) const {
1594af6ee580SValentin Clement     auto *thisBlock = rewriter.getInsertionBlock();
1595af6ee580SValentin Clement     if (thisBlock && mlir::isa<mlir::LLVM::GlobalOp>(thisBlock->getParentOp()))
1596af6ee580SValentin Clement       return boxValue;
1597af6ee580SValentin Clement     auto boxPtrTy = mlir::LLVM::LLVMPointerType::get(boxValue.getType());
1598af6ee580SValentin Clement     auto alloca = genAllocaWithType(loc, boxPtrTy, defaultAlign, rewriter);
1599af6ee580SValentin Clement     rewriter.create<mlir::LLVM::StoreOp>(loc, boxValue, alloca);
1600af6ee580SValentin Clement     return alloca;
1601af6ee580SValentin Clement   }
1602af6ee580SValentin Clement };
1603af6ee580SValentin Clement 
1604*1f551032SValentin Clement /// Compute the extent of a triplet slice (lb:ub:step).
1605*1f551032SValentin Clement static mlir::Value
1606*1f551032SValentin Clement computeTripletExtent(mlir::ConversionPatternRewriter &rewriter,
1607*1f551032SValentin Clement                      mlir::Location loc, mlir::Value lb, mlir::Value ub,
1608*1f551032SValentin Clement                      mlir::Value step, mlir::Value zero, mlir::Type type) {
1609*1f551032SValentin Clement   mlir::Value extent = rewriter.create<mlir::LLVM::SubOp>(loc, type, ub, lb);
1610*1f551032SValentin Clement   extent = rewriter.create<mlir::LLVM::AddOp>(loc, type, extent, step);
1611*1f551032SValentin Clement   extent = rewriter.create<mlir::LLVM::SDivOp>(loc, type, extent, step);
1612*1f551032SValentin Clement   // If the resulting extent is negative (`ub-lb` and `step` have different
1613*1f551032SValentin Clement   // signs), zero must be returned instead.
1614*1f551032SValentin Clement   auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
1615*1f551032SValentin Clement       loc, mlir::LLVM::ICmpPredicate::sgt, extent, zero);
1616*1f551032SValentin Clement   return rewriter.create<mlir::LLVM::SelectOp>(loc, cmp, extent, zero);
1617*1f551032SValentin Clement }
1618*1f551032SValentin Clement 
1619*1f551032SValentin Clement /// Helper function for generating the LLVM IR that computes the size
1620*1f551032SValentin Clement /// in bytes for a derived type.
1621*1f551032SValentin Clement static mlir::Value
1622*1f551032SValentin Clement computeDerivedTypeSize(mlir::Location loc, mlir::Type ptrTy, mlir::Type idxTy,
1623*1f551032SValentin Clement                        mlir::ConversionPatternRewriter &rewriter) {
1624*1f551032SValentin Clement   auto nullPtr = rewriter.create<mlir::LLVM::NullOp>(loc, ptrTy);
1625*1f551032SValentin Clement   mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1);
1626*1f551032SValentin Clement   llvm::SmallVector<mlir::Value> args{nullPtr, one};
1627*1f551032SValentin Clement   auto gep = rewriter.create<mlir::LLVM::GEPOp>(loc, ptrTy, args);
1628*1f551032SValentin Clement   return rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, gep);
1629*1f551032SValentin Clement }
1630*1f551032SValentin Clement 
1631af6ee580SValentin Clement /// Create a generic box on a memory reference. This conversions lowers the
1632af6ee580SValentin Clement /// abstract box to the appropriate, initialized descriptor.
1633af6ee580SValentin Clement struct EmboxOpConversion : public EmboxCommonConversion<fir::EmboxOp> {
1634af6ee580SValentin Clement   using EmboxCommonConversion::EmboxCommonConversion;
1635af6ee580SValentin Clement 
1636af6ee580SValentin Clement   mlir::LogicalResult
1637af6ee580SValentin Clement   matchAndRewrite(fir::EmboxOp embox, OpAdaptor adaptor,
1638af6ee580SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1639af6ee580SValentin Clement     assert(!embox.getShape() && "There should be no dims on this embox op");
1640af6ee580SValentin Clement     auto [boxTy, dest, eleSize] =
1641af6ee580SValentin Clement         consDescriptorPrefix(embox, rewriter, /*rank=*/0,
1642af6ee580SValentin Clement                              /*lenParams=*/adaptor.getOperands().drop_front(1));
1643af6ee580SValentin Clement     dest = insertBaseAddress(rewriter, embox.getLoc(), dest,
1644af6ee580SValentin Clement                              adaptor.getOperands()[0]);
16457ce8c6fcSKiran Chandramohan     if (isDerivedTypeWithLenParams(boxTy)) {
16467ce8c6fcSKiran Chandramohan       TODO(embox.getLoc(),
16477ce8c6fcSKiran Chandramohan            "fir.embox codegen of derived with length parameters");
16487ce8c6fcSKiran Chandramohan       return failure();
16497ce8c6fcSKiran Chandramohan     }
1650af6ee580SValentin Clement     auto result = placeInMemoryIfNotGlobalInit(rewriter, embox.getLoc(), dest);
1651af6ee580SValentin Clement     rewriter.replaceOp(embox, result);
1652af6ee580SValentin Clement     return success();
1653af6ee580SValentin Clement   }
1654af6ee580SValentin Clement };
1655af6ee580SValentin Clement 
1656cc505c0bSKiran Chandramohan /// Lower `fir.emboxproc` operation. Creates a procedure box.
1657cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
1658cc505c0bSKiran Chandramohan struct EmboxProcOpConversion : public FIROpConversion<fir::EmboxProcOp> {
1659cc505c0bSKiran Chandramohan   using FIROpConversion::FIROpConversion;
1660cc505c0bSKiran Chandramohan 
1661cc505c0bSKiran Chandramohan   mlir::LogicalResult
1662cc505c0bSKiran Chandramohan   matchAndRewrite(fir::EmboxProcOp emboxproc, OpAdaptor adaptor,
1663cc505c0bSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
16647ce8c6fcSKiran Chandramohan     TODO(emboxproc.getLoc(), "fir.emboxproc codegen");
16657ce8c6fcSKiran Chandramohan     return failure();
1666cc505c0bSKiran Chandramohan   }
1667cc505c0bSKiran Chandramohan };
1668cc505c0bSKiran Chandramohan 
1669*1f551032SValentin Clement /// Create a generic box on a memory reference.
1670*1f551032SValentin Clement struct XEmboxOpConversion : public EmboxCommonConversion<fir::cg::XEmboxOp> {
1671*1f551032SValentin Clement   using EmboxCommonConversion::EmboxCommonConversion;
1672*1f551032SValentin Clement 
1673*1f551032SValentin Clement   mlir::LogicalResult
1674*1f551032SValentin Clement   matchAndRewrite(fir::cg::XEmboxOp xbox, OpAdaptor adaptor,
1675*1f551032SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1676*1f551032SValentin Clement     auto [boxTy, dest, eleSize] = consDescriptorPrefix(
1677*1f551032SValentin Clement         xbox, rewriter, xbox.getOutRank(),
1678*1f551032SValentin Clement         adaptor.getOperands().drop_front(xbox.lenParamOffset()));
1679*1f551032SValentin Clement     // Generate the triples in the dims field of the descriptor
1680*1f551032SValentin Clement     mlir::ValueRange operands = adaptor.getOperands();
1681*1f551032SValentin Clement     auto i64Ty = mlir::IntegerType::get(xbox.getContext(), 64);
1682*1f551032SValentin Clement     mlir::Value base = operands[0];
1683*1f551032SValentin Clement     assert(!xbox.shape().empty() && "must have a shape");
1684*1f551032SValentin Clement     unsigned shapeOffset = xbox.shapeOffset();
1685*1f551032SValentin Clement     bool hasShift = !xbox.shift().empty();
1686*1f551032SValentin Clement     unsigned shiftOffset = xbox.shiftOffset();
1687*1f551032SValentin Clement     bool hasSlice = !xbox.slice().empty();
1688*1f551032SValentin Clement     unsigned sliceOffset = xbox.sliceOffset();
1689*1f551032SValentin Clement     mlir::Location loc = xbox.getLoc();
1690*1f551032SValentin Clement     mlir::Value zero = genConstantIndex(loc, i64Ty, rewriter, 0);
1691*1f551032SValentin Clement     mlir::Value one = genConstantIndex(loc, i64Ty, rewriter, 1);
1692*1f551032SValentin Clement     mlir::Value prevDim = integerCast(loc, rewriter, i64Ty, eleSize);
1693*1f551032SValentin Clement     mlir::Value prevPtrOff = one;
1694*1f551032SValentin Clement     mlir::Type eleTy = boxTy.getEleTy();
1695*1f551032SValentin Clement     const unsigned rank = xbox.getRank();
1696*1f551032SValentin Clement     llvm::SmallVector<mlir::Value> gepArgs;
1697*1f551032SValentin Clement     unsigned constRows = 0;
1698*1f551032SValentin Clement     mlir::Value ptrOffset = zero;
1699*1f551032SValentin Clement     if (auto memEleTy = fir::dyn_cast_ptrEleTy(xbox.memref().getType()))
1700*1f551032SValentin Clement       if (auto seqTy = memEleTy.dyn_cast<fir::SequenceType>()) {
1701*1f551032SValentin Clement         mlir::Type seqEleTy = seqTy.getEleTy();
1702*1f551032SValentin Clement         // Adjust the element scaling factor if the element is a dependent type.
1703*1f551032SValentin Clement         if (fir::hasDynamicSize(seqEleTy)) {
1704*1f551032SValentin Clement           if (fir::isa_char(seqEleTy)) {
1705*1f551032SValentin Clement             assert(xbox.lenParams().size() == 1);
1706*1f551032SValentin Clement             prevPtrOff = integerCast(loc, rewriter, i64Ty,
1707*1f551032SValentin Clement                                      operands[xbox.lenParamOffset()]);
1708*1f551032SValentin Clement           } else if (seqEleTy.isa<fir::RecordType>()) {
1709*1f551032SValentin Clement             TODO(loc, "generate call to calculate size of PDT");
1710*1f551032SValentin Clement           } else {
1711*1f551032SValentin Clement             return rewriter.notifyMatchFailure(xbox, "unexpected dynamic type");
1712*1f551032SValentin Clement           }
1713*1f551032SValentin Clement         } else {
1714*1f551032SValentin Clement           constRows = seqTy.getConstantRows();
1715*1f551032SValentin Clement         }
1716*1f551032SValentin Clement       }
1717*1f551032SValentin Clement 
1718*1f551032SValentin Clement     bool hasSubcomp = !xbox.subcomponent().empty();
1719*1f551032SValentin Clement     mlir::Value stepExpr;
1720*1f551032SValentin Clement     if (hasSubcomp) {
1721*1f551032SValentin Clement       // We have a subcomponent. The step value needs to be the number of
1722*1f551032SValentin Clement       // bytes per element (which is a derived type).
1723*1f551032SValentin Clement       mlir::Type ty0 = base.getType();
1724*1f551032SValentin Clement       [[maybe_unused]] auto ptrTy = ty0.dyn_cast<mlir::LLVM::LLVMPointerType>();
1725*1f551032SValentin Clement       assert(ptrTy && "expected pointer type");
1726*1f551032SValentin Clement       mlir::Type memEleTy = fir::dyn_cast_ptrEleTy(xbox.memref().getType());
1727*1f551032SValentin Clement       assert(memEleTy && "expected fir pointer type");
1728*1f551032SValentin Clement       auto seqTy = memEleTy.dyn_cast<fir::SequenceType>();
1729*1f551032SValentin Clement       assert(seqTy && "expected sequence type");
1730*1f551032SValentin Clement       mlir::Type seqEleTy = seqTy.getEleTy();
1731*1f551032SValentin Clement       auto eleTy = mlir::LLVM::LLVMPointerType::get(convertType(seqEleTy));
1732*1f551032SValentin Clement       stepExpr = computeDerivedTypeSize(loc, eleTy, i64Ty, rewriter);
1733*1f551032SValentin Clement     }
1734*1f551032SValentin Clement 
1735*1f551032SValentin Clement     // Process the array subspace arguments (shape, shift, etc.), if any,
1736*1f551032SValentin Clement     // translating everything to values in the descriptor wherever the entity
1737*1f551032SValentin Clement     // has a dynamic array dimension.
1738*1f551032SValentin Clement     for (unsigned di = 0, descIdx = 0; di < rank; ++di) {
1739*1f551032SValentin Clement       mlir::Value extent = operands[shapeOffset];
1740*1f551032SValentin Clement       mlir::Value outerExtent = extent;
1741*1f551032SValentin Clement       bool skipNext = false;
1742*1f551032SValentin Clement       if (hasSlice) {
1743*1f551032SValentin Clement         mlir::Value off = operands[sliceOffset];
1744*1f551032SValentin Clement         mlir::Value adj = one;
1745*1f551032SValentin Clement         if (hasShift)
1746*1f551032SValentin Clement           adj = operands[shiftOffset];
1747*1f551032SValentin Clement         auto ao = rewriter.create<mlir::LLVM::SubOp>(loc, i64Ty, off, adj);
1748*1f551032SValentin Clement         if (constRows > 0) {
1749*1f551032SValentin Clement           gepArgs.push_back(ao);
1750*1f551032SValentin Clement           --constRows;
1751*1f551032SValentin Clement         } else {
1752*1f551032SValentin Clement           auto dimOff =
1753*1f551032SValentin Clement               rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, ao, prevPtrOff);
1754*1f551032SValentin Clement           ptrOffset =
1755*1f551032SValentin Clement               rewriter.create<mlir::LLVM::AddOp>(loc, i64Ty, dimOff, ptrOffset);
1756*1f551032SValentin Clement         }
1757*1f551032SValentin Clement         if (mlir::isa_and_nonnull<fir::UndefOp>(
1758*1f551032SValentin Clement                 xbox.slice()[3 * di + 1].getDefiningOp())) {
1759*1f551032SValentin Clement           // This dimension contains a scalar expression in the array slice op.
1760*1f551032SValentin Clement           // The dimension is loop invariant, will be dropped, and will not
1761*1f551032SValentin Clement           // appear in the descriptor.
1762*1f551032SValentin Clement           skipNext = true;
1763*1f551032SValentin Clement         }
1764*1f551032SValentin Clement       }
1765*1f551032SValentin Clement       if (!skipNext) {
1766*1f551032SValentin Clement         // store lower bound (normally 0)
1767*1f551032SValentin Clement         mlir::Value lb = zero;
1768*1f551032SValentin Clement         if (eleTy.isa<fir::PointerType>() || eleTy.isa<fir::HeapType>()) {
1769*1f551032SValentin Clement           lb = one;
1770*1f551032SValentin Clement           if (hasShift)
1771*1f551032SValentin Clement             lb = operands[shiftOffset];
1772*1f551032SValentin Clement         }
1773*1f551032SValentin Clement         dest = insertLowerBound(rewriter, loc, dest, descIdx, lb);
1774*1f551032SValentin Clement 
1775*1f551032SValentin Clement         // store extent
1776*1f551032SValentin Clement         if (hasSlice)
1777*1f551032SValentin Clement           extent = computeTripletExtent(rewriter, loc, operands[sliceOffset],
1778*1f551032SValentin Clement                                         operands[sliceOffset + 1],
1779*1f551032SValentin Clement                                         operands[sliceOffset + 2], zero, i64Ty);
1780*1f551032SValentin Clement         dest = insertExtent(rewriter, loc, dest, descIdx, extent);
1781*1f551032SValentin Clement 
1782*1f551032SValentin Clement         // store step (scaled by shaped extent)
1783*1f551032SValentin Clement 
1784*1f551032SValentin Clement         mlir::Value step = hasSubcomp ? stepExpr : prevDim;
1785*1f551032SValentin Clement         if (hasSlice)
1786*1f551032SValentin Clement           step = rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, step,
1787*1f551032SValentin Clement                                                     operands[sliceOffset + 2]);
1788*1f551032SValentin Clement         dest = insertStride(rewriter, loc, dest, descIdx, step);
1789*1f551032SValentin Clement         ++descIdx;
1790*1f551032SValentin Clement       }
1791*1f551032SValentin Clement 
1792*1f551032SValentin Clement       // compute the stride and offset for the next natural dimension
1793*1f551032SValentin Clement       prevDim =
1794*1f551032SValentin Clement           rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, prevDim, outerExtent);
1795*1f551032SValentin Clement       if (constRows == 0)
1796*1f551032SValentin Clement         prevPtrOff = rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, prevPtrOff,
1797*1f551032SValentin Clement                                                         outerExtent);
1798*1f551032SValentin Clement 
1799*1f551032SValentin Clement       // increment iterators
1800*1f551032SValentin Clement       ++shapeOffset;
1801*1f551032SValentin Clement       if (hasShift)
1802*1f551032SValentin Clement         ++shiftOffset;
1803*1f551032SValentin Clement       if (hasSlice)
1804*1f551032SValentin Clement         sliceOffset += 3;
1805*1f551032SValentin Clement     }
1806*1f551032SValentin Clement     if (hasSlice || hasSubcomp || !xbox.substr().empty()) {
1807*1f551032SValentin Clement       llvm::SmallVector<mlir::Value> args = {base, ptrOffset};
1808*1f551032SValentin Clement       args.append(gepArgs.rbegin(), gepArgs.rend());
1809*1f551032SValentin Clement       if (hasSubcomp) {
1810*1f551032SValentin Clement         // For each field in the path add the offset to base via the args list.
1811*1f551032SValentin Clement         // In the most general case, some offsets must be computed since
1812*1f551032SValentin Clement         // they are not be known until runtime.
1813*1f551032SValentin Clement         if (fir::hasDynamicSize(fir::unwrapSequenceType(
1814*1f551032SValentin Clement                 fir::unwrapPassByRefType(xbox.memref().getType()))))
1815*1f551032SValentin Clement           TODO(loc, "fir.embox codegen dynamic size component in derived type");
1816*1f551032SValentin Clement         args.append(operands.begin() + xbox.subcomponentOffset(),
1817*1f551032SValentin Clement                     operands.begin() + xbox.subcomponentOffset() +
1818*1f551032SValentin Clement                         xbox.subcomponent().size());
1819*1f551032SValentin Clement       }
1820*1f551032SValentin Clement       base = rewriter.create<mlir::LLVM::GEPOp>(loc, base.getType(), args);
1821*1f551032SValentin Clement       if (!xbox.substr().empty())
1822*1f551032SValentin Clement         base = shiftSubstringBase(rewriter, loc, base,
1823*1f551032SValentin Clement                                   operands[xbox.substrOffset()]);
1824*1f551032SValentin Clement     }
1825*1f551032SValentin Clement     dest = insertBaseAddress(rewriter, loc, dest, base);
1826*1f551032SValentin Clement     if (isDerivedTypeWithLenParams(boxTy))
1827*1f551032SValentin Clement       TODO(loc, "fir.embox codegen of derived with length parameters");
1828*1f551032SValentin Clement 
1829*1f551032SValentin Clement     mlir::Value result = placeInMemoryIfNotGlobalInit(rewriter, loc, dest);
1830*1f551032SValentin Clement     rewriter.replaceOp(xbox, result);
1831*1f551032SValentin Clement     return success();
1832*1f551032SValentin Clement   }
1833*1f551032SValentin Clement };
1834*1f551032SValentin Clement 
183554c56347SValentin Clement // Code shared between insert_value and extract_value Ops.
183654c56347SValentin Clement struct ValueOpCommon {
183754c56347SValentin Clement   // Translate the arguments pertaining to any multidimensional array to
183854c56347SValentin Clement   // row-major order for LLVM-IR.
183954c56347SValentin Clement   static void toRowMajor(SmallVectorImpl<mlir::Attribute> &attrs,
184054c56347SValentin Clement                          mlir::Type ty) {
184154c56347SValentin Clement     assert(ty && "type is null");
184254c56347SValentin Clement     const auto end = attrs.size();
184354c56347SValentin Clement     for (std::remove_const_t<decltype(end)> i = 0; i < end; ++i) {
184454c56347SValentin Clement       if (auto seq = ty.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
184554c56347SValentin Clement         const auto dim = getDimension(seq);
184654c56347SValentin Clement         if (dim > 1) {
184754c56347SValentin Clement           auto ub = std::min(i + dim, end);
184854c56347SValentin Clement           std::reverse(attrs.begin() + i, attrs.begin() + ub);
184954c56347SValentin Clement           i += dim - 1;
185054c56347SValentin Clement         }
185154c56347SValentin Clement         ty = getArrayElementType(seq);
185254c56347SValentin Clement       } else if (auto st = ty.dyn_cast<mlir::LLVM::LLVMStructType>()) {
185354c56347SValentin Clement         ty = st.getBody()[attrs[i].cast<mlir::IntegerAttr>().getInt()];
185454c56347SValentin Clement       } else {
185554c56347SValentin Clement         llvm_unreachable("index into invalid type");
185654c56347SValentin Clement       }
185754c56347SValentin Clement     }
185854c56347SValentin Clement   }
185954c56347SValentin Clement 
186054c56347SValentin Clement   static llvm::SmallVector<mlir::Attribute>
186154c56347SValentin Clement   collectIndices(mlir::ConversionPatternRewriter &rewriter,
186254c56347SValentin Clement                  mlir::ArrayAttr arrAttr) {
186354c56347SValentin Clement     llvm::SmallVector<mlir::Attribute> attrs;
186454c56347SValentin Clement     for (auto i = arrAttr.begin(), e = arrAttr.end(); i != e; ++i) {
186554c56347SValentin Clement       if (i->isa<mlir::IntegerAttr>()) {
186654c56347SValentin Clement         attrs.push_back(*i);
186754c56347SValentin Clement       } else {
186854c56347SValentin Clement         auto fieldName = i->cast<mlir::StringAttr>().getValue();
186954c56347SValentin Clement         ++i;
187054c56347SValentin Clement         auto ty = i->cast<mlir::TypeAttr>().getValue();
187154c56347SValentin Clement         auto index = ty.cast<fir::RecordType>().getFieldIndex(fieldName);
187254c56347SValentin Clement         attrs.push_back(mlir::IntegerAttr::get(rewriter.getI32Type(), index));
187354c56347SValentin Clement       }
187454c56347SValentin Clement     }
187554c56347SValentin Clement     return attrs;
187654c56347SValentin Clement   }
187754c56347SValentin Clement 
187854c56347SValentin Clement private:
187954c56347SValentin Clement   static unsigned getDimension(mlir::LLVM::LLVMArrayType ty) {
188054c56347SValentin Clement     unsigned result = 1;
188154c56347SValentin Clement     for (auto eleTy = ty.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>();
188254c56347SValentin Clement          eleTy;
188354c56347SValentin Clement          eleTy = eleTy.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>())
188454c56347SValentin Clement       ++result;
188554c56347SValentin Clement     return result;
188654c56347SValentin Clement   }
188754c56347SValentin Clement 
188854c56347SValentin Clement   static mlir::Type getArrayElementType(mlir::LLVM::LLVMArrayType ty) {
188954c56347SValentin Clement     auto eleTy = ty.getElementType();
189054c56347SValentin Clement     while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>())
189154c56347SValentin Clement       eleTy = arrTy.getElementType();
189254c56347SValentin Clement     return eleTy;
189354c56347SValentin Clement   }
189454c56347SValentin Clement };
189554c56347SValentin Clement 
189654c56347SValentin Clement /// Extract a subobject value from an ssa-value of aggregate type
189754c56347SValentin Clement struct ExtractValueOpConversion
189854c56347SValentin Clement     : public FIROpAndTypeConversion<fir::ExtractValueOp>,
189954c56347SValentin Clement       public ValueOpCommon {
190054c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
190154c56347SValentin Clement 
190254c56347SValentin Clement   mlir::LogicalResult
190354c56347SValentin Clement   doRewrite(fir::ExtractValueOp extractVal, mlir::Type ty, OpAdaptor adaptor,
190454c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
190554c56347SValentin Clement     auto attrs = collectIndices(rewriter, extractVal.coor());
190654c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
190754c56347SValentin Clement     auto position = mlir::ArrayAttr::get(extractVal.getContext(), attrs);
190854c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(
190954c56347SValentin Clement         extractVal, ty, adaptor.getOperands()[0], position);
191054c56347SValentin Clement     return success();
191154c56347SValentin Clement   }
191254c56347SValentin Clement };
191354c56347SValentin Clement 
191454c56347SValentin Clement /// InsertValue is the generalized instruction for the composition of new
191554c56347SValentin Clement /// aggregate type values.
191654c56347SValentin Clement struct InsertValueOpConversion
191754c56347SValentin Clement     : public FIROpAndTypeConversion<fir::InsertValueOp>,
191854c56347SValentin Clement       public ValueOpCommon {
191954c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
192054c56347SValentin Clement 
192154c56347SValentin Clement   mlir::LogicalResult
192254c56347SValentin Clement   doRewrite(fir::InsertValueOp insertVal, mlir::Type ty, OpAdaptor adaptor,
192354c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
192454c56347SValentin Clement     auto attrs = collectIndices(rewriter, insertVal.coor());
192554c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
192654c56347SValentin Clement     auto position = mlir::ArrayAttr::get(insertVal.getContext(), attrs);
192754c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
192854c56347SValentin Clement         insertVal, ty, adaptor.getOperands()[0], adaptor.getOperands()[1],
192954c56347SValentin Clement         position);
193054c56347SValentin Clement     return success();
193154c56347SValentin Clement   }
193254c56347SValentin Clement };
193354c56347SValentin Clement 
19343ae8e442SValentin Clement /// InsertOnRange inserts a value into a sequence over a range of offsets.
19353ae8e442SValentin Clement struct InsertOnRangeOpConversion
19363ae8e442SValentin Clement     : public FIROpAndTypeConversion<fir::InsertOnRangeOp> {
19373ae8e442SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
19383ae8e442SValentin Clement 
19393ae8e442SValentin Clement   // Increments an array of subscripts in a row major fasion.
19403ae8e442SValentin Clement   void incrementSubscripts(const SmallVector<uint64_t> &dims,
19413ae8e442SValentin Clement                            SmallVector<uint64_t> &subscripts) const {
19423ae8e442SValentin Clement     for (size_t i = dims.size(); i > 0; --i) {
19433ae8e442SValentin Clement       if (++subscripts[i - 1] < dims[i - 1]) {
19443ae8e442SValentin Clement         return;
19453ae8e442SValentin Clement       }
19463ae8e442SValentin Clement       subscripts[i - 1] = 0;
19473ae8e442SValentin Clement     }
19483ae8e442SValentin Clement   }
19493ae8e442SValentin Clement 
19503ae8e442SValentin Clement   mlir::LogicalResult
19513ae8e442SValentin Clement   doRewrite(fir::InsertOnRangeOp range, mlir::Type ty, OpAdaptor adaptor,
19523ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
19533ae8e442SValentin Clement 
19543ae8e442SValentin Clement     llvm::SmallVector<uint64_t> dims;
19553ae8e442SValentin Clement     auto type = adaptor.getOperands()[0].getType();
19563ae8e442SValentin Clement 
19573ae8e442SValentin Clement     // Iteratively extract the array dimensions from the type.
19583ae8e442SValentin Clement     while (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
19593ae8e442SValentin Clement       dims.push_back(t.getNumElements());
19603ae8e442SValentin Clement       type = t.getElementType();
19613ae8e442SValentin Clement     }
19623ae8e442SValentin Clement 
19633ae8e442SValentin Clement     SmallVector<uint64_t> lBounds;
19643ae8e442SValentin Clement     SmallVector<uint64_t> uBounds;
19653ae8e442SValentin Clement 
19663ae8e442SValentin Clement     // Unzip the upper and lower bound and convert to a row major format.
19678ec0f221SMehdi Amini     mlir::DenseIntElementsAttr coor = range.coor();
19688ec0f221SMehdi Amini     auto reversedCoor = llvm::reverse(coor.getValues<int64_t>());
19698ec0f221SMehdi Amini     for (auto i = reversedCoor.begin(), e = reversedCoor.end(); i != e; ++i) {
19703ae8e442SValentin Clement       uBounds.push_back(*i++);
19713ae8e442SValentin Clement       lBounds.push_back(*i);
19723ae8e442SValentin Clement     }
19733ae8e442SValentin Clement 
19743ae8e442SValentin Clement     auto &subscripts = lBounds;
19753ae8e442SValentin Clement     auto loc = range.getLoc();
19763ae8e442SValentin Clement     mlir::Value lastOp = adaptor.getOperands()[0];
19773ae8e442SValentin Clement     mlir::Value insertVal = adaptor.getOperands()[1];
19783ae8e442SValentin Clement 
19793ae8e442SValentin Clement     auto i64Ty = rewriter.getI64Type();
19803ae8e442SValentin Clement     while (subscripts != uBounds) {
19813ae8e442SValentin Clement       // Convert uint64_t's to Attribute's.
19823ae8e442SValentin Clement       SmallVector<mlir::Attribute> subscriptAttrs;
19833ae8e442SValentin Clement       for (const auto &subscript : subscripts)
19843ae8e442SValentin Clement         subscriptAttrs.push_back(IntegerAttr::get(i64Ty, subscript));
19853ae8e442SValentin Clement       lastOp = rewriter.create<mlir::LLVM::InsertValueOp>(
19863ae8e442SValentin Clement           loc, ty, lastOp, insertVal,
19873ae8e442SValentin Clement           ArrayAttr::get(range.getContext(), subscriptAttrs));
19883ae8e442SValentin Clement 
19893ae8e442SValentin Clement       incrementSubscripts(dims, subscripts);
19903ae8e442SValentin Clement     }
19913ae8e442SValentin Clement 
19923ae8e442SValentin Clement     // Convert uint64_t's to Attribute's.
19933ae8e442SValentin Clement     SmallVector<mlir::Attribute> subscriptAttrs;
19943ae8e442SValentin Clement     for (const auto &subscript : subscripts)
19953ae8e442SValentin Clement       subscriptAttrs.push_back(
19963ae8e442SValentin Clement           IntegerAttr::get(rewriter.getI64Type(), subscript));
19973ae8e442SValentin Clement     mlir::ArrayRef<mlir::Attribute> arrayRef(subscriptAttrs);
19983ae8e442SValentin Clement 
19993ae8e442SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
20003ae8e442SValentin Clement         range, ty, lastOp, insertVal,
20013ae8e442SValentin Clement         ArrayAttr::get(range.getContext(), arrayRef));
20023ae8e442SValentin Clement 
20033ae8e442SValentin Clement     return success();
20043ae8e442SValentin Clement   }
20053ae8e442SValentin Clement };
20067b5132daSValentin Clement 
20077b5132daSValentin Clement //
20087b5132daSValentin Clement // Primitive operations on Complex types
20097b5132daSValentin Clement //
20107b5132daSValentin Clement 
20117b5132daSValentin Clement /// Generate inline code for complex addition/subtraction
20127b5132daSValentin Clement template <typename LLVMOP, typename OPTY>
20137b5132daSValentin Clement mlir::LLVM::InsertValueOp complexSum(OPTY sumop, mlir::ValueRange opnds,
20147b5132daSValentin Clement                                      mlir::ConversionPatternRewriter &rewriter,
20157b5132daSValentin Clement                                      fir::LLVMTypeConverter &lowering) {
20167b5132daSValentin Clement   mlir::Value a = opnds[0];
20177b5132daSValentin Clement   mlir::Value b = opnds[1];
20187b5132daSValentin Clement   auto loc = sumop.getLoc();
20197b5132daSValentin Clement   auto ctx = sumop.getContext();
20207b5132daSValentin Clement   auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
20217b5132daSValentin Clement   auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
20227b5132daSValentin Clement   mlir::Type eleTy = lowering.convertType(getComplexEleTy(sumop.getType()));
20237b5132daSValentin Clement   mlir::Type ty = lowering.convertType(sumop.getType());
20247b5132daSValentin Clement   auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
20257b5132daSValentin Clement   auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
20267b5132daSValentin Clement   auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
20277b5132daSValentin Clement   auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
20287b5132daSValentin Clement   auto rx = rewriter.create<LLVMOP>(loc, eleTy, x0, x1);
20297b5132daSValentin Clement   auto ry = rewriter.create<LLVMOP>(loc, eleTy, y0, y1);
20307b5132daSValentin Clement   auto r0 = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
20317b5132daSValentin Clement   auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r0, rx, c0);
20327b5132daSValentin Clement   return rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ry, c1);
20337b5132daSValentin Clement }
20347b5132daSValentin Clement 
20357b5132daSValentin Clement struct AddcOpConversion : public FIROpConversion<fir::AddcOp> {
20367b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
20377b5132daSValentin Clement 
20387b5132daSValentin Clement   mlir::LogicalResult
20397b5132daSValentin Clement   matchAndRewrite(fir::AddcOp addc, OpAdaptor adaptor,
20407b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
20417b5132daSValentin Clement     // given: (x + iy) + (x' + iy')
20427b5132daSValentin Clement     // result: (x + x') + i(y + y')
20437b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FAddOp>(addc, adaptor.getOperands(),
20447b5132daSValentin Clement                                             rewriter, lowerTy());
20457b5132daSValentin Clement     rewriter.replaceOp(addc, r.getResult());
20467b5132daSValentin Clement     return success();
20477b5132daSValentin Clement   }
20487b5132daSValentin Clement };
20497b5132daSValentin Clement 
20507b5132daSValentin Clement struct SubcOpConversion : public FIROpConversion<fir::SubcOp> {
20517b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
20527b5132daSValentin Clement 
20537b5132daSValentin Clement   mlir::LogicalResult
20547b5132daSValentin Clement   matchAndRewrite(fir::SubcOp subc, OpAdaptor adaptor,
20557b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
20567b5132daSValentin Clement     // given: (x + iy) - (x' + iy')
20577b5132daSValentin Clement     // result: (x - x') + i(y - y')
20587b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FSubOp>(subc, adaptor.getOperands(),
20597b5132daSValentin Clement                                             rewriter, lowerTy());
20607b5132daSValentin Clement     rewriter.replaceOp(subc, r.getResult());
20617b5132daSValentin Clement     return success();
20627b5132daSValentin Clement   }
20637b5132daSValentin Clement };
20647b5132daSValentin Clement 
20657b5132daSValentin Clement /// Inlined complex multiply
20667b5132daSValentin Clement struct MulcOpConversion : public FIROpConversion<fir::MulcOp> {
20677b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
20687b5132daSValentin Clement 
20697b5132daSValentin Clement   mlir::LogicalResult
20707b5132daSValentin Clement   matchAndRewrite(fir::MulcOp mulc, OpAdaptor adaptor,
20717b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
20727b5132daSValentin Clement     // TODO: Can we use a call to __muldc3 ?
20737b5132daSValentin Clement     // given: (x + iy) * (x' + iy')
20747b5132daSValentin Clement     // result: (xx'-yy')+i(xy'+yx')
20757b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
20767b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
20777b5132daSValentin Clement     auto loc = mulc.getLoc();
20787b5132daSValentin Clement     auto *ctx = mulc.getContext();
20797b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
20807b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
20817b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(mulc.getType()));
20827b5132daSValentin Clement     mlir::Type ty = convertType(mulc.getType());
20837b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
20847b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
20857b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
20867b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
20877b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
20887b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
20897b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
20907b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xy, yx);
20917b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
20927b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, xx, yy);
20937b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
20947b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
20957b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
20967b5132daSValentin Clement     rewriter.replaceOp(mulc, r0.getResult());
20977b5132daSValentin Clement     return success();
20987b5132daSValentin Clement   }
20997b5132daSValentin Clement };
21007b5132daSValentin Clement 
21017b5132daSValentin Clement /// Inlined complex division
21027b5132daSValentin Clement struct DivcOpConversion : public FIROpConversion<fir::DivcOp> {
21037b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
21047b5132daSValentin Clement 
21057b5132daSValentin Clement   mlir::LogicalResult
21067b5132daSValentin Clement   matchAndRewrite(fir::DivcOp divc, OpAdaptor adaptor,
21077b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
21087b5132daSValentin Clement     // TODO: Can we use a call to __divdc3 instead?
21097b5132daSValentin Clement     // Just generate inline code for now.
21107b5132daSValentin Clement     // given: (x + iy) / (x' + iy')
21117b5132daSValentin Clement     // result: ((xx'+yy')/d) + i((yx'-xy')/d) where d = x'x' + y'y'
21127b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
21137b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
21147b5132daSValentin Clement     auto loc = divc.getLoc();
21157b5132daSValentin Clement     auto *ctx = divc.getContext();
21167b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
21177b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
21187b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(divc.getType()));
21197b5132daSValentin Clement     mlir::Type ty = convertType(divc.getType());
21207b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
21217b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
21227b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
21237b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
21247b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
21257b5132daSValentin Clement     auto x1x1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x1, x1);
21267b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
21277b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
21287b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
21297b5132daSValentin Clement     auto y1y1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y1, y1);
21307b5132daSValentin Clement     auto d = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, x1x1, y1y1);
21317b5132daSValentin Clement     auto rrn = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xx, yy);
21327b5132daSValentin Clement     auto rin = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, yx, xy);
21337b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rrn, d);
21347b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rin, d);
21357b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
21367b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
21377b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
21387b5132daSValentin Clement     rewriter.replaceOp(divc, r0.getResult());
21397b5132daSValentin Clement     return success();
21407b5132daSValentin Clement   }
21417b5132daSValentin Clement };
21427b5132daSValentin Clement 
21437b5132daSValentin Clement /// Inlined complex negation
21447b5132daSValentin Clement struct NegcOpConversion : public FIROpConversion<fir::NegcOp> {
21457b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
21467b5132daSValentin Clement 
21477b5132daSValentin Clement   mlir::LogicalResult
21487b5132daSValentin Clement   matchAndRewrite(fir::NegcOp neg, OpAdaptor adaptor,
21497b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
21507b5132daSValentin Clement     // given: -(x + iy)
21517b5132daSValentin Clement     // result: -x - iy
21527b5132daSValentin Clement     auto *ctxt = neg.getContext();
21537b5132daSValentin Clement     auto eleTy = convertType(getComplexEleTy(neg.getType()));
21547b5132daSValentin Clement     auto ty = convertType(neg.getType());
21557b5132daSValentin Clement     auto loc = neg.getLoc();
21567b5132daSValentin Clement     mlir::Value o0 = adaptor.getOperands()[0];
21577b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0));
21587b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1));
21597b5132daSValentin Clement     auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c0);
21607b5132daSValentin Clement     auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c1);
21617b5132daSValentin Clement     auto nrp = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, rp);
21627b5132daSValentin Clement     auto nip = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, ip);
21637b5132daSValentin Clement     auto r = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, o0, nrp, c0);
21647b5132daSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(neg, ty, r, nip, c1);
21657b5132daSValentin Clement     return success();
21667b5132daSValentin Clement   }
21677b5132daSValentin Clement };
21687b5132daSValentin Clement 
21691ed5a90fSValentin Clement /// Conversion pattern for operation that must be dead. The information in these
21701ed5a90fSValentin Clement /// operations is used by other operation. At this point they should not have
21711ed5a90fSValentin Clement /// anymore uses.
21721ed5a90fSValentin Clement /// These operations are normally dead after the pre-codegen pass.
21731ed5a90fSValentin Clement template <typename FromOp>
21741ed5a90fSValentin Clement struct MustBeDeadConversion : public FIROpConversion<FromOp> {
21751ed5a90fSValentin Clement   explicit MustBeDeadConversion(fir::LLVMTypeConverter &lowering)
21761ed5a90fSValentin Clement       : FIROpConversion<FromOp>(lowering) {}
21771ed5a90fSValentin Clement   using OpAdaptor = typename FromOp::Adaptor;
21781ed5a90fSValentin Clement 
21791ed5a90fSValentin Clement   mlir::LogicalResult
21801ed5a90fSValentin Clement   matchAndRewrite(FromOp op, OpAdaptor adaptor,
21811ed5a90fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const final {
21821ed5a90fSValentin Clement     if (!op->getUses().empty())
21831ed5a90fSValentin Clement       return rewriter.notifyMatchFailure(op, "op must be dead");
21841ed5a90fSValentin Clement     rewriter.eraseOp(op);
21851ed5a90fSValentin Clement     return success();
21861ed5a90fSValentin Clement   }
21871ed5a90fSValentin Clement };
21881ed5a90fSValentin Clement 
21891ed5a90fSValentin Clement struct ShapeOpConversion : public MustBeDeadConversion<fir::ShapeOp> {
21901ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
21911ed5a90fSValentin Clement };
21921ed5a90fSValentin Clement 
21931ed5a90fSValentin Clement struct ShapeShiftOpConversion : public MustBeDeadConversion<fir::ShapeShiftOp> {
21941ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
21951ed5a90fSValentin Clement };
21961ed5a90fSValentin Clement 
21971ed5a90fSValentin Clement struct ShiftOpConversion : public MustBeDeadConversion<fir::ShiftOp> {
21981ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
21991ed5a90fSValentin Clement };
22001ed5a90fSValentin Clement 
22011ed5a90fSValentin Clement struct SliceOpConversion : public MustBeDeadConversion<fir::SliceOp> {
22021ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
22031ed5a90fSValentin Clement };
22041ed5a90fSValentin Clement 
2205420ad7ceSAndrzej Warzynski /// `fir.is_present` -->
2206420ad7ceSAndrzej Warzynski /// ```
2207420ad7ceSAndrzej Warzynski ///  %0 = llvm.mlir.constant(0 : i64)
2208420ad7ceSAndrzej Warzynski ///  %1 = llvm.ptrtoint %0
2209420ad7ceSAndrzej Warzynski ///  %2 = llvm.icmp "ne" %1, %0 : i64
2210420ad7ceSAndrzej Warzynski /// ```
2211420ad7ceSAndrzej Warzynski struct IsPresentOpConversion : public FIROpConversion<fir::IsPresentOp> {
2212420ad7ceSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
2213420ad7ceSAndrzej Warzynski 
2214420ad7ceSAndrzej Warzynski   mlir::LogicalResult
2215420ad7ceSAndrzej Warzynski   matchAndRewrite(fir::IsPresentOp isPresent, OpAdaptor adaptor,
2216420ad7ceSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
2217420ad7ceSAndrzej Warzynski     mlir::Type idxTy = lowerTy().indexType();
2218420ad7ceSAndrzej Warzynski     mlir::Location loc = isPresent.getLoc();
2219420ad7ceSAndrzej Warzynski     auto ptr = adaptor.getOperands()[0];
2220420ad7ceSAndrzej Warzynski 
2221420ad7ceSAndrzej Warzynski     if (isPresent.val().getType().isa<fir::BoxCharType>()) {
2222420ad7ceSAndrzej Warzynski       auto structTy = ptr.getType().cast<mlir::LLVM::LLVMStructType>();
2223420ad7ceSAndrzej Warzynski       assert(!structTy.isOpaque() && !structTy.getBody().empty());
2224420ad7ceSAndrzej Warzynski 
2225420ad7ceSAndrzej Warzynski       mlir::Type ty = structTy.getBody()[0];
2226420ad7ceSAndrzej Warzynski       mlir::MLIRContext *ctx = isPresent.getContext();
2227420ad7ceSAndrzej Warzynski       auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
2228420ad7ceSAndrzej Warzynski       ptr = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, ptr, c0);
2229420ad7ceSAndrzej Warzynski     }
2230420ad7ceSAndrzej Warzynski     mlir::LLVM::ConstantOp c0 =
2231420ad7ceSAndrzej Warzynski         genConstantIndex(isPresent.getLoc(), idxTy, rewriter, 0);
2232420ad7ceSAndrzej Warzynski     auto addr = rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, ptr);
2233420ad7ceSAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
2234420ad7ceSAndrzej Warzynski         isPresent, mlir::LLVM::ICmpPredicate::ne, addr, c0);
2235420ad7ceSAndrzej Warzynski 
2236420ad7ceSAndrzej Warzynski     return success();
2237420ad7ceSAndrzej Warzynski   }
2238420ad7ceSAndrzej Warzynski };
22391e77b095SAndrzej Warzynski 
22401e77b095SAndrzej Warzynski /// Convert `!fir.emboxchar<!fir.char<KIND, ?>, #n>` into a sequence of
22411e77b095SAndrzej Warzynski /// instructions that generate `!llvm.struct<(ptr<ik>, i64)>`. The 1st element
22421e77b095SAndrzej Warzynski /// in this struct is a pointer. Its type is determined from `KIND`. The 2nd
22431e77b095SAndrzej Warzynski /// element is the length of the character buffer (`#n`).
22441e77b095SAndrzej Warzynski struct EmboxCharOpConversion : public FIROpConversion<fir::EmboxCharOp> {
22451e77b095SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
22461e77b095SAndrzej Warzynski 
22471e77b095SAndrzej Warzynski   mlir::LogicalResult
22481e77b095SAndrzej Warzynski   matchAndRewrite(fir::EmboxCharOp emboxChar, OpAdaptor adaptor,
22491e77b095SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
22501e77b095SAndrzej Warzynski     mlir::ValueRange operands = adaptor.getOperands();
22511e77b095SAndrzej Warzynski     MLIRContext *ctx = emboxChar.getContext();
22521e77b095SAndrzej Warzynski 
22531e77b095SAndrzej Warzynski     mlir::Value charBuffer = operands[0];
22541e77b095SAndrzej Warzynski     mlir::Value charBufferLen = operands[1];
22551e77b095SAndrzej Warzynski 
22561e77b095SAndrzej Warzynski     mlir::Location loc = emboxChar.getLoc();
22571e77b095SAndrzej Warzynski     mlir::Type llvmStructTy = convertType(emboxChar.getType());
22581e77b095SAndrzej Warzynski     auto llvmStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, llvmStructTy);
22591e77b095SAndrzej Warzynski 
22601e77b095SAndrzej Warzynski     mlir::Type lenTy =
22611e77b095SAndrzej Warzynski         llvmStructTy.cast<mlir::LLVM::LLVMStructType>().getBody()[1];
22621e77b095SAndrzej Warzynski     mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, charBufferLen);
22631e77b095SAndrzej Warzynski 
22641e77b095SAndrzej Warzynski     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
22651e77b095SAndrzej Warzynski     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
22661e77b095SAndrzej Warzynski     auto insertBufferOp = rewriter.create<mlir::LLVM::InsertValueOp>(
22671e77b095SAndrzej Warzynski         loc, llvmStructTy, llvmStruct, charBuffer, c0);
22681e77b095SAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
22691e77b095SAndrzej Warzynski         emboxChar, llvmStructTy, insertBufferOp, lenAfterCast, c1);
22701e77b095SAndrzej Warzynski 
22711e77b095SAndrzej Warzynski     return success();
22721e77b095SAndrzej Warzynski   }
22731e77b095SAndrzej Warzynski };
227414867ffcSAndrzej Warzynski 
227514867ffcSAndrzej Warzynski /// Construct an `llvm.extractvalue` instruction. It will return value at
227614867ffcSAndrzej Warzynski /// element \p x from  \p tuple.
227714867ffcSAndrzej Warzynski mlir::LLVM::ExtractValueOp
227814867ffcSAndrzej Warzynski genExtractValueWithIndex(mlir::Location loc, mlir::Value tuple, mlir::Type ty,
227914867ffcSAndrzej Warzynski                          mlir::ConversionPatternRewriter &rewriter,
228014867ffcSAndrzej Warzynski                          mlir::MLIRContext *ctx, int x) {
228114867ffcSAndrzej Warzynski   auto cx = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(x));
228214867ffcSAndrzej Warzynski   auto xty = ty.cast<mlir::LLVM::LLVMStructType>().getBody()[x];
228314867ffcSAndrzej Warzynski   return rewriter.create<mlir::LLVM::ExtractValueOp>(loc, xty, tuple, cx);
228414867ffcSAndrzej Warzynski }
228514867ffcSAndrzej Warzynski 
22866c3d7fd4SAndrzej Warzynski /// Convert `!fir.boxchar_len` to  `!llvm.extractvalue` for the 2nd part of the
22876c3d7fd4SAndrzej Warzynski /// boxchar.
22886c3d7fd4SAndrzej Warzynski struct BoxCharLenOpConversion : public FIROpConversion<fir::BoxCharLenOp> {
22896c3d7fd4SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
22906c3d7fd4SAndrzej Warzynski 
22916c3d7fd4SAndrzej Warzynski   mlir::LogicalResult
22926c3d7fd4SAndrzej Warzynski   matchAndRewrite(fir::BoxCharLenOp boxCharLen, OpAdaptor adaptor,
22936c3d7fd4SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
22946c3d7fd4SAndrzej Warzynski     mlir::Value boxChar = adaptor.getOperands()[0];
22956c3d7fd4SAndrzej Warzynski     mlir::Location loc = boxChar.getLoc();
22966c3d7fd4SAndrzej Warzynski     mlir::MLIRContext *ctx = boxChar.getContext();
22976c3d7fd4SAndrzej Warzynski     mlir::Type returnValTy = boxCharLen.getResult().getType();
22986c3d7fd4SAndrzej Warzynski 
22996c3d7fd4SAndrzej Warzynski     constexpr int boxcharLenIdx = 1;
23006c3d7fd4SAndrzej Warzynski     mlir::LLVM::ExtractValueOp len = genExtractValueWithIndex(
23016c3d7fd4SAndrzej Warzynski         loc, boxChar, boxChar.getType(), rewriter, ctx, boxcharLenIdx);
23026c3d7fd4SAndrzej Warzynski     mlir::Value lenAfterCast = integerCast(loc, rewriter, returnValTy, len);
23036c3d7fd4SAndrzej Warzynski     rewriter.replaceOp(boxCharLen, lenAfterCast);
23046c3d7fd4SAndrzej Warzynski 
23056c3d7fd4SAndrzej Warzynski     return success();
23066c3d7fd4SAndrzej Warzynski   }
23076c3d7fd4SAndrzej Warzynski };
23086c3d7fd4SAndrzej Warzynski 
230914867ffcSAndrzej Warzynski /// Convert `fir.unboxchar` into two `llvm.extractvalue` instructions. One for
231014867ffcSAndrzej Warzynski /// the character buffer and one for the buffer length.
231114867ffcSAndrzej Warzynski struct UnboxCharOpConversion : public FIROpConversion<fir::UnboxCharOp> {
231214867ffcSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
231314867ffcSAndrzej Warzynski 
231414867ffcSAndrzej Warzynski   mlir::LogicalResult
231514867ffcSAndrzej Warzynski   matchAndRewrite(fir::UnboxCharOp unboxchar, OpAdaptor adaptor,
231614867ffcSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
231714867ffcSAndrzej Warzynski     MLIRContext *ctx = unboxchar.getContext();
231814867ffcSAndrzej Warzynski 
231914867ffcSAndrzej Warzynski     mlir::Type lenTy = convertType(unboxchar.getType(1));
232014867ffcSAndrzej Warzynski     mlir::Value tuple = adaptor.getOperands()[0];
232114867ffcSAndrzej Warzynski     mlir::Type tupleTy = tuple.getType();
232214867ffcSAndrzej Warzynski 
232314867ffcSAndrzej Warzynski     mlir::Location loc = unboxchar.getLoc();
232414867ffcSAndrzej Warzynski     mlir::Value ptrToBuffer =
232514867ffcSAndrzej Warzynski         genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 0);
232614867ffcSAndrzej Warzynski 
232714867ffcSAndrzej Warzynski     mlir::LLVM::ExtractValueOp len =
232814867ffcSAndrzej Warzynski         genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 1);
232914867ffcSAndrzej Warzynski     mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, len);
233014867ffcSAndrzej Warzynski 
233114867ffcSAndrzej Warzynski     rewriter.replaceOp(unboxchar,
233214867ffcSAndrzej Warzynski                        ArrayRef<mlir::Value>{ptrToBuffer, lenAfterCast});
233314867ffcSAndrzej Warzynski     return success();
233414867ffcSAndrzej Warzynski   }
233514867ffcSAndrzej Warzynski };
233614867ffcSAndrzej Warzynski 
2337cc505c0bSKiran Chandramohan /// Lower `fir.unboxproc` operation. Unbox a procedure box value, yielding its
2338cc505c0bSKiran Chandramohan /// components.
2339cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
2340cc505c0bSKiran Chandramohan struct UnboxProcOpConversion : public FIROpConversion<fir::UnboxProcOp> {
2341cc505c0bSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2342cc505c0bSKiran Chandramohan 
2343cc505c0bSKiran Chandramohan   mlir::LogicalResult
2344cc505c0bSKiran Chandramohan   matchAndRewrite(fir::UnboxProcOp unboxproc, OpAdaptor adaptor,
2345cc505c0bSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
23467ce8c6fcSKiran Chandramohan     TODO(unboxproc.getLoc(), "fir.unboxproc codegen");
23477ce8c6fcSKiran Chandramohan     return failure();
2348cc505c0bSKiran Chandramohan   }
2349cc505c0bSKiran Chandramohan };
2350cc505c0bSKiran Chandramohan 
2351e6c66ef5SAndrzej Warzynski /// Convert `fir.field_index`. The conversion depends on whether the size of
2352e6c66ef5SAndrzej Warzynski /// the record is static or dynamic.
2353e6c66ef5SAndrzej Warzynski struct FieldIndexOpConversion : public FIROpConversion<fir::FieldIndexOp> {
2354e6c66ef5SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
2355e6c66ef5SAndrzej Warzynski 
2356e6c66ef5SAndrzej Warzynski   // NB: most field references should be resolved by this point
2357e6c66ef5SAndrzej Warzynski   mlir::LogicalResult
2358e6c66ef5SAndrzej Warzynski   matchAndRewrite(fir::FieldIndexOp field, OpAdaptor adaptor,
2359e6c66ef5SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
2360e6c66ef5SAndrzej Warzynski     auto recTy = field.on_type().cast<fir::RecordType>();
2361e6c66ef5SAndrzej Warzynski     unsigned index = recTy.getFieldIndex(field.field_id());
2362e6c66ef5SAndrzej Warzynski 
2363e6c66ef5SAndrzej Warzynski     if (!fir::hasDynamicSize(recTy)) {
2364e6c66ef5SAndrzej Warzynski       // Derived type has compile-time constant layout. Return index of the
2365e6c66ef5SAndrzej Warzynski       // component type in the parent type (to be used in GEP).
2366e6c66ef5SAndrzej Warzynski       rewriter.replaceOp(field, mlir::ValueRange{genConstantOffset(
2367e6c66ef5SAndrzej Warzynski                                     field.getLoc(), rewriter, index)});
2368e6c66ef5SAndrzej Warzynski       return success();
2369e6c66ef5SAndrzej Warzynski     }
2370e6c66ef5SAndrzej Warzynski 
2371e6c66ef5SAndrzej Warzynski     // Derived type has compile-time constant layout. Call the compiler
2372e6c66ef5SAndrzej Warzynski     // generated function to determine the byte offset of the field at runtime.
2373e6c66ef5SAndrzej Warzynski     // This returns a non-constant.
2374e6c66ef5SAndrzej Warzynski     FlatSymbolRefAttr symAttr = mlir::SymbolRefAttr::get(
2375e6c66ef5SAndrzej Warzynski         field.getContext(), getOffsetMethodName(recTy, field.field_id()));
2376e6c66ef5SAndrzej Warzynski     NamedAttribute callAttr = rewriter.getNamedAttr("callee", symAttr);
2377e6c66ef5SAndrzej Warzynski     NamedAttribute fieldAttr = rewriter.getNamedAttr(
2378e6c66ef5SAndrzej Warzynski         "field", mlir::IntegerAttr::get(lowerTy().indexType(), index));
2379e6c66ef5SAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
2380e6c66ef5SAndrzej Warzynski         field, lowerTy().offsetType(), adaptor.getOperands(),
2381e6c66ef5SAndrzej Warzynski         llvm::ArrayRef<mlir::NamedAttribute>{callAttr, fieldAttr});
2382e6c66ef5SAndrzej Warzynski     return success();
2383e6c66ef5SAndrzej Warzynski   }
2384e6c66ef5SAndrzej Warzynski 
2385e6c66ef5SAndrzej Warzynski   // Re-Construct the name of the compiler generated method that calculates the
2386e6c66ef5SAndrzej Warzynski   // offset
2387e6c66ef5SAndrzej Warzynski   inline static std::string getOffsetMethodName(fir::RecordType recTy,
2388e6c66ef5SAndrzej Warzynski                                                 llvm::StringRef field) {
2389e6c66ef5SAndrzej Warzynski     return recTy.getName().str() + "P." + field.str() + ".offset";
2390e6c66ef5SAndrzej Warzynski   }
2391e6c66ef5SAndrzej Warzynski };
2392e6c66ef5SAndrzej Warzynski 
2393044d5b5dSValentin Clement } // namespace
2394044d5b5dSValentin Clement 
2395044d5b5dSValentin Clement namespace {
2396044d5b5dSValentin Clement /// Convert FIR dialect to LLVM dialect
2397044d5b5dSValentin Clement ///
2398044d5b5dSValentin Clement /// This pass lowers all FIR dialect operations to LLVM IR dialect. An
2399044d5b5dSValentin Clement /// MLIR pass is used to lower residual Std dialect to LLVM IR dialect.
2400044d5b5dSValentin Clement ///
2401044d5b5dSValentin Clement /// This pass is not complete yet. We are upstreaming it in small patches.
2402044d5b5dSValentin Clement class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> {
2403044d5b5dSValentin Clement public:
2404044d5b5dSValentin Clement   mlir::ModuleOp getModule() { return getOperation(); }
2405044d5b5dSValentin Clement 
2406044d5b5dSValentin Clement   void runOnOperation() override final {
24077b5132daSValentin Clement     auto mod = getModule();
24087b5132daSValentin Clement     if (!forcedTargetTriple.empty()) {
24097b5132daSValentin Clement       fir::setTargetTriple(mod, forcedTargetTriple);
24107b5132daSValentin Clement     }
24117b5132daSValentin Clement 
2412044d5b5dSValentin Clement     auto *context = getModule().getContext();
2413044d5b5dSValentin Clement     fir::LLVMTypeConverter typeConverter{getModule()};
2414044d5b5dSValentin Clement     mlir::OwningRewritePatternList pattern(context);
2415df3b9810SValentin Clement     pattern.insert<
2416420ad7ceSAndrzej Warzynski         AbsentOpConversion, AddcOpConversion, AddrOfOpConversion,
24171a2ec667SValentin Clement         AllocaOpConversion, BoxAddrOpConversion, BoxCharLenOpConversion,
24181a2ec667SValentin Clement         BoxDimsOpConversion, BoxEleSizeOpConversion, BoxIsAllocOpConversion,
2419cc505c0bSKiran Chandramohan         BoxIsArrayOpConversion, BoxIsPtrOpConversion, BoxProcHostOpConversion,
2420cc505c0bSKiran Chandramohan         BoxRankOpConversion, BoxTypeDescOpConversion, CallOpConversion,
2421cc505c0bSKiran Chandramohan         CmpcOpConversion, ConstcOpConversion, ConvertOpConversion,
2422cc505c0bSKiran Chandramohan         DispatchOpConversion, DispatchTableOpConversion, DTEntryOpConversion,
2423cc505c0bSKiran Chandramohan         DivcOpConversion, EmboxOpConversion, EmboxCharOpConversion,
2424e6c66ef5SAndrzej Warzynski         EmboxProcOpConversion, ExtractValueOpConversion, FieldIndexOpConversion,
2425e6c66ef5SAndrzej Warzynski         FirEndOpConversion, HasValueOpConversion, GenTypeDescOpConversion,
2426e6c66ef5SAndrzej Warzynski         GlobalLenOpConversion, GlobalOpConversion, InsertOnRangeOpConversion,
2427cdc476abSDiana Picus         InsertValueOpConversion, IsPresentOpConversion,
2428cdc476abSDiana Picus         LenParamIndexOpConversion, LoadOpConversion, NegcOpConversion,
2429cdc476abSDiana Picus         NoReassocOpConversion, MulcOpConversion, SelectCaseOpConversion,
2430cdc476abSDiana Picus         SelectOpConversion, SelectRankOpConversion, SelectTypeOpConversion,
2431cdc476abSDiana Picus         ShapeOpConversion, ShapeShiftOpConversion, ShiftOpConversion,
2432cdc476abSDiana Picus         SliceOpConversion, StoreOpConversion, StringLitOpConversion,
2433cdc476abSDiana Picus         SubcOpConversion, UnboxCharOpConversion, UnboxProcOpConversion,
2434*1f551032SValentin Clement         UndefOpConversion, UnreachableOpConversion, XEmboxOpConversion,
2435*1f551032SValentin Clement         ZeroOpConversion>(typeConverter);
2436044d5b5dSValentin Clement     mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern);
2437044d5b5dSValentin Clement     mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter,
2438044d5b5dSValentin Clement                                                             pattern);
2439044d5b5dSValentin Clement     mlir::ConversionTarget target{*context};
2440044d5b5dSValentin Clement     target.addLegalDialect<mlir::LLVM::LLVMDialect>();
2441044d5b5dSValentin Clement 
2442044d5b5dSValentin Clement     // required NOPs for applying a full conversion
2443044d5b5dSValentin Clement     target.addLegalOp<mlir::ModuleOp>();
2444044d5b5dSValentin Clement 
2445044d5b5dSValentin Clement     // apply the patterns
2446044d5b5dSValentin Clement     if (mlir::failed(mlir::applyFullConversion(getModule(), target,
2447044d5b5dSValentin Clement                                                std::move(pattern)))) {
2448044d5b5dSValentin Clement       signalPassFailure();
2449044d5b5dSValentin Clement     }
2450044d5b5dSValentin Clement   }
2451044d5b5dSValentin Clement };
2452044d5b5dSValentin Clement } // namespace
2453044d5b5dSValentin Clement 
2454044d5b5dSValentin Clement std::unique_ptr<mlir::Pass> fir::createFIRToLLVMPass() {
2455044d5b5dSValentin Clement   return std::make_unique<FIRToLLVMLowering>();
2456044d5b5dSValentin Clement }
2457