1044d5b5dSValentin Clement //===-- CodeGen.cpp -- bridge to lower to LLVM ----------------------------===//
2044d5b5dSValentin Clement //
3044d5b5dSValentin Clement // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4044d5b5dSValentin Clement // See https://llvm.org/LICENSE.txt for license information.
5044d5b5dSValentin Clement // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6044d5b5dSValentin Clement //
7044d5b5dSValentin Clement //===----------------------------------------------------------------------===//
8044d5b5dSValentin Clement //
9044d5b5dSValentin Clement // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10044d5b5dSValentin Clement //
11044d5b5dSValentin Clement //===----------------------------------------------------------------------===//
12044d5b5dSValentin Clement 
13044d5b5dSValentin Clement #include "flang/Optimizer/CodeGen/CodeGen.h"
14044d5b5dSValentin Clement #include "PassDetail.h"
15b6e44ecdSValentin Clement #include "flang/ISO_Fortran_binding.h"
1639f4ef81SValentin Clement #include "flang/Optimizer/Dialect/FIRAttr.h"
17044d5b5dSValentin Clement #include "flang/Optimizer/Dialect/FIROps.h"
18af6ee580SValentin Clement #include "flang/Optimizer/Support/TypeCode.h"
19044d5b5dSValentin Clement #include "mlir/Conversion/ArithmeticToLLVM/ArithmeticToLLVM.h"
20044d5b5dSValentin Clement #include "mlir/Conversion/LLVMCommon/Pattern.h"
21044d5b5dSValentin Clement #include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h"
22044d5b5dSValentin Clement #include "mlir/IR/BuiltinTypes.h"
233ae8e442SValentin Clement #include "mlir/IR/Matchers.h"
24044d5b5dSValentin Clement #include "mlir/Pass/Pass.h"
25044d5b5dSValentin Clement #include "llvm/ADT/ArrayRef.h"
26044d5b5dSValentin Clement 
27044d5b5dSValentin Clement #define DEBUG_TYPE "flang-codegen"
28044d5b5dSValentin Clement 
29044d5b5dSValentin Clement // fir::LLVMTypeConverter for converting to LLVM IR dialect types.
30044d5b5dSValentin Clement #include "TypeConverter.h"
31044d5b5dSValentin Clement 
32af6ee580SValentin Clement // TODO: This should really be recovered from the specified target.
33af6ee580SValentin Clement static constexpr unsigned defaultAlign = 8;
34af6ee580SValentin Clement 
35b6e44ecdSValentin Clement /// `fir.box` attribute values as defined for CFI_attribute_t in
36b6e44ecdSValentin Clement /// flang/ISO_Fortran_binding.h.
37b6e44ecdSValentin Clement static constexpr unsigned kAttrPointer = CFI_attribute_pointer;
38b6e44ecdSValentin Clement static constexpr unsigned kAttrAllocatable = CFI_attribute_allocatable;
39b6e44ecdSValentin Clement 
401e6d9c06SDiana Picus static mlir::LLVM::ConstantOp
411e6d9c06SDiana Picus genConstantIndex(mlir::Location loc, mlir::Type ity,
421e6d9c06SDiana Picus                  mlir::ConversionPatternRewriter &rewriter,
431e6d9c06SDiana Picus                  std::int64_t offset) {
441e6d9c06SDiana Picus   auto cattr = rewriter.getI64IntegerAttr(offset);
451e6d9c06SDiana Picus   return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr);
461e6d9c06SDiana Picus }
471e6d9c06SDiana Picus 
4839f4ef81SValentin Clement static Block *createBlock(mlir::ConversionPatternRewriter &rewriter,
4939f4ef81SValentin Clement                           mlir::Block *insertBefore) {
5039f4ef81SValentin Clement   assert(insertBefore && "expected valid insertion block");
5139f4ef81SValentin Clement   return rewriter.createBlock(insertBefore->getParent(),
5239f4ef81SValentin Clement                               mlir::Region::iterator(insertBefore));
5339f4ef81SValentin Clement }
5439f4ef81SValentin Clement 
55044d5b5dSValentin Clement namespace {
56044d5b5dSValentin Clement /// FIR conversion pattern template
57044d5b5dSValentin Clement template <typename FromOp>
58044d5b5dSValentin Clement class FIROpConversion : public mlir::ConvertOpToLLVMPattern<FromOp> {
59044d5b5dSValentin Clement public:
60044d5b5dSValentin Clement   explicit FIROpConversion(fir::LLVMTypeConverter &lowering)
61044d5b5dSValentin Clement       : mlir::ConvertOpToLLVMPattern<FromOp>(lowering) {}
62044d5b5dSValentin Clement 
63044d5b5dSValentin Clement protected:
64044d5b5dSValentin Clement   mlir::Type convertType(mlir::Type ty) const {
65044d5b5dSValentin Clement     return lowerTy().convertType(ty);
66044d5b5dSValentin Clement   }
67044d5b5dSValentin Clement 
68df3b9810SValentin Clement   mlir::LLVM::ConstantOp
69af6ee580SValentin Clement   genI32Constant(mlir::Location loc, mlir::ConversionPatternRewriter &rewriter,
70af6ee580SValentin Clement                  int value) const {
71af6ee580SValentin Clement     mlir::Type i32Ty = rewriter.getI32Type();
72af6ee580SValentin Clement     mlir::IntegerAttr attr = rewriter.getI32IntegerAttr(value);
73af6ee580SValentin Clement     return rewriter.create<mlir::LLVM::ConstantOp>(loc, i32Ty, attr);
74af6ee580SValentin Clement   }
75af6ee580SValentin Clement 
76af6ee580SValentin Clement   mlir::LLVM::ConstantOp
77df3b9810SValentin Clement   genConstantOffset(mlir::Location loc,
78df3b9810SValentin Clement                     mlir::ConversionPatternRewriter &rewriter,
79df3b9810SValentin Clement                     int offset) const {
80af6ee580SValentin Clement     mlir::Type ity = lowerTy().offsetType();
81af6ee580SValentin Clement     mlir::IntegerAttr cattr = rewriter.getI32IntegerAttr(offset);
82df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr);
83df3b9810SValentin Clement   }
84df3b9810SValentin Clement 
85b6e44ecdSValentin Clement   /// Construct code sequence to extract the specifc value from a `fir.box`.
86b6e44ecdSValentin Clement   mlir::Value getValueFromBox(mlir::Location loc, mlir::Value box,
87df3b9810SValentin Clement                               mlir::Type resultTy,
88b6e44ecdSValentin Clement                               mlir::ConversionPatternRewriter &rewriter,
89b6e44ecdSValentin Clement                               unsigned boxValue) const {
90df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
91b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp cValuePos =
92b6e44ecdSValentin Clement         genConstantOffset(loc, rewriter, boxValue);
93df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(resultTy);
94df3b9810SValentin Clement     auto p = rewriter.create<mlir::LLVM::GEPOp>(
95b6e44ecdSValentin Clement         loc, pty, mlir::ValueRange{box, c0, cValuePos});
96df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, resultTy, p);
97df3b9810SValentin Clement   }
98df3b9810SValentin Clement 
99df3b9810SValentin Clement   /// Method to construct code sequence to get the triple for dimension `dim`
100df3b9810SValentin Clement   /// from a box.
101df3b9810SValentin Clement   SmallVector<mlir::Value, 3>
102df3b9810SValentin Clement   getDimsFromBox(mlir::Location loc, ArrayRef<mlir::Type> retTys,
103df3b9810SValentin Clement                  mlir::Value box, mlir::Value dim,
104df3b9810SValentin Clement                  mlir::ConversionPatternRewriter &rewriter) const {
105df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
106df3b9810SValentin Clement     mlir::LLVM::ConstantOp cDims =
107df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kDimsPosInBox);
108df3b9810SValentin Clement     mlir::LLVM::LoadOp l0 =
109df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 0, retTys[0], rewriter);
110df3b9810SValentin Clement     mlir::LLVM::LoadOp l1 =
111df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 1, retTys[1], rewriter);
112df3b9810SValentin Clement     mlir::LLVM::LoadOp l2 =
113df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 2, retTys[2], rewriter);
114df3b9810SValentin Clement     return {l0.getResult(), l1.getResult(), l2.getResult()};
115df3b9810SValentin Clement   }
116df3b9810SValentin Clement 
117df3b9810SValentin Clement   mlir::LLVM::LoadOp
118df3b9810SValentin Clement   loadFromOffset(mlir::Location loc, mlir::Value a, mlir::LLVM::ConstantOp c0,
119df3b9810SValentin Clement                  mlir::LLVM::ConstantOp cDims, mlir::Value dim, int off,
120df3b9810SValentin Clement                  mlir::Type ty,
121df3b9810SValentin Clement                  mlir::ConversionPatternRewriter &rewriter) const {
122df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
123df3b9810SValentin Clement     mlir::LLVM::ConstantOp c = genConstantOffset(loc, rewriter, off);
124df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, a, c0, cDims, dim, c);
125df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
126df3b9810SValentin Clement   }
127df3b9810SValentin Clement 
128df3b9810SValentin Clement   /// Read base address from a fir.box. Returned address has type ty.
129df3b9810SValentin Clement   mlir::Value
130df3b9810SValentin Clement   loadBaseAddrFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box,
131df3b9810SValentin Clement                       mlir::ConversionPatternRewriter &rewriter) const {
132df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
133df3b9810SValentin Clement     mlir::LLVM::ConstantOp cAddr =
134df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kAddrPosInBox);
135df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
136df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cAddr);
137df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
138df3b9810SValentin Clement   }
139df3b9810SValentin Clement 
140df3b9810SValentin Clement   mlir::Value
141df3b9810SValentin Clement   loadElementSizeFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box,
142df3b9810SValentin Clement                          mlir::ConversionPatternRewriter &rewriter) const {
143df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
144df3b9810SValentin Clement     mlir::LLVM::ConstantOp cElemLen =
145df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kElemLenPosInBox);
146df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
147df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cElemLen);
148df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
149df3b9810SValentin Clement   }
150df3b9810SValentin Clement 
151b6e44ecdSValentin Clement   // Load the attribute from the \p box and perform a check against \p maskValue
152b6e44ecdSValentin Clement   // The final comparison is implemented as `(attribute & maskValue) != 0`.
153b6e44ecdSValentin Clement   mlir::Value genBoxAttributeCheck(mlir::Location loc, mlir::Value box,
154b6e44ecdSValentin Clement                                    mlir::ConversionPatternRewriter &rewriter,
155b6e44ecdSValentin Clement                                    unsigned maskValue) const {
156b6e44ecdSValentin Clement     mlir::Type attrTy = rewriter.getI32Type();
157b6e44ecdSValentin Clement     mlir::Value attribute =
158b6e44ecdSValentin Clement         getValueFromBox(loc, box, attrTy, rewriter, kAttributePosInBox);
159b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp attrMask =
160b6e44ecdSValentin Clement         genConstantOffset(loc, rewriter, maskValue);
161b6e44ecdSValentin Clement     auto maskRes =
162b6e44ecdSValentin Clement         rewriter.create<mlir::LLVM::AndOp>(loc, attrTy, attribute, attrMask);
163b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
164b6e44ecdSValentin Clement     return rewriter.create<mlir::LLVM::ICmpOp>(
165b6e44ecdSValentin Clement         loc, mlir::LLVM::ICmpPredicate::ne, maskRes, c0);
166b6e44ecdSValentin Clement   }
167b6e44ecdSValentin Clement 
168af6ee580SValentin Clement   // Get the element type given an LLVM type that is of the form
169af6ee580SValentin Clement   // [llvm.ptr](array|struct|vector)+ and the provided indexes.
170af6ee580SValentin Clement   static mlir::Type getBoxEleTy(mlir::Type type,
171af6ee580SValentin Clement                                 llvm::ArrayRef<unsigned> indexes) {
172af6ee580SValentin Clement     if (auto t = type.dyn_cast<mlir::LLVM::LLVMPointerType>())
173af6ee580SValentin Clement       type = t.getElementType();
174af6ee580SValentin Clement     for (auto i : indexes) {
175af6ee580SValentin Clement       if (auto t = type.dyn_cast<mlir::LLVM::LLVMStructType>()) {
176af6ee580SValentin Clement         assert(!t.isOpaque() && i < t.getBody().size());
177af6ee580SValentin Clement         type = t.getBody()[i];
178af6ee580SValentin Clement       } else if (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
179af6ee580SValentin Clement         type = t.getElementType();
180af6ee580SValentin Clement       } else if (auto t = type.dyn_cast<mlir::VectorType>()) {
181af6ee580SValentin Clement         type = t.getElementType();
182af6ee580SValentin Clement       } else {
183af6ee580SValentin Clement         fir::emitFatalError(mlir::UnknownLoc::get(type.getContext()),
184af6ee580SValentin Clement                             "request for invalid box element type");
185af6ee580SValentin Clement       }
186af6ee580SValentin Clement     }
187af6ee580SValentin Clement     return type;
188af6ee580SValentin Clement   }
189af6ee580SValentin Clement 
190df3b9810SValentin Clement   template <typename... ARGS>
191df3b9810SValentin Clement   mlir::LLVM::GEPOp genGEP(mlir::Location loc, mlir::Type ty,
192df3b9810SValentin Clement                            mlir::ConversionPatternRewriter &rewriter,
193df3b9810SValentin Clement                            mlir::Value base, ARGS... args) const {
194df3b9810SValentin Clement     SmallVector<mlir::Value> cv{args...};
195df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::GEPOp>(loc, ty, base, cv);
196df3b9810SValentin Clement   }
197df3b9810SValentin Clement 
1981e6d9c06SDiana Picus   /// Perform an extension or truncation as needed on an integer value. Lowering
1991e6d9c06SDiana Picus   /// to the specific target may involve some sign-extending or truncation of
2001e6d9c06SDiana Picus   /// values, particularly to fit them from abstract box types to the
2011e6d9c06SDiana Picus   /// appropriate reified structures.
2021e6d9c06SDiana Picus   mlir::Value integerCast(mlir::Location loc,
2031e6d9c06SDiana Picus                           mlir::ConversionPatternRewriter &rewriter,
2041e6d9c06SDiana Picus                           mlir::Type ty, mlir::Value val) const {
2051e6d9c06SDiana Picus     auto valTy = val.getType();
2061e6d9c06SDiana Picus     // If the value was not yet lowered, lower its type so that it can
2071e6d9c06SDiana Picus     // be used in getPrimitiveTypeSizeInBits.
2081e6d9c06SDiana Picus     if (!valTy.isa<mlir::IntegerType>())
2091e6d9c06SDiana Picus       valTy = convertType(valTy);
2101e6d9c06SDiana Picus     auto toSize = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
2111e6d9c06SDiana Picus     auto fromSize = mlir::LLVM::getPrimitiveTypeSizeInBits(valTy);
2121e6d9c06SDiana Picus     if (toSize < fromSize)
2131e6d9c06SDiana Picus       return rewriter.create<mlir::LLVM::TruncOp>(loc, ty, val);
2141e6d9c06SDiana Picus     if (toSize > fromSize)
2151e6d9c06SDiana Picus       return rewriter.create<mlir::LLVM::SExtOp>(loc, ty, val);
2161e6d9c06SDiana Picus     return val;
2171e6d9c06SDiana Picus   }
2181e6d9c06SDiana Picus 
219044d5b5dSValentin Clement   fir::LLVMTypeConverter &lowerTy() const {
220044d5b5dSValentin Clement     return *static_cast<fir::LLVMTypeConverter *>(this->getTypeConverter());
221044d5b5dSValentin Clement   }
222044d5b5dSValentin Clement };
223044d5b5dSValentin Clement 
2243ae8e442SValentin Clement /// FIR conversion pattern template
2253ae8e442SValentin Clement template <typename FromOp>
2263ae8e442SValentin Clement class FIROpAndTypeConversion : public FIROpConversion<FromOp> {
2273ae8e442SValentin Clement public:
2283ae8e442SValentin Clement   using FIROpConversion<FromOp>::FIROpConversion;
2293ae8e442SValentin Clement   using OpAdaptor = typename FromOp::Adaptor;
2303ae8e442SValentin Clement 
2313ae8e442SValentin Clement   mlir::LogicalResult
2323ae8e442SValentin Clement   matchAndRewrite(FromOp op, OpAdaptor adaptor,
2333ae8e442SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const final {
2343ae8e442SValentin Clement     mlir::Type ty = this->convertType(op.getType());
2353ae8e442SValentin Clement     return doRewrite(op, ty, adaptor, rewriter);
2363ae8e442SValentin Clement   }
2373ae8e442SValentin Clement 
2383ae8e442SValentin Clement   virtual mlir::LogicalResult
2393ae8e442SValentin Clement   doRewrite(FromOp addr, mlir::Type ty, OpAdaptor adaptor,
2403ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const = 0;
2413ae8e442SValentin Clement };
2423ae8e442SValentin Clement 
243420ad7ceSAndrzej Warzynski /// Create value signaling an absent optional argument in a call, e.g.
244420ad7ceSAndrzej Warzynski /// `fir.absent !fir.ref<i64>` -->  `llvm.mlir.null : !llvm.ptr<i64>`
245420ad7ceSAndrzej Warzynski struct AbsentOpConversion : public FIROpConversion<fir::AbsentOp> {
246420ad7ceSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
247420ad7ceSAndrzej Warzynski 
248420ad7ceSAndrzej Warzynski   mlir::LogicalResult
249420ad7ceSAndrzej Warzynski   matchAndRewrite(fir::AbsentOp absent, OpAdaptor,
250420ad7ceSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
251420ad7ceSAndrzej Warzynski     mlir::Type ty = convertType(absent.getType());
252420ad7ceSAndrzej Warzynski     mlir::Location loc = absent.getLoc();
253420ad7ceSAndrzej Warzynski 
254420ad7ceSAndrzej Warzynski     if (absent.getType().isa<fir::BoxCharType>()) {
255420ad7ceSAndrzej Warzynski       auto structTy = ty.cast<mlir::LLVM::LLVMStructType>();
256420ad7ceSAndrzej Warzynski       assert(!structTy.isOpaque() && !structTy.getBody().empty());
257420ad7ceSAndrzej Warzynski       auto undefStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
258420ad7ceSAndrzej Warzynski       auto nullField =
259420ad7ceSAndrzej Warzynski           rewriter.create<mlir::LLVM::NullOp>(loc, structTy.getBody()[0]);
260420ad7ceSAndrzej Warzynski       mlir::MLIRContext *ctx = absent.getContext();
261420ad7ceSAndrzej Warzynski       auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
262420ad7ceSAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
263420ad7ceSAndrzej Warzynski           absent, ty, undefStruct, nullField, c0);
264420ad7ceSAndrzej Warzynski     } else {
265420ad7ceSAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(absent, ty);
266420ad7ceSAndrzej Warzynski     }
267420ad7ceSAndrzej Warzynski     return success();
268420ad7ceSAndrzej Warzynski   }
269420ad7ceSAndrzej Warzynski };
270420ad7ceSAndrzej Warzynski 
2710c4a7a52SValentin Clement // Lower `fir.address_of` operation to `llvm.address_of` operation.
272044d5b5dSValentin Clement struct AddrOfOpConversion : public FIROpConversion<fir::AddrOfOp> {
273044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
274044d5b5dSValentin Clement 
275044d5b5dSValentin Clement   mlir::LogicalResult
276044d5b5dSValentin Clement   matchAndRewrite(fir::AddrOfOp addr, OpAdaptor adaptor,
277044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
278044d5b5dSValentin Clement     auto ty = convertType(addr.getType());
279044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::AddressOfOp>(
280044d5b5dSValentin Clement         addr, ty, addr.symbol().getRootReference().getValue());
281044d5b5dSValentin Clement     return success();
282044d5b5dSValentin Clement   }
283044d5b5dSValentin Clement };
2841e6d9c06SDiana Picus } // namespace
2851e6d9c06SDiana Picus 
2861e6d9c06SDiana Picus /// Lookup the function to compute the memory size of this parametric derived
2871e6d9c06SDiana Picus /// type. The size of the object may depend on the LEN type parameters of the
2881e6d9c06SDiana Picus /// derived type.
2891e6d9c06SDiana Picus static mlir::LLVM::LLVMFuncOp
2901e6d9c06SDiana Picus getDependentTypeMemSizeFn(fir::RecordType recTy, fir::AllocaOp op,
2911e6d9c06SDiana Picus                           mlir::ConversionPatternRewriter &rewriter) {
2921e6d9c06SDiana Picus   auto module = op->getParentOfType<mlir::ModuleOp>();
2931e6d9c06SDiana Picus   std::string name = recTy.getName().str() + "P.mem.size";
2941e6d9c06SDiana Picus   return module.lookupSymbol<mlir::LLVM::LLVMFuncOp>(name);
2951e6d9c06SDiana Picus }
2961e6d9c06SDiana Picus 
2971e6d9c06SDiana Picus namespace {
2981e6d9c06SDiana Picus /// convert to LLVM IR dialect `alloca`
2991e6d9c06SDiana Picus struct AllocaOpConversion : public FIROpConversion<fir::AllocaOp> {
3001e6d9c06SDiana Picus   using FIROpConversion::FIROpConversion;
3011e6d9c06SDiana Picus 
3021e6d9c06SDiana Picus   mlir::LogicalResult
3031e6d9c06SDiana Picus   matchAndRewrite(fir::AllocaOp alloc, OpAdaptor adaptor,
3041e6d9c06SDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
3051e6d9c06SDiana Picus     mlir::ValueRange operands = adaptor.getOperands();
3061e6d9c06SDiana Picus     auto loc = alloc.getLoc();
3071e6d9c06SDiana Picus     mlir::Type ity = lowerTy().indexType();
3081e6d9c06SDiana Picus     unsigned i = 0;
3091e6d9c06SDiana Picus     mlir::Value size = genConstantIndex(loc, ity, rewriter, 1).getResult();
3101e6d9c06SDiana Picus     mlir::Type ty = convertType(alloc.getType());
3111e6d9c06SDiana Picus     mlir::Type resultTy = ty;
3121e6d9c06SDiana Picus     if (alloc.hasLenParams()) {
3131e6d9c06SDiana Picus       unsigned end = alloc.numLenParams();
3141e6d9c06SDiana Picus       llvm::SmallVector<mlir::Value> lenParams;
3151e6d9c06SDiana Picus       for (; i < end; ++i)
3161e6d9c06SDiana Picus         lenParams.push_back(operands[i]);
3171e6d9c06SDiana Picus       mlir::Type scalarType = fir::unwrapSequenceType(alloc.getInType());
3181e6d9c06SDiana Picus       if (auto chrTy = scalarType.dyn_cast<fir::CharacterType>()) {
3191e6d9c06SDiana Picus         fir::CharacterType rawCharTy = fir::CharacterType::getUnknownLen(
3201e6d9c06SDiana Picus             chrTy.getContext(), chrTy.getFKind());
3211e6d9c06SDiana Picus         ty = mlir::LLVM::LLVMPointerType::get(convertType(rawCharTy));
3221e6d9c06SDiana Picus         assert(end == 1);
3231e6d9c06SDiana Picus         size = integerCast(loc, rewriter, ity, lenParams[0]);
3241e6d9c06SDiana Picus       } else if (auto recTy = scalarType.dyn_cast<fir::RecordType>()) {
3251e6d9c06SDiana Picus         mlir::LLVM::LLVMFuncOp memSizeFn =
3261e6d9c06SDiana Picus             getDependentTypeMemSizeFn(recTy, alloc, rewriter);
3271e6d9c06SDiana Picus         if (!memSizeFn)
3281e6d9c06SDiana Picus           emitError(loc, "did not find allocation function");
3291e6d9c06SDiana Picus         mlir::NamedAttribute attr = rewriter.getNamedAttr(
3301e6d9c06SDiana Picus             "callee", mlir::SymbolRefAttr::get(memSizeFn));
3311e6d9c06SDiana Picus         auto call = rewriter.create<mlir::LLVM::CallOp>(
3321e6d9c06SDiana Picus             loc, ity, lenParams, llvm::ArrayRef<mlir::NamedAttribute>{attr});
3331e6d9c06SDiana Picus         size = call.getResult(0);
3341e6d9c06SDiana Picus         ty = mlir::LLVM::LLVMPointerType::get(
3351e6d9c06SDiana Picus             mlir::IntegerType::get(alloc.getContext(), 8));
3361e6d9c06SDiana Picus       } else {
3371e6d9c06SDiana Picus         return emitError(loc, "unexpected type ")
3381e6d9c06SDiana Picus                << scalarType << " with type parameters";
3391e6d9c06SDiana Picus       }
3401e6d9c06SDiana Picus     }
3411e6d9c06SDiana Picus     if (alloc.hasShapeOperands()) {
3421e6d9c06SDiana Picus       mlir::Type allocEleTy = fir::unwrapRefType(alloc.getType());
3431e6d9c06SDiana Picus       // Scale the size by constant factors encoded in the array type.
3441e6d9c06SDiana Picus       if (auto seqTy = allocEleTy.dyn_cast<fir::SequenceType>()) {
3451e6d9c06SDiana Picus         fir::SequenceType::Extent constSize = 1;
3461e6d9c06SDiana Picus         for (auto extent : seqTy.getShape())
3471e6d9c06SDiana Picus           if (extent != fir::SequenceType::getUnknownExtent())
3481e6d9c06SDiana Picus             constSize *= extent;
3491e6d9c06SDiana Picus         mlir::Value constVal{
3501e6d9c06SDiana Picus             genConstantIndex(loc, ity, rewriter, constSize).getResult()};
3511e6d9c06SDiana Picus         size = rewriter.create<mlir::LLVM::MulOp>(loc, ity, size, constVal);
3521e6d9c06SDiana Picus       }
3531e6d9c06SDiana Picus       unsigned end = operands.size();
3541e6d9c06SDiana Picus       for (; i < end; ++i)
3551e6d9c06SDiana Picus         size = rewriter.create<mlir::LLVM::MulOp>(
3561e6d9c06SDiana Picus             loc, ity, size, integerCast(loc, rewriter, ity, operands[i]));
3571e6d9c06SDiana Picus     }
3581e6d9c06SDiana Picus     if (ty == resultTy) {
3591e6d9c06SDiana Picus       // Do not emit the bitcast if ty and resultTy are the same.
3601e6d9c06SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::AllocaOp>(alloc, ty, size,
3611e6d9c06SDiana Picus                                                         alloc->getAttrs());
3621e6d9c06SDiana Picus     } else {
3631e6d9c06SDiana Picus       auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, ty, size,
3641e6d9c06SDiana Picus                                                       alloc->getAttrs());
3651e6d9c06SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(alloc, resultTy, al);
3661e6d9c06SDiana Picus     }
3671e6d9c06SDiana Picus     return success();
3681e6d9c06SDiana Picus   }
3691e6d9c06SDiana Picus };
370044d5b5dSValentin Clement 
371df3b9810SValentin Clement /// Lower `fir.box_addr` to the sequence of operations to extract the first
372df3b9810SValentin Clement /// element of the box.
373df3b9810SValentin Clement struct BoxAddrOpConversion : public FIROpConversion<fir::BoxAddrOp> {
374df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
375df3b9810SValentin Clement 
376df3b9810SValentin Clement   mlir::LogicalResult
377df3b9810SValentin Clement   matchAndRewrite(fir::BoxAddrOp boxaddr, OpAdaptor adaptor,
378df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
379df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
380df3b9810SValentin Clement     auto loc = boxaddr.getLoc();
381df3b9810SValentin Clement     mlir::Type ty = convertType(boxaddr.getType());
382df3b9810SValentin Clement     if (auto argty = boxaddr.val().getType().dyn_cast<fir::BoxType>()) {
383df3b9810SValentin Clement       rewriter.replaceOp(boxaddr, loadBaseAddrFromBox(loc, ty, a, rewriter));
384df3b9810SValentin Clement     } else {
385df3b9810SValentin Clement       auto c0attr = rewriter.getI32IntegerAttr(0);
386df3b9810SValentin Clement       auto c0 = mlir::ArrayAttr::get(boxaddr.getContext(), c0attr);
387df3b9810SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(boxaddr, ty, a,
388df3b9810SValentin Clement                                                               c0);
389df3b9810SValentin Clement     }
390df3b9810SValentin Clement     return success();
391df3b9810SValentin Clement   }
392df3b9810SValentin Clement };
393df3b9810SValentin Clement 
394df3b9810SValentin Clement /// Lower `fir.box_dims` to a sequence of operations to extract the requested
395df3b9810SValentin Clement /// dimension infomartion from the boxed value.
396df3b9810SValentin Clement /// Result in a triple set of GEPs and loads.
397df3b9810SValentin Clement struct BoxDimsOpConversion : public FIROpConversion<fir::BoxDimsOp> {
398df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
399df3b9810SValentin Clement 
400df3b9810SValentin Clement   mlir::LogicalResult
401df3b9810SValentin Clement   matchAndRewrite(fir::BoxDimsOp boxdims, OpAdaptor adaptor,
402df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
403df3b9810SValentin Clement     SmallVector<mlir::Type, 3> resultTypes = {
404df3b9810SValentin Clement         convertType(boxdims.getResult(0).getType()),
405df3b9810SValentin Clement         convertType(boxdims.getResult(1).getType()),
406df3b9810SValentin Clement         convertType(boxdims.getResult(2).getType()),
407df3b9810SValentin Clement     };
408df3b9810SValentin Clement     auto results =
409df3b9810SValentin Clement         getDimsFromBox(boxdims.getLoc(), resultTypes, adaptor.getOperands()[0],
410df3b9810SValentin Clement                        adaptor.getOperands()[1], rewriter);
411df3b9810SValentin Clement     rewriter.replaceOp(boxdims, results);
412df3b9810SValentin Clement     return success();
413df3b9810SValentin Clement   }
414df3b9810SValentin Clement };
415df3b9810SValentin Clement 
416df3b9810SValentin Clement /// Lower `fir.box_elesize` to a sequence of operations ro extract the size of
417df3b9810SValentin Clement /// an element in the boxed value.
418df3b9810SValentin Clement struct BoxEleSizeOpConversion : public FIROpConversion<fir::BoxEleSizeOp> {
419df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
420df3b9810SValentin Clement 
421df3b9810SValentin Clement   mlir::LogicalResult
422df3b9810SValentin Clement   matchAndRewrite(fir::BoxEleSizeOp boxelesz, OpAdaptor adaptor,
423df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
424df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
425df3b9810SValentin Clement     auto loc = boxelesz.getLoc();
426df3b9810SValentin Clement     auto ty = convertType(boxelesz.getType());
427b6e44ecdSValentin Clement     auto elemSize = getValueFromBox(loc, a, ty, rewriter, kElemLenPosInBox);
428b6e44ecdSValentin Clement     rewriter.replaceOp(boxelesz, elemSize);
429b6e44ecdSValentin Clement     return success();
430b6e44ecdSValentin Clement   }
431b6e44ecdSValentin Clement };
432b6e44ecdSValentin Clement 
433b6e44ecdSValentin Clement /// Lower `fir.box_isalloc` to a sequence of operations to determine if the
434b6e44ecdSValentin Clement /// boxed value was from an ALLOCATABLE entity.
435b6e44ecdSValentin Clement struct BoxIsAllocOpConversion : public FIROpConversion<fir::BoxIsAllocOp> {
436b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
437b6e44ecdSValentin Clement 
438b6e44ecdSValentin Clement   mlir::LogicalResult
439b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsAllocOp boxisalloc, OpAdaptor adaptor,
440b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
441b6e44ecdSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
442b6e44ecdSValentin Clement     auto loc = boxisalloc.getLoc();
443b6e44ecdSValentin Clement     mlir::Value check =
444b6e44ecdSValentin Clement         genBoxAttributeCheck(loc, box, rewriter, kAttrAllocatable);
445b6e44ecdSValentin Clement     rewriter.replaceOp(boxisalloc, check);
446b6e44ecdSValentin Clement     return success();
447b6e44ecdSValentin Clement   }
448b6e44ecdSValentin Clement };
449b6e44ecdSValentin Clement 
450b6e44ecdSValentin Clement /// Lower `fir.box_isarray` to a sequence of operations to determine if the
451b6e44ecdSValentin Clement /// boxed is an array.
452b6e44ecdSValentin Clement struct BoxIsArrayOpConversion : public FIROpConversion<fir::BoxIsArrayOp> {
453b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
454b6e44ecdSValentin Clement 
455b6e44ecdSValentin Clement   mlir::LogicalResult
456b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsArrayOp boxisarray, OpAdaptor adaptor,
457b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
458b6e44ecdSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
459b6e44ecdSValentin Clement     auto loc = boxisarray.getLoc();
460b6e44ecdSValentin Clement     auto rank =
461b6e44ecdSValentin Clement         getValueFromBox(loc, a, rewriter.getI32Type(), rewriter, kRankPosInBox);
462b6e44ecdSValentin Clement     auto c0 = genConstantOffset(loc, rewriter, 0);
463b6e44ecdSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
464b6e44ecdSValentin Clement         boxisarray, mlir::LLVM::ICmpPredicate::ne, rank, c0);
465b6e44ecdSValentin Clement     return success();
466b6e44ecdSValentin Clement   }
467b6e44ecdSValentin Clement };
468b6e44ecdSValentin Clement 
469b6e44ecdSValentin Clement /// Lower `fir.box_isptr` to a sequence of operations to determined if the
470b6e44ecdSValentin Clement /// boxed value was from a POINTER entity.
471b6e44ecdSValentin Clement struct BoxIsPtrOpConversion : public FIROpConversion<fir::BoxIsPtrOp> {
472b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
473b6e44ecdSValentin Clement 
474b6e44ecdSValentin Clement   mlir::LogicalResult
475b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsPtrOp boxisptr, OpAdaptor adaptor,
476b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
477b6e44ecdSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
478b6e44ecdSValentin Clement     auto loc = boxisptr.getLoc();
479b6e44ecdSValentin Clement     mlir::Value check = genBoxAttributeCheck(loc, box, rewriter, kAttrPointer);
480b6e44ecdSValentin Clement     rewriter.replaceOp(boxisptr, check);
481df3b9810SValentin Clement     return success();
482df3b9810SValentin Clement   }
483df3b9810SValentin Clement };
484df3b9810SValentin Clement 
485df3b9810SValentin Clement /// Lower `fir.box_rank` to the sequence of operation to extract the rank from
486df3b9810SValentin Clement /// the box.
487df3b9810SValentin Clement struct BoxRankOpConversion : public FIROpConversion<fir::BoxRankOp> {
488df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
489df3b9810SValentin Clement 
490df3b9810SValentin Clement   mlir::LogicalResult
491df3b9810SValentin Clement   matchAndRewrite(fir::BoxRankOp boxrank, OpAdaptor adaptor,
492df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
493df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
494df3b9810SValentin Clement     auto loc = boxrank.getLoc();
495df3b9810SValentin Clement     mlir::Type ty = convertType(boxrank.getType());
496b6e44ecdSValentin Clement     auto result = getValueFromBox(loc, a, ty, rewriter, kRankPosInBox);
497df3b9810SValentin Clement     rewriter.replaceOp(boxrank, result);
498df3b9810SValentin Clement     return success();
499df3b9810SValentin Clement   }
500df3b9810SValentin Clement };
501df3b9810SValentin Clement 
5021a2ec667SValentin Clement /// Lower `fir.string_lit` to LLVM IR dialect operation.
5031a2ec667SValentin Clement struct StringLitOpConversion : public FIROpConversion<fir::StringLitOp> {
5041a2ec667SValentin Clement   using FIROpConversion::FIROpConversion;
5051a2ec667SValentin Clement 
5061a2ec667SValentin Clement   mlir::LogicalResult
5071a2ec667SValentin Clement   matchAndRewrite(fir::StringLitOp constop, OpAdaptor adaptor,
5081a2ec667SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
5091a2ec667SValentin Clement     auto ty = convertType(constop.getType());
5101a2ec667SValentin Clement     auto attr = constop.getValue();
5111a2ec667SValentin Clement     if (attr.isa<mlir::StringAttr>()) {
5121a2ec667SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(constop, ty, attr);
5131a2ec667SValentin Clement       return success();
5141a2ec667SValentin Clement     }
5151a2ec667SValentin Clement 
5161a2ec667SValentin Clement     auto arr = attr.cast<mlir::ArrayAttr>();
5171a2ec667SValentin Clement     auto charTy = constop.getType().cast<fir::CharacterType>();
5181a2ec667SValentin Clement     unsigned bits = lowerTy().characterBitsize(charTy);
5191a2ec667SValentin Clement     mlir::Type intTy = rewriter.getIntegerType(bits);
5201a2ec667SValentin Clement     auto attrs = llvm::map_range(
5211a2ec667SValentin Clement         arr.getValue(), [intTy, bits](mlir::Attribute attr) -> Attribute {
5221a2ec667SValentin Clement           return mlir::IntegerAttr::get(
5231a2ec667SValentin Clement               intTy,
5241a2ec667SValentin Clement               attr.cast<mlir::IntegerAttr>().getValue().sextOrTrunc(bits));
5251a2ec667SValentin Clement         });
5261a2ec667SValentin Clement     mlir::Type vecType = mlir::VectorType::get(arr.size(), intTy);
5271a2ec667SValentin Clement     auto denseAttr = mlir::DenseElementsAttr::get(
5281a2ec667SValentin Clement         vecType.cast<mlir::ShapedType>(), llvm::to_vector<8>(attrs));
5291a2ec667SValentin Clement     rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(constop, ty,
5301a2ec667SValentin Clement                                                          denseAttr);
5311a2ec667SValentin Clement     return success();
5321a2ec667SValentin Clement   }
5331a2ec667SValentin Clement };
5341a2ec667SValentin Clement 
535cc505c0bSKiran Chandramohan /// Lower `fir.boxproc_host` operation. Extracts the host pointer from the
536cc505c0bSKiran Chandramohan /// boxproc.
537cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
538cc505c0bSKiran Chandramohan struct BoxProcHostOpConversion : public FIROpConversion<fir::BoxProcHostOp> {
539cc505c0bSKiran Chandramohan   using FIROpConversion::FIROpConversion;
540cc505c0bSKiran Chandramohan 
541cc505c0bSKiran Chandramohan   mlir::LogicalResult
542cc505c0bSKiran Chandramohan   matchAndRewrite(fir::BoxProcHostOp boxprochost, OpAdaptor adaptor,
543cc505c0bSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
544cc505c0bSKiran Chandramohan     return rewriter.notifyMatchFailure(
545cc505c0bSKiran Chandramohan         boxprochost, "fir.boxproc_host codegen is not implemented yet");
546cc505c0bSKiran Chandramohan   }
547cc505c0bSKiran Chandramohan };
548cc505c0bSKiran Chandramohan 
549e38ef2ffSValentin Clement /// Lower `fir.box_tdesc` to the sequence of operations to extract the type
550e38ef2ffSValentin Clement /// descriptor from the box.
551e38ef2ffSValentin Clement struct BoxTypeDescOpConversion : public FIROpConversion<fir::BoxTypeDescOp> {
552e38ef2ffSValentin Clement   using FIROpConversion::FIROpConversion;
553e38ef2ffSValentin Clement 
554e38ef2ffSValentin Clement   mlir::LogicalResult
555e38ef2ffSValentin Clement   matchAndRewrite(fir::BoxTypeDescOp boxtypedesc, OpAdaptor adaptor,
556e38ef2ffSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
557e38ef2ffSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
558e38ef2ffSValentin Clement     auto loc = boxtypedesc.getLoc();
559e38ef2ffSValentin Clement     mlir::Type typeTy =
560e38ef2ffSValentin Clement         fir::getDescFieldTypeModel<kTypePosInBox>()(boxtypedesc.getContext());
561e38ef2ffSValentin Clement     auto result = getValueFromBox(loc, box, typeTy, rewriter, kTypePosInBox);
562e38ef2ffSValentin Clement     auto typePtrTy = mlir::LLVM::LLVMPointerType::get(typeTy);
563e38ef2ffSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(boxtypedesc, typePtrTy,
564e38ef2ffSValentin Clement                                                         result);
565e38ef2ffSValentin Clement     return success();
566e38ef2ffSValentin Clement   }
567e38ef2ffSValentin Clement };
568e38ef2ffSValentin Clement 
569ddd11b9aSAndrzej Warzynski // `fir.call` -> `llvm.call`
570ddd11b9aSAndrzej Warzynski struct CallOpConversion : public FIROpConversion<fir::CallOp> {
571ddd11b9aSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
572ddd11b9aSAndrzej Warzynski 
573ddd11b9aSAndrzej Warzynski   mlir::LogicalResult
574ddd11b9aSAndrzej Warzynski   matchAndRewrite(fir::CallOp call, OpAdaptor adaptor,
575ddd11b9aSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
576ddd11b9aSAndrzej Warzynski     SmallVector<mlir::Type> resultTys;
577ddd11b9aSAndrzej Warzynski     for (auto r : call.getResults())
578ddd11b9aSAndrzej Warzynski       resultTys.push_back(convertType(r.getType()));
579ddd11b9aSAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
580ddd11b9aSAndrzej Warzynski         call, resultTys, adaptor.getOperands(), call->getAttrs());
581ddd11b9aSAndrzej Warzynski     return success();
582ddd11b9aSAndrzej Warzynski   }
583ddd11b9aSAndrzej Warzynski };
584ddd11b9aSAndrzej Warzynski 
585092cee5fSValentin Clement static mlir::Type getComplexEleTy(mlir::Type complex) {
586092cee5fSValentin Clement   if (auto cc = complex.dyn_cast<mlir::ComplexType>())
587092cee5fSValentin Clement     return cc.getElementType();
588092cee5fSValentin Clement   return complex.cast<fir::ComplexType>().getElementType();
589092cee5fSValentin Clement }
590092cee5fSValentin Clement 
591f1dfc027SDiana Picus /// Compare complex values
592f1dfc027SDiana Picus ///
593f1dfc027SDiana Picus /// Per 10.1, the only comparisons available are .EQ. (oeq) and .NE. (une).
594f1dfc027SDiana Picus ///
595f1dfc027SDiana Picus /// For completeness, all other comparison are done on the real component only.
596f1dfc027SDiana Picus struct CmpcOpConversion : public FIROpConversion<fir::CmpcOp> {
597f1dfc027SDiana Picus   using FIROpConversion::FIROpConversion;
598f1dfc027SDiana Picus 
599f1dfc027SDiana Picus   mlir::LogicalResult
600f1dfc027SDiana Picus   matchAndRewrite(fir::CmpcOp cmp, OpAdaptor adaptor,
601f1dfc027SDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
602f1dfc027SDiana Picus     mlir::ValueRange operands = adaptor.getOperands();
603f1dfc027SDiana Picus     mlir::MLIRContext *ctxt = cmp.getContext();
604f1dfc027SDiana Picus     mlir::Type eleTy = convertType(getComplexEleTy(cmp.lhs().getType()));
605f1dfc027SDiana Picus     mlir::Type resTy = convertType(cmp.getType());
606f1dfc027SDiana Picus     mlir::Location loc = cmp.getLoc();
607f1dfc027SDiana Picus     auto pos0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0));
608f1dfc027SDiana Picus     SmallVector<mlir::Value, 2> rp{rewriter.create<mlir::LLVM::ExtractValueOp>(
609f1dfc027SDiana Picus                                        loc, eleTy, operands[0], pos0),
610f1dfc027SDiana Picus                                    rewriter.create<mlir::LLVM::ExtractValueOp>(
611f1dfc027SDiana Picus                                        loc, eleTy, operands[1], pos0)};
612f1dfc027SDiana Picus     auto rcp =
613f1dfc027SDiana Picus         rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, rp, cmp->getAttrs());
614f1dfc027SDiana Picus     auto pos1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1));
615f1dfc027SDiana Picus     SmallVector<mlir::Value, 2> ip{rewriter.create<mlir::LLVM::ExtractValueOp>(
616f1dfc027SDiana Picus                                        loc, eleTy, operands[0], pos1),
617f1dfc027SDiana Picus                                    rewriter.create<mlir::LLVM::ExtractValueOp>(
618f1dfc027SDiana Picus                                        loc, eleTy, operands[1], pos1)};
619f1dfc027SDiana Picus     auto icp =
620f1dfc027SDiana Picus         rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, ip, cmp->getAttrs());
621f1dfc027SDiana Picus     SmallVector<mlir::Value, 2> cp{rcp, icp};
622f1dfc027SDiana Picus     switch (cmp.getPredicate()) {
623f1dfc027SDiana Picus     case mlir::arith::CmpFPredicate::OEQ: // .EQ.
624f1dfc027SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(cmp, resTy, cp);
625f1dfc027SDiana Picus       break;
626f1dfc027SDiana Picus     case mlir::arith::CmpFPredicate::UNE: // .NE.
627f1dfc027SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(cmp, resTy, cp);
628f1dfc027SDiana Picus       break;
629f1dfc027SDiana Picus     default:
630f1dfc027SDiana Picus       rewriter.replaceOp(cmp, rcp.getResult());
631f1dfc027SDiana Picus       break;
632f1dfc027SDiana Picus     }
633f1dfc027SDiana Picus     return success();
634f1dfc027SDiana Picus   }
635f1dfc027SDiana Picus };
636f1dfc027SDiana Picus 
637e81d73edSDiana Picus /// Lower complex constants
638e81d73edSDiana Picus struct ConstcOpConversion : public FIROpConversion<fir::ConstcOp> {
639e81d73edSDiana Picus   using FIROpConversion::FIROpConversion;
640e81d73edSDiana Picus 
641e81d73edSDiana Picus   mlir::LogicalResult
642e81d73edSDiana Picus   matchAndRewrite(fir::ConstcOp conc, OpAdaptor,
643e81d73edSDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
644e81d73edSDiana Picus     mlir::Location loc = conc.getLoc();
645e81d73edSDiana Picus     mlir::MLIRContext *ctx = conc.getContext();
646e81d73edSDiana Picus     mlir::Type ty = convertType(conc.getType());
647e81d73edSDiana Picus     mlir::Type ety = convertType(getComplexEleTy(conc.getType()));
648e81d73edSDiana Picus     auto realFloatAttr = mlir::FloatAttr::get(ety, getValue(conc.getReal()));
649e81d73edSDiana Picus     auto realPart =
650e81d73edSDiana Picus         rewriter.create<mlir::LLVM::ConstantOp>(loc, ety, realFloatAttr);
651e81d73edSDiana Picus     auto imFloatAttr = mlir::FloatAttr::get(ety, getValue(conc.getImaginary()));
652e81d73edSDiana Picus     auto imPart =
653e81d73edSDiana Picus         rewriter.create<mlir::LLVM::ConstantOp>(loc, ety, imFloatAttr);
654e81d73edSDiana Picus     auto realIndex = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
655e81d73edSDiana Picus     auto imIndex = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
656e81d73edSDiana Picus     auto undef = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
657e81d73edSDiana Picus     auto setReal = rewriter.create<mlir::LLVM::InsertValueOp>(
658e81d73edSDiana Picus         loc, ty, undef, realPart, realIndex);
659e81d73edSDiana Picus     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(conc, ty, setReal,
660e81d73edSDiana Picus                                                            imPart, imIndex);
661e81d73edSDiana Picus     return success();
662e81d73edSDiana Picus   }
663e81d73edSDiana Picus 
664e81d73edSDiana Picus   inline APFloat getValue(mlir::Attribute attr) const {
665e81d73edSDiana Picus     return attr.cast<fir::RealAttr>().getValue();
666e81d73edSDiana Picus   }
667e81d73edSDiana Picus };
668e81d73edSDiana Picus 
669092cee5fSValentin Clement /// convert value of from-type to value of to-type
670092cee5fSValentin Clement struct ConvertOpConversion : public FIROpConversion<fir::ConvertOp> {
671092cee5fSValentin Clement   using FIROpConversion::FIROpConversion;
672092cee5fSValentin Clement 
673092cee5fSValentin Clement   static bool isFloatingPointTy(mlir::Type ty) {
674092cee5fSValentin Clement     return ty.isa<mlir::FloatType>();
675092cee5fSValentin Clement   }
676092cee5fSValentin Clement 
677092cee5fSValentin Clement   mlir::LogicalResult
678092cee5fSValentin Clement   matchAndRewrite(fir::ConvertOp convert, OpAdaptor adaptor,
679092cee5fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
680092cee5fSValentin Clement     auto fromTy = convertType(convert.value().getType());
681092cee5fSValentin Clement     auto toTy = convertType(convert.res().getType());
682092cee5fSValentin Clement     mlir::Value op0 = adaptor.getOperands()[0];
683092cee5fSValentin Clement     if (fromTy == toTy) {
684092cee5fSValentin Clement       rewriter.replaceOp(convert, op0);
685092cee5fSValentin Clement       return success();
686092cee5fSValentin Clement     }
687092cee5fSValentin Clement     auto loc = convert.getLoc();
688092cee5fSValentin Clement     auto convertFpToFp = [&](mlir::Value val, unsigned fromBits,
689092cee5fSValentin Clement                              unsigned toBits, mlir::Type toTy) -> mlir::Value {
690092cee5fSValentin Clement       if (fromBits == toBits) {
691092cee5fSValentin Clement         // TODO: Converting between two floating-point representations with the
692092cee5fSValentin Clement         // same bitwidth is not allowed for now.
693092cee5fSValentin Clement         mlir::emitError(loc,
694092cee5fSValentin Clement                         "cannot implicitly convert between two floating-point "
695092cee5fSValentin Clement                         "representations of the same bitwidth");
696092cee5fSValentin Clement         return {};
697092cee5fSValentin Clement       }
698092cee5fSValentin Clement       if (fromBits > toBits)
699092cee5fSValentin Clement         return rewriter.create<mlir::LLVM::FPTruncOp>(loc, toTy, val);
700092cee5fSValentin Clement       return rewriter.create<mlir::LLVM::FPExtOp>(loc, toTy, val);
701092cee5fSValentin Clement     };
702092cee5fSValentin Clement     // Complex to complex conversion.
703092cee5fSValentin Clement     if (fir::isa_complex(convert.value().getType()) &&
704092cee5fSValentin Clement         fir::isa_complex(convert.res().getType())) {
705092cee5fSValentin Clement       // Special case: handle the conversion of a complex such that both the
706092cee5fSValentin Clement       // real and imaginary parts are converted together.
707092cee5fSValentin Clement       auto zero = mlir::ArrayAttr::get(convert.getContext(),
708092cee5fSValentin Clement                                        rewriter.getI32IntegerAttr(0));
709092cee5fSValentin Clement       auto one = mlir::ArrayAttr::get(convert.getContext(),
710092cee5fSValentin Clement                                       rewriter.getI32IntegerAttr(1));
711092cee5fSValentin Clement       auto ty = convertType(getComplexEleTy(convert.value().getType()));
712092cee5fSValentin Clement       auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, zero);
713092cee5fSValentin Clement       auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, one);
714092cee5fSValentin Clement       auto nt = convertType(getComplexEleTy(convert.res().getType()));
715092cee5fSValentin Clement       auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
716092cee5fSValentin Clement       auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(nt);
717092cee5fSValentin Clement       auto rc = convertFpToFp(rp, fromBits, toBits, nt);
718092cee5fSValentin Clement       auto ic = convertFpToFp(ip, fromBits, toBits, nt);
719092cee5fSValentin Clement       auto un = rewriter.create<mlir::LLVM::UndefOp>(loc, toTy);
720092cee5fSValentin Clement       auto i1 =
721092cee5fSValentin Clement           rewriter.create<mlir::LLVM::InsertValueOp>(loc, toTy, un, rc, zero);
722092cee5fSValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(convert, toTy, i1,
723092cee5fSValentin Clement                                                              ic, one);
724092cee5fSValentin Clement       return mlir::success();
725092cee5fSValentin Clement     }
726092cee5fSValentin Clement     // Floating point to floating point conversion.
727092cee5fSValentin Clement     if (isFloatingPointTy(fromTy)) {
728092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
729092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
730092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
731092cee5fSValentin Clement         auto v = convertFpToFp(op0, fromBits, toBits, toTy);
732092cee5fSValentin Clement         rewriter.replaceOp(convert, v);
733092cee5fSValentin Clement         return mlir::success();
734092cee5fSValentin Clement       }
735092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
736092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::FPToSIOp>(convert, toTy, op0);
737092cee5fSValentin Clement         return mlir::success();
738092cee5fSValentin Clement       }
739092cee5fSValentin Clement     } else if (fromTy.isa<mlir::IntegerType>()) {
740092cee5fSValentin Clement       // Integer to integer conversion.
741092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
742092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
743092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
744092cee5fSValentin Clement         assert(fromBits != toBits);
745092cee5fSValentin Clement         if (fromBits > toBits) {
746092cee5fSValentin Clement           rewriter.replaceOpWithNewOp<mlir::LLVM::TruncOp>(convert, toTy, op0);
747092cee5fSValentin Clement           return mlir::success();
748092cee5fSValentin Clement         }
749092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SExtOp>(convert, toTy, op0);
750092cee5fSValentin Clement         return mlir::success();
751092cee5fSValentin Clement       }
752092cee5fSValentin Clement       // Integer to floating point conversion.
753092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
754092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SIToFPOp>(convert, toTy, op0);
755092cee5fSValentin Clement         return mlir::success();
756092cee5fSValentin Clement       }
757092cee5fSValentin Clement       // Integer to pointer conversion.
758092cee5fSValentin Clement       if (toTy.isa<mlir::LLVM::LLVMPointerType>()) {
759092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(convert, toTy, op0);
760092cee5fSValentin Clement         return mlir::success();
761092cee5fSValentin Clement       }
762092cee5fSValentin Clement     } else if (fromTy.isa<mlir::LLVM::LLVMPointerType>()) {
763092cee5fSValentin Clement       // Pointer to integer conversion.
764092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
765092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::PtrToIntOp>(convert, toTy, op0);
766092cee5fSValentin Clement         return mlir::success();
767092cee5fSValentin Clement       }
768092cee5fSValentin Clement       // Pointer to pointer conversion.
769092cee5fSValentin Clement       if (toTy.isa<mlir::LLVM::LLVMPointerType>()) {
770092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(convert, toTy, op0);
771092cee5fSValentin Clement         return mlir::success();
772092cee5fSValentin Clement       }
773092cee5fSValentin Clement     }
774092cee5fSValentin Clement     return emitError(loc) << "cannot convert " << fromTy << " to " << toTy;
775092cee5fSValentin Clement   }
776092cee5fSValentin Clement };
777092cee5fSValentin Clement 
7789534e361SValentin Clement /// Lower `fir.dispatch` operation. A virtual call to a method in a dispatch
7799534e361SValentin Clement /// table.
7809534e361SValentin Clement struct DispatchOpConversion : public FIROpConversion<fir::DispatchOp> {
7819534e361SValentin Clement   using FIROpConversion::FIROpConversion;
7829534e361SValentin Clement 
7839534e361SValentin Clement   mlir::LogicalResult
7849534e361SValentin Clement   matchAndRewrite(fir::DispatchOp dispatch, OpAdaptor adaptor,
7859534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
7869534e361SValentin Clement     return rewriter.notifyMatchFailure(
7879534e361SValentin Clement         dispatch, "fir.dispatch codegen is not implemented yet");
7889534e361SValentin Clement   }
7899534e361SValentin Clement };
7909534e361SValentin Clement 
7919534e361SValentin Clement /// Lower `fir.dispatch_table` operation. The dispatch table for a Fortran
7929534e361SValentin Clement /// derived type.
7939534e361SValentin Clement struct DispatchTableOpConversion
7949534e361SValentin Clement     : public FIROpConversion<fir::DispatchTableOp> {
7959534e361SValentin Clement   using FIROpConversion::FIROpConversion;
7969534e361SValentin Clement 
7979534e361SValentin Clement   mlir::LogicalResult
7989534e361SValentin Clement   matchAndRewrite(fir::DispatchTableOp dispTab, OpAdaptor adaptor,
7999534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8009534e361SValentin Clement     return rewriter.notifyMatchFailure(
8019534e361SValentin Clement         dispTab, "fir.dispatch_table codegen is not implemented yet");
8029534e361SValentin Clement   }
8039534e361SValentin Clement };
8049534e361SValentin Clement 
8059534e361SValentin Clement /// Lower `fir.dt_entry` operation. An entry in a dispatch table; binds a
8069534e361SValentin Clement /// method-name to a function.
8079534e361SValentin Clement struct DTEntryOpConversion : public FIROpConversion<fir::DTEntryOp> {
8089534e361SValentin Clement   using FIROpConversion::FIROpConversion;
8099534e361SValentin Clement 
8109534e361SValentin Clement   mlir::LogicalResult
8119534e361SValentin Clement   matchAndRewrite(fir::DTEntryOp dtEnt, OpAdaptor adaptor,
8129534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8139534e361SValentin Clement     return rewriter.notifyMatchFailure(
8149534e361SValentin Clement         dtEnt, "fir.dt_entry codegen is not implemented yet");
8159534e361SValentin Clement   }
8169534e361SValentin Clement };
8179534e361SValentin Clement 
818677df8c7SValentin Clement /// Lower `fir.global_len` operation.
819677df8c7SValentin Clement struct GlobalLenOpConversion : public FIROpConversion<fir::GlobalLenOp> {
820677df8c7SValentin Clement   using FIROpConversion::FIROpConversion;
821677df8c7SValentin Clement 
822677df8c7SValentin Clement   mlir::LogicalResult
823677df8c7SValentin Clement   matchAndRewrite(fir::GlobalLenOp globalLen, OpAdaptor adaptor,
824677df8c7SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
825677df8c7SValentin Clement     return rewriter.notifyMatchFailure(
826677df8c7SValentin Clement         globalLen, "fir.global_len codegen is not implemented yet");
827677df8c7SValentin Clement   }
828677df8c7SValentin Clement };
829677df8c7SValentin Clement 
83031246187SValentin Clement /// Lower `fir.gentypedesc` to a global constant.
83131246187SValentin Clement struct GenTypeDescOpConversion : public FIROpConversion<fir::GenTypeDescOp> {
83231246187SValentin Clement   using FIROpConversion::FIROpConversion;
83331246187SValentin Clement 
83431246187SValentin Clement   mlir::LogicalResult
83531246187SValentin Clement   matchAndRewrite(fir::GenTypeDescOp gentypedesc, OpAdaptor adaptor,
83631246187SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
83731246187SValentin Clement     return rewriter.notifyMatchFailure(
83831246187SValentin Clement         gentypedesc, "fir.fir.gentypedesc codegen is not implemented yet");
83931246187SValentin Clement   }
84031246187SValentin Clement };
84131246187SValentin Clement 
84222d332a0SAndrzej Warzynski /// Convert `fir.end`
84322d332a0SAndrzej Warzynski struct FirEndOpConversion : public FIROpConversion<fir::FirEndOp> {
84422d332a0SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
84522d332a0SAndrzej Warzynski 
84622d332a0SAndrzej Warzynski   mlir::LogicalResult
84722d332a0SAndrzej Warzynski   matchAndRewrite(fir::FirEndOp firEnd, OpAdaptor,
84822d332a0SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
84922d332a0SAndrzej Warzynski     return rewriter.notifyMatchFailure(
85022d332a0SAndrzej Warzynski         firEnd, "fir.end codegen is not implemented yet");
85122d332a0SAndrzej Warzynski   }
85222d332a0SAndrzej Warzynski };
85322d332a0SAndrzej Warzynski 
8540c4a7a52SValentin Clement /// Lower `fir.has_value` operation to `llvm.return` operation.
855044d5b5dSValentin Clement struct HasValueOpConversion : public FIROpConversion<fir::HasValueOp> {
856044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
857044d5b5dSValentin Clement 
858044d5b5dSValentin Clement   mlir::LogicalResult
859044d5b5dSValentin Clement   matchAndRewrite(fir::HasValueOp op, OpAdaptor adaptor,
860044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
861044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, adaptor.getOperands());
862044d5b5dSValentin Clement     return success();
863044d5b5dSValentin Clement   }
864044d5b5dSValentin Clement };
865044d5b5dSValentin Clement 
8660c4a7a52SValentin Clement /// Lower `fir.global` operation to `llvm.global` operation.
8670c4a7a52SValentin Clement /// `fir.insert_on_range` operations are replaced with constant dense attribute
8680c4a7a52SValentin Clement /// if they are applied on the full range.
869044d5b5dSValentin Clement struct GlobalOpConversion : public FIROpConversion<fir::GlobalOp> {
870044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
871044d5b5dSValentin Clement 
872044d5b5dSValentin Clement   mlir::LogicalResult
873044d5b5dSValentin Clement   matchAndRewrite(fir::GlobalOp global, OpAdaptor adaptor,
874044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
875044d5b5dSValentin Clement     auto tyAttr = convertType(global.getType());
876044d5b5dSValentin Clement     if (global.getType().isa<fir::BoxType>())
877044d5b5dSValentin Clement       tyAttr = tyAttr.cast<mlir::LLVM::LLVMPointerType>().getElementType();
878044d5b5dSValentin Clement     auto loc = global.getLoc();
879044d5b5dSValentin Clement     mlir::Attribute initAttr{};
880044d5b5dSValentin Clement     if (global.initVal())
881044d5b5dSValentin Clement       initAttr = global.initVal().getValue();
882044d5b5dSValentin Clement     auto linkage = convertLinkage(global.linkName());
883044d5b5dSValentin Clement     auto isConst = global.constant().hasValue();
884044d5b5dSValentin Clement     auto g = rewriter.create<mlir::LLVM::GlobalOp>(
885044d5b5dSValentin Clement         loc, tyAttr, isConst, linkage, global.sym_name(), initAttr);
886044d5b5dSValentin Clement     auto &gr = g.getInitializerRegion();
887044d5b5dSValentin Clement     rewriter.inlineRegionBefore(global.region(), gr, gr.end());
888044d5b5dSValentin Clement     if (!gr.empty()) {
889044d5b5dSValentin Clement       // Replace insert_on_range with a constant dense attribute if the
890044d5b5dSValentin Clement       // initialization is on the full range.
891044d5b5dSValentin Clement       auto insertOnRangeOps = gr.front().getOps<fir::InsertOnRangeOp>();
892044d5b5dSValentin Clement       for (auto insertOp : insertOnRangeOps) {
893044d5b5dSValentin Clement         if (isFullRange(insertOp.coor(), insertOp.getType())) {
894044d5b5dSValentin Clement           auto seqTyAttr = convertType(insertOp.getType());
895044d5b5dSValentin Clement           auto *op = insertOp.val().getDefiningOp();
896044d5b5dSValentin Clement           auto constant = mlir::dyn_cast<mlir::arith::ConstantOp>(op);
897044d5b5dSValentin Clement           if (!constant) {
898044d5b5dSValentin Clement             auto convertOp = mlir::dyn_cast<fir::ConvertOp>(op);
899044d5b5dSValentin Clement             if (!convertOp)
900044d5b5dSValentin Clement               continue;
901044d5b5dSValentin Clement             constant = cast<mlir::arith::ConstantOp>(
902044d5b5dSValentin Clement                 convertOp.value().getDefiningOp());
903044d5b5dSValentin Clement           }
904044d5b5dSValentin Clement           mlir::Type vecType = mlir::VectorType::get(
905044d5b5dSValentin Clement               insertOp.getType().getShape(), constant.getType());
906044d5b5dSValentin Clement           auto denseAttr = mlir::DenseElementsAttr::get(
907044d5b5dSValentin Clement               vecType.cast<ShapedType>(), constant.value());
908044d5b5dSValentin Clement           rewriter.setInsertionPointAfter(insertOp);
909044d5b5dSValentin Clement           rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(
910044d5b5dSValentin Clement               insertOp, seqTyAttr, denseAttr);
911044d5b5dSValentin Clement         }
912044d5b5dSValentin Clement       }
913044d5b5dSValentin Clement     }
914044d5b5dSValentin Clement     rewriter.eraseOp(global);
915044d5b5dSValentin Clement     return success();
916044d5b5dSValentin Clement   }
917044d5b5dSValentin Clement 
918044d5b5dSValentin Clement   bool isFullRange(mlir::ArrayAttr indexes, fir::SequenceType seqTy) const {
919044d5b5dSValentin Clement     auto extents = seqTy.getShape();
920044d5b5dSValentin Clement     if (indexes.size() / 2 != extents.size())
921044d5b5dSValentin Clement       return false;
922044d5b5dSValentin Clement     for (unsigned i = 0; i < indexes.size(); i += 2) {
923044d5b5dSValentin Clement       if (indexes[i].cast<IntegerAttr>().getInt() != 0)
924044d5b5dSValentin Clement         return false;
925044d5b5dSValentin Clement       if (indexes[i + 1].cast<IntegerAttr>().getInt() != extents[i / 2] - 1)
926044d5b5dSValentin Clement         return false;
927044d5b5dSValentin Clement     }
928044d5b5dSValentin Clement     return true;
929044d5b5dSValentin Clement   }
930044d5b5dSValentin Clement 
9310c4a7a52SValentin Clement   // TODO: String comparaison should be avoided. Replace linkName with an
9320c4a7a52SValentin Clement   // enumeration.
933044d5b5dSValentin Clement   mlir::LLVM::Linkage convertLinkage(Optional<StringRef> optLinkage) const {
934044d5b5dSValentin Clement     if (optLinkage.hasValue()) {
935044d5b5dSValentin Clement       auto name = optLinkage.getValue();
936044d5b5dSValentin Clement       if (name == "internal")
937044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Internal;
938044d5b5dSValentin Clement       if (name == "linkonce")
939044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Linkonce;
940044d5b5dSValentin Clement       if (name == "common")
941044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Common;
942044d5b5dSValentin Clement       if (name == "weak")
943044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Weak;
944044d5b5dSValentin Clement     }
945044d5b5dSValentin Clement     return mlir::LLVM::Linkage::External;
946044d5b5dSValentin Clement   }
947044d5b5dSValentin Clement };
948044d5b5dSValentin Clement 
94939f4ef81SValentin Clement void genCondBrOp(mlir::Location loc, mlir::Value cmp, mlir::Block *dest,
95039f4ef81SValentin Clement                  Optional<mlir::ValueRange> destOps,
95139f4ef81SValentin Clement                  mlir::ConversionPatternRewriter &rewriter,
95239f4ef81SValentin Clement                  mlir::Block *newBlock) {
95339f4ef81SValentin Clement   if (destOps.hasValue())
95439f4ef81SValentin Clement     rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, destOps.getValue(),
95539f4ef81SValentin Clement                                           newBlock, mlir::ValueRange());
95639f4ef81SValentin Clement   else
95739f4ef81SValentin Clement     rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, newBlock);
95839f4ef81SValentin Clement }
95939f4ef81SValentin Clement 
96039f4ef81SValentin Clement template <typename A, typename B>
96139f4ef81SValentin Clement void genBrOp(A caseOp, mlir::Block *dest, Optional<B> destOps,
96239f4ef81SValentin Clement              mlir::ConversionPatternRewriter &rewriter) {
96339f4ef81SValentin Clement   if (destOps.hasValue())
96439f4ef81SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, destOps.getValue(),
96539f4ef81SValentin Clement                                                   dest);
96639f4ef81SValentin Clement   else
96739f4ef81SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, llvm::None, dest);
96839f4ef81SValentin Clement }
96939f4ef81SValentin Clement 
97039f4ef81SValentin Clement void genCaseLadderStep(mlir::Location loc, mlir::Value cmp, mlir::Block *dest,
97139f4ef81SValentin Clement                        Optional<mlir::ValueRange> destOps,
97239f4ef81SValentin Clement                        mlir::ConversionPatternRewriter &rewriter) {
97339f4ef81SValentin Clement   auto *thisBlock = rewriter.getInsertionBlock();
97439f4ef81SValentin Clement   auto *newBlock = createBlock(rewriter, dest);
97539f4ef81SValentin Clement   rewriter.setInsertionPointToEnd(thisBlock);
97639f4ef81SValentin Clement   genCondBrOp(loc, cmp, dest, destOps, rewriter, newBlock);
97739f4ef81SValentin Clement   rewriter.setInsertionPointToEnd(newBlock);
97839f4ef81SValentin Clement }
97939f4ef81SValentin Clement 
98039f4ef81SValentin Clement /// Conversion of `fir.select_case`
98139f4ef81SValentin Clement ///
98239f4ef81SValentin Clement /// The `fir.select_case` operation is converted to a if-then-else ladder.
98339f4ef81SValentin Clement /// Depending on the case condition type, one or several comparison and
98439f4ef81SValentin Clement /// conditional branching can be generated.
98539f4ef81SValentin Clement ///
98639f4ef81SValentin Clement /// A a point value case such as `case(4)`, a lower bound case such as
98739f4ef81SValentin Clement /// `case(5:)` or an upper bound case such as `case(:3)` are converted to a
98839f4ef81SValentin Clement /// simple comparison between the selector value and the constant value in the
98939f4ef81SValentin Clement /// case. The block associated with the case condition is then executed if
99039f4ef81SValentin Clement /// the comparison succeed otherwise it branch to the next block with the
99139f4ef81SValentin Clement /// comparison for the the next case conditon.
99239f4ef81SValentin Clement ///
99339f4ef81SValentin Clement /// A closed interval case condition such as `case(7:10)` is converted with a
99439f4ef81SValentin Clement /// first comparison and conditional branching for the lower bound. If
99539f4ef81SValentin Clement /// successful, it branch to a second block with the comparison for the
99639f4ef81SValentin Clement /// upper bound in the same case condition.
99739f4ef81SValentin Clement ///
99839f4ef81SValentin Clement /// TODO: lowering of CHARACTER type cases is not handled yet.
99939f4ef81SValentin Clement struct SelectCaseOpConversion : public FIROpConversion<fir::SelectCaseOp> {
100039f4ef81SValentin Clement   using FIROpConversion::FIROpConversion;
100139f4ef81SValentin Clement 
100239f4ef81SValentin Clement   mlir::LogicalResult
100339f4ef81SValentin Clement   matchAndRewrite(fir::SelectCaseOp caseOp, OpAdaptor adaptor,
100439f4ef81SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
100539f4ef81SValentin Clement     unsigned conds = caseOp.getNumConditions();
100639f4ef81SValentin Clement     llvm::ArrayRef<mlir::Attribute> cases = caseOp.getCases().getValue();
100739f4ef81SValentin Clement     // Type can be CHARACTER, INTEGER, or LOGICAL (C1145)
100839f4ef81SValentin Clement     LLVM_ATTRIBUTE_UNUSED auto ty = caseOp.getSelector().getType();
100939f4ef81SValentin Clement     if (ty.isa<fir::CharacterType>())
101039f4ef81SValentin Clement       return rewriter.notifyMatchFailure(caseOp,
101139f4ef81SValentin Clement                                          "conversion of fir.select_case with "
101239f4ef81SValentin Clement                                          "character type not implemented yet");
101339f4ef81SValentin Clement     mlir::Value selector = caseOp.getSelector(adaptor.getOperands());
101439f4ef81SValentin Clement     auto loc = caseOp.getLoc();
101539f4ef81SValentin Clement     for (unsigned t = 0; t != conds; ++t) {
101639f4ef81SValentin Clement       mlir::Block *dest = caseOp.getSuccessor(t);
101739f4ef81SValentin Clement       llvm::Optional<mlir::ValueRange> destOps =
101839f4ef81SValentin Clement           caseOp.getSuccessorOperands(adaptor.getOperands(), t);
101939f4ef81SValentin Clement       llvm::Optional<mlir::ValueRange> cmpOps =
102039f4ef81SValentin Clement           *caseOp.getCompareOperands(adaptor.getOperands(), t);
102139f4ef81SValentin Clement       mlir::Value caseArg = *(cmpOps.getValue().begin());
102239f4ef81SValentin Clement       mlir::Attribute attr = cases[t];
102339f4ef81SValentin Clement       if (attr.isa<fir::PointIntervalAttr>()) {
102439f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
102539f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::eq, selector, caseArg);
102639f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
102739f4ef81SValentin Clement         continue;
102839f4ef81SValentin Clement       }
102939f4ef81SValentin Clement       if (attr.isa<fir::LowerBoundAttr>()) {
103039f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
103139f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector);
103239f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
103339f4ef81SValentin Clement         continue;
103439f4ef81SValentin Clement       }
103539f4ef81SValentin Clement       if (attr.isa<fir::UpperBoundAttr>()) {
103639f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
103739f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg);
103839f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
103939f4ef81SValentin Clement         continue;
104039f4ef81SValentin Clement       }
104139f4ef81SValentin Clement       if (attr.isa<fir::ClosedIntervalAttr>()) {
104239f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
104339f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector);
104439f4ef81SValentin Clement         auto *thisBlock = rewriter.getInsertionBlock();
104539f4ef81SValentin Clement         auto *newBlock1 = createBlock(rewriter, dest);
104639f4ef81SValentin Clement         auto *newBlock2 = createBlock(rewriter, dest);
104739f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(thisBlock);
104839f4ef81SValentin Clement         rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, newBlock1, newBlock2);
104939f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(newBlock1);
105039f4ef81SValentin Clement         mlir::Value caseArg0 = *(cmpOps.getValue().begin() + 1);
105139f4ef81SValentin Clement         auto cmp0 = rewriter.create<mlir::LLVM::ICmpOp>(
105239f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg0);
105339f4ef81SValentin Clement         genCondBrOp(loc, cmp0, dest, destOps, rewriter, newBlock2);
105439f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(newBlock2);
105539f4ef81SValentin Clement         continue;
105639f4ef81SValentin Clement       }
105739f4ef81SValentin Clement       assert(attr.isa<mlir::UnitAttr>());
105839f4ef81SValentin Clement       assert((t + 1 == conds) && "unit must be last");
105939f4ef81SValentin Clement       genBrOp(caseOp, dest, destOps, rewriter);
106039f4ef81SValentin Clement     }
106139f4ef81SValentin Clement     return success();
106239f4ef81SValentin Clement   }
106339f4ef81SValentin Clement };
106439f4ef81SValentin Clement 
10658c239909SValentin Clement template <typename OP>
10668c239909SValentin Clement void selectMatchAndRewrite(fir::LLVMTypeConverter &lowering, OP select,
10678c239909SValentin Clement                            typename OP::Adaptor adaptor,
10688c239909SValentin Clement                            mlir::ConversionPatternRewriter &rewriter) {
10698c239909SValentin Clement   unsigned conds = select.getNumConditions();
10708c239909SValentin Clement   auto cases = select.getCases().getValue();
10718c239909SValentin Clement   mlir::Value selector = adaptor.selector();
10728c239909SValentin Clement   auto loc = select.getLoc();
10738c239909SValentin Clement   assert(conds > 0 && "select must have cases");
10748c239909SValentin Clement 
10758c239909SValentin Clement   llvm::SmallVector<mlir::Block *> destinations;
10768c239909SValentin Clement   llvm::SmallVector<mlir::ValueRange> destinationsOperands;
10778c239909SValentin Clement   mlir::Block *defaultDestination;
10788c239909SValentin Clement   mlir::ValueRange defaultOperands;
10798c239909SValentin Clement   llvm::SmallVector<int32_t> caseValues;
10808c239909SValentin Clement 
10818c239909SValentin Clement   for (unsigned t = 0; t != conds; ++t) {
10828c239909SValentin Clement     mlir::Block *dest = select.getSuccessor(t);
10838c239909SValentin Clement     auto destOps = select.getSuccessorOperands(adaptor.getOperands(), t);
10848c239909SValentin Clement     const mlir::Attribute &attr = cases[t];
10858c239909SValentin Clement     if (auto intAttr = attr.template dyn_cast<mlir::IntegerAttr>()) {
10868c239909SValentin Clement       destinations.push_back(dest);
10878c239909SValentin Clement       destinationsOperands.push_back(destOps.hasValue() ? *destOps
10888c239909SValentin Clement                                                         : ValueRange());
10898c239909SValentin Clement       caseValues.push_back(intAttr.getInt());
10908c239909SValentin Clement       continue;
10918c239909SValentin Clement     }
10928c239909SValentin Clement     assert(attr.template dyn_cast_or_null<mlir::UnitAttr>());
10938c239909SValentin Clement     assert((t + 1 == conds) && "unit must be last");
10948c239909SValentin Clement     defaultDestination = dest;
10958c239909SValentin Clement     defaultOperands = destOps.hasValue() ? *destOps : ValueRange();
10968c239909SValentin Clement   }
10978c239909SValentin Clement 
10988c239909SValentin Clement   // LLVM::SwitchOp takes a i32 type for the selector.
10998c239909SValentin Clement   if (select.getSelector().getType() != rewriter.getI32Type())
11008c239909SValentin Clement     selector =
11018c239909SValentin Clement         rewriter.create<LLVM::TruncOp>(loc, rewriter.getI32Type(), selector);
11028c239909SValentin Clement 
11038c239909SValentin Clement   rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>(
11048c239909SValentin Clement       select, selector,
11058c239909SValentin Clement       /*defaultDestination=*/defaultDestination,
11068c239909SValentin Clement       /*defaultOperands=*/defaultOperands,
11078c239909SValentin Clement       /*caseValues=*/caseValues,
11088c239909SValentin Clement       /*caseDestinations=*/destinations,
11098c239909SValentin Clement       /*caseOperands=*/destinationsOperands,
11108c239909SValentin Clement       /*branchWeights=*/ArrayRef<int32_t>());
11118c239909SValentin Clement }
11128c239909SValentin Clement 
11138c239909SValentin Clement /// conversion of fir::SelectOp to an if-then-else ladder
11148c239909SValentin Clement struct SelectOpConversion : public FIROpConversion<fir::SelectOp> {
11158c239909SValentin Clement   using FIROpConversion::FIROpConversion;
11168c239909SValentin Clement 
11178c239909SValentin Clement   mlir::LogicalResult
11188c239909SValentin Clement   matchAndRewrite(fir::SelectOp op, OpAdaptor adaptor,
11198c239909SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
11208c239909SValentin Clement     selectMatchAndRewrite<fir::SelectOp>(lowerTy(), op, adaptor, rewriter);
11218c239909SValentin Clement     return success();
11228c239909SValentin Clement   }
11238c239909SValentin Clement };
11248c239909SValentin Clement 
1125e3349fa1SAndrzej Warzynski /// `fir.load` --> `llvm.load`
1126e3349fa1SAndrzej Warzynski struct LoadOpConversion : public FIROpConversion<fir::LoadOp> {
1127e3349fa1SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
1128e3349fa1SAndrzej Warzynski 
1129e3349fa1SAndrzej Warzynski   mlir::LogicalResult
1130e3349fa1SAndrzej Warzynski   matchAndRewrite(fir::LoadOp load, OpAdaptor adaptor,
1131e3349fa1SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
1132e3349fa1SAndrzej Warzynski     // fir.box is a special case because it is considered as an ssa values in
1133e3349fa1SAndrzej Warzynski     // fir, but it is lowered as a pointer to a descriptor. So fir.ref<fir.box>
1134e3349fa1SAndrzej Warzynski     // and fir.box end up being the same llvm types and loading a
1135e3349fa1SAndrzej Warzynski     // fir.ref<fir.box> is actually a no op in LLVM.
1136e3349fa1SAndrzej Warzynski     if (load.getType().isa<fir::BoxType>()) {
1137e3349fa1SAndrzej Warzynski       rewriter.replaceOp(load, adaptor.getOperands()[0]);
1138e3349fa1SAndrzej Warzynski     } else {
1139e3349fa1SAndrzej Warzynski       mlir::Type ty = convertType(load.getType());
1140e3349fa1SAndrzej Warzynski       ArrayRef<NamedAttribute> at = load->getAttrs();
1141e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::LoadOp>(
1142e3349fa1SAndrzej Warzynski           load, ty, adaptor.getOperands(), at);
1143e3349fa1SAndrzej Warzynski     }
1144e3349fa1SAndrzej Warzynski     return success();
1145e3349fa1SAndrzej Warzynski   }
1146e3349fa1SAndrzej Warzynski };
1147e3349fa1SAndrzej Warzynski 
1148*b8207db7SValentin Clement /// Lower `fir.no_reassoc` to LLVM IR dialect.
1149*b8207db7SValentin Clement /// TODO: how do we want to enforce this in LLVM-IR? Can we manipulate the fast
1150*b8207db7SValentin Clement /// math flags?
1151*b8207db7SValentin Clement struct NoReassocOpConversion : public FIROpConversion<fir::NoReassocOp> {
1152*b8207db7SValentin Clement   using FIROpConversion::FIROpConversion;
1153*b8207db7SValentin Clement 
1154*b8207db7SValentin Clement   mlir::LogicalResult
1155*b8207db7SValentin Clement   matchAndRewrite(fir::NoReassocOp noreassoc, OpAdaptor adaptor,
1156*b8207db7SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1157*b8207db7SValentin Clement     rewriter.replaceOp(noreassoc, adaptor.getOperands()[0]);
1158*b8207db7SValentin Clement     return success();
1159*b8207db7SValentin Clement   }
1160*b8207db7SValentin Clement };
1161*b8207db7SValentin Clement 
11622a299e4fSValentin Clement /// Lower `fir.select_type` to LLVM IR dialect.
11632a299e4fSValentin Clement struct SelectTypeOpConversion : public FIROpConversion<fir::SelectTypeOp> {
11642a299e4fSValentin Clement   using FIROpConversion::FIROpConversion;
11652a299e4fSValentin Clement 
11662a299e4fSValentin Clement   mlir::LogicalResult
11672a299e4fSValentin Clement   matchAndRewrite(fir::SelectTypeOp select, OpAdaptor adaptor,
11682a299e4fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
11692a299e4fSValentin Clement     return rewriter.notifyMatchFailure(
11702a299e4fSValentin Clement         select, "fir.select_type codegen is not implemented yet");
11712a299e4fSValentin Clement   }
11722a299e4fSValentin Clement };
11732a299e4fSValentin Clement 
11748c239909SValentin Clement /// conversion of fir::SelectRankOp to an if-then-else ladder
11758c239909SValentin Clement struct SelectRankOpConversion : public FIROpConversion<fir::SelectRankOp> {
11768c239909SValentin Clement   using FIROpConversion::FIROpConversion;
11778c239909SValentin Clement 
11788c239909SValentin Clement   mlir::LogicalResult
11798c239909SValentin Clement   matchAndRewrite(fir::SelectRankOp op, OpAdaptor adaptor,
11808c239909SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
11818c239909SValentin Clement     selectMatchAndRewrite<fir::SelectRankOp>(lowerTy(), op, adaptor, rewriter);
11828c239909SValentin Clement     return success();
11838c239909SValentin Clement   }
11848c239909SValentin Clement };
11858c239909SValentin Clement 
1186e3349fa1SAndrzej Warzynski /// `fir.store` --> `llvm.store`
1187e3349fa1SAndrzej Warzynski struct StoreOpConversion : public FIROpConversion<fir::StoreOp> {
1188e3349fa1SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
1189e3349fa1SAndrzej Warzynski 
1190e3349fa1SAndrzej Warzynski   mlir::LogicalResult
1191e3349fa1SAndrzej Warzynski   matchAndRewrite(fir::StoreOp store, OpAdaptor adaptor,
1192e3349fa1SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
1193e3349fa1SAndrzej Warzynski     if (store.value().getType().isa<fir::BoxType>()) {
1194e3349fa1SAndrzej Warzynski       // fir.box value is actually in memory, load it first before storing it.
1195e3349fa1SAndrzej Warzynski       mlir::Location loc = store.getLoc();
1196e3349fa1SAndrzej Warzynski       mlir::Type boxPtrTy = adaptor.getOperands()[0].getType();
1197e3349fa1SAndrzej Warzynski       auto val = rewriter.create<mlir::LLVM::LoadOp>(
1198e3349fa1SAndrzej Warzynski           loc, boxPtrTy.cast<mlir::LLVM::LLVMPointerType>().getElementType(),
1199e3349fa1SAndrzej Warzynski           adaptor.getOperands()[0]);
1200e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
1201e3349fa1SAndrzej Warzynski           store, val, adaptor.getOperands()[1]);
1202e3349fa1SAndrzej Warzynski     } else {
1203e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
1204e3349fa1SAndrzej Warzynski           store, adaptor.getOperands()[0], adaptor.getOperands()[1]);
1205e3349fa1SAndrzej Warzynski     }
1206e3349fa1SAndrzej Warzynski     return success();
1207e3349fa1SAndrzej Warzynski   }
1208e3349fa1SAndrzej Warzynski };
1209e3349fa1SAndrzej Warzynski 
1210e3349fa1SAndrzej Warzynski /// convert to LLVM IR dialect `undef`
1211044d5b5dSValentin Clement struct UndefOpConversion : public FIROpConversion<fir::UndefOp> {
1212044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
1213044d5b5dSValentin Clement 
1214044d5b5dSValentin Clement   mlir::LogicalResult
1215044d5b5dSValentin Clement   matchAndRewrite(fir::UndefOp undef, OpAdaptor,
1216044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1217044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::UndefOp>(
1218044d5b5dSValentin Clement         undef, convertType(undef.getType()));
1219044d5b5dSValentin Clement     return success();
1220044d5b5dSValentin Clement   }
1221044d5b5dSValentin Clement };
1222a7a61359SValentin Clement 
1223e3349fa1SAndrzej Warzynski /// `fir.unreachable` --> `llvm.unreachable`
122432e08248SAndrzej Warzynski struct UnreachableOpConversion : public FIROpConversion<fir::UnreachableOp> {
122532e08248SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
122632e08248SAndrzej Warzynski 
122732e08248SAndrzej Warzynski   mlir::LogicalResult
122832e08248SAndrzej Warzynski   matchAndRewrite(fir::UnreachableOp unreach, OpAdaptor adaptor,
122932e08248SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
123032e08248SAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(unreach);
123132e08248SAndrzej Warzynski     return success();
123232e08248SAndrzej Warzynski   }
123332e08248SAndrzej Warzynski };
123432e08248SAndrzej Warzynski 
1235a7a61359SValentin Clement struct ZeroOpConversion : public FIROpConversion<fir::ZeroOp> {
1236a7a61359SValentin Clement   using FIROpConversion::FIROpConversion;
1237a7a61359SValentin Clement 
1238a7a61359SValentin Clement   mlir::LogicalResult
1239a7a61359SValentin Clement   matchAndRewrite(fir::ZeroOp zero, OpAdaptor,
1240a7a61359SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1241a7a61359SValentin Clement     auto ty = convertType(zero.getType());
1242a7a61359SValentin Clement     if (ty.isa<mlir::LLVM::LLVMPointerType>()) {
1243a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(zero, ty);
1244a7a61359SValentin Clement     } else if (ty.isa<mlir::IntegerType>()) {
1245a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
1246a7a61359SValentin Clement           zero, ty, mlir::IntegerAttr::get(zero.getType(), 0));
1247a7a61359SValentin Clement     } else if (mlir::LLVM::isCompatibleFloatingPointType(ty)) {
1248a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
1249a7a61359SValentin Clement           zero, ty, mlir::FloatAttr::get(zero.getType(), 0.0));
1250a7a61359SValentin Clement     } else {
1251a7a61359SValentin Clement       // TODO: create ConstantAggregateZero for FIR aggregate/array types.
125252d813edSValentin Clement       return rewriter.notifyMatchFailure(
125352d813edSValentin Clement           zero,
1254a7a61359SValentin Clement           "conversion of fir.zero with aggregate type not implemented yet");
1255a7a61359SValentin Clement     }
1256a7a61359SValentin Clement     return success();
1257a7a61359SValentin Clement   }
1258a7a61359SValentin Clement };
125932e08248SAndrzej Warzynski 
1260af6ee580SValentin Clement /// Common base class for embox to descriptor conversion.
1261af6ee580SValentin Clement template <typename OP>
1262af6ee580SValentin Clement struct EmboxCommonConversion : public FIROpConversion<OP> {
1263af6ee580SValentin Clement   using FIROpConversion<OP>::FIROpConversion;
1264af6ee580SValentin Clement 
1265af6ee580SValentin Clement   // Find the LLVMFuncOp in whose entry block the alloca should be inserted.
1266af6ee580SValentin Clement   // The order to find the LLVMFuncOp is as follows:
1267af6ee580SValentin Clement   // 1. The parent operation of the current block if it is a LLVMFuncOp.
1268af6ee580SValentin Clement   // 2. The first ancestor that is a LLVMFuncOp.
1269af6ee580SValentin Clement   mlir::LLVM::LLVMFuncOp
1270af6ee580SValentin Clement   getFuncForAllocaInsert(mlir::ConversionPatternRewriter &rewriter) const {
1271af6ee580SValentin Clement     mlir::Operation *parentOp = rewriter.getInsertionBlock()->getParentOp();
1272af6ee580SValentin Clement     return mlir::isa<mlir::LLVM::LLVMFuncOp>(parentOp)
1273af6ee580SValentin Clement                ? mlir::cast<mlir::LLVM::LLVMFuncOp>(parentOp)
1274af6ee580SValentin Clement                : parentOp->getParentOfType<mlir::LLVM::LLVMFuncOp>();
1275af6ee580SValentin Clement   }
1276af6ee580SValentin Clement 
1277af6ee580SValentin Clement   // Generate an alloca of size 1 and type \p toTy.
1278af6ee580SValentin Clement   mlir::LLVM::AllocaOp
1279af6ee580SValentin Clement   genAllocaWithType(mlir::Location loc, mlir::Type toTy, unsigned alignment,
1280af6ee580SValentin Clement                     mlir::ConversionPatternRewriter &rewriter) const {
1281af6ee580SValentin Clement     auto thisPt = rewriter.saveInsertionPoint();
1282af6ee580SValentin Clement     mlir::LLVM::LLVMFuncOp func = getFuncForAllocaInsert(rewriter);
1283af6ee580SValentin Clement     rewriter.setInsertionPointToStart(&func.front());
1284af6ee580SValentin Clement     auto size = this->genI32Constant(loc, rewriter, 1);
1285af6ee580SValentin Clement     auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, toTy, size, alignment);
1286af6ee580SValentin Clement     rewriter.restoreInsertionPoint(thisPt);
1287af6ee580SValentin Clement     return al;
1288af6ee580SValentin Clement   }
1289af6ee580SValentin Clement 
1290af6ee580SValentin Clement   static int getCFIAttr(fir::BoxType boxTy) {
1291af6ee580SValentin Clement     auto eleTy = boxTy.getEleTy();
1292af6ee580SValentin Clement     if (eleTy.isa<fir::PointerType>())
1293af6ee580SValentin Clement       return CFI_attribute_pointer;
1294af6ee580SValentin Clement     if (eleTy.isa<fir::HeapType>())
1295af6ee580SValentin Clement       return CFI_attribute_allocatable;
1296af6ee580SValentin Clement     return CFI_attribute_other;
1297af6ee580SValentin Clement   }
1298af6ee580SValentin Clement 
1299af6ee580SValentin Clement   static fir::RecordType unwrapIfDerived(fir::BoxType boxTy) {
1300af6ee580SValentin Clement     return fir::unwrapSequenceType(fir::dyn_cast_ptrOrBoxEleTy(boxTy))
1301af6ee580SValentin Clement         .template dyn_cast<fir::RecordType>();
1302af6ee580SValentin Clement   }
1303af6ee580SValentin Clement   static bool isDerivedTypeWithLenParams(fir::BoxType boxTy) {
1304af6ee580SValentin Clement     auto recTy = unwrapIfDerived(boxTy);
1305af6ee580SValentin Clement     return recTy && recTy.getNumLenParams() > 0;
1306af6ee580SValentin Clement   }
1307af6ee580SValentin Clement   static bool isDerivedType(fir::BoxType boxTy) {
1308af6ee580SValentin Clement     return unwrapIfDerived(boxTy) != nullptr;
1309af6ee580SValentin Clement   }
1310af6ee580SValentin Clement 
1311af6ee580SValentin Clement   // Get the element size and CFI type code of the boxed value.
1312af6ee580SValentin Clement   std::tuple<mlir::Value, mlir::Value> getSizeAndTypeCode(
1313af6ee580SValentin Clement       mlir::Location loc, mlir::ConversionPatternRewriter &rewriter,
1314af6ee580SValentin Clement       mlir::Type boxEleTy, mlir::ValueRange lenParams = {}) const {
1315af6ee580SValentin Clement     auto doInteger =
1316af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1317af6ee580SValentin Clement       int typeCode = fir::integerBitsToTypeCode(width);
1318af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1319af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1320af6ee580SValentin Clement     };
1321af6ee580SValentin Clement     auto doLogical =
1322af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1323af6ee580SValentin Clement       int typeCode = fir::logicalBitsToTypeCode(width);
1324af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1325af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1326af6ee580SValentin Clement     };
1327af6ee580SValentin Clement     auto doFloat = [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1328af6ee580SValentin Clement       int typeCode = fir::realBitsToTypeCode(width);
1329af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1330af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1331af6ee580SValentin Clement     };
1332af6ee580SValentin Clement     auto doComplex =
1333af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1334af6ee580SValentin Clement       auto typeCode = fir::complexBitsToTypeCode(width);
1335af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8 * 2),
1336af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1337af6ee580SValentin Clement     };
1338af6ee580SValentin Clement     auto doCharacter =
1339af6ee580SValentin Clement         [&](unsigned width,
1340af6ee580SValentin Clement             mlir::Value len) -> std::tuple<mlir::Value, mlir::Value> {
1341af6ee580SValentin Clement       auto typeCode = fir::characterBitsToTypeCode(width);
1342af6ee580SValentin Clement       auto typeCodeVal = this->genConstantOffset(loc, rewriter, typeCode);
1343af6ee580SValentin Clement       if (width == 8)
1344af6ee580SValentin Clement         return {len, typeCodeVal};
1345af6ee580SValentin Clement       auto byteWidth = this->genConstantOffset(loc, rewriter, width / 8);
1346af6ee580SValentin Clement       auto i64Ty = mlir::IntegerType::get(&this->lowerTy().getContext(), 64);
1347af6ee580SValentin Clement       auto size =
1348af6ee580SValentin Clement           rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, byteWidth, len);
1349af6ee580SValentin Clement       return {size, typeCodeVal};
1350af6ee580SValentin Clement     };
1351af6ee580SValentin Clement     auto getKindMap = [&]() -> fir::KindMapping & {
1352af6ee580SValentin Clement       return this->lowerTy().getKindMap();
1353af6ee580SValentin Clement     };
1354af6ee580SValentin Clement     // Pointer-like types.
1355af6ee580SValentin Clement     if (auto eleTy = fir::dyn_cast_ptrEleTy(boxEleTy))
1356af6ee580SValentin Clement       boxEleTy = eleTy;
1357af6ee580SValentin Clement     // Integer types.
1358af6ee580SValentin Clement     if (fir::isa_integer(boxEleTy)) {
1359af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::IntegerType>())
1360af6ee580SValentin Clement         return doInteger(ty.getWidth());
1361af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::IntegerType>();
1362af6ee580SValentin Clement       return doInteger(getKindMap().getIntegerBitsize(ty.getFKind()));
1363af6ee580SValentin Clement     }
1364af6ee580SValentin Clement     // Floating point types.
1365af6ee580SValentin Clement     if (fir::isa_real(boxEleTy)) {
1366af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::FloatType>())
1367af6ee580SValentin Clement         return doFloat(ty.getWidth());
1368af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::RealType>();
1369af6ee580SValentin Clement       return doFloat(getKindMap().getRealBitsize(ty.getFKind()));
1370af6ee580SValentin Clement     }
1371af6ee580SValentin Clement     // Complex types.
1372af6ee580SValentin Clement     if (fir::isa_complex(boxEleTy)) {
1373af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::ComplexType>())
1374af6ee580SValentin Clement         return doComplex(
1375af6ee580SValentin Clement             ty.getElementType().cast<mlir::FloatType>().getWidth());
1376af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::ComplexType>();
1377af6ee580SValentin Clement       return doComplex(getKindMap().getRealBitsize(ty.getFKind()));
1378af6ee580SValentin Clement     }
1379af6ee580SValentin Clement     // Character types.
1380af6ee580SValentin Clement     if (auto ty = boxEleTy.dyn_cast<fir::CharacterType>()) {
1381af6ee580SValentin Clement       auto charWidth = getKindMap().getCharacterBitsize(ty.getFKind());
1382af6ee580SValentin Clement       if (ty.getLen() != fir::CharacterType::unknownLen()) {
1383af6ee580SValentin Clement         auto len = this->genConstantOffset(loc, rewriter, ty.getLen());
1384af6ee580SValentin Clement         return doCharacter(charWidth, len);
1385af6ee580SValentin Clement       }
1386af6ee580SValentin Clement       assert(!lenParams.empty());
1387af6ee580SValentin Clement       return doCharacter(charWidth, lenParams.back());
1388af6ee580SValentin Clement     }
1389af6ee580SValentin Clement     // Logical type.
1390af6ee580SValentin Clement     if (auto ty = boxEleTy.dyn_cast<fir::LogicalType>())
1391af6ee580SValentin Clement       return doLogical(getKindMap().getLogicalBitsize(ty.getFKind()));
1392af6ee580SValentin Clement     // Array types.
1393af6ee580SValentin Clement     if (auto seqTy = boxEleTy.dyn_cast<fir::SequenceType>())
1394af6ee580SValentin Clement       return getSizeAndTypeCode(loc, rewriter, seqTy.getEleTy(), lenParams);
1395af6ee580SValentin Clement     // Derived-type types.
1396af6ee580SValentin Clement     if (boxEleTy.isa<fir::RecordType>()) {
1397af6ee580SValentin Clement       auto ptrTy = mlir::LLVM::LLVMPointerType::get(
1398af6ee580SValentin Clement           this->lowerTy().convertType(boxEleTy));
1399af6ee580SValentin Clement       auto nullPtr = rewriter.create<mlir::LLVM::NullOp>(loc, ptrTy);
1400af6ee580SValentin Clement       auto one =
1401af6ee580SValentin Clement           genConstantIndex(loc, this->lowerTy().offsetType(), rewriter, 1);
1402af6ee580SValentin Clement       auto gep = rewriter.create<mlir::LLVM::GEPOp>(
1403af6ee580SValentin Clement           loc, ptrTy, mlir::ValueRange{nullPtr, one});
1404af6ee580SValentin Clement       auto eleSize = rewriter.create<mlir::LLVM::PtrToIntOp>(
1405af6ee580SValentin Clement           loc, this->lowerTy().indexType(), gep);
1406af6ee580SValentin Clement       return {eleSize,
1407af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, fir::derivedToTypeCode())};
1408af6ee580SValentin Clement     }
1409af6ee580SValentin Clement     // Reference type.
1410af6ee580SValentin Clement     if (fir::isa_ref_type(boxEleTy)) {
1411af6ee580SValentin Clement       // FIXME: use the target pointer size rather than sizeof(void*)
1412af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, sizeof(void *)),
1413af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, CFI_type_cptr)};
1414af6ee580SValentin Clement     }
1415af6ee580SValentin Clement     fir::emitFatalError(loc, "unhandled type in fir.box code generation");
1416af6ee580SValentin Clement   }
1417af6ee580SValentin Clement 
1418af6ee580SValentin Clement   /// Basic pattern to write a field in the descriptor
1419af6ee580SValentin Clement   mlir::Value insertField(mlir::ConversionPatternRewriter &rewriter,
1420af6ee580SValentin Clement                           mlir::Location loc, mlir::Value dest,
1421af6ee580SValentin Clement                           ArrayRef<unsigned> fldIndexes, mlir::Value value,
1422af6ee580SValentin Clement                           bool bitcast = false) const {
1423af6ee580SValentin Clement     auto boxTy = dest.getType();
1424af6ee580SValentin Clement     auto fldTy = this->getBoxEleTy(boxTy, fldIndexes);
1425af6ee580SValentin Clement     if (bitcast)
1426af6ee580SValentin Clement       value = rewriter.create<mlir::LLVM::BitcastOp>(loc, fldTy, value);
1427af6ee580SValentin Clement     else
1428af6ee580SValentin Clement       value = this->integerCast(loc, rewriter, fldTy, value);
1429af6ee580SValentin Clement     SmallVector<mlir::Attribute, 2> attrs;
1430af6ee580SValentin Clement     for (auto i : fldIndexes)
1431af6ee580SValentin Clement       attrs.push_back(rewriter.getI32IntegerAttr(i));
1432af6ee580SValentin Clement     auto indexesAttr = mlir::ArrayAttr::get(rewriter.getContext(), attrs);
1433af6ee580SValentin Clement     return rewriter.create<mlir::LLVM::InsertValueOp>(loc, boxTy, dest, value,
1434af6ee580SValentin Clement                                                       indexesAttr);
1435af6ee580SValentin Clement   }
1436af6ee580SValentin Clement 
1437af6ee580SValentin Clement   inline mlir::Value
1438af6ee580SValentin Clement   insertBaseAddress(mlir::ConversionPatternRewriter &rewriter,
1439af6ee580SValentin Clement                     mlir::Location loc, mlir::Value dest,
1440af6ee580SValentin Clement                     mlir::Value base) const {
1441af6ee580SValentin Clement     return insertField(rewriter, loc, dest, {0}, base, /*bitCast=*/true);
1442af6ee580SValentin Clement   }
1443af6ee580SValentin Clement 
1444af6ee580SValentin Clement   /// Get the address of the type descriptor global variable that was created by
1445af6ee580SValentin Clement   /// lowering for derived type \p recType.
1446af6ee580SValentin Clement   template <typename BOX>
1447af6ee580SValentin Clement   mlir::Value
1448af6ee580SValentin Clement   getTypeDescriptor(BOX box, mlir::ConversionPatternRewriter &rewriter,
1449af6ee580SValentin Clement                     mlir::Location loc, fir::RecordType recType) const {
1450af6ee580SValentin Clement     std::string name = recType.getLoweredName();
1451af6ee580SValentin Clement     auto module = box->template getParentOfType<mlir::ModuleOp>();
1452af6ee580SValentin Clement     if (auto global = module.template lookupSymbol<fir::GlobalOp>(name)) {
1453af6ee580SValentin Clement       auto ty = mlir::LLVM::LLVMPointerType::get(
1454af6ee580SValentin Clement           this->lowerTy().convertType(global.getType()));
1455af6ee580SValentin Clement       return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty,
1456af6ee580SValentin Clement                                                       global.sym_name());
1457af6ee580SValentin Clement     }
1458af6ee580SValentin Clement     if (auto global =
1459af6ee580SValentin Clement             module.template lookupSymbol<mlir::LLVM::GlobalOp>(name)) {
1460af6ee580SValentin Clement       // The global may have already been translated to LLVM.
1461af6ee580SValentin Clement       auto ty = mlir::LLVM::LLVMPointerType::get(global.getType());
1462af6ee580SValentin Clement       return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty,
1463af6ee580SValentin Clement                                                       global.sym_name());
1464af6ee580SValentin Clement     }
1465af6ee580SValentin Clement     // The global does not exist in the current translation unit, but may be
1466af6ee580SValentin Clement     // defined elsewhere (e.g., type defined in a module).
1467af6ee580SValentin Clement     // For now, create a extern_weak symbol (will become nullptr if unresolved)
1468af6ee580SValentin Clement     // to support generating code without the front-end generated symbols.
1469af6ee580SValentin Clement     // These could be made available_externally to require the symbols to be
1470af6ee580SValentin Clement     // defined elsewhere and to cause link-time failure otherwise.
1471af6ee580SValentin Clement     auto i8Ty = rewriter.getIntegerType(8);
1472af6ee580SValentin Clement     mlir::OpBuilder modBuilder(module.getBodyRegion());
1473af6ee580SValentin Clement     // TODO: The symbol should be lowered to constant in lowering, they are read
1474af6ee580SValentin Clement     // only.
1475af6ee580SValentin Clement     modBuilder.create<mlir::LLVM::GlobalOp>(loc, i8Ty, /*isConstant=*/false,
1476af6ee580SValentin Clement                                             mlir::LLVM::Linkage::ExternWeak,
1477af6ee580SValentin Clement                                             name, mlir::Attribute{});
1478af6ee580SValentin Clement     auto ty = mlir::LLVM::LLVMPointerType::get(i8Ty);
1479af6ee580SValentin Clement     return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty, name);
1480af6ee580SValentin Clement   }
1481af6ee580SValentin Clement 
1482af6ee580SValentin Clement   template <typename BOX>
1483af6ee580SValentin Clement   std::tuple<fir::BoxType, mlir::Value, mlir::Value>
1484af6ee580SValentin Clement   consDescriptorPrefix(BOX box, mlir::ConversionPatternRewriter &rewriter,
1485af6ee580SValentin Clement                        unsigned rank, mlir::ValueRange lenParams) const {
1486af6ee580SValentin Clement     auto loc = box.getLoc();
1487af6ee580SValentin Clement     auto boxTy = box.getType().template dyn_cast<fir::BoxType>();
1488af6ee580SValentin Clement     auto convTy = this->lowerTy().convertBoxType(boxTy, rank);
1489af6ee580SValentin Clement     auto llvmBoxPtrTy = convTy.template cast<mlir::LLVM::LLVMPointerType>();
1490af6ee580SValentin Clement     auto llvmBoxTy = llvmBoxPtrTy.getElementType();
1491af6ee580SValentin Clement     mlir::Value descriptor =
1492af6ee580SValentin Clement         rewriter.create<mlir::LLVM::UndefOp>(loc, llvmBoxTy);
1493af6ee580SValentin Clement 
1494af6ee580SValentin Clement     llvm::SmallVector<mlir::Value> typeparams = lenParams;
1495af6ee580SValentin Clement     if constexpr (!std::is_same_v<BOX, fir::EmboxOp>) {
1496af6ee580SValentin Clement       if (!box.substr().empty() && fir::hasDynamicSize(boxTy.getEleTy()))
1497af6ee580SValentin Clement         typeparams.push_back(box.substr()[1]);
1498af6ee580SValentin Clement     }
1499af6ee580SValentin Clement 
1500af6ee580SValentin Clement     // Write each of the fields with the appropriate values
1501af6ee580SValentin Clement     auto [eleSize, cfiTy] =
1502af6ee580SValentin Clement         getSizeAndTypeCode(loc, rewriter, boxTy.getEleTy(), typeparams);
1503af6ee580SValentin Clement     descriptor =
1504af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kElemLenPosInBox}, eleSize);
1505af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kVersionPosInBox},
1506af6ee580SValentin Clement                              this->genI32Constant(loc, rewriter, CFI_VERSION));
1507af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kRankPosInBox},
1508af6ee580SValentin Clement                              this->genI32Constant(loc, rewriter, rank));
1509af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kTypePosInBox}, cfiTy);
1510af6ee580SValentin Clement     descriptor =
1511af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kAttributePosInBox},
1512af6ee580SValentin Clement                     this->genI32Constant(loc, rewriter, getCFIAttr(boxTy)));
1513af6ee580SValentin Clement     const bool hasAddendum = isDerivedType(boxTy);
1514af6ee580SValentin Clement     descriptor =
1515af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kF18AddendumPosInBox},
1516af6ee580SValentin Clement                     this->genI32Constant(loc, rewriter, hasAddendum ? 1 : 0));
1517af6ee580SValentin Clement 
1518af6ee580SValentin Clement     if (hasAddendum) {
1519af6ee580SValentin Clement       auto isArray =
1520af6ee580SValentin Clement           fir::dyn_cast_ptrOrBoxEleTy(boxTy).template isa<fir::SequenceType>();
1521af6ee580SValentin Clement       unsigned typeDescFieldId = isArray ? kOptTypePtrPosInBox : kDimsPosInBox;
1522af6ee580SValentin Clement       auto typeDesc =
1523af6ee580SValentin Clement           getTypeDescriptor(box, rewriter, loc, unwrapIfDerived(boxTy));
1524af6ee580SValentin Clement       descriptor =
1525af6ee580SValentin Clement           insertField(rewriter, loc, descriptor, {typeDescFieldId}, typeDesc,
1526af6ee580SValentin Clement                       /*bitCast=*/true);
1527af6ee580SValentin Clement     }
1528af6ee580SValentin Clement 
1529af6ee580SValentin Clement     return {boxTy, descriptor, eleSize};
1530af6ee580SValentin Clement   }
1531af6ee580SValentin Clement 
1532af6ee580SValentin Clement   /// If the embox is not in a globalOp body, allocate storage for the box;
1533af6ee580SValentin Clement   /// store the value inside and return the generated alloca. Return the input
1534af6ee580SValentin Clement   /// value otherwise.
1535af6ee580SValentin Clement   mlir::Value
1536af6ee580SValentin Clement   placeInMemoryIfNotGlobalInit(mlir::ConversionPatternRewriter &rewriter,
1537af6ee580SValentin Clement                                mlir::Location loc, mlir::Value boxValue) const {
1538af6ee580SValentin Clement     auto *thisBlock = rewriter.getInsertionBlock();
1539af6ee580SValentin Clement     if (thisBlock && mlir::isa<mlir::LLVM::GlobalOp>(thisBlock->getParentOp()))
1540af6ee580SValentin Clement       return boxValue;
1541af6ee580SValentin Clement     auto boxPtrTy = mlir::LLVM::LLVMPointerType::get(boxValue.getType());
1542af6ee580SValentin Clement     auto alloca = genAllocaWithType(loc, boxPtrTy, defaultAlign, rewriter);
1543af6ee580SValentin Clement     rewriter.create<mlir::LLVM::StoreOp>(loc, boxValue, alloca);
1544af6ee580SValentin Clement     return alloca;
1545af6ee580SValentin Clement   }
1546af6ee580SValentin Clement };
1547af6ee580SValentin Clement 
1548af6ee580SValentin Clement /// Create a generic box on a memory reference. This conversions lowers the
1549af6ee580SValentin Clement /// abstract box to the appropriate, initialized descriptor.
1550af6ee580SValentin Clement struct EmboxOpConversion : public EmboxCommonConversion<fir::EmboxOp> {
1551af6ee580SValentin Clement   using EmboxCommonConversion::EmboxCommonConversion;
1552af6ee580SValentin Clement 
1553af6ee580SValentin Clement   mlir::LogicalResult
1554af6ee580SValentin Clement   matchAndRewrite(fir::EmboxOp embox, OpAdaptor adaptor,
1555af6ee580SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1556af6ee580SValentin Clement     assert(!embox.getShape() && "There should be no dims on this embox op");
1557af6ee580SValentin Clement     auto [boxTy, dest, eleSize] =
1558af6ee580SValentin Clement         consDescriptorPrefix(embox, rewriter, /*rank=*/0,
1559af6ee580SValentin Clement                              /*lenParams=*/adaptor.getOperands().drop_front(1));
1560af6ee580SValentin Clement     dest = insertBaseAddress(rewriter, embox.getLoc(), dest,
1561af6ee580SValentin Clement                              adaptor.getOperands()[0]);
1562af6ee580SValentin Clement     if (isDerivedTypeWithLenParams(boxTy))
1563af6ee580SValentin Clement       return rewriter.notifyMatchFailure(
1564af6ee580SValentin Clement           embox, "fir.embox codegen of derived with length parameters not "
1565af6ee580SValentin Clement                  "implemented yet");
1566af6ee580SValentin Clement     auto result = placeInMemoryIfNotGlobalInit(rewriter, embox.getLoc(), dest);
1567af6ee580SValentin Clement     rewriter.replaceOp(embox, result);
1568af6ee580SValentin Clement     return success();
1569af6ee580SValentin Clement   }
1570af6ee580SValentin Clement };
1571af6ee580SValentin Clement 
1572cc505c0bSKiran Chandramohan /// Lower `fir.emboxproc` operation. Creates a procedure box.
1573cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
1574cc505c0bSKiran Chandramohan struct EmboxProcOpConversion : public FIROpConversion<fir::EmboxProcOp> {
1575cc505c0bSKiran Chandramohan   using FIROpConversion::FIROpConversion;
1576cc505c0bSKiran Chandramohan 
1577cc505c0bSKiran Chandramohan   mlir::LogicalResult
1578cc505c0bSKiran Chandramohan   matchAndRewrite(fir::EmboxProcOp emboxproc, OpAdaptor adaptor,
1579cc505c0bSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
1580cc505c0bSKiran Chandramohan     return rewriter.notifyMatchFailure(
1581cc505c0bSKiran Chandramohan         emboxproc, "fir.emboxproc codegen is not implemented yet");
1582cc505c0bSKiran Chandramohan   }
1583cc505c0bSKiran Chandramohan };
1584cc505c0bSKiran Chandramohan 
1585cc505c0bSKiran Chandramohan 
158654c56347SValentin Clement // Code shared between insert_value and extract_value Ops.
158754c56347SValentin Clement struct ValueOpCommon {
158854c56347SValentin Clement   // Translate the arguments pertaining to any multidimensional array to
158954c56347SValentin Clement   // row-major order for LLVM-IR.
159054c56347SValentin Clement   static void toRowMajor(SmallVectorImpl<mlir::Attribute> &attrs,
159154c56347SValentin Clement                          mlir::Type ty) {
159254c56347SValentin Clement     assert(ty && "type is null");
159354c56347SValentin Clement     const auto end = attrs.size();
159454c56347SValentin Clement     for (std::remove_const_t<decltype(end)> i = 0; i < end; ++i) {
159554c56347SValentin Clement       if (auto seq = ty.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
159654c56347SValentin Clement         const auto dim = getDimension(seq);
159754c56347SValentin Clement         if (dim > 1) {
159854c56347SValentin Clement           auto ub = std::min(i + dim, end);
159954c56347SValentin Clement           std::reverse(attrs.begin() + i, attrs.begin() + ub);
160054c56347SValentin Clement           i += dim - 1;
160154c56347SValentin Clement         }
160254c56347SValentin Clement         ty = getArrayElementType(seq);
160354c56347SValentin Clement       } else if (auto st = ty.dyn_cast<mlir::LLVM::LLVMStructType>()) {
160454c56347SValentin Clement         ty = st.getBody()[attrs[i].cast<mlir::IntegerAttr>().getInt()];
160554c56347SValentin Clement       } else {
160654c56347SValentin Clement         llvm_unreachable("index into invalid type");
160754c56347SValentin Clement       }
160854c56347SValentin Clement     }
160954c56347SValentin Clement   }
161054c56347SValentin Clement 
161154c56347SValentin Clement   static llvm::SmallVector<mlir::Attribute>
161254c56347SValentin Clement   collectIndices(mlir::ConversionPatternRewriter &rewriter,
161354c56347SValentin Clement                  mlir::ArrayAttr arrAttr) {
161454c56347SValentin Clement     llvm::SmallVector<mlir::Attribute> attrs;
161554c56347SValentin Clement     for (auto i = arrAttr.begin(), e = arrAttr.end(); i != e; ++i) {
161654c56347SValentin Clement       if (i->isa<mlir::IntegerAttr>()) {
161754c56347SValentin Clement         attrs.push_back(*i);
161854c56347SValentin Clement       } else {
161954c56347SValentin Clement         auto fieldName = i->cast<mlir::StringAttr>().getValue();
162054c56347SValentin Clement         ++i;
162154c56347SValentin Clement         auto ty = i->cast<mlir::TypeAttr>().getValue();
162254c56347SValentin Clement         auto index = ty.cast<fir::RecordType>().getFieldIndex(fieldName);
162354c56347SValentin Clement         attrs.push_back(mlir::IntegerAttr::get(rewriter.getI32Type(), index));
162454c56347SValentin Clement       }
162554c56347SValentin Clement     }
162654c56347SValentin Clement     return attrs;
162754c56347SValentin Clement   }
162854c56347SValentin Clement 
162954c56347SValentin Clement private:
163054c56347SValentin Clement   static unsigned getDimension(mlir::LLVM::LLVMArrayType ty) {
163154c56347SValentin Clement     unsigned result = 1;
163254c56347SValentin Clement     for (auto eleTy = ty.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>();
163354c56347SValentin Clement          eleTy;
163454c56347SValentin Clement          eleTy = eleTy.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>())
163554c56347SValentin Clement       ++result;
163654c56347SValentin Clement     return result;
163754c56347SValentin Clement   }
163854c56347SValentin Clement 
163954c56347SValentin Clement   static mlir::Type getArrayElementType(mlir::LLVM::LLVMArrayType ty) {
164054c56347SValentin Clement     auto eleTy = ty.getElementType();
164154c56347SValentin Clement     while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>())
164254c56347SValentin Clement       eleTy = arrTy.getElementType();
164354c56347SValentin Clement     return eleTy;
164454c56347SValentin Clement   }
164554c56347SValentin Clement };
164654c56347SValentin Clement 
164754c56347SValentin Clement /// Extract a subobject value from an ssa-value of aggregate type
164854c56347SValentin Clement struct ExtractValueOpConversion
164954c56347SValentin Clement     : public FIROpAndTypeConversion<fir::ExtractValueOp>,
165054c56347SValentin Clement       public ValueOpCommon {
165154c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
165254c56347SValentin Clement 
165354c56347SValentin Clement   mlir::LogicalResult
165454c56347SValentin Clement   doRewrite(fir::ExtractValueOp extractVal, mlir::Type ty, OpAdaptor adaptor,
165554c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
165654c56347SValentin Clement     auto attrs = collectIndices(rewriter, extractVal.coor());
165754c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
165854c56347SValentin Clement     auto position = mlir::ArrayAttr::get(extractVal.getContext(), attrs);
165954c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(
166054c56347SValentin Clement         extractVal, ty, adaptor.getOperands()[0], position);
166154c56347SValentin Clement     return success();
166254c56347SValentin Clement   }
166354c56347SValentin Clement };
166454c56347SValentin Clement 
166554c56347SValentin Clement /// InsertValue is the generalized instruction for the composition of new
166654c56347SValentin Clement /// aggregate type values.
166754c56347SValentin Clement struct InsertValueOpConversion
166854c56347SValentin Clement     : public FIROpAndTypeConversion<fir::InsertValueOp>,
166954c56347SValentin Clement       public ValueOpCommon {
167054c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
167154c56347SValentin Clement 
167254c56347SValentin Clement   mlir::LogicalResult
167354c56347SValentin Clement   doRewrite(fir::InsertValueOp insertVal, mlir::Type ty, OpAdaptor adaptor,
167454c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
167554c56347SValentin Clement     auto attrs = collectIndices(rewriter, insertVal.coor());
167654c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
167754c56347SValentin Clement     auto position = mlir::ArrayAttr::get(insertVal.getContext(), attrs);
167854c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
167954c56347SValentin Clement         insertVal, ty, adaptor.getOperands()[0], adaptor.getOperands()[1],
168054c56347SValentin Clement         position);
168154c56347SValentin Clement     return success();
168254c56347SValentin Clement   }
168354c56347SValentin Clement };
168454c56347SValentin Clement 
16853ae8e442SValentin Clement /// InsertOnRange inserts a value into a sequence over a range of offsets.
16863ae8e442SValentin Clement struct InsertOnRangeOpConversion
16873ae8e442SValentin Clement     : public FIROpAndTypeConversion<fir::InsertOnRangeOp> {
16883ae8e442SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
16893ae8e442SValentin Clement 
16903ae8e442SValentin Clement   // Increments an array of subscripts in a row major fasion.
16913ae8e442SValentin Clement   void incrementSubscripts(const SmallVector<uint64_t> &dims,
16923ae8e442SValentin Clement                            SmallVector<uint64_t> &subscripts) const {
16933ae8e442SValentin Clement     for (size_t i = dims.size(); i > 0; --i) {
16943ae8e442SValentin Clement       if (++subscripts[i - 1] < dims[i - 1]) {
16953ae8e442SValentin Clement         return;
16963ae8e442SValentin Clement       }
16973ae8e442SValentin Clement       subscripts[i - 1] = 0;
16983ae8e442SValentin Clement     }
16993ae8e442SValentin Clement   }
17003ae8e442SValentin Clement 
17013ae8e442SValentin Clement   mlir::LogicalResult
17023ae8e442SValentin Clement   doRewrite(fir::InsertOnRangeOp range, mlir::Type ty, OpAdaptor adaptor,
17033ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
17043ae8e442SValentin Clement 
17053ae8e442SValentin Clement     llvm::SmallVector<uint64_t> dims;
17063ae8e442SValentin Clement     auto type = adaptor.getOperands()[0].getType();
17073ae8e442SValentin Clement 
17083ae8e442SValentin Clement     // Iteratively extract the array dimensions from the type.
17093ae8e442SValentin Clement     while (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
17103ae8e442SValentin Clement       dims.push_back(t.getNumElements());
17113ae8e442SValentin Clement       type = t.getElementType();
17123ae8e442SValentin Clement     }
17133ae8e442SValentin Clement 
17143ae8e442SValentin Clement     SmallVector<uint64_t> lBounds;
17153ae8e442SValentin Clement     SmallVector<uint64_t> uBounds;
17163ae8e442SValentin Clement 
17173ae8e442SValentin Clement     // Extract integer value from the attribute
17183ae8e442SValentin Clement     SmallVector<int64_t> coordinates = llvm::to_vector<4>(
17193ae8e442SValentin Clement         llvm::map_range(range.coor(), [](Attribute a) -> int64_t {
17203ae8e442SValentin Clement           return a.cast<IntegerAttr>().getInt();
17213ae8e442SValentin Clement         }));
17223ae8e442SValentin Clement 
17233ae8e442SValentin Clement     // Unzip the upper and lower bound and convert to a row major format.
17243ae8e442SValentin Clement     for (auto i = coordinates.rbegin(), e = coordinates.rend(); i != e; ++i) {
17253ae8e442SValentin Clement       uBounds.push_back(*i++);
17263ae8e442SValentin Clement       lBounds.push_back(*i);
17273ae8e442SValentin Clement     }
17283ae8e442SValentin Clement 
17293ae8e442SValentin Clement     auto &subscripts = lBounds;
17303ae8e442SValentin Clement     auto loc = range.getLoc();
17313ae8e442SValentin Clement     mlir::Value lastOp = adaptor.getOperands()[0];
17323ae8e442SValentin Clement     mlir::Value insertVal = adaptor.getOperands()[1];
17333ae8e442SValentin Clement 
17343ae8e442SValentin Clement     auto i64Ty = rewriter.getI64Type();
17353ae8e442SValentin Clement     while (subscripts != uBounds) {
17363ae8e442SValentin Clement       // Convert uint64_t's to Attribute's.
17373ae8e442SValentin Clement       SmallVector<mlir::Attribute> subscriptAttrs;
17383ae8e442SValentin Clement       for (const auto &subscript : subscripts)
17393ae8e442SValentin Clement         subscriptAttrs.push_back(IntegerAttr::get(i64Ty, subscript));
17403ae8e442SValentin Clement       lastOp = rewriter.create<mlir::LLVM::InsertValueOp>(
17413ae8e442SValentin Clement           loc, ty, lastOp, insertVal,
17423ae8e442SValentin Clement           ArrayAttr::get(range.getContext(), subscriptAttrs));
17433ae8e442SValentin Clement 
17443ae8e442SValentin Clement       incrementSubscripts(dims, subscripts);
17453ae8e442SValentin Clement     }
17463ae8e442SValentin Clement 
17473ae8e442SValentin Clement     // Convert uint64_t's to Attribute's.
17483ae8e442SValentin Clement     SmallVector<mlir::Attribute> subscriptAttrs;
17493ae8e442SValentin Clement     for (const auto &subscript : subscripts)
17503ae8e442SValentin Clement       subscriptAttrs.push_back(
17513ae8e442SValentin Clement           IntegerAttr::get(rewriter.getI64Type(), subscript));
17523ae8e442SValentin Clement     mlir::ArrayRef<mlir::Attribute> arrayRef(subscriptAttrs);
17533ae8e442SValentin Clement 
17543ae8e442SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
17553ae8e442SValentin Clement         range, ty, lastOp, insertVal,
17563ae8e442SValentin Clement         ArrayAttr::get(range.getContext(), arrayRef));
17573ae8e442SValentin Clement 
17583ae8e442SValentin Clement     return success();
17593ae8e442SValentin Clement   }
17603ae8e442SValentin Clement };
17617b5132daSValentin Clement 
17627b5132daSValentin Clement //
17637b5132daSValentin Clement // Primitive operations on Complex types
17647b5132daSValentin Clement //
17657b5132daSValentin Clement 
17667b5132daSValentin Clement /// Generate inline code for complex addition/subtraction
17677b5132daSValentin Clement template <typename LLVMOP, typename OPTY>
17687b5132daSValentin Clement mlir::LLVM::InsertValueOp complexSum(OPTY sumop, mlir::ValueRange opnds,
17697b5132daSValentin Clement                                      mlir::ConversionPatternRewriter &rewriter,
17707b5132daSValentin Clement                                      fir::LLVMTypeConverter &lowering) {
17717b5132daSValentin Clement   mlir::Value a = opnds[0];
17727b5132daSValentin Clement   mlir::Value b = opnds[1];
17737b5132daSValentin Clement   auto loc = sumop.getLoc();
17747b5132daSValentin Clement   auto ctx = sumop.getContext();
17757b5132daSValentin Clement   auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
17767b5132daSValentin Clement   auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
17777b5132daSValentin Clement   mlir::Type eleTy = lowering.convertType(getComplexEleTy(sumop.getType()));
17787b5132daSValentin Clement   mlir::Type ty = lowering.convertType(sumop.getType());
17797b5132daSValentin Clement   auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
17807b5132daSValentin Clement   auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
17817b5132daSValentin Clement   auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
17827b5132daSValentin Clement   auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
17837b5132daSValentin Clement   auto rx = rewriter.create<LLVMOP>(loc, eleTy, x0, x1);
17847b5132daSValentin Clement   auto ry = rewriter.create<LLVMOP>(loc, eleTy, y0, y1);
17857b5132daSValentin Clement   auto r0 = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
17867b5132daSValentin Clement   auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r0, rx, c0);
17877b5132daSValentin Clement   return rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ry, c1);
17887b5132daSValentin Clement }
17897b5132daSValentin Clement 
17907b5132daSValentin Clement struct AddcOpConversion : public FIROpConversion<fir::AddcOp> {
17917b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
17927b5132daSValentin Clement 
17937b5132daSValentin Clement   mlir::LogicalResult
17947b5132daSValentin Clement   matchAndRewrite(fir::AddcOp addc, OpAdaptor adaptor,
17957b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
17967b5132daSValentin Clement     // given: (x + iy) + (x' + iy')
17977b5132daSValentin Clement     // result: (x + x') + i(y + y')
17987b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FAddOp>(addc, adaptor.getOperands(),
17997b5132daSValentin Clement                                             rewriter, lowerTy());
18007b5132daSValentin Clement     rewriter.replaceOp(addc, r.getResult());
18017b5132daSValentin Clement     return success();
18027b5132daSValentin Clement   }
18037b5132daSValentin Clement };
18047b5132daSValentin Clement 
18057b5132daSValentin Clement struct SubcOpConversion : public FIROpConversion<fir::SubcOp> {
18067b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
18077b5132daSValentin Clement 
18087b5132daSValentin Clement   mlir::LogicalResult
18097b5132daSValentin Clement   matchAndRewrite(fir::SubcOp subc, OpAdaptor adaptor,
18107b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
18117b5132daSValentin Clement     // given: (x + iy) - (x' + iy')
18127b5132daSValentin Clement     // result: (x - x') + i(y - y')
18137b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FSubOp>(subc, adaptor.getOperands(),
18147b5132daSValentin Clement                                             rewriter, lowerTy());
18157b5132daSValentin Clement     rewriter.replaceOp(subc, r.getResult());
18167b5132daSValentin Clement     return success();
18177b5132daSValentin Clement   }
18187b5132daSValentin Clement };
18197b5132daSValentin Clement 
18207b5132daSValentin Clement /// Inlined complex multiply
18217b5132daSValentin Clement struct MulcOpConversion : public FIROpConversion<fir::MulcOp> {
18227b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
18237b5132daSValentin Clement 
18247b5132daSValentin Clement   mlir::LogicalResult
18257b5132daSValentin Clement   matchAndRewrite(fir::MulcOp mulc, OpAdaptor adaptor,
18267b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
18277b5132daSValentin Clement     // TODO: Can we use a call to __muldc3 ?
18287b5132daSValentin Clement     // given: (x + iy) * (x' + iy')
18297b5132daSValentin Clement     // result: (xx'-yy')+i(xy'+yx')
18307b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
18317b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
18327b5132daSValentin Clement     auto loc = mulc.getLoc();
18337b5132daSValentin Clement     auto *ctx = mulc.getContext();
18347b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
18357b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
18367b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(mulc.getType()));
18377b5132daSValentin Clement     mlir::Type ty = convertType(mulc.getType());
18387b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
18397b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
18407b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
18417b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
18427b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
18437b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
18447b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
18457b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xy, yx);
18467b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
18477b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, xx, yy);
18487b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
18497b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
18507b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
18517b5132daSValentin Clement     rewriter.replaceOp(mulc, r0.getResult());
18527b5132daSValentin Clement     return success();
18537b5132daSValentin Clement   }
18547b5132daSValentin Clement };
18557b5132daSValentin Clement 
18567b5132daSValentin Clement /// Inlined complex division
18577b5132daSValentin Clement struct DivcOpConversion : public FIROpConversion<fir::DivcOp> {
18587b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
18597b5132daSValentin Clement 
18607b5132daSValentin Clement   mlir::LogicalResult
18617b5132daSValentin Clement   matchAndRewrite(fir::DivcOp divc, OpAdaptor adaptor,
18627b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
18637b5132daSValentin Clement     // TODO: Can we use a call to __divdc3 instead?
18647b5132daSValentin Clement     // Just generate inline code for now.
18657b5132daSValentin Clement     // given: (x + iy) / (x' + iy')
18667b5132daSValentin Clement     // result: ((xx'+yy')/d) + i((yx'-xy')/d) where d = x'x' + y'y'
18677b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
18687b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
18697b5132daSValentin Clement     auto loc = divc.getLoc();
18707b5132daSValentin Clement     auto *ctx = divc.getContext();
18717b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
18727b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
18737b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(divc.getType()));
18747b5132daSValentin Clement     mlir::Type ty = convertType(divc.getType());
18757b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
18767b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
18777b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
18787b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
18797b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
18807b5132daSValentin Clement     auto x1x1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x1, x1);
18817b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
18827b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
18837b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
18847b5132daSValentin Clement     auto y1y1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y1, y1);
18857b5132daSValentin Clement     auto d = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, x1x1, y1y1);
18867b5132daSValentin Clement     auto rrn = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xx, yy);
18877b5132daSValentin Clement     auto rin = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, yx, xy);
18887b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rrn, d);
18897b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rin, d);
18907b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
18917b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
18927b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
18937b5132daSValentin Clement     rewriter.replaceOp(divc, r0.getResult());
18947b5132daSValentin Clement     return success();
18957b5132daSValentin Clement   }
18967b5132daSValentin Clement };
18977b5132daSValentin Clement 
18987b5132daSValentin Clement /// Inlined complex negation
18997b5132daSValentin Clement struct NegcOpConversion : public FIROpConversion<fir::NegcOp> {
19007b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
19017b5132daSValentin Clement 
19027b5132daSValentin Clement   mlir::LogicalResult
19037b5132daSValentin Clement   matchAndRewrite(fir::NegcOp neg, OpAdaptor adaptor,
19047b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
19057b5132daSValentin Clement     // given: -(x + iy)
19067b5132daSValentin Clement     // result: -x - iy
19077b5132daSValentin Clement     auto *ctxt = neg.getContext();
19087b5132daSValentin Clement     auto eleTy = convertType(getComplexEleTy(neg.getType()));
19097b5132daSValentin Clement     auto ty = convertType(neg.getType());
19107b5132daSValentin Clement     auto loc = neg.getLoc();
19117b5132daSValentin Clement     mlir::Value o0 = adaptor.getOperands()[0];
19127b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0));
19137b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1));
19147b5132daSValentin Clement     auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c0);
19157b5132daSValentin Clement     auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c1);
19167b5132daSValentin Clement     auto nrp = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, rp);
19177b5132daSValentin Clement     auto nip = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, ip);
19187b5132daSValentin Clement     auto r = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, o0, nrp, c0);
19197b5132daSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(neg, ty, r, nip, c1);
19207b5132daSValentin Clement     return success();
19217b5132daSValentin Clement   }
19227b5132daSValentin Clement };
19237b5132daSValentin Clement 
19241ed5a90fSValentin Clement /// Conversion pattern for operation that must be dead. The information in these
19251ed5a90fSValentin Clement /// operations is used by other operation. At this point they should not have
19261ed5a90fSValentin Clement /// anymore uses.
19271ed5a90fSValentin Clement /// These operations are normally dead after the pre-codegen pass.
19281ed5a90fSValentin Clement template <typename FromOp>
19291ed5a90fSValentin Clement struct MustBeDeadConversion : public FIROpConversion<FromOp> {
19301ed5a90fSValentin Clement   explicit MustBeDeadConversion(fir::LLVMTypeConverter &lowering)
19311ed5a90fSValentin Clement       : FIROpConversion<FromOp>(lowering) {}
19321ed5a90fSValentin Clement   using OpAdaptor = typename FromOp::Adaptor;
19331ed5a90fSValentin Clement 
19341ed5a90fSValentin Clement   mlir::LogicalResult
19351ed5a90fSValentin Clement   matchAndRewrite(FromOp op, OpAdaptor adaptor,
19361ed5a90fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const final {
19371ed5a90fSValentin Clement     if (!op->getUses().empty())
19381ed5a90fSValentin Clement       return rewriter.notifyMatchFailure(op, "op must be dead");
19391ed5a90fSValentin Clement     rewriter.eraseOp(op);
19401ed5a90fSValentin Clement     return success();
19411ed5a90fSValentin Clement   }
19421ed5a90fSValentin Clement };
19431ed5a90fSValentin Clement 
19441ed5a90fSValentin Clement struct ShapeOpConversion : public MustBeDeadConversion<fir::ShapeOp> {
19451ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
19461ed5a90fSValentin Clement };
19471ed5a90fSValentin Clement 
19481ed5a90fSValentin Clement struct ShapeShiftOpConversion : public MustBeDeadConversion<fir::ShapeShiftOp> {
19491ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
19501ed5a90fSValentin Clement };
19511ed5a90fSValentin Clement 
19521ed5a90fSValentin Clement struct ShiftOpConversion : public MustBeDeadConversion<fir::ShiftOp> {
19531ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
19541ed5a90fSValentin Clement };
19551ed5a90fSValentin Clement 
19561ed5a90fSValentin Clement struct SliceOpConversion : public MustBeDeadConversion<fir::SliceOp> {
19571ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
19581ed5a90fSValentin Clement };
19591ed5a90fSValentin Clement 
1960420ad7ceSAndrzej Warzynski /// `fir.is_present` -->
1961420ad7ceSAndrzej Warzynski /// ```
1962420ad7ceSAndrzej Warzynski ///  %0 = llvm.mlir.constant(0 : i64)
1963420ad7ceSAndrzej Warzynski ///  %1 = llvm.ptrtoint %0
1964420ad7ceSAndrzej Warzynski ///  %2 = llvm.icmp "ne" %1, %0 : i64
1965420ad7ceSAndrzej Warzynski /// ```
1966420ad7ceSAndrzej Warzynski struct IsPresentOpConversion : public FIROpConversion<fir::IsPresentOp> {
1967420ad7ceSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
1968420ad7ceSAndrzej Warzynski 
1969420ad7ceSAndrzej Warzynski   mlir::LogicalResult
1970420ad7ceSAndrzej Warzynski   matchAndRewrite(fir::IsPresentOp isPresent, OpAdaptor adaptor,
1971420ad7ceSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
1972420ad7ceSAndrzej Warzynski     mlir::Type idxTy = lowerTy().indexType();
1973420ad7ceSAndrzej Warzynski     mlir::Location loc = isPresent.getLoc();
1974420ad7ceSAndrzej Warzynski     auto ptr = adaptor.getOperands()[0];
1975420ad7ceSAndrzej Warzynski 
1976420ad7ceSAndrzej Warzynski     if (isPresent.val().getType().isa<fir::BoxCharType>()) {
1977420ad7ceSAndrzej Warzynski       auto structTy = ptr.getType().cast<mlir::LLVM::LLVMStructType>();
1978420ad7ceSAndrzej Warzynski       assert(!structTy.isOpaque() && !structTy.getBody().empty());
1979420ad7ceSAndrzej Warzynski 
1980420ad7ceSAndrzej Warzynski       mlir::Type ty = structTy.getBody()[0];
1981420ad7ceSAndrzej Warzynski       mlir::MLIRContext *ctx = isPresent.getContext();
1982420ad7ceSAndrzej Warzynski       auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
1983420ad7ceSAndrzej Warzynski       ptr = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, ptr, c0);
1984420ad7ceSAndrzej Warzynski     }
1985420ad7ceSAndrzej Warzynski     mlir::LLVM::ConstantOp c0 =
1986420ad7ceSAndrzej Warzynski         genConstantIndex(isPresent.getLoc(), idxTy, rewriter, 0);
1987420ad7ceSAndrzej Warzynski     auto addr = rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, ptr);
1988420ad7ceSAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
1989420ad7ceSAndrzej Warzynski         isPresent, mlir::LLVM::ICmpPredicate::ne, addr, c0);
1990420ad7ceSAndrzej Warzynski 
1991420ad7ceSAndrzej Warzynski     return success();
1992420ad7ceSAndrzej Warzynski   }
1993420ad7ceSAndrzej Warzynski };
19941e77b095SAndrzej Warzynski 
19951e77b095SAndrzej Warzynski /// Convert `!fir.emboxchar<!fir.char<KIND, ?>, #n>` into a sequence of
19961e77b095SAndrzej Warzynski /// instructions that generate `!llvm.struct<(ptr<ik>, i64)>`. The 1st element
19971e77b095SAndrzej Warzynski /// in this struct is a pointer. Its type is determined from `KIND`. The 2nd
19981e77b095SAndrzej Warzynski /// element is the length of the character buffer (`#n`).
19991e77b095SAndrzej Warzynski struct EmboxCharOpConversion : public FIROpConversion<fir::EmboxCharOp> {
20001e77b095SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
20011e77b095SAndrzej Warzynski 
20021e77b095SAndrzej Warzynski   mlir::LogicalResult
20031e77b095SAndrzej Warzynski   matchAndRewrite(fir::EmboxCharOp emboxChar, OpAdaptor adaptor,
20041e77b095SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
20051e77b095SAndrzej Warzynski     mlir::ValueRange operands = adaptor.getOperands();
20061e77b095SAndrzej Warzynski     MLIRContext *ctx = emboxChar.getContext();
20071e77b095SAndrzej Warzynski 
20081e77b095SAndrzej Warzynski     mlir::Value charBuffer = operands[0];
20091e77b095SAndrzej Warzynski     mlir::Value charBufferLen = operands[1];
20101e77b095SAndrzej Warzynski 
20111e77b095SAndrzej Warzynski     mlir::Location loc = emboxChar.getLoc();
20121e77b095SAndrzej Warzynski     mlir::Type llvmStructTy = convertType(emboxChar.getType());
20131e77b095SAndrzej Warzynski     auto llvmStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, llvmStructTy);
20141e77b095SAndrzej Warzynski 
20151e77b095SAndrzej Warzynski     mlir::Type lenTy =
20161e77b095SAndrzej Warzynski         llvmStructTy.cast<mlir::LLVM::LLVMStructType>().getBody()[1];
20171e77b095SAndrzej Warzynski     mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, charBufferLen);
20181e77b095SAndrzej Warzynski 
20191e77b095SAndrzej Warzynski     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
20201e77b095SAndrzej Warzynski     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
20211e77b095SAndrzej Warzynski     auto insertBufferOp = rewriter.create<mlir::LLVM::InsertValueOp>(
20221e77b095SAndrzej Warzynski         loc, llvmStructTy, llvmStruct, charBuffer, c0);
20231e77b095SAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
20241e77b095SAndrzej Warzynski         emboxChar, llvmStructTy, insertBufferOp, lenAfterCast, c1);
20251e77b095SAndrzej Warzynski 
20261e77b095SAndrzej Warzynski     return success();
20271e77b095SAndrzej Warzynski   }
20281e77b095SAndrzej Warzynski };
202914867ffcSAndrzej Warzynski 
203014867ffcSAndrzej Warzynski /// Construct an `llvm.extractvalue` instruction. It will return value at
203114867ffcSAndrzej Warzynski /// element \p x from  \p tuple.
203214867ffcSAndrzej Warzynski mlir::LLVM::ExtractValueOp
203314867ffcSAndrzej Warzynski genExtractValueWithIndex(mlir::Location loc, mlir::Value tuple, mlir::Type ty,
203414867ffcSAndrzej Warzynski                          mlir::ConversionPatternRewriter &rewriter,
203514867ffcSAndrzej Warzynski                          mlir::MLIRContext *ctx, int x) {
203614867ffcSAndrzej Warzynski   auto cx = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(x));
203714867ffcSAndrzej Warzynski   auto xty = ty.cast<mlir::LLVM::LLVMStructType>().getBody()[x];
203814867ffcSAndrzej Warzynski   return rewriter.create<mlir::LLVM::ExtractValueOp>(loc, xty, tuple, cx);
203914867ffcSAndrzej Warzynski }
204014867ffcSAndrzej Warzynski 
20416c3d7fd4SAndrzej Warzynski /// Convert `!fir.boxchar_len` to  `!llvm.extractvalue` for the 2nd part of the
20426c3d7fd4SAndrzej Warzynski /// boxchar.
20436c3d7fd4SAndrzej Warzynski struct BoxCharLenOpConversion : public FIROpConversion<fir::BoxCharLenOp> {
20446c3d7fd4SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
20456c3d7fd4SAndrzej Warzynski 
20466c3d7fd4SAndrzej Warzynski   mlir::LogicalResult
20476c3d7fd4SAndrzej Warzynski   matchAndRewrite(fir::BoxCharLenOp boxCharLen, OpAdaptor adaptor,
20486c3d7fd4SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
20496c3d7fd4SAndrzej Warzynski     mlir::Value boxChar = adaptor.getOperands()[0];
20506c3d7fd4SAndrzej Warzynski     mlir::Location loc = boxChar.getLoc();
20516c3d7fd4SAndrzej Warzynski     mlir::MLIRContext *ctx = boxChar.getContext();
20526c3d7fd4SAndrzej Warzynski     mlir::Type returnValTy = boxCharLen.getResult().getType();
20536c3d7fd4SAndrzej Warzynski 
20546c3d7fd4SAndrzej Warzynski     constexpr int boxcharLenIdx = 1;
20556c3d7fd4SAndrzej Warzynski     mlir::LLVM::ExtractValueOp len = genExtractValueWithIndex(
20566c3d7fd4SAndrzej Warzynski         loc, boxChar, boxChar.getType(), rewriter, ctx, boxcharLenIdx);
20576c3d7fd4SAndrzej Warzynski     mlir::Value lenAfterCast = integerCast(loc, rewriter, returnValTy, len);
20586c3d7fd4SAndrzej Warzynski     rewriter.replaceOp(boxCharLen, lenAfterCast);
20596c3d7fd4SAndrzej Warzynski 
20606c3d7fd4SAndrzej Warzynski     return success();
20616c3d7fd4SAndrzej Warzynski   }
20626c3d7fd4SAndrzej Warzynski };
20636c3d7fd4SAndrzej Warzynski 
206414867ffcSAndrzej Warzynski /// Convert `fir.unboxchar` into two `llvm.extractvalue` instructions. One for
206514867ffcSAndrzej Warzynski /// the character buffer and one for the buffer length.
206614867ffcSAndrzej Warzynski struct UnboxCharOpConversion : public FIROpConversion<fir::UnboxCharOp> {
206714867ffcSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
206814867ffcSAndrzej Warzynski 
206914867ffcSAndrzej Warzynski   mlir::LogicalResult
207014867ffcSAndrzej Warzynski   matchAndRewrite(fir::UnboxCharOp unboxchar, OpAdaptor adaptor,
207114867ffcSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
207214867ffcSAndrzej Warzynski     MLIRContext *ctx = unboxchar.getContext();
207314867ffcSAndrzej Warzynski 
207414867ffcSAndrzej Warzynski     mlir::Type lenTy = convertType(unboxchar.getType(1));
207514867ffcSAndrzej Warzynski     mlir::Value tuple = adaptor.getOperands()[0];
207614867ffcSAndrzej Warzynski     mlir::Type tupleTy = tuple.getType();
207714867ffcSAndrzej Warzynski 
207814867ffcSAndrzej Warzynski     mlir::Location loc = unboxchar.getLoc();
207914867ffcSAndrzej Warzynski     mlir::Value ptrToBuffer =
208014867ffcSAndrzej Warzynski         genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 0);
208114867ffcSAndrzej Warzynski 
208214867ffcSAndrzej Warzynski     mlir::LLVM::ExtractValueOp len =
208314867ffcSAndrzej Warzynski         genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 1);
208414867ffcSAndrzej Warzynski     mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, len);
208514867ffcSAndrzej Warzynski 
208614867ffcSAndrzej Warzynski     rewriter.replaceOp(unboxchar,
208714867ffcSAndrzej Warzynski                        ArrayRef<mlir::Value>{ptrToBuffer, lenAfterCast});
208814867ffcSAndrzej Warzynski     return success();
208914867ffcSAndrzej Warzynski   }
209014867ffcSAndrzej Warzynski };
209114867ffcSAndrzej Warzynski 
2092cc505c0bSKiran Chandramohan /// Lower `fir.unboxproc` operation. Unbox a procedure box value, yielding its
2093cc505c0bSKiran Chandramohan /// components.
2094cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
2095cc505c0bSKiran Chandramohan struct UnboxProcOpConversion : public FIROpConversion<fir::UnboxProcOp> {
2096cc505c0bSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2097cc505c0bSKiran Chandramohan 
2098cc505c0bSKiran Chandramohan   mlir::LogicalResult
2099cc505c0bSKiran Chandramohan   matchAndRewrite(fir::UnboxProcOp unboxproc, OpAdaptor adaptor,
2100cc505c0bSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2101cc505c0bSKiran Chandramohan     return rewriter.notifyMatchFailure(
2102cc505c0bSKiran Chandramohan         unboxproc, "fir.unboxproc codegen is not implemented yet");
2103cc505c0bSKiran Chandramohan   }
2104cc505c0bSKiran Chandramohan };
2105cc505c0bSKiran Chandramohan 
2106e6c66ef5SAndrzej Warzynski /// Convert `fir.field_index`. The conversion depends on whether the size of
2107e6c66ef5SAndrzej Warzynski /// the record is static or dynamic.
2108e6c66ef5SAndrzej Warzynski struct FieldIndexOpConversion : public FIROpConversion<fir::FieldIndexOp> {
2109e6c66ef5SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
2110e6c66ef5SAndrzej Warzynski 
2111e6c66ef5SAndrzej Warzynski   // NB: most field references should be resolved by this point
2112e6c66ef5SAndrzej Warzynski   mlir::LogicalResult
2113e6c66ef5SAndrzej Warzynski   matchAndRewrite(fir::FieldIndexOp field, OpAdaptor adaptor,
2114e6c66ef5SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
2115e6c66ef5SAndrzej Warzynski     auto recTy = field.on_type().cast<fir::RecordType>();
2116e6c66ef5SAndrzej Warzynski     unsigned index = recTy.getFieldIndex(field.field_id());
2117e6c66ef5SAndrzej Warzynski 
2118e6c66ef5SAndrzej Warzynski     if (!fir::hasDynamicSize(recTy)) {
2119e6c66ef5SAndrzej Warzynski       // Derived type has compile-time constant layout. Return index of the
2120e6c66ef5SAndrzej Warzynski       // component type in the parent type (to be used in GEP).
2121e6c66ef5SAndrzej Warzynski       rewriter.replaceOp(field, mlir::ValueRange{genConstantOffset(
2122e6c66ef5SAndrzej Warzynski                                     field.getLoc(), rewriter, index)});
2123e6c66ef5SAndrzej Warzynski       return success();
2124e6c66ef5SAndrzej Warzynski     }
2125e6c66ef5SAndrzej Warzynski 
2126e6c66ef5SAndrzej Warzynski     // Derived type has compile-time constant layout. Call the compiler
2127e6c66ef5SAndrzej Warzynski     // generated function to determine the byte offset of the field at runtime.
2128e6c66ef5SAndrzej Warzynski     // This returns a non-constant.
2129e6c66ef5SAndrzej Warzynski     FlatSymbolRefAttr symAttr = mlir::SymbolRefAttr::get(
2130e6c66ef5SAndrzej Warzynski         field.getContext(), getOffsetMethodName(recTy, field.field_id()));
2131e6c66ef5SAndrzej Warzynski     NamedAttribute callAttr = rewriter.getNamedAttr("callee", symAttr);
2132e6c66ef5SAndrzej Warzynski     NamedAttribute fieldAttr = rewriter.getNamedAttr(
2133e6c66ef5SAndrzej Warzynski         "field", mlir::IntegerAttr::get(lowerTy().indexType(), index));
2134e6c66ef5SAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
2135e6c66ef5SAndrzej Warzynski         field, lowerTy().offsetType(), adaptor.getOperands(),
2136e6c66ef5SAndrzej Warzynski         llvm::ArrayRef<mlir::NamedAttribute>{callAttr, fieldAttr});
2137e6c66ef5SAndrzej Warzynski     return success();
2138e6c66ef5SAndrzej Warzynski   }
2139e6c66ef5SAndrzej Warzynski 
2140e6c66ef5SAndrzej Warzynski   // Re-Construct the name of the compiler generated method that calculates the
2141e6c66ef5SAndrzej Warzynski   // offset
2142e6c66ef5SAndrzej Warzynski   inline static std::string getOffsetMethodName(fir::RecordType recTy,
2143e6c66ef5SAndrzej Warzynski                                                 llvm::StringRef field) {
2144e6c66ef5SAndrzej Warzynski     return recTy.getName().str() + "P." + field.str() + ".offset";
2145e6c66ef5SAndrzej Warzynski   }
2146e6c66ef5SAndrzej Warzynski };
2147e6c66ef5SAndrzej Warzynski 
2148044d5b5dSValentin Clement } // namespace
2149044d5b5dSValentin Clement 
2150044d5b5dSValentin Clement namespace {
2151044d5b5dSValentin Clement /// Convert FIR dialect to LLVM dialect
2152044d5b5dSValentin Clement ///
2153044d5b5dSValentin Clement /// This pass lowers all FIR dialect operations to LLVM IR dialect. An
2154044d5b5dSValentin Clement /// MLIR pass is used to lower residual Std dialect to LLVM IR dialect.
2155044d5b5dSValentin Clement ///
2156044d5b5dSValentin Clement /// This pass is not complete yet. We are upstreaming it in small patches.
2157044d5b5dSValentin Clement class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> {
2158044d5b5dSValentin Clement public:
2159044d5b5dSValentin Clement   mlir::ModuleOp getModule() { return getOperation(); }
2160044d5b5dSValentin Clement 
2161044d5b5dSValentin Clement   void runOnOperation() override final {
21627b5132daSValentin Clement     auto mod = getModule();
21637b5132daSValentin Clement     if (!forcedTargetTriple.empty()) {
21647b5132daSValentin Clement       fir::setTargetTriple(mod, forcedTargetTriple);
21657b5132daSValentin Clement     }
21667b5132daSValentin Clement 
2167044d5b5dSValentin Clement     auto *context = getModule().getContext();
2168044d5b5dSValentin Clement     fir::LLVMTypeConverter typeConverter{getModule()};
2169044d5b5dSValentin Clement     mlir::OwningRewritePatternList pattern(context);
2170df3b9810SValentin Clement     pattern.insert<
2171420ad7ceSAndrzej Warzynski         AbsentOpConversion, AddcOpConversion, AddrOfOpConversion,
21721a2ec667SValentin Clement         AllocaOpConversion, BoxAddrOpConversion, BoxCharLenOpConversion,
21731a2ec667SValentin Clement         BoxDimsOpConversion, BoxEleSizeOpConversion, BoxIsAllocOpConversion,
2174cc505c0bSKiran Chandramohan         BoxIsArrayOpConversion, BoxIsPtrOpConversion, BoxProcHostOpConversion,
2175cc505c0bSKiran Chandramohan         BoxRankOpConversion, BoxTypeDescOpConversion, CallOpConversion,
2176cc505c0bSKiran Chandramohan         CmpcOpConversion, ConstcOpConversion, ConvertOpConversion,
2177cc505c0bSKiran Chandramohan         DispatchOpConversion, DispatchTableOpConversion, DTEntryOpConversion,
2178cc505c0bSKiran Chandramohan         DivcOpConversion, EmboxOpConversion, EmboxCharOpConversion,
2179e6c66ef5SAndrzej Warzynski         EmboxProcOpConversion, ExtractValueOpConversion, FieldIndexOpConversion,
2180e6c66ef5SAndrzej Warzynski         FirEndOpConversion, HasValueOpConversion, GenTypeDescOpConversion,
2181e6c66ef5SAndrzej Warzynski         GlobalLenOpConversion, GlobalOpConversion, InsertOnRangeOpConversion,
2182e6c66ef5SAndrzej Warzynski         InsertValueOpConversion, IsPresentOpConversion, LoadOpConversion,
2183*b8207db7SValentin Clement         NegcOpConversion, NoReassocOpConversion, MulcOpConversion,
2184*b8207db7SValentin Clement         SelectCaseOpConversion, SelectOpConversion, SelectRankOpConversion,
2185*b8207db7SValentin Clement         SelectTypeOpConversion, ShapeOpConversion, ShapeShiftOpConversion,
2186*b8207db7SValentin Clement         ShiftOpConversion, SliceOpConversion, StoreOpConversion,
2187*b8207db7SValentin Clement         StringLitOpConversion, SubcOpConversion, UnboxCharOpConversion,
2188*b8207db7SValentin Clement         UnboxProcOpConversion, UndefOpConversion, UnreachableOpConversion,
2189*b8207db7SValentin Clement         ZeroOpConversion>(typeConverter);
2190044d5b5dSValentin Clement     mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern);
2191044d5b5dSValentin Clement     mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter,
2192044d5b5dSValentin Clement                                                             pattern);
2193044d5b5dSValentin Clement     mlir::ConversionTarget target{*context};
2194044d5b5dSValentin Clement     target.addLegalDialect<mlir::LLVM::LLVMDialect>();
2195044d5b5dSValentin Clement 
2196044d5b5dSValentin Clement     // required NOPs for applying a full conversion
2197044d5b5dSValentin Clement     target.addLegalOp<mlir::ModuleOp>();
2198044d5b5dSValentin Clement 
2199044d5b5dSValentin Clement     // apply the patterns
2200044d5b5dSValentin Clement     if (mlir::failed(mlir::applyFullConversion(getModule(), target,
2201044d5b5dSValentin Clement                                                std::move(pattern)))) {
2202044d5b5dSValentin Clement       signalPassFailure();
2203044d5b5dSValentin Clement     }
2204044d5b5dSValentin Clement   }
2205044d5b5dSValentin Clement };
2206044d5b5dSValentin Clement } // namespace
2207044d5b5dSValentin Clement 
2208044d5b5dSValentin Clement std::unique_ptr<mlir::Pass> fir::createFIRToLLVMPass() {
2209044d5b5dSValentin Clement   return std::make_unique<FIRToLLVMLowering>();
2210044d5b5dSValentin Clement }
2211