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"
141f551032SValentin Clement #include "CGOps.h"
15044d5b5dSValentin Clement #include "PassDetail.h"
16b6e44ecdSValentin Clement #include "flang/ISO_Fortran_binding.h"
1739f4ef81SValentin Clement #include "flang/Optimizer/Dialect/FIRAttr.h"
18044d5b5dSValentin Clement #include "flang/Optimizer/Dialect/FIROps.h"
19af6ee580SValentin Clement #include "flang/Optimizer/Support/TypeCode.h"
20044d5b5dSValentin Clement #include "mlir/Conversion/ArithmeticToLLVM/ArithmeticToLLVM.h"
21044d5b5dSValentin Clement #include "mlir/Conversion/LLVMCommon/Pattern.h"
22044d5b5dSValentin Clement #include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h"
23044d5b5dSValentin Clement #include "mlir/IR/BuiltinTypes.h"
243ae8e442SValentin Clement #include "mlir/IR/Matchers.h"
25044d5b5dSValentin Clement #include "mlir/Pass/Pass.h"
26044d5b5dSValentin Clement #include "llvm/ADT/ArrayRef.h"
27044d5b5dSValentin Clement 
28044d5b5dSValentin Clement #define DEBUG_TYPE "flang-codegen"
29044d5b5dSValentin Clement 
30044d5b5dSValentin Clement // fir::LLVMTypeConverter for converting to LLVM IR dialect types.
31044d5b5dSValentin Clement #include "TypeConverter.h"
32044d5b5dSValentin Clement 
33af6ee580SValentin Clement // TODO: This should really be recovered from the specified target.
34af6ee580SValentin Clement static constexpr unsigned defaultAlign = 8;
35af6ee580SValentin Clement 
36b6e44ecdSValentin Clement /// `fir.box` attribute values as defined for CFI_attribute_t in
37b6e44ecdSValentin Clement /// flang/ISO_Fortran_binding.h.
38b6e44ecdSValentin Clement static constexpr unsigned kAttrPointer = CFI_attribute_pointer;
39b6e44ecdSValentin Clement static constexpr unsigned kAttrAllocatable = CFI_attribute_allocatable;
40b6e44ecdSValentin Clement 
411e6d9c06SDiana Picus static mlir::LLVM::ConstantOp
421e6d9c06SDiana Picus genConstantIndex(mlir::Location loc, mlir::Type ity,
431e6d9c06SDiana Picus                  mlir::ConversionPatternRewriter &rewriter,
441e6d9c06SDiana Picus                  std::int64_t offset) {
451e6d9c06SDiana Picus   auto cattr = rewriter.getI64IntegerAttr(offset);
461e6d9c06SDiana Picus   return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr);
471e6d9c06SDiana Picus }
481e6d9c06SDiana Picus 
4939f4ef81SValentin Clement static Block *createBlock(mlir::ConversionPatternRewriter &rewriter,
5039f4ef81SValentin Clement                           mlir::Block *insertBefore) {
5139f4ef81SValentin Clement   assert(insertBefore && "expected valid insertion block");
5239f4ef81SValentin Clement   return rewriter.createBlock(insertBefore->getParent(),
5339f4ef81SValentin Clement                               mlir::Region::iterator(insertBefore));
5439f4ef81SValentin Clement }
5539f4ef81SValentin Clement 
56044d5b5dSValentin Clement namespace {
57044d5b5dSValentin Clement /// FIR conversion pattern template
58044d5b5dSValentin Clement template <typename FromOp>
59044d5b5dSValentin Clement class FIROpConversion : public mlir::ConvertOpToLLVMPattern<FromOp> {
60044d5b5dSValentin Clement public:
61044d5b5dSValentin Clement   explicit FIROpConversion(fir::LLVMTypeConverter &lowering)
62044d5b5dSValentin Clement       : mlir::ConvertOpToLLVMPattern<FromOp>(lowering) {}
63044d5b5dSValentin Clement 
64044d5b5dSValentin Clement protected:
65044d5b5dSValentin Clement   mlir::Type convertType(mlir::Type ty) const {
66044d5b5dSValentin Clement     return lowerTy().convertType(ty);
67044d5b5dSValentin Clement   }
68044d5b5dSValentin Clement 
69*5d27abe6SValentin Clement   mlir::Type getVoidPtrType() const {
70*5d27abe6SValentin Clement     return mlir::LLVM::LLVMPointerType::get(
71*5d27abe6SValentin Clement         mlir::IntegerType::get(&lowerTy().getContext(), 8));
72*5d27abe6SValentin Clement   }
73*5d27abe6SValentin Clement 
74df3b9810SValentin Clement   mlir::LLVM::ConstantOp
75af6ee580SValentin Clement   genI32Constant(mlir::Location loc, mlir::ConversionPatternRewriter &rewriter,
76af6ee580SValentin Clement                  int value) const {
77af6ee580SValentin Clement     mlir::Type i32Ty = rewriter.getI32Type();
78af6ee580SValentin Clement     mlir::IntegerAttr attr = rewriter.getI32IntegerAttr(value);
79af6ee580SValentin Clement     return rewriter.create<mlir::LLVM::ConstantOp>(loc, i32Ty, attr);
80af6ee580SValentin Clement   }
81af6ee580SValentin Clement 
82af6ee580SValentin Clement   mlir::LLVM::ConstantOp
83df3b9810SValentin Clement   genConstantOffset(mlir::Location loc,
84df3b9810SValentin Clement                     mlir::ConversionPatternRewriter &rewriter,
85df3b9810SValentin Clement                     int offset) const {
86af6ee580SValentin Clement     mlir::Type ity = lowerTy().offsetType();
87af6ee580SValentin Clement     mlir::IntegerAttr cattr = rewriter.getI32IntegerAttr(offset);
88df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr);
89df3b9810SValentin Clement   }
90df3b9810SValentin Clement 
91b6e44ecdSValentin Clement   /// Construct code sequence to extract the specifc value from a `fir.box`.
92b6e44ecdSValentin Clement   mlir::Value getValueFromBox(mlir::Location loc, mlir::Value box,
93df3b9810SValentin Clement                               mlir::Type resultTy,
94b6e44ecdSValentin Clement                               mlir::ConversionPatternRewriter &rewriter,
95b6e44ecdSValentin Clement                               unsigned boxValue) const {
96df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
97b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp cValuePos =
98b6e44ecdSValentin Clement         genConstantOffset(loc, rewriter, boxValue);
99df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(resultTy);
100df3b9810SValentin Clement     auto p = rewriter.create<mlir::LLVM::GEPOp>(
101b6e44ecdSValentin Clement         loc, pty, mlir::ValueRange{box, c0, cValuePos});
102df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, resultTy, p);
103df3b9810SValentin Clement   }
104df3b9810SValentin Clement 
105df3b9810SValentin Clement   /// Method to construct code sequence to get the triple for dimension `dim`
106df3b9810SValentin Clement   /// from a box.
107df3b9810SValentin Clement   SmallVector<mlir::Value, 3>
108df3b9810SValentin Clement   getDimsFromBox(mlir::Location loc, ArrayRef<mlir::Type> retTys,
109df3b9810SValentin Clement                  mlir::Value box, mlir::Value dim,
110df3b9810SValentin Clement                  mlir::ConversionPatternRewriter &rewriter) const {
111df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
112df3b9810SValentin Clement     mlir::LLVM::ConstantOp cDims =
113df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kDimsPosInBox);
114df3b9810SValentin Clement     mlir::LLVM::LoadOp l0 =
115df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 0, retTys[0], rewriter);
116df3b9810SValentin Clement     mlir::LLVM::LoadOp l1 =
117df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 1, retTys[1], rewriter);
118df3b9810SValentin Clement     mlir::LLVM::LoadOp l2 =
119df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 2, retTys[2], rewriter);
120df3b9810SValentin Clement     return {l0.getResult(), l1.getResult(), l2.getResult()};
121df3b9810SValentin Clement   }
122df3b9810SValentin Clement 
123df3b9810SValentin Clement   mlir::LLVM::LoadOp
124df3b9810SValentin Clement   loadFromOffset(mlir::Location loc, mlir::Value a, mlir::LLVM::ConstantOp c0,
125df3b9810SValentin Clement                  mlir::LLVM::ConstantOp cDims, mlir::Value dim, int off,
126df3b9810SValentin Clement                  mlir::Type ty,
127df3b9810SValentin Clement                  mlir::ConversionPatternRewriter &rewriter) const {
128df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
129df3b9810SValentin Clement     mlir::LLVM::ConstantOp c = genConstantOffset(loc, rewriter, off);
130df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, a, c0, cDims, dim, c);
131df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
132df3b9810SValentin Clement   }
133df3b9810SValentin Clement 
134*5d27abe6SValentin Clement   mlir::Value
135*5d27abe6SValentin Clement   loadStrideFromBox(mlir::Location loc, mlir::Value box, unsigned dim,
136*5d27abe6SValentin Clement                     mlir::ConversionPatternRewriter &rewriter) const {
137*5d27abe6SValentin Clement     auto idxTy = lowerTy().indexType();
138*5d27abe6SValentin Clement     auto c0 = genConstantOffset(loc, rewriter, 0);
139*5d27abe6SValentin Clement     auto cDims = genConstantOffset(loc, rewriter, kDimsPosInBox);
140*5d27abe6SValentin Clement     auto dimValue = genConstantIndex(loc, idxTy, rewriter, dim);
141*5d27abe6SValentin Clement     return loadFromOffset(loc, box, c0, cDims, dimValue, kDimStridePos, idxTy,
142*5d27abe6SValentin Clement                           rewriter);
143*5d27abe6SValentin Clement   }
144*5d27abe6SValentin Clement 
145df3b9810SValentin Clement   /// Read base address from a fir.box. Returned address has type ty.
146df3b9810SValentin Clement   mlir::Value
147df3b9810SValentin Clement   loadBaseAddrFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box,
148df3b9810SValentin Clement                       mlir::ConversionPatternRewriter &rewriter) const {
149df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
150df3b9810SValentin Clement     mlir::LLVM::ConstantOp cAddr =
151df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kAddrPosInBox);
152df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
153df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cAddr);
154df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
155df3b9810SValentin Clement   }
156df3b9810SValentin Clement 
157df3b9810SValentin Clement   mlir::Value
158df3b9810SValentin Clement   loadElementSizeFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box,
159df3b9810SValentin Clement                          mlir::ConversionPatternRewriter &rewriter) const {
160df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
161df3b9810SValentin Clement     mlir::LLVM::ConstantOp cElemLen =
162df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kElemLenPosInBox);
163df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
164df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cElemLen);
165df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
166df3b9810SValentin Clement   }
167df3b9810SValentin Clement 
168b6e44ecdSValentin Clement   // Load the attribute from the \p box and perform a check against \p maskValue
169b6e44ecdSValentin Clement   // The final comparison is implemented as `(attribute & maskValue) != 0`.
170b6e44ecdSValentin Clement   mlir::Value genBoxAttributeCheck(mlir::Location loc, mlir::Value box,
171b6e44ecdSValentin Clement                                    mlir::ConversionPatternRewriter &rewriter,
172b6e44ecdSValentin Clement                                    unsigned maskValue) const {
173b6e44ecdSValentin Clement     mlir::Type attrTy = rewriter.getI32Type();
174b6e44ecdSValentin Clement     mlir::Value attribute =
175b6e44ecdSValentin Clement         getValueFromBox(loc, box, attrTy, rewriter, kAttributePosInBox);
176b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp attrMask =
177b6e44ecdSValentin Clement         genConstantOffset(loc, rewriter, maskValue);
178b6e44ecdSValentin Clement     auto maskRes =
179b6e44ecdSValentin Clement         rewriter.create<mlir::LLVM::AndOp>(loc, attrTy, attribute, attrMask);
180b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
181b6e44ecdSValentin Clement     return rewriter.create<mlir::LLVM::ICmpOp>(
182b6e44ecdSValentin Clement         loc, mlir::LLVM::ICmpPredicate::ne, maskRes, c0);
183b6e44ecdSValentin Clement   }
184b6e44ecdSValentin Clement 
185af6ee580SValentin Clement   // Get the element type given an LLVM type that is of the form
186af6ee580SValentin Clement   // [llvm.ptr](array|struct|vector)+ and the provided indexes.
187af6ee580SValentin Clement   static mlir::Type getBoxEleTy(mlir::Type type,
188af6ee580SValentin Clement                                 llvm::ArrayRef<unsigned> indexes) {
189af6ee580SValentin Clement     if (auto t = type.dyn_cast<mlir::LLVM::LLVMPointerType>())
190af6ee580SValentin Clement       type = t.getElementType();
191af6ee580SValentin Clement     for (auto i : indexes) {
192af6ee580SValentin Clement       if (auto t = type.dyn_cast<mlir::LLVM::LLVMStructType>()) {
193af6ee580SValentin Clement         assert(!t.isOpaque() && i < t.getBody().size());
194af6ee580SValentin Clement         type = t.getBody()[i];
195af6ee580SValentin Clement       } else if (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
196af6ee580SValentin Clement         type = t.getElementType();
197af6ee580SValentin Clement       } else if (auto t = type.dyn_cast<mlir::VectorType>()) {
198af6ee580SValentin Clement         type = t.getElementType();
199af6ee580SValentin Clement       } else {
200af6ee580SValentin Clement         fir::emitFatalError(mlir::UnknownLoc::get(type.getContext()),
201af6ee580SValentin Clement                             "request for invalid box element type");
202af6ee580SValentin Clement       }
203af6ee580SValentin Clement     }
204af6ee580SValentin Clement     return type;
205af6ee580SValentin Clement   }
206af6ee580SValentin Clement 
207*5d27abe6SValentin Clement   // Return LLVM type of the base address given the LLVM type
208*5d27abe6SValentin Clement   // of the related descriptor (lowered fir.box type).
209*5d27abe6SValentin Clement   static mlir::Type getBaseAddrTypeFromBox(mlir::Type type) {
210*5d27abe6SValentin Clement     return getBoxEleTy(type, {kAddrPosInBox});
211*5d27abe6SValentin Clement   }
212*5d27abe6SValentin Clement 
213df3b9810SValentin Clement   template <typename... ARGS>
214df3b9810SValentin Clement   mlir::LLVM::GEPOp genGEP(mlir::Location loc, mlir::Type ty,
215df3b9810SValentin Clement                            mlir::ConversionPatternRewriter &rewriter,
216df3b9810SValentin Clement                            mlir::Value base, ARGS... args) const {
217df3b9810SValentin Clement     SmallVector<mlir::Value> cv{args...};
218df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::GEPOp>(loc, ty, base, cv);
219df3b9810SValentin Clement   }
220df3b9810SValentin Clement 
2211e6d9c06SDiana Picus   /// Perform an extension or truncation as needed on an integer value. Lowering
2221e6d9c06SDiana Picus   /// to the specific target may involve some sign-extending or truncation of
2231e6d9c06SDiana Picus   /// values, particularly to fit them from abstract box types to the
2241e6d9c06SDiana Picus   /// appropriate reified structures.
2251e6d9c06SDiana Picus   mlir::Value integerCast(mlir::Location loc,
2261e6d9c06SDiana Picus                           mlir::ConversionPatternRewriter &rewriter,
2271e6d9c06SDiana Picus                           mlir::Type ty, mlir::Value val) const {
2281e6d9c06SDiana Picus     auto valTy = val.getType();
2291e6d9c06SDiana Picus     // If the value was not yet lowered, lower its type so that it can
2301e6d9c06SDiana Picus     // be used in getPrimitiveTypeSizeInBits.
2311e6d9c06SDiana Picus     if (!valTy.isa<mlir::IntegerType>())
2321e6d9c06SDiana Picus       valTy = convertType(valTy);
2331e6d9c06SDiana Picus     auto toSize = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
2341e6d9c06SDiana Picus     auto fromSize = mlir::LLVM::getPrimitiveTypeSizeInBits(valTy);
2351e6d9c06SDiana Picus     if (toSize < fromSize)
2361e6d9c06SDiana Picus       return rewriter.create<mlir::LLVM::TruncOp>(loc, ty, val);
2371e6d9c06SDiana Picus     if (toSize > fromSize)
2381e6d9c06SDiana Picus       return rewriter.create<mlir::LLVM::SExtOp>(loc, ty, val);
2391e6d9c06SDiana Picus     return val;
2401e6d9c06SDiana Picus   }
2411e6d9c06SDiana Picus 
242044d5b5dSValentin Clement   fir::LLVMTypeConverter &lowerTy() const {
243044d5b5dSValentin Clement     return *static_cast<fir::LLVMTypeConverter *>(this->getTypeConverter());
244044d5b5dSValentin Clement   }
245044d5b5dSValentin Clement };
246044d5b5dSValentin Clement 
2473ae8e442SValentin Clement /// FIR conversion pattern template
2483ae8e442SValentin Clement template <typename FromOp>
2493ae8e442SValentin Clement class FIROpAndTypeConversion : public FIROpConversion<FromOp> {
2503ae8e442SValentin Clement public:
2513ae8e442SValentin Clement   using FIROpConversion<FromOp>::FIROpConversion;
2523ae8e442SValentin Clement   using OpAdaptor = typename FromOp::Adaptor;
2533ae8e442SValentin Clement 
2543ae8e442SValentin Clement   mlir::LogicalResult
2553ae8e442SValentin Clement   matchAndRewrite(FromOp op, OpAdaptor adaptor,
2563ae8e442SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const final {
2573ae8e442SValentin Clement     mlir::Type ty = this->convertType(op.getType());
2583ae8e442SValentin Clement     return doRewrite(op, ty, adaptor, rewriter);
2593ae8e442SValentin Clement   }
2603ae8e442SValentin Clement 
2613ae8e442SValentin Clement   virtual mlir::LogicalResult
2623ae8e442SValentin Clement   doRewrite(FromOp addr, mlir::Type ty, OpAdaptor adaptor,
2633ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const = 0;
2643ae8e442SValentin Clement };
2653ae8e442SValentin Clement 
266420ad7ceSAndrzej Warzynski /// Create value signaling an absent optional argument in a call, e.g.
267420ad7ceSAndrzej Warzynski /// `fir.absent !fir.ref<i64>` -->  `llvm.mlir.null : !llvm.ptr<i64>`
268420ad7ceSAndrzej Warzynski struct AbsentOpConversion : public FIROpConversion<fir::AbsentOp> {
269420ad7ceSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
270420ad7ceSAndrzej Warzynski 
271420ad7ceSAndrzej Warzynski   mlir::LogicalResult
272420ad7ceSAndrzej Warzynski   matchAndRewrite(fir::AbsentOp absent, OpAdaptor,
273420ad7ceSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
274420ad7ceSAndrzej Warzynski     mlir::Type ty = convertType(absent.getType());
275420ad7ceSAndrzej Warzynski     mlir::Location loc = absent.getLoc();
276420ad7ceSAndrzej Warzynski 
277420ad7ceSAndrzej Warzynski     if (absent.getType().isa<fir::BoxCharType>()) {
278420ad7ceSAndrzej Warzynski       auto structTy = ty.cast<mlir::LLVM::LLVMStructType>();
279420ad7ceSAndrzej Warzynski       assert(!structTy.isOpaque() && !structTy.getBody().empty());
280420ad7ceSAndrzej Warzynski       auto undefStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
281420ad7ceSAndrzej Warzynski       auto nullField =
282420ad7ceSAndrzej Warzynski           rewriter.create<mlir::LLVM::NullOp>(loc, structTy.getBody()[0]);
283420ad7ceSAndrzej Warzynski       mlir::MLIRContext *ctx = absent.getContext();
284420ad7ceSAndrzej Warzynski       auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
285420ad7ceSAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
286420ad7ceSAndrzej Warzynski           absent, ty, undefStruct, nullField, c0);
287420ad7ceSAndrzej Warzynski     } else {
288420ad7ceSAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(absent, ty);
289420ad7ceSAndrzej Warzynski     }
290420ad7ceSAndrzej Warzynski     return success();
291420ad7ceSAndrzej Warzynski   }
292420ad7ceSAndrzej Warzynski };
293420ad7ceSAndrzej Warzynski 
2940c4a7a52SValentin Clement // Lower `fir.address_of` operation to `llvm.address_of` operation.
295044d5b5dSValentin Clement struct AddrOfOpConversion : public FIROpConversion<fir::AddrOfOp> {
296044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
297044d5b5dSValentin Clement 
298044d5b5dSValentin Clement   mlir::LogicalResult
299044d5b5dSValentin Clement   matchAndRewrite(fir::AddrOfOp addr, OpAdaptor adaptor,
300044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
301044d5b5dSValentin Clement     auto ty = convertType(addr.getType());
302044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::AddressOfOp>(
303044d5b5dSValentin Clement         addr, ty, addr.symbol().getRootReference().getValue());
304044d5b5dSValentin Clement     return success();
305044d5b5dSValentin Clement   }
306044d5b5dSValentin Clement };
3071e6d9c06SDiana Picus } // namespace
3081e6d9c06SDiana Picus 
3091e6d9c06SDiana Picus /// Lookup the function to compute the memory size of this parametric derived
3101e6d9c06SDiana Picus /// type. The size of the object may depend on the LEN type parameters of the
3111e6d9c06SDiana Picus /// derived type.
3121e6d9c06SDiana Picus static mlir::LLVM::LLVMFuncOp
3131e6d9c06SDiana Picus getDependentTypeMemSizeFn(fir::RecordType recTy, fir::AllocaOp op,
3141e6d9c06SDiana Picus                           mlir::ConversionPatternRewriter &rewriter) {
3151e6d9c06SDiana Picus   auto module = op->getParentOfType<mlir::ModuleOp>();
3161e6d9c06SDiana Picus   std::string name = recTy.getName().str() + "P.mem.size";
3171e6d9c06SDiana Picus   return module.lookupSymbol<mlir::LLVM::LLVMFuncOp>(name);
3181e6d9c06SDiana Picus }
3191e6d9c06SDiana Picus 
3201e6d9c06SDiana Picus namespace {
3211e6d9c06SDiana Picus /// convert to LLVM IR dialect `alloca`
3221e6d9c06SDiana Picus struct AllocaOpConversion : public FIROpConversion<fir::AllocaOp> {
3231e6d9c06SDiana Picus   using FIROpConversion::FIROpConversion;
3241e6d9c06SDiana Picus 
3251e6d9c06SDiana Picus   mlir::LogicalResult
3261e6d9c06SDiana Picus   matchAndRewrite(fir::AllocaOp alloc, OpAdaptor adaptor,
3271e6d9c06SDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
3281e6d9c06SDiana Picus     mlir::ValueRange operands = adaptor.getOperands();
3291e6d9c06SDiana Picus     auto loc = alloc.getLoc();
3301e6d9c06SDiana Picus     mlir::Type ity = lowerTy().indexType();
3311e6d9c06SDiana Picus     unsigned i = 0;
3321e6d9c06SDiana Picus     mlir::Value size = genConstantIndex(loc, ity, rewriter, 1).getResult();
3331e6d9c06SDiana Picus     mlir::Type ty = convertType(alloc.getType());
3341e6d9c06SDiana Picus     mlir::Type resultTy = ty;
3351e6d9c06SDiana Picus     if (alloc.hasLenParams()) {
3361e6d9c06SDiana Picus       unsigned end = alloc.numLenParams();
3371e6d9c06SDiana Picus       llvm::SmallVector<mlir::Value> lenParams;
3381e6d9c06SDiana Picus       for (; i < end; ++i)
3391e6d9c06SDiana Picus         lenParams.push_back(operands[i]);
3401e6d9c06SDiana Picus       mlir::Type scalarType = fir::unwrapSequenceType(alloc.getInType());
3411e6d9c06SDiana Picus       if (auto chrTy = scalarType.dyn_cast<fir::CharacterType>()) {
3421e6d9c06SDiana Picus         fir::CharacterType rawCharTy = fir::CharacterType::getUnknownLen(
3431e6d9c06SDiana Picus             chrTy.getContext(), chrTy.getFKind());
3441e6d9c06SDiana Picus         ty = mlir::LLVM::LLVMPointerType::get(convertType(rawCharTy));
3451e6d9c06SDiana Picus         assert(end == 1);
3461e6d9c06SDiana Picus         size = integerCast(loc, rewriter, ity, lenParams[0]);
3471e6d9c06SDiana Picus       } else if (auto recTy = scalarType.dyn_cast<fir::RecordType>()) {
3481e6d9c06SDiana Picus         mlir::LLVM::LLVMFuncOp memSizeFn =
3491e6d9c06SDiana Picus             getDependentTypeMemSizeFn(recTy, alloc, rewriter);
3501e6d9c06SDiana Picus         if (!memSizeFn)
3511e6d9c06SDiana Picus           emitError(loc, "did not find allocation function");
3521e6d9c06SDiana Picus         mlir::NamedAttribute attr = rewriter.getNamedAttr(
3531e6d9c06SDiana Picus             "callee", mlir::SymbolRefAttr::get(memSizeFn));
3541e6d9c06SDiana Picus         auto call = rewriter.create<mlir::LLVM::CallOp>(
3551e6d9c06SDiana Picus             loc, ity, lenParams, llvm::ArrayRef<mlir::NamedAttribute>{attr});
3561e6d9c06SDiana Picus         size = call.getResult(0);
3571e6d9c06SDiana Picus         ty = mlir::LLVM::LLVMPointerType::get(
3581e6d9c06SDiana Picus             mlir::IntegerType::get(alloc.getContext(), 8));
3591e6d9c06SDiana Picus       } else {
3601e6d9c06SDiana Picus         return emitError(loc, "unexpected type ")
3611e6d9c06SDiana Picus                << scalarType << " with type parameters";
3621e6d9c06SDiana Picus       }
3631e6d9c06SDiana Picus     }
3641e6d9c06SDiana Picus     if (alloc.hasShapeOperands()) {
3651e6d9c06SDiana Picus       mlir::Type allocEleTy = fir::unwrapRefType(alloc.getType());
3661e6d9c06SDiana Picus       // Scale the size by constant factors encoded in the array type.
3671e6d9c06SDiana Picus       if (auto seqTy = allocEleTy.dyn_cast<fir::SequenceType>()) {
3681e6d9c06SDiana Picus         fir::SequenceType::Extent constSize = 1;
3691e6d9c06SDiana Picus         for (auto extent : seqTy.getShape())
3701e6d9c06SDiana Picus           if (extent != fir::SequenceType::getUnknownExtent())
3711e6d9c06SDiana Picus             constSize *= extent;
3721e6d9c06SDiana Picus         mlir::Value constVal{
3731e6d9c06SDiana Picus             genConstantIndex(loc, ity, rewriter, constSize).getResult()};
3741e6d9c06SDiana Picus         size = rewriter.create<mlir::LLVM::MulOp>(loc, ity, size, constVal);
3751e6d9c06SDiana Picus       }
3761e6d9c06SDiana Picus       unsigned end = operands.size();
3771e6d9c06SDiana Picus       for (; i < end; ++i)
3781e6d9c06SDiana Picus         size = rewriter.create<mlir::LLVM::MulOp>(
3791e6d9c06SDiana Picus             loc, ity, size, integerCast(loc, rewriter, ity, operands[i]));
3801e6d9c06SDiana Picus     }
3811e6d9c06SDiana Picus     if (ty == resultTy) {
3821e6d9c06SDiana Picus       // Do not emit the bitcast if ty and resultTy are the same.
3831e6d9c06SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::AllocaOp>(alloc, ty, size,
3841e6d9c06SDiana Picus                                                         alloc->getAttrs());
3851e6d9c06SDiana Picus     } else {
3861e6d9c06SDiana Picus       auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, ty, size,
3871e6d9c06SDiana Picus                                                       alloc->getAttrs());
3881e6d9c06SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(alloc, resultTy, al);
3891e6d9c06SDiana Picus     }
3901e6d9c06SDiana Picus     return success();
3911e6d9c06SDiana Picus   }
3921e6d9c06SDiana Picus };
393044d5b5dSValentin Clement 
394df3b9810SValentin Clement /// Lower `fir.box_addr` to the sequence of operations to extract the first
395df3b9810SValentin Clement /// element of the box.
396df3b9810SValentin Clement struct BoxAddrOpConversion : public FIROpConversion<fir::BoxAddrOp> {
397df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
398df3b9810SValentin Clement 
399df3b9810SValentin Clement   mlir::LogicalResult
400df3b9810SValentin Clement   matchAndRewrite(fir::BoxAddrOp boxaddr, OpAdaptor adaptor,
401df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
402df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
403df3b9810SValentin Clement     auto loc = boxaddr.getLoc();
404df3b9810SValentin Clement     mlir::Type ty = convertType(boxaddr.getType());
405df3b9810SValentin Clement     if (auto argty = boxaddr.val().getType().dyn_cast<fir::BoxType>()) {
406df3b9810SValentin Clement       rewriter.replaceOp(boxaddr, loadBaseAddrFromBox(loc, ty, a, rewriter));
407df3b9810SValentin Clement     } else {
408df3b9810SValentin Clement       auto c0attr = rewriter.getI32IntegerAttr(0);
409df3b9810SValentin Clement       auto c0 = mlir::ArrayAttr::get(boxaddr.getContext(), c0attr);
410df3b9810SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(boxaddr, ty, a,
411df3b9810SValentin Clement                                                               c0);
412df3b9810SValentin Clement     }
413df3b9810SValentin Clement     return success();
414df3b9810SValentin Clement   }
415df3b9810SValentin Clement };
416df3b9810SValentin Clement 
417df3b9810SValentin Clement /// Lower `fir.box_dims` to a sequence of operations to extract the requested
418df3b9810SValentin Clement /// dimension infomartion from the boxed value.
419df3b9810SValentin Clement /// Result in a triple set of GEPs and loads.
420df3b9810SValentin Clement struct BoxDimsOpConversion : public FIROpConversion<fir::BoxDimsOp> {
421df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
422df3b9810SValentin Clement 
423df3b9810SValentin Clement   mlir::LogicalResult
424df3b9810SValentin Clement   matchAndRewrite(fir::BoxDimsOp boxdims, OpAdaptor adaptor,
425df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
426df3b9810SValentin Clement     SmallVector<mlir::Type, 3> resultTypes = {
427df3b9810SValentin Clement         convertType(boxdims.getResult(0).getType()),
428df3b9810SValentin Clement         convertType(boxdims.getResult(1).getType()),
429df3b9810SValentin Clement         convertType(boxdims.getResult(2).getType()),
430df3b9810SValentin Clement     };
431df3b9810SValentin Clement     auto results =
432df3b9810SValentin Clement         getDimsFromBox(boxdims.getLoc(), resultTypes, adaptor.getOperands()[0],
433df3b9810SValentin Clement                        adaptor.getOperands()[1], rewriter);
434df3b9810SValentin Clement     rewriter.replaceOp(boxdims, results);
435df3b9810SValentin Clement     return success();
436df3b9810SValentin Clement   }
437df3b9810SValentin Clement };
438df3b9810SValentin Clement 
439df3b9810SValentin Clement /// Lower `fir.box_elesize` to a sequence of operations ro extract the size of
440df3b9810SValentin Clement /// an element in the boxed value.
441df3b9810SValentin Clement struct BoxEleSizeOpConversion : public FIROpConversion<fir::BoxEleSizeOp> {
442df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
443df3b9810SValentin Clement 
444df3b9810SValentin Clement   mlir::LogicalResult
445df3b9810SValentin Clement   matchAndRewrite(fir::BoxEleSizeOp boxelesz, OpAdaptor adaptor,
446df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
447df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
448df3b9810SValentin Clement     auto loc = boxelesz.getLoc();
449df3b9810SValentin Clement     auto ty = convertType(boxelesz.getType());
450b6e44ecdSValentin Clement     auto elemSize = getValueFromBox(loc, a, ty, rewriter, kElemLenPosInBox);
451b6e44ecdSValentin Clement     rewriter.replaceOp(boxelesz, elemSize);
452b6e44ecdSValentin Clement     return success();
453b6e44ecdSValentin Clement   }
454b6e44ecdSValentin Clement };
455b6e44ecdSValentin Clement 
456b6e44ecdSValentin Clement /// Lower `fir.box_isalloc` to a sequence of operations to determine if the
457b6e44ecdSValentin Clement /// boxed value was from an ALLOCATABLE entity.
458b6e44ecdSValentin Clement struct BoxIsAllocOpConversion : public FIROpConversion<fir::BoxIsAllocOp> {
459b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
460b6e44ecdSValentin Clement 
461b6e44ecdSValentin Clement   mlir::LogicalResult
462b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsAllocOp boxisalloc, OpAdaptor adaptor,
463b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
464b6e44ecdSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
465b6e44ecdSValentin Clement     auto loc = boxisalloc.getLoc();
466b6e44ecdSValentin Clement     mlir::Value check =
467b6e44ecdSValentin Clement         genBoxAttributeCheck(loc, box, rewriter, kAttrAllocatable);
468b6e44ecdSValentin Clement     rewriter.replaceOp(boxisalloc, check);
469b6e44ecdSValentin Clement     return success();
470b6e44ecdSValentin Clement   }
471b6e44ecdSValentin Clement };
472b6e44ecdSValentin Clement 
473b6e44ecdSValentin Clement /// Lower `fir.box_isarray` to a sequence of operations to determine if the
474b6e44ecdSValentin Clement /// boxed is an array.
475b6e44ecdSValentin Clement struct BoxIsArrayOpConversion : public FIROpConversion<fir::BoxIsArrayOp> {
476b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
477b6e44ecdSValentin Clement 
478b6e44ecdSValentin Clement   mlir::LogicalResult
479b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsArrayOp boxisarray, OpAdaptor adaptor,
480b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
481b6e44ecdSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
482b6e44ecdSValentin Clement     auto loc = boxisarray.getLoc();
483b6e44ecdSValentin Clement     auto rank =
484b6e44ecdSValentin Clement         getValueFromBox(loc, a, rewriter.getI32Type(), rewriter, kRankPosInBox);
485b6e44ecdSValentin Clement     auto c0 = genConstantOffset(loc, rewriter, 0);
486b6e44ecdSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
487b6e44ecdSValentin Clement         boxisarray, mlir::LLVM::ICmpPredicate::ne, rank, c0);
488b6e44ecdSValentin Clement     return success();
489b6e44ecdSValentin Clement   }
490b6e44ecdSValentin Clement };
491b6e44ecdSValentin Clement 
492b6e44ecdSValentin Clement /// Lower `fir.box_isptr` to a sequence of operations to determined if the
493b6e44ecdSValentin Clement /// boxed value was from a POINTER entity.
494b6e44ecdSValentin Clement struct BoxIsPtrOpConversion : public FIROpConversion<fir::BoxIsPtrOp> {
495b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
496b6e44ecdSValentin Clement 
497b6e44ecdSValentin Clement   mlir::LogicalResult
498b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsPtrOp boxisptr, OpAdaptor adaptor,
499b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
500b6e44ecdSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
501b6e44ecdSValentin Clement     auto loc = boxisptr.getLoc();
502b6e44ecdSValentin Clement     mlir::Value check = genBoxAttributeCheck(loc, box, rewriter, kAttrPointer);
503b6e44ecdSValentin Clement     rewriter.replaceOp(boxisptr, check);
504df3b9810SValentin Clement     return success();
505df3b9810SValentin Clement   }
506df3b9810SValentin Clement };
507df3b9810SValentin Clement 
508df3b9810SValentin Clement /// Lower `fir.box_rank` to the sequence of operation to extract the rank from
509df3b9810SValentin Clement /// the box.
510df3b9810SValentin Clement struct BoxRankOpConversion : public FIROpConversion<fir::BoxRankOp> {
511df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
512df3b9810SValentin Clement 
513df3b9810SValentin Clement   mlir::LogicalResult
514df3b9810SValentin Clement   matchAndRewrite(fir::BoxRankOp boxrank, OpAdaptor adaptor,
515df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
516df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
517df3b9810SValentin Clement     auto loc = boxrank.getLoc();
518df3b9810SValentin Clement     mlir::Type ty = convertType(boxrank.getType());
519b6e44ecdSValentin Clement     auto result = getValueFromBox(loc, a, ty, rewriter, kRankPosInBox);
520df3b9810SValentin Clement     rewriter.replaceOp(boxrank, result);
521df3b9810SValentin Clement     return success();
522df3b9810SValentin Clement   }
523df3b9810SValentin Clement };
524df3b9810SValentin Clement 
5251a2ec667SValentin Clement /// Lower `fir.string_lit` to LLVM IR dialect operation.
5261a2ec667SValentin Clement struct StringLitOpConversion : public FIROpConversion<fir::StringLitOp> {
5271a2ec667SValentin Clement   using FIROpConversion::FIROpConversion;
5281a2ec667SValentin Clement 
5291a2ec667SValentin Clement   mlir::LogicalResult
5301a2ec667SValentin Clement   matchAndRewrite(fir::StringLitOp constop, OpAdaptor adaptor,
5311a2ec667SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
5321a2ec667SValentin Clement     auto ty = convertType(constop.getType());
5331a2ec667SValentin Clement     auto attr = constop.getValue();
5341a2ec667SValentin Clement     if (attr.isa<mlir::StringAttr>()) {
5351a2ec667SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(constop, ty, attr);
5361a2ec667SValentin Clement       return success();
5371a2ec667SValentin Clement     }
5381a2ec667SValentin Clement 
5391a2ec667SValentin Clement     auto arr = attr.cast<mlir::ArrayAttr>();
5401a2ec667SValentin Clement     auto charTy = constop.getType().cast<fir::CharacterType>();
5411a2ec667SValentin Clement     unsigned bits = lowerTy().characterBitsize(charTy);
5421a2ec667SValentin Clement     mlir::Type intTy = rewriter.getIntegerType(bits);
5431a2ec667SValentin Clement     auto attrs = llvm::map_range(
5441a2ec667SValentin Clement         arr.getValue(), [intTy, bits](mlir::Attribute attr) -> Attribute {
5451a2ec667SValentin Clement           return mlir::IntegerAttr::get(
5461a2ec667SValentin Clement               intTy,
5471a2ec667SValentin Clement               attr.cast<mlir::IntegerAttr>().getValue().sextOrTrunc(bits));
5481a2ec667SValentin Clement         });
5491a2ec667SValentin Clement     mlir::Type vecType = mlir::VectorType::get(arr.size(), intTy);
5501a2ec667SValentin Clement     auto denseAttr = mlir::DenseElementsAttr::get(
5511a2ec667SValentin Clement         vecType.cast<mlir::ShapedType>(), llvm::to_vector<8>(attrs));
5521a2ec667SValentin Clement     rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(constop, ty,
5531a2ec667SValentin Clement                                                          denseAttr);
5541a2ec667SValentin Clement     return success();
5551a2ec667SValentin Clement   }
5561a2ec667SValentin Clement };
5571a2ec667SValentin Clement 
558cc505c0bSKiran Chandramohan /// Lower `fir.boxproc_host` operation. Extracts the host pointer from the
559cc505c0bSKiran Chandramohan /// boxproc.
560cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
561cc505c0bSKiran Chandramohan struct BoxProcHostOpConversion : public FIROpConversion<fir::BoxProcHostOp> {
562cc505c0bSKiran Chandramohan   using FIROpConversion::FIROpConversion;
563cc505c0bSKiran Chandramohan 
564cc505c0bSKiran Chandramohan   mlir::LogicalResult
565cc505c0bSKiran Chandramohan   matchAndRewrite(fir::BoxProcHostOp boxprochost, OpAdaptor adaptor,
566cc505c0bSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
5677ce8c6fcSKiran Chandramohan     TODO(boxprochost.getLoc(), "fir.boxproc_host codegen");
5687ce8c6fcSKiran Chandramohan     return failure();
569cc505c0bSKiran Chandramohan   }
570cc505c0bSKiran Chandramohan };
571cc505c0bSKiran Chandramohan 
572e38ef2ffSValentin Clement /// Lower `fir.box_tdesc` to the sequence of operations to extract the type
573e38ef2ffSValentin Clement /// descriptor from the box.
574e38ef2ffSValentin Clement struct BoxTypeDescOpConversion : public FIROpConversion<fir::BoxTypeDescOp> {
575e38ef2ffSValentin Clement   using FIROpConversion::FIROpConversion;
576e38ef2ffSValentin Clement 
577e38ef2ffSValentin Clement   mlir::LogicalResult
578e38ef2ffSValentin Clement   matchAndRewrite(fir::BoxTypeDescOp boxtypedesc, OpAdaptor adaptor,
579e38ef2ffSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
580e38ef2ffSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
581e38ef2ffSValentin Clement     auto loc = boxtypedesc.getLoc();
582e38ef2ffSValentin Clement     mlir::Type typeTy =
583e38ef2ffSValentin Clement         fir::getDescFieldTypeModel<kTypePosInBox>()(boxtypedesc.getContext());
584e38ef2ffSValentin Clement     auto result = getValueFromBox(loc, box, typeTy, rewriter, kTypePosInBox);
585e38ef2ffSValentin Clement     auto typePtrTy = mlir::LLVM::LLVMPointerType::get(typeTy);
586e38ef2ffSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(boxtypedesc, typePtrTy,
587e38ef2ffSValentin Clement                                                         result);
588e38ef2ffSValentin Clement     return success();
589e38ef2ffSValentin Clement   }
590e38ef2ffSValentin Clement };
591e38ef2ffSValentin Clement 
592ddd11b9aSAndrzej Warzynski // `fir.call` -> `llvm.call`
593ddd11b9aSAndrzej Warzynski struct CallOpConversion : public FIROpConversion<fir::CallOp> {
594ddd11b9aSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
595ddd11b9aSAndrzej Warzynski 
596ddd11b9aSAndrzej Warzynski   mlir::LogicalResult
597ddd11b9aSAndrzej Warzynski   matchAndRewrite(fir::CallOp call, OpAdaptor adaptor,
598ddd11b9aSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
599ddd11b9aSAndrzej Warzynski     SmallVector<mlir::Type> resultTys;
600ddd11b9aSAndrzej Warzynski     for (auto r : call.getResults())
601ddd11b9aSAndrzej Warzynski       resultTys.push_back(convertType(r.getType()));
602ddd11b9aSAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
603ddd11b9aSAndrzej Warzynski         call, resultTys, adaptor.getOperands(), call->getAttrs());
604ddd11b9aSAndrzej Warzynski     return success();
605ddd11b9aSAndrzej Warzynski   }
606ddd11b9aSAndrzej Warzynski };
607ddd11b9aSAndrzej Warzynski 
608092cee5fSValentin Clement static mlir::Type getComplexEleTy(mlir::Type complex) {
609092cee5fSValentin Clement   if (auto cc = complex.dyn_cast<mlir::ComplexType>())
610092cee5fSValentin Clement     return cc.getElementType();
611092cee5fSValentin Clement   return complex.cast<fir::ComplexType>().getElementType();
612092cee5fSValentin Clement }
613092cee5fSValentin Clement 
614f1dfc027SDiana Picus /// Compare complex values
615f1dfc027SDiana Picus ///
616f1dfc027SDiana Picus /// Per 10.1, the only comparisons available are .EQ. (oeq) and .NE. (une).
617f1dfc027SDiana Picus ///
618f1dfc027SDiana Picus /// For completeness, all other comparison are done on the real component only.
619f1dfc027SDiana Picus struct CmpcOpConversion : public FIROpConversion<fir::CmpcOp> {
620f1dfc027SDiana Picus   using FIROpConversion::FIROpConversion;
621f1dfc027SDiana Picus 
622f1dfc027SDiana Picus   mlir::LogicalResult
623f1dfc027SDiana Picus   matchAndRewrite(fir::CmpcOp cmp, OpAdaptor adaptor,
624f1dfc027SDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
625f1dfc027SDiana Picus     mlir::ValueRange operands = adaptor.getOperands();
626f1dfc027SDiana Picus     mlir::MLIRContext *ctxt = cmp.getContext();
627f1dfc027SDiana Picus     mlir::Type eleTy = convertType(getComplexEleTy(cmp.lhs().getType()));
628f1dfc027SDiana Picus     mlir::Type resTy = convertType(cmp.getType());
629f1dfc027SDiana Picus     mlir::Location loc = cmp.getLoc();
630f1dfc027SDiana Picus     auto pos0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0));
631f1dfc027SDiana Picus     SmallVector<mlir::Value, 2> rp{rewriter.create<mlir::LLVM::ExtractValueOp>(
632f1dfc027SDiana Picus                                        loc, eleTy, operands[0], pos0),
633f1dfc027SDiana Picus                                    rewriter.create<mlir::LLVM::ExtractValueOp>(
634f1dfc027SDiana Picus                                        loc, eleTy, operands[1], pos0)};
635f1dfc027SDiana Picus     auto rcp =
636f1dfc027SDiana Picus         rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, rp, cmp->getAttrs());
637f1dfc027SDiana Picus     auto pos1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1));
638f1dfc027SDiana Picus     SmallVector<mlir::Value, 2> ip{rewriter.create<mlir::LLVM::ExtractValueOp>(
639f1dfc027SDiana Picus                                        loc, eleTy, operands[0], pos1),
640f1dfc027SDiana Picus                                    rewriter.create<mlir::LLVM::ExtractValueOp>(
641f1dfc027SDiana Picus                                        loc, eleTy, operands[1], pos1)};
642f1dfc027SDiana Picus     auto icp =
643f1dfc027SDiana Picus         rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, ip, cmp->getAttrs());
644f1dfc027SDiana Picus     SmallVector<mlir::Value, 2> cp{rcp, icp};
645f1dfc027SDiana Picus     switch (cmp.getPredicate()) {
646f1dfc027SDiana Picus     case mlir::arith::CmpFPredicate::OEQ: // .EQ.
647f1dfc027SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(cmp, resTy, cp);
648f1dfc027SDiana Picus       break;
649f1dfc027SDiana Picus     case mlir::arith::CmpFPredicate::UNE: // .NE.
650f1dfc027SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(cmp, resTy, cp);
651f1dfc027SDiana Picus       break;
652f1dfc027SDiana Picus     default:
653f1dfc027SDiana Picus       rewriter.replaceOp(cmp, rcp.getResult());
654f1dfc027SDiana Picus       break;
655f1dfc027SDiana Picus     }
656f1dfc027SDiana Picus     return success();
657f1dfc027SDiana Picus   }
658f1dfc027SDiana Picus };
659f1dfc027SDiana Picus 
660e81d73edSDiana Picus /// Lower complex constants
661e81d73edSDiana Picus struct ConstcOpConversion : public FIROpConversion<fir::ConstcOp> {
662e81d73edSDiana Picus   using FIROpConversion::FIROpConversion;
663e81d73edSDiana Picus 
664e81d73edSDiana Picus   mlir::LogicalResult
665e81d73edSDiana Picus   matchAndRewrite(fir::ConstcOp conc, OpAdaptor,
666e81d73edSDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
667e81d73edSDiana Picus     mlir::Location loc = conc.getLoc();
668e81d73edSDiana Picus     mlir::MLIRContext *ctx = conc.getContext();
669e81d73edSDiana Picus     mlir::Type ty = convertType(conc.getType());
670e81d73edSDiana Picus     mlir::Type ety = convertType(getComplexEleTy(conc.getType()));
671e81d73edSDiana Picus     auto realFloatAttr = mlir::FloatAttr::get(ety, getValue(conc.getReal()));
672e81d73edSDiana Picus     auto realPart =
673e81d73edSDiana Picus         rewriter.create<mlir::LLVM::ConstantOp>(loc, ety, realFloatAttr);
674e81d73edSDiana Picus     auto imFloatAttr = mlir::FloatAttr::get(ety, getValue(conc.getImaginary()));
675e81d73edSDiana Picus     auto imPart =
676e81d73edSDiana Picus         rewriter.create<mlir::LLVM::ConstantOp>(loc, ety, imFloatAttr);
677e81d73edSDiana Picus     auto realIndex = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
678e81d73edSDiana Picus     auto imIndex = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
679e81d73edSDiana Picus     auto undef = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
680e81d73edSDiana Picus     auto setReal = rewriter.create<mlir::LLVM::InsertValueOp>(
681e81d73edSDiana Picus         loc, ty, undef, realPart, realIndex);
682e81d73edSDiana Picus     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(conc, ty, setReal,
683e81d73edSDiana Picus                                                            imPart, imIndex);
684e81d73edSDiana Picus     return success();
685e81d73edSDiana Picus   }
686e81d73edSDiana Picus 
687e81d73edSDiana Picus   inline APFloat getValue(mlir::Attribute attr) const {
688e81d73edSDiana Picus     return attr.cast<fir::RealAttr>().getValue();
689e81d73edSDiana Picus   }
690e81d73edSDiana Picus };
691e81d73edSDiana Picus 
692092cee5fSValentin Clement /// convert value of from-type to value of to-type
693092cee5fSValentin Clement struct ConvertOpConversion : public FIROpConversion<fir::ConvertOp> {
694092cee5fSValentin Clement   using FIROpConversion::FIROpConversion;
695092cee5fSValentin Clement 
696092cee5fSValentin Clement   static bool isFloatingPointTy(mlir::Type ty) {
697092cee5fSValentin Clement     return ty.isa<mlir::FloatType>();
698092cee5fSValentin Clement   }
699092cee5fSValentin Clement 
700092cee5fSValentin Clement   mlir::LogicalResult
701092cee5fSValentin Clement   matchAndRewrite(fir::ConvertOp convert, OpAdaptor adaptor,
702092cee5fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
703092cee5fSValentin Clement     auto fromTy = convertType(convert.value().getType());
704092cee5fSValentin Clement     auto toTy = convertType(convert.res().getType());
705092cee5fSValentin Clement     mlir::Value op0 = adaptor.getOperands()[0];
706092cee5fSValentin Clement     if (fromTy == toTy) {
707092cee5fSValentin Clement       rewriter.replaceOp(convert, op0);
708092cee5fSValentin Clement       return success();
709092cee5fSValentin Clement     }
710092cee5fSValentin Clement     auto loc = convert.getLoc();
711092cee5fSValentin Clement     auto convertFpToFp = [&](mlir::Value val, unsigned fromBits,
712092cee5fSValentin Clement                              unsigned toBits, mlir::Type toTy) -> mlir::Value {
713092cee5fSValentin Clement       if (fromBits == toBits) {
714092cee5fSValentin Clement         // TODO: Converting between two floating-point representations with the
715092cee5fSValentin Clement         // same bitwidth is not allowed for now.
716092cee5fSValentin Clement         mlir::emitError(loc,
717092cee5fSValentin Clement                         "cannot implicitly convert between two floating-point "
718092cee5fSValentin Clement                         "representations of the same bitwidth");
719092cee5fSValentin Clement         return {};
720092cee5fSValentin Clement       }
721092cee5fSValentin Clement       if (fromBits > toBits)
722092cee5fSValentin Clement         return rewriter.create<mlir::LLVM::FPTruncOp>(loc, toTy, val);
723092cee5fSValentin Clement       return rewriter.create<mlir::LLVM::FPExtOp>(loc, toTy, val);
724092cee5fSValentin Clement     };
725092cee5fSValentin Clement     // Complex to complex conversion.
726092cee5fSValentin Clement     if (fir::isa_complex(convert.value().getType()) &&
727092cee5fSValentin Clement         fir::isa_complex(convert.res().getType())) {
728092cee5fSValentin Clement       // Special case: handle the conversion of a complex such that both the
729092cee5fSValentin Clement       // real and imaginary parts are converted together.
730092cee5fSValentin Clement       auto zero = mlir::ArrayAttr::get(convert.getContext(),
731092cee5fSValentin Clement                                        rewriter.getI32IntegerAttr(0));
732092cee5fSValentin Clement       auto one = mlir::ArrayAttr::get(convert.getContext(),
733092cee5fSValentin Clement                                       rewriter.getI32IntegerAttr(1));
734092cee5fSValentin Clement       auto ty = convertType(getComplexEleTy(convert.value().getType()));
735092cee5fSValentin Clement       auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, zero);
736092cee5fSValentin Clement       auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, one);
737092cee5fSValentin Clement       auto nt = convertType(getComplexEleTy(convert.res().getType()));
738092cee5fSValentin Clement       auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
739092cee5fSValentin Clement       auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(nt);
740092cee5fSValentin Clement       auto rc = convertFpToFp(rp, fromBits, toBits, nt);
741092cee5fSValentin Clement       auto ic = convertFpToFp(ip, fromBits, toBits, nt);
742092cee5fSValentin Clement       auto un = rewriter.create<mlir::LLVM::UndefOp>(loc, toTy);
743092cee5fSValentin Clement       auto i1 =
744092cee5fSValentin Clement           rewriter.create<mlir::LLVM::InsertValueOp>(loc, toTy, un, rc, zero);
745092cee5fSValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(convert, toTy, i1,
746092cee5fSValentin Clement                                                              ic, one);
747092cee5fSValentin Clement       return mlir::success();
748092cee5fSValentin Clement     }
749092cee5fSValentin Clement     // Floating point to floating point conversion.
750092cee5fSValentin Clement     if (isFloatingPointTy(fromTy)) {
751092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
752092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
753092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
754092cee5fSValentin Clement         auto v = convertFpToFp(op0, fromBits, toBits, toTy);
755092cee5fSValentin Clement         rewriter.replaceOp(convert, v);
756092cee5fSValentin Clement         return mlir::success();
757092cee5fSValentin Clement       }
758092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
759092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::FPToSIOp>(convert, toTy, op0);
760092cee5fSValentin Clement         return mlir::success();
761092cee5fSValentin Clement       }
762092cee5fSValentin Clement     } else if (fromTy.isa<mlir::IntegerType>()) {
763092cee5fSValentin Clement       // Integer to integer conversion.
764092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
765092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
766092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
767092cee5fSValentin Clement         assert(fromBits != toBits);
768092cee5fSValentin Clement         if (fromBits > toBits) {
769092cee5fSValentin Clement           rewriter.replaceOpWithNewOp<mlir::LLVM::TruncOp>(convert, toTy, op0);
770092cee5fSValentin Clement           return mlir::success();
771092cee5fSValentin Clement         }
772092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SExtOp>(convert, toTy, op0);
773092cee5fSValentin Clement         return mlir::success();
774092cee5fSValentin Clement       }
775092cee5fSValentin Clement       // Integer to floating point conversion.
776092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
777092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SIToFPOp>(convert, toTy, op0);
778092cee5fSValentin Clement         return mlir::success();
779092cee5fSValentin Clement       }
780092cee5fSValentin Clement       // Integer to pointer conversion.
781092cee5fSValentin Clement       if (toTy.isa<mlir::LLVM::LLVMPointerType>()) {
782092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(convert, toTy, op0);
783092cee5fSValentin Clement         return mlir::success();
784092cee5fSValentin Clement       }
785092cee5fSValentin Clement     } else if (fromTy.isa<mlir::LLVM::LLVMPointerType>()) {
786092cee5fSValentin Clement       // Pointer to integer conversion.
787092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
788092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::PtrToIntOp>(convert, toTy, op0);
789092cee5fSValentin Clement         return mlir::success();
790092cee5fSValentin Clement       }
791092cee5fSValentin Clement       // Pointer to pointer conversion.
792092cee5fSValentin Clement       if (toTy.isa<mlir::LLVM::LLVMPointerType>()) {
793092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(convert, toTy, op0);
794092cee5fSValentin Clement         return mlir::success();
795092cee5fSValentin Clement       }
796092cee5fSValentin Clement     }
797092cee5fSValentin Clement     return emitError(loc) << "cannot convert " << fromTy << " to " << toTy;
798092cee5fSValentin Clement   }
799092cee5fSValentin Clement };
800092cee5fSValentin Clement 
8019534e361SValentin Clement /// Lower `fir.dispatch` operation. A virtual call to a method in a dispatch
8029534e361SValentin Clement /// table.
8039534e361SValentin Clement struct DispatchOpConversion : public FIROpConversion<fir::DispatchOp> {
8049534e361SValentin Clement   using FIROpConversion::FIROpConversion;
8059534e361SValentin Clement 
8069534e361SValentin Clement   mlir::LogicalResult
8079534e361SValentin Clement   matchAndRewrite(fir::DispatchOp dispatch, OpAdaptor adaptor,
8089534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8097ce8c6fcSKiran Chandramohan     TODO(dispatch.getLoc(), "fir.dispatch codegen");
8107ce8c6fcSKiran Chandramohan     return failure();
8119534e361SValentin Clement   }
8129534e361SValentin Clement };
8139534e361SValentin Clement 
8149534e361SValentin Clement /// Lower `fir.dispatch_table` operation. The dispatch table for a Fortran
8159534e361SValentin Clement /// derived type.
8169534e361SValentin Clement struct DispatchTableOpConversion
8179534e361SValentin Clement     : public FIROpConversion<fir::DispatchTableOp> {
8189534e361SValentin Clement   using FIROpConversion::FIROpConversion;
8199534e361SValentin Clement 
8209534e361SValentin Clement   mlir::LogicalResult
8219534e361SValentin Clement   matchAndRewrite(fir::DispatchTableOp dispTab, OpAdaptor adaptor,
8229534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8237ce8c6fcSKiran Chandramohan     TODO(dispTab.getLoc(), "fir.dispatch_table codegen");
8247ce8c6fcSKiran Chandramohan     return failure();
8259534e361SValentin Clement   }
8269534e361SValentin Clement };
8279534e361SValentin Clement 
8289534e361SValentin Clement /// Lower `fir.dt_entry` operation. An entry in a dispatch table; binds a
8299534e361SValentin Clement /// method-name to a function.
8309534e361SValentin Clement struct DTEntryOpConversion : public FIROpConversion<fir::DTEntryOp> {
8319534e361SValentin Clement   using FIROpConversion::FIROpConversion;
8329534e361SValentin Clement 
8339534e361SValentin Clement   mlir::LogicalResult
8349534e361SValentin Clement   matchAndRewrite(fir::DTEntryOp dtEnt, OpAdaptor adaptor,
8359534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8367ce8c6fcSKiran Chandramohan     TODO(dtEnt.getLoc(), "fir.dt_entry codegen");
8377ce8c6fcSKiran Chandramohan     return failure();
8389534e361SValentin Clement   }
8399534e361SValentin Clement };
8409534e361SValentin Clement 
841677df8c7SValentin Clement /// Lower `fir.global_len` operation.
842677df8c7SValentin Clement struct GlobalLenOpConversion : public FIROpConversion<fir::GlobalLenOp> {
843677df8c7SValentin Clement   using FIROpConversion::FIROpConversion;
844677df8c7SValentin Clement 
845677df8c7SValentin Clement   mlir::LogicalResult
846677df8c7SValentin Clement   matchAndRewrite(fir::GlobalLenOp globalLen, OpAdaptor adaptor,
847677df8c7SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8487ce8c6fcSKiran Chandramohan     TODO(globalLen.getLoc(), "fir.global_len codegen");
8497ce8c6fcSKiran Chandramohan     return failure();
850677df8c7SValentin Clement   }
851677df8c7SValentin Clement };
852677df8c7SValentin Clement 
853cdc476abSDiana Picus /// Lower fir.len_param_index
854cdc476abSDiana Picus struct LenParamIndexOpConversion
855cdc476abSDiana Picus     : public FIROpConversion<fir::LenParamIndexOp> {
856cdc476abSDiana Picus   using FIROpConversion::FIROpConversion;
857cdc476abSDiana Picus 
858cdc476abSDiana Picus   // FIXME: this should be specialized by the runtime target
859cdc476abSDiana Picus   mlir::LogicalResult
860cdc476abSDiana Picus   matchAndRewrite(fir::LenParamIndexOp lenp, OpAdaptor,
861cdc476abSDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
8627ce8c6fcSKiran Chandramohan     TODO(lenp.getLoc(), "fir.len_param_index codegen");
863cdc476abSDiana Picus   }
864cdc476abSDiana Picus };
865cdc476abSDiana Picus 
86631246187SValentin Clement /// Lower `fir.gentypedesc` to a global constant.
86731246187SValentin Clement struct GenTypeDescOpConversion : public FIROpConversion<fir::GenTypeDescOp> {
86831246187SValentin Clement   using FIROpConversion::FIROpConversion;
86931246187SValentin Clement 
87031246187SValentin Clement   mlir::LogicalResult
87131246187SValentin Clement   matchAndRewrite(fir::GenTypeDescOp gentypedesc, OpAdaptor adaptor,
87231246187SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8737ce8c6fcSKiran Chandramohan     TODO(gentypedesc.getLoc(), "fir.gentypedesc codegen");
8747ce8c6fcSKiran Chandramohan     return failure();
87531246187SValentin Clement   }
87631246187SValentin Clement };
87731246187SValentin Clement 
87822d332a0SAndrzej Warzynski /// Convert `fir.end`
87922d332a0SAndrzej Warzynski struct FirEndOpConversion : public FIROpConversion<fir::FirEndOp> {
88022d332a0SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
88122d332a0SAndrzej Warzynski 
88222d332a0SAndrzej Warzynski   mlir::LogicalResult
88322d332a0SAndrzej Warzynski   matchAndRewrite(fir::FirEndOp firEnd, OpAdaptor,
88422d332a0SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
8857ce8c6fcSKiran Chandramohan     TODO(firEnd.getLoc(), "fir.end codegen");
8867ce8c6fcSKiran Chandramohan     return failure();
88722d332a0SAndrzej Warzynski   }
88822d332a0SAndrzej Warzynski };
88922d332a0SAndrzej Warzynski 
8900c4a7a52SValentin Clement /// Lower `fir.has_value` operation to `llvm.return` operation.
891044d5b5dSValentin Clement struct HasValueOpConversion : public FIROpConversion<fir::HasValueOp> {
892044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
893044d5b5dSValentin Clement 
894044d5b5dSValentin Clement   mlir::LogicalResult
895044d5b5dSValentin Clement   matchAndRewrite(fir::HasValueOp op, OpAdaptor adaptor,
896044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
897044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, adaptor.getOperands());
898044d5b5dSValentin Clement     return success();
899044d5b5dSValentin Clement   }
900044d5b5dSValentin Clement };
901044d5b5dSValentin Clement 
9020c4a7a52SValentin Clement /// Lower `fir.global` operation to `llvm.global` operation.
9030c4a7a52SValentin Clement /// `fir.insert_on_range` operations are replaced with constant dense attribute
9040c4a7a52SValentin Clement /// if they are applied on the full range.
905044d5b5dSValentin Clement struct GlobalOpConversion : public FIROpConversion<fir::GlobalOp> {
906044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
907044d5b5dSValentin Clement 
908044d5b5dSValentin Clement   mlir::LogicalResult
909044d5b5dSValentin Clement   matchAndRewrite(fir::GlobalOp global, OpAdaptor adaptor,
910044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
911044d5b5dSValentin Clement     auto tyAttr = convertType(global.getType());
912044d5b5dSValentin Clement     if (global.getType().isa<fir::BoxType>())
913044d5b5dSValentin Clement       tyAttr = tyAttr.cast<mlir::LLVM::LLVMPointerType>().getElementType();
914044d5b5dSValentin Clement     auto loc = global.getLoc();
915044d5b5dSValentin Clement     mlir::Attribute initAttr{};
916044d5b5dSValentin Clement     if (global.initVal())
917044d5b5dSValentin Clement       initAttr = global.initVal().getValue();
918044d5b5dSValentin Clement     auto linkage = convertLinkage(global.linkName());
919044d5b5dSValentin Clement     auto isConst = global.constant().hasValue();
920044d5b5dSValentin Clement     auto g = rewriter.create<mlir::LLVM::GlobalOp>(
921044d5b5dSValentin Clement         loc, tyAttr, isConst, linkage, global.sym_name(), initAttr);
922044d5b5dSValentin Clement     auto &gr = g.getInitializerRegion();
923044d5b5dSValentin Clement     rewriter.inlineRegionBefore(global.region(), gr, gr.end());
924044d5b5dSValentin Clement     if (!gr.empty()) {
925044d5b5dSValentin Clement       // Replace insert_on_range with a constant dense attribute if the
926044d5b5dSValentin Clement       // initialization is on the full range.
927044d5b5dSValentin Clement       auto insertOnRangeOps = gr.front().getOps<fir::InsertOnRangeOp>();
928044d5b5dSValentin Clement       for (auto insertOp : insertOnRangeOps) {
929044d5b5dSValentin Clement         if (isFullRange(insertOp.coor(), insertOp.getType())) {
930044d5b5dSValentin Clement           auto seqTyAttr = convertType(insertOp.getType());
931044d5b5dSValentin Clement           auto *op = insertOp.val().getDefiningOp();
932044d5b5dSValentin Clement           auto constant = mlir::dyn_cast<mlir::arith::ConstantOp>(op);
933044d5b5dSValentin Clement           if (!constant) {
934044d5b5dSValentin Clement             auto convertOp = mlir::dyn_cast<fir::ConvertOp>(op);
935044d5b5dSValentin Clement             if (!convertOp)
936044d5b5dSValentin Clement               continue;
937044d5b5dSValentin Clement             constant = cast<mlir::arith::ConstantOp>(
938044d5b5dSValentin Clement                 convertOp.value().getDefiningOp());
939044d5b5dSValentin Clement           }
940044d5b5dSValentin Clement           mlir::Type vecType = mlir::VectorType::get(
941044d5b5dSValentin Clement               insertOp.getType().getShape(), constant.getType());
942044d5b5dSValentin Clement           auto denseAttr = mlir::DenseElementsAttr::get(
943044d5b5dSValentin Clement               vecType.cast<ShapedType>(), constant.value());
944044d5b5dSValentin Clement           rewriter.setInsertionPointAfter(insertOp);
945044d5b5dSValentin Clement           rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(
946044d5b5dSValentin Clement               insertOp, seqTyAttr, denseAttr);
947044d5b5dSValentin Clement         }
948044d5b5dSValentin Clement       }
949044d5b5dSValentin Clement     }
950044d5b5dSValentin Clement     rewriter.eraseOp(global);
951044d5b5dSValentin Clement     return success();
952044d5b5dSValentin Clement   }
953044d5b5dSValentin Clement 
9548ec0f221SMehdi Amini   bool isFullRange(mlir::DenseIntElementsAttr indexes,
9558ec0f221SMehdi Amini                    fir::SequenceType seqTy) const {
956044d5b5dSValentin Clement     auto extents = seqTy.getShape();
9578ec0f221SMehdi Amini     if (indexes.size() / 2 != static_cast<int64_t>(extents.size()))
958044d5b5dSValentin Clement       return false;
9598ec0f221SMehdi Amini     auto cur_index = indexes.value_begin<int64_t>();
960044d5b5dSValentin Clement     for (unsigned i = 0; i < indexes.size(); i += 2) {
9618ec0f221SMehdi Amini       if (*(cur_index++) != 0)
962044d5b5dSValentin Clement         return false;
9638ec0f221SMehdi Amini       if (*(cur_index++) != extents[i / 2] - 1)
964044d5b5dSValentin Clement         return false;
965044d5b5dSValentin Clement     }
966044d5b5dSValentin Clement     return true;
967044d5b5dSValentin Clement   }
968044d5b5dSValentin Clement 
9690c4a7a52SValentin Clement   // TODO: String comparaison should be avoided. Replace linkName with an
9700c4a7a52SValentin Clement   // enumeration.
971044d5b5dSValentin Clement   mlir::LLVM::Linkage convertLinkage(Optional<StringRef> optLinkage) const {
972044d5b5dSValentin Clement     if (optLinkage.hasValue()) {
973044d5b5dSValentin Clement       auto name = optLinkage.getValue();
974044d5b5dSValentin Clement       if (name == "internal")
975044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Internal;
976044d5b5dSValentin Clement       if (name == "linkonce")
977044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Linkonce;
978044d5b5dSValentin Clement       if (name == "common")
979044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Common;
980044d5b5dSValentin Clement       if (name == "weak")
981044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Weak;
982044d5b5dSValentin Clement     }
983044d5b5dSValentin Clement     return mlir::LLVM::Linkage::External;
984044d5b5dSValentin Clement   }
985044d5b5dSValentin Clement };
986044d5b5dSValentin Clement 
98739f4ef81SValentin Clement void genCondBrOp(mlir::Location loc, mlir::Value cmp, mlir::Block *dest,
98839f4ef81SValentin Clement                  Optional<mlir::ValueRange> destOps,
98939f4ef81SValentin Clement                  mlir::ConversionPatternRewriter &rewriter,
99039f4ef81SValentin Clement                  mlir::Block *newBlock) {
99139f4ef81SValentin Clement   if (destOps.hasValue())
99239f4ef81SValentin Clement     rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, destOps.getValue(),
99339f4ef81SValentin Clement                                           newBlock, mlir::ValueRange());
99439f4ef81SValentin Clement   else
99539f4ef81SValentin Clement     rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, newBlock);
99639f4ef81SValentin Clement }
99739f4ef81SValentin Clement 
99839f4ef81SValentin Clement template <typename A, typename B>
99939f4ef81SValentin Clement void genBrOp(A caseOp, mlir::Block *dest, Optional<B> destOps,
100039f4ef81SValentin Clement              mlir::ConversionPatternRewriter &rewriter) {
100139f4ef81SValentin Clement   if (destOps.hasValue())
100239f4ef81SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, destOps.getValue(),
100339f4ef81SValentin Clement                                                   dest);
100439f4ef81SValentin Clement   else
100539f4ef81SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, llvm::None, dest);
100639f4ef81SValentin Clement }
100739f4ef81SValentin Clement 
100839f4ef81SValentin Clement void genCaseLadderStep(mlir::Location loc, mlir::Value cmp, mlir::Block *dest,
100939f4ef81SValentin Clement                        Optional<mlir::ValueRange> destOps,
101039f4ef81SValentin Clement                        mlir::ConversionPatternRewriter &rewriter) {
101139f4ef81SValentin Clement   auto *thisBlock = rewriter.getInsertionBlock();
101239f4ef81SValentin Clement   auto *newBlock = createBlock(rewriter, dest);
101339f4ef81SValentin Clement   rewriter.setInsertionPointToEnd(thisBlock);
101439f4ef81SValentin Clement   genCondBrOp(loc, cmp, dest, destOps, rewriter, newBlock);
101539f4ef81SValentin Clement   rewriter.setInsertionPointToEnd(newBlock);
101639f4ef81SValentin Clement }
101739f4ef81SValentin Clement 
101839f4ef81SValentin Clement /// Conversion of `fir.select_case`
101939f4ef81SValentin Clement ///
102039f4ef81SValentin Clement /// The `fir.select_case` operation is converted to a if-then-else ladder.
102139f4ef81SValentin Clement /// Depending on the case condition type, one or several comparison and
102239f4ef81SValentin Clement /// conditional branching can be generated.
102339f4ef81SValentin Clement ///
102439f4ef81SValentin Clement /// A a point value case such as `case(4)`, a lower bound case such as
102539f4ef81SValentin Clement /// `case(5:)` or an upper bound case such as `case(:3)` are converted to a
102639f4ef81SValentin Clement /// simple comparison between the selector value and the constant value in the
102739f4ef81SValentin Clement /// case. The block associated with the case condition is then executed if
102839f4ef81SValentin Clement /// the comparison succeed otherwise it branch to the next block with the
102939f4ef81SValentin Clement /// comparison for the the next case conditon.
103039f4ef81SValentin Clement ///
103139f4ef81SValentin Clement /// A closed interval case condition such as `case(7:10)` is converted with a
103239f4ef81SValentin Clement /// first comparison and conditional branching for the lower bound. If
103339f4ef81SValentin Clement /// successful, it branch to a second block with the comparison for the
103439f4ef81SValentin Clement /// upper bound in the same case condition.
103539f4ef81SValentin Clement ///
103639f4ef81SValentin Clement /// TODO: lowering of CHARACTER type cases is not handled yet.
103739f4ef81SValentin Clement struct SelectCaseOpConversion : public FIROpConversion<fir::SelectCaseOp> {
103839f4ef81SValentin Clement   using FIROpConversion::FIROpConversion;
103939f4ef81SValentin Clement 
104039f4ef81SValentin Clement   mlir::LogicalResult
104139f4ef81SValentin Clement   matchAndRewrite(fir::SelectCaseOp caseOp, OpAdaptor adaptor,
104239f4ef81SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
104339f4ef81SValentin Clement     unsigned conds = caseOp.getNumConditions();
104439f4ef81SValentin Clement     llvm::ArrayRef<mlir::Attribute> cases = caseOp.getCases().getValue();
104539f4ef81SValentin Clement     // Type can be CHARACTER, INTEGER, or LOGICAL (C1145)
10467ce8c6fcSKiran Chandramohan     auto ty = caseOp.getSelector().getType();
10477ce8c6fcSKiran Chandramohan     if (ty.isa<fir::CharacterType>()) {
10487ce8c6fcSKiran Chandramohan       TODO(caseOp.getLoc(), "fir.select_case codegen with character type");
10497ce8c6fcSKiran Chandramohan       return failure();
10507ce8c6fcSKiran Chandramohan     }
105139f4ef81SValentin Clement     mlir::Value selector = caseOp.getSelector(adaptor.getOperands());
105239f4ef81SValentin Clement     auto loc = caseOp.getLoc();
105339f4ef81SValentin Clement     for (unsigned t = 0; t != conds; ++t) {
105439f4ef81SValentin Clement       mlir::Block *dest = caseOp.getSuccessor(t);
105539f4ef81SValentin Clement       llvm::Optional<mlir::ValueRange> destOps =
105639f4ef81SValentin Clement           caseOp.getSuccessorOperands(adaptor.getOperands(), t);
105739f4ef81SValentin Clement       llvm::Optional<mlir::ValueRange> cmpOps =
105839f4ef81SValentin Clement           *caseOp.getCompareOperands(adaptor.getOperands(), t);
105939f4ef81SValentin Clement       mlir::Value caseArg = *(cmpOps.getValue().begin());
106039f4ef81SValentin Clement       mlir::Attribute attr = cases[t];
106139f4ef81SValentin Clement       if (attr.isa<fir::PointIntervalAttr>()) {
106239f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
106339f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::eq, selector, caseArg);
106439f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
106539f4ef81SValentin Clement         continue;
106639f4ef81SValentin Clement       }
106739f4ef81SValentin Clement       if (attr.isa<fir::LowerBoundAttr>()) {
106839f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
106939f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector);
107039f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
107139f4ef81SValentin Clement         continue;
107239f4ef81SValentin Clement       }
107339f4ef81SValentin Clement       if (attr.isa<fir::UpperBoundAttr>()) {
107439f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
107539f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg);
107639f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
107739f4ef81SValentin Clement         continue;
107839f4ef81SValentin Clement       }
107939f4ef81SValentin Clement       if (attr.isa<fir::ClosedIntervalAttr>()) {
108039f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
108139f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector);
108239f4ef81SValentin Clement         auto *thisBlock = rewriter.getInsertionBlock();
108339f4ef81SValentin Clement         auto *newBlock1 = createBlock(rewriter, dest);
108439f4ef81SValentin Clement         auto *newBlock2 = createBlock(rewriter, dest);
108539f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(thisBlock);
108639f4ef81SValentin Clement         rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, newBlock1, newBlock2);
108739f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(newBlock1);
108839f4ef81SValentin Clement         mlir::Value caseArg0 = *(cmpOps.getValue().begin() + 1);
108939f4ef81SValentin Clement         auto cmp0 = rewriter.create<mlir::LLVM::ICmpOp>(
109039f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg0);
109139f4ef81SValentin Clement         genCondBrOp(loc, cmp0, dest, destOps, rewriter, newBlock2);
109239f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(newBlock2);
109339f4ef81SValentin Clement         continue;
109439f4ef81SValentin Clement       }
109539f4ef81SValentin Clement       assert(attr.isa<mlir::UnitAttr>());
109639f4ef81SValentin Clement       assert((t + 1 == conds) && "unit must be last");
109739f4ef81SValentin Clement       genBrOp(caseOp, dest, destOps, rewriter);
109839f4ef81SValentin Clement     }
109939f4ef81SValentin Clement     return success();
110039f4ef81SValentin Clement   }
110139f4ef81SValentin Clement };
110239f4ef81SValentin Clement 
11038c239909SValentin Clement template <typename OP>
11048c239909SValentin Clement void selectMatchAndRewrite(fir::LLVMTypeConverter &lowering, OP select,
11058c239909SValentin Clement                            typename OP::Adaptor adaptor,
11068c239909SValentin Clement                            mlir::ConversionPatternRewriter &rewriter) {
11078c239909SValentin Clement   unsigned conds = select.getNumConditions();
11088c239909SValentin Clement   auto cases = select.getCases().getValue();
11098c239909SValentin Clement   mlir::Value selector = adaptor.selector();
11108c239909SValentin Clement   auto loc = select.getLoc();
11118c239909SValentin Clement   assert(conds > 0 && "select must have cases");
11128c239909SValentin Clement 
11138c239909SValentin Clement   llvm::SmallVector<mlir::Block *> destinations;
11148c239909SValentin Clement   llvm::SmallVector<mlir::ValueRange> destinationsOperands;
11158c239909SValentin Clement   mlir::Block *defaultDestination;
11168c239909SValentin Clement   mlir::ValueRange defaultOperands;
11178c239909SValentin Clement   llvm::SmallVector<int32_t> caseValues;
11188c239909SValentin Clement 
11198c239909SValentin Clement   for (unsigned t = 0; t != conds; ++t) {
11208c239909SValentin Clement     mlir::Block *dest = select.getSuccessor(t);
11218c239909SValentin Clement     auto destOps = select.getSuccessorOperands(adaptor.getOperands(), t);
11228c239909SValentin Clement     const mlir::Attribute &attr = cases[t];
11238c239909SValentin Clement     if (auto intAttr = attr.template dyn_cast<mlir::IntegerAttr>()) {
11248c239909SValentin Clement       destinations.push_back(dest);
11258c239909SValentin Clement       destinationsOperands.push_back(destOps.hasValue() ? *destOps
11268c239909SValentin Clement                                                         : ValueRange());
11278c239909SValentin Clement       caseValues.push_back(intAttr.getInt());
11288c239909SValentin Clement       continue;
11298c239909SValentin Clement     }
11308c239909SValentin Clement     assert(attr.template dyn_cast_or_null<mlir::UnitAttr>());
11318c239909SValentin Clement     assert((t + 1 == conds) && "unit must be last");
11328c239909SValentin Clement     defaultDestination = dest;
11338c239909SValentin Clement     defaultOperands = destOps.hasValue() ? *destOps : ValueRange();
11348c239909SValentin Clement   }
11358c239909SValentin Clement 
11368c239909SValentin Clement   // LLVM::SwitchOp takes a i32 type for the selector.
11378c239909SValentin Clement   if (select.getSelector().getType() != rewriter.getI32Type())
11388c239909SValentin Clement     selector =
11398c239909SValentin Clement         rewriter.create<LLVM::TruncOp>(loc, rewriter.getI32Type(), selector);
11408c239909SValentin Clement 
11418c239909SValentin Clement   rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>(
11428c239909SValentin Clement       select, selector,
11438c239909SValentin Clement       /*defaultDestination=*/defaultDestination,
11448c239909SValentin Clement       /*defaultOperands=*/defaultOperands,
11458c239909SValentin Clement       /*caseValues=*/caseValues,
11468c239909SValentin Clement       /*caseDestinations=*/destinations,
11478c239909SValentin Clement       /*caseOperands=*/destinationsOperands,
11488c239909SValentin Clement       /*branchWeights=*/ArrayRef<int32_t>());
11498c239909SValentin Clement }
11508c239909SValentin Clement 
11518c239909SValentin Clement /// conversion of fir::SelectOp to an if-then-else ladder
11528c239909SValentin Clement struct SelectOpConversion : public FIROpConversion<fir::SelectOp> {
11538c239909SValentin Clement   using FIROpConversion::FIROpConversion;
11548c239909SValentin Clement 
11558c239909SValentin Clement   mlir::LogicalResult
11568c239909SValentin Clement   matchAndRewrite(fir::SelectOp op, OpAdaptor adaptor,
11578c239909SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
11588c239909SValentin Clement     selectMatchAndRewrite<fir::SelectOp>(lowerTy(), op, adaptor, rewriter);
11598c239909SValentin Clement     return success();
11608c239909SValentin Clement   }
11618c239909SValentin Clement };
11628c239909SValentin Clement 
1163e3349fa1SAndrzej Warzynski /// `fir.load` --> `llvm.load`
1164e3349fa1SAndrzej Warzynski struct LoadOpConversion : public FIROpConversion<fir::LoadOp> {
1165e3349fa1SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
1166e3349fa1SAndrzej Warzynski 
1167e3349fa1SAndrzej Warzynski   mlir::LogicalResult
1168e3349fa1SAndrzej Warzynski   matchAndRewrite(fir::LoadOp load, OpAdaptor adaptor,
1169e3349fa1SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
1170e3349fa1SAndrzej Warzynski     // fir.box is a special case because it is considered as an ssa values in
1171e3349fa1SAndrzej Warzynski     // fir, but it is lowered as a pointer to a descriptor. So fir.ref<fir.box>
1172e3349fa1SAndrzej Warzynski     // and fir.box end up being the same llvm types and loading a
1173e3349fa1SAndrzej Warzynski     // fir.ref<fir.box> is actually a no op in LLVM.
1174e3349fa1SAndrzej Warzynski     if (load.getType().isa<fir::BoxType>()) {
1175e3349fa1SAndrzej Warzynski       rewriter.replaceOp(load, adaptor.getOperands()[0]);
1176e3349fa1SAndrzej Warzynski     } else {
1177e3349fa1SAndrzej Warzynski       mlir::Type ty = convertType(load.getType());
1178e3349fa1SAndrzej Warzynski       ArrayRef<NamedAttribute> at = load->getAttrs();
1179e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::LoadOp>(
1180e3349fa1SAndrzej Warzynski           load, ty, adaptor.getOperands(), at);
1181e3349fa1SAndrzej Warzynski     }
1182e3349fa1SAndrzej Warzynski     return success();
1183e3349fa1SAndrzej Warzynski   }
1184e3349fa1SAndrzej Warzynski };
1185e3349fa1SAndrzej Warzynski 
1186b8207db7SValentin Clement /// Lower `fir.no_reassoc` to LLVM IR dialect.
1187b8207db7SValentin Clement /// TODO: how do we want to enforce this in LLVM-IR? Can we manipulate the fast
1188b8207db7SValentin Clement /// math flags?
1189b8207db7SValentin Clement struct NoReassocOpConversion : public FIROpConversion<fir::NoReassocOp> {
1190b8207db7SValentin Clement   using FIROpConversion::FIROpConversion;
1191b8207db7SValentin Clement 
1192b8207db7SValentin Clement   mlir::LogicalResult
1193b8207db7SValentin Clement   matchAndRewrite(fir::NoReassocOp noreassoc, OpAdaptor adaptor,
1194b8207db7SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1195b8207db7SValentin Clement     rewriter.replaceOp(noreassoc, adaptor.getOperands()[0]);
1196b8207db7SValentin Clement     return success();
1197b8207db7SValentin Clement   }
1198b8207db7SValentin Clement };
1199b8207db7SValentin Clement 
12002a299e4fSValentin Clement /// Lower `fir.select_type` to LLVM IR dialect.
12012a299e4fSValentin Clement struct SelectTypeOpConversion : public FIROpConversion<fir::SelectTypeOp> {
12022a299e4fSValentin Clement   using FIROpConversion::FIROpConversion;
12032a299e4fSValentin Clement 
12042a299e4fSValentin Clement   mlir::LogicalResult
12052a299e4fSValentin Clement   matchAndRewrite(fir::SelectTypeOp select, OpAdaptor adaptor,
12062a299e4fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
12077ce8c6fcSKiran Chandramohan     mlir::emitError(select.getLoc(),
12087ce8c6fcSKiran Chandramohan                     "fir.select_type should have already been converted");
12097ce8c6fcSKiran Chandramohan     return failure();
12102a299e4fSValentin Clement   }
12112a299e4fSValentin Clement };
12122a299e4fSValentin Clement 
12138c239909SValentin Clement /// conversion of fir::SelectRankOp to an if-then-else ladder
12148c239909SValentin Clement struct SelectRankOpConversion : public FIROpConversion<fir::SelectRankOp> {
12158c239909SValentin Clement   using FIROpConversion::FIROpConversion;
12168c239909SValentin Clement 
12178c239909SValentin Clement   mlir::LogicalResult
12188c239909SValentin Clement   matchAndRewrite(fir::SelectRankOp op, OpAdaptor adaptor,
12198c239909SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
12208c239909SValentin Clement     selectMatchAndRewrite<fir::SelectRankOp>(lowerTy(), op, adaptor, rewriter);
12218c239909SValentin Clement     return success();
12228c239909SValentin Clement   }
12238c239909SValentin Clement };
12248c239909SValentin Clement 
1225e3349fa1SAndrzej Warzynski /// `fir.store` --> `llvm.store`
1226e3349fa1SAndrzej Warzynski struct StoreOpConversion : public FIROpConversion<fir::StoreOp> {
1227e3349fa1SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
1228e3349fa1SAndrzej Warzynski 
1229e3349fa1SAndrzej Warzynski   mlir::LogicalResult
1230e3349fa1SAndrzej Warzynski   matchAndRewrite(fir::StoreOp store, OpAdaptor adaptor,
1231e3349fa1SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
1232e3349fa1SAndrzej Warzynski     if (store.value().getType().isa<fir::BoxType>()) {
1233e3349fa1SAndrzej Warzynski       // fir.box value is actually in memory, load it first before storing it.
1234e3349fa1SAndrzej Warzynski       mlir::Location loc = store.getLoc();
1235e3349fa1SAndrzej Warzynski       mlir::Type boxPtrTy = adaptor.getOperands()[0].getType();
1236e3349fa1SAndrzej Warzynski       auto val = rewriter.create<mlir::LLVM::LoadOp>(
1237e3349fa1SAndrzej Warzynski           loc, boxPtrTy.cast<mlir::LLVM::LLVMPointerType>().getElementType(),
1238e3349fa1SAndrzej Warzynski           adaptor.getOperands()[0]);
1239e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
1240e3349fa1SAndrzej Warzynski           store, val, adaptor.getOperands()[1]);
1241e3349fa1SAndrzej Warzynski     } else {
1242e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
1243e3349fa1SAndrzej Warzynski           store, adaptor.getOperands()[0], adaptor.getOperands()[1]);
1244e3349fa1SAndrzej Warzynski     }
1245e3349fa1SAndrzej Warzynski     return success();
1246e3349fa1SAndrzej Warzynski   }
1247e3349fa1SAndrzej Warzynski };
1248e3349fa1SAndrzej Warzynski 
1249e3349fa1SAndrzej Warzynski /// convert to LLVM IR dialect `undef`
1250044d5b5dSValentin Clement struct UndefOpConversion : public FIROpConversion<fir::UndefOp> {
1251044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
1252044d5b5dSValentin Clement 
1253044d5b5dSValentin Clement   mlir::LogicalResult
1254044d5b5dSValentin Clement   matchAndRewrite(fir::UndefOp undef, OpAdaptor,
1255044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1256044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::UndefOp>(
1257044d5b5dSValentin Clement         undef, convertType(undef.getType()));
1258044d5b5dSValentin Clement     return success();
1259044d5b5dSValentin Clement   }
1260044d5b5dSValentin Clement };
1261a7a61359SValentin Clement 
1262e3349fa1SAndrzej Warzynski /// `fir.unreachable` --> `llvm.unreachable`
126332e08248SAndrzej Warzynski struct UnreachableOpConversion : public FIROpConversion<fir::UnreachableOp> {
126432e08248SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
126532e08248SAndrzej Warzynski 
126632e08248SAndrzej Warzynski   mlir::LogicalResult
126732e08248SAndrzej Warzynski   matchAndRewrite(fir::UnreachableOp unreach, OpAdaptor adaptor,
126832e08248SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
126932e08248SAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(unreach);
127032e08248SAndrzej Warzynski     return success();
127132e08248SAndrzej Warzynski   }
127232e08248SAndrzej Warzynski };
127332e08248SAndrzej Warzynski 
1274a7a61359SValentin Clement struct ZeroOpConversion : public FIROpConversion<fir::ZeroOp> {
1275a7a61359SValentin Clement   using FIROpConversion::FIROpConversion;
1276a7a61359SValentin Clement 
1277a7a61359SValentin Clement   mlir::LogicalResult
1278a7a61359SValentin Clement   matchAndRewrite(fir::ZeroOp zero, OpAdaptor,
1279a7a61359SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
12807ce8c6fcSKiran Chandramohan     mlir::Type ty = convertType(zero.getType());
1281a7a61359SValentin Clement     if (ty.isa<mlir::LLVM::LLVMPointerType>()) {
1282a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(zero, ty);
1283a7a61359SValentin Clement     } else if (ty.isa<mlir::IntegerType>()) {
1284a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
1285a7a61359SValentin Clement           zero, ty, mlir::IntegerAttr::get(zero.getType(), 0));
1286a7a61359SValentin Clement     } else if (mlir::LLVM::isCompatibleFloatingPointType(ty)) {
1287a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
1288a7a61359SValentin Clement           zero, ty, mlir::FloatAttr::get(zero.getType(), 0.0));
1289a7a61359SValentin Clement     } else {
1290a7a61359SValentin Clement       // TODO: create ConstantAggregateZero for FIR aggregate/array types.
129152d813edSValentin Clement       return rewriter.notifyMatchFailure(
129252d813edSValentin Clement           zero,
1293a7a61359SValentin Clement           "conversion of fir.zero with aggregate type not implemented yet");
1294a7a61359SValentin Clement     }
1295a7a61359SValentin Clement     return success();
1296a7a61359SValentin Clement   }
1297a7a61359SValentin Clement };
129832e08248SAndrzej Warzynski 
1299af6ee580SValentin Clement /// Common base class for embox to descriptor conversion.
1300af6ee580SValentin Clement template <typename OP>
1301af6ee580SValentin Clement struct EmboxCommonConversion : public FIROpConversion<OP> {
1302af6ee580SValentin Clement   using FIROpConversion<OP>::FIROpConversion;
1303af6ee580SValentin Clement 
1304af6ee580SValentin Clement   // Find the LLVMFuncOp in whose entry block the alloca should be inserted.
1305af6ee580SValentin Clement   // The order to find the LLVMFuncOp is as follows:
1306af6ee580SValentin Clement   // 1. The parent operation of the current block if it is a LLVMFuncOp.
1307af6ee580SValentin Clement   // 2. The first ancestor that is a LLVMFuncOp.
1308af6ee580SValentin Clement   mlir::LLVM::LLVMFuncOp
1309af6ee580SValentin Clement   getFuncForAllocaInsert(mlir::ConversionPatternRewriter &rewriter) const {
1310af6ee580SValentin Clement     mlir::Operation *parentOp = rewriter.getInsertionBlock()->getParentOp();
1311af6ee580SValentin Clement     return mlir::isa<mlir::LLVM::LLVMFuncOp>(parentOp)
1312af6ee580SValentin Clement                ? mlir::cast<mlir::LLVM::LLVMFuncOp>(parentOp)
1313af6ee580SValentin Clement                : parentOp->getParentOfType<mlir::LLVM::LLVMFuncOp>();
1314af6ee580SValentin Clement   }
1315af6ee580SValentin Clement 
1316af6ee580SValentin Clement   // Generate an alloca of size 1 and type \p toTy.
1317af6ee580SValentin Clement   mlir::LLVM::AllocaOp
1318af6ee580SValentin Clement   genAllocaWithType(mlir::Location loc, mlir::Type toTy, unsigned alignment,
1319af6ee580SValentin Clement                     mlir::ConversionPatternRewriter &rewriter) const {
1320af6ee580SValentin Clement     auto thisPt = rewriter.saveInsertionPoint();
1321af6ee580SValentin Clement     mlir::LLVM::LLVMFuncOp func = getFuncForAllocaInsert(rewriter);
1322af6ee580SValentin Clement     rewriter.setInsertionPointToStart(&func.front());
1323af6ee580SValentin Clement     auto size = this->genI32Constant(loc, rewriter, 1);
1324af6ee580SValentin Clement     auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, toTy, size, alignment);
1325af6ee580SValentin Clement     rewriter.restoreInsertionPoint(thisPt);
1326af6ee580SValentin Clement     return al;
1327af6ee580SValentin Clement   }
1328af6ee580SValentin Clement 
1329af6ee580SValentin Clement   static int getCFIAttr(fir::BoxType boxTy) {
1330af6ee580SValentin Clement     auto eleTy = boxTy.getEleTy();
1331af6ee580SValentin Clement     if (eleTy.isa<fir::PointerType>())
1332af6ee580SValentin Clement       return CFI_attribute_pointer;
1333af6ee580SValentin Clement     if (eleTy.isa<fir::HeapType>())
1334af6ee580SValentin Clement       return CFI_attribute_allocatable;
1335af6ee580SValentin Clement     return CFI_attribute_other;
1336af6ee580SValentin Clement   }
1337af6ee580SValentin Clement 
1338af6ee580SValentin Clement   static fir::RecordType unwrapIfDerived(fir::BoxType boxTy) {
1339af6ee580SValentin Clement     return fir::unwrapSequenceType(fir::dyn_cast_ptrOrBoxEleTy(boxTy))
1340af6ee580SValentin Clement         .template dyn_cast<fir::RecordType>();
1341af6ee580SValentin Clement   }
1342af6ee580SValentin Clement   static bool isDerivedTypeWithLenParams(fir::BoxType boxTy) {
1343af6ee580SValentin Clement     auto recTy = unwrapIfDerived(boxTy);
1344af6ee580SValentin Clement     return recTy && recTy.getNumLenParams() > 0;
1345af6ee580SValentin Clement   }
1346af6ee580SValentin Clement   static bool isDerivedType(fir::BoxType boxTy) {
1347af6ee580SValentin Clement     return unwrapIfDerived(boxTy) != nullptr;
1348af6ee580SValentin Clement   }
1349af6ee580SValentin Clement 
1350af6ee580SValentin Clement   // Get the element size and CFI type code of the boxed value.
1351af6ee580SValentin Clement   std::tuple<mlir::Value, mlir::Value> getSizeAndTypeCode(
1352af6ee580SValentin Clement       mlir::Location loc, mlir::ConversionPatternRewriter &rewriter,
1353af6ee580SValentin Clement       mlir::Type boxEleTy, mlir::ValueRange lenParams = {}) const {
1354af6ee580SValentin Clement     auto doInteger =
1355af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1356af6ee580SValentin Clement       int typeCode = fir::integerBitsToTypeCode(width);
1357af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1358af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1359af6ee580SValentin Clement     };
1360af6ee580SValentin Clement     auto doLogical =
1361af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1362af6ee580SValentin Clement       int typeCode = fir::logicalBitsToTypeCode(width);
1363af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1364af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1365af6ee580SValentin Clement     };
1366af6ee580SValentin Clement     auto doFloat = [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1367af6ee580SValentin Clement       int typeCode = fir::realBitsToTypeCode(width);
1368af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1369af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1370af6ee580SValentin Clement     };
1371af6ee580SValentin Clement     auto doComplex =
1372af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1373af6ee580SValentin Clement       auto typeCode = fir::complexBitsToTypeCode(width);
1374af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8 * 2),
1375af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1376af6ee580SValentin Clement     };
1377af6ee580SValentin Clement     auto doCharacter =
1378af6ee580SValentin Clement         [&](unsigned width,
1379af6ee580SValentin Clement             mlir::Value len) -> std::tuple<mlir::Value, mlir::Value> {
1380af6ee580SValentin Clement       auto typeCode = fir::characterBitsToTypeCode(width);
1381af6ee580SValentin Clement       auto typeCodeVal = this->genConstantOffset(loc, rewriter, typeCode);
1382af6ee580SValentin Clement       if (width == 8)
1383af6ee580SValentin Clement         return {len, typeCodeVal};
1384af6ee580SValentin Clement       auto byteWidth = this->genConstantOffset(loc, rewriter, width / 8);
1385af6ee580SValentin Clement       auto i64Ty = mlir::IntegerType::get(&this->lowerTy().getContext(), 64);
1386af6ee580SValentin Clement       auto size =
1387af6ee580SValentin Clement           rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, byteWidth, len);
1388af6ee580SValentin Clement       return {size, typeCodeVal};
1389af6ee580SValentin Clement     };
1390af6ee580SValentin Clement     auto getKindMap = [&]() -> fir::KindMapping & {
1391af6ee580SValentin Clement       return this->lowerTy().getKindMap();
1392af6ee580SValentin Clement     };
1393af6ee580SValentin Clement     // Pointer-like types.
1394af6ee580SValentin Clement     if (auto eleTy = fir::dyn_cast_ptrEleTy(boxEleTy))
1395af6ee580SValentin Clement       boxEleTy = eleTy;
1396af6ee580SValentin Clement     // Integer types.
1397af6ee580SValentin Clement     if (fir::isa_integer(boxEleTy)) {
1398af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::IntegerType>())
1399af6ee580SValentin Clement         return doInteger(ty.getWidth());
1400af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::IntegerType>();
1401af6ee580SValentin Clement       return doInteger(getKindMap().getIntegerBitsize(ty.getFKind()));
1402af6ee580SValentin Clement     }
1403af6ee580SValentin Clement     // Floating point types.
1404af6ee580SValentin Clement     if (fir::isa_real(boxEleTy)) {
1405af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::FloatType>())
1406af6ee580SValentin Clement         return doFloat(ty.getWidth());
1407af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::RealType>();
1408af6ee580SValentin Clement       return doFloat(getKindMap().getRealBitsize(ty.getFKind()));
1409af6ee580SValentin Clement     }
1410af6ee580SValentin Clement     // Complex types.
1411af6ee580SValentin Clement     if (fir::isa_complex(boxEleTy)) {
1412af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::ComplexType>())
1413af6ee580SValentin Clement         return doComplex(
1414af6ee580SValentin Clement             ty.getElementType().cast<mlir::FloatType>().getWidth());
1415af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::ComplexType>();
1416af6ee580SValentin Clement       return doComplex(getKindMap().getRealBitsize(ty.getFKind()));
1417af6ee580SValentin Clement     }
1418af6ee580SValentin Clement     // Character types.
1419af6ee580SValentin Clement     if (auto ty = boxEleTy.dyn_cast<fir::CharacterType>()) {
1420af6ee580SValentin Clement       auto charWidth = getKindMap().getCharacterBitsize(ty.getFKind());
1421af6ee580SValentin Clement       if (ty.getLen() != fir::CharacterType::unknownLen()) {
1422af6ee580SValentin Clement         auto len = this->genConstantOffset(loc, rewriter, ty.getLen());
1423af6ee580SValentin Clement         return doCharacter(charWidth, len);
1424af6ee580SValentin Clement       }
1425af6ee580SValentin Clement       assert(!lenParams.empty());
1426af6ee580SValentin Clement       return doCharacter(charWidth, lenParams.back());
1427af6ee580SValentin Clement     }
1428af6ee580SValentin Clement     // Logical type.
1429af6ee580SValentin Clement     if (auto ty = boxEleTy.dyn_cast<fir::LogicalType>())
1430af6ee580SValentin Clement       return doLogical(getKindMap().getLogicalBitsize(ty.getFKind()));
1431af6ee580SValentin Clement     // Array types.
1432af6ee580SValentin Clement     if (auto seqTy = boxEleTy.dyn_cast<fir::SequenceType>())
1433af6ee580SValentin Clement       return getSizeAndTypeCode(loc, rewriter, seqTy.getEleTy(), lenParams);
1434af6ee580SValentin Clement     // Derived-type types.
1435af6ee580SValentin Clement     if (boxEleTy.isa<fir::RecordType>()) {
1436af6ee580SValentin Clement       auto ptrTy = mlir::LLVM::LLVMPointerType::get(
1437af6ee580SValentin Clement           this->lowerTy().convertType(boxEleTy));
1438af6ee580SValentin Clement       auto nullPtr = rewriter.create<mlir::LLVM::NullOp>(loc, ptrTy);
1439af6ee580SValentin Clement       auto one =
1440af6ee580SValentin Clement           genConstantIndex(loc, this->lowerTy().offsetType(), rewriter, 1);
1441af6ee580SValentin Clement       auto gep = rewriter.create<mlir::LLVM::GEPOp>(
1442af6ee580SValentin Clement           loc, ptrTy, mlir::ValueRange{nullPtr, one});
1443af6ee580SValentin Clement       auto eleSize = rewriter.create<mlir::LLVM::PtrToIntOp>(
1444af6ee580SValentin Clement           loc, this->lowerTy().indexType(), gep);
1445af6ee580SValentin Clement       return {eleSize,
1446af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, fir::derivedToTypeCode())};
1447af6ee580SValentin Clement     }
1448af6ee580SValentin Clement     // Reference type.
1449af6ee580SValentin Clement     if (fir::isa_ref_type(boxEleTy)) {
1450af6ee580SValentin Clement       // FIXME: use the target pointer size rather than sizeof(void*)
1451af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, sizeof(void *)),
1452af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, CFI_type_cptr)};
1453af6ee580SValentin Clement     }
1454af6ee580SValentin Clement     fir::emitFatalError(loc, "unhandled type in fir.box code generation");
1455af6ee580SValentin Clement   }
1456af6ee580SValentin Clement 
1457af6ee580SValentin Clement   /// Basic pattern to write a field in the descriptor
1458af6ee580SValentin Clement   mlir::Value insertField(mlir::ConversionPatternRewriter &rewriter,
1459af6ee580SValentin Clement                           mlir::Location loc, mlir::Value dest,
1460af6ee580SValentin Clement                           ArrayRef<unsigned> fldIndexes, mlir::Value value,
1461af6ee580SValentin Clement                           bool bitcast = false) const {
1462af6ee580SValentin Clement     auto boxTy = dest.getType();
1463af6ee580SValentin Clement     auto fldTy = this->getBoxEleTy(boxTy, fldIndexes);
1464af6ee580SValentin Clement     if (bitcast)
1465af6ee580SValentin Clement       value = rewriter.create<mlir::LLVM::BitcastOp>(loc, fldTy, value);
1466af6ee580SValentin Clement     else
1467af6ee580SValentin Clement       value = this->integerCast(loc, rewriter, fldTy, value);
1468af6ee580SValentin Clement     SmallVector<mlir::Attribute, 2> attrs;
1469af6ee580SValentin Clement     for (auto i : fldIndexes)
1470af6ee580SValentin Clement       attrs.push_back(rewriter.getI32IntegerAttr(i));
1471af6ee580SValentin Clement     auto indexesAttr = mlir::ArrayAttr::get(rewriter.getContext(), attrs);
1472af6ee580SValentin Clement     return rewriter.create<mlir::LLVM::InsertValueOp>(loc, boxTy, dest, value,
1473af6ee580SValentin Clement                                                       indexesAttr);
1474af6ee580SValentin Clement   }
1475af6ee580SValentin Clement 
1476af6ee580SValentin Clement   inline mlir::Value
1477af6ee580SValentin Clement   insertBaseAddress(mlir::ConversionPatternRewriter &rewriter,
1478af6ee580SValentin Clement                     mlir::Location loc, mlir::Value dest,
1479af6ee580SValentin Clement                     mlir::Value base) const {
14801f551032SValentin Clement     return insertField(rewriter, loc, dest, {kAddrPosInBox}, base,
14811f551032SValentin Clement                        /*bitCast=*/true);
14821f551032SValentin Clement   }
14831f551032SValentin Clement 
14841f551032SValentin Clement   inline mlir::Value insertLowerBound(mlir::ConversionPatternRewriter &rewriter,
14851f551032SValentin Clement                                       mlir::Location loc, mlir::Value dest,
14861f551032SValentin Clement                                       unsigned dim, mlir::Value lb) const {
14871f551032SValentin Clement     return insertField(rewriter, loc, dest,
14881f551032SValentin Clement                        {kDimsPosInBox, dim, kDimLowerBoundPos}, lb);
14891f551032SValentin Clement   }
14901f551032SValentin Clement 
14911f551032SValentin Clement   inline mlir::Value insertExtent(mlir::ConversionPatternRewriter &rewriter,
14921f551032SValentin Clement                                   mlir::Location loc, mlir::Value dest,
14931f551032SValentin Clement                                   unsigned dim, mlir::Value extent) const {
14941f551032SValentin Clement     return insertField(rewriter, loc, dest, {kDimsPosInBox, dim, kDimExtentPos},
14951f551032SValentin Clement                        extent);
14961f551032SValentin Clement   }
14971f551032SValentin Clement 
14981f551032SValentin Clement   inline mlir::Value insertStride(mlir::ConversionPatternRewriter &rewriter,
14991f551032SValentin Clement                                   mlir::Location loc, mlir::Value dest,
15001f551032SValentin Clement                                   unsigned dim, mlir::Value stride) const {
15011f551032SValentin Clement     return insertField(rewriter, loc, dest, {kDimsPosInBox, dim, kDimStridePos},
15021f551032SValentin Clement                        stride);
1503af6ee580SValentin Clement   }
1504af6ee580SValentin Clement 
1505af6ee580SValentin Clement   /// Get the address of the type descriptor global variable that was created by
1506af6ee580SValentin Clement   /// lowering for derived type \p recType.
1507af6ee580SValentin Clement   template <typename BOX>
1508af6ee580SValentin Clement   mlir::Value
1509af6ee580SValentin Clement   getTypeDescriptor(BOX box, mlir::ConversionPatternRewriter &rewriter,
1510af6ee580SValentin Clement                     mlir::Location loc, fir::RecordType recType) const {
1511af6ee580SValentin Clement     std::string name = recType.getLoweredName();
1512af6ee580SValentin Clement     auto module = box->template getParentOfType<mlir::ModuleOp>();
1513af6ee580SValentin Clement     if (auto global = module.template lookupSymbol<fir::GlobalOp>(name)) {
1514af6ee580SValentin Clement       auto ty = mlir::LLVM::LLVMPointerType::get(
1515af6ee580SValentin Clement           this->lowerTy().convertType(global.getType()));
1516af6ee580SValentin Clement       return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty,
1517af6ee580SValentin Clement                                                       global.sym_name());
1518af6ee580SValentin Clement     }
1519af6ee580SValentin Clement     if (auto global =
1520af6ee580SValentin Clement             module.template lookupSymbol<mlir::LLVM::GlobalOp>(name)) {
1521af6ee580SValentin Clement       // The global may have already been translated to LLVM.
1522af6ee580SValentin Clement       auto ty = mlir::LLVM::LLVMPointerType::get(global.getType());
1523af6ee580SValentin Clement       return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty,
1524af6ee580SValentin Clement                                                       global.sym_name());
1525af6ee580SValentin Clement     }
1526af6ee580SValentin Clement     // The global does not exist in the current translation unit, but may be
1527af6ee580SValentin Clement     // defined elsewhere (e.g., type defined in a module).
1528af6ee580SValentin Clement     // For now, create a extern_weak symbol (will become nullptr if unresolved)
1529af6ee580SValentin Clement     // to support generating code without the front-end generated symbols.
1530af6ee580SValentin Clement     // These could be made available_externally to require the symbols to be
1531af6ee580SValentin Clement     // defined elsewhere and to cause link-time failure otherwise.
1532af6ee580SValentin Clement     auto i8Ty = rewriter.getIntegerType(8);
1533af6ee580SValentin Clement     mlir::OpBuilder modBuilder(module.getBodyRegion());
1534af6ee580SValentin Clement     // TODO: The symbol should be lowered to constant in lowering, they are read
1535af6ee580SValentin Clement     // only.
1536af6ee580SValentin Clement     modBuilder.create<mlir::LLVM::GlobalOp>(loc, i8Ty, /*isConstant=*/false,
1537af6ee580SValentin Clement                                             mlir::LLVM::Linkage::ExternWeak,
1538af6ee580SValentin Clement                                             name, mlir::Attribute{});
1539af6ee580SValentin Clement     auto ty = mlir::LLVM::LLVMPointerType::get(i8Ty);
1540af6ee580SValentin Clement     return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty, name);
1541af6ee580SValentin Clement   }
1542af6ee580SValentin Clement 
1543af6ee580SValentin Clement   template <typename BOX>
1544af6ee580SValentin Clement   std::tuple<fir::BoxType, mlir::Value, mlir::Value>
1545af6ee580SValentin Clement   consDescriptorPrefix(BOX box, mlir::ConversionPatternRewriter &rewriter,
1546af6ee580SValentin Clement                        unsigned rank, mlir::ValueRange lenParams) const {
1547af6ee580SValentin Clement     auto loc = box.getLoc();
1548af6ee580SValentin Clement     auto boxTy = box.getType().template dyn_cast<fir::BoxType>();
1549af6ee580SValentin Clement     auto convTy = this->lowerTy().convertBoxType(boxTy, rank);
1550af6ee580SValentin Clement     auto llvmBoxPtrTy = convTy.template cast<mlir::LLVM::LLVMPointerType>();
1551af6ee580SValentin Clement     auto llvmBoxTy = llvmBoxPtrTy.getElementType();
1552af6ee580SValentin Clement     mlir::Value descriptor =
1553af6ee580SValentin Clement         rewriter.create<mlir::LLVM::UndefOp>(loc, llvmBoxTy);
1554af6ee580SValentin Clement 
1555af6ee580SValentin Clement     llvm::SmallVector<mlir::Value> typeparams = lenParams;
1556af6ee580SValentin Clement     if constexpr (!std::is_same_v<BOX, fir::EmboxOp>) {
1557af6ee580SValentin Clement       if (!box.substr().empty() && fir::hasDynamicSize(boxTy.getEleTy()))
1558af6ee580SValentin Clement         typeparams.push_back(box.substr()[1]);
1559af6ee580SValentin Clement     }
1560af6ee580SValentin Clement 
1561af6ee580SValentin Clement     // Write each of the fields with the appropriate values
1562af6ee580SValentin Clement     auto [eleSize, cfiTy] =
1563af6ee580SValentin Clement         getSizeAndTypeCode(loc, rewriter, boxTy.getEleTy(), typeparams);
1564af6ee580SValentin Clement     descriptor =
1565af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kElemLenPosInBox}, eleSize);
1566af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kVersionPosInBox},
1567af6ee580SValentin Clement                              this->genI32Constant(loc, rewriter, CFI_VERSION));
1568af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kRankPosInBox},
1569af6ee580SValentin Clement                              this->genI32Constant(loc, rewriter, rank));
1570af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kTypePosInBox}, cfiTy);
1571af6ee580SValentin Clement     descriptor =
1572af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kAttributePosInBox},
1573af6ee580SValentin Clement                     this->genI32Constant(loc, rewriter, getCFIAttr(boxTy)));
1574af6ee580SValentin Clement     const bool hasAddendum = isDerivedType(boxTy);
1575af6ee580SValentin Clement     descriptor =
1576af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kF18AddendumPosInBox},
1577af6ee580SValentin Clement                     this->genI32Constant(loc, rewriter, hasAddendum ? 1 : 0));
1578af6ee580SValentin Clement 
1579af6ee580SValentin Clement     if (hasAddendum) {
1580af6ee580SValentin Clement       auto isArray =
1581af6ee580SValentin Clement           fir::dyn_cast_ptrOrBoxEleTy(boxTy).template isa<fir::SequenceType>();
1582af6ee580SValentin Clement       unsigned typeDescFieldId = isArray ? kOptTypePtrPosInBox : kDimsPosInBox;
1583af6ee580SValentin Clement       auto typeDesc =
1584af6ee580SValentin Clement           getTypeDescriptor(box, rewriter, loc, unwrapIfDerived(boxTy));
1585af6ee580SValentin Clement       descriptor =
1586af6ee580SValentin Clement           insertField(rewriter, loc, descriptor, {typeDescFieldId}, typeDesc,
1587af6ee580SValentin Clement                       /*bitCast=*/true);
1588af6ee580SValentin Clement     }
1589af6ee580SValentin Clement 
1590af6ee580SValentin Clement     return {boxTy, descriptor, eleSize};
1591af6ee580SValentin Clement   }
1592af6ee580SValentin Clement 
15931f551032SValentin Clement   /// Compute the base address of a substring given the base address of a scalar
15941f551032SValentin Clement   /// string and the zero based string lower bound.
15951f551032SValentin Clement   mlir::Value shiftSubstringBase(mlir::ConversionPatternRewriter &rewriter,
15961f551032SValentin Clement                                  mlir::Location loc, mlir::Value base,
15971f551032SValentin Clement                                  mlir::Value lowerBound) const {
15981f551032SValentin Clement     llvm::SmallVector<mlir::Value> gepOperands;
15991f551032SValentin Clement     auto baseType =
16001f551032SValentin Clement         base.getType().cast<mlir::LLVM::LLVMPointerType>().getElementType();
16011f551032SValentin Clement     if (baseType.isa<mlir::LLVM::LLVMArrayType>()) {
16021f551032SValentin Clement       auto idxTy = this->lowerTy().indexType();
16031f551032SValentin Clement       mlir::Value zero = genConstantIndex(loc, idxTy, rewriter, 0);
16041f551032SValentin Clement       gepOperands.push_back(zero);
16051f551032SValentin Clement     }
16061f551032SValentin Clement     gepOperands.push_back(lowerBound);
16071f551032SValentin Clement     return this->genGEP(loc, base.getType(), rewriter, base, gepOperands);
16081f551032SValentin Clement   }
16091f551032SValentin Clement 
1610af6ee580SValentin Clement   /// If the embox is not in a globalOp body, allocate storage for the box;
1611af6ee580SValentin Clement   /// store the value inside and return the generated alloca. Return the input
1612af6ee580SValentin Clement   /// value otherwise.
1613af6ee580SValentin Clement   mlir::Value
1614af6ee580SValentin Clement   placeInMemoryIfNotGlobalInit(mlir::ConversionPatternRewriter &rewriter,
1615af6ee580SValentin Clement                                mlir::Location loc, mlir::Value boxValue) const {
1616af6ee580SValentin Clement     auto *thisBlock = rewriter.getInsertionBlock();
1617af6ee580SValentin Clement     if (thisBlock && mlir::isa<mlir::LLVM::GlobalOp>(thisBlock->getParentOp()))
1618af6ee580SValentin Clement       return boxValue;
1619af6ee580SValentin Clement     auto boxPtrTy = mlir::LLVM::LLVMPointerType::get(boxValue.getType());
1620af6ee580SValentin Clement     auto alloca = genAllocaWithType(loc, boxPtrTy, defaultAlign, rewriter);
1621af6ee580SValentin Clement     rewriter.create<mlir::LLVM::StoreOp>(loc, boxValue, alloca);
1622af6ee580SValentin Clement     return alloca;
1623af6ee580SValentin Clement   }
1624af6ee580SValentin Clement };
1625af6ee580SValentin Clement 
16261f551032SValentin Clement /// Compute the extent of a triplet slice (lb:ub:step).
16271f551032SValentin Clement static mlir::Value
16281f551032SValentin Clement computeTripletExtent(mlir::ConversionPatternRewriter &rewriter,
16291f551032SValentin Clement                      mlir::Location loc, mlir::Value lb, mlir::Value ub,
16301f551032SValentin Clement                      mlir::Value step, mlir::Value zero, mlir::Type type) {
16311f551032SValentin Clement   mlir::Value extent = rewriter.create<mlir::LLVM::SubOp>(loc, type, ub, lb);
16321f551032SValentin Clement   extent = rewriter.create<mlir::LLVM::AddOp>(loc, type, extent, step);
16331f551032SValentin Clement   extent = rewriter.create<mlir::LLVM::SDivOp>(loc, type, extent, step);
16341f551032SValentin Clement   // If the resulting extent is negative (`ub-lb` and `step` have different
16351f551032SValentin Clement   // signs), zero must be returned instead.
16361f551032SValentin Clement   auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
16371f551032SValentin Clement       loc, mlir::LLVM::ICmpPredicate::sgt, extent, zero);
16381f551032SValentin Clement   return rewriter.create<mlir::LLVM::SelectOp>(loc, cmp, extent, zero);
16391f551032SValentin Clement }
16401f551032SValentin Clement 
16411f551032SValentin Clement /// Helper function for generating the LLVM IR that computes the size
16421f551032SValentin Clement /// in bytes for a derived type.
16431f551032SValentin Clement static mlir::Value
16441f551032SValentin Clement computeDerivedTypeSize(mlir::Location loc, mlir::Type ptrTy, mlir::Type idxTy,
16451f551032SValentin Clement                        mlir::ConversionPatternRewriter &rewriter) {
16461f551032SValentin Clement   auto nullPtr = rewriter.create<mlir::LLVM::NullOp>(loc, ptrTy);
16471f551032SValentin Clement   mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1);
16481f551032SValentin Clement   llvm::SmallVector<mlir::Value> args{nullPtr, one};
16491f551032SValentin Clement   auto gep = rewriter.create<mlir::LLVM::GEPOp>(loc, ptrTy, args);
16501f551032SValentin Clement   return rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, gep);
16511f551032SValentin Clement }
16521f551032SValentin Clement 
1653af6ee580SValentin Clement /// Create a generic box on a memory reference. This conversions lowers the
1654af6ee580SValentin Clement /// abstract box to the appropriate, initialized descriptor.
1655af6ee580SValentin Clement struct EmboxOpConversion : public EmboxCommonConversion<fir::EmboxOp> {
1656af6ee580SValentin Clement   using EmboxCommonConversion::EmboxCommonConversion;
1657af6ee580SValentin Clement 
1658af6ee580SValentin Clement   mlir::LogicalResult
1659af6ee580SValentin Clement   matchAndRewrite(fir::EmboxOp embox, OpAdaptor adaptor,
1660af6ee580SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1661af6ee580SValentin Clement     assert(!embox.getShape() && "There should be no dims on this embox op");
1662af6ee580SValentin Clement     auto [boxTy, dest, eleSize] =
1663af6ee580SValentin Clement         consDescriptorPrefix(embox, rewriter, /*rank=*/0,
1664af6ee580SValentin Clement                              /*lenParams=*/adaptor.getOperands().drop_front(1));
1665af6ee580SValentin Clement     dest = insertBaseAddress(rewriter, embox.getLoc(), dest,
1666af6ee580SValentin Clement                              adaptor.getOperands()[0]);
16677ce8c6fcSKiran Chandramohan     if (isDerivedTypeWithLenParams(boxTy)) {
16687ce8c6fcSKiran Chandramohan       TODO(embox.getLoc(),
16697ce8c6fcSKiran Chandramohan            "fir.embox codegen of derived with length parameters");
16707ce8c6fcSKiran Chandramohan       return failure();
16717ce8c6fcSKiran Chandramohan     }
1672af6ee580SValentin Clement     auto result = placeInMemoryIfNotGlobalInit(rewriter, embox.getLoc(), dest);
1673af6ee580SValentin Clement     rewriter.replaceOp(embox, result);
1674af6ee580SValentin Clement     return success();
1675af6ee580SValentin Clement   }
1676af6ee580SValentin Clement };
1677af6ee580SValentin Clement 
1678cc505c0bSKiran Chandramohan /// Lower `fir.emboxproc` operation. Creates a procedure box.
1679cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
1680cc505c0bSKiran Chandramohan struct EmboxProcOpConversion : public FIROpConversion<fir::EmboxProcOp> {
1681cc505c0bSKiran Chandramohan   using FIROpConversion::FIROpConversion;
1682cc505c0bSKiran Chandramohan 
1683cc505c0bSKiran Chandramohan   mlir::LogicalResult
1684cc505c0bSKiran Chandramohan   matchAndRewrite(fir::EmboxProcOp emboxproc, OpAdaptor adaptor,
1685cc505c0bSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
16867ce8c6fcSKiran Chandramohan     TODO(emboxproc.getLoc(), "fir.emboxproc codegen");
16877ce8c6fcSKiran Chandramohan     return failure();
1688cc505c0bSKiran Chandramohan   }
1689cc505c0bSKiran Chandramohan };
1690cc505c0bSKiran Chandramohan 
16911f551032SValentin Clement /// Create a generic box on a memory reference.
16921f551032SValentin Clement struct XEmboxOpConversion : public EmboxCommonConversion<fir::cg::XEmboxOp> {
16931f551032SValentin Clement   using EmboxCommonConversion::EmboxCommonConversion;
16941f551032SValentin Clement 
16951f551032SValentin Clement   mlir::LogicalResult
16961f551032SValentin Clement   matchAndRewrite(fir::cg::XEmboxOp xbox, OpAdaptor adaptor,
16971f551032SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
16981f551032SValentin Clement     auto [boxTy, dest, eleSize] = consDescriptorPrefix(
16991f551032SValentin Clement         xbox, rewriter, xbox.getOutRank(),
17001f551032SValentin Clement         adaptor.getOperands().drop_front(xbox.lenParamOffset()));
17011f551032SValentin Clement     // Generate the triples in the dims field of the descriptor
17021f551032SValentin Clement     mlir::ValueRange operands = adaptor.getOperands();
17031f551032SValentin Clement     auto i64Ty = mlir::IntegerType::get(xbox.getContext(), 64);
17041f551032SValentin Clement     mlir::Value base = operands[0];
17051f551032SValentin Clement     assert(!xbox.shape().empty() && "must have a shape");
17061f551032SValentin Clement     unsigned shapeOffset = xbox.shapeOffset();
17071f551032SValentin Clement     bool hasShift = !xbox.shift().empty();
17081f551032SValentin Clement     unsigned shiftOffset = xbox.shiftOffset();
17091f551032SValentin Clement     bool hasSlice = !xbox.slice().empty();
17101f551032SValentin Clement     unsigned sliceOffset = xbox.sliceOffset();
17111f551032SValentin Clement     mlir::Location loc = xbox.getLoc();
17121f551032SValentin Clement     mlir::Value zero = genConstantIndex(loc, i64Ty, rewriter, 0);
17131f551032SValentin Clement     mlir::Value one = genConstantIndex(loc, i64Ty, rewriter, 1);
17141f551032SValentin Clement     mlir::Value prevDim = integerCast(loc, rewriter, i64Ty, eleSize);
17151f551032SValentin Clement     mlir::Value prevPtrOff = one;
17161f551032SValentin Clement     mlir::Type eleTy = boxTy.getEleTy();
17171f551032SValentin Clement     const unsigned rank = xbox.getRank();
17181f551032SValentin Clement     llvm::SmallVector<mlir::Value> gepArgs;
17191f551032SValentin Clement     unsigned constRows = 0;
17201f551032SValentin Clement     mlir::Value ptrOffset = zero;
17211f551032SValentin Clement     if (auto memEleTy = fir::dyn_cast_ptrEleTy(xbox.memref().getType()))
17221f551032SValentin Clement       if (auto seqTy = memEleTy.dyn_cast<fir::SequenceType>()) {
17231f551032SValentin Clement         mlir::Type seqEleTy = seqTy.getEleTy();
17241f551032SValentin Clement         // Adjust the element scaling factor if the element is a dependent type.
17251f551032SValentin Clement         if (fir::hasDynamicSize(seqEleTy)) {
17261f551032SValentin Clement           if (fir::isa_char(seqEleTy)) {
17271f551032SValentin Clement             assert(xbox.lenParams().size() == 1);
17281f551032SValentin Clement             prevPtrOff = integerCast(loc, rewriter, i64Ty,
17291f551032SValentin Clement                                      operands[xbox.lenParamOffset()]);
17301f551032SValentin Clement           } else if (seqEleTy.isa<fir::RecordType>()) {
17311f551032SValentin Clement             TODO(loc, "generate call to calculate size of PDT");
17321f551032SValentin Clement           } else {
17331f551032SValentin Clement             return rewriter.notifyMatchFailure(xbox, "unexpected dynamic type");
17341f551032SValentin Clement           }
17351f551032SValentin Clement         } else {
17361f551032SValentin Clement           constRows = seqTy.getConstantRows();
17371f551032SValentin Clement         }
17381f551032SValentin Clement       }
17391f551032SValentin Clement 
17401f551032SValentin Clement     bool hasSubcomp = !xbox.subcomponent().empty();
17411f551032SValentin Clement     mlir::Value stepExpr;
17421f551032SValentin Clement     if (hasSubcomp) {
17431f551032SValentin Clement       // We have a subcomponent. The step value needs to be the number of
17441f551032SValentin Clement       // bytes per element (which is a derived type).
17451f551032SValentin Clement       mlir::Type ty0 = base.getType();
17461f551032SValentin Clement       [[maybe_unused]] auto ptrTy = ty0.dyn_cast<mlir::LLVM::LLVMPointerType>();
17471f551032SValentin Clement       assert(ptrTy && "expected pointer type");
17481f551032SValentin Clement       mlir::Type memEleTy = fir::dyn_cast_ptrEleTy(xbox.memref().getType());
17491f551032SValentin Clement       assert(memEleTy && "expected fir pointer type");
17501f551032SValentin Clement       auto seqTy = memEleTy.dyn_cast<fir::SequenceType>();
17511f551032SValentin Clement       assert(seqTy && "expected sequence type");
17521f551032SValentin Clement       mlir::Type seqEleTy = seqTy.getEleTy();
17531f551032SValentin Clement       auto eleTy = mlir::LLVM::LLVMPointerType::get(convertType(seqEleTy));
17541f551032SValentin Clement       stepExpr = computeDerivedTypeSize(loc, eleTy, i64Ty, rewriter);
17551f551032SValentin Clement     }
17561f551032SValentin Clement 
17571f551032SValentin Clement     // Process the array subspace arguments (shape, shift, etc.), if any,
17581f551032SValentin Clement     // translating everything to values in the descriptor wherever the entity
17591f551032SValentin Clement     // has a dynamic array dimension.
17601f551032SValentin Clement     for (unsigned di = 0, descIdx = 0; di < rank; ++di) {
17611f551032SValentin Clement       mlir::Value extent = operands[shapeOffset];
17621f551032SValentin Clement       mlir::Value outerExtent = extent;
17631f551032SValentin Clement       bool skipNext = false;
17641f551032SValentin Clement       if (hasSlice) {
17651f551032SValentin Clement         mlir::Value off = operands[sliceOffset];
17661f551032SValentin Clement         mlir::Value adj = one;
17671f551032SValentin Clement         if (hasShift)
17681f551032SValentin Clement           adj = operands[shiftOffset];
17691f551032SValentin Clement         auto ao = rewriter.create<mlir::LLVM::SubOp>(loc, i64Ty, off, adj);
17701f551032SValentin Clement         if (constRows > 0) {
17711f551032SValentin Clement           gepArgs.push_back(ao);
17721f551032SValentin Clement           --constRows;
17731f551032SValentin Clement         } else {
17741f551032SValentin Clement           auto dimOff =
17751f551032SValentin Clement               rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, ao, prevPtrOff);
17761f551032SValentin Clement           ptrOffset =
17771f551032SValentin Clement               rewriter.create<mlir::LLVM::AddOp>(loc, i64Ty, dimOff, ptrOffset);
17781f551032SValentin Clement         }
17791f551032SValentin Clement         if (mlir::isa_and_nonnull<fir::UndefOp>(
17801f551032SValentin Clement                 xbox.slice()[3 * di + 1].getDefiningOp())) {
17811f551032SValentin Clement           // This dimension contains a scalar expression in the array slice op.
17821f551032SValentin Clement           // The dimension is loop invariant, will be dropped, and will not
17831f551032SValentin Clement           // appear in the descriptor.
17841f551032SValentin Clement           skipNext = true;
17851f551032SValentin Clement         }
17861f551032SValentin Clement       }
17871f551032SValentin Clement       if (!skipNext) {
17881f551032SValentin Clement         // store lower bound (normally 0)
17891f551032SValentin Clement         mlir::Value lb = zero;
17901f551032SValentin Clement         if (eleTy.isa<fir::PointerType>() || eleTy.isa<fir::HeapType>()) {
17911f551032SValentin Clement           lb = one;
17921f551032SValentin Clement           if (hasShift)
17931f551032SValentin Clement             lb = operands[shiftOffset];
17941f551032SValentin Clement         }
17951f551032SValentin Clement         dest = insertLowerBound(rewriter, loc, dest, descIdx, lb);
17961f551032SValentin Clement 
17971f551032SValentin Clement         // store extent
17981f551032SValentin Clement         if (hasSlice)
17991f551032SValentin Clement           extent = computeTripletExtent(rewriter, loc, operands[sliceOffset],
18001f551032SValentin Clement                                         operands[sliceOffset + 1],
18011f551032SValentin Clement                                         operands[sliceOffset + 2], zero, i64Ty);
18021f551032SValentin Clement         dest = insertExtent(rewriter, loc, dest, descIdx, extent);
18031f551032SValentin Clement 
18041f551032SValentin Clement         // store step (scaled by shaped extent)
18051f551032SValentin Clement 
18061f551032SValentin Clement         mlir::Value step = hasSubcomp ? stepExpr : prevDim;
18071f551032SValentin Clement         if (hasSlice)
18081f551032SValentin Clement           step = rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, step,
18091f551032SValentin Clement                                                     operands[sliceOffset + 2]);
18101f551032SValentin Clement         dest = insertStride(rewriter, loc, dest, descIdx, step);
18111f551032SValentin Clement         ++descIdx;
18121f551032SValentin Clement       }
18131f551032SValentin Clement 
18141f551032SValentin Clement       // compute the stride and offset for the next natural dimension
18151f551032SValentin Clement       prevDim =
18161f551032SValentin Clement           rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, prevDim, outerExtent);
18171f551032SValentin Clement       if (constRows == 0)
18181f551032SValentin Clement         prevPtrOff = rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, prevPtrOff,
18191f551032SValentin Clement                                                         outerExtent);
18201f551032SValentin Clement 
18211f551032SValentin Clement       // increment iterators
18221f551032SValentin Clement       ++shapeOffset;
18231f551032SValentin Clement       if (hasShift)
18241f551032SValentin Clement         ++shiftOffset;
18251f551032SValentin Clement       if (hasSlice)
18261f551032SValentin Clement         sliceOffset += 3;
18271f551032SValentin Clement     }
18281f551032SValentin Clement     if (hasSlice || hasSubcomp || !xbox.substr().empty()) {
18291f551032SValentin Clement       llvm::SmallVector<mlir::Value> args = {base, ptrOffset};
18301f551032SValentin Clement       args.append(gepArgs.rbegin(), gepArgs.rend());
18311f551032SValentin Clement       if (hasSubcomp) {
18321f551032SValentin Clement         // For each field in the path add the offset to base via the args list.
18331f551032SValentin Clement         // In the most general case, some offsets must be computed since
18341f551032SValentin Clement         // they are not be known until runtime.
18351f551032SValentin Clement         if (fir::hasDynamicSize(fir::unwrapSequenceType(
18361f551032SValentin Clement                 fir::unwrapPassByRefType(xbox.memref().getType()))))
18371f551032SValentin Clement           TODO(loc, "fir.embox codegen dynamic size component in derived type");
18381f551032SValentin Clement         args.append(operands.begin() + xbox.subcomponentOffset(),
18391f551032SValentin Clement                     operands.begin() + xbox.subcomponentOffset() +
18401f551032SValentin Clement                         xbox.subcomponent().size());
18411f551032SValentin Clement       }
18421f551032SValentin Clement       base = rewriter.create<mlir::LLVM::GEPOp>(loc, base.getType(), args);
18431f551032SValentin Clement       if (!xbox.substr().empty())
18441f551032SValentin Clement         base = shiftSubstringBase(rewriter, loc, base,
18451f551032SValentin Clement                                   operands[xbox.substrOffset()]);
18461f551032SValentin Clement     }
18471f551032SValentin Clement     dest = insertBaseAddress(rewriter, loc, dest, base);
18481f551032SValentin Clement     if (isDerivedTypeWithLenParams(boxTy))
18491f551032SValentin Clement       TODO(loc, "fir.embox codegen of derived with length parameters");
18501f551032SValentin Clement 
18511f551032SValentin Clement     mlir::Value result = placeInMemoryIfNotGlobalInit(rewriter, loc, dest);
18521f551032SValentin Clement     rewriter.replaceOp(xbox, result);
18531f551032SValentin Clement     return success();
18541f551032SValentin Clement   }
18551f551032SValentin Clement };
18561f551032SValentin Clement 
185754c56347SValentin Clement // Code shared between insert_value and extract_value Ops.
185854c56347SValentin Clement struct ValueOpCommon {
185954c56347SValentin Clement   // Translate the arguments pertaining to any multidimensional array to
186054c56347SValentin Clement   // row-major order for LLVM-IR.
186154c56347SValentin Clement   static void toRowMajor(SmallVectorImpl<mlir::Attribute> &attrs,
186254c56347SValentin Clement                          mlir::Type ty) {
186354c56347SValentin Clement     assert(ty && "type is null");
186454c56347SValentin Clement     const auto end = attrs.size();
186554c56347SValentin Clement     for (std::remove_const_t<decltype(end)> i = 0; i < end; ++i) {
186654c56347SValentin Clement       if (auto seq = ty.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
186754c56347SValentin Clement         const auto dim = getDimension(seq);
186854c56347SValentin Clement         if (dim > 1) {
186954c56347SValentin Clement           auto ub = std::min(i + dim, end);
187054c56347SValentin Clement           std::reverse(attrs.begin() + i, attrs.begin() + ub);
187154c56347SValentin Clement           i += dim - 1;
187254c56347SValentin Clement         }
187354c56347SValentin Clement         ty = getArrayElementType(seq);
187454c56347SValentin Clement       } else if (auto st = ty.dyn_cast<mlir::LLVM::LLVMStructType>()) {
187554c56347SValentin Clement         ty = st.getBody()[attrs[i].cast<mlir::IntegerAttr>().getInt()];
187654c56347SValentin Clement       } else {
187754c56347SValentin Clement         llvm_unreachable("index into invalid type");
187854c56347SValentin Clement       }
187954c56347SValentin Clement     }
188054c56347SValentin Clement   }
188154c56347SValentin Clement 
188254c56347SValentin Clement   static llvm::SmallVector<mlir::Attribute>
188354c56347SValentin Clement   collectIndices(mlir::ConversionPatternRewriter &rewriter,
188454c56347SValentin Clement                  mlir::ArrayAttr arrAttr) {
188554c56347SValentin Clement     llvm::SmallVector<mlir::Attribute> attrs;
188654c56347SValentin Clement     for (auto i = arrAttr.begin(), e = arrAttr.end(); i != e; ++i) {
188754c56347SValentin Clement       if (i->isa<mlir::IntegerAttr>()) {
188854c56347SValentin Clement         attrs.push_back(*i);
188954c56347SValentin Clement       } else {
189054c56347SValentin Clement         auto fieldName = i->cast<mlir::StringAttr>().getValue();
189154c56347SValentin Clement         ++i;
189254c56347SValentin Clement         auto ty = i->cast<mlir::TypeAttr>().getValue();
189354c56347SValentin Clement         auto index = ty.cast<fir::RecordType>().getFieldIndex(fieldName);
189454c56347SValentin Clement         attrs.push_back(mlir::IntegerAttr::get(rewriter.getI32Type(), index));
189554c56347SValentin Clement       }
189654c56347SValentin Clement     }
189754c56347SValentin Clement     return attrs;
189854c56347SValentin Clement   }
189954c56347SValentin Clement 
190054c56347SValentin Clement private:
190154c56347SValentin Clement   static unsigned getDimension(mlir::LLVM::LLVMArrayType ty) {
190254c56347SValentin Clement     unsigned result = 1;
190354c56347SValentin Clement     for (auto eleTy = ty.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>();
190454c56347SValentin Clement          eleTy;
190554c56347SValentin Clement          eleTy = eleTy.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>())
190654c56347SValentin Clement       ++result;
190754c56347SValentin Clement     return result;
190854c56347SValentin Clement   }
190954c56347SValentin Clement 
191054c56347SValentin Clement   static mlir::Type getArrayElementType(mlir::LLVM::LLVMArrayType ty) {
191154c56347SValentin Clement     auto eleTy = ty.getElementType();
191254c56347SValentin Clement     while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>())
191354c56347SValentin Clement       eleTy = arrTy.getElementType();
191454c56347SValentin Clement     return eleTy;
191554c56347SValentin Clement   }
191654c56347SValentin Clement };
191754c56347SValentin Clement 
191854c56347SValentin Clement /// Extract a subobject value from an ssa-value of aggregate type
191954c56347SValentin Clement struct ExtractValueOpConversion
192054c56347SValentin Clement     : public FIROpAndTypeConversion<fir::ExtractValueOp>,
192154c56347SValentin Clement       public ValueOpCommon {
192254c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
192354c56347SValentin Clement 
192454c56347SValentin Clement   mlir::LogicalResult
192554c56347SValentin Clement   doRewrite(fir::ExtractValueOp extractVal, mlir::Type ty, OpAdaptor adaptor,
192654c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
192754c56347SValentin Clement     auto attrs = collectIndices(rewriter, extractVal.coor());
192854c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
192954c56347SValentin Clement     auto position = mlir::ArrayAttr::get(extractVal.getContext(), attrs);
193054c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(
193154c56347SValentin Clement         extractVal, ty, adaptor.getOperands()[0], position);
193254c56347SValentin Clement     return success();
193354c56347SValentin Clement   }
193454c56347SValentin Clement };
193554c56347SValentin Clement 
193654c56347SValentin Clement /// InsertValue is the generalized instruction for the composition of new
193754c56347SValentin Clement /// aggregate type values.
193854c56347SValentin Clement struct InsertValueOpConversion
193954c56347SValentin Clement     : public FIROpAndTypeConversion<fir::InsertValueOp>,
194054c56347SValentin Clement       public ValueOpCommon {
194154c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
194254c56347SValentin Clement 
194354c56347SValentin Clement   mlir::LogicalResult
194454c56347SValentin Clement   doRewrite(fir::InsertValueOp insertVal, mlir::Type ty, OpAdaptor adaptor,
194554c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
194654c56347SValentin Clement     auto attrs = collectIndices(rewriter, insertVal.coor());
194754c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
194854c56347SValentin Clement     auto position = mlir::ArrayAttr::get(insertVal.getContext(), attrs);
194954c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
195054c56347SValentin Clement         insertVal, ty, adaptor.getOperands()[0], adaptor.getOperands()[1],
195154c56347SValentin Clement         position);
195254c56347SValentin Clement     return success();
195354c56347SValentin Clement   }
195454c56347SValentin Clement };
195554c56347SValentin Clement 
19563ae8e442SValentin Clement /// InsertOnRange inserts a value into a sequence over a range of offsets.
19573ae8e442SValentin Clement struct InsertOnRangeOpConversion
19583ae8e442SValentin Clement     : public FIROpAndTypeConversion<fir::InsertOnRangeOp> {
19593ae8e442SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
19603ae8e442SValentin Clement 
19613ae8e442SValentin Clement   // Increments an array of subscripts in a row major fasion.
19623ae8e442SValentin Clement   void incrementSubscripts(const SmallVector<uint64_t> &dims,
19633ae8e442SValentin Clement                            SmallVector<uint64_t> &subscripts) const {
19643ae8e442SValentin Clement     for (size_t i = dims.size(); i > 0; --i) {
19653ae8e442SValentin Clement       if (++subscripts[i - 1] < dims[i - 1]) {
19663ae8e442SValentin Clement         return;
19673ae8e442SValentin Clement       }
19683ae8e442SValentin Clement       subscripts[i - 1] = 0;
19693ae8e442SValentin Clement     }
19703ae8e442SValentin Clement   }
19713ae8e442SValentin Clement 
19723ae8e442SValentin Clement   mlir::LogicalResult
19733ae8e442SValentin Clement   doRewrite(fir::InsertOnRangeOp range, mlir::Type ty, OpAdaptor adaptor,
19743ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
19753ae8e442SValentin Clement 
19763ae8e442SValentin Clement     llvm::SmallVector<uint64_t> dims;
19773ae8e442SValentin Clement     auto type = adaptor.getOperands()[0].getType();
19783ae8e442SValentin Clement 
19793ae8e442SValentin Clement     // Iteratively extract the array dimensions from the type.
19803ae8e442SValentin Clement     while (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
19813ae8e442SValentin Clement       dims.push_back(t.getNumElements());
19823ae8e442SValentin Clement       type = t.getElementType();
19833ae8e442SValentin Clement     }
19843ae8e442SValentin Clement 
19853ae8e442SValentin Clement     SmallVector<uint64_t> lBounds;
19863ae8e442SValentin Clement     SmallVector<uint64_t> uBounds;
19873ae8e442SValentin Clement 
19883ae8e442SValentin Clement     // Unzip the upper and lower bound and convert to a row major format.
19898ec0f221SMehdi Amini     mlir::DenseIntElementsAttr coor = range.coor();
19908ec0f221SMehdi Amini     auto reversedCoor = llvm::reverse(coor.getValues<int64_t>());
19918ec0f221SMehdi Amini     for (auto i = reversedCoor.begin(), e = reversedCoor.end(); i != e; ++i) {
19923ae8e442SValentin Clement       uBounds.push_back(*i++);
19933ae8e442SValentin Clement       lBounds.push_back(*i);
19943ae8e442SValentin Clement     }
19953ae8e442SValentin Clement 
19963ae8e442SValentin Clement     auto &subscripts = lBounds;
19973ae8e442SValentin Clement     auto loc = range.getLoc();
19983ae8e442SValentin Clement     mlir::Value lastOp = adaptor.getOperands()[0];
19993ae8e442SValentin Clement     mlir::Value insertVal = adaptor.getOperands()[1];
20003ae8e442SValentin Clement 
20013ae8e442SValentin Clement     auto i64Ty = rewriter.getI64Type();
20023ae8e442SValentin Clement     while (subscripts != uBounds) {
20033ae8e442SValentin Clement       // Convert uint64_t's to Attribute's.
20043ae8e442SValentin Clement       SmallVector<mlir::Attribute> subscriptAttrs;
20053ae8e442SValentin Clement       for (const auto &subscript : subscripts)
20063ae8e442SValentin Clement         subscriptAttrs.push_back(IntegerAttr::get(i64Ty, subscript));
20073ae8e442SValentin Clement       lastOp = rewriter.create<mlir::LLVM::InsertValueOp>(
20083ae8e442SValentin Clement           loc, ty, lastOp, insertVal,
20093ae8e442SValentin Clement           ArrayAttr::get(range.getContext(), subscriptAttrs));
20103ae8e442SValentin Clement 
20113ae8e442SValentin Clement       incrementSubscripts(dims, subscripts);
20123ae8e442SValentin Clement     }
20133ae8e442SValentin Clement 
20143ae8e442SValentin Clement     // Convert uint64_t's to Attribute's.
20153ae8e442SValentin Clement     SmallVector<mlir::Attribute> subscriptAttrs;
20163ae8e442SValentin Clement     for (const auto &subscript : subscripts)
20173ae8e442SValentin Clement       subscriptAttrs.push_back(
20183ae8e442SValentin Clement           IntegerAttr::get(rewriter.getI64Type(), subscript));
20193ae8e442SValentin Clement     mlir::ArrayRef<mlir::Attribute> arrayRef(subscriptAttrs);
20203ae8e442SValentin Clement 
20213ae8e442SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
20223ae8e442SValentin Clement         range, ty, lastOp, insertVal,
20233ae8e442SValentin Clement         ArrayAttr::get(range.getContext(), arrayRef));
20243ae8e442SValentin Clement 
20253ae8e442SValentin Clement     return success();
20263ae8e442SValentin Clement   }
20273ae8e442SValentin Clement };
20287b5132daSValentin Clement 
2029*5d27abe6SValentin Clement /// XArrayCoor is the address arithmetic on a dynamically shaped, sliced,
2030*5d27abe6SValentin Clement /// shifted etc. array.
2031*5d27abe6SValentin Clement /// (See the static restriction on coordinate_of.) array_coor determines the
2032*5d27abe6SValentin Clement /// coordinate (location) of a specific element.
2033*5d27abe6SValentin Clement struct XArrayCoorOpConversion
2034*5d27abe6SValentin Clement     : public FIROpAndTypeConversion<fir::cg::XArrayCoorOp> {
2035*5d27abe6SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
2036*5d27abe6SValentin Clement 
2037*5d27abe6SValentin Clement   mlir::LogicalResult
2038*5d27abe6SValentin Clement   doRewrite(fir::cg::XArrayCoorOp coor, mlir::Type ty, OpAdaptor adaptor,
2039*5d27abe6SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
2040*5d27abe6SValentin Clement     auto loc = coor.getLoc();
2041*5d27abe6SValentin Clement     mlir::ValueRange operands = adaptor.getOperands();
2042*5d27abe6SValentin Clement     unsigned rank = coor.getRank();
2043*5d27abe6SValentin Clement     assert(coor.indices().size() == rank);
2044*5d27abe6SValentin Clement     assert(coor.shape().empty() || coor.shape().size() == rank);
2045*5d27abe6SValentin Clement     assert(coor.shift().empty() || coor.shift().size() == rank);
2046*5d27abe6SValentin Clement     assert(coor.slice().empty() || coor.slice().size() == 3 * rank);
2047*5d27abe6SValentin Clement     mlir::Type idxTy = lowerTy().indexType();
2048*5d27abe6SValentin Clement     mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1);
2049*5d27abe6SValentin Clement     mlir::Value prevExt = one;
2050*5d27abe6SValentin Clement     mlir::Value zero = genConstantIndex(loc, idxTy, rewriter, 0);
2051*5d27abe6SValentin Clement     mlir::Value offset = zero;
2052*5d27abe6SValentin Clement     const bool isShifted = !coor.shift().empty();
2053*5d27abe6SValentin Clement     const bool isSliced = !coor.slice().empty();
2054*5d27abe6SValentin Clement     const bool baseIsBoxed = coor.memref().getType().isa<fir::BoxType>();
2055*5d27abe6SValentin Clement 
2056*5d27abe6SValentin Clement     auto indexOps = coor.indices().begin();
2057*5d27abe6SValentin Clement     auto shapeOps = coor.shape().begin();
2058*5d27abe6SValentin Clement     auto shiftOps = coor.shift().begin();
2059*5d27abe6SValentin Clement     auto sliceOps = coor.slice().begin();
2060*5d27abe6SValentin Clement     // For each dimension of the array, generate the offset calculation.
2061*5d27abe6SValentin Clement     for (unsigned i = 0; i < rank;
2062*5d27abe6SValentin Clement          ++i, ++indexOps, ++shapeOps, ++shiftOps, sliceOps += 3) {
2063*5d27abe6SValentin Clement       mlir::Value index =
2064*5d27abe6SValentin Clement           integerCast(loc, rewriter, idxTy, operands[coor.indicesOffset() + i]);
2065*5d27abe6SValentin Clement       mlir::Value lb = isShifted ? integerCast(loc, rewriter, idxTy,
2066*5d27abe6SValentin Clement                                                operands[coor.shiftOffset() + i])
2067*5d27abe6SValentin Clement                                  : one;
2068*5d27abe6SValentin Clement       mlir::Value step = one;
2069*5d27abe6SValentin Clement       bool normalSlice = isSliced;
2070*5d27abe6SValentin Clement       // Compute zero based index in dimension i of the element, applying
2071*5d27abe6SValentin Clement       // potential triplets and lower bounds.
2072*5d27abe6SValentin Clement       if (isSliced) {
2073*5d27abe6SValentin Clement         mlir::Value ub = *(sliceOps + 1);
2074*5d27abe6SValentin Clement         normalSlice = !mlir::isa_and_nonnull<fir::UndefOp>(ub.getDefiningOp());
2075*5d27abe6SValentin Clement         if (normalSlice)
2076*5d27abe6SValentin Clement           step = integerCast(loc, rewriter, idxTy, *(sliceOps + 2));
2077*5d27abe6SValentin Clement       }
2078*5d27abe6SValentin Clement       auto idx = rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, index, lb);
2079*5d27abe6SValentin Clement       mlir::Value diff =
2080*5d27abe6SValentin Clement           rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, idx, step);
2081*5d27abe6SValentin Clement       if (normalSlice) {
2082*5d27abe6SValentin Clement         mlir::Value sliceLb =
2083*5d27abe6SValentin Clement             integerCast(loc, rewriter, idxTy, operands[coor.sliceOffset() + i]);
2084*5d27abe6SValentin Clement         auto adj = rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, sliceLb, lb);
2085*5d27abe6SValentin Clement         diff = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, diff, adj);
2086*5d27abe6SValentin Clement       }
2087*5d27abe6SValentin Clement       // Update the offset given the stride and the zero based index `diff`
2088*5d27abe6SValentin Clement       // that was just computed.
2089*5d27abe6SValentin Clement       if (baseIsBoxed) {
2090*5d27abe6SValentin Clement         // Use stride in bytes from the descriptor.
2091*5d27abe6SValentin Clement         mlir::Value stride =
2092*5d27abe6SValentin Clement             loadStrideFromBox(loc, adaptor.getOperands()[0], i, rewriter);
2093*5d27abe6SValentin Clement         auto sc = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, stride);
2094*5d27abe6SValentin Clement         offset = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, offset);
2095*5d27abe6SValentin Clement       } else {
2096*5d27abe6SValentin Clement         // Use stride computed at last iteration.
2097*5d27abe6SValentin Clement         auto sc = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, prevExt);
2098*5d27abe6SValentin Clement         offset = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, offset);
2099*5d27abe6SValentin Clement         // Compute next stride assuming contiguity of the base array
2100*5d27abe6SValentin Clement         // (in element number).
2101*5d27abe6SValentin Clement         auto nextExt =
2102*5d27abe6SValentin Clement             integerCast(loc, rewriter, idxTy, operands[coor.shapeOffset() + i]);
2103*5d27abe6SValentin Clement         prevExt =
2104*5d27abe6SValentin Clement             rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, prevExt, nextExt);
2105*5d27abe6SValentin Clement       }
2106*5d27abe6SValentin Clement     }
2107*5d27abe6SValentin Clement 
2108*5d27abe6SValentin Clement     // Add computed offset to the base address.
2109*5d27abe6SValentin Clement     if (baseIsBoxed) {
2110*5d27abe6SValentin Clement       // Working with byte offsets. The base address is read from the fir.box.
2111*5d27abe6SValentin Clement       // and need to be casted to i8* to do the pointer arithmetic.
2112*5d27abe6SValentin Clement       mlir::Type baseTy =
2113*5d27abe6SValentin Clement           getBaseAddrTypeFromBox(adaptor.getOperands()[0].getType());
2114*5d27abe6SValentin Clement       mlir::Value base =
2115*5d27abe6SValentin Clement           loadBaseAddrFromBox(loc, baseTy, adaptor.getOperands()[0], rewriter);
2116*5d27abe6SValentin Clement       mlir::Type voidPtrTy = getVoidPtrType();
2117*5d27abe6SValentin Clement       base = rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, base);
2118*5d27abe6SValentin Clement       llvm::SmallVector<mlir::Value> args{base, offset};
2119*5d27abe6SValentin Clement       auto addr = rewriter.create<mlir::LLVM::GEPOp>(loc, voidPtrTy, args);
2120*5d27abe6SValentin Clement       if (coor.subcomponent().empty()) {
2121*5d27abe6SValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(coor, baseTy, addr);
2122*5d27abe6SValentin Clement         return success();
2123*5d27abe6SValentin Clement       }
2124*5d27abe6SValentin Clement       auto casted = rewriter.create<mlir::LLVM::BitcastOp>(loc, baseTy, addr);
2125*5d27abe6SValentin Clement       args.clear();
2126*5d27abe6SValentin Clement       args.push_back(casted);
2127*5d27abe6SValentin Clement       args.push_back(zero);
2128*5d27abe6SValentin Clement       if (!coor.lenParams().empty()) {
2129*5d27abe6SValentin Clement         // If type parameters are present, then we don't want to use a GEPOp
2130*5d27abe6SValentin Clement         // as below, as the LLVM struct type cannot be statically defined.
2131*5d27abe6SValentin Clement         TODO(loc, "derived type with type parameters");
2132*5d27abe6SValentin Clement       }
2133*5d27abe6SValentin Clement       // TODO: array offset subcomponents must be converted to LLVM's
2134*5d27abe6SValentin Clement       // row-major layout here.
2135*5d27abe6SValentin Clement       for (auto i = coor.subcomponentOffset(); i != coor.indicesOffset(); ++i)
2136*5d27abe6SValentin Clement         args.push_back(operands[i]);
2137*5d27abe6SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(coor, baseTy, args);
2138*5d27abe6SValentin Clement       return success();
2139*5d27abe6SValentin Clement     }
2140*5d27abe6SValentin Clement 
2141*5d27abe6SValentin Clement     // The array was not boxed, so it must be contiguous. offset is therefore an
2142*5d27abe6SValentin Clement     // element offset and the base type is kept in the GEP unless the element
2143*5d27abe6SValentin Clement     // type size is itself dynamic.
2144*5d27abe6SValentin Clement     mlir::Value base;
2145*5d27abe6SValentin Clement     if (coor.subcomponent().empty()) {
2146*5d27abe6SValentin Clement       // No subcomponent.
2147*5d27abe6SValentin Clement       if (!coor.lenParams().empty()) {
2148*5d27abe6SValentin Clement         // Type parameters. Adjust element size explicitly.
2149*5d27abe6SValentin Clement         auto eleTy = fir::dyn_cast_ptrEleTy(coor.getType());
2150*5d27abe6SValentin Clement         assert(eleTy && "result must be a reference-like type");
2151*5d27abe6SValentin Clement         if (fir::characterWithDynamicLen(eleTy)) {
2152*5d27abe6SValentin Clement           assert(coor.lenParams().size() == 1);
2153*5d27abe6SValentin Clement           auto bitsInChar = lowerTy().getKindMap().getCharacterBitsize(
2154*5d27abe6SValentin Clement               eleTy.cast<fir::CharacterType>().getFKind());
2155*5d27abe6SValentin Clement           auto scaling = genConstantIndex(loc, idxTy, rewriter, bitsInChar / 8);
2156*5d27abe6SValentin Clement           auto scaledBySize =
2157*5d27abe6SValentin Clement               rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, offset, scaling);
2158*5d27abe6SValentin Clement           auto length =
2159*5d27abe6SValentin Clement               integerCast(loc, rewriter, idxTy,
2160*5d27abe6SValentin Clement                           adaptor.getOperands()[coor.lenParamsOffset()]);
2161*5d27abe6SValentin Clement           offset = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, scaledBySize,
2162*5d27abe6SValentin Clement                                                       length);
2163*5d27abe6SValentin Clement         } else {
2164*5d27abe6SValentin Clement           TODO(loc, "compute size of derived type with type parameters");
2165*5d27abe6SValentin Clement         }
2166*5d27abe6SValentin Clement       }
2167*5d27abe6SValentin Clement       // Cast the base address to a pointer to T.
2168*5d27abe6SValentin Clement       base = rewriter.create<mlir::LLVM::BitcastOp>(loc, ty,
2169*5d27abe6SValentin Clement                                                     adaptor.getOperands()[0]);
2170*5d27abe6SValentin Clement     } else {
2171*5d27abe6SValentin Clement       // Operand #0 must have a pointer type. For subcomponent slicing, we
2172*5d27abe6SValentin Clement       // want to cast away the array type and have a plain struct type.
2173*5d27abe6SValentin Clement       mlir::Type ty0 = adaptor.getOperands()[0].getType();
2174*5d27abe6SValentin Clement       auto ptrTy = ty0.dyn_cast<mlir::LLVM::LLVMPointerType>();
2175*5d27abe6SValentin Clement       assert(ptrTy && "expected pointer type");
2176*5d27abe6SValentin Clement       mlir::Type eleTy = ptrTy.getElementType();
2177*5d27abe6SValentin Clement       while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>())
2178*5d27abe6SValentin Clement         eleTy = arrTy.getElementType();
2179*5d27abe6SValentin Clement       auto newTy = mlir::LLVM::LLVMPointerType::get(eleTy);
2180*5d27abe6SValentin Clement       base = rewriter.create<mlir::LLVM::BitcastOp>(loc, newTy,
2181*5d27abe6SValentin Clement                                                     adaptor.getOperands()[0]);
2182*5d27abe6SValentin Clement     }
2183*5d27abe6SValentin Clement     SmallVector<mlir::Value> args = {base, offset};
2184*5d27abe6SValentin Clement     for (auto i = coor.subcomponentOffset(); i != coor.indicesOffset(); ++i)
2185*5d27abe6SValentin Clement       args.push_back(operands[i]);
2186*5d27abe6SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(coor, ty, args);
2187*5d27abe6SValentin Clement     return success();
2188*5d27abe6SValentin Clement   }
2189*5d27abe6SValentin Clement };
2190*5d27abe6SValentin Clement 
21917b5132daSValentin Clement //
21927b5132daSValentin Clement // Primitive operations on Complex types
21937b5132daSValentin Clement //
21947b5132daSValentin Clement 
21957b5132daSValentin Clement /// Generate inline code for complex addition/subtraction
21967b5132daSValentin Clement template <typename LLVMOP, typename OPTY>
21977b5132daSValentin Clement mlir::LLVM::InsertValueOp complexSum(OPTY sumop, mlir::ValueRange opnds,
21987b5132daSValentin Clement                                      mlir::ConversionPatternRewriter &rewriter,
21997b5132daSValentin Clement                                      fir::LLVMTypeConverter &lowering) {
22007b5132daSValentin Clement   mlir::Value a = opnds[0];
22017b5132daSValentin Clement   mlir::Value b = opnds[1];
22027b5132daSValentin Clement   auto loc = sumop.getLoc();
22037b5132daSValentin Clement   auto ctx = sumop.getContext();
22047b5132daSValentin Clement   auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
22057b5132daSValentin Clement   auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
22067b5132daSValentin Clement   mlir::Type eleTy = lowering.convertType(getComplexEleTy(sumop.getType()));
22077b5132daSValentin Clement   mlir::Type ty = lowering.convertType(sumop.getType());
22087b5132daSValentin Clement   auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
22097b5132daSValentin Clement   auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
22107b5132daSValentin Clement   auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
22117b5132daSValentin Clement   auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
22127b5132daSValentin Clement   auto rx = rewriter.create<LLVMOP>(loc, eleTy, x0, x1);
22137b5132daSValentin Clement   auto ry = rewriter.create<LLVMOP>(loc, eleTy, y0, y1);
22147b5132daSValentin Clement   auto r0 = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
22157b5132daSValentin Clement   auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r0, rx, c0);
22167b5132daSValentin Clement   return rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ry, c1);
22177b5132daSValentin Clement }
22187b5132daSValentin Clement 
22197b5132daSValentin Clement struct AddcOpConversion : public FIROpConversion<fir::AddcOp> {
22207b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
22217b5132daSValentin Clement 
22227b5132daSValentin Clement   mlir::LogicalResult
22237b5132daSValentin Clement   matchAndRewrite(fir::AddcOp addc, OpAdaptor adaptor,
22247b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
22257b5132daSValentin Clement     // given: (x + iy) + (x' + iy')
22267b5132daSValentin Clement     // result: (x + x') + i(y + y')
22277b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FAddOp>(addc, adaptor.getOperands(),
22287b5132daSValentin Clement                                             rewriter, lowerTy());
22297b5132daSValentin Clement     rewriter.replaceOp(addc, r.getResult());
22307b5132daSValentin Clement     return success();
22317b5132daSValentin Clement   }
22327b5132daSValentin Clement };
22337b5132daSValentin Clement 
22347b5132daSValentin Clement struct SubcOpConversion : public FIROpConversion<fir::SubcOp> {
22357b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
22367b5132daSValentin Clement 
22377b5132daSValentin Clement   mlir::LogicalResult
22387b5132daSValentin Clement   matchAndRewrite(fir::SubcOp subc, OpAdaptor adaptor,
22397b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
22407b5132daSValentin Clement     // given: (x + iy) - (x' + iy')
22417b5132daSValentin Clement     // result: (x - x') + i(y - y')
22427b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FSubOp>(subc, adaptor.getOperands(),
22437b5132daSValentin Clement                                             rewriter, lowerTy());
22447b5132daSValentin Clement     rewriter.replaceOp(subc, r.getResult());
22457b5132daSValentin Clement     return success();
22467b5132daSValentin Clement   }
22477b5132daSValentin Clement };
22487b5132daSValentin Clement 
22497b5132daSValentin Clement /// Inlined complex multiply
22507b5132daSValentin Clement struct MulcOpConversion : public FIROpConversion<fir::MulcOp> {
22517b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
22527b5132daSValentin Clement 
22537b5132daSValentin Clement   mlir::LogicalResult
22547b5132daSValentin Clement   matchAndRewrite(fir::MulcOp mulc, OpAdaptor adaptor,
22557b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
22567b5132daSValentin Clement     // TODO: Can we use a call to __muldc3 ?
22577b5132daSValentin Clement     // given: (x + iy) * (x' + iy')
22587b5132daSValentin Clement     // result: (xx'-yy')+i(xy'+yx')
22597b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
22607b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
22617b5132daSValentin Clement     auto loc = mulc.getLoc();
22627b5132daSValentin Clement     auto *ctx = mulc.getContext();
22637b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
22647b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
22657b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(mulc.getType()));
22667b5132daSValentin Clement     mlir::Type ty = convertType(mulc.getType());
22677b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
22687b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
22697b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
22707b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
22717b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
22727b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
22737b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
22747b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xy, yx);
22757b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
22767b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, xx, yy);
22777b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
22787b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
22797b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
22807b5132daSValentin Clement     rewriter.replaceOp(mulc, r0.getResult());
22817b5132daSValentin Clement     return success();
22827b5132daSValentin Clement   }
22837b5132daSValentin Clement };
22847b5132daSValentin Clement 
22857b5132daSValentin Clement /// Inlined complex division
22867b5132daSValentin Clement struct DivcOpConversion : public FIROpConversion<fir::DivcOp> {
22877b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
22887b5132daSValentin Clement 
22897b5132daSValentin Clement   mlir::LogicalResult
22907b5132daSValentin Clement   matchAndRewrite(fir::DivcOp divc, OpAdaptor adaptor,
22917b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
22927b5132daSValentin Clement     // TODO: Can we use a call to __divdc3 instead?
22937b5132daSValentin Clement     // Just generate inline code for now.
22947b5132daSValentin Clement     // given: (x + iy) / (x' + iy')
22957b5132daSValentin Clement     // result: ((xx'+yy')/d) + i((yx'-xy')/d) where d = x'x' + y'y'
22967b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
22977b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
22987b5132daSValentin Clement     auto loc = divc.getLoc();
22997b5132daSValentin Clement     auto *ctx = divc.getContext();
23007b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
23017b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
23027b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(divc.getType()));
23037b5132daSValentin Clement     mlir::Type ty = convertType(divc.getType());
23047b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
23057b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
23067b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
23077b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
23087b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
23097b5132daSValentin Clement     auto x1x1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x1, x1);
23107b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
23117b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
23127b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
23137b5132daSValentin Clement     auto y1y1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y1, y1);
23147b5132daSValentin Clement     auto d = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, x1x1, y1y1);
23157b5132daSValentin Clement     auto rrn = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xx, yy);
23167b5132daSValentin Clement     auto rin = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, yx, xy);
23177b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rrn, d);
23187b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rin, d);
23197b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
23207b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
23217b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
23227b5132daSValentin Clement     rewriter.replaceOp(divc, r0.getResult());
23237b5132daSValentin Clement     return success();
23247b5132daSValentin Clement   }
23257b5132daSValentin Clement };
23267b5132daSValentin Clement 
23277b5132daSValentin Clement /// Inlined complex negation
23287b5132daSValentin Clement struct NegcOpConversion : public FIROpConversion<fir::NegcOp> {
23297b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
23307b5132daSValentin Clement 
23317b5132daSValentin Clement   mlir::LogicalResult
23327b5132daSValentin Clement   matchAndRewrite(fir::NegcOp neg, OpAdaptor adaptor,
23337b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
23347b5132daSValentin Clement     // given: -(x + iy)
23357b5132daSValentin Clement     // result: -x - iy
23367b5132daSValentin Clement     auto *ctxt = neg.getContext();
23377b5132daSValentin Clement     auto eleTy = convertType(getComplexEleTy(neg.getType()));
23387b5132daSValentin Clement     auto ty = convertType(neg.getType());
23397b5132daSValentin Clement     auto loc = neg.getLoc();
23407b5132daSValentin Clement     mlir::Value o0 = adaptor.getOperands()[0];
23417b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0));
23427b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1));
23437b5132daSValentin Clement     auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c0);
23447b5132daSValentin Clement     auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c1);
23457b5132daSValentin Clement     auto nrp = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, rp);
23467b5132daSValentin Clement     auto nip = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, ip);
23477b5132daSValentin Clement     auto r = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, o0, nrp, c0);
23487b5132daSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(neg, ty, r, nip, c1);
23497b5132daSValentin Clement     return success();
23507b5132daSValentin Clement   }
23517b5132daSValentin Clement };
23527b5132daSValentin Clement 
23531ed5a90fSValentin Clement /// Conversion pattern for operation that must be dead. The information in these
23541ed5a90fSValentin Clement /// operations is used by other operation. At this point they should not have
23551ed5a90fSValentin Clement /// anymore uses.
23561ed5a90fSValentin Clement /// These operations are normally dead after the pre-codegen pass.
23571ed5a90fSValentin Clement template <typename FromOp>
23581ed5a90fSValentin Clement struct MustBeDeadConversion : public FIROpConversion<FromOp> {
23591ed5a90fSValentin Clement   explicit MustBeDeadConversion(fir::LLVMTypeConverter &lowering)
23601ed5a90fSValentin Clement       : FIROpConversion<FromOp>(lowering) {}
23611ed5a90fSValentin Clement   using OpAdaptor = typename FromOp::Adaptor;
23621ed5a90fSValentin Clement 
23631ed5a90fSValentin Clement   mlir::LogicalResult
23641ed5a90fSValentin Clement   matchAndRewrite(FromOp op, OpAdaptor adaptor,
23651ed5a90fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const final {
23661ed5a90fSValentin Clement     if (!op->getUses().empty())
23671ed5a90fSValentin Clement       return rewriter.notifyMatchFailure(op, "op must be dead");
23681ed5a90fSValentin Clement     rewriter.eraseOp(op);
23691ed5a90fSValentin Clement     return success();
23701ed5a90fSValentin Clement   }
23711ed5a90fSValentin Clement };
23721ed5a90fSValentin Clement 
23731ed5a90fSValentin Clement struct ShapeOpConversion : public MustBeDeadConversion<fir::ShapeOp> {
23741ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
23751ed5a90fSValentin Clement };
23761ed5a90fSValentin Clement 
23771ed5a90fSValentin Clement struct ShapeShiftOpConversion : public MustBeDeadConversion<fir::ShapeShiftOp> {
23781ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
23791ed5a90fSValentin Clement };
23801ed5a90fSValentin Clement 
23811ed5a90fSValentin Clement struct ShiftOpConversion : public MustBeDeadConversion<fir::ShiftOp> {
23821ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
23831ed5a90fSValentin Clement };
23841ed5a90fSValentin Clement 
23851ed5a90fSValentin Clement struct SliceOpConversion : public MustBeDeadConversion<fir::SliceOp> {
23861ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
23871ed5a90fSValentin Clement };
23881ed5a90fSValentin Clement 
2389420ad7ceSAndrzej Warzynski /// `fir.is_present` -->
2390420ad7ceSAndrzej Warzynski /// ```
2391420ad7ceSAndrzej Warzynski ///  %0 = llvm.mlir.constant(0 : i64)
2392420ad7ceSAndrzej Warzynski ///  %1 = llvm.ptrtoint %0
2393420ad7ceSAndrzej Warzynski ///  %2 = llvm.icmp "ne" %1, %0 : i64
2394420ad7ceSAndrzej Warzynski /// ```
2395420ad7ceSAndrzej Warzynski struct IsPresentOpConversion : public FIROpConversion<fir::IsPresentOp> {
2396420ad7ceSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
2397420ad7ceSAndrzej Warzynski 
2398420ad7ceSAndrzej Warzynski   mlir::LogicalResult
2399420ad7ceSAndrzej Warzynski   matchAndRewrite(fir::IsPresentOp isPresent, OpAdaptor adaptor,
2400420ad7ceSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
2401420ad7ceSAndrzej Warzynski     mlir::Type idxTy = lowerTy().indexType();
2402420ad7ceSAndrzej Warzynski     mlir::Location loc = isPresent.getLoc();
2403420ad7ceSAndrzej Warzynski     auto ptr = adaptor.getOperands()[0];
2404420ad7ceSAndrzej Warzynski 
2405420ad7ceSAndrzej Warzynski     if (isPresent.val().getType().isa<fir::BoxCharType>()) {
2406420ad7ceSAndrzej Warzynski       auto structTy = ptr.getType().cast<mlir::LLVM::LLVMStructType>();
2407420ad7ceSAndrzej Warzynski       assert(!structTy.isOpaque() && !structTy.getBody().empty());
2408420ad7ceSAndrzej Warzynski 
2409420ad7ceSAndrzej Warzynski       mlir::Type ty = structTy.getBody()[0];
2410420ad7ceSAndrzej Warzynski       mlir::MLIRContext *ctx = isPresent.getContext();
2411420ad7ceSAndrzej Warzynski       auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
2412420ad7ceSAndrzej Warzynski       ptr = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, ptr, c0);
2413420ad7ceSAndrzej Warzynski     }
2414420ad7ceSAndrzej Warzynski     mlir::LLVM::ConstantOp c0 =
2415420ad7ceSAndrzej Warzynski         genConstantIndex(isPresent.getLoc(), idxTy, rewriter, 0);
2416420ad7ceSAndrzej Warzynski     auto addr = rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, ptr);
2417420ad7ceSAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
2418420ad7ceSAndrzej Warzynski         isPresent, mlir::LLVM::ICmpPredicate::ne, addr, c0);
2419420ad7ceSAndrzej Warzynski 
2420420ad7ceSAndrzej Warzynski     return success();
2421420ad7ceSAndrzej Warzynski   }
2422420ad7ceSAndrzej Warzynski };
24231e77b095SAndrzej Warzynski 
24241e77b095SAndrzej Warzynski /// Convert `!fir.emboxchar<!fir.char<KIND, ?>, #n>` into a sequence of
24251e77b095SAndrzej Warzynski /// instructions that generate `!llvm.struct<(ptr<ik>, i64)>`. The 1st element
24261e77b095SAndrzej Warzynski /// in this struct is a pointer. Its type is determined from `KIND`. The 2nd
24271e77b095SAndrzej Warzynski /// element is the length of the character buffer (`#n`).
24281e77b095SAndrzej Warzynski struct EmboxCharOpConversion : public FIROpConversion<fir::EmboxCharOp> {
24291e77b095SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
24301e77b095SAndrzej Warzynski 
24311e77b095SAndrzej Warzynski   mlir::LogicalResult
24321e77b095SAndrzej Warzynski   matchAndRewrite(fir::EmboxCharOp emboxChar, OpAdaptor adaptor,
24331e77b095SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
24341e77b095SAndrzej Warzynski     mlir::ValueRange operands = adaptor.getOperands();
24351e77b095SAndrzej Warzynski     MLIRContext *ctx = emboxChar.getContext();
24361e77b095SAndrzej Warzynski 
24371e77b095SAndrzej Warzynski     mlir::Value charBuffer = operands[0];
24381e77b095SAndrzej Warzynski     mlir::Value charBufferLen = operands[1];
24391e77b095SAndrzej Warzynski 
24401e77b095SAndrzej Warzynski     mlir::Location loc = emboxChar.getLoc();
24411e77b095SAndrzej Warzynski     mlir::Type llvmStructTy = convertType(emboxChar.getType());
24421e77b095SAndrzej Warzynski     auto llvmStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, llvmStructTy);
24431e77b095SAndrzej Warzynski 
24441e77b095SAndrzej Warzynski     mlir::Type lenTy =
24451e77b095SAndrzej Warzynski         llvmStructTy.cast<mlir::LLVM::LLVMStructType>().getBody()[1];
24461e77b095SAndrzej Warzynski     mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, charBufferLen);
24471e77b095SAndrzej Warzynski 
24481e77b095SAndrzej Warzynski     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
24491e77b095SAndrzej Warzynski     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
24501e77b095SAndrzej Warzynski     auto insertBufferOp = rewriter.create<mlir::LLVM::InsertValueOp>(
24511e77b095SAndrzej Warzynski         loc, llvmStructTy, llvmStruct, charBuffer, c0);
24521e77b095SAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
24531e77b095SAndrzej Warzynski         emboxChar, llvmStructTy, insertBufferOp, lenAfterCast, c1);
24541e77b095SAndrzej Warzynski 
24551e77b095SAndrzej Warzynski     return success();
24561e77b095SAndrzej Warzynski   }
24571e77b095SAndrzej Warzynski };
245814867ffcSAndrzej Warzynski 
245914867ffcSAndrzej Warzynski /// Construct an `llvm.extractvalue` instruction. It will return value at
246014867ffcSAndrzej Warzynski /// element \p x from  \p tuple.
246114867ffcSAndrzej Warzynski mlir::LLVM::ExtractValueOp
246214867ffcSAndrzej Warzynski genExtractValueWithIndex(mlir::Location loc, mlir::Value tuple, mlir::Type ty,
246314867ffcSAndrzej Warzynski                          mlir::ConversionPatternRewriter &rewriter,
246414867ffcSAndrzej Warzynski                          mlir::MLIRContext *ctx, int x) {
246514867ffcSAndrzej Warzynski   auto cx = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(x));
246614867ffcSAndrzej Warzynski   auto xty = ty.cast<mlir::LLVM::LLVMStructType>().getBody()[x];
246714867ffcSAndrzej Warzynski   return rewriter.create<mlir::LLVM::ExtractValueOp>(loc, xty, tuple, cx);
246814867ffcSAndrzej Warzynski }
246914867ffcSAndrzej Warzynski 
24706c3d7fd4SAndrzej Warzynski /// Convert `!fir.boxchar_len` to  `!llvm.extractvalue` for the 2nd part of the
24716c3d7fd4SAndrzej Warzynski /// boxchar.
24726c3d7fd4SAndrzej Warzynski struct BoxCharLenOpConversion : public FIROpConversion<fir::BoxCharLenOp> {
24736c3d7fd4SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
24746c3d7fd4SAndrzej Warzynski 
24756c3d7fd4SAndrzej Warzynski   mlir::LogicalResult
24766c3d7fd4SAndrzej Warzynski   matchAndRewrite(fir::BoxCharLenOp boxCharLen, OpAdaptor adaptor,
24776c3d7fd4SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
24786c3d7fd4SAndrzej Warzynski     mlir::Value boxChar = adaptor.getOperands()[0];
24796c3d7fd4SAndrzej Warzynski     mlir::Location loc = boxChar.getLoc();
24806c3d7fd4SAndrzej Warzynski     mlir::MLIRContext *ctx = boxChar.getContext();
24816c3d7fd4SAndrzej Warzynski     mlir::Type returnValTy = boxCharLen.getResult().getType();
24826c3d7fd4SAndrzej Warzynski 
24836c3d7fd4SAndrzej Warzynski     constexpr int boxcharLenIdx = 1;
24846c3d7fd4SAndrzej Warzynski     mlir::LLVM::ExtractValueOp len = genExtractValueWithIndex(
24856c3d7fd4SAndrzej Warzynski         loc, boxChar, boxChar.getType(), rewriter, ctx, boxcharLenIdx);
24866c3d7fd4SAndrzej Warzynski     mlir::Value lenAfterCast = integerCast(loc, rewriter, returnValTy, len);
24876c3d7fd4SAndrzej Warzynski     rewriter.replaceOp(boxCharLen, lenAfterCast);
24886c3d7fd4SAndrzej Warzynski 
24896c3d7fd4SAndrzej Warzynski     return success();
24906c3d7fd4SAndrzej Warzynski   }
24916c3d7fd4SAndrzej Warzynski };
24926c3d7fd4SAndrzej Warzynski 
249314867ffcSAndrzej Warzynski /// Convert `fir.unboxchar` into two `llvm.extractvalue` instructions. One for
249414867ffcSAndrzej Warzynski /// the character buffer and one for the buffer length.
249514867ffcSAndrzej Warzynski struct UnboxCharOpConversion : public FIROpConversion<fir::UnboxCharOp> {
249614867ffcSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
249714867ffcSAndrzej Warzynski 
249814867ffcSAndrzej Warzynski   mlir::LogicalResult
249914867ffcSAndrzej Warzynski   matchAndRewrite(fir::UnboxCharOp unboxchar, OpAdaptor adaptor,
250014867ffcSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
250114867ffcSAndrzej Warzynski     MLIRContext *ctx = unboxchar.getContext();
250214867ffcSAndrzej Warzynski 
250314867ffcSAndrzej Warzynski     mlir::Type lenTy = convertType(unboxchar.getType(1));
250414867ffcSAndrzej Warzynski     mlir::Value tuple = adaptor.getOperands()[0];
250514867ffcSAndrzej Warzynski     mlir::Type tupleTy = tuple.getType();
250614867ffcSAndrzej Warzynski 
250714867ffcSAndrzej Warzynski     mlir::Location loc = unboxchar.getLoc();
250814867ffcSAndrzej Warzynski     mlir::Value ptrToBuffer =
250914867ffcSAndrzej Warzynski         genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 0);
251014867ffcSAndrzej Warzynski 
251114867ffcSAndrzej Warzynski     mlir::LLVM::ExtractValueOp len =
251214867ffcSAndrzej Warzynski         genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 1);
251314867ffcSAndrzej Warzynski     mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, len);
251414867ffcSAndrzej Warzynski 
251514867ffcSAndrzej Warzynski     rewriter.replaceOp(unboxchar,
251614867ffcSAndrzej Warzynski                        ArrayRef<mlir::Value>{ptrToBuffer, lenAfterCast});
251714867ffcSAndrzej Warzynski     return success();
251814867ffcSAndrzej Warzynski   }
251914867ffcSAndrzej Warzynski };
252014867ffcSAndrzej Warzynski 
2521cc505c0bSKiran Chandramohan /// Lower `fir.unboxproc` operation. Unbox a procedure box value, yielding its
2522cc505c0bSKiran Chandramohan /// components.
2523cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
2524cc505c0bSKiran Chandramohan struct UnboxProcOpConversion : public FIROpConversion<fir::UnboxProcOp> {
2525cc505c0bSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2526cc505c0bSKiran Chandramohan 
2527cc505c0bSKiran Chandramohan   mlir::LogicalResult
2528cc505c0bSKiran Chandramohan   matchAndRewrite(fir::UnboxProcOp unboxproc, OpAdaptor adaptor,
2529cc505c0bSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
25307ce8c6fcSKiran Chandramohan     TODO(unboxproc.getLoc(), "fir.unboxproc codegen");
25317ce8c6fcSKiran Chandramohan     return failure();
2532cc505c0bSKiran Chandramohan   }
2533cc505c0bSKiran Chandramohan };
2534cc505c0bSKiran Chandramohan 
2535e6c66ef5SAndrzej Warzynski /// Convert `fir.field_index`. The conversion depends on whether the size of
2536e6c66ef5SAndrzej Warzynski /// the record is static or dynamic.
2537e6c66ef5SAndrzej Warzynski struct FieldIndexOpConversion : public FIROpConversion<fir::FieldIndexOp> {
2538e6c66ef5SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
2539e6c66ef5SAndrzej Warzynski 
2540e6c66ef5SAndrzej Warzynski   // NB: most field references should be resolved by this point
2541e6c66ef5SAndrzej Warzynski   mlir::LogicalResult
2542e6c66ef5SAndrzej Warzynski   matchAndRewrite(fir::FieldIndexOp field, OpAdaptor adaptor,
2543e6c66ef5SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
2544e6c66ef5SAndrzej Warzynski     auto recTy = field.on_type().cast<fir::RecordType>();
2545e6c66ef5SAndrzej Warzynski     unsigned index = recTy.getFieldIndex(field.field_id());
2546e6c66ef5SAndrzej Warzynski 
2547e6c66ef5SAndrzej Warzynski     if (!fir::hasDynamicSize(recTy)) {
2548e6c66ef5SAndrzej Warzynski       // Derived type has compile-time constant layout. Return index of the
2549e6c66ef5SAndrzej Warzynski       // component type in the parent type (to be used in GEP).
2550e6c66ef5SAndrzej Warzynski       rewriter.replaceOp(field, mlir::ValueRange{genConstantOffset(
2551e6c66ef5SAndrzej Warzynski                                     field.getLoc(), rewriter, index)});
2552e6c66ef5SAndrzej Warzynski       return success();
2553e6c66ef5SAndrzej Warzynski     }
2554e6c66ef5SAndrzej Warzynski 
2555e6c66ef5SAndrzej Warzynski     // Derived type has compile-time constant layout. Call the compiler
2556e6c66ef5SAndrzej Warzynski     // generated function to determine the byte offset of the field at runtime.
2557e6c66ef5SAndrzej Warzynski     // This returns a non-constant.
2558e6c66ef5SAndrzej Warzynski     FlatSymbolRefAttr symAttr = mlir::SymbolRefAttr::get(
2559e6c66ef5SAndrzej Warzynski         field.getContext(), getOffsetMethodName(recTy, field.field_id()));
2560e6c66ef5SAndrzej Warzynski     NamedAttribute callAttr = rewriter.getNamedAttr("callee", symAttr);
2561e6c66ef5SAndrzej Warzynski     NamedAttribute fieldAttr = rewriter.getNamedAttr(
2562e6c66ef5SAndrzej Warzynski         "field", mlir::IntegerAttr::get(lowerTy().indexType(), index));
2563e6c66ef5SAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
2564e6c66ef5SAndrzej Warzynski         field, lowerTy().offsetType(), adaptor.getOperands(),
2565e6c66ef5SAndrzej Warzynski         llvm::ArrayRef<mlir::NamedAttribute>{callAttr, fieldAttr});
2566e6c66ef5SAndrzej Warzynski     return success();
2567e6c66ef5SAndrzej Warzynski   }
2568e6c66ef5SAndrzej Warzynski 
2569e6c66ef5SAndrzej Warzynski   // Re-Construct the name of the compiler generated method that calculates the
2570e6c66ef5SAndrzej Warzynski   // offset
2571e6c66ef5SAndrzej Warzynski   inline static std::string getOffsetMethodName(fir::RecordType recTy,
2572e6c66ef5SAndrzej Warzynski                                                 llvm::StringRef field) {
2573e6c66ef5SAndrzej Warzynski     return recTy.getName().str() + "P." + field.str() + ".offset";
2574e6c66ef5SAndrzej Warzynski   }
2575e6c66ef5SAndrzej Warzynski };
2576e6c66ef5SAndrzej Warzynski 
2577044d5b5dSValentin Clement } // namespace
2578044d5b5dSValentin Clement 
2579044d5b5dSValentin Clement namespace {
2580044d5b5dSValentin Clement /// Convert FIR dialect to LLVM dialect
2581044d5b5dSValentin Clement ///
2582044d5b5dSValentin Clement /// This pass lowers all FIR dialect operations to LLVM IR dialect. An
2583044d5b5dSValentin Clement /// MLIR pass is used to lower residual Std dialect to LLVM IR dialect.
2584044d5b5dSValentin Clement ///
2585044d5b5dSValentin Clement /// This pass is not complete yet. We are upstreaming it in small patches.
2586044d5b5dSValentin Clement class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> {
2587044d5b5dSValentin Clement public:
2588044d5b5dSValentin Clement   mlir::ModuleOp getModule() { return getOperation(); }
2589044d5b5dSValentin Clement 
2590044d5b5dSValentin Clement   void runOnOperation() override final {
25917b5132daSValentin Clement     auto mod = getModule();
25927b5132daSValentin Clement     if (!forcedTargetTriple.empty()) {
25937b5132daSValentin Clement       fir::setTargetTriple(mod, forcedTargetTriple);
25947b5132daSValentin Clement     }
25957b5132daSValentin Clement 
2596044d5b5dSValentin Clement     auto *context = getModule().getContext();
2597044d5b5dSValentin Clement     fir::LLVMTypeConverter typeConverter{getModule()};
2598044d5b5dSValentin Clement     mlir::OwningRewritePatternList pattern(context);
2599df3b9810SValentin Clement     pattern.insert<
2600420ad7ceSAndrzej Warzynski         AbsentOpConversion, AddcOpConversion, AddrOfOpConversion,
26011a2ec667SValentin Clement         AllocaOpConversion, BoxAddrOpConversion, BoxCharLenOpConversion,
26021a2ec667SValentin Clement         BoxDimsOpConversion, BoxEleSizeOpConversion, BoxIsAllocOpConversion,
2603cc505c0bSKiran Chandramohan         BoxIsArrayOpConversion, BoxIsPtrOpConversion, BoxProcHostOpConversion,
2604cc505c0bSKiran Chandramohan         BoxRankOpConversion, BoxTypeDescOpConversion, CallOpConversion,
2605cc505c0bSKiran Chandramohan         CmpcOpConversion, ConstcOpConversion, ConvertOpConversion,
2606cc505c0bSKiran Chandramohan         DispatchOpConversion, DispatchTableOpConversion, DTEntryOpConversion,
2607cc505c0bSKiran Chandramohan         DivcOpConversion, EmboxOpConversion, EmboxCharOpConversion,
2608e6c66ef5SAndrzej Warzynski         EmboxProcOpConversion, ExtractValueOpConversion, FieldIndexOpConversion,
2609e6c66ef5SAndrzej Warzynski         FirEndOpConversion, HasValueOpConversion, GenTypeDescOpConversion,
2610e6c66ef5SAndrzej Warzynski         GlobalLenOpConversion, GlobalOpConversion, InsertOnRangeOpConversion,
2611cdc476abSDiana Picus         InsertValueOpConversion, IsPresentOpConversion,
2612cdc476abSDiana Picus         LenParamIndexOpConversion, LoadOpConversion, NegcOpConversion,
2613cdc476abSDiana Picus         NoReassocOpConversion, MulcOpConversion, SelectCaseOpConversion,
2614cdc476abSDiana Picus         SelectOpConversion, SelectRankOpConversion, SelectTypeOpConversion,
2615cdc476abSDiana Picus         ShapeOpConversion, ShapeShiftOpConversion, ShiftOpConversion,
2616cdc476abSDiana Picus         SliceOpConversion, StoreOpConversion, StringLitOpConversion,
2617cdc476abSDiana Picus         SubcOpConversion, UnboxCharOpConversion, UnboxProcOpConversion,
2618*5d27abe6SValentin Clement         UndefOpConversion, UnreachableOpConversion, XArrayCoorOpConversion,
2619*5d27abe6SValentin Clement         XEmboxOpConversion, ZeroOpConversion>(typeConverter);
2620044d5b5dSValentin Clement     mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern);
2621044d5b5dSValentin Clement     mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter,
2622044d5b5dSValentin Clement                                                             pattern);
2623044d5b5dSValentin Clement     mlir::ConversionTarget target{*context};
2624044d5b5dSValentin Clement     target.addLegalDialect<mlir::LLVM::LLVMDialect>();
2625044d5b5dSValentin Clement 
2626044d5b5dSValentin Clement     // required NOPs for applying a full conversion
2627044d5b5dSValentin Clement     target.addLegalOp<mlir::ModuleOp>();
2628044d5b5dSValentin Clement 
2629044d5b5dSValentin Clement     // apply the patterns
2630044d5b5dSValentin Clement     if (mlir::failed(mlir::applyFullConversion(getModule(), target,
2631044d5b5dSValentin Clement                                                std::move(pattern)))) {
2632044d5b5dSValentin Clement       signalPassFailure();
2633044d5b5dSValentin Clement     }
2634044d5b5dSValentin Clement   }
2635044d5b5dSValentin Clement };
2636044d5b5dSValentin Clement } // namespace
2637044d5b5dSValentin Clement 
2638044d5b5dSValentin Clement std::unique_ptr<mlir::Pass> fir::createFIRToLLVMPass() {
2639044d5b5dSValentin Clement   return std::make_unique<FIRToLLVMLowering>();
2640044d5b5dSValentin Clement }
2641