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 
535*cc505c0bSKiran Chandramohan /// Lower `fir.boxproc_host` operation. Extracts the host pointer from the
536*cc505c0bSKiran Chandramohan /// boxproc.
537*cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
538*cc505c0bSKiran Chandramohan struct BoxProcHostOpConversion : public FIROpConversion<fir::BoxProcHostOp> {
539*cc505c0bSKiran Chandramohan   using FIROpConversion::FIROpConversion;
540*cc505c0bSKiran Chandramohan 
541*cc505c0bSKiran Chandramohan   mlir::LogicalResult
542*cc505c0bSKiran Chandramohan   matchAndRewrite(fir::BoxProcHostOp boxprochost, OpAdaptor adaptor,
543*cc505c0bSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
544*cc505c0bSKiran Chandramohan     return rewriter.notifyMatchFailure(
545*cc505c0bSKiran Chandramohan         boxprochost, "fir.boxproc_host codegen is not implemented yet");
546*cc505c0bSKiran Chandramohan   }
547*cc505c0bSKiran Chandramohan };
548*cc505c0bSKiran 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 
8420c4a7a52SValentin Clement /// Lower `fir.has_value` operation to `llvm.return` operation.
843044d5b5dSValentin Clement struct HasValueOpConversion : public FIROpConversion<fir::HasValueOp> {
844044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
845044d5b5dSValentin Clement 
846044d5b5dSValentin Clement   mlir::LogicalResult
847044d5b5dSValentin Clement   matchAndRewrite(fir::HasValueOp op, OpAdaptor adaptor,
848044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
849044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, adaptor.getOperands());
850044d5b5dSValentin Clement     return success();
851044d5b5dSValentin Clement   }
852044d5b5dSValentin Clement };
853044d5b5dSValentin Clement 
8540c4a7a52SValentin Clement /// Lower `fir.global` operation to `llvm.global` operation.
8550c4a7a52SValentin Clement /// `fir.insert_on_range` operations are replaced with constant dense attribute
8560c4a7a52SValentin Clement /// if they are applied on the full range.
857044d5b5dSValentin Clement struct GlobalOpConversion : public FIROpConversion<fir::GlobalOp> {
858044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
859044d5b5dSValentin Clement 
860044d5b5dSValentin Clement   mlir::LogicalResult
861044d5b5dSValentin Clement   matchAndRewrite(fir::GlobalOp global, OpAdaptor adaptor,
862044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
863044d5b5dSValentin Clement     auto tyAttr = convertType(global.getType());
864044d5b5dSValentin Clement     if (global.getType().isa<fir::BoxType>())
865044d5b5dSValentin Clement       tyAttr = tyAttr.cast<mlir::LLVM::LLVMPointerType>().getElementType();
866044d5b5dSValentin Clement     auto loc = global.getLoc();
867044d5b5dSValentin Clement     mlir::Attribute initAttr{};
868044d5b5dSValentin Clement     if (global.initVal())
869044d5b5dSValentin Clement       initAttr = global.initVal().getValue();
870044d5b5dSValentin Clement     auto linkage = convertLinkage(global.linkName());
871044d5b5dSValentin Clement     auto isConst = global.constant().hasValue();
872044d5b5dSValentin Clement     auto g = rewriter.create<mlir::LLVM::GlobalOp>(
873044d5b5dSValentin Clement         loc, tyAttr, isConst, linkage, global.sym_name(), initAttr);
874044d5b5dSValentin Clement     auto &gr = g.getInitializerRegion();
875044d5b5dSValentin Clement     rewriter.inlineRegionBefore(global.region(), gr, gr.end());
876044d5b5dSValentin Clement     if (!gr.empty()) {
877044d5b5dSValentin Clement       // Replace insert_on_range with a constant dense attribute if the
878044d5b5dSValentin Clement       // initialization is on the full range.
879044d5b5dSValentin Clement       auto insertOnRangeOps = gr.front().getOps<fir::InsertOnRangeOp>();
880044d5b5dSValentin Clement       for (auto insertOp : insertOnRangeOps) {
881044d5b5dSValentin Clement         if (isFullRange(insertOp.coor(), insertOp.getType())) {
882044d5b5dSValentin Clement           auto seqTyAttr = convertType(insertOp.getType());
883044d5b5dSValentin Clement           auto *op = insertOp.val().getDefiningOp();
884044d5b5dSValentin Clement           auto constant = mlir::dyn_cast<mlir::arith::ConstantOp>(op);
885044d5b5dSValentin Clement           if (!constant) {
886044d5b5dSValentin Clement             auto convertOp = mlir::dyn_cast<fir::ConvertOp>(op);
887044d5b5dSValentin Clement             if (!convertOp)
888044d5b5dSValentin Clement               continue;
889044d5b5dSValentin Clement             constant = cast<mlir::arith::ConstantOp>(
890044d5b5dSValentin Clement                 convertOp.value().getDefiningOp());
891044d5b5dSValentin Clement           }
892044d5b5dSValentin Clement           mlir::Type vecType = mlir::VectorType::get(
893044d5b5dSValentin Clement               insertOp.getType().getShape(), constant.getType());
894044d5b5dSValentin Clement           auto denseAttr = mlir::DenseElementsAttr::get(
895044d5b5dSValentin Clement               vecType.cast<ShapedType>(), constant.value());
896044d5b5dSValentin Clement           rewriter.setInsertionPointAfter(insertOp);
897044d5b5dSValentin Clement           rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(
898044d5b5dSValentin Clement               insertOp, seqTyAttr, denseAttr);
899044d5b5dSValentin Clement         }
900044d5b5dSValentin Clement       }
901044d5b5dSValentin Clement     }
902044d5b5dSValentin Clement     rewriter.eraseOp(global);
903044d5b5dSValentin Clement     return success();
904044d5b5dSValentin Clement   }
905044d5b5dSValentin Clement 
906044d5b5dSValentin Clement   bool isFullRange(mlir::ArrayAttr indexes, fir::SequenceType seqTy) const {
907044d5b5dSValentin Clement     auto extents = seqTy.getShape();
908044d5b5dSValentin Clement     if (indexes.size() / 2 != extents.size())
909044d5b5dSValentin Clement       return false;
910044d5b5dSValentin Clement     for (unsigned i = 0; i < indexes.size(); i += 2) {
911044d5b5dSValentin Clement       if (indexes[i].cast<IntegerAttr>().getInt() != 0)
912044d5b5dSValentin Clement         return false;
913044d5b5dSValentin Clement       if (indexes[i + 1].cast<IntegerAttr>().getInt() != extents[i / 2] - 1)
914044d5b5dSValentin Clement         return false;
915044d5b5dSValentin Clement     }
916044d5b5dSValentin Clement     return true;
917044d5b5dSValentin Clement   }
918044d5b5dSValentin Clement 
9190c4a7a52SValentin Clement   // TODO: String comparaison should be avoided. Replace linkName with an
9200c4a7a52SValentin Clement   // enumeration.
921044d5b5dSValentin Clement   mlir::LLVM::Linkage convertLinkage(Optional<StringRef> optLinkage) const {
922044d5b5dSValentin Clement     if (optLinkage.hasValue()) {
923044d5b5dSValentin Clement       auto name = optLinkage.getValue();
924044d5b5dSValentin Clement       if (name == "internal")
925044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Internal;
926044d5b5dSValentin Clement       if (name == "linkonce")
927044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Linkonce;
928044d5b5dSValentin Clement       if (name == "common")
929044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Common;
930044d5b5dSValentin Clement       if (name == "weak")
931044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Weak;
932044d5b5dSValentin Clement     }
933044d5b5dSValentin Clement     return mlir::LLVM::Linkage::External;
934044d5b5dSValentin Clement   }
935044d5b5dSValentin Clement };
936044d5b5dSValentin Clement 
93739f4ef81SValentin Clement void genCondBrOp(mlir::Location loc, mlir::Value cmp, mlir::Block *dest,
93839f4ef81SValentin Clement                  Optional<mlir::ValueRange> destOps,
93939f4ef81SValentin Clement                  mlir::ConversionPatternRewriter &rewriter,
94039f4ef81SValentin Clement                  mlir::Block *newBlock) {
94139f4ef81SValentin Clement   if (destOps.hasValue())
94239f4ef81SValentin Clement     rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, destOps.getValue(),
94339f4ef81SValentin Clement                                           newBlock, mlir::ValueRange());
94439f4ef81SValentin Clement   else
94539f4ef81SValentin Clement     rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, newBlock);
94639f4ef81SValentin Clement }
94739f4ef81SValentin Clement 
94839f4ef81SValentin Clement template <typename A, typename B>
94939f4ef81SValentin Clement void genBrOp(A caseOp, mlir::Block *dest, Optional<B> destOps,
95039f4ef81SValentin Clement              mlir::ConversionPatternRewriter &rewriter) {
95139f4ef81SValentin Clement   if (destOps.hasValue())
95239f4ef81SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, destOps.getValue(),
95339f4ef81SValentin Clement                                                   dest);
95439f4ef81SValentin Clement   else
95539f4ef81SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, llvm::None, dest);
95639f4ef81SValentin Clement }
95739f4ef81SValentin Clement 
95839f4ef81SValentin Clement void genCaseLadderStep(mlir::Location loc, mlir::Value cmp, mlir::Block *dest,
95939f4ef81SValentin Clement                        Optional<mlir::ValueRange> destOps,
96039f4ef81SValentin Clement                        mlir::ConversionPatternRewriter &rewriter) {
96139f4ef81SValentin Clement   auto *thisBlock = rewriter.getInsertionBlock();
96239f4ef81SValentin Clement   auto *newBlock = createBlock(rewriter, dest);
96339f4ef81SValentin Clement   rewriter.setInsertionPointToEnd(thisBlock);
96439f4ef81SValentin Clement   genCondBrOp(loc, cmp, dest, destOps, rewriter, newBlock);
96539f4ef81SValentin Clement   rewriter.setInsertionPointToEnd(newBlock);
96639f4ef81SValentin Clement }
96739f4ef81SValentin Clement 
96839f4ef81SValentin Clement /// Conversion of `fir.select_case`
96939f4ef81SValentin Clement ///
97039f4ef81SValentin Clement /// The `fir.select_case` operation is converted to a if-then-else ladder.
97139f4ef81SValentin Clement /// Depending on the case condition type, one or several comparison and
97239f4ef81SValentin Clement /// conditional branching can be generated.
97339f4ef81SValentin Clement ///
97439f4ef81SValentin Clement /// A a point value case such as `case(4)`, a lower bound case such as
97539f4ef81SValentin Clement /// `case(5:)` or an upper bound case such as `case(:3)` are converted to a
97639f4ef81SValentin Clement /// simple comparison between the selector value and the constant value in the
97739f4ef81SValentin Clement /// case. The block associated with the case condition is then executed if
97839f4ef81SValentin Clement /// the comparison succeed otherwise it branch to the next block with the
97939f4ef81SValentin Clement /// comparison for the the next case conditon.
98039f4ef81SValentin Clement ///
98139f4ef81SValentin Clement /// A closed interval case condition such as `case(7:10)` is converted with a
98239f4ef81SValentin Clement /// first comparison and conditional branching for the lower bound. If
98339f4ef81SValentin Clement /// successful, it branch to a second block with the comparison for the
98439f4ef81SValentin Clement /// upper bound in the same case condition.
98539f4ef81SValentin Clement ///
98639f4ef81SValentin Clement /// TODO: lowering of CHARACTER type cases is not handled yet.
98739f4ef81SValentin Clement struct SelectCaseOpConversion : public FIROpConversion<fir::SelectCaseOp> {
98839f4ef81SValentin Clement   using FIROpConversion::FIROpConversion;
98939f4ef81SValentin Clement 
99039f4ef81SValentin Clement   mlir::LogicalResult
99139f4ef81SValentin Clement   matchAndRewrite(fir::SelectCaseOp caseOp, OpAdaptor adaptor,
99239f4ef81SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
99339f4ef81SValentin Clement     unsigned conds = caseOp.getNumConditions();
99439f4ef81SValentin Clement     llvm::ArrayRef<mlir::Attribute> cases = caseOp.getCases().getValue();
99539f4ef81SValentin Clement     // Type can be CHARACTER, INTEGER, or LOGICAL (C1145)
99639f4ef81SValentin Clement     LLVM_ATTRIBUTE_UNUSED auto ty = caseOp.getSelector().getType();
99739f4ef81SValentin Clement     if (ty.isa<fir::CharacterType>())
99839f4ef81SValentin Clement       return rewriter.notifyMatchFailure(caseOp,
99939f4ef81SValentin Clement                                          "conversion of fir.select_case with "
100039f4ef81SValentin Clement                                          "character type not implemented yet");
100139f4ef81SValentin Clement     mlir::Value selector = caseOp.getSelector(adaptor.getOperands());
100239f4ef81SValentin Clement     auto loc = caseOp.getLoc();
100339f4ef81SValentin Clement     for (unsigned t = 0; t != conds; ++t) {
100439f4ef81SValentin Clement       mlir::Block *dest = caseOp.getSuccessor(t);
100539f4ef81SValentin Clement       llvm::Optional<mlir::ValueRange> destOps =
100639f4ef81SValentin Clement           caseOp.getSuccessorOperands(adaptor.getOperands(), t);
100739f4ef81SValentin Clement       llvm::Optional<mlir::ValueRange> cmpOps =
100839f4ef81SValentin Clement           *caseOp.getCompareOperands(adaptor.getOperands(), t);
100939f4ef81SValentin Clement       mlir::Value caseArg = *(cmpOps.getValue().begin());
101039f4ef81SValentin Clement       mlir::Attribute attr = cases[t];
101139f4ef81SValentin Clement       if (attr.isa<fir::PointIntervalAttr>()) {
101239f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
101339f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::eq, selector, caseArg);
101439f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
101539f4ef81SValentin Clement         continue;
101639f4ef81SValentin Clement       }
101739f4ef81SValentin Clement       if (attr.isa<fir::LowerBoundAttr>()) {
101839f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
101939f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector);
102039f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
102139f4ef81SValentin Clement         continue;
102239f4ef81SValentin Clement       }
102339f4ef81SValentin Clement       if (attr.isa<fir::UpperBoundAttr>()) {
102439f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
102539f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg);
102639f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
102739f4ef81SValentin Clement         continue;
102839f4ef81SValentin Clement       }
102939f4ef81SValentin Clement       if (attr.isa<fir::ClosedIntervalAttr>()) {
103039f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
103139f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector);
103239f4ef81SValentin Clement         auto *thisBlock = rewriter.getInsertionBlock();
103339f4ef81SValentin Clement         auto *newBlock1 = createBlock(rewriter, dest);
103439f4ef81SValentin Clement         auto *newBlock2 = createBlock(rewriter, dest);
103539f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(thisBlock);
103639f4ef81SValentin Clement         rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, newBlock1, newBlock2);
103739f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(newBlock1);
103839f4ef81SValentin Clement         mlir::Value caseArg0 = *(cmpOps.getValue().begin() + 1);
103939f4ef81SValentin Clement         auto cmp0 = rewriter.create<mlir::LLVM::ICmpOp>(
104039f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg0);
104139f4ef81SValentin Clement         genCondBrOp(loc, cmp0, dest, destOps, rewriter, newBlock2);
104239f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(newBlock2);
104339f4ef81SValentin Clement         continue;
104439f4ef81SValentin Clement       }
104539f4ef81SValentin Clement       assert(attr.isa<mlir::UnitAttr>());
104639f4ef81SValentin Clement       assert((t + 1 == conds) && "unit must be last");
104739f4ef81SValentin Clement       genBrOp(caseOp, dest, destOps, rewriter);
104839f4ef81SValentin Clement     }
104939f4ef81SValentin Clement     return success();
105039f4ef81SValentin Clement   }
105139f4ef81SValentin Clement };
105239f4ef81SValentin Clement 
10538c239909SValentin Clement template <typename OP>
10548c239909SValentin Clement void selectMatchAndRewrite(fir::LLVMTypeConverter &lowering, OP select,
10558c239909SValentin Clement                            typename OP::Adaptor adaptor,
10568c239909SValentin Clement                            mlir::ConversionPatternRewriter &rewriter) {
10578c239909SValentin Clement   unsigned conds = select.getNumConditions();
10588c239909SValentin Clement   auto cases = select.getCases().getValue();
10598c239909SValentin Clement   mlir::Value selector = adaptor.selector();
10608c239909SValentin Clement   auto loc = select.getLoc();
10618c239909SValentin Clement   assert(conds > 0 && "select must have cases");
10628c239909SValentin Clement 
10638c239909SValentin Clement   llvm::SmallVector<mlir::Block *> destinations;
10648c239909SValentin Clement   llvm::SmallVector<mlir::ValueRange> destinationsOperands;
10658c239909SValentin Clement   mlir::Block *defaultDestination;
10668c239909SValentin Clement   mlir::ValueRange defaultOperands;
10678c239909SValentin Clement   llvm::SmallVector<int32_t> caseValues;
10688c239909SValentin Clement 
10698c239909SValentin Clement   for (unsigned t = 0; t != conds; ++t) {
10708c239909SValentin Clement     mlir::Block *dest = select.getSuccessor(t);
10718c239909SValentin Clement     auto destOps = select.getSuccessorOperands(adaptor.getOperands(), t);
10728c239909SValentin Clement     const mlir::Attribute &attr = cases[t];
10738c239909SValentin Clement     if (auto intAttr = attr.template dyn_cast<mlir::IntegerAttr>()) {
10748c239909SValentin Clement       destinations.push_back(dest);
10758c239909SValentin Clement       destinationsOperands.push_back(destOps.hasValue() ? *destOps
10768c239909SValentin Clement                                                         : ValueRange());
10778c239909SValentin Clement       caseValues.push_back(intAttr.getInt());
10788c239909SValentin Clement       continue;
10798c239909SValentin Clement     }
10808c239909SValentin Clement     assert(attr.template dyn_cast_or_null<mlir::UnitAttr>());
10818c239909SValentin Clement     assert((t + 1 == conds) && "unit must be last");
10828c239909SValentin Clement     defaultDestination = dest;
10838c239909SValentin Clement     defaultOperands = destOps.hasValue() ? *destOps : ValueRange();
10848c239909SValentin Clement   }
10858c239909SValentin Clement 
10868c239909SValentin Clement   // LLVM::SwitchOp takes a i32 type for the selector.
10878c239909SValentin Clement   if (select.getSelector().getType() != rewriter.getI32Type())
10888c239909SValentin Clement     selector =
10898c239909SValentin Clement         rewriter.create<LLVM::TruncOp>(loc, rewriter.getI32Type(), selector);
10908c239909SValentin Clement 
10918c239909SValentin Clement   rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>(
10928c239909SValentin Clement       select, selector,
10938c239909SValentin Clement       /*defaultDestination=*/defaultDestination,
10948c239909SValentin Clement       /*defaultOperands=*/defaultOperands,
10958c239909SValentin Clement       /*caseValues=*/caseValues,
10968c239909SValentin Clement       /*caseDestinations=*/destinations,
10978c239909SValentin Clement       /*caseOperands=*/destinationsOperands,
10988c239909SValentin Clement       /*branchWeights=*/ArrayRef<int32_t>());
10998c239909SValentin Clement }
11008c239909SValentin Clement 
11018c239909SValentin Clement /// conversion of fir::SelectOp to an if-then-else ladder
11028c239909SValentin Clement struct SelectOpConversion : public FIROpConversion<fir::SelectOp> {
11038c239909SValentin Clement   using FIROpConversion::FIROpConversion;
11048c239909SValentin Clement 
11058c239909SValentin Clement   mlir::LogicalResult
11068c239909SValentin Clement   matchAndRewrite(fir::SelectOp op, OpAdaptor adaptor,
11078c239909SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
11088c239909SValentin Clement     selectMatchAndRewrite<fir::SelectOp>(lowerTy(), op, adaptor, rewriter);
11098c239909SValentin Clement     return success();
11108c239909SValentin Clement   }
11118c239909SValentin Clement };
11128c239909SValentin Clement 
1113e3349fa1SAndrzej Warzynski /// `fir.load` --> `llvm.load`
1114e3349fa1SAndrzej Warzynski struct LoadOpConversion : public FIROpConversion<fir::LoadOp> {
1115e3349fa1SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
1116e3349fa1SAndrzej Warzynski 
1117e3349fa1SAndrzej Warzynski   mlir::LogicalResult
1118e3349fa1SAndrzej Warzynski   matchAndRewrite(fir::LoadOp load, OpAdaptor adaptor,
1119e3349fa1SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
1120e3349fa1SAndrzej Warzynski     // fir.box is a special case because it is considered as an ssa values in
1121e3349fa1SAndrzej Warzynski     // fir, but it is lowered as a pointer to a descriptor. So fir.ref<fir.box>
1122e3349fa1SAndrzej Warzynski     // and fir.box end up being the same llvm types and loading a
1123e3349fa1SAndrzej Warzynski     // fir.ref<fir.box> is actually a no op in LLVM.
1124e3349fa1SAndrzej Warzynski     if (load.getType().isa<fir::BoxType>()) {
1125e3349fa1SAndrzej Warzynski       rewriter.replaceOp(load, adaptor.getOperands()[0]);
1126e3349fa1SAndrzej Warzynski     } else {
1127e3349fa1SAndrzej Warzynski       mlir::Type ty = convertType(load.getType());
1128e3349fa1SAndrzej Warzynski       ArrayRef<NamedAttribute> at = load->getAttrs();
1129e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::LoadOp>(
1130e3349fa1SAndrzej Warzynski           load, ty, adaptor.getOperands(), at);
1131e3349fa1SAndrzej Warzynski     }
1132e3349fa1SAndrzej Warzynski     return success();
1133e3349fa1SAndrzej Warzynski   }
1134e3349fa1SAndrzej Warzynski };
1135e3349fa1SAndrzej Warzynski 
11362a299e4fSValentin Clement /// Lower `fir.select_type` to LLVM IR dialect.
11372a299e4fSValentin Clement struct SelectTypeOpConversion : public FIROpConversion<fir::SelectTypeOp> {
11382a299e4fSValentin Clement   using FIROpConversion::FIROpConversion;
11392a299e4fSValentin Clement 
11402a299e4fSValentin Clement   mlir::LogicalResult
11412a299e4fSValentin Clement   matchAndRewrite(fir::SelectTypeOp select, OpAdaptor adaptor,
11422a299e4fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
11432a299e4fSValentin Clement     return rewriter.notifyMatchFailure(
11442a299e4fSValentin Clement         select, "fir.select_type codegen is not implemented yet");
11452a299e4fSValentin Clement   }
11462a299e4fSValentin Clement };
11472a299e4fSValentin Clement 
11488c239909SValentin Clement /// conversion of fir::SelectRankOp to an if-then-else ladder
11498c239909SValentin Clement struct SelectRankOpConversion : public FIROpConversion<fir::SelectRankOp> {
11508c239909SValentin Clement   using FIROpConversion::FIROpConversion;
11518c239909SValentin Clement 
11528c239909SValentin Clement   mlir::LogicalResult
11538c239909SValentin Clement   matchAndRewrite(fir::SelectRankOp op, OpAdaptor adaptor,
11548c239909SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
11558c239909SValentin Clement     selectMatchAndRewrite<fir::SelectRankOp>(lowerTy(), op, adaptor, rewriter);
11568c239909SValentin Clement     return success();
11578c239909SValentin Clement   }
11588c239909SValentin Clement };
11598c239909SValentin Clement 
1160e3349fa1SAndrzej Warzynski /// `fir.store` --> `llvm.store`
1161e3349fa1SAndrzej Warzynski struct StoreOpConversion : public FIROpConversion<fir::StoreOp> {
1162e3349fa1SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
1163e3349fa1SAndrzej Warzynski 
1164e3349fa1SAndrzej Warzynski   mlir::LogicalResult
1165e3349fa1SAndrzej Warzynski   matchAndRewrite(fir::StoreOp store, OpAdaptor adaptor,
1166e3349fa1SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
1167e3349fa1SAndrzej Warzynski     if (store.value().getType().isa<fir::BoxType>()) {
1168e3349fa1SAndrzej Warzynski       // fir.box value is actually in memory, load it first before storing it.
1169e3349fa1SAndrzej Warzynski       mlir::Location loc = store.getLoc();
1170e3349fa1SAndrzej Warzynski       mlir::Type boxPtrTy = adaptor.getOperands()[0].getType();
1171e3349fa1SAndrzej Warzynski       auto val = rewriter.create<mlir::LLVM::LoadOp>(
1172e3349fa1SAndrzej Warzynski           loc, boxPtrTy.cast<mlir::LLVM::LLVMPointerType>().getElementType(),
1173e3349fa1SAndrzej Warzynski           adaptor.getOperands()[0]);
1174e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
1175e3349fa1SAndrzej Warzynski           store, val, adaptor.getOperands()[1]);
1176e3349fa1SAndrzej Warzynski     } else {
1177e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
1178e3349fa1SAndrzej Warzynski           store, adaptor.getOperands()[0], adaptor.getOperands()[1]);
1179e3349fa1SAndrzej Warzynski     }
1180e3349fa1SAndrzej Warzynski     return success();
1181e3349fa1SAndrzej Warzynski   }
1182e3349fa1SAndrzej Warzynski };
1183e3349fa1SAndrzej Warzynski 
1184e3349fa1SAndrzej Warzynski /// convert to LLVM IR dialect `undef`
1185044d5b5dSValentin Clement struct UndefOpConversion : public FIROpConversion<fir::UndefOp> {
1186044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
1187044d5b5dSValentin Clement 
1188044d5b5dSValentin Clement   mlir::LogicalResult
1189044d5b5dSValentin Clement   matchAndRewrite(fir::UndefOp undef, OpAdaptor,
1190044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1191044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::UndefOp>(
1192044d5b5dSValentin Clement         undef, convertType(undef.getType()));
1193044d5b5dSValentin Clement     return success();
1194044d5b5dSValentin Clement   }
1195044d5b5dSValentin Clement };
1196a7a61359SValentin Clement 
1197e3349fa1SAndrzej Warzynski /// `fir.unreachable` --> `llvm.unreachable`
119832e08248SAndrzej Warzynski struct UnreachableOpConversion : public FIROpConversion<fir::UnreachableOp> {
119932e08248SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
120032e08248SAndrzej Warzynski 
120132e08248SAndrzej Warzynski   mlir::LogicalResult
120232e08248SAndrzej Warzynski   matchAndRewrite(fir::UnreachableOp unreach, OpAdaptor adaptor,
120332e08248SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
120432e08248SAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(unreach);
120532e08248SAndrzej Warzynski     return success();
120632e08248SAndrzej Warzynski   }
120732e08248SAndrzej Warzynski };
120832e08248SAndrzej Warzynski 
1209a7a61359SValentin Clement struct ZeroOpConversion : public FIROpConversion<fir::ZeroOp> {
1210a7a61359SValentin Clement   using FIROpConversion::FIROpConversion;
1211a7a61359SValentin Clement 
1212a7a61359SValentin Clement   mlir::LogicalResult
1213a7a61359SValentin Clement   matchAndRewrite(fir::ZeroOp zero, OpAdaptor,
1214a7a61359SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1215a7a61359SValentin Clement     auto ty = convertType(zero.getType());
1216a7a61359SValentin Clement     if (ty.isa<mlir::LLVM::LLVMPointerType>()) {
1217a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(zero, ty);
1218a7a61359SValentin Clement     } else if (ty.isa<mlir::IntegerType>()) {
1219a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
1220a7a61359SValentin Clement           zero, ty, mlir::IntegerAttr::get(zero.getType(), 0));
1221a7a61359SValentin Clement     } else if (mlir::LLVM::isCompatibleFloatingPointType(ty)) {
1222a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
1223a7a61359SValentin Clement           zero, ty, mlir::FloatAttr::get(zero.getType(), 0.0));
1224a7a61359SValentin Clement     } else {
1225a7a61359SValentin Clement       // TODO: create ConstantAggregateZero for FIR aggregate/array types.
122652d813edSValentin Clement       return rewriter.notifyMatchFailure(
122752d813edSValentin Clement           zero,
1228a7a61359SValentin Clement           "conversion of fir.zero with aggregate type not implemented yet");
1229a7a61359SValentin Clement     }
1230a7a61359SValentin Clement     return success();
1231a7a61359SValentin Clement   }
1232a7a61359SValentin Clement };
123332e08248SAndrzej Warzynski 
1234af6ee580SValentin Clement /// Common base class for embox to descriptor conversion.
1235af6ee580SValentin Clement template <typename OP>
1236af6ee580SValentin Clement struct EmboxCommonConversion : public FIROpConversion<OP> {
1237af6ee580SValentin Clement   using FIROpConversion<OP>::FIROpConversion;
1238af6ee580SValentin Clement 
1239af6ee580SValentin Clement   // Find the LLVMFuncOp in whose entry block the alloca should be inserted.
1240af6ee580SValentin Clement   // The order to find the LLVMFuncOp is as follows:
1241af6ee580SValentin Clement   // 1. The parent operation of the current block if it is a LLVMFuncOp.
1242af6ee580SValentin Clement   // 2. The first ancestor that is a LLVMFuncOp.
1243af6ee580SValentin Clement   mlir::LLVM::LLVMFuncOp
1244af6ee580SValentin Clement   getFuncForAllocaInsert(mlir::ConversionPatternRewriter &rewriter) const {
1245af6ee580SValentin Clement     mlir::Operation *parentOp = rewriter.getInsertionBlock()->getParentOp();
1246af6ee580SValentin Clement     return mlir::isa<mlir::LLVM::LLVMFuncOp>(parentOp)
1247af6ee580SValentin Clement                ? mlir::cast<mlir::LLVM::LLVMFuncOp>(parentOp)
1248af6ee580SValentin Clement                : parentOp->getParentOfType<mlir::LLVM::LLVMFuncOp>();
1249af6ee580SValentin Clement   }
1250af6ee580SValentin Clement 
1251af6ee580SValentin Clement   // Generate an alloca of size 1 and type \p toTy.
1252af6ee580SValentin Clement   mlir::LLVM::AllocaOp
1253af6ee580SValentin Clement   genAllocaWithType(mlir::Location loc, mlir::Type toTy, unsigned alignment,
1254af6ee580SValentin Clement                     mlir::ConversionPatternRewriter &rewriter) const {
1255af6ee580SValentin Clement     auto thisPt = rewriter.saveInsertionPoint();
1256af6ee580SValentin Clement     mlir::LLVM::LLVMFuncOp func = getFuncForAllocaInsert(rewriter);
1257af6ee580SValentin Clement     rewriter.setInsertionPointToStart(&func.front());
1258af6ee580SValentin Clement     auto size = this->genI32Constant(loc, rewriter, 1);
1259af6ee580SValentin Clement     auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, toTy, size, alignment);
1260af6ee580SValentin Clement     rewriter.restoreInsertionPoint(thisPt);
1261af6ee580SValentin Clement     return al;
1262af6ee580SValentin Clement   }
1263af6ee580SValentin Clement 
1264af6ee580SValentin Clement   static int getCFIAttr(fir::BoxType boxTy) {
1265af6ee580SValentin Clement     auto eleTy = boxTy.getEleTy();
1266af6ee580SValentin Clement     if (eleTy.isa<fir::PointerType>())
1267af6ee580SValentin Clement       return CFI_attribute_pointer;
1268af6ee580SValentin Clement     if (eleTy.isa<fir::HeapType>())
1269af6ee580SValentin Clement       return CFI_attribute_allocatable;
1270af6ee580SValentin Clement     return CFI_attribute_other;
1271af6ee580SValentin Clement   }
1272af6ee580SValentin Clement 
1273af6ee580SValentin Clement   static fir::RecordType unwrapIfDerived(fir::BoxType boxTy) {
1274af6ee580SValentin Clement     return fir::unwrapSequenceType(fir::dyn_cast_ptrOrBoxEleTy(boxTy))
1275af6ee580SValentin Clement         .template dyn_cast<fir::RecordType>();
1276af6ee580SValentin Clement   }
1277af6ee580SValentin Clement   static bool isDerivedTypeWithLenParams(fir::BoxType boxTy) {
1278af6ee580SValentin Clement     auto recTy = unwrapIfDerived(boxTy);
1279af6ee580SValentin Clement     return recTy && recTy.getNumLenParams() > 0;
1280af6ee580SValentin Clement   }
1281af6ee580SValentin Clement   static bool isDerivedType(fir::BoxType boxTy) {
1282af6ee580SValentin Clement     return unwrapIfDerived(boxTy) != nullptr;
1283af6ee580SValentin Clement   }
1284af6ee580SValentin Clement 
1285af6ee580SValentin Clement   // Get the element size and CFI type code of the boxed value.
1286af6ee580SValentin Clement   std::tuple<mlir::Value, mlir::Value> getSizeAndTypeCode(
1287af6ee580SValentin Clement       mlir::Location loc, mlir::ConversionPatternRewriter &rewriter,
1288af6ee580SValentin Clement       mlir::Type boxEleTy, mlir::ValueRange lenParams = {}) const {
1289af6ee580SValentin Clement     auto doInteger =
1290af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1291af6ee580SValentin Clement       int typeCode = fir::integerBitsToTypeCode(width);
1292af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1293af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1294af6ee580SValentin Clement     };
1295af6ee580SValentin Clement     auto doLogical =
1296af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1297af6ee580SValentin Clement       int typeCode = fir::logicalBitsToTypeCode(width);
1298af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1299af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1300af6ee580SValentin Clement     };
1301af6ee580SValentin Clement     auto doFloat = [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1302af6ee580SValentin Clement       int typeCode = fir::realBitsToTypeCode(width);
1303af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1304af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1305af6ee580SValentin Clement     };
1306af6ee580SValentin Clement     auto doComplex =
1307af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1308af6ee580SValentin Clement       auto typeCode = fir::complexBitsToTypeCode(width);
1309af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8 * 2),
1310af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1311af6ee580SValentin Clement     };
1312af6ee580SValentin Clement     auto doCharacter =
1313af6ee580SValentin Clement         [&](unsigned width,
1314af6ee580SValentin Clement             mlir::Value len) -> std::tuple<mlir::Value, mlir::Value> {
1315af6ee580SValentin Clement       auto typeCode = fir::characterBitsToTypeCode(width);
1316af6ee580SValentin Clement       auto typeCodeVal = this->genConstantOffset(loc, rewriter, typeCode);
1317af6ee580SValentin Clement       if (width == 8)
1318af6ee580SValentin Clement         return {len, typeCodeVal};
1319af6ee580SValentin Clement       auto byteWidth = this->genConstantOffset(loc, rewriter, width / 8);
1320af6ee580SValentin Clement       auto i64Ty = mlir::IntegerType::get(&this->lowerTy().getContext(), 64);
1321af6ee580SValentin Clement       auto size =
1322af6ee580SValentin Clement           rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, byteWidth, len);
1323af6ee580SValentin Clement       return {size, typeCodeVal};
1324af6ee580SValentin Clement     };
1325af6ee580SValentin Clement     auto getKindMap = [&]() -> fir::KindMapping & {
1326af6ee580SValentin Clement       return this->lowerTy().getKindMap();
1327af6ee580SValentin Clement     };
1328af6ee580SValentin Clement     // Pointer-like types.
1329af6ee580SValentin Clement     if (auto eleTy = fir::dyn_cast_ptrEleTy(boxEleTy))
1330af6ee580SValentin Clement       boxEleTy = eleTy;
1331af6ee580SValentin Clement     // Integer types.
1332af6ee580SValentin Clement     if (fir::isa_integer(boxEleTy)) {
1333af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::IntegerType>())
1334af6ee580SValentin Clement         return doInteger(ty.getWidth());
1335af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::IntegerType>();
1336af6ee580SValentin Clement       return doInteger(getKindMap().getIntegerBitsize(ty.getFKind()));
1337af6ee580SValentin Clement     }
1338af6ee580SValentin Clement     // Floating point types.
1339af6ee580SValentin Clement     if (fir::isa_real(boxEleTy)) {
1340af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::FloatType>())
1341af6ee580SValentin Clement         return doFloat(ty.getWidth());
1342af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::RealType>();
1343af6ee580SValentin Clement       return doFloat(getKindMap().getRealBitsize(ty.getFKind()));
1344af6ee580SValentin Clement     }
1345af6ee580SValentin Clement     // Complex types.
1346af6ee580SValentin Clement     if (fir::isa_complex(boxEleTy)) {
1347af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::ComplexType>())
1348af6ee580SValentin Clement         return doComplex(
1349af6ee580SValentin Clement             ty.getElementType().cast<mlir::FloatType>().getWidth());
1350af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::ComplexType>();
1351af6ee580SValentin Clement       return doComplex(getKindMap().getRealBitsize(ty.getFKind()));
1352af6ee580SValentin Clement     }
1353af6ee580SValentin Clement     // Character types.
1354af6ee580SValentin Clement     if (auto ty = boxEleTy.dyn_cast<fir::CharacterType>()) {
1355af6ee580SValentin Clement       auto charWidth = getKindMap().getCharacterBitsize(ty.getFKind());
1356af6ee580SValentin Clement       if (ty.getLen() != fir::CharacterType::unknownLen()) {
1357af6ee580SValentin Clement         auto len = this->genConstantOffset(loc, rewriter, ty.getLen());
1358af6ee580SValentin Clement         return doCharacter(charWidth, len);
1359af6ee580SValentin Clement       }
1360af6ee580SValentin Clement       assert(!lenParams.empty());
1361af6ee580SValentin Clement       return doCharacter(charWidth, lenParams.back());
1362af6ee580SValentin Clement     }
1363af6ee580SValentin Clement     // Logical type.
1364af6ee580SValentin Clement     if (auto ty = boxEleTy.dyn_cast<fir::LogicalType>())
1365af6ee580SValentin Clement       return doLogical(getKindMap().getLogicalBitsize(ty.getFKind()));
1366af6ee580SValentin Clement     // Array types.
1367af6ee580SValentin Clement     if (auto seqTy = boxEleTy.dyn_cast<fir::SequenceType>())
1368af6ee580SValentin Clement       return getSizeAndTypeCode(loc, rewriter, seqTy.getEleTy(), lenParams);
1369af6ee580SValentin Clement     // Derived-type types.
1370af6ee580SValentin Clement     if (boxEleTy.isa<fir::RecordType>()) {
1371af6ee580SValentin Clement       auto ptrTy = mlir::LLVM::LLVMPointerType::get(
1372af6ee580SValentin Clement           this->lowerTy().convertType(boxEleTy));
1373af6ee580SValentin Clement       auto nullPtr = rewriter.create<mlir::LLVM::NullOp>(loc, ptrTy);
1374af6ee580SValentin Clement       auto one =
1375af6ee580SValentin Clement           genConstantIndex(loc, this->lowerTy().offsetType(), rewriter, 1);
1376af6ee580SValentin Clement       auto gep = rewriter.create<mlir::LLVM::GEPOp>(
1377af6ee580SValentin Clement           loc, ptrTy, mlir::ValueRange{nullPtr, one});
1378af6ee580SValentin Clement       auto eleSize = rewriter.create<mlir::LLVM::PtrToIntOp>(
1379af6ee580SValentin Clement           loc, this->lowerTy().indexType(), gep);
1380af6ee580SValentin Clement       return {eleSize,
1381af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, fir::derivedToTypeCode())};
1382af6ee580SValentin Clement     }
1383af6ee580SValentin Clement     // Reference type.
1384af6ee580SValentin Clement     if (fir::isa_ref_type(boxEleTy)) {
1385af6ee580SValentin Clement       // FIXME: use the target pointer size rather than sizeof(void*)
1386af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, sizeof(void *)),
1387af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, CFI_type_cptr)};
1388af6ee580SValentin Clement     }
1389af6ee580SValentin Clement     fir::emitFatalError(loc, "unhandled type in fir.box code generation");
1390af6ee580SValentin Clement   }
1391af6ee580SValentin Clement 
1392af6ee580SValentin Clement   /// Basic pattern to write a field in the descriptor
1393af6ee580SValentin Clement   mlir::Value insertField(mlir::ConversionPatternRewriter &rewriter,
1394af6ee580SValentin Clement                           mlir::Location loc, mlir::Value dest,
1395af6ee580SValentin Clement                           ArrayRef<unsigned> fldIndexes, mlir::Value value,
1396af6ee580SValentin Clement                           bool bitcast = false) const {
1397af6ee580SValentin Clement     auto boxTy = dest.getType();
1398af6ee580SValentin Clement     auto fldTy = this->getBoxEleTy(boxTy, fldIndexes);
1399af6ee580SValentin Clement     if (bitcast)
1400af6ee580SValentin Clement       value = rewriter.create<mlir::LLVM::BitcastOp>(loc, fldTy, value);
1401af6ee580SValentin Clement     else
1402af6ee580SValentin Clement       value = this->integerCast(loc, rewriter, fldTy, value);
1403af6ee580SValentin Clement     SmallVector<mlir::Attribute, 2> attrs;
1404af6ee580SValentin Clement     for (auto i : fldIndexes)
1405af6ee580SValentin Clement       attrs.push_back(rewriter.getI32IntegerAttr(i));
1406af6ee580SValentin Clement     auto indexesAttr = mlir::ArrayAttr::get(rewriter.getContext(), attrs);
1407af6ee580SValentin Clement     return rewriter.create<mlir::LLVM::InsertValueOp>(loc, boxTy, dest, value,
1408af6ee580SValentin Clement                                                       indexesAttr);
1409af6ee580SValentin Clement   }
1410af6ee580SValentin Clement 
1411af6ee580SValentin Clement   inline mlir::Value
1412af6ee580SValentin Clement   insertBaseAddress(mlir::ConversionPatternRewriter &rewriter,
1413af6ee580SValentin Clement                     mlir::Location loc, mlir::Value dest,
1414af6ee580SValentin Clement                     mlir::Value base) const {
1415af6ee580SValentin Clement     return insertField(rewriter, loc, dest, {0}, base, /*bitCast=*/true);
1416af6ee580SValentin Clement   }
1417af6ee580SValentin Clement 
1418af6ee580SValentin Clement   /// Get the address of the type descriptor global variable that was created by
1419af6ee580SValentin Clement   /// lowering for derived type \p recType.
1420af6ee580SValentin Clement   template <typename BOX>
1421af6ee580SValentin Clement   mlir::Value
1422af6ee580SValentin Clement   getTypeDescriptor(BOX box, mlir::ConversionPatternRewriter &rewriter,
1423af6ee580SValentin Clement                     mlir::Location loc, fir::RecordType recType) const {
1424af6ee580SValentin Clement     std::string name = recType.getLoweredName();
1425af6ee580SValentin Clement     auto module = box->template getParentOfType<mlir::ModuleOp>();
1426af6ee580SValentin Clement     if (auto global = module.template lookupSymbol<fir::GlobalOp>(name)) {
1427af6ee580SValentin Clement       auto ty = mlir::LLVM::LLVMPointerType::get(
1428af6ee580SValentin Clement           this->lowerTy().convertType(global.getType()));
1429af6ee580SValentin Clement       return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty,
1430af6ee580SValentin Clement                                                       global.sym_name());
1431af6ee580SValentin Clement     }
1432af6ee580SValentin Clement     if (auto global =
1433af6ee580SValentin Clement             module.template lookupSymbol<mlir::LLVM::GlobalOp>(name)) {
1434af6ee580SValentin Clement       // The global may have already been translated to LLVM.
1435af6ee580SValentin Clement       auto ty = mlir::LLVM::LLVMPointerType::get(global.getType());
1436af6ee580SValentin Clement       return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty,
1437af6ee580SValentin Clement                                                       global.sym_name());
1438af6ee580SValentin Clement     }
1439af6ee580SValentin Clement     // The global does not exist in the current translation unit, but may be
1440af6ee580SValentin Clement     // defined elsewhere (e.g., type defined in a module).
1441af6ee580SValentin Clement     // For now, create a extern_weak symbol (will become nullptr if unresolved)
1442af6ee580SValentin Clement     // to support generating code without the front-end generated symbols.
1443af6ee580SValentin Clement     // These could be made available_externally to require the symbols to be
1444af6ee580SValentin Clement     // defined elsewhere and to cause link-time failure otherwise.
1445af6ee580SValentin Clement     auto i8Ty = rewriter.getIntegerType(8);
1446af6ee580SValentin Clement     mlir::OpBuilder modBuilder(module.getBodyRegion());
1447af6ee580SValentin Clement     // TODO: The symbol should be lowered to constant in lowering, they are read
1448af6ee580SValentin Clement     // only.
1449af6ee580SValentin Clement     modBuilder.create<mlir::LLVM::GlobalOp>(loc, i8Ty, /*isConstant=*/false,
1450af6ee580SValentin Clement                                             mlir::LLVM::Linkage::ExternWeak,
1451af6ee580SValentin Clement                                             name, mlir::Attribute{});
1452af6ee580SValentin Clement     auto ty = mlir::LLVM::LLVMPointerType::get(i8Ty);
1453af6ee580SValentin Clement     return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty, name);
1454af6ee580SValentin Clement   }
1455af6ee580SValentin Clement 
1456af6ee580SValentin Clement   template <typename BOX>
1457af6ee580SValentin Clement   std::tuple<fir::BoxType, mlir::Value, mlir::Value>
1458af6ee580SValentin Clement   consDescriptorPrefix(BOX box, mlir::ConversionPatternRewriter &rewriter,
1459af6ee580SValentin Clement                        unsigned rank, mlir::ValueRange lenParams) const {
1460af6ee580SValentin Clement     auto loc = box.getLoc();
1461af6ee580SValentin Clement     auto boxTy = box.getType().template dyn_cast<fir::BoxType>();
1462af6ee580SValentin Clement     auto convTy = this->lowerTy().convertBoxType(boxTy, rank);
1463af6ee580SValentin Clement     auto llvmBoxPtrTy = convTy.template cast<mlir::LLVM::LLVMPointerType>();
1464af6ee580SValentin Clement     auto llvmBoxTy = llvmBoxPtrTy.getElementType();
1465af6ee580SValentin Clement     mlir::Value descriptor =
1466af6ee580SValentin Clement         rewriter.create<mlir::LLVM::UndefOp>(loc, llvmBoxTy);
1467af6ee580SValentin Clement 
1468af6ee580SValentin Clement     llvm::SmallVector<mlir::Value> typeparams = lenParams;
1469af6ee580SValentin Clement     if constexpr (!std::is_same_v<BOX, fir::EmboxOp>) {
1470af6ee580SValentin Clement       if (!box.substr().empty() && fir::hasDynamicSize(boxTy.getEleTy()))
1471af6ee580SValentin Clement         typeparams.push_back(box.substr()[1]);
1472af6ee580SValentin Clement     }
1473af6ee580SValentin Clement 
1474af6ee580SValentin Clement     // Write each of the fields with the appropriate values
1475af6ee580SValentin Clement     auto [eleSize, cfiTy] =
1476af6ee580SValentin Clement         getSizeAndTypeCode(loc, rewriter, boxTy.getEleTy(), typeparams);
1477af6ee580SValentin Clement     descriptor =
1478af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kElemLenPosInBox}, eleSize);
1479af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kVersionPosInBox},
1480af6ee580SValentin Clement                              this->genI32Constant(loc, rewriter, CFI_VERSION));
1481af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kRankPosInBox},
1482af6ee580SValentin Clement                              this->genI32Constant(loc, rewriter, rank));
1483af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kTypePosInBox}, cfiTy);
1484af6ee580SValentin Clement     descriptor =
1485af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kAttributePosInBox},
1486af6ee580SValentin Clement                     this->genI32Constant(loc, rewriter, getCFIAttr(boxTy)));
1487af6ee580SValentin Clement     const bool hasAddendum = isDerivedType(boxTy);
1488af6ee580SValentin Clement     descriptor =
1489af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kF18AddendumPosInBox},
1490af6ee580SValentin Clement                     this->genI32Constant(loc, rewriter, hasAddendum ? 1 : 0));
1491af6ee580SValentin Clement 
1492af6ee580SValentin Clement     if (hasAddendum) {
1493af6ee580SValentin Clement       auto isArray =
1494af6ee580SValentin Clement           fir::dyn_cast_ptrOrBoxEleTy(boxTy).template isa<fir::SequenceType>();
1495af6ee580SValentin Clement       unsigned typeDescFieldId = isArray ? kOptTypePtrPosInBox : kDimsPosInBox;
1496af6ee580SValentin Clement       auto typeDesc =
1497af6ee580SValentin Clement           getTypeDescriptor(box, rewriter, loc, unwrapIfDerived(boxTy));
1498af6ee580SValentin Clement       descriptor =
1499af6ee580SValentin Clement           insertField(rewriter, loc, descriptor, {typeDescFieldId}, typeDesc,
1500af6ee580SValentin Clement                       /*bitCast=*/true);
1501af6ee580SValentin Clement     }
1502af6ee580SValentin Clement 
1503af6ee580SValentin Clement     return {boxTy, descriptor, eleSize};
1504af6ee580SValentin Clement   }
1505af6ee580SValentin Clement 
1506af6ee580SValentin Clement   /// If the embox is not in a globalOp body, allocate storage for the box;
1507af6ee580SValentin Clement   /// store the value inside and return the generated alloca. Return the input
1508af6ee580SValentin Clement   /// value otherwise.
1509af6ee580SValentin Clement   mlir::Value
1510af6ee580SValentin Clement   placeInMemoryIfNotGlobalInit(mlir::ConversionPatternRewriter &rewriter,
1511af6ee580SValentin Clement                                mlir::Location loc, mlir::Value boxValue) const {
1512af6ee580SValentin Clement     auto *thisBlock = rewriter.getInsertionBlock();
1513af6ee580SValentin Clement     if (thisBlock && mlir::isa<mlir::LLVM::GlobalOp>(thisBlock->getParentOp()))
1514af6ee580SValentin Clement       return boxValue;
1515af6ee580SValentin Clement     auto boxPtrTy = mlir::LLVM::LLVMPointerType::get(boxValue.getType());
1516af6ee580SValentin Clement     auto alloca = genAllocaWithType(loc, boxPtrTy, defaultAlign, rewriter);
1517af6ee580SValentin Clement     rewriter.create<mlir::LLVM::StoreOp>(loc, boxValue, alloca);
1518af6ee580SValentin Clement     return alloca;
1519af6ee580SValentin Clement   }
1520af6ee580SValentin Clement };
1521af6ee580SValentin Clement 
1522af6ee580SValentin Clement /// Create a generic box on a memory reference. This conversions lowers the
1523af6ee580SValentin Clement /// abstract box to the appropriate, initialized descriptor.
1524af6ee580SValentin Clement struct EmboxOpConversion : public EmboxCommonConversion<fir::EmboxOp> {
1525af6ee580SValentin Clement   using EmboxCommonConversion::EmboxCommonConversion;
1526af6ee580SValentin Clement 
1527af6ee580SValentin Clement   mlir::LogicalResult
1528af6ee580SValentin Clement   matchAndRewrite(fir::EmboxOp embox, OpAdaptor adaptor,
1529af6ee580SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1530af6ee580SValentin Clement     assert(!embox.getShape() && "There should be no dims on this embox op");
1531af6ee580SValentin Clement     auto [boxTy, dest, eleSize] =
1532af6ee580SValentin Clement         consDescriptorPrefix(embox, rewriter, /*rank=*/0,
1533af6ee580SValentin Clement                              /*lenParams=*/adaptor.getOperands().drop_front(1));
1534af6ee580SValentin Clement     dest = insertBaseAddress(rewriter, embox.getLoc(), dest,
1535af6ee580SValentin Clement                              adaptor.getOperands()[0]);
1536af6ee580SValentin Clement     if (isDerivedTypeWithLenParams(boxTy))
1537af6ee580SValentin Clement       return rewriter.notifyMatchFailure(
1538af6ee580SValentin Clement           embox, "fir.embox codegen of derived with length parameters not "
1539af6ee580SValentin Clement                  "implemented yet");
1540af6ee580SValentin Clement     auto result = placeInMemoryIfNotGlobalInit(rewriter, embox.getLoc(), dest);
1541af6ee580SValentin Clement     rewriter.replaceOp(embox, result);
1542af6ee580SValentin Clement     return success();
1543af6ee580SValentin Clement   }
1544af6ee580SValentin Clement };
1545af6ee580SValentin Clement 
1546*cc505c0bSKiran Chandramohan /// Lower `fir.emboxproc` operation. Creates a procedure box.
1547*cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
1548*cc505c0bSKiran Chandramohan struct EmboxProcOpConversion : public FIROpConversion<fir::EmboxProcOp> {
1549*cc505c0bSKiran Chandramohan   using FIROpConversion::FIROpConversion;
1550*cc505c0bSKiran Chandramohan 
1551*cc505c0bSKiran Chandramohan   mlir::LogicalResult
1552*cc505c0bSKiran Chandramohan   matchAndRewrite(fir::EmboxProcOp emboxproc, OpAdaptor adaptor,
1553*cc505c0bSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
1554*cc505c0bSKiran Chandramohan     return rewriter.notifyMatchFailure(
1555*cc505c0bSKiran Chandramohan         emboxproc, "fir.emboxproc codegen is not implemented yet");
1556*cc505c0bSKiran Chandramohan   }
1557*cc505c0bSKiran Chandramohan };
1558*cc505c0bSKiran Chandramohan 
1559*cc505c0bSKiran Chandramohan 
156054c56347SValentin Clement // Code shared between insert_value and extract_value Ops.
156154c56347SValentin Clement struct ValueOpCommon {
156254c56347SValentin Clement   // Translate the arguments pertaining to any multidimensional array to
156354c56347SValentin Clement   // row-major order for LLVM-IR.
156454c56347SValentin Clement   static void toRowMajor(SmallVectorImpl<mlir::Attribute> &attrs,
156554c56347SValentin Clement                          mlir::Type ty) {
156654c56347SValentin Clement     assert(ty && "type is null");
156754c56347SValentin Clement     const auto end = attrs.size();
156854c56347SValentin Clement     for (std::remove_const_t<decltype(end)> i = 0; i < end; ++i) {
156954c56347SValentin Clement       if (auto seq = ty.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
157054c56347SValentin Clement         const auto dim = getDimension(seq);
157154c56347SValentin Clement         if (dim > 1) {
157254c56347SValentin Clement           auto ub = std::min(i + dim, end);
157354c56347SValentin Clement           std::reverse(attrs.begin() + i, attrs.begin() + ub);
157454c56347SValentin Clement           i += dim - 1;
157554c56347SValentin Clement         }
157654c56347SValentin Clement         ty = getArrayElementType(seq);
157754c56347SValentin Clement       } else if (auto st = ty.dyn_cast<mlir::LLVM::LLVMStructType>()) {
157854c56347SValentin Clement         ty = st.getBody()[attrs[i].cast<mlir::IntegerAttr>().getInt()];
157954c56347SValentin Clement       } else {
158054c56347SValentin Clement         llvm_unreachable("index into invalid type");
158154c56347SValentin Clement       }
158254c56347SValentin Clement     }
158354c56347SValentin Clement   }
158454c56347SValentin Clement 
158554c56347SValentin Clement   static llvm::SmallVector<mlir::Attribute>
158654c56347SValentin Clement   collectIndices(mlir::ConversionPatternRewriter &rewriter,
158754c56347SValentin Clement                  mlir::ArrayAttr arrAttr) {
158854c56347SValentin Clement     llvm::SmallVector<mlir::Attribute> attrs;
158954c56347SValentin Clement     for (auto i = arrAttr.begin(), e = arrAttr.end(); i != e; ++i) {
159054c56347SValentin Clement       if (i->isa<mlir::IntegerAttr>()) {
159154c56347SValentin Clement         attrs.push_back(*i);
159254c56347SValentin Clement       } else {
159354c56347SValentin Clement         auto fieldName = i->cast<mlir::StringAttr>().getValue();
159454c56347SValentin Clement         ++i;
159554c56347SValentin Clement         auto ty = i->cast<mlir::TypeAttr>().getValue();
159654c56347SValentin Clement         auto index = ty.cast<fir::RecordType>().getFieldIndex(fieldName);
159754c56347SValentin Clement         attrs.push_back(mlir::IntegerAttr::get(rewriter.getI32Type(), index));
159854c56347SValentin Clement       }
159954c56347SValentin Clement     }
160054c56347SValentin Clement     return attrs;
160154c56347SValentin Clement   }
160254c56347SValentin Clement 
160354c56347SValentin Clement private:
160454c56347SValentin Clement   static unsigned getDimension(mlir::LLVM::LLVMArrayType ty) {
160554c56347SValentin Clement     unsigned result = 1;
160654c56347SValentin Clement     for (auto eleTy = ty.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>();
160754c56347SValentin Clement          eleTy;
160854c56347SValentin Clement          eleTy = eleTy.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>())
160954c56347SValentin Clement       ++result;
161054c56347SValentin Clement     return result;
161154c56347SValentin Clement   }
161254c56347SValentin Clement 
161354c56347SValentin Clement   static mlir::Type getArrayElementType(mlir::LLVM::LLVMArrayType ty) {
161454c56347SValentin Clement     auto eleTy = ty.getElementType();
161554c56347SValentin Clement     while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>())
161654c56347SValentin Clement       eleTy = arrTy.getElementType();
161754c56347SValentin Clement     return eleTy;
161854c56347SValentin Clement   }
161954c56347SValentin Clement };
162054c56347SValentin Clement 
162154c56347SValentin Clement /// Extract a subobject value from an ssa-value of aggregate type
162254c56347SValentin Clement struct ExtractValueOpConversion
162354c56347SValentin Clement     : public FIROpAndTypeConversion<fir::ExtractValueOp>,
162454c56347SValentin Clement       public ValueOpCommon {
162554c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
162654c56347SValentin Clement 
162754c56347SValentin Clement   mlir::LogicalResult
162854c56347SValentin Clement   doRewrite(fir::ExtractValueOp extractVal, mlir::Type ty, OpAdaptor adaptor,
162954c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
163054c56347SValentin Clement     auto attrs = collectIndices(rewriter, extractVal.coor());
163154c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
163254c56347SValentin Clement     auto position = mlir::ArrayAttr::get(extractVal.getContext(), attrs);
163354c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(
163454c56347SValentin Clement         extractVal, ty, adaptor.getOperands()[0], position);
163554c56347SValentin Clement     return success();
163654c56347SValentin Clement   }
163754c56347SValentin Clement };
163854c56347SValentin Clement 
163954c56347SValentin Clement /// InsertValue is the generalized instruction for the composition of new
164054c56347SValentin Clement /// aggregate type values.
164154c56347SValentin Clement struct InsertValueOpConversion
164254c56347SValentin Clement     : public FIROpAndTypeConversion<fir::InsertValueOp>,
164354c56347SValentin Clement       public ValueOpCommon {
164454c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
164554c56347SValentin Clement 
164654c56347SValentin Clement   mlir::LogicalResult
164754c56347SValentin Clement   doRewrite(fir::InsertValueOp insertVal, mlir::Type ty, OpAdaptor adaptor,
164854c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
164954c56347SValentin Clement     auto attrs = collectIndices(rewriter, insertVal.coor());
165054c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
165154c56347SValentin Clement     auto position = mlir::ArrayAttr::get(insertVal.getContext(), attrs);
165254c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
165354c56347SValentin Clement         insertVal, ty, adaptor.getOperands()[0], adaptor.getOperands()[1],
165454c56347SValentin Clement         position);
165554c56347SValentin Clement     return success();
165654c56347SValentin Clement   }
165754c56347SValentin Clement };
165854c56347SValentin Clement 
16593ae8e442SValentin Clement /// InsertOnRange inserts a value into a sequence over a range of offsets.
16603ae8e442SValentin Clement struct InsertOnRangeOpConversion
16613ae8e442SValentin Clement     : public FIROpAndTypeConversion<fir::InsertOnRangeOp> {
16623ae8e442SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
16633ae8e442SValentin Clement 
16643ae8e442SValentin Clement   // Increments an array of subscripts in a row major fasion.
16653ae8e442SValentin Clement   void incrementSubscripts(const SmallVector<uint64_t> &dims,
16663ae8e442SValentin Clement                            SmallVector<uint64_t> &subscripts) const {
16673ae8e442SValentin Clement     for (size_t i = dims.size(); i > 0; --i) {
16683ae8e442SValentin Clement       if (++subscripts[i - 1] < dims[i - 1]) {
16693ae8e442SValentin Clement         return;
16703ae8e442SValentin Clement       }
16713ae8e442SValentin Clement       subscripts[i - 1] = 0;
16723ae8e442SValentin Clement     }
16733ae8e442SValentin Clement   }
16743ae8e442SValentin Clement 
16753ae8e442SValentin Clement   mlir::LogicalResult
16763ae8e442SValentin Clement   doRewrite(fir::InsertOnRangeOp range, mlir::Type ty, OpAdaptor adaptor,
16773ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
16783ae8e442SValentin Clement 
16793ae8e442SValentin Clement     llvm::SmallVector<uint64_t> dims;
16803ae8e442SValentin Clement     auto type = adaptor.getOperands()[0].getType();
16813ae8e442SValentin Clement 
16823ae8e442SValentin Clement     // Iteratively extract the array dimensions from the type.
16833ae8e442SValentin Clement     while (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
16843ae8e442SValentin Clement       dims.push_back(t.getNumElements());
16853ae8e442SValentin Clement       type = t.getElementType();
16863ae8e442SValentin Clement     }
16873ae8e442SValentin Clement 
16883ae8e442SValentin Clement     SmallVector<uint64_t> lBounds;
16893ae8e442SValentin Clement     SmallVector<uint64_t> uBounds;
16903ae8e442SValentin Clement 
16913ae8e442SValentin Clement     // Extract integer value from the attribute
16923ae8e442SValentin Clement     SmallVector<int64_t> coordinates = llvm::to_vector<4>(
16933ae8e442SValentin Clement         llvm::map_range(range.coor(), [](Attribute a) -> int64_t {
16943ae8e442SValentin Clement           return a.cast<IntegerAttr>().getInt();
16953ae8e442SValentin Clement         }));
16963ae8e442SValentin Clement 
16973ae8e442SValentin Clement     // Unzip the upper and lower bound and convert to a row major format.
16983ae8e442SValentin Clement     for (auto i = coordinates.rbegin(), e = coordinates.rend(); i != e; ++i) {
16993ae8e442SValentin Clement       uBounds.push_back(*i++);
17003ae8e442SValentin Clement       lBounds.push_back(*i);
17013ae8e442SValentin Clement     }
17023ae8e442SValentin Clement 
17033ae8e442SValentin Clement     auto &subscripts = lBounds;
17043ae8e442SValentin Clement     auto loc = range.getLoc();
17053ae8e442SValentin Clement     mlir::Value lastOp = adaptor.getOperands()[0];
17063ae8e442SValentin Clement     mlir::Value insertVal = adaptor.getOperands()[1];
17073ae8e442SValentin Clement 
17083ae8e442SValentin Clement     auto i64Ty = rewriter.getI64Type();
17093ae8e442SValentin Clement     while (subscripts != uBounds) {
17103ae8e442SValentin Clement       // Convert uint64_t's to Attribute's.
17113ae8e442SValentin Clement       SmallVector<mlir::Attribute> subscriptAttrs;
17123ae8e442SValentin Clement       for (const auto &subscript : subscripts)
17133ae8e442SValentin Clement         subscriptAttrs.push_back(IntegerAttr::get(i64Ty, subscript));
17143ae8e442SValentin Clement       lastOp = rewriter.create<mlir::LLVM::InsertValueOp>(
17153ae8e442SValentin Clement           loc, ty, lastOp, insertVal,
17163ae8e442SValentin Clement           ArrayAttr::get(range.getContext(), subscriptAttrs));
17173ae8e442SValentin Clement 
17183ae8e442SValentin Clement       incrementSubscripts(dims, subscripts);
17193ae8e442SValentin Clement     }
17203ae8e442SValentin Clement 
17213ae8e442SValentin Clement     // Convert uint64_t's to Attribute's.
17223ae8e442SValentin Clement     SmallVector<mlir::Attribute> subscriptAttrs;
17233ae8e442SValentin Clement     for (const auto &subscript : subscripts)
17243ae8e442SValentin Clement       subscriptAttrs.push_back(
17253ae8e442SValentin Clement           IntegerAttr::get(rewriter.getI64Type(), subscript));
17263ae8e442SValentin Clement     mlir::ArrayRef<mlir::Attribute> arrayRef(subscriptAttrs);
17273ae8e442SValentin Clement 
17283ae8e442SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
17293ae8e442SValentin Clement         range, ty, lastOp, insertVal,
17303ae8e442SValentin Clement         ArrayAttr::get(range.getContext(), arrayRef));
17313ae8e442SValentin Clement 
17323ae8e442SValentin Clement     return success();
17333ae8e442SValentin Clement   }
17343ae8e442SValentin Clement };
17357b5132daSValentin Clement 
17367b5132daSValentin Clement //
17377b5132daSValentin Clement // Primitive operations on Complex types
17387b5132daSValentin Clement //
17397b5132daSValentin Clement 
17407b5132daSValentin Clement /// Generate inline code for complex addition/subtraction
17417b5132daSValentin Clement template <typename LLVMOP, typename OPTY>
17427b5132daSValentin Clement mlir::LLVM::InsertValueOp complexSum(OPTY sumop, mlir::ValueRange opnds,
17437b5132daSValentin Clement                                      mlir::ConversionPatternRewriter &rewriter,
17447b5132daSValentin Clement                                      fir::LLVMTypeConverter &lowering) {
17457b5132daSValentin Clement   mlir::Value a = opnds[0];
17467b5132daSValentin Clement   mlir::Value b = opnds[1];
17477b5132daSValentin Clement   auto loc = sumop.getLoc();
17487b5132daSValentin Clement   auto ctx = sumop.getContext();
17497b5132daSValentin Clement   auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
17507b5132daSValentin Clement   auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
17517b5132daSValentin Clement   mlir::Type eleTy = lowering.convertType(getComplexEleTy(sumop.getType()));
17527b5132daSValentin Clement   mlir::Type ty = lowering.convertType(sumop.getType());
17537b5132daSValentin Clement   auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
17547b5132daSValentin Clement   auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
17557b5132daSValentin Clement   auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
17567b5132daSValentin Clement   auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
17577b5132daSValentin Clement   auto rx = rewriter.create<LLVMOP>(loc, eleTy, x0, x1);
17587b5132daSValentin Clement   auto ry = rewriter.create<LLVMOP>(loc, eleTy, y0, y1);
17597b5132daSValentin Clement   auto r0 = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
17607b5132daSValentin Clement   auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r0, rx, c0);
17617b5132daSValentin Clement   return rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ry, c1);
17627b5132daSValentin Clement }
17637b5132daSValentin Clement 
17647b5132daSValentin Clement struct AddcOpConversion : public FIROpConversion<fir::AddcOp> {
17657b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
17667b5132daSValentin Clement 
17677b5132daSValentin Clement   mlir::LogicalResult
17687b5132daSValentin Clement   matchAndRewrite(fir::AddcOp addc, OpAdaptor adaptor,
17697b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
17707b5132daSValentin Clement     // given: (x + iy) + (x' + iy')
17717b5132daSValentin Clement     // result: (x + x') + i(y + y')
17727b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FAddOp>(addc, adaptor.getOperands(),
17737b5132daSValentin Clement                                             rewriter, lowerTy());
17747b5132daSValentin Clement     rewriter.replaceOp(addc, r.getResult());
17757b5132daSValentin Clement     return success();
17767b5132daSValentin Clement   }
17777b5132daSValentin Clement };
17787b5132daSValentin Clement 
17797b5132daSValentin Clement struct SubcOpConversion : public FIROpConversion<fir::SubcOp> {
17807b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
17817b5132daSValentin Clement 
17827b5132daSValentin Clement   mlir::LogicalResult
17837b5132daSValentin Clement   matchAndRewrite(fir::SubcOp subc, OpAdaptor adaptor,
17847b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
17857b5132daSValentin Clement     // given: (x + iy) - (x' + iy')
17867b5132daSValentin Clement     // result: (x - x') + i(y - y')
17877b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FSubOp>(subc, adaptor.getOperands(),
17887b5132daSValentin Clement                                             rewriter, lowerTy());
17897b5132daSValentin Clement     rewriter.replaceOp(subc, r.getResult());
17907b5132daSValentin Clement     return success();
17917b5132daSValentin Clement   }
17927b5132daSValentin Clement };
17937b5132daSValentin Clement 
17947b5132daSValentin Clement /// Inlined complex multiply
17957b5132daSValentin Clement struct MulcOpConversion : public FIROpConversion<fir::MulcOp> {
17967b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
17977b5132daSValentin Clement 
17987b5132daSValentin Clement   mlir::LogicalResult
17997b5132daSValentin Clement   matchAndRewrite(fir::MulcOp mulc, OpAdaptor adaptor,
18007b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
18017b5132daSValentin Clement     // TODO: Can we use a call to __muldc3 ?
18027b5132daSValentin Clement     // given: (x + iy) * (x' + iy')
18037b5132daSValentin Clement     // result: (xx'-yy')+i(xy'+yx')
18047b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
18057b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
18067b5132daSValentin Clement     auto loc = mulc.getLoc();
18077b5132daSValentin Clement     auto *ctx = mulc.getContext();
18087b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
18097b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
18107b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(mulc.getType()));
18117b5132daSValentin Clement     mlir::Type ty = convertType(mulc.getType());
18127b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
18137b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
18147b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
18157b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
18167b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
18177b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
18187b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
18197b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xy, yx);
18207b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
18217b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, xx, yy);
18227b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
18237b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
18247b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
18257b5132daSValentin Clement     rewriter.replaceOp(mulc, r0.getResult());
18267b5132daSValentin Clement     return success();
18277b5132daSValentin Clement   }
18287b5132daSValentin Clement };
18297b5132daSValentin Clement 
18307b5132daSValentin Clement /// Inlined complex division
18317b5132daSValentin Clement struct DivcOpConversion : public FIROpConversion<fir::DivcOp> {
18327b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
18337b5132daSValentin Clement 
18347b5132daSValentin Clement   mlir::LogicalResult
18357b5132daSValentin Clement   matchAndRewrite(fir::DivcOp divc, OpAdaptor adaptor,
18367b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
18377b5132daSValentin Clement     // TODO: Can we use a call to __divdc3 instead?
18387b5132daSValentin Clement     // Just generate inline code for now.
18397b5132daSValentin Clement     // given: (x + iy) / (x' + iy')
18407b5132daSValentin Clement     // result: ((xx'+yy')/d) + i((yx'-xy')/d) where d = x'x' + y'y'
18417b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
18427b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
18437b5132daSValentin Clement     auto loc = divc.getLoc();
18447b5132daSValentin Clement     auto *ctx = divc.getContext();
18457b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
18467b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
18477b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(divc.getType()));
18487b5132daSValentin Clement     mlir::Type ty = convertType(divc.getType());
18497b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
18507b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
18517b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
18527b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
18537b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
18547b5132daSValentin Clement     auto x1x1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x1, x1);
18557b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
18567b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
18577b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
18587b5132daSValentin Clement     auto y1y1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y1, y1);
18597b5132daSValentin Clement     auto d = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, x1x1, y1y1);
18607b5132daSValentin Clement     auto rrn = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xx, yy);
18617b5132daSValentin Clement     auto rin = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, yx, xy);
18627b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rrn, d);
18637b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rin, d);
18647b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
18657b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
18667b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
18677b5132daSValentin Clement     rewriter.replaceOp(divc, r0.getResult());
18687b5132daSValentin Clement     return success();
18697b5132daSValentin Clement   }
18707b5132daSValentin Clement };
18717b5132daSValentin Clement 
18727b5132daSValentin Clement /// Inlined complex negation
18737b5132daSValentin Clement struct NegcOpConversion : public FIROpConversion<fir::NegcOp> {
18747b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
18757b5132daSValentin Clement 
18767b5132daSValentin Clement   mlir::LogicalResult
18777b5132daSValentin Clement   matchAndRewrite(fir::NegcOp neg, OpAdaptor adaptor,
18787b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
18797b5132daSValentin Clement     // given: -(x + iy)
18807b5132daSValentin Clement     // result: -x - iy
18817b5132daSValentin Clement     auto *ctxt = neg.getContext();
18827b5132daSValentin Clement     auto eleTy = convertType(getComplexEleTy(neg.getType()));
18837b5132daSValentin Clement     auto ty = convertType(neg.getType());
18847b5132daSValentin Clement     auto loc = neg.getLoc();
18857b5132daSValentin Clement     mlir::Value o0 = adaptor.getOperands()[0];
18867b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0));
18877b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1));
18887b5132daSValentin Clement     auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c0);
18897b5132daSValentin Clement     auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c1);
18907b5132daSValentin Clement     auto nrp = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, rp);
18917b5132daSValentin Clement     auto nip = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, ip);
18927b5132daSValentin Clement     auto r = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, o0, nrp, c0);
18937b5132daSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(neg, ty, r, nip, c1);
18947b5132daSValentin Clement     return success();
18957b5132daSValentin Clement   }
18967b5132daSValentin Clement };
18977b5132daSValentin Clement 
18981ed5a90fSValentin Clement /// Conversion pattern for operation that must be dead. The information in these
18991ed5a90fSValentin Clement /// operations is used by other operation. At this point they should not have
19001ed5a90fSValentin Clement /// anymore uses.
19011ed5a90fSValentin Clement /// These operations are normally dead after the pre-codegen pass.
19021ed5a90fSValentin Clement template <typename FromOp>
19031ed5a90fSValentin Clement struct MustBeDeadConversion : public FIROpConversion<FromOp> {
19041ed5a90fSValentin Clement   explicit MustBeDeadConversion(fir::LLVMTypeConverter &lowering)
19051ed5a90fSValentin Clement       : FIROpConversion<FromOp>(lowering) {}
19061ed5a90fSValentin Clement   using OpAdaptor = typename FromOp::Adaptor;
19071ed5a90fSValentin Clement 
19081ed5a90fSValentin Clement   mlir::LogicalResult
19091ed5a90fSValentin Clement   matchAndRewrite(FromOp op, OpAdaptor adaptor,
19101ed5a90fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const final {
19111ed5a90fSValentin Clement     if (!op->getUses().empty())
19121ed5a90fSValentin Clement       return rewriter.notifyMatchFailure(op, "op must be dead");
19131ed5a90fSValentin Clement     rewriter.eraseOp(op);
19141ed5a90fSValentin Clement     return success();
19151ed5a90fSValentin Clement   }
19161ed5a90fSValentin Clement };
19171ed5a90fSValentin Clement 
19181ed5a90fSValentin Clement struct ShapeOpConversion : public MustBeDeadConversion<fir::ShapeOp> {
19191ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
19201ed5a90fSValentin Clement };
19211ed5a90fSValentin Clement 
19221ed5a90fSValentin Clement struct ShapeShiftOpConversion : public MustBeDeadConversion<fir::ShapeShiftOp> {
19231ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
19241ed5a90fSValentin Clement };
19251ed5a90fSValentin Clement 
19261ed5a90fSValentin Clement struct ShiftOpConversion : public MustBeDeadConversion<fir::ShiftOp> {
19271ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
19281ed5a90fSValentin Clement };
19291ed5a90fSValentin Clement 
19301ed5a90fSValentin Clement struct SliceOpConversion : public MustBeDeadConversion<fir::SliceOp> {
19311ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
19321ed5a90fSValentin Clement };
19331ed5a90fSValentin Clement 
1934420ad7ceSAndrzej Warzynski /// `fir.is_present` -->
1935420ad7ceSAndrzej Warzynski /// ```
1936420ad7ceSAndrzej Warzynski ///  %0 = llvm.mlir.constant(0 : i64)
1937420ad7ceSAndrzej Warzynski ///  %1 = llvm.ptrtoint %0
1938420ad7ceSAndrzej Warzynski ///  %2 = llvm.icmp "ne" %1, %0 : i64
1939420ad7ceSAndrzej Warzynski /// ```
1940420ad7ceSAndrzej Warzynski struct IsPresentOpConversion : public FIROpConversion<fir::IsPresentOp> {
1941420ad7ceSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
1942420ad7ceSAndrzej Warzynski 
1943420ad7ceSAndrzej Warzynski   mlir::LogicalResult
1944420ad7ceSAndrzej Warzynski   matchAndRewrite(fir::IsPresentOp isPresent, OpAdaptor adaptor,
1945420ad7ceSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
1946420ad7ceSAndrzej Warzynski     mlir::Type idxTy = lowerTy().indexType();
1947420ad7ceSAndrzej Warzynski     mlir::Location loc = isPresent.getLoc();
1948420ad7ceSAndrzej Warzynski     auto ptr = adaptor.getOperands()[0];
1949420ad7ceSAndrzej Warzynski 
1950420ad7ceSAndrzej Warzynski     if (isPresent.val().getType().isa<fir::BoxCharType>()) {
1951420ad7ceSAndrzej Warzynski       auto structTy = ptr.getType().cast<mlir::LLVM::LLVMStructType>();
1952420ad7ceSAndrzej Warzynski       assert(!structTy.isOpaque() && !structTy.getBody().empty());
1953420ad7ceSAndrzej Warzynski 
1954420ad7ceSAndrzej Warzynski       mlir::Type ty = structTy.getBody()[0];
1955420ad7ceSAndrzej Warzynski       mlir::MLIRContext *ctx = isPresent.getContext();
1956420ad7ceSAndrzej Warzynski       auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
1957420ad7ceSAndrzej Warzynski       ptr = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, ptr, c0);
1958420ad7ceSAndrzej Warzynski     }
1959420ad7ceSAndrzej Warzynski     mlir::LLVM::ConstantOp c0 =
1960420ad7ceSAndrzej Warzynski         genConstantIndex(isPresent.getLoc(), idxTy, rewriter, 0);
1961420ad7ceSAndrzej Warzynski     auto addr = rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, ptr);
1962420ad7ceSAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
1963420ad7ceSAndrzej Warzynski         isPresent, mlir::LLVM::ICmpPredicate::ne, addr, c0);
1964420ad7ceSAndrzej Warzynski 
1965420ad7ceSAndrzej Warzynski     return success();
1966420ad7ceSAndrzej Warzynski   }
1967420ad7ceSAndrzej Warzynski };
19681e77b095SAndrzej Warzynski 
19691e77b095SAndrzej Warzynski /// Convert `!fir.emboxchar<!fir.char<KIND, ?>, #n>` into a sequence of
19701e77b095SAndrzej Warzynski /// instructions that generate `!llvm.struct<(ptr<ik>, i64)>`. The 1st element
19711e77b095SAndrzej Warzynski /// in this struct is a pointer. Its type is determined from `KIND`. The 2nd
19721e77b095SAndrzej Warzynski /// element is the length of the character buffer (`#n`).
19731e77b095SAndrzej Warzynski struct EmboxCharOpConversion : public FIROpConversion<fir::EmboxCharOp> {
19741e77b095SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
19751e77b095SAndrzej Warzynski 
19761e77b095SAndrzej Warzynski   mlir::LogicalResult
19771e77b095SAndrzej Warzynski   matchAndRewrite(fir::EmboxCharOp emboxChar, OpAdaptor adaptor,
19781e77b095SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
19791e77b095SAndrzej Warzynski     mlir::ValueRange operands = adaptor.getOperands();
19801e77b095SAndrzej Warzynski     MLIRContext *ctx = emboxChar.getContext();
19811e77b095SAndrzej Warzynski 
19821e77b095SAndrzej Warzynski     mlir::Value charBuffer = operands[0];
19831e77b095SAndrzej Warzynski     mlir::Value charBufferLen = operands[1];
19841e77b095SAndrzej Warzynski 
19851e77b095SAndrzej Warzynski     mlir::Location loc = emboxChar.getLoc();
19861e77b095SAndrzej Warzynski     mlir::Type llvmStructTy = convertType(emboxChar.getType());
19871e77b095SAndrzej Warzynski     auto llvmStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, llvmStructTy);
19881e77b095SAndrzej Warzynski 
19891e77b095SAndrzej Warzynski     mlir::Type lenTy =
19901e77b095SAndrzej Warzynski         llvmStructTy.cast<mlir::LLVM::LLVMStructType>().getBody()[1];
19911e77b095SAndrzej Warzynski     mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, charBufferLen);
19921e77b095SAndrzej Warzynski 
19931e77b095SAndrzej Warzynski     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
19941e77b095SAndrzej Warzynski     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
19951e77b095SAndrzej Warzynski     auto insertBufferOp = rewriter.create<mlir::LLVM::InsertValueOp>(
19961e77b095SAndrzej Warzynski         loc, llvmStructTy, llvmStruct, charBuffer, c0);
19971e77b095SAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
19981e77b095SAndrzej Warzynski         emboxChar, llvmStructTy, insertBufferOp, lenAfterCast, c1);
19991e77b095SAndrzej Warzynski 
20001e77b095SAndrzej Warzynski     return success();
20011e77b095SAndrzej Warzynski   }
20021e77b095SAndrzej Warzynski };
200314867ffcSAndrzej Warzynski 
200414867ffcSAndrzej Warzynski /// Construct an `llvm.extractvalue` instruction. It will return value at
200514867ffcSAndrzej Warzynski /// element \p x from  \p tuple.
200614867ffcSAndrzej Warzynski mlir::LLVM::ExtractValueOp
200714867ffcSAndrzej Warzynski genExtractValueWithIndex(mlir::Location loc, mlir::Value tuple, mlir::Type ty,
200814867ffcSAndrzej Warzynski                          mlir::ConversionPatternRewriter &rewriter,
200914867ffcSAndrzej Warzynski                          mlir::MLIRContext *ctx, int x) {
201014867ffcSAndrzej Warzynski   auto cx = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(x));
201114867ffcSAndrzej Warzynski   auto xty = ty.cast<mlir::LLVM::LLVMStructType>().getBody()[x];
201214867ffcSAndrzej Warzynski   return rewriter.create<mlir::LLVM::ExtractValueOp>(loc, xty, tuple, cx);
201314867ffcSAndrzej Warzynski }
201414867ffcSAndrzej Warzynski 
20156c3d7fd4SAndrzej Warzynski /// Convert `!fir.boxchar_len` to  `!llvm.extractvalue` for the 2nd part of the
20166c3d7fd4SAndrzej Warzynski /// boxchar.
20176c3d7fd4SAndrzej Warzynski struct BoxCharLenOpConversion : public FIROpConversion<fir::BoxCharLenOp> {
20186c3d7fd4SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
20196c3d7fd4SAndrzej Warzynski 
20206c3d7fd4SAndrzej Warzynski   mlir::LogicalResult
20216c3d7fd4SAndrzej Warzynski   matchAndRewrite(fir::BoxCharLenOp boxCharLen, OpAdaptor adaptor,
20226c3d7fd4SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
20236c3d7fd4SAndrzej Warzynski     mlir::Value boxChar = adaptor.getOperands()[0];
20246c3d7fd4SAndrzej Warzynski     mlir::Location loc = boxChar.getLoc();
20256c3d7fd4SAndrzej Warzynski     mlir::MLIRContext *ctx = boxChar.getContext();
20266c3d7fd4SAndrzej Warzynski     mlir::Type returnValTy = boxCharLen.getResult().getType();
20276c3d7fd4SAndrzej Warzynski 
20286c3d7fd4SAndrzej Warzynski     constexpr int boxcharLenIdx = 1;
20296c3d7fd4SAndrzej Warzynski     mlir::LLVM::ExtractValueOp len = genExtractValueWithIndex(
20306c3d7fd4SAndrzej Warzynski         loc, boxChar, boxChar.getType(), rewriter, ctx, boxcharLenIdx);
20316c3d7fd4SAndrzej Warzynski     mlir::Value lenAfterCast = integerCast(loc, rewriter, returnValTy, len);
20326c3d7fd4SAndrzej Warzynski     rewriter.replaceOp(boxCharLen, lenAfterCast);
20336c3d7fd4SAndrzej Warzynski 
20346c3d7fd4SAndrzej Warzynski     return success();
20356c3d7fd4SAndrzej Warzynski   }
20366c3d7fd4SAndrzej Warzynski };
20376c3d7fd4SAndrzej Warzynski 
203814867ffcSAndrzej Warzynski /// Convert `fir.unboxchar` into two `llvm.extractvalue` instructions. One for
203914867ffcSAndrzej Warzynski /// the character buffer and one for the buffer length.
204014867ffcSAndrzej Warzynski struct UnboxCharOpConversion : public FIROpConversion<fir::UnboxCharOp> {
204114867ffcSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
204214867ffcSAndrzej Warzynski 
204314867ffcSAndrzej Warzynski   mlir::LogicalResult
204414867ffcSAndrzej Warzynski   matchAndRewrite(fir::UnboxCharOp unboxchar, OpAdaptor adaptor,
204514867ffcSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
204614867ffcSAndrzej Warzynski     MLIRContext *ctx = unboxchar.getContext();
204714867ffcSAndrzej Warzynski 
204814867ffcSAndrzej Warzynski     mlir::Type lenTy = convertType(unboxchar.getType(1));
204914867ffcSAndrzej Warzynski     mlir::Value tuple = adaptor.getOperands()[0];
205014867ffcSAndrzej Warzynski     mlir::Type tupleTy = tuple.getType();
205114867ffcSAndrzej Warzynski 
205214867ffcSAndrzej Warzynski     mlir::Location loc = unboxchar.getLoc();
205314867ffcSAndrzej Warzynski     mlir::Value ptrToBuffer =
205414867ffcSAndrzej Warzynski         genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 0);
205514867ffcSAndrzej Warzynski 
205614867ffcSAndrzej Warzynski     mlir::LLVM::ExtractValueOp len =
205714867ffcSAndrzej Warzynski         genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 1);
205814867ffcSAndrzej Warzynski     mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, len);
205914867ffcSAndrzej Warzynski 
206014867ffcSAndrzej Warzynski     rewriter.replaceOp(unboxchar,
206114867ffcSAndrzej Warzynski                        ArrayRef<mlir::Value>{ptrToBuffer, lenAfterCast});
206214867ffcSAndrzej Warzynski     return success();
206314867ffcSAndrzej Warzynski   }
206414867ffcSAndrzej Warzynski };
206514867ffcSAndrzej Warzynski 
2066*cc505c0bSKiran Chandramohan /// Lower `fir.unboxproc` operation. Unbox a procedure box value, yielding its
2067*cc505c0bSKiran Chandramohan /// components.
2068*cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
2069*cc505c0bSKiran Chandramohan struct UnboxProcOpConversion : public FIROpConversion<fir::UnboxProcOp> {
2070*cc505c0bSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2071*cc505c0bSKiran Chandramohan 
2072*cc505c0bSKiran Chandramohan   mlir::LogicalResult
2073*cc505c0bSKiran Chandramohan   matchAndRewrite(fir::UnboxProcOp unboxproc, OpAdaptor adaptor,
2074*cc505c0bSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2075*cc505c0bSKiran Chandramohan     return rewriter.notifyMatchFailure(
2076*cc505c0bSKiran Chandramohan         unboxproc, "fir.unboxproc codegen is not implemented yet");
2077*cc505c0bSKiran Chandramohan   }
2078*cc505c0bSKiran Chandramohan };
2079*cc505c0bSKiran Chandramohan 
2080044d5b5dSValentin Clement } // namespace
2081044d5b5dSValentin Clement 
2082044d5b5dSValentin Clement namespace {
2083044d5b5dSValentin Clement /// Convert FIR dialect to LLVM dialect
2084044d5b5dSValentin Clement ///
2085044d5b5dSValentin Clement /// This pass lowers all FIR dialect operations to LLVM IR dialect. An
2086044d5b5dSValentin Clement /// MLIR pass is used to lower residual Std dialect to LLVM IR dialect.
2087044d5b5dSValentin Clement ///
2088044d5b5dSValentin Clement /// This pass is not complete yet. We are upstreaming it in small patches.
2089044d5b5dSValentin Clement class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> {
2090044d5b5dSValentin Clement public:
2091044d5b5dSValentin Clement   mlir::ModuleOp getModule() { return getOperation(); }
2092044d5b5dSValentin Clement 
2093044d5b5dSValentin Clement   void runOnOperation() override final {
20947b5132daSValentin Clement     auto mod = getModule();
20957b5132daSValentin Clement     if (!forcedTargetTriple.empty()) {
20967b5132daSValentin Clement       fir::setTargetTriple(mod, forcedTargetTriple);
20977b5132daSValentin Clement     }
20987b5132daSValentin Clement 
2099044d5b5dSValentin Clement     auto *context = getModule().getContext();
2100044d5b5dSValentin Clement     fir::LLVMTypeConverter typeConverter{getModule()};
2101044d5b5dSValentin Clement     mlir::OwningRewritePatternList pattern(context);
2102df3b9810SValentin Clement     pattern.insert<
2103420ad7ceSAndrzej Warzynski         AbsentOpConversion, AddcOpConversion, AddrOfOpConversion,
21041a2ec667SValentin Clement         AllocaOpConversion, BoxAddrOpConversion, BoxCharLenOpConversion,
21051a2ec667SValentin Clement         BoxDimsOpConversion, BoxEleSizeOpConversion, BoxIsAllocOpConversion,
2106*cc505c0bSKiran Chandramohan         BoxIsArrayOpConversion, BoxIsPtrOpConversion, BoxProcHostOpConversion,
2107*cc505c0bSKiran Chandramohan         BoxRankOpConversion, BoxTypeDescOpConversion, CallOpConversion,
2108*cc505c0bSKiran Chandramohan         CmpcOpConversion, ConstcOpConversion, ConvertOpConversion,
2109*cc505c0bSKiran Chandramohan         DispatchOpConversion, DispatchTableOpConversion, DTEntryOpConversion,
2110*cc505c0bSKiran Chandramohan         DivcOpConversion, EmboxOpConversion, EmboxCharOpConversion,
2111*cc505c0bSKiran Chandramohan         EmboxProcOpConversion, ExtractValueOpConversion, HasValueOpConversion,
2112*cc505c0bSKiran Chandramohan         GenTypeDescOpConversion, GlobalLenOpConversion, GlobalOpConversion,
2113*cc505c0bSKiran Chandramohan         InsertOnRangeOpConversion, InsertValueOpConversion,
2114e81d73edSDiana Picus         IsPresentOpConversion, LoadOpConversion, NegcOpConversion,
2115e81d73edSDiana Picus         MulcOpConversion, SelectCaseOpConversion, SelectOpConversion,
2116e81d73edSDiana Picus         SelectRankOpConversion, SelectTypeOpConversion, ShapeOpConversion,
2117e81d73edSDiana Picus         ShapeShiftOpConversion, ShiftOpConversion, SliceOpConversion,
2118e81d73edSDiana Picus         StoreOpConversion, StringLitOpConversion, SubcOpConversion,
2119*cc505c0bSKiran Chandramohan         UnboxCharOpConversion, UnboxProcOpConversion, UndefOpConversion,
2120*cc505c0bSKiran Chandramohan         UnreachableOpConversion, ZeroOpConversion>(typeConverter);
2121044d5b5dSValentin Clement     mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern);
2122044d5b5dSValentin Clement     mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter,
2123044d5b5dSValentin Clement                                                             pattern);
2124044d5b5dSValentin Clement     mlir::ConversionTarget target{*context};
2125044d5b5dSValentin Clement     target.addLegalDialect<mlir::LLVM::LLVMDialect>();
2126044d5b5dSValentin Clement 
2127044d5b5dSValentin Clement     // required NOPs for applying a full conversion
2128044d5b5dSValentin Clement     target.addLegalOp<mlir::ModuleOp>();
2129044d5b5dSValentin Clement 
2130044d5b5dSValentin Clement     // apply the patterns
2131044d5b5dSValentin Clement     if (mlir::failed(mlir::applyFullConversion(getModule(), target,
2132044d5b5dSValentin Clement                                                std::move(pattern)))) {
2133044d5b5dSValentin Clement       signalPassFailure();
2134044d5b5dSValentin Clement     }
2135044d5b5dSValentin Clement   }
2136044d5b5dSValentin Clement };
2137044d5b5dSValentin Clement } // namespace
2138044d5b5dSValentin Clement 
2139044d5b5dSValentin Clement std::unique_ptr<mlir::Pass> fir::createFIRToLLVMPass() {
2140044d5b5dSValentin Clement   return std::make_unique<FIRToLLVMLowering>();
2141044d5b5dSValentin Clement }
2142