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 
41fa517555SKiran Chandramohan static mlir::Type getVoidPtrType(mlir::MLIRContext *context) {
42fa517555SKiran Chandramohan   return mlir::LLVM::LLVMPointerType::get(mlir::IntegerType::get(context, 8));
43fa517555SKiran Chandramohan }
44fa517555SKiran Chandramohan 
451e6d9c06SDiana Picus static mlir::LLVM::ConstantOp
461e6d9c06SDiana Picus genConstantIndex(mlir::Location loc, mlir::Type ity,
471e6d9c06SDiana Picus                  mlir::ConversionPatternRewriter &rewriter,
481e6d9c06SDiana Picus                  std::int64_t offset) {
491e6d9c06SDiana Picus   auto cattr = rewriter.getI64IntegerAttr(offset);
501e6d9c06SDiana Picus   return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr);
511e6d9c06SDiana Picus }
521e6d9c06SDiana Picus 
5339f4ef81SValentin Clement static Block *createBlock(mlir::ConversionPatternRewriter &rewriter,
5439f4ef81SValentin Clement                           mlir::Block *insertBefore) {
5539f4ef81SValentin Clement   assert(insertBefore && "expected valid insertion block");
5639f4ef81SValentin Clement   return rewriter.createBlock(insertBefore->getParent(),
5739f4ef81SValentin Clement                               mlir::Region::iterator(insertBefore));
5839f4ef81SValentin Clement }
5939f4ef81SValentin Clement 
60044d5b5dSValentin Clement namespace {
61044d5b5dSValentin Clement /// FIR conversion pattern template
62044d5b5dSValentin Clement template <typename FromOp>
63044d5b5dSValentin Clement class FIROpConversion : public mlir::ConvertOpToLLVMPattern<FromOp> {
64044d5b5dSValentin Clement public:
65044d5b5dSValentin Clement   explicit FIROpConversion(fir::LLVMTypeConverter &lowering)
66044d5b5dSValentin Clement       : mlir::ConvertOpToLLVMPattern<FromOp>(lowering) {}
67044d5b5dSValentin Clement 
68044d5b5dSValentin Clement protected:
69044d5b5dSValentin Clement   mlir::Type convertType(mlir::Type ty) const {
70044d5b5dSValentin Clement     return lowerTy().convertType(ty);
71044d5b5dSValentin Clement   }
72*c2acd453SAlexisPerry   mlir::Type voidPtrTy() const { return getVoidPtrType(); }
73044d5b5dSValentin Clement 
745d27abe6SValentin Clement   mlir::Type getVoidPtrType() const {
755d27abe6SValentin Clement     return mlir::LLVM::LLVMPointerType::get(
765d27abe6SValentin Clement         mlir::IntegerType::get(&lowerTy().getContext(), 8));
775d27abe6SValentin Clement   }
785d27abe6SValentin Clement 
79df3b9810SValentin Clement   mlir::LLVM::ConstantOp
80af6ee580SValentin Clement   genI32Constant(mlir::Location loc, mlir::ConversionPatternRewriter &rewriter,
81af6ee580SValentin Clement                  int value) const {
82af6ee580SValentin Clement     mlir::Type i32Ty = rewriter.getI32Type();
83af6ee580SValentin Clement     mlir::IntegerAttr attr = rewriter.getI32IntegerAttr(value);
84af6ee580SValentin Clement     return rewriter.create<mlir::LLVM::ConstantOp>(loc, i32Ty, attr);
85af6ee580SValentin Clement   }
86af6ee580SValentin Clement 
87af6ee580SValentin Clement   mlir::LLVM::ConstantOp
88df3b9810SValentin Clement   genConstantOffset(mlir::Location loc,
89df3b9810SValentin Clement                     mlir::ConversionPatternRewriter &rewriter,
90df3b9810SValentin Clement                     int offset) const {
91af6ee580SValentin Clement     mlir::Type ity = lowerTy().offsetType();
92af6ee580SValentin Clement     mlir::IntegerAttr cattr = rewriter.getI32IntegerAttr(offset);
93df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr);
94df3b9810SValentin Clement   }
95df3b9810SValentin Clement 
96b6e44ecdSValentin Clement   /// Construct code sequence to extract the specifc value from a `fir.box`.
97b6e44ecdSValentin Clement   mlir::Value getValueFromBox(mlir::Location loc, mlir::Value box,
98df3b9810SValentin Clement                               mlir::Type resultTy,
99b6e44ecdSValentin Clement                               mlir::ConversionPatternRewriter &rewriter,
100b6e44ecdSValentin Clement                               unsigned boxValue) const {
101df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
102b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp cValuePos =
103b6e44ecdSValentin Clement         genConstantOffset(loc, rewriter, boxValue);
104df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(resultTy);
105df3b9810SValentin Clement     auto p = rewriter.create<mlir::LLVM::GEPOp>(
106b6e44ecdSValentin Clement         loc, pty, mlir::ValueRange{box, c0, cValuePos});
107df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, resultTy, p);
108df3b9810SValentin Clement   }
109df3b9810SValentin Clement 
110df3b9810SValentin Clement   /// Method to construct code sequence to get the triple for dimension `dim`
111df3b9810SValentin Clement   /// from a box.
112df3b9810SValentin Clement   SmallVector<mlir::Value, 3>
113df3b9810SValentin Clement   getDimsFromBox(mlir::Location loc, ArrayRef<mlir::Type> retTys,
114df3b9810SValentin Clement                  mlir::Value box, mlir::Value dim,
115df3b9810SValentin Clement                  mlir::ConversionPatternRewriter &rewriter) const {
116df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
117df3b9810SValentin Clement     mlir::LLVM::ConstantOp cDims =
118df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kDimsPosInBox);
119df3b9810SValentin Clement     mlir::LLVM::LoadOp l0 =
120df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 0, retTys[0], rewriter);
121df3b9810SValentin Clement     mlir::LLVM::LoadOp l1 =
122df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 1, retTys[1], rewriter);
123df3b9810SValentin Clement     mlir::LLVM::LoadOp l2 =
124df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 2, retTys[2], rewriter);
125df3b9810SValentin Clement     return {l0.getResult(), l1.getResult(), l2.getResult()};
126df3b9810SValentin Clement   }
127df3b9810SValentin Clement 
128df3b9810SValentin Clement   mlir::LLVM::LoadOp
129df3b9810SValentin Clement   loadFromOffset(mlir::Location loc, mlir::Value a, mlir::LLVM::ConstantOp c0,
130df3b9810SValentin Clement                  mlir::LLVM::ConstantOp cDims, mlir::Value dim, int off,
131df3b9810SValentin Clement                  mlir::Type ty,
132df3b9810SValentin Clement                  mlir::ConversionPatternRewriter &rewriter) const {
133df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
134df3b9810SValentin Clement     mlir::LLVM::ConstantOp c = genConstantOffset(loc, rewriter, off);
135df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, a, c0, cDims, dim, c);
136df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
137df3b9810SValentin Clement   }
138df3b9810SValentin Clement 
1395d27abe6SValentin Clement   mlir::Value
1405d27abe6SValentin Clement   loadStrideFromBox(mlir::Location loc, mlir::Value box, unsigned dim,
1415d27abe6SValentin Clement                     mlir::ConversionPatternRewriter &rewriter) const {
1425d27abe6SValentin Clement     auto idxTy = lowerTy().indexType();
1435d27abe6SValentin Clement     auto c0 = genConstantOffset(loc, rewriter, 0);
1445d27abe6SValentin Clement     auto cDims = genConstantOffset(loc, rewriter, kDimsPosInBox);
1455d27abe6SValentin Clement     auto dimValue = genConstantIndex(loc, idxTy, rewriter, dim);
1465d27abe6SValentin Clement     return loadFromOffset(loc, box, c0, cDims, dimValue, kDimStridePos, idxTy,
1475d27abe6SValentin Clement                           rewriter);
1485d27abe6SValentin Clement   }
1495d27abe6SValentin Clement 
150df3b9810SValentin Clement   /// Read base address from a fir.box. Returned address has type ty.
151df3b9810SValentin Clement   mlir::Value
152df3b9810SValentin Clement   loadBaseAddrFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box,
153df3b9810SValentin Clement                       mlir::ConversionPatternRewriter &rewriter) const {
154df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
155df3b9810SValentin Clement     mlir::LLVM::ConstantOp cAddr =
156df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kAddrPosInBox);
157df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
158df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cAddr);
159df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
160df3b9810SValentin Clement   }
161df3b9810SValentin Clement 
162df3b9810SValentin Clement   mlir::Value
163df3b9810SValentin Clement   loadElementSizeFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box,
164df3b9810SValentin Clement                          mlir::ConversionPatternRewriter &rewriter) const {
165df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
166df3b9810SValentin Clement     mlir::LLVM::ConstantOp cElemLen =
167df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kElemLenPosInBox);
168df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
169df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cElemLen);
170df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
171df3b9810SValentin Clement   }
172df3b9810SValentin Clement 
173b6e44ecdSValentin Clement   // Load the attribute from the \p box and perform a check against \p maskValue
174b6e44ecdSValentin Clement   // The final comparison is implemented as `(attribute & maskValue) != 0`.
175b6e44ecdSValentin Clement   mlir::Value genBoxAttributeCheck(mlir::Location loc, mlir::Value box,
176b6e44ecdSValentin Clement                                    mlir::ConversionPatternRewriter &rewriter,
177b6e44ecdSValentin Clement                                    unsigned maskValue) const {
178b6e44ecdSValentin Clement     mlir::Type attrTy = rewriter.getI32Type();
179b6e44ecdSValentin Clement     mlir::Value attribute =
180b6e44ecdSValentin Clement         getValueFromBox(loc, box, attrTy, rewriter, kAttributePosInBox);
181b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp attrMask =
182b6e44ecdSValentin Clement         genConstantOffset(loc, rewriter, maskValue);
183b6e44ecdSValentin Clement     auto maskRes =
184b6e44ecdSValentin Clement         rewriter.create<mlir::LLVM::AndOp>(loc, attrTy, attribute, attrMask);
185b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
186b6e44ecdSValentin Clement     return rewriter.create<mlir::LLVM::ICmpOp>(
187b6e44ecdSValentin Clement         loc, mlir::LLVM::ICmpPredicate::ne, maskRes, c0);
188b6e44ecdSValentin Clement   }
189b6e44ecdSValentin Clement 
190af6ee580SValentin Clement   // Get the element type given an LLVM type that is of the form
191af6ee580SValentin Clement   // [llvm.ptr](array|struct|vector)+ and the provided indexes.
192af6ee580SValentin Clement   static mlir::Type getBoxEleTy(mlir::Type type,
193af6ee580SValentin Clement                                 llvm::ArrayRef<unsigned> indexes) {
194af6ee580SValentin Clement     if (auto t = type.dyn_cast<mlir::LLVM::LLVMPointerType>())
195af6ee580SValentin Clement       type = t.getElementType();
196af6ee580SValentin Clement     for (auto i : indexes) {
197af6ee580SValentin Clement       if (auto t = type.dyn_cast<mlir::LLVM::LLVMStructType>()) {
198af6ee580SValentin Clement         assert(!t.isOpaque() && i < t.getBody().size());
199af6ee580SValentin Clement         type = t.getBody()[i];
200af6ee580SValentin Clement       } else if (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
201af6ee580SValentin Clement         type = t.getElementType();
202af6ee580SValentin Clement       } else if (auto t = type.dyn_cast<mlir::VectorType>()) {
203af6ee580SValentin Clement         type = t.getElementType();
204af6ee580SValentin Clement       } else {
205af6ee580SValentin Clement         fir::emitFatalError(mlir::UnknownLoc::get(type.getContext()),
206af6ee580SValentin Clement                             "request for invalid box element type");
207af6ee580SValentin Clement       }
208af6ee580SValentin Clement     }
209af6ee580SValentin Clement     return type;
210af6ee580SValentin Clement   }
211af6ee580SValentin Clement 
2125d27abe6SValentin Clement   // Return LLVM type of the base address given the LLVM type
2135d27abe6SValentin Clement   // of the related descriptor (lowered fir.box type).
2145d27abe6SValentin Clement   static mlir::Type getBaseAddrTypeFromBox(mlir::Type type) {
2155d27abe6SValentin Clement     return getBoxEleTy(type, {kAddrPosInBox});
2165d27abe6SValentin Clement   }
2175d27abe6SValentin Clement 
218df3b9810SValentin Clement   template <typename... ARGS>
219df3b9810SValentin Clement   mlir::LLVM::GEPOp genGEP(mlir::Location loc, mlir::Type ty,
220df3b9810SValentin Clement                            mlir::ConversionPatternRewriter &rewriter,
221df3b9810SValentin Clement                            mlir::Value base, ARGS... args) const {
222df3b9810SValentin Clement     SmallVector<mlir::Value> cv{args...};
223df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::GEPOp>(loc, ty, base, cv);
224df3b9810SValentin Clement   }
225df3b9810SValentin Clement 
2261e6d9c06SDiana Picus   /// Perform an extension or truncation as needed on an integer value. Lowering
2271e6d9c06SDiana Picus   /// to the specific target may involve some sign-extending or truncation of
2281e6d9c06SDiana Picus   /// values, particularly to fit them from abstract box types to the
2291e6d9c06SDiana Picus   /// appropriate reified structures.
2301e6d9c06SDiana Picus   mlir::Value integerCast(mlir::Location loc,
2311e6d9c06SDiana Picus                           mlir::ConversionPatternRewriter &rewriter,
2321e6d9c06SDiana Picus                           mlir::Type ty, mlir::Value val) const {
2331e6d9c06SDiana Picus     auto valTy = val.getType();
2341e6d9c06SDiana Picus     // If the value was not yet lowered, lower its type so that it can
2351e6d9c06SDiana Picus     // be used in getPrimitiveTypeSizeInBits.
2361e6d9c06SDiana Picus     if (!valTy.isa<mlir::IntegerType>())
2371e6d9c06SDiana Picus       valTy = convertType(valTy);
2381e6d9c06SDiana Picus     auto toSize = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
2391e6d9c06SDiana Picus     auto fromSize = mlir::LLVM::getPrimitiveTypeSizeInBits(valTy);
2401e6d9c06SDiana Picus     if (toSize < fromSize)
2411e6d9c06SDiana Picus       return rewriter.create<mlir::LLVM::TruncOp>(loc, ty, val);
2421e6d9c06SDiana Picus     if (toSize > fromSize)
2431e6d9c06SDiana Picus       return rewriter.create<mlir::LLVM::SExtOp>(loc, ty, val);
2441e6d9c06SDiana Picus     return val;
2451e6d9c06SDiana Picus   }
2461e6d9c06SDiana Picus 
247044d5b5dSValentin Clement   fir::LLVMTypeConverter &lowerTy() const {
248044d5b5dSValentin Clement     return *static_cast<fir::LLVMTypeConverter *>(this->getTypeConverter());
249044d5b5dSValentin Clement   }
250044d5b5dSValentin Clement };
251044d5b5dSValentin Clement 
2523ae8e442SValentin Clement /// FIR conversion pattern template
2533ae8e442SValentin Clement template <typename FromOp>
2543ae8e442SValentin Clement class FIROpAndTypeConversion : public FIROpConversion<FromOp> {
2553ae8e442SValentin Clement public:
2563ae8e442SValentin Clement   using FIROpConversion<FromOp>::FIROpConversion;
2573ae8e442SValentin Clement   using OpAdaptor = typename FromOp::Adaptor;
2583ae8e442SValentin Clement 
2593ae8e442SValentin Clement   mlir::LogicalResult
2603ae8e442SValentin Clement   matchAndRewrite(FromOp op, OpAdaptor adaptor,
2613ae8e442SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const final {
2623ae8e442SValentin Clement     mlir::Type ty = this->convertType(op.getType());
2633ae8e442SValentin Clement     return doRewrite(op, ty, adaptor, rewriter);
2643ae8e442SValentin Clement   }
2653ae8e442SValentin Clement 
2663ae8e442SValentin Clement   virtual mlir::LogicalResult
2673ae8e442SValentin Clement   doRewrite(FromOp addr, mlir::Type ty, OpAdaptor adaptor,
2683ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const = 0;
2693ae8e442SValentin Clement };
2703ae8e442SValentin Clement 
271420ad7ceSAndrzej Warzynski /// Create value signaling an absent optional argument in a call, e.g.
272420ad7ceSAndrzej Warzynski /// `fir.absent !fir.ref<i64>` -->  `llvm.mlir.null : !llvm.ptr<i64>`
273420ad7ceSAndrzej Warzynski struct AbsentOpConversion : public FIROpConversion<fir::AbsentOp> {
274420ad7ceSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
275420ad7ceSAndrzej Warzynski 
276420ad7ceSAndrzej Warzynski   mlir::LogicalResult
277420ad7ceSAndrzej Warzynski   matchAndRewrite(fir::AbsentOp absent, OpAdaptor,
278420ad7ceSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
279420ad7ceSAndrzej Warzynski     mlir::Type ty = convertType(absent.getType());
280420ad7ceSAndrzej Warzynski     mlir::Location loc = absent.getLoc();
281420ad7ceSAndrzej Warzynski 
282420ad7ceSAndrzej Warzynski     if (absent.getType().isa<fir::BoxCharType>()) {
283420ad7ceSAndrzej Warzynski       auto structTy = ty.cast<mlir::LLVM::LLVMStructType>();
284420ad7ceSAndrzej Warzynski       assert(!structTy.isOpaque() && !structTy.getBody().empty());
285420ad7ceSAndrzej Warzynski       auto undefStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
286420ad7ceSAndrzej Warzynski       auto nullField =
287420ad7ceSAndrzej Warzynski           rewriter.create<mlir::LLVM::NullOp>(loc, structTy.getBody()[0]);
288420ad7ceSAndrzej Warzynski       mlir::MLIRContext *ctx = absent.getContext();
289420ad7ceSAndrzej Warzynski       auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
290420ad7ceSAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
291420ad7ceSAndrzej Warzynski           absent, ty, undefStruct, nullField, c0);
292420ad7ceSAndrzej Warzynski     } else {
293420ad7ceSAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(absent, ty);
294420ad7ceSAndrzej Warzynski     }
295420ad7ceSAndrzej Warzynski     return success();
296420ad7ceSAndrzej Warzynski   }
297420ad7ceSAndrzej Warzynski };
298420ad7ceSAndrzej Warzynski 
2990c4a7a52SValentin Clement // Lower `fir.address_of` operation to `llvm.address_of` operation.
300044d5b5dSValentin Clement struct AddrOfOpConversion : public FIROpConversion<fir::AddrOfOp> {
301044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
302044d5b5dSValentin Clement 
303044d5b5dSValentin Clement   mlir::LogicalResult
304044d5b5dSValentin Clement   matchAndRewrite(fir::AddrOfOp addr, OpAdaptor adaptor,
305044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
306044d5b5dSValentin Clement     auto ty = convertType(addr.getType());
307044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::AddressOfOp>(
308044d5b5dSValentin Clement         addr, ty, addr.symbol().getRootReference().getValue());
309044d5b5dSValentin Clement     return success();
310044d5b5dSValentin Clement   }
311044d5b5dSValentin Clement };
3121e6d9c06SDiana Picus } // namespace
3131e6d9c06SDiana Picus 
3141e6d9c06SDiana Picus /// Lookup the function to compute the memory size of this parametric derived
3151e6d9c06SDiana Picus /// type. The size of the object may depend on the LEN type parameters of the
3161e6d9c06SDiana Picus /// derived type.
3171e6d9c06SDiana Picus static mlir::LLVM::LLVMFuncOp
3181e6d9c06SDiana Picus getDependentTypeMemSizeFn(fir::RecordType recTy, fir::AllocaOp op,
3191e6d9c06SDiana Picus                           mlir::ConversionPatternRewriter &rewriter) {
3201e6d9c06SDiana Picus   auto module = op->getParentOfType<mlir::ModuleOp>();
3211e6d9c06SDiana Picus   std::string name = recTy.getName().str() + "P.mem.size";
3221e6d9c06SDiana Picus   return module.lookupSymbol<mlir::LLVM::LLVMFuncOp>(name);
3231e6d9c06SDiana Picus }
3241e6d9c06SDiana Picus 
3251e6d9c06SDiana Picus namespace {
3261e6d9c06SDiana Picus /// convert to LLVM IR dialect `alloca`
3271e6d9c06SDiana Picus struct AllocaOpConversion : public FIROpConversion<fir::AllocaOp> {
3281e6d9c06SDiana Picus   using FIROpConversion::FIROpConversion;
3291e6d9c06SDiana Picus 
3301e6d9c06SDiana Picus   mlir::LogicalResult
3311e6d9c06SDiana Picus   matchAndRewrite(fir::AllocaOp alloc, OpAdaptor adaptor,
3321e6d9c06SDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
3331e6d9c06SDiana Picus     mlir::ValueRange operands = adaptor.getOperands();
3341e6d9c06SDiana Picus     auto loc = alloc.getLoc();
3351e6d9c06SDiana Picus     mlir::Type ity = lowerTy().indexType();
3361e6d9c06SDiana Picus     unsigned i = 0;
3371e6d9c06SDiana Picus     mlir::Value size = genConstantIndex(loc, ity, rewriter, 1).getResult();
3381e6d9c06SDiana Picus     mlir::Type ty = convertType(alloc.getType());
3391e6d9c06SDiana Picus     mlir::Type resultTy = ty;
3401e6d9c06SDiana Picus     if (alloc.hasLenParams()) {
3411e6d9c06SDiana Picus       unsigned end = alloc.numLenParams();
3421e6d9c06SDiana Picus       llvm::SmallVector<mlir::Value> lenParams;
3431e6d9c06SDiana Picus       for (; i < end; ++i)
3441e6d9c06SDiana Picus         lenParams.push_back(operands[i]);
3451e6d9c06SDiana Picus       mlir::Type scalarType = fir::unwrapSequenceType(alloc.getInType());
3461e6d9c06SDiana Picus       if (auto chrTy = scalarType.dyn_cast<fir::CharacterType>()) {
3471e6d9c06SDiana Picus         fir::CharacterType rawCharTy = fir::CharacterType::getUnknownLen(
3481e6d9c06SDiana Picus             chrTy.getContext(), chrTy.getFKind());
3491e6d9c06SDiana Picus         ty = mlir::LLVM::LLVMPointerType::get(convertType(rawCharTy));
3501e6d9c06SDiana Picus         assert(end == 1);
3511e6d9c06SDiana Picus         size = integerCast(loc, rewriter, ity, lenParams[0]);
3521e6d9c06SDiana Picus       } else if (auto recTy = scalarType.dyn_cast<fir::RecordType>()) {
3531e6d9c06SDiana Picus         mlir::LLVM::LLVMFuncOp memSizeFn =
3541e6d9c06SDiana Picus             getDependentTypeMemSizeFn(recTy, alloc, rewriter);
3551e6d9c06SDiana Picus         if (!memSizeFn)
3561e6d9c06SDiana Picus           emitError(loc, "did not find allocation function");
3571e6d9c06SDiana Picus         mlir::NamedAttribute attr = rewriter.getNamedAttr(
3581e6d9c06SDiana Picus             "callee", mlir::SymbolRefAttr::get(memSizeFn));
3591e6d9c06SDiana Picus         auto call = rewriter.create<mlir::LLVM::CallOp>(
3601e6d9c06SDiana Picus             loc, ity, lenParams, llvm::ArrayRef<mlir::NamedAttribute>{attr});
3611e6d9c06SDiana Picus         size = call.getResult(0);
3621e6d9c06SDiana Picus         ty = mlir::LLVM::LLVMPointerType::get(
3631e6d9c06SDiana Picus             mlir::IntegerType::get(alloc.getContext(), 8));
3641e6d9c06SDiana Picus       } else {
3651e6d9c06SDiana Picus         return emitError(loc, "unexpected type ")
3661e6d9c06SDiana Picus                << scalarType << " with type parameters";
3671e6d9c06SDiana Picus       }
3681e6d9c06SDiana Picus     }
3691e6d9c06SDiana Picus     if (alloc.hasShapeOperands()) {
3701e6d9c06SDiana Picus       mlir::Type allocEleTy = fir::unwrapRefType(alloc.getType());
3711e6d9c06SDiana Picus       // Scale the size by constant factors encoded in the array type.
3721e6d9c06SDiana Picus       if (auto seqTy = allocEleTy.dyn_cast<fir::SequenceType>()) {
3731e6d9c06SDiana Picus         fir::SequenceType::Extent constSize = 1;
3741e6d9c06SDiana Picus         for (auto extent : seqTy.getShape())
3751e6d9c06SDiana Picus           if (extent != fir::SequenceType::getUnknownExtent())
3761e6d9c06SDiana Picus             constSize *= extent;
3771e6d9c06SDiana Picus         mlir::Value constVal{
3781e6d9c06SDiana Picus             genConstantIndex(loc, ity, rewriter, constSize).getResult()};
3791e6d9c06SDiana Picus         size = rewriter.create<mlir::LLVM::MulOp>(loc, ity, size, constVal);
3801e6d9c06SDiana Picus       }
3811e6d9c06SDiana Picus       unsigned end = operands.size();
3821e6d9c06SDiana Picus       for (; i < end; ++i)
3831e6d9c06SDiana Picus         size = rewriter.create<mlir::LLVM::MulOp>(
3841e6d9c06SDiana Picus             loc, ity, size, integerCast(loc, rewriter, ity, operands[i]));
3851e6d9c06SDiana Picus     }
3861e6d9c06SDiana Picus     if (ty == resultTy) {
3871e6d9c06SDiana Picus       // Do not emit the bitcast if ty and resultTy are the same.
3881e6d9c06SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::AllocaOp>(alloc, ty, size,
3891e6d9c06SDiana Picus                                                         alloc->getAttrs());
3901e6d9c06SDiana Picus     } else {
3911e6d9c06SDiana Picus       auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, ty, size,
3921e6d9c06SDiana Picus                                                       alloc->getAttrs());
3931e6d9c06SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(alloc, resultTy, al);
3941e6d9c06SDiana Picus     }
3951e6d9c06SDiana Picus     return success();
3961e6d9c06SDiana Picus   }
3971e6d9c06SDiana Picus };
398044d5b5dSValentin Clement 
399df3b9810SValentin Clement /// Lower `fir.box_addr` to the sequence of operations to extract the first
400df3b9810SValentin Clement /// element of the box.
401df3b9810SValentin Clement struct BoxAddrOpConversion : public FIROpConversion<fir::BoxAddrOp> {
402df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
403df3b9810SValentin Clement 
404df3b9810SValentin Clement   mlir::LogicalResult
405df3b9810SValentin Clement   matchAndRewrite(fir::BoxAddrOp boxaddr, OpAdaptor adaptor,
406df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
407df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
408df3b9810SValentin Clement     auto loc = boxaddr.getLoc();
409df3b9810SValentin Clement     mlir::Type ty = convertType(boxaddr.getType());
410df3b9810SValentin Clement     if (auto argty = boxaddr.val().getType().dyn_cast<fir::BoxType>()) {
411df3b9810SValentin Clement       rewriter.replaceOp(boxaddr, loadBaseAddrFromBox(loc, ty, a, rewriter));
412df3b9810SValentin Clement     } else {
413df3b9810SValentin Clement       auto c0attr = rewriter.getI32IntegerAttr(0);
414df3b9810SValentin Clement       auto c0 = mlir::ArrayAttr::get(boxaddr.getContext(), c0attr);
415df3b9810SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(boxaddr, ty, a,
416df3b9810SValentin Clement                                                               c0);
417df3b9810SValentin Clement     }
418df3b9810SValentin Clement     return success();
419df3b9810SValentin Clement   }
420df3b9810SValentin Clement };
421df3b9810SValentin Clement 
422df3b9810SValentin Clement /// Lower `fir.box_dims` to a sequence of operations to extract the requested
423df3b9810SValentin Clement /// dimension infomartion from the boxed value.
424df3b9810SValentin Clement /// Result in a triple set of GEPs and loads.
425df3b9810SValentin Clement struct BoxDimsOpConversion : public FIROpConversion<fir::BoxDimsOp> {
426df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
427df3b9810SValentin Clement 
428df3b9810SValentin Clement   mlir::LogicalResult
429df3b9810SValentin Clement   matchAndRewrite(fir::BoxDimsOp boxdims, OpAdaptor adaptor,
430df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
431df3b9810SValentin Clement     SmallVector<mlir::Type, 3> resultTypes = {
432df3b9810SValentin Clement         convertType(boxdims.getResult(0).getType()),
433df3b9810SValentin Clement         convertType(boxdims.getResult(1).getType()),
434df3b9810SValentin Clement         convertType(boxdims.getResult(2).getType()),
435df3b9810SValentin Clement     };
436df3b9810SValentin Clement     auto results =
437df3b9810SValentin Clement         getDimsFromBox(boxdims.getLoc(), resultTypes, adaptor.getOperands()[0],
438df3b9810SValentin Clement                        adaptor.getOperands()[1], rewriter);
439df3b9810SValentin Clement     rewriter.replaceOp(boxdims, results);
440df3b9810SValentin Clement     return success();
441df3b9810SValentin Clement   }
442df3b9810SValentin Clement };
443df3b9810SValentin Clement 
444df3b9810SValentin Clement /// Lower `fir.box_elesize` to a sequence of operations ro extract the size of
445df3b9810SValentin Clement /// an element in the boxed value.
446df3b9810SValentin Clement struct BoxEleSizeOpConversion : public FIROpConversion<fir::BoxEleSizeOp> {
447df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
448df3b9810SValentin Clement 
449df3b9810SValentin Clement   mlir::LogicalResult
450df3b9810SValentin Clement   matchAndRewrite(fir::BoxEleSizeOp boxelesz, OpAdaptor adaptor,
451df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
452df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
453df3b9810SValentin Clement     auto loc = boxelesz.getLoc();
454df3b9810SValentin Clement     auto ty = convertType(boxelesz.getType());
455b6e44ecdSValentin Clement     auto elemSize = getValueFromBox(loc, a, ty, rewriter, kElemLenPosInBox);
456b6e44ecdSValentin Clement     rewriter.replaceOp(boxelesz, elemSize);
457b6e44ecdSValentin Clement     return success();
458b6e44ecdSValentin Clement   }
459b6e44ecdSValentin Clement };
460b6e44ecdSValentin Clement 
461b6e44ecdSValentin Clement /// Lower `fir.box_isalloc` to a sequence of operations to determine if the
462b6e44ecdSValentin Clement /// boxed value was from an ALLOCATABLE entity.
463b6e44ecdSValentin Clement struct BoxIsAllocOpConversion : public FIROpConversion<fir::BoxIsAllocOp> {
464b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
465b6e44ecdSValentin Clement 
466b6e44ecdSValentin Clement   mlir::LogicalResult
467b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsAllocOp boxisalloc, OpAdaptor adaptor,
468b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
469b6e44ecdSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
470b6e44ecdSValentin Clement     auto loc = boxisalloc.getLoc();
471b6e44ecdSValentin Clement     mlir::Value check =
472b6e44ecdSValentin Clement         genBoxAttributeCheck(loc, box, rewriter, kAttrAllocatable);
473b6e44ecdSValentin Clement     rewriter.replaceOp(boxisalloc, check);
474b6e44ecdSValentin Clement     return success();
475b6e44ecdSValentin Clement   }
476b6e44ecdSValentin Clement };
477b6e44ecdSValentin Clement 
478b6e44ecdSValentin Clement /// Lower `fir.box_isarray` to a sequence of operations to determine if the
479b6e44ecdSValentin Clement /// boxed is an array.
480b6e44ecdSValentin Clement struct BoxIsArrayOpConversion : public FIROpConversion<fir::BoxIsArrayOp> {
481b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
482b6e44ecdSValentin Clement 
483b6e44ecdSValentin Clement   mlir::LogicalResult
484b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsArrayOp boxisarray, OpAdaptor adaptor,
485b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
486b6e44ecdSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
487b6e44ecdSValentin Clement     auto loc = boxisarray.getLoc();
488b6e44ecdSValentin Clement     auto rank =
489b6e44ecdSValentin Clement         getValueFromBox(loc, a, rewriter.getI32Type(), rewriter, kRankPosInBox);
490b6e44ecdSValentin Clement     auto c0 = genConstantOffset(loc, rewriter, 0);
491b6e44ecdSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
492b6e44ecdSValentin Clement         boxisarray, mlir::LLVM::ICmpPredicate::ne, rank, c0);
493b6e44ecdSValentin Clement     return success();
494b6e44ecdSValentin Clement   }
495b6e44ecdSValentin Clement };
496b6e44ecdSValentin Clement 
497b6e44ecdSValentin Clement /// Lower `fir.box_isptr` to a sequence of operations to determined if the
498b6e44ecdSValentin Clement /// boxed value was from a POINTER entity.
499b6e44ecdSValentin Clement struct BoxIsPtrOpConversion : public FIROpConversion<fir::BoxIsPtrOp> {
500b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
501b6e44ecdSValentin Clement 
502b6e44ecdSValentin Clement   mlir::LogicalResult
503b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsPtrOp boxisptr, OpAdaptor adaptor,
504b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
505b6e44ecdSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
506b6e44ecdSValentin Clement     auto loc = boxisptr.getLoc();
507b6e44ecdSValentin Clement     mlir::Value check = genBoxAttributeCheck(loc, box, rewriter, kAttrPointer);
508b6e44ecdSValentin Clement     rewriter.replaceOp(boxisptr, check);
509df3b9810SValentin Clement     return success();
510df3b9810SValentin Clement   }
511df3b9810SValentin Clement };
512df3b9810SValentin Clement 
513df3b9810SValentin Clement /// Lower `fir.box_rank` to the sequence of operation to extract the rank from
514df3b9810SValentin Clement /// the box.
515df3b9810SValentin Clement struct BoxRankOpConversion : public FIROpConversion<fir::BoxRankOp> {
516df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
517df3b9810SValentin Clement 
518df3b9810SValentin Clement   mlir::LogicalResult
519df3b9810SValentin Clement   matchAndRewrite(fir::BoxRankOp boxrank, OpAdaptor adaptor,
520df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
521df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
522df3b9810SValentin Clement     auto loc = boxrank.getLoc();
523df3b9810SValentin Clement     mlir::Type ty = convertType(boxrank.getType());
524b6e44ecdSValentin Clement     auto result = getValueFromBox(loc, a, ty, rewriter, kRankPosInBox);
525df3b9810SValentin Clement     rewriter.replaceOp(boxrank, result);
526df3b9810SValentin Clement     return success();
527df3b9810SValentin Clement   }
528df3b9810SValentin Clement };
529df3b9810SValentin Clement 
5301a2ec667SValentin Clement /// Lower `fir.string_lit` to LLVM IR dialect operation.
5311a2ec667SValentin Clement struct StringLitOpConversion : public FIROpConversion<fir::StringLitOp> {
5321a2ec667SValentin Clement   using FIROpConversion::FIROpConversion;
5331a2ec667SValentin Clement 
5341a2ec667SValentin Clement   mlir::LogicalResult
5351a2ec667SValentin Clement   matchAndRewrite(fir::StringLitOp constop, OpAdaptor adaptor,
5361a2ec667SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
5371a2ec667SValentin Clement     auto ty = convertType(constop.getType());
5381a2ec667SValentin Clement     auto attr = constop.getValue();
5391a2ec667SValentin Clement     if (attr.isa<mlir::StringAttr>()) {
5401a2ec667SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(constop, ty, attr);
5411a2ec667SValentin Clement       return success();
5421a2ec667SValentin Clement     }
5431a2ec667SValentin Clement 
5441a2ec667SValentin Clement     auto arr = attr.cast<mlir::ArrayAttr>();
5451a2ec667SValentin Clement     auto charTy = constop.getType().cast<fir::CharacterType>();
5461a2ec667SValentin Clement     unsigned bits = lowerTy().characterBitsize(charTy);
5471a2ec667SValentin Clement     mlir::Type intTy = rewriter.getIntegerType(bits);
5481a2ec667SValentin Clement     auto attrs = llvm::map_range(
5491a2ec667SValentin Clement         arr.getValue(), [intTy, bits](mlir::Attribute attr) -> Attribute {
5501a2ec667SValentin Clement           return mlir::IntegerAttr::get(
5511a2ec667SValentin Clement               intTy,
5521a2ec667SValentin Clement               attr.cast<mlir::IntegerAttr>().getValue().sextOrTrunc(bits));
5531a2ec667SValentin Clement         });
5541a2ec667SValentin Clement     mlir::Type vecType = mlir::VectorType::get(arr.size(), intTy);
5551a2ec667SValentin Clement     auto denseAttr = mlir::DenseElementsAttr::get(
5561a2ec667SValentin Clement         vecType.cast<mlir::ShapedType>(), llvm::to_vector<8>(attrs));
5571a2ec667SValentin Clement     rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(constop, ty,
5581a2ec667SValentin Clement                                                          denseAttr);
5591a2ec667SValentin Clement     return success();
5601a2ec667SValentin Clement   }
5611a2ec667SValentin Clement };
5621a2ec667SValentin Clement 
563cc505c0bSKiran Chandramohan /// Lower `fir.boxproc_host` operation. Extracts the host pointer from the
564cc505c0bSKiran Chandramohan /// boxproc.
565cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
566cc505c0bSKiran Chandramohan struct BoxProcHostOpConversion : public FIROpConversion<fir::BoxProcHostOp> {
567cc505c0bSKiran Chandramohan   using FIROpConversion::FIROpConversion;
568cc505c0bSKiran Chandramohan 
569cc505c0bSKiran Chandramohan   mlir::LogicalResult
570cc505c0bSKiran Chandramohan   matchAndRewrite(fir::BoxProcHostOp boxprochost, OpAdaptor adaptor,
571cc505c0bSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
5727ce8c6fcSKiran Chandramohan     TODO(boxprochost.getLoc(), "fir.boxproc_host codegen");
5737ce8c6fcSKiran Chandramohan     return failure();
574cc505c0bSKiran Chandramohan   }
575cc505c0bSKiran Chandramohan };
576cc505c0bSKiran Chandramohan 
577e38ef2ffSValentin Clement /// Lower `fir.box_tdesc` to the sequence of operations to extract the type
578e38ef2ffSValentin Clement /// descriptor from the box.
579e38ef2ffSValentin Clement struct BoxTypeDescOpConversion : public FIROpConversion<fir::BoxTypeDescOp> {
580e38ef2ffSValentin Clement   using FIROpConversion::FIROpConversion;
581e38ef2ffSValentin Clement 
582e38ef2ffSValentin Clement   mlir::LogicalResult
583e38ef2ffSValentin Clement   matchAndRewrite(fir::BoxTypeDescOp boxtypedesc, OpAdaptor adaptor,
584e38ef2ffSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
585e38ef2ffSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
586e38ef2ffSValentin Clement     auto loc = boxtypedesc.getLoc();
587e38ef2ffSValentin Clement     mlir::Type typeTy =
588e38ef2ffSValentin Clement         fir::getDescFieldTypeModel<kTypePosInBox>()(boxtypedesc.getContext());
589e38ef2ffSValentin Clement     auto result = getValueFromBox(loc, box, typeTy, rewriter, kTypePosInBox);
590e38ef2ffSValentin Clement     auto typePtrTy = mlir::LLVM::LLVMPointerType::get(typeTy);
591e38ef2ffSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(boxtypedesc, typePtrTy,
592e38ef2ffSValentin Clement                                                         result);
593e38ef2ffSValentin Clement     return success();
594e38ef2ffSValentin Clement   }
595e38ef2ffSValentin Clement };
596e38ef2ffSValentin Clement 
597ddd11b9aSAndrzej Warzynski // `fir.call` -> `llvm.call`
598ddd11b9aSAndrzej Warzynski struct CallOpConversion : public FIROpConversion<fir::CallOp> {
599ddd11b9aSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
600ddd11b9aSAndrzej Warzynski 
601ddd11b9aSAndrzej Warzynski   mlir::LogicalResult
602ddd11b9aSAndrzej Warzynski   matchAndRewrite(fir::CallOp call, OpAdaptor adaptor,
603ddd11b9aSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
604ddd11b9aSAndrzej Warzynski     SmallVector<mlir::Type> resultTys;
605ddd11b9aSAndrzej Warzynski     for (auto r : call.getResults())
606ddd11b9aSAndrzej Warzynski       resultTys.push_back(convertType(r.getType()));
607ddd11b9aSAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
608ddd11b9aSAndrzej Warzynski         call, resultTys, adaptor.getOperands(), call->getAttrs());
609ddd11b9aSAndrzej Warzynski     return success();
610ddd11b9aSAndrzej Warzynski   }
611ddd11b9aSAndrzej Warzynski };
612*c2acd453SAlexisPerry } // namespace
613ddd11b9aSAndrzej Warzynski 
614092cee5fSValentin Clement static mlir::Type getComplexEleTy(mlir::Type complex) {
615092cee5fSValentin Clement   if (auto cc = complex.dyn_cast<mlir::ComplexType>())
616092cee5fSValentin Clement     return cc.getElementType();
617092cee5fSValentin Clement   return complex.cast<fir::ComplexType>().getElementType();
618092cee5fSValentin Clement }
619092cee5fSValentin Clement 
620*c2acd453SAlexisPerry namespace {
621f1dfc027SDiana Picus /// Compare complex values
622f1dfc027SDiana Picus ///
623f1dfc027SDiana Picus /// Per 10.1, the only comparisons available are .EQ. (oeq) and .NE. (une).
624f1dfc027SDiana Picus ///
625f1dfc027SDiana Picus /// For completeness, all other comparison are done on the real component only.
626f1dfc027SDiana Picus struct CmpcOpConversion : public FIROpConversion<fir::CmpcOp> {
627f1dfc027SDiana Picus   using FIROpConversion::FIROpConversion;
628f1dfc027SDiana Picus 
629f1dfc027SDiana Picus   mlir::LogicalResult
630f1dfc027SDiana Picus   matchAndRewrite(fir::CmpcOp cmp, OpAdaptor adaptor,
631f1dfc027SDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
632f1dfc027SDiana Picus     mlir::ValueRange operands = adaptor.getOperands();
633f1dfc027SDiana Picus     mlir::MLIRContext *ctxt = cmp.getContext();
634f1dfc027SDiana Picus     mlir::Type eleTy = convertType(getComplexEleTy(cmp.lhs().getType()));
635f1dfc027SDiana Picus     mlir::Type resTy = convertType(cmp.getType());
636f1dfc027SDiana Picus     mlir::Location loc = cmp.getLoc();
637f1dfc027SDiana Picus     auto pos0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0));
638f1dfc027SDiana Picus     SmallVector<mlir::Value, 2> rp{rewriter.create<mlir::LLVM::ExtractValueOp>(
639f1dfc027SDiana Picus                                        loc, eleTy, operands[0], pos0),
640f1dfc027SDiana Picus                                    rewriter.create<mlir::LLVM::ExtractValueOp>(
641f1dfc027SDiana Picus                                        loc, eleTy, operands[1], pos0)};
642f1dfc027SDiana Picus     auto rcp =
643f1dfc027SDiana Picus         rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, rp, cmp->getAttrs());
644f1dfc027SDiana Picus     auto pos1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1));
645f1dfc027SDiana Picus     SmallVector<mlir::Value, 2> ip{rewriter.create<mlir::LLVM::ExtractValueOp>(
646f1dfc027SDiana Picus                                        loc, eleTy, operands[0], pos1),
647f1dfc027SDiana Picus                                    rewriter.create<mlir::LLVM::ExtractValueOp>(
648f1dfc027SDiana Picus                                        loc, eleTy, operands[1], pos1)};
649f1dfc027SDiana Picus     auto icp =
650f1dfc027SDiana Picus         rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, ip, cmp->getAttrs());
651f1dfc027SDiana Picus     SmallVector<mlir::Value, 2> cp{rcp, icp};
652f1dfc027SDiana Picus     switch (cmp.getPredicate()) {
653f1dfc027SDiana Picus     case mlir::arith::CmpFPredicate::OEQ: // .EQ.
654f1dfc027SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(cmp, resTy, cp);
655f1dfc027SDiana Picus       break;
656f1dfc027SDiana Picus     case mlir::arith::CmpFPredicate::UNE: // .NE.
657f1dfc027SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(cmp, resTy, cp);
658f1dfc027SDiana Picus       break;
659f1dfc027SDiana Picus     default:
660f1dfc027SDiana Picus       rewriter.replaceOp(cmp, rcp.getResult());
661f1dfc027SDiana Picus       break;
662f1dfc027SDiana Picus     }
663f1dfc027SDiana Picus     return success();
664f1dfc027SDiana Picus   }
665f1dfc027SDiana Picus };
666f1dfc027SDiana Picus 
667e81d73edSDiana Picus /// Lower complex constants
668e81d73edSDiana Picus struct ConstcOpConversion : public FIROpConversion<fir::ConstcOp> {
669e81d73edSDiana Picus   using FIROpConversion::FIROpConversion;
670e81d73edSDiana Picus 
671e81d73edSDiana Picus   mlir::LogicalResult
672e81d73edSDiana Picus   matchAndRewrite(fir::ConstcOp conc, OpAdaptor,
673e81d73edSDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
674e81d73edSDiana Picus     mlir::Location loc = conc.getLoc();
675e81d73edSDiana Picus     mlir::MLIRContext *ctx = conc.getContext();
676e81d73edSDiana Picus     mlir::Type ty = convertType(conc.getType());
677e81d73edSDiana Picus     mlir::Type ety = convertType(getComplexEleTy(conc.getType()));
678e81d73edSDiana Picus     auto realFloatAttr = mlir::FloatAttr::get(ety, getValue(conc.getReal()));
679e81d73edSDiana Picus     auto realPart =
680e81d73edSDiana Picus         rewriter.create<mlir::LLVM::ConstantOp>(loc, ety, realFloatAttr);
681e81d73edSDiana Picus     auto imFloatAttr = mlir::FloatAttr::get(ety, getValue(conc.getImaginary()));
682e81d73edSDiana Picus     auto imPart =
683e81d73edSDiana Picus         rewriter.create<mlir::LLVM::ConstantOp>(loc, ety, imFloatAttr);
684e81d73edSDiana Picus     auto realIndex = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
685e81d73edSDiana Picus     auto imIndex = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
686e81d73edSDiana Picus     auto undef = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
687e81d73edSDiana Picus     auto setReal = rewriter.create<mlir::LLVM::InsertValueOp>(
688e81d73edSDiana Picus         loc, ty, undef, realPart, realIndex);
689e81d73edSDiana Picus     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(conc, ty, setReal,
690e81d73edSDiana Picus                                                            imPart, imIndex);
691e81d73edSDiana Picus     return success();
692e81d73edSDiana Picus   }
693e81d73edSDiana Picus 
694e81d73edSDiana Picus   inline APFloat getValue(mlir::Attribute attr) const {
695e81d73edSDiana Picus     return attr.cast<fir::RealAttr>().getValue();
696e81d73edSDiana Picus   }
697e81d73edSDiana Picus };
698e81d73edSDiana Picus 
699092cee5fSValentin Clement /// convert value of from-type to value of to-type
700092cee5fSValentin Clement struct ConvertOpConversion : public FIROpConversion<fir::ConvertOp> {
701092cee5fSValentin Clement   using FIROpConversion::FIROpConversion;
702092cee5fSValentin Clement 
703092cee5fSValentin Clement   static bool isFloatingPointTy(mlir::Type ty) {
704092cee5fSValentin Clement     return ty.isa<mlir::FloatType>();
705092cee5fSValentin Clement   }
706092cee5fSValentin Clement 
707092cee5fSValentin Clement   mlir::LogicalResult
708092cee5fSValentin Clement   matchAndRewrite(fir::ConvertOp convert, OpAdaptor adaptor,
709092cee5fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
710092cee5fSValentin Clement     auto fromTy = convertType(convert.value().getType());
711092cee5fSValentin Clement     auto toTy = convertType(convert.res().getType());
712092cee5fSValentin Clement     mlir::Value op0 = adaptor.getOperands()[0];
713092cee5fSValentin Clement     if (fromTy == toTy) {
714092cee5fSValentin Clement       rewriter.replaceOp(convert, op0);
715092cee5fSValentin Clement       return success();
716092cee5fSValentin Clement     }
717092cee5fSValentin Clement     auto loc = convert.getLoc();
718092cee5fSValentin Clement     auto convertFpToFp = [&](mlir::Value val, unsigned fromBits,
719092cee5fSValentin Clement                              unsigned toBits, mlir::Type toTy) -> mlir::Value {
720092cee5fSValentin Clement       if (fromBits == toBits) {
721092cee5fSValentin Clement         // TODO: Converting between two floating-point representations with the
722092cee5fSValentin Clement         // same bitwidth is not allowed for now.
723092cee5fSValentin Clement         mlir::emitError(loc,
724092cee5fSValentin Clement                         "cannot implicitly convert between two floating-point "
725092cee5fSValentin Clement                         "representations of the same bitwidth");
726092cee5fSValentin Clement         return {};
727092cee5fSValentin Clement       }
728092cee5fSValentin Clement       if (fromBits > toBits)
729092cee5fSValentin Clement         return rewriter.create<mlir::LLVM::FPTruncOp>(loc, toTy, val);
730092cee5fSValentin Clement       return rewriter.create<mlir::LLVM::FPExtOp>(loc, toTy, val);
731092cee5fSValentin Clement     };
732092cee5fSValentin Clement     // Complex to complex conversion.
733092cee5fSValentin Clement     if (fir::isa_complex(convert.value().getType()) &&
734092cee5fSValentin Clement         fir::isa_complex(convert.res().getType())) {
735092cee5fSValentin Clement       // Special case: handle the conversion of a complex such that both the
736092cee5fSValentin Clement       // real and imaginary parts are converted together.
737092cee5fSValentin Clement       auto zero = mlir::ArrayAttr::get(convert.getContext(),
738092cee5fSValentin Clement                                        rewriter.getI32IntegerAttr(0));
739092cee5fSValentin Clement       auto one = mlir::ArrayAttr::get(convert.getContext(),
740092cee5fSValentin Clement                                       rewriter.getI32IntegerAttr(1));
741092cee5fSValentin Clement       auto ty = convertType(getComplexEleTy(convert.value().getType()));
742092cee5fSValentin Clement       auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, zero);
743092cee5fSValentin Clement       auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, one);
744092cee5fSValentin Clement       auto nt = convertType(getComplexEleTy(convert.res().getType()));
745092cee5fSValentin Clement       auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
746092cee5fSValentin Clement       auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(nt);
747092cee5fSValentin Clement       auto rc = convertFpToFp(rp, fromBits, toBits, nt);
748092cee5fSValentin Clement       auto ic = convertFpToFp(ip, fromBits, toBits, nt);
749092cee5fSValentin Clement       auto un = rewriter.create<mlir::LLVM::UndefOp>(loc, toTy);
750092cee5fSValentin Clement       auto i1 =
751092cee5fSValentin Clement           rewriter.create<mlir::LLVM::InsertValueOp>(loc, toTy, un, rc, zero);
752092cee5fSValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(convert, toTy, i1,
753092cee5fSValentin Clement                                                              ic, one);
754092cee5fSValentin Clement       return mlir::success();
755092cee5fSValentin Clement     }
756092cee5fSValentin Clement     // Floating point to floating point conversion.
757092cee5fSValentin Clement     if (isFloatingPointTy(fromTy)) {
758092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
759092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
760092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
761092cee5fSValentin Clement         auto v = convertFpToFp(op0, fromBits, toBits, toTy);
762092cee5fSValentin Clement         rewriter.replaceOp(convert, v);
763092cee5fSValentin Clement         return mlir::success();
764092cee5fSValentin Clement       }
765092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
766092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::FPToSIOp>(convert, toTy, op0);
767092cee5fSValentin Clement         return mlir::success();
768092cee5fSValentin Clement       }
769092cee5fSValentin Clement     } else if (fromTy.isa<mlir::IntegerType>()) {
770092cee5fSValentin Clement       // Integer to integer conversion.
771092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
772092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
773092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
774092cee5fSValentin Clement         assert(fromBits != toBits);
775092cee5fSValentin Clement         if (fromBits > toBits) {
776092cee5fSValentin Clement           rewriter.replaceOpWithNewOp<mlir::LLVM::TruncOp>(convert, toTy, op0);
777092cee5fSValentin Clement           return mlir::success();
778092cee5fSValentin Clement         }
779092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SExtOp>(convert, toTy, op0);
780092cee5fSValentin Clement         return mlir::success();
781092cee5fSValentin Clement       }
782092cee5fSValentin Clement       // Integer to floating point conversion.
783092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
784092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SIToFPOp>(convert, toTy, op0);
785092cee5fSValentin Clement         return mlir::success();
786092cee5fSValentin Clement       }
787092cee5fSValentin Clement       // Integer to pointer conversion.
788092cee5fSValentin Clement       if (toTy.isa<mlir::LLVM::LLVMPointerType>()) {
789092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(convert, toTy, op0);
790092cee5fSValentin Clement         return mlir::success();
791092cee5fSValentin Clement       }
792092cee5fSValentin Clement     } else if (fromTy.isa<mlir::LLVM::LLVMPointerType>()) {
793092cee5fSValentin Clement       // Pointer to integer conversion.
794092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
795092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::PtrToIntOp>(convert, toTy, op0);
796092cee5fSValentin Clement         return mlir::success();
797092cee5fSValentin Clement       }
798092cee5fSValentin Clement       // Pointer to pointer conversion.
799092cee5fSValentin Clement       if (toTy.isa<mlir::LLVM::LLVMPointerType>()) {
800092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(convert, toTy, op0);
801092cee5fSValentin Clement         return mlir::success();
802092cee5fSValentin Clement       }
803092cee5fSValentin Clement     }
804092cee5fSValentin Clement     return emitError(loc) << "cannot convert " << fromTy << " to " << toTy;
805092cee5fSValentin Clement   }
806092cee5fSValentin Clement };
807092cee5fSValentin Clement 
8089534e361SValentin Clement /// Lower `fir.dispatch` operation. A virtual call to a method in a dispatch
8099534e361SValentin Clement /// table.
8109534e361SValentin Clement struct DispatchOpConversion : public FIROpConversion<fir::DispatchOp> {
8119534e361SValentin Clement   using FIROpConversion::FIROpConversion;
8129534e361SValentin Clement 
8139534e361SValentin Clement   mlir::LogicalResult
8149534e361SValentin Clement   matchAndRewrite(fir::DispatchOp dispatch, OpAdaptor adaptor,
8159534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8167ce8c6fcSKiran Chandramohan     TODO(dispatch.getLoc(), "fir.dispatch codegen");
8177ce8c6fcSKiran Chandramohan     return failure();
8189534e361SValentin Clement   }
8199534e361SValentin Clement };
8209534e361SValentin Clement 
8219534e361SValentin Clement /// Lower `fir.dispatch_table` operation. The dispatch table for a Fortran
8229534e361SValentin Clement /// derived type.
8239534e361SValentin Clement struct DispatchTableOpConversion
8249534e361SValentin Clement     : public FIROpConversion<fir::DispatchTableOp> {
8259534e361SValentin Clement   using FIROpConversion::FIROpConversion;
8269534e361SValentin Clement 
8279534e361SValentin Clement   mlir::LogicalResult
8289534e361SValentin Clement   matchAndRewrite(fir::DispatchTableOp dispTab, OpAdaptor adaptor,
8299534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8307ce8c6fcSKiran Chandramohan     TODO(dispTab.getLoc(), "fir.dispatch_table codegen");
8317ce8c6fcSKiran Chandramohan     return failure();
8329534e361SValentin Clement   }
8339534e361SValentin Clement };
8349534e361SValentin Clement 
8359534e361SValentin Clement /// Lower `fir.dt_entry` operation. An entry in a dispatch table; binds a
8369534e361SValentin Clement /// method-name to a function.
8379534e361SValentin Clement struct DTEntryOpConversion : public FIROpConversion<fir::DTEntryOp> {
8389534e361SValentin Clement   using FIROpConversion::FIROpConversion;
8399534e361SValentin Clement 
8409534e361SValentin Clement   mlir::LogicalResult
8419534e361SValentin Clement   matchAndRewrite(fir::DTEntryOp dtEnt, OpAdaptor adaptor,
8429534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8437ce8c6fcSKiran Chandramohan     TODO(dtEnt.getLoc(), "fir.dt_entry codegen");
8447ce8c6fcSKiran Chandramohan     return failure();
8459534e361SValentin Clement   }
8469534e361SValentin Clement };
8479534e361SValentin Clement 
848677df8c7SValentin Clement /// Lower `fir.global_len` operation.
849677df8c7SValentin Clement struct GlobalLenOpConversion : public FIROpConversion<fir::GlobalLenOp> {
850677df8c7SValentin Clement   using FIROpConversion::FIROpConversion;
851677df8c7SValentin Clement 
852677df8c7SValentin Clement   mlir::LogicalResult
853677df8c7SValentin Clement   matchAndRewrite(fir::GlobalLenOp globalLen, OpAdaptor adaptor,
854677df8c7SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8557ce8c6fcSKiran Chandramohan     TODO(globalLen.getLoc(), "fir.global_len codegen");
8567ce8c6fcSKiran Chandramohan     return failure();
857677df8c7SValentin Clement   }
858677df8c7SValentin Clement };
859677df8c7SValentin Clement 
860cdc476abSDiana Picus /// Lower fir.len_param_index
861cdc476abSDiana Picus struct LenParamIndexOpConversion
862cdc476abSDiana Picus     : public FIROpConversion<fir::LenParamIndexOp> {
863cdc476abSDiana Picus   using FIROpConversion::FIROpConversion;
864cdc476abSDiana Picus 
865cdc476abSDiana Picus   // FIXME: this should be specialized by the runtime target
866cdc476abSDiana Picus   mlir::LogicalResult
867cdc476abSDiana Picus   matchAndRewrite(fir::LenParamIndexOp lenp, OpAdaptor,
868cdc476abSDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
8697ce8c6fcSKiran Chandramohan     TODO(lenp.getLoc(), "fir.len_param_index codegen");
870cdc476abSDiana Picus   }
871cdc476abSDiana Picus };
872cdc476abSDiana Picus 
87331246187SValentin Clement /// Lower `fir.gentypedesc` to a global constant.
87431246187SValentin Clement struct GenTypeDescOpConversion : public FIROpConversion<fir::GenTypeDescOp> {
87531246187SValentin Clement   using FIROpConversion::FIROpConversion;
87631246187SValentin Clement 
87731246187SValentin Clement   mlir::LogicalResult
87831246187SValentin Clement   matchAndRewrite(fir::GenTypeDescOp gentypedesc, OpAdaptor adaptor,
87931246187SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8807ce8c6fcSKiran Chandramohan     TODO(gentypedesc.getLoc(), "fir.gentypedesc codegen");
8817ce8c6fcSKiran Chandramohan     return failure();
88231246187SValentin Clement   }
88331246187SValentin Clement };
884*c2acd453SAlexisPerry } // namespace
885*c2acd453SAlexisPerry 
886*c2acd453SAlexisPerry /// Return the LLVMFuncOp corresponding to the standard malloc call.
887*c2acd453SAlexisPerry static mlir::LLVM::LLVMFuncOp
888*c2acd453SAlexisPerry getMalloc(fir::AllocMemOp op, mlir::ConversionPatternRewriter &rewriter) {
889*c2acd453SAlexisPerry   auto module = op->getParentOfType<mlir::ModuleOp>();
890*c2acd453SAlexisPerry   if (mlir::LLVM::LLVMFuncOp mallocFunc =
891*c2acd453SAlexisPerry           module.lookupSymbol<mlir::LLVM::LLVMFuncOp>("malloc"))
892*c2acd453SAlexisPerry     return mallocFunc;
893*c2acd453SAlexisPerry   mlir::OpBuilder moduleBuilder(
894*c2acd453SAlexisPerry       op->getParentOfType<mlir::ModuleOp>().getBodyRegion());
895*c2acd453SAlexisPerry   auto indexType = mlir::IntegerType::get(op.getContext(), 64);
896*c2acd453SAlexisPerry   return moduleBuilder.create<mlir::LLVM::LLVMFuncOp>(
897*c2acd453SAlexisPerry       rewriter.getUnknownLoc(), "malloc",
898*c2acd453SAlexisPerry       mlir::LLVM::LLVMFunctionType::get(getVoidPtrType(op.getContext()),
899*c2acd453SAlexisPerry                                         indexType,
900*c2acd453SAlexisPerry                                         /*isVarArg=*/false));
901*c2acd453SAlexisPerry }
902*c2acd453SAlexisPerry 
903*c2acd453SAlexisPerry /// Helper function for generating the LLVM IR that computes the size
904*c2acd453SAlexisPerry /// in bytes for a derived type.
905*c2acd453SAlexisPerry static mlir::Value
906*c2acd453SAlexisPerry computeDerivedTypeSize(mlir::Location loc, mlir::Type ptrTy, mlir::Type idxTy,
907*c2acd453SAlexisPerry                        mlir::ConversionPatternRewriter &rewriter) {
908*c2acd453SAlexisPerry   auto nullPtr = rewriter.create<mlir::LLVM::NullOp>(loc, ptrTy);
909*c2acd453SAlexisPerry   mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1);
910*c2acd453SAlexisPerry   llvm::SmallVector<mlir::Value> args{nullPtr, one};
911*c2acd453SAlexisPerry   auto gep = rewriter.create<mlir::LLVM::GEPOp>(loc, ptrTy, args);
912*c2acd453SAlexisPerry   return rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, gep);
913*c2acd453SAlexisPerry }
914*c2acd453SAlexisPerry 
915*c2acd453SAlexisPerry namespace {
916*c2acd453SAlexisPerry /// Lower a `fir.allocmem` instruction into `llvm.call @malloc`
917*c2acd453SAlexisPerry struct AllocMemOpConversion : public FIROpConversion<fir::AllocMemOp> {
918*c2acd453SAlexisPerry   using FIROpConversion::FIROpConversion;
919*c2acd453SAlexisPerry 
920*c2acd453SAlexisPerry   mlir::LogicalResult
921*c2acd453SAlexisPerry   matchAndRewrite(fir::AllocMemOp heap, OpAdaptor adaptor,
922*c2acd453SAlexisPerry                   mlir::ConversionPatternRewriter &rewriter) const override {
923*c2acd453SAlexisPerry     mlir::Type ty = convertType(heap.getType());
924*c2acd453SAlexisPerry     mlir::LLVM::LLVMFuncOp mallocFunc = getMalloc(heap, rewriter);
925*c2acd453SAlexisPerry     mlir::Location loc = heap.getLoc();
926*c2acd453SAlexisPerry     auto ity = lowerTy().indexType();
927*c2acd453SAlexisPerry     if (auto recTy = fir::unwrapSequenceType(heap.getAllocatedType())
928*c2acd453SAlexisPerry                          .dyn_cast<fir::RecordType>())
929*c2acd453SAlexisPerry       if (recTy.getNumLenParams() != 0) {
930*c2acd453SAlexisPerry         TODO(loc,
931*c2acd453SAlexisPerry              "fir.allocmem codegen of derived type with length parameters");
932*c2acd453SAlexisPerry         return failure();
933*c2acd453SAlexisPerry       }
934*c2acd453SAlexisPerry     mlir::Value size = genTypeSizeInBytes(loc, ity, rewriter, ty);
935*c2acd453SAlexisPerry     for (mlir::Value opnd : adaptor.getOperands())
936*c2acd453SAlexisPerry       size = rewriter.create<mlir::LLVM::MulOp>(
937*c2acd453SAlexisPerry           loc, ity, size, integerCast(loc, rewriter, ity, opnd));
938*c2acd453SAlexisPerry     heap->setAttr("callee", mlir::SymbolRefAttr::get(mallocFunc));
939*c2acd453SAlexisPerry     auto malloc = rewriter.create<mlir::LLVM::CallOp>(
940*c2acd453SAlexisPerry         loc, ::getVoidPtrType(heap.getContext()), size, heap->getAttrs());
941*c2acd453SAlexisPerry     rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(heap, ty,
942*c2acd453SAlexisPerry                                                        malloc.getResult(0));
943*c2acd453SAlexisPerry     return success();
944*c2acd453SAlexisPerry   }
945*c2acd453SAlexisPerry 
946*c2acd453SAlexisPerry   // Compute the (allocation) size of the allocmem type in bytes.
947*c2acd453SAlexisPerry   mlir::Value genTypeSizeInBytes(mlir::Location loc, mlir::Type idxTy,
948*c2acd453SAlexisPerry                                  mlir::ConversionPatternRewriter &rewriter,
949*c2acd453SAlexisPerry                                  mlir::Type llTy) const {
950*c2acd453SAlexisPerry     // Use the primitive size, if available.
951*c2acd453SAlexisPerry     auto ptrTy = llTy.dyn_cast<mlir::LLVM::LLVMPointerType>();
952*c2acd453SAlexisPerry     if (auto size =
953*c2acd453SAlexisPerry             mlir::LLVM::getPrimitiveTypeSizeInBits(ptrTy.getElementType()))
954*c2acd453SAlexisPerry       return genConstantIndex(loc, idxTy, rewriter, size / 8);
955*c2acd453SAlexisPerry 
956*c2acd453SAlexisPerry     // Otherwise, generate the GEP trick in LLVM IR to compute the size.
957*c2acd453SAlexisPerry     return computeDerivedTypeSize(loc, ptrTy, idxTy, rewriter);
958*c2acd453SAlexisPerry   }
959*c2acd453SAlexisPerry };
960*c2acd453SAlexisPerry } // namespace
961*c2acd453SAlexisPerry 
962*c2acd453SAlexisPerry /// Return the LLVMFuncOp corresponding to the standard free call.
963*c2acd453SAlexisPerry static mlir::LLVM::LLVMFuncOp
964*c2acd453SAlexisPerry getFree(fir::FreeMemOp op, mlir::ConversionPatternRewriter &rewriter) {
965*c2acd453SAlexisPerry   auto module = op->getParentOfType<mlir::ModuleOp>();
966*c2acd453SAlexisPerry   if (mlir::LLVM::LLVMFuncOp freeFunc =
967*c2acd453SAlexisPerry           module.lookupSymbol<mlir::LLVM::LLVMFuncOp>("free"))
968*c2acd453SAlexisPerry     return freeFunc;
969*c2acd453SAlexisPerry   mlir::OpBuilder moduleBuilder(module.getBodyRegion());
970*c2acd453SAlexisPerry   auto voidType = mlir::LLVM::LLVMVoidType::get(op.getContext());
971*c2acd453SAlexisPerry   return moduleBuilder.create<mlir::LLVM::LLVMFuncOp>(
972*c2acd453SAlexisPerry       rewriter.getUnknownLoc(), "free",
973*c2acd453SAlexisPerry       mlir::LLVM::LLVMFunctionType::get(voidType,
974*c2acd453SAlexisPerry                                         getVoidPtrType(op.getContext()),
975*c2acd453SAlexisPerry                                         /*isVarArg=*/false));
976*c2acd453SAlexisPerry }
977*c2acd453SAlexisPerry 
978*c2acd453SAlexisPerry namespace {
979*c2acd453SAlexisPerry /// Lower a `fir.freemem` instruction into `llvm.call @free`
980*c2acd453SAlexisPerry struct FreeMemOpConversion : public FIROpConversion<fir::FreeMemOp> {
981*c2acd453SAlexisPerry   using FIROpConversion::FIROpConversion;
982*c2acd453SAlexisPerry 
983*c2acd453SAlexisPerry   mlir::LogicalResult
984*c2acd453SAlexisPerry   matchAndRewrite(fir::FreeMemOp freemem, OpAdaptor adaptor,
985*c2acd453SAlexisPerry                   mlir::ConversionPatternRewriter &rewriter) const override {
986*c2acd453SAlexisPerry     mlir::LLVM::LLVMFuncOp freeFunc = getFree(freemem, rewriter);
987*c2acd453SAlexisPerry     mlir::Location loc = freemem.getLoc();
988*c2acd453SAlexisPerry     auto bitcast = rewriter.create<mlir::LLVM::BitcastOp>(
989*c2acd453SAlexisPerry         freemem.getLoc(), voidPtrTy(), adaptor.getOperands()[0]);
990*c2acd453SAlexisPerry     freemem->setAttr("callee", mlir::SymbolRefAttr::get(freeFunc));
991*c2acd453SAlexisPerry     rewriter.create<mlir::LLVM::CallOp>(
992*c2acd453SAlexisPerry         loc, mlir::TypeRange{}, mlir::ValueRange{bitcast}, freemem->getAttrs());
993*c2acd453SAlexisPerry     rewriter.eraseOp(freemem);
994*c2acd453SAlexisPerry     return success();
995*c2acd453SAlexisPerry   }
996*c2acd453SAlexisPerry };
99731246187SValentin Clement 
99822d332a0SAndrzej Warzynski /// Convert `fir.end`
99922d332a0SAndrzej Warzynski struct FirEndOpConversion : public FIROpConversion<fir::FirEndOp> {
100022d332a0SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
100122d332a0SAndrzej Warzynski 
100222d332a0SAndrzej Warzynski   mlir::LogicalResult
100322d332a0SAndrzej Warzynski   matchAndRewrite(fir::FirEndOp firEnd, OpAdaptor,
100422d332a0SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
10057ce8c6fcSKiran Chandramohan     TODO(firEnd.getLoc(), "fir.end codegen");
10067ce8c6fcSKiran Chandramohan     return failure();
100722d332a0SAndrzej Warzynski   }
100822d332a0SAndrzej Warzynski };
100922d332a0SAndrzej Warzynski 
10100c4a7a52SValentin Clement /// Lower `fir.has_value` operation to `llvm.return` operation.
1011044d5b5dSValentin Clement struct HasValueOpConversion : public FIROpConversion<fir::HasValueOp> {
1012044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
1013044d5b5dSValentin Clement 
1014044d5b5dSValentin Clement   mlir::LogicalResult
1015044d5b5dSValentin Clement   matchAndRewrite(fir::HasValueOp op, OpAdaptor adaptor,
1016044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1017044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, adaptor.getOperands());
1018044d5b5dSValentin Clement     return success();
1019044d5b5dSValentin Clement   }
1020044d5b5dSValentin Clement };
1021044d5b5dSValentin Clement 
10220c4a7a52SValentin Clement /// Lower `fir.global` operation to `llvm.global` operation.
10230c4a7a52SValentin Clement /// `fir.insert_on_range` operations are replaced with constant dense attribute
10240c4a7a52SValentin Clement /// if they are applied on the full range.
1025044d5b5dSValentin Clement struct GlobalOpConversion : public FIROpConversion<fir::GlobalOp> {
1026044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
1027044d5b5dSValentin Clement 
1028044d5b5dSValentin Clement   mlir::LogicalResult
1029044d5b5dSValentin Clement   matchAndRewrite(fir::GlobalOp global, OpAdaptor adaptor,
1030044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1031044d5b5dSValentin Clement     auto tyAttr = convertType(global.getType());
1032044d5b5dSValentin Clement     if (global.getType().isa<fir::BoxType>())
1033044d5b5dSValentin Clement       tyAttr = tyAttr.cast<mlir::LLVM::LLVMPointerType>().getElementType();
1034044d5b5dSValentin Clement     auto loc = global.getLoc();
1035044d5b5dSValentin Clement     mlir::Attribute initAttr{};
1036044d5b5dSValentin Clement     if (global.initVal())
1037044d5b5dSValentin Clement       initAttr = global.initVal().getValue();
1038044d5b5dSValentin Clement     auto linkage = convertLinkage(global.linkName());
1039044d5b5dSValentin Clement     auto isConst = global.constant().hasValue();
1040044d5b5dSValentin Clement     auto g = rewriter.create<mlir::LLVM::GlobalOp>(
1041044d5b5dSValentin Clement         loc, tyAttr, isConst, linkage, global.sym_name(), initAttr);
1042044d5b5dSValentin Clement     auto &gr = g.getInitializerRegion();
1043044d5b5dSValentin Clement     rewriter.inlineRegionBefore(global.region(), gr, gr.end());
1044044d5b5dSValentin Clement     if (!gr.empty()) {
1045044d5b5dSValentin Clement       // Replace insert_on_range with a constant dense attribute if the
1046044d5b5dSValentin Clement       // initialization is on the full range.
1047044d5b5dSValentin Clement       auto insertOnRangeOps = gr.front().getOps<fir::InsertOnRangeOp>();
1048044d5b5dSValentin Clement       for (auto insertOp : insertOnRangeOps) {
1049044d5b5dSValentin Clement         if (isFullRange(insertOp.coor(), insertOp.getType())) {
1050044d5b5dSValentin Clement           auto seqTyAttr = convertType(insertOp.getType());
1051044d5b5dSValentin Clement           auto *op = insertOp.val().getDefiningOp();
1052044d5b5dSValentin Clement           auto constant = mlir::dyn_cast<mlir::arith::ConstantOp>(op);
1053044d5b5dSValentin Clement           if (!constant) {
1054044d5b5dSValentin Clement             auto convertOp = mlir::dyn_cast<fir::ConvertOp>(op);
1055044d5b5dSValentin Clement             if (!convertOp)
1056044d5b5dSValentin Clement               continue;
1057044d5b5dSValentin Clement             constant = cast<mlir::arith::ConstantOp>(
1058044d5b5dSValentin Clement                 convertOp.value().getDefiningOp());
1059044d5b5dSValentin Clement           }
1060044d5b5dSValentin Clement           mlir::Type vecType = mlir::VectorType::get(
1061044d5b5dSValentin Clement               insertOp.getType().getShape(), constant.getType());
1062044d5b5dSValentin Clement           auto denseAttr = mlir::DenseElementsAttr::get(
1063044d5b5dSValentin Clement               vecType.cast<ShapedType>(), constant.value());
1064044d5b5dSValentin Clement           rewriter.setInsertionPointAfter(insertOp);
1065044d5b5dSValentin Clement           rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(
1066044d5b5dSValentin Clement               insertOp, seqTyAttr, denseAttr);
1067044d5b5dSValentin Clement         }
1068044d5b5dSValentin Clement       }
1069044d5b5dSValentin Clement     }
1070044d5b5dSValentin Clement     rewriter.eraseOp(global);
1071044d5b5dSValentin Clement     return success();
1072044d5b5dSValentin Clement   }
1073044d5b5dSValentin Clement 
10748ec0f221SMehdi Amini   bool isFullRange(mlir::DenseIntElementsAttr indexes,
10758ec0f221SMehdi Amini                    fir::SequenceType seqTy) const {
1076044d5b5dSValentin Clement     auto extents = seqTy.getShape();
10778ec0f221SMehdi Amini     if (indexes.size() / 2 != static_cast<int64_t>(extents.size()))
1078044d5b5dSValentin Clement       return false;
10798ec0f221SMehdi Amini     auto cur_index = indexes.value_begin<int64_t>();
1080044d5b5dSValentin Clement     for (unsigned i = 0; i < indexes.size(); i += 2) {
10818ec0f221SMehdi Amini       if (*(cur_index++) != 0)
1082044d5b5dSValentin Clement         return false;
10838ec0f221SMehdi Amini       if (*(cur_index++) != extents[i / 2] - 1)
1084044d5b5dSValentin Clement         return false;
1085044d5b5dSValentin Clement     }
1086044d5b5dSValentin Clement     return true;
1087044d5b5dSValentin Clement   }
1088044d5b5dSValentin Clement 
10890c4a7a52SValentin Clement   // TODO: String comparaison should be avoided. Replace linkName with an
10900c4a7a52SValentin Clement   // enumeration.
1091044d5b5dSValentin Clement   mlir::LLVM::Linkage convertLinkage(Optional<StringRef> optLinkage) const {
1092044d5b5dSValentin Clement     if (optLinkage.hasValue()) {
1093044d5b5dSValentin Clement       auto name = optLinkage.getValue();
1094044d5b5dSValentin Clement       if (name == "internal")
1095044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Internal;
1096044d5b5dSValentin Clement       if (name == "linkonce")
1097044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Linkonce;
1098044d5b5dSValentin Clement       if (name == "common")
1099044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Common;
1100044d5b5dSValentin Clement       if (name == "weak")
1101044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Weak;
1102044d5b5dSValentin Clement     }
1103044d5b5dSValentin Clement     return mlir::LLVM::Linkage::External;
1104044d5b5dSValentin Clement   }
1105044d5b5dSValentin Clement };
1106*c2acd453SAlexisPerry } // namespace
1107044d5b5dSValentin Clement 
1108*c2acd453SAlexisPerry static void genCondBrOp(mlir::Location loc, mlir::Value cmp, mlir::Block *dest,
110939f4ef81SValentin Clement                         Optional<mlir::ValueRange> destOps,
111039f4ef81SValentin Clement                         mlir::ConversionPatternRewriter &rewriter,
111139f4ef81SValentin Clement                         mlir::Block *newBlock) {
111239f4ef81SValentin Clement   if (destOps.hasValue())
111339f4ef81SValentin Clement     rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, destOps.getValue(),
111439f4ef81SValentin Clement                                           newBlock, mlir::ValueRange());
111539f4ef81SValentin Clement   else
111639f4ef81SValentin Clement     rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, newBlock);
111739f4ef81SValentin Clement }
111839f4ef81SValentin Clement 
111939f4ef81SValentin Clement template <typename A, typename B>
1120*c2acd453SAlexisPerry static void genBrOp(A caseOp, mlir::Block *dest, Optional<B> destOps,
112139f4ef81SValentin Clement                     mlir::ConversionPatternRewriter &rewriter) {
112239f4ef81SValentin Clement   if (destOps.hasValue())
112339f4ef81SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, destOps.getValue(),
112439f4ef81SValentin Clement                                                   dest);
112539f4ef81SValentin Clement   else
112639f4ef81SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, llvm::None, dest);
112739f4ef81SValentin Clement }
112839f4ef81SValentin Clement 
1129*c2acd453SAlexisPerry static void genCaseLadderStep(mlir::Location loc, mlir::Value cmp,
1130*c2acd453SAlexisPerry                               mlir::Block *dest,
113139f4ef81SValentin Clement                               Optional<mlir::ValueRange> destOps,
113239f4ef81SValentin Clement                               mlir::ConversionPatternRewriter &rewriter) {
113339f4ef81SValentin Clement   auto *thisBlock = rewriter.getInsertionBlock();
113439f4ef81SValentin Clement   auto *newBlock = createBlock(rewriter, dest);
113539f4ef81SValentin Clement   rewriter.setInsertionPointToEnd(thisBlock);
113639f4ef81SValentin Clement   genCondBrOp(loc, cmp, dest, destOps, rewriter, newBlock);
113739f4ef81SValentin Clement   rewriter.setInsertionPointToEnd(newBlock);
113839f4ef81SValentin Clement }
113939f4ef81SValentin Clement 
1140*c2acd453SAlexisPerry namespace {
114139f4ef81SValentin Clement /// Conversion of `fir.select_case`
114239f4ef81SValentin Clement ///
114339f4ef81SValentin Clement /// The `fir.select_case` operation is converted to a if-then-else ladder.
114439f4ef81SValentin Clement /// Depending on the case condition type, one or several comparison and
114539f4ef81SValentin Clement /// conditional branching can be generated.
114639f4ef81SValentin Clement ///
114739f4ef81SValentin Clement /// A a point value case such as `case(4)`, a lower bound case such as
114839f4ef81SValentin Clement /// `case(5:)` or an upper bound case such as `case(:3)` are converted to a
114939f4ef81SValentin Clement /// simple comparison between the selector value and the constant value in the
115039f4ef81SValentin Clement /// case. The block associated with the case condition is then executed if
115139f4ef81SValentin Clement /// the comparison succeed otherwise it branch to the next block with the
115239f4ef81SValentin Clement /// comparison for the the next case conditon.
115339f4ef81SValentin Clement ///
115439f4ef81SValentin Clement /// A closed interval case condition such as `case(7:10)` is converted with a
115539f4ef81SValentin Clement /// first comparison and conditional branching for the lower bound. If
115639f4ef81SValentin Clement /// successful, it branch to a second block with the comparison for the
115739f4ef81SValentin Clement /// upper bound in the same case condition.
115839f4ef81SValentin Clement ///
115939f4ef81SValentin Clement /// TODO: lowering of CHARACTER type cases is not handled yet.
116039f4ef81SValentin Clement struct SelectCaseOpConversion : public FIROpConversion<fir::SelectCaseOp> {
116139f4ef81SValentin Clement   using FIROpConversion::FIROpConversion;
116239f4ef81SValentin Clement 
116339f4ef81SValentin Clement   mlir::LogicalResult
116439f4ef81SValentin Clement   matchAndRewrite(fir::SelectCaseOp caseOp, OpAdaptor adaptor,
116539f4ef81SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
116639f4ef81SValentin Clement     unsigned conds = caseOp.getNumConditions();
116739f4ef81SValentin Clement     llvm::ArrayRef<mlir::Attribute> cases = caseOp.getCases().getValue();
116839f4ef81SValentin Clement     // Type can be CHARACTER, INTEGER, or LOGICAL (C1145)
11697ce8c6fcSKiran Chandramohan     auto ty = caseOp.getSelector().getType();
11707ce8c6fcSKiran Chandramohan     if (ty.isa<fir::CharacterType>()) {
11717ce8c6fcSKiran Chandramohan       TODO(caseOp.getLoc(), "fir.select_case codegen with character type");
11727ce8c6fcSKiran Chandramohan       return failure();
11737ce8c6fcSKiran Chandramohan     }
117439f4ef81SValentin Clement     mlir::Value selector = caseOp.getSelector(adaptor.getOperands());
117539f4ef81SValentin Clement     auto loc = caseOp.getLoc();
117639f4ef81SValentin Clement     for (unsigned t = 0; t != conds; ++t) {
117739f4ef81SValentin Clement       mlir::Block *dest = caseOp.getSuccessor(t);
117839f4ef81SValentin Clement       llvm::Optional<mlir::ValueRange> destOps =
117939f4ef81SValentin Clement           caseOp.getSuccessorOperands(adaptor.getOperands(), t);
118039f4ef81SValentin Clement       llvm::Optional<mlir::ValueRange> cmpOps =
118139f4ef81SValentin Clement           *caseOp.getCompareOperands(adaptor.getOperands(), t);
118239f4ef81SValentin Clement       mlir::Value caseArg = *(cmpOps.getValue().begin());
118339f4ef81SValentin Clement       mlir::Attribute attr = cases[t];
118439f4ef81SValentin Clement       if (attr.isa<fir::PointIntervalAttr>()) {
118539f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
118639f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::eq, selector, caseArg);
118739f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
118839f4ef81SValentin Clement         continue;
118939f4ef81SValentin Clement       }
119039f4ef81SValentin Clement       if (attr.isa<fir::LowerBoundAttr>()) {
119139f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
119239f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector);
119339f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
119439f4ef81SValentin Clement         continue;
119539f4ef81SValentin Clement       }
119639f4ef81SValentin Clement       if (attr.isa<fir::UpperBoundAttr>()) {
119739f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
119839f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg);
119939f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
120039f4ef81SValentin Clement         continue;
120139f4ef81SValentin Clement       }
120239f4ef81SValentin Clement       if (attr.isa<fir::ClosedIntervalAttr>()) {
120339f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
120439f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector);
120539f4ef81SValentin Clement         auto *thisBlock = rewriter.getInsertionBlock();
120639f4ef81SValentin Clement         auto *newBlock1 = createBlock(rewriter, dest);
120739f4ef81SValentin Clement         auto *newBlock2 = createBlock(rewriter, dest);
120839f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(thisBlock);
120939f4ef81SValentin Clement         rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, newBlock1, newBlock2);
121039f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(newBlock1);
121139f4ef81SValentin Clement         mlir::Value caseArg0 = *(cmpOps.getValue().begin() + 1);
121239f4ef81SValentin Clement         auto cmp0 = rewriter.create<mlir::LLVM::ICmpOp>(
121339f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg0);
121439f4ef81SValentin Clement         genCondBrOp(loc, cmp0, dest, destOps, rewriter, newBlock2);
121539f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(newBlock2);
121639f4ef81SValentin Clement         continue;
121739f4ef81SValentin Clement       }
121839f4ef81SValentin Clement       assert(attr.isa<mlir::UnitAttr>());
121939f4ef81SValentin Clement       assert((t + 1 == conds) && "unit must be last");
122039f4ef81SValentin Clement       genBrOp(caseOp, dest, destOps, rewriter);
122139f4ef81SValentin Clement     }
122239f4ef81SValentin Clement     return success();
122339f4ef81SValentin Clement   }
122439f4ef81SValentin Clement };
1225*c2acd453SAlexisPerry } // namespace
122639f4ef81SValentin Clement 
12278c239909SValentin Clement template <typename OP>
1228*c2acd453SAlexisPerry static void selectMatchAndRewrite(fir::LLVMTypeConverter &lowering, OP select,
12298c239909SValentin Clement                                   typename OP::Adaptor adaptor,
12308c239909SValentin Clement                                   mlir::ConversionPatternRewriter &rewriter) {
12318c239909SValentin Clement   unsigned conds = select.getNumConditions();
12328c239909SValentin Clement   auto cases = select.getCases().getValue();
12338c239909SValentin Clement   mlir::Value selector = adaptor.selector();
12348c239909SValentin Clement   auto loc = select.getLoc();
12358c239909SValentin Clement   assert(conds > 0 && "select must have cases");
12368c239909SValentin Clement 
12378c239909SValentin Clement   llvm::SmallVector<mlir::Block *> destinations;
12388c239909SValentin Clement   llvm::SmallVector<mlir::ValueRange> destinationsOperands;
12398c239909SValentin Clement   mlir::Block *defaultDestination;
12408c239909SValentin Clement   mlir::ValueRange defaultOperands;
12418c239909SValentin Clement   llvm::SmallVector<int32_t> caseValues;
12428c239909SValentin Clement 
12438c239909SValentin Clement   for (unsigned t = 0; t != conds; ++t) {
12448c239909SValentin Clement     mlir::Block *dest = select.getSuccessor(t);
12458c239909SValentin Clement     auto destOps = select.getSuccessorOperands(adaptor.getOperands(), t);
12468c239909SValentin Clement     const mlir::Attribute &attr = cases[t];
12478c239909SValentin Clement     if (auto intAttr = attr.template dyn_cast<mlir::IntegerAttr>()) {
12488c239909SValentin Clement       destinations.push_back(dest);
12498c239909SValentin Clement       destinationsOperands.push_back(destOps.hasValue() ? *destOps
12508c239909SValentin Clement                                                         : ValueRange());
12518c239909SValentin Clement       caseValues.push_back(intAttr.getInt());
12528c239909SValentin Clement       continue;
12538c239909SValentin Clement     }
12548c239909SValentin Clement     assert(attr.template dyn_cast_or_null<mlir::UnitAttr>());
12558c239909SValentin Clement     assert((t + 1 == conds) && "unit must be last");
12568c239909SValentin Clement     defaultDestination = dest;
12578c239909SValentin Clement     defaultOperands = destOps.hasValue() ? *destOps : ValueRange();
12588c239909SValentin Clement   }
12598c239909SValentin Clement 
12608c239909SValentin Clement   // LLVM::SwitchOp takes a i32 type for the selector.
12618c239909SValentin Clement   if (select.getSelector().getType() != rewriter.getI32Type())
12628c239909SValentin Clement     selector =
12638c239909SValentin Clement         rewriter.create<LLVM::TruncOp>(loc, rewriter.getI32Type(), selector);
12648c239909SValentin Clement 
12658c239909SValentin Clement   rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>(
12668c239909SValentin Clement       select, selector,
12678c239909SValentin Clement       /*defaultDestination=*/defaultDestination,
12688c239909SValentin Clement       /*defaultOperands=*/defaultOperands,
12698c239909SValentin Clement       /*caseValues=*/caseValues,
12708c239909SValentin Clement       /*caseDestinations=*/destinations,
12718c239909SValentin Clement       /*caseOperands=*/destinationsOperands,
12728c239909SValentin Clement       /*branchWeights=*/ArrayRef<int32_t>());
12738c239909SValentin Clement }
12748c239909SValentin Clement 
1275*c2acd453SAlexisPerry namespace {
12768c239909SValentin Clement /// conversion of fir::SelectOp to an if-then-else ladder
12778c239909SValentin Clement struct SelectOpConversion : public FIROpConversion<fir::SelectOp> {
12788c239909SValentin Clement   using FIROpConversion::FIROpConversion;
12798c239909SValentin Clement 
12808c239909SValentin Clement   mlir::LogicalResult
12818c239909SValentin Clement   matchAndRewrite(fir::SelectOp op, OpAdaptor adaptor,
12828c239909SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
12838c239909SValentin Clement     selectMatchAndRewrite<fir::SelectOp>(lowerTy(), op, adaptor, rewriter);
12848c239909SValentin Clement     return success();
12858c239909SValentin Clement   }
12868c239909SValentin Clement };
12878c239909SValentin Clement 
1288e3349fa1SAndrzej Warzynski /// `fir.load` --> `llvm.load`
1289e3349fa1SAndrzej Warzynski struct LoadOpConversion : public FIROpConversion<fir::LoadOp> {
1290e3349fa1SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
1291e3349fa1SAndrzej Warzynski 
1292e3349fa1SAndrzej Warzynski   mlir::LogicalResult
1293e3349fa1SAndrzej Warzynski   matchAndRewrite(fir::LoadOp load, OpAdaptor adaptor,
1294e3349fa1SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
1295e3349fa1SAndrzej Warzynski     // fir.box is a special case because it is considered as an ssa values in
1296e3349fa1SAndrzej Warzynski     // fir, but it is lowered as a pointer to a descriptor. So fir.ref<fir.box>
1297e3349fa1SAndrzej Warzynski     // and fir.box end up being the same llvm types and loading a
1298e3349fa1SAndrzej Warzynski     // fir.ref<fir.box> is actually a no op in LLVM.
1299e3349fa1SAndrzej Warzynski     if (load.getType().isa<fir::BoxType>()) {
1300e3349fa1SAndrzej Warzynski       rewriter.replaceOp(load, adaptor.getOperands()[0]);
1301e3349fa1SAndrzej Warzynski     } else {
1302e3349fa1SAndrzej Warzynski       mlir::Type ty = convertType(load.getType());
1303e3349fa1SAndrzej Warzynski       ArrayRef<NamedAttribute> at = load->getAttrs();
1304e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::LoadOp>(
1305e3349fa1SAndrzej Warzynski           load, ty, adaptor.getOperands(), at);
1306e3349fa1SAndrzej Warzynski     }
1307e3349fa1SAndrzej Warzynski     return success();
1308e3349fa1SAndrzej Warzynski   }
1309e3349fa1SAndrzej Warzynski };
1310e3349fa1SAndrzej Warzynski 
1311b8207db7SValentin Clement /// Lower `fir.no_reassoc` to LLVM IR dialect.
1312b8207db7SValentin Clement /// TODO: how do we want to enforce this in LLVM-IR? Can we manipulate the fast
1313b8207db7SValentin Clement /// math flags?
1314b8207db7SValentin Clement struct NoReassocOpConversion : public FIROpConversion<fir::NoReassocOp> {
1315b8207db7SValentin Clement   using FIROpConversion::FIROpConversion;
1316b8207db7SValentin Clement 
1317b8207db7SValentin Clement   mlir::LogicalResult
1318b8207db7SValentin Clement   matchAndRewrite(fir::NoReassocOp noreassoc, OpAdaptor adaptor,
1319b8207db7SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1320b8207db7SValentin Clement     rewriter.replaceOp(noreassoc, adaptor.getOperands()[0]);
1321b8207db7SValentin Clement     return success();
1322b8207db7SValentin Clement   }
1323b8207db7SValentin Clement };
1324b8207db7SValentin Clement 
13252a299e4fSValentin Clement /// Lower `fir.select_type` to LLVM IR dialect.
13262a299e4fSValentin Clement struct SelectTypeOpConversion : public FIROpConversion<fir::SelectTypeOp> {
13272a299e4fSValentin Clement   using FIROpConversion::FIROpConversion;
13282a299e4fSValentin Clement 
13292a299e4fSValentin Clement   mlir::LogicalResult
13302a299e4fSValentin Clement   matchAndRewrite(fir::SelectTypeOp select, OpAdaptor adaptor,
13312a299e4fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
13327ce8c6fcSKiran Chandramohan     mlir::emitError(select.getLoc(),
13337ce8c6fcSKiran Chandramohan                     "fir.select_type should have already been converted");
13347ce8c6fcSKiran Chandramohan     return failure();
13352a299e4fSValentin Clement   }
13362a299e4fSValentin Clement };
13372a299e4fSValentin Clement 
13388c239909SValentin Clement /// conversion of fir::SelectRankOp to an if-then-else ladder
13398c239909SValentin Clement struct SelectRankOpConversion : public FIROpConversion<fir::SelectRankOp> {
13408c239909SValentin Clement   using FIROpConversion::FIROpConversion;
13418c239909SValentin Clement 
13428c239909SValentin Clement   mlir::LogicalResult
13438c239909SValentin Clement   matchAndRewrite(fir::SelectRankOp op, OpAdaptor adaptor,
13448c239909SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
13458c239909SValentin Clement     selectMatchAndRewrite<fir::SelectRankOp>(lowerTy(), op, adaptor, rewriter);
13468c239909SValentin Clement     return success();
13478c239909SValentin Clement   }
13488c239909SValentin Clement };
13498c239909SValentin Clement 
1350e3349fa1SAndrzej Warzynski /// `fir.store` --> `llvm.store`
1351e3349fa1SAndrzej Warzynski struct StoreOpConversion : public FIROpConversion<fir::StoreOp> {
1352e3349fa1SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
1353e3349fa1SAndrzej Warzynski 
1354e3349fa1SAndrzej Warzynski   mlir::LogicalResult
1355e3349fa1SAndrzej Warzynski   matchAndRewrite(fir::StoreOp store, OpAdaptor adaptor,
1356e3349fa1SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
1357e3349fa1SAndrzej Warzynski     if (store.value().getType().isa<fir::BoxType>()) {
1358e3349fa1SAndrzej Warzynski       // fir.box value is actually in memory, load it first before storing it.
1359e3349fa1SAndrzej Warzynski       mlir::Location loc = store.getLoc();
1360e3349fa1SAndrzej Warzynski       mlir::Type boxPtrTy = adaptor.getOperands()[0].getType();
1361e3349fa1SAndrzej Warzynski       auto val = rewriter.create<mlir::LLVM::LoadOp>(
1362e3349fa1SAndrzej Warzynski           loc, boxPtrTy.cast<mlir::LLVM::LLVMPointerType>().getElementType(),
1363e3349fa1SAndrzej Warzynski           adaptor.getOperands()[0]);
1364e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
1365e3349fa1SAndrzej Warzynski           store, val, adaptor.getOperands()[1]);
1366e3349fa1SAndrzej Warzynski     } else {
1367e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
1368e3349fa1SAndrzej Warzynski           store, adaptor.getOperands()[0], adaptor.getOperands()[1]);
1369e3349fa1SAndrzej Warzynski     }
1370e3349fa1SAndrzej Warzynski     return success();
1371e3349fa1SAndrzej Warzynski   }
1372e3349fa1SAndrzej Warzynski };
1373e3349fa1SAndrzej Warzynski 
1374e3349fa1SAndrzej Warzynski /// convert to LLVM IR dialect `undef`
1375044d5b5dSValentin Clement struct UndefOpConversion : public FIROpConversion<fir::UndefOp> {
1376044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
1377044d5b5dSValentin Clement 
1378044d5b5dSValentin Clement   mlir::LogicalResult
1379044d5b5dSValentin Clement   matchAndRewrite(fir::UndefOp undef, OpAdaptor,
1380044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1381044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::UndefOp>(
1382044d5b5dSValentin Clement         undef, convertType(undef.getType()));
1383044d5b5dSValentin Clement     return success();
1384044d5b5dSValentin Clement   }
1385044d5b5dSValentin Clement };
1386a7a61359SValentin Clement 
1387e3349fa1SAndrzej Warzynski /// `fir.unreachable` --> `llvm.unreachable`
138832e08248SAndrzej Warzynski struct UnreachableOpConversion : public FIROpConversion<fir::UnreachableOp> {
138932e08248SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
139032e08248SAndrzej Warzynski 
139132e08248SAndrzej Warzynski   mlir::LogicalResult
139232e08248SAndrzej Warzynski   matchAndRewrite(fir::UnreachableOp unreach, OpAdaptor adaptor,
139332e08248SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
139432e08248SAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(unreach);
139532e08248SAndrzej Warzynski     return success();
139632e08248SAndrzej Warzynski   }
139732e08248SAndrzej Warzynski };
139832e08248SAndrzej Warzynski 
1399a7a61359SValentin Clement struct ZeroOpConversion : public FIROpConversion<fir::ZeroOp> {
1400a7a61359SValentin Clement   using FIROpConversion::FIROpConversion;
1401a7a61359SValentin Clement 
1402a7a61359SValentin Clement   mlir::LogicalResult
1403a7a61359SValentin Clement   matchAndRewrite(fir::ZeroOp zero, OpAdaptor,
1404a7a61359SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
14057ce8c6fcSKiran Chandramohan     mlir::Type ty = convertType(zero.getType());
1406a7a61359SValentin Clement     if (ty.isa<mlir::LLVM::LLVMPointerType>()) {
1407a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(zero, ty);
1408a7a61359SValentin Clement     } else if (ty.isa<mlir::IntegerType>()) {
1409a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
1410a7a61359SValentin Clement           zero, ty, mlir::IntegerAttr::get(zero.getType(), 0));
1411a7a61359SValentin Clement     } else if (mlir::LLVM::isCompatibleFloatingPointType(ty)) {
1412a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
1413a7a61359SValentin Clement           zero, ty, mlir::FloatAttr::get(zero.getType(), 0.0));
1414a7a61359SValentin Clement     } else {
1415a7a61359SValentin Clement       // TODO: create ConstantAggregateZero for FIR aggregate/array types.
141652d813edSValentin Clement       return rewriter.notifyMatchFailure(
141752d813edSValentin Clement           zero,
1418a7a61359SValentin Clement           "conversion of fir.zero with aggregate type not implemented yet");
1419a7a61359SValentin Clement     }
1420a7a61359SValentin Clement     return success();
1421a7a61359SValentin Clement   }
1422a7a61359SValentin Clement };
1423*c2acd453SAlexisPerry } // namespace
142432e08248SAndrzej Warzynski 
1425af6ee580SValentin Clement /// Common base class for embox to descriptor conversion.
1426af6ee580SValentin Clement template <typename OP>
1427af6ee580SValentin Clement struct EmboxCommonConversion : public FIROpConversion<OP> {
1428af6ee580SValentin Clement   using FIROpConversion<OP>::FIROpConversion;
1429af6ee580SValentin Clement 
1430af6ee580SValentin Clement   // Find the LLVMFuncOp in whose entry block the alloca should be inserted.
1431af6ee580SValentin Clement   // The order to find the LLVMFuncOp is as follows:
1432af6ee580SValentin Clement   // 1. The parent operation of the current block if it is a LLVMFuncOp.
1433af6ee580SValentin Clement   // 2. The first ancestor that is a LLVMFuncOp.
1434af6ee580SValentin Clement   mlir::LLVM::LLVMFuncOp
1435af6ee580SValentin Clement   getFuncForAllocaInsert(mlir::ConversionPatternRewriter &rewriter) const {
1436af6ee580SValentin Clement     mlir::Operation *parentOp = rewriter.getInsertionBlock()->getParentOp();
1437af6ee580SValentin Clement     return mlir::isa<mlir::LLVM::LLVMFuncOp>(parentOp)
1438af6ee580SValentin Clement                ? mlir::cast<mlir::LLVM::LLVMFuncOp>(parentOp)
1439af6ee580SValentin Clement                : parentOp->getParentOfType<mlir::LLVM::LLVMFuncOp>();
1440af6ee580SValentin Clement   }
1441af6ee580SValentin Clement 
1442af6ee580SValentin Clement   // Generate an alloca of size 1 and type \p toTy.
1443af6ee580SValentin Clement   mlir::LLVM::AllocaOp
1444af6ee580SValentin Clement   genAllocaWithType(mlir::Location loc, mlir::Type toTy, unsigned alignment,
1445af6ee580SValentin Clement                     mlir::ConversionPatternRewriter &rewriter) const {
1446af6ee580SValentin Clement     auto thisPt = rewriter.saveInsertionPoint();
1447af6ee580SValentin Clement     mlir::LLVM::LLVMFuncOp func = getFuncForAllocaInsert(rewriter);
1448af6ee580SValentin Clement     rewriter.setInsertionPointToStart(&func.front());
1449af6ee580SValentin Clement     auto size = this->genI32Constant(loc, rewriter, 1);
1450af6ee580SValentin Clement     auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, toTy, size, alignment);
1451af6ee580SValentin Clement     rewriter.restoreInsertionPoint(thisPt);
1452af6ee580SValentin Clement     return al;
1453af6ee580SValentin Clement   }
1454af6ee580SValentin Clement 
1455af6ee580SValentin Clement   static int getCFIAttr(fir::BoxType boxTy) {
1456af6ee580SValentin Clement     auto eleTy = boxTy.getEleTy();
1457af6ee580SValentin Clement     if (eleTy.isa<fir::PointerType>())
1458af6ee580SValentin Clement       return CFI_attribute_pointer;
1459af6ee580SValentin Clement     if (eleTy.isa<fir::HeapType>())
1460af6ee580SValentin Clement       return CFI_attribute_allocatable;
1461af6ee580SValentin Clement     return CFI_attribute_other;
1462af6ee580SValentin Clement   }
1463af6ee580SValentin Clement 
1464af6ee580SValentin Clement   static fir::RecordType unwrapIfDerived(fir::BoxType boxTy) {
1465af6ee580SValentin Clement     return fir::unwrapSequenceType(fir::dyn_cast_ptrOrBoxEleTy(boxTy))
1466af6ee580SValentin Clement         .template dyn_cast<fir::RecordType>();
1467af6ee580SValentin Clement   }
1468af6ee580SValentin Clement   static bool isDerivedTypeWithLenParams(fir::BoxType boxTy) {
1469af6ee580SValentin Clement     auto recTy = unwrapIfDerived(boxTy);
1470af6ee580SValentin Clement     return recTy && recTy.getNumLenParams() > 0;
1471af6ee580SValentin Clement   }
1472af6ee580SValentin Clement   static bool isDerivedType(fir::BoxType boxTy) {
1473af6ee580SValentin Clement     return unwrapIfDerived(boxTy) != nullptr;
1474af6ee580SValentin Clement   }
1475af6ee580SValentin Clement 
1476af6ee580SValentin Clement   // Get the element size and CFI type code of the boxed value.
1477af6ee580SValentin Clement   std::tuple<mlir::Value, mlir::Value> getSizeAndTypeCode(
1478af6ee580SValentin Clement       mlir::Location loc, mlir::ConversionPatternRewriter &rewriter,
1479af6ee580SValentin Clement       mlir::Type boxEleTy, mlir::ValueRange lenParams = {}) const {
1480af6ee580SValentin Clement     auto doInteger =
1481af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1482af6ee580SValentin Clement       int typeCode = fir::integerBitsToTypeCode(width);
1483af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1484af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1485af6ee580SValentin Clement     };
1486af6ee580SValentin Clement     auto doLogical =
1487af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1488af6ee580SValentin Clement       int typeCode = fir::logicalBitsToTypeCode(width);
1489af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1490af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1491af6ee580SValentin Clement     };
1492af6ee580SValentin Clement     auto doFloat = [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1493af6ee580SValentin Clement       int typeCode = fir::realBitsToTypeCode(width);
1494af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1495af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1496af6ee580SValentin Clement     };
1497af6ee580SValentin Clement     auto doComplex =
1498af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1499af6ee580SValentin Clement       auto typeCode = fir::complexBitsToTypeCode(width);
1500af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8 * 2),
1501af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1502af6ee580SValentin Clement     };
1503af6ee580SValentin Clement     auto doCharacter =
1504af6ee580SValentin Clement         [&](unsigned width,
1505af6ee580SValentin Clement             mlir::Value len) -> std::tuple<mlir::Value, mlir::Value> {
1506af6ee580SValentin Clement       auto typeCode = fir::characterBitsToTypeCode(width);
1507af6ee580SValentin Clement       auto typeCodeVal = this->genConstantOffset(loc, rewriter, typeCode);
1508af6ee580SValentin Clement       if (width == 8)
1509af6ee580SValentin Clement         return {len, typeCodeVal};
1510af6ee580SValentin Clement       auto byteWidth = this->genConstantOffset(loc, rewriter, width / 8);
1511af6ee580SValentin Clement       auto i64Ty = mlir::IntegerType::get(&this->lowerTy().getContext(), 64);
1512af6ee580SValentin Clement       auto size =
1513af6ee580SValentin Clement           rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, byteWidth, len);
1514af6ee580SValentin Clement       return {size, typeCodeVal};
1515af6ee580SValentin Clement     };
1516af6ee580SValentin Clement     auto getKindMap = [&]() -> fir::KindMapping & {
1517af6ee580SValentin Clement       return this->lowerTy().getKindMap();
1518af6ee580SValentin Clement     };
1519af6ee580SValentin Clement     // Pointer-like types.
1520af6ee580SValentin Clement     if (auto eleTy = fir::dyn_cast_ptrEleTy(boxEleTy))
1521af6ee580SValentin Clement       boxEleTy = eleTy;
1522af6ee580SValentin Clement     // Integer types.
1523af6ee580SValentin Clement     if (fir::isa_integer(boxEleTy)) {
1524af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::IntegerType>())
1525af6ee580SValentin Clement         return doInteger(ty.getWidth());
1526af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::IntegerType>();
1527af6ee580SValentin Clement       return doInteger(getKindMap().getIntegerBitsize(ty.getFKind()));
1528af6ee580SValentin Clement     }
1529af6ee580SValentin Clement     // Floating point types.
1530af6ee580SValentin Clement     if (fir::isa_real(boxEleTy)) {
1531af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::FloatType>())
1532af6ee580SValentin Clement         return doFloat(ty.getWidth());
1533af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::RealType>();
1534af6ee580SValentin Clement       return doFloat(getKindMap().getRealBitsize(ty.getFKind()));
1535af6ee580SValentin Clement     }
1536af6ee580SValentin Clement     // Complex types.
1537af6ee580SValentin Clement     if (fir::isa_complex(boxEleTy)) {
1538af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::ComplexType>())
1539af6ee580SValentin Clement         return doComplex(
1540af6ee580SValentin Clement             ty.getElementType().cast<mlir::FloatType>().getWidth());
1541af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::ComplexType>();
1542af6ee580SValentin Clement       return doComplex(getKindMap().getRealBitsize(ty.getFKind()));
1543af6ee580SValentin Clement     }
1544af6ee580SValentin Clement     // Character types.
1545af6ee580SValentin Clement     if (auto ty = boxEleTy.dyn_cast<fir::CharacterType>()) {
1546af6ee580SValentin Clement       auto charWidth = getKindMap().getCharacterBitsize(ty.getFKind());
1547af6ee580SValentin Clement       if (ty.getLen() != fir::CharacterType::unknownLen()) {
1548af6ee580SValentin Clement         auto len = this->genConstantOffset(loc, rewriter, ty.getLen());
1549af6ee580SValentin Clement         return doCharacter(charWidth, len);
1550af6ee580SValentin Clement       }
1551af6ee580SValentin Clement       assert(!lenParams.empty());
1552af6ee580SValentin Clement       return doCharacter(charWidth, lenParams.back());
1553af6ee580SValentin Clement     }
1554af6ee580SValentin Clement     // Logical type.
1555af6ee580SValentin Clement     if (auto ty = boxEleTy.dyn_cast<fir::LogicalType>())
1556af6ee580SValentin Clement       return doLogical(getKindMap().getLogicalBitsize(ty.getFKind()));
1557af6ee580SValentin Clement     // Array types.
1558af6ee580SValentin Clement     if (auto seqTy = boxEleTy.dyn_cast<fir::SequenceType>())
1559af6ee580SValentin Clement       return getSizeAndTypeCode(loc, rewriter, seqTy.getEleTy(), lenParams);
1560af6ee580SValentin Clement     // Derived-type types.
1561af6ee580SValentin Clement     if (boxEleTy.isa<fir::RecordType>()) {
1562af6ee580SValentin Clement       auto ptrTy = mlir::LLVM::LLVMPointerType::get(
1563af6ee580SValentin Clement           this->lowerTy().convertType(boxEleTy));
1564af6ee580SValentin Clement       auto nullPtr = rewriter.create<mlir::LLVM::NullOp>(loc, ptrTy);
1565af6ee580SValentin Clement       auto one =
1566af6ee580SValentin Clement           genConstantIndex(loc, this->lowerTy().offsetType(), rewriter, 1);
1567af6ee580SValentin Clement       auto gep = rewriter.create<mlir::LLVM::GEPOp>(
1568af6ee580SValentin Clement           loc, ptrTy, mlir::ValueRange{nullPtr, one});
1569af6ee580SValentin Clement       auto eleSize = rewriter.create<mlir::LLVM::PtrToIntOp>(
1570af6ee580SValentin Clement           loc, this->lowerTy().indexType(), gep);
1571af6ee580SValentin Clement       return {eleSize,
1572af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, fir::derivedToTypeCode())};
1573af6ee580SValentin Clement     }
1574af6ee580SValentin Clement     // Reference type.
1575af6ee580SValentin Clement     if (fir::isa_ref_type(boxEleTy)) {
1576af6ee580SValentin Clement       // FIXME: use the target pointer size rather than sizeof(void*)
1577af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, sizeof(void *)),
1578af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, CFI_type_cptr)};
1579af6ee580SValentin Clement     }
1580af6ee580SValentin Clement     fir::emitFatalError(loc, "unhandled type in fir.box code generation");
1581af6ee580SValentin Clement   }
1582af6ee580SValentin Clement 
1583af6ee580SValentin Clement   /// Basic pattern to write a field in the descriptor
1584af6ee580SValentin Clement   mlir::Value insertField(mlir::ConversionPatternRewriter &rewriter,
1585af6ee580SValentin Clement                           mlir::Location loc, mlir::Value dest,
1586af6ee580SValentin Clement                           ArrayRef<unsigned> fldIndexes, mlir::Value value,
1587af6ee580SValentin Clement                           bool bitcast = false) const {
1588af6ee580SValentin Clement     auto boxTy = dest.getType();
1589af6ee580SValentin Clement     auto fldTy = this->getBoxEleTy(boxTy, fldIndexes);
1590af6ee580SValentin Clement     if (bitcast)
1591af6ee580SValentin Clement       value = rewriter.create<mlir::LLVM::BitcastOp>(loc, fldTy, value);
1592af6ee580SValentin Clement     else
1593af6ee580SValentin Clement       value = this->integerCast(loc, rewriter, fldTy, value);
1594af6ee580SValentin Clement     SmallVector<mlir::Attribute, 2> attrs;
1595af6ee580SValentin Clement     for (auto i : fldIndexes)
1596af6ee580SValentin Clement       attrs.push_back(rewriter.getI32IntegerAttr(i));
1597af6ee580SValentin Clement     auto indexesAttr = mlir::ArrayAttr::get(rewriter.getContext(), attrs);
1598af6ee580SValentin Clement     return rewriter.create<mlir::LLVM::InsertValueOp>(loc, boxTy, dest, value,
1599af6ee580SValentin Clement                                                       indexesAttr);
1600af6ee580SValentin Clement   }
1601af6ee580SValentin Clement 
1602af6ee580SValentin Clement   inline mlir::Value
1603af6ee580SValentin Clement   insertBaseAddress(mlir::ConversionPatternRewriter &rewriter,
1604af6ee580SValentin Clement                     mlir::Location loc, mlir::Value dest,
1605af6ee580SValentin Clement                     mlir::Value base) const {
16061f551032SValentin Clement     return insertField(rewriter, loc, dest, {kAddrPosInBox}, base,
16071f551032SValentin Clement                        /*bitCast=*/true);
16081f551032SValentin Clement   }
16091f551032SValentin Clement 
16101f551032SValentin Clement   inline mlir::Value insertLowerBound(mlir::ConversionPatternRewriter &rewriter,
16111f551032SValentin Clement                                       mlir::Location loc, mlir::Value dest,
16121f551032SValentin Clement                                       unsigned dim, mlir::Value lb) const {
16131f551032SValentin Clement     return insertField(rewriter, loc, dest,
16141f551032SValentin Clement                        {kDimsPosInBox, dim, kDimLowerBoundPos}, lb);
16151f551032SValentin Clement   }
16161f551032SValentin Clement 
16171f551032SValentin Clement   inline mlir::Value insertExtent(mlir::ConversionPatternRewriter &rewriter,
16181f551032SValentin Clement                                   mlir::Location loc, mlir::Value dest,
16191f551032SValentin Clement                                   unsigned dim, mlir::Value extent) const {
16201f551032SValentin Clement     return insertField(rewriter, loc, dest, {kDimsPosInBox, dim, kDimExtentPos},
16211f551032SValentin Clement                        extent);
16221f551032SValentin Clement   }
16231f551032SValentin Clement 
16241f551032SValentin Clement   inline mlir::Value insertStride(mlir::ConversionPatternRewriter &rewriter,
16251f551032SValentin Clement                                   mlir::Location loc, mlir::Value dest,
16261f551032SValentin Clement                                   unsigned dim, mlir::Value stride) const {
16271f551032SValentin Clement     return insertField(rewriter, loc, dest, {kDimsPosInBox, dim, kDimStridePos},
16281f551032SValentin Clement                        stride);
1629af6ee580SValentin Clement   }
1630af6ee580SValentin Clement 
1631af6ee580SValentin Clement   /// Get the address of the type descriptor global variable that was created by
1632af6ee580SValentin Clement   /// lowering for derived type \p recType.
1633af6ee580SValentin Clement   template <typename BOX>
1634af6ee580SValentin Clement   mlir::Value
1635af6ee580SValentin Clement   getTypeDescriptor(BOX box, mlir::ConversionPatternRewriter &rewriter,
1636af6ee580SValentin Clement                     mlir::Location loc, fir::RecordType recType) const {
1637af6ee580SValentin Clement     std::string name = recType.getLoweredName();
1638af6ee580SValentin Clement     auto module = box->template getParentOfType<mlir::ModuleOp>();
1639af6ee580SValentin Clement     if (auto global = module.template lookupSymbol<fir::GlobalOp>(name)) {
1640af6ee580SValentin Clement       auto ty = mlir::LLVM::LLVMPointerType::get(
1641af6ee580SValentin Clement           this->lowerTy().convertType(global.getType()));
1642af6ee580SValentin Clement       return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty,
1643af6ee580SValentin Clement                                                       global.sym_name());
1644af6ee580SValentin Clement     }
1645af6ee580SValentin Clement     if (auto global =
1646af6ee580SValentin Clement             module.template lookupSymbol<mlir::LLVM::GlobalOp>(name)) {
1647af6ee580SValentin Clement       // The global may have already been translated to LLVM.
1648af6ee580SValentin Clement       auto ty = mlir::LLVM::LLVMPointerType::get(global.getType());
1649af6ee580SValentin Clement       return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty,
1650af6ee580SValentin Clement                                                       global.sym_name());
1651af6ee580SValentin Clement     }
1652af6ee580SValentin Clement     // The global does not exist in the current translation unit, but may be
1653af6ee580SValentin Clement     // defined elsewhere (e.g., type defined in a module).
1654af6ee580SValentin Clement     // For now, create a extern_weak symbol (will become nullptr if unresolved)
1655af6ee580SValentin Clement     // to support generating code without the front-end generated symbols.
1656af6ee580SValentin Clement     // These could be made available_externally to require the symbols to be
1657af6ee580SValentin Clement     // defined elsewhere and to cause link-time failure otherwise.
1658af6ee580SValentin Clement     auto i8Ty = rewriter.getIntegerType(8);
1659af6ee580SValentin Clement     mlir::OpBuilder modBuilder(module.getBodyRegion());
1660af6ee580SValentin Clement     // TODO: The symbol should be lowered to constant in lowering, they are read
1661af6ee580SValentin Clement     // only.
1662af6ee580SValentin Clement     modBuilder.create<mlir::LLVM::GlobalOp>(loc, i8Ty, /*isConstant=*/false,
1663af6ee580SValentin Clement                                             mlir::LLVM::Linkage::ExternWeak,
1664af6ee580SValentin Clement                                             name, mlir::Attribute{});
1665af6ee580SValentin Clement     auto ty = mlir::LLVM::LLVMPointerType::get(i8Ty);
1666af6ee580SValentin Clement     return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty, name);
1667af6ee580SValentin Clement   }
1668af6ee580SValentin Clement 
1669af6ee580SValentin Clement   template <typename BOX>
1670af6ee580SValentin Clement   std::tuple<fir::BoxType, mlir::Value, mlir::Value>
1671af6ee580SValentin Clement   consDescriptorPrefix(BOX box, mlir::ConversionPatternRewriter &rewriter,
1672af6ee580SValentin Clement                        unsigned rank, mlir::ValueRange lenParams) const {
1673af6ee580SValentin Clement     auto loc = box.getLoc();
1674af6ee580SValentin Clement     auto boxTy = box.getType().template dyn_cast<fir::BoxType>();
1675af6ee580SValentin Clement     auto convTy = this->lowerTy().convertBoxType(boxTy, rank);
1676af6ee580SValentin Clement     auto llvmBoxPtrTy = convTy.template cast<mlir::LLVM::LLVMPointerType>();
1677af6ee580SValentin Clement     auto llvmBoxTy = llvmBoxPtrTy.getElementType();
1678af6ee580SValentin Clement     mlir::Value descriptor =
1679af6ee580SValentin Clement         rewriter.create<mlir::LLVM::UndefOp>(loc, llvmBoxTy);
1680af6ee580SValentin Clement 
1681af6ee580SValentin Clement     llvm::SmallVector<mlir::Value> typeparams = lenParams;
1682af6ee580SValentin Clement     if constexpr (!std::is_same_v<BOX, fir::EmboxOp>) {
1683af6ee580SValentin Clement       if (!box.substr().empty() && fir::hasDynamicSize(boxTy.getEleTy()))
1684af6ee580SValentin Clement         typeparams.push_back(box.substr()[1]);
1685af6ee580SValentin Clement     }
1686af6ee580SValentin Clement 
1687af6ee580SValentin Clement     // Write each of the fields with the appropriate values
1688af6ee580SValentin Clement     auto [eleSize, cfiTy] =
1689af6ee580SValentin Clement         getSizeAndTypeCode(loc, rewriter, boxTy.getEleTy(), typeparams);
1690af6ee580SValentin Clement     descriptor =
1691af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kElemLenPosInBox}, eleSize);
1692af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kVersionPosInBox},
1693af6ee580SValentin Clement                              this->genI32Constant(loc, rewriter, CFI_VERSION));
1694af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kRankPosInBox},
1695af6ee580SValentin Clement                              this->genI32Constant(loc, rewriter, rank));
1696af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kTypePosInBox}, cfiTy);
1697af6ee580SValentin Clement     descriptor =
1698af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kAttributePosInBox},
1699af6ee580SValentin Clement                     this->genI32Constant(loc, rewriter, getCFIAttr(boxTy)));
1700af6ee580SValentin Clement     const bool hasAddendum = isDerivedType(boxTy);
1701af6ee580SValentin Clement     descriptor =
1702af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kF18AddendumPosInBox},
1703af6ee580SValentin Clement                     this->genI32Constant(loc, rewriter, hasAddendum ? 1 : 0));
1704af6ee580SValentin Clement 
1705af6ee580SValentin Clement     if (hasAddendum) {
1706af6ee580SValentin Clement       auto isArray =
1707af6ee580SValentin Clement           fir::dyn_cast_ptrOrBoxEleTy(boxTy).template isa<fir::SequenceType>();
1708af6ee580SValentin Clement       unsigned typeDescFieldId = isArray ? kOptTypePtrPosInBox : kDimsPosInBox;
1709af6ee580SValentin Clement       auto typeDesc =
1710af6ee580SValentin Clement           getTypeDescriptor(box, rewriter, loc, unwrapIfDerived(boxTy));
1711af6ee580SValentin Clement       descriptor =
1712af6ee580SValentin Clement           insertField(rewriter, loc, descriptor, {typeDescFieldId}, typeDesc,
1713af6ee580SValentin Clement                       /*bitCast=*/true);
1714af6ee580SValentin Clement     }
1715af6ee580SValentin Clement 
1716af6ee580SValentin Clement     return {boxTy, descriptor, eleSize};
1717af6ee580SValentin Clement   }
1718af6ee580SValentin Clement 
17191f551032SValentin Clement   /// Compute the base address of a substring given the base address of a scalar
17201f551032SValentin Clement   /// string and the zero based string lower bound.
17211f551032SValentin Clement   mlir::Value shiftSubstringBase(mlir::ConversionPatternRewriter &rewriter,
17221f551032SValentin Clement                                  mlir::Location loc, mlir::Value base,
17231f551032SValentin Clement                                  mlir::Value lowerBound) const {
17241f551032SValentin Clement     llvm::SmallVector<mlir::Value> gepOperands;
17251f551032SValentin Clement     auto baseType =
17261f551032SValentin Clement         base.getType().cast<mlir::LLVM::LLVMPointerType>().getElementType();
17271f551032SValentin Clement     if (baseType.isa<mlir::LLVM::LLVMArrayType>()) {
17281f551032SValentin Clement       auto idxTy = this->lowerTy().indexType();
17291f551032SValentin Clement       mlir::Value zero = genConstantIndex(loc, idxTy, rewriter, 0);
17301f551032SValentin Clement       gepOperands.push_back(zero);
17311f551032SValentin Clement     }
17321f551032SValentin Clement     gepOperands.push_back(lowerBound);
17331f551032SValentin Clement     return this->genGEP(loc, base.getType(), rewriter, base, gepOperands);
17341f551032SValentin Clement   }
17351f551032SValentin Clement 
1736af6ee580SValentin Clement   /// If the embox is not in a globalOp body, allocate storage for the box;
1737af6ee580SValentin Clement   /// store the value inside and return the generated alloca. Return the input
1738af6ee580SValentin Clement   /// value otherwise.
1739af6ee580SValentin Clement   mlir::Value
1740af6ee580SValentin Clement   placeInMemoryIfNotGlobalInit(mlir::ConversionPatternRewriter &rewriter,
1741af6ee580SValentin Clement                                mlir::Location loc, mlir::Value boxValue) const {
1742af6ee580SValentin Clement     auto *thisBlock = rewriter.getInsertionBlock();
1743af6ee580SValentin Clement     if (thisBlock && mlir::isa<mlir::LLVM::GlobalOp>(thisBlock->getParentOp()))
1744af6ee580SValentin Clement       return boxValue;
1745af6ee580SValentin Clement     auto boxPtrTy = mlir::LLVM::LLVMPointerType::get(boxValue.getType());
1746af6ee580SValentin Clement     auto alloca = genAllocaWithType(loc, boxPtrTy, defaultAlign, rewriter);
1747af6ee580SValentin Clement     rewriter.create<mlir::LLVM::StoreOp>(loc, boxValue, alloca);
1748af6ee580SValentin Clement     return alloca;
1749af6ee580SValentin Clement   }
1750af6ee580SValentin Clement };
1751af6ee580SValentin Clement 
17521f551032SValentin Clement /// Compute the extent of a triplet slice (lb:ub:step).
17531f551032SValentin Clement static mlir::Value
17541f551032SValentin Clement computeTripletExtent(mlir::ConversionPatternRewriter &rewriter,
17551f551032SValentin Clement                      mlir::Location loc, mlir::Value lb, mlir::Value ub,
17561f551032SValentin Clement                      mlir::Value step, mlir::Value zero, mlir::Type type) {
17571f551032SValentin Clement   mlir::Value extent = rewriter.create<mlir::LLVM::SubOp>(loc, type, ub, lb);
17581f551032SValentin Clement   extent = rewriter.create<mlir::LLVM::AddOp>(loc, type, extent, step);
17591f551032SValentin Clement   extent = rewriter.create<mlir::LLVM::SDivOp>(loc, type, extent, step);
17601f551032SValentin Clement   // If the resulting extent is negative (`ub-lb` and `step` have different
17611f551032SValentin Clement   // signs), zero must be returned instead.
17621f551032SValentin Clement   auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
17631f551032SValentin Clement       loc, mlir::LLVM::ICmpPredicate::sgt, extent, zero);
17641f551032SValentin Clement   return rewriter.create<mlir::LLVM::SelectOp>(loc, cmp, extent, zero);
17651f551032SValentin Clement }
17661f551032SValentin Clement 
1767af6ee580SValentin Clement /// Create a generic box on a memory reference. This conversions lowers the
1768af6ee580SValentin Clement /// abstract box to the appropriate, initialized descriptor.
1769af6ee580SValentin Clement struct EmboxOpConversion : public EmboxCommonConversion<fir::EmboxOp> {
1770af6ee580SValentin Clement   using EmboxCommonConversion::EmboxCommonConversion;
1771af6ee580SValentin Clement 
1772af6ee580SValentin Clement   mlir::LogicalResult
1773af6ee580SValentin Clement   matchAndRewrite(fir::EmboxOp embox, OpAdaptor adaptor,
1774af6ee580SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1775af6ee580SValentin Clement     assert(!embox.getShape() && "There should be no dims on this embox op");
1776af6ee580SValentin Clement     auto [boxTy, dest, eleSize] =
1777af6ee580SValentin Clement         consDescriptorPrefix(embox, rewriter, /*rank=*/0,
1778af6ee580SValentin Clement                              /*lenParams=*/adaptor.getOperands().drop_front(1));
1779af6ee580SValentin Clement     dest = insertBaseAddress(rewriter, embox.getLoc(), dest,
1780af6ee580SValentin Clement                              adaptor.getOperands()[0]);
17817ce8c6fcSKiran Chandramohan     if (isDerivedTypeWithLenParams(boxTy)) {
17827ce8c6fcSKiran Chandramohan       TODO(embox.getLoc(),
17837ce8c6fcSKiran Chandramohan            "fir.embox codegen of derived with length parameters");
17847ce8c6fcSKiran Chandramohan       return failure();
17857ce8c6fcSKiran Chandramohan     }
1786af6ee580SValentin Clement     auto result = placeInMemoryIfNotGlobalInit(rewriter, embox.getLoc(), dest);
1787af6ee580SValentin Clement     rewriter.replaceOp(embox, result);
1788af6ee580SValentin Clement     return success();
1789af6ee580SValentin Clement   }
1790af6ee580SValentin Clement };
1791af6ee580SValentin Clement 
1792cc505c0bSKiran Chandramohan /// Lower `fir.emboxproc` operation. Creates a procedure box.
1793cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
1794cc505c0bSKiran Chandramohan struct EmboxProcOpConversion : public FIROpConversion<fir::EmboxProcOp> {
1795cc505c0bSKiran Chandramohan   using FIROpConversion::FIROpConversion;
1796cc505c0bSKiran Chandramohan 
1797cc505c0bSKiran Chandramohan   mlir::LogicalResult
1798cc505c0bSKiran Chandramohan   matchAndRewrite(fir::EmboxProcOp emboxproc, OpAdaptor adaptor,
1799cc505c0bSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
18007ce8c6fcSKiran Chandramohan     TODO(emboxproc.getLoc(), "fir.emboxproc codegen");
18017ce8c6fcSKiran Chandramohan     return failure();
1802cc505c0bSKiran Chandramohan   }
1803cc505c0bSKiran Chandramohan };
1804cc505c0bSKiran Chandramohan 
18051f551032SValentin Clement /// Create a generic box on a memory reference.
18061f551032SValentin Clement struct XEmboxOpConversion : public EmboxCommonConversion<fir::cg::XEmboxOp> {
18071f551032SValentin Clement   using EmboxCommonConversion::EmboxCommonConversion;
18081f551032SValentin Clement 
18091f551032SValentin Clement   mlir::LogicalResult
18101f551032SValentin Clement   matchAndRewrite(fir::cg::XEmboxOp xbox, OpAdaptor adaptor,
18111f551032SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
18121f551032SValentin Clement     auto [boxTy, dest, eleSize] = consDescriptorPrefix(
18131f551032SValentin Clement         xbox, rewriter, xbox.getOutRank(),
18141f551032SValentin Clement         adaptor.getOperands().drop_front(xbox.lenParamOffset()));
18151f551032SValentin Clement     // Generate the triples in the dims field of the descriptor
18161f551032SValentin Clement     mlir::ValueRange operands = adaptor.getOperands();
18171f551032SValentin Clement     auto i64Ty = mlir::IntegerType::get(xbox.getContext(), 64);
18181f551032SValentin Clement     mlir::Value base = operands[0];
18191f551032SValentin Clement     assert(!xbox.shape().empty() && "must have a shape");
18201f551032SValentin Clement     unsigned shapeOffset = xbox.shapeOffset();
18211f551032SValentin Clement     bool hasShift = !xbox.shift().empty();
18221f551032SValentin Clement     unsigned shiftOffset = xbox.shiftOffset();
18231f551032SValentin Clement     bool hasSlice = !xbox.slice().empty();
18241f551032SValentin Clement     unsigned sliceOffset = xbox.sliceOffset();
18251f551032SValentin Clement     mlir::Location loc = xbox.getLoc();
18261f551032SValentin Clement     mlir::Value zero = genConstantIndex(loc, i64Ty, rewriter, 0);
18271f551032SValentin Clement     mlir::Value one = genConstantIndex(loc, i64Ty, rewriter, 1);
18281f551032SValentin Clement     mlir::Value prevDim = integerCast(loc, rewriter, i64Ty, eleSize);
18291f551032SValentin Clement     mlir::Value prevPtrOff = one;
18301f551032SValentin Clement     mlir::Type eleTy = boxTy.getEleTy();
18311f551032SValentin Clement     const unsigned rank = xbox.getRank();
18321f551032SValentin Clement     llvm::SmallVector<mlir::Value> gepArgs;
18331f551032SValentin Clement     unsigned constRows = 0;
18341f551032SValentin Clement     mlir::Value ptrOffset = zero;
18351f551032SValentin Clement     if (auto memEleTy = fir::dyn_cast_ptrEleTy(xbox.memref().getType()))
18361f551032SValentin Clement       if (auto seqTy = memEleTy.dyn_cast<fir::SequenceType>()) {
18371f551032SValentin Clement         mlir::Type seqEleTy = seqTy.getEleTy();
18381f551032SValentin Clement         // Adjust the element scaling factor if the element is a dependent type.
18391f551032SValentin Clement         if (fir::hasDynamicSize(seqEleTy)) {
18401f551032SValentin Clement           if (fir::isa_char(seqEleTy)) {
18411f551032SValentin Clement             assert(xbox.lenParams().size() == 1);
18421f551032SValentin Clement             prevPtrOff = integerCast(loc, rewriter, i64Ty,
18431f551032SValentin Clement                                      operands[xbox.lenParamOffset()]);
18441f551032SValentin Clement           } else if (seqEleTy.isa<fir::RecordType>()) {
18451f551032SValentin Clement             TODO(loc, "generate call to calculate size of PDT");
18461f551032SValentin Clement           } else {
18471f551032SValentin Clement             return rewriter.notifyMatchFailure(xbox, "unexpected dynamic type");
18481f551032SValentin Clement           }
18491f551032SValentin Clement         } else {
18501f551032SValentin Clement           constRows = seqTy.getConstantRows();
18511f551032SValentin Clement         }
18521f551032SValentin Clement       }
18531f551032SValentin Clement 
18541f551032SValentin Clement     bool hasSubcomp = !xbox.subcomponent().empty();
18551f551032SValentin Clement     mlir::Value stepExpr;
18561f551032SValentin Clement     if (hasSubcomp) {
18571f551032SValentin Clement       // We have a subcomponent. The step value needs to be the number of
18581f551032SValentin Clement       // bytes per element (which is a derived type).
18591f551032SValentin Clement       mlir::Type ty0 = base.getType();
18601f551032SValentin Clement       [[maybe_unused]] auto ptrTy = ty0.dyn_cast<mlir::LLVM::LLVMPointerType>();
18611f551032SValentin Clement       assert(ptrTy && "expected pointer type");
18621f551032SValentin Clement       mlir::Type memEleTy = fir::dyn_cast_ptrEleTy(xbox.memref().getType());
18631f551032SValentin Clement       assert(memEleTy && "expected fir pointer type");
18641f551032SValentin Clement       auto seqTy = memEleTy.dyn_cast<fir::SequenceType>();
18651f551032SValentin Clement       assert(seqTy && "expected sequence type");
18661f551032SValentin Clement       mlir::Type seqEleTy = seqTy.getEleTy();
18671f551032SValentin Clement       auto eleTy = mlir::LLVM::LLVMPointerType::get(convertType(seqEleTy));
18681f551032SValentin Clement       stepExpr = computeDerivedTypeSize(loc, eleTy, i64Ty, rewriter);
18691f551032SValentin Clement     }
18701f551032SValentin Clement 
18711f551032SValentin Clement     // Process the array subspace arguments (shape, shift, etc.), if any,
18721f551032SValentin Clement     // translating everything to values in the descriptor wherever the entity
18731f551032SValentin Clement     // has a dynamic array dimension.
18741f551032SValentin Clement     for (unsigned di = 0, descIdx = 0; di < rank; ++di) {
18751f551032SValentin Clement       mlir::Value extent = operands[shapeOffset];
18761f551032SValentin Clement       mlir::Value outerExtent = extent;
18771f551032SValentin Clement       bool skipNext = false;
18781f551032SValentin Clement       if (hasSlice) {
18791f551032SValentin Clement         mlir::Value off = operands[sliceOffset];
18801f551032SValentin Clement         mlir::Value adj = one;
18811f551032SValentin Clement         if (hasShift)
18821f551032SValentin Clement           adj = operands[shiftOffset];
18831f551032SValentin Clement         auto ao = rewriter.create<mlir::LLVM::SubOp>(loc, i64Ty, off, adj);
18841f551032SValentin Clement         if (constRows > 0) {
18851f551032SValentin Clement           gepArgs.push_back(ao);
18861f551032SValentin Clement           --constRows;
18871f551032SValentin Clement         } else {
18881f551032SValentin Clement           auto dimOff =
18891f551032SValentin Clement               rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, ao, prevPtrOff);
18901f551032SValentin Clement           ptrOffset =
18911f551032SValentin Clement               rewriter.create<mlir::LLVM::AddOp>(loc, i64Ty, dimOff, ptrOffset);
18921f551032SValentin Clement         }
18931f551032SValentin Clement         if (mlir::isa_and_nonnull<fir::UndefOp>(
18941f551032SValentin Clement                 xbox.slice()[3 * di + 1].getDefiningOp())) {
18951f551032SValentin Clement           // This dimension contains a scalar expression in the array slice op.
18961f551032SValentin Clement           // The dimension is loop invariant, will be dropped, and will not
18971f551032SValentin Clement           // appear in the descriptor.
18981f551032SValentin Clement           skipNext = true;
18991f551032SValentin Clement         }
19001f551032SValentin Clement       }
19011f551032SValentin Clement       if (!skipNext) {
19021f551032SValentin Clement         // store lower bound (normally 0)
19031f551032SValentin Clement         mlir::Value lb = zero;
19041f551032SValentin Clement         if (eleTy.isa<fir::PointerType>() || eleTy.isa<fir::HeapType>()) {
19051f551032SValentin Clement           lb = one;
19061f551032SValentin Clement           if (hasShift)
19071f551032SValentin Clement             lb = operands[shiftOffset];
19081f551032SValentin Clement         }
19091f551032SValentin Clement         dest = insertLowerBound(rewriter, loc, dest, descIdx, lb);
19101f551032SValentin Clement 
19111f551032SValentin Clement         // store extent
19121f551032SValentin Clement         if (hasSlice)
19131f551032SValentin Clement           extent = computeTripletExtent(rewriter, loc, operands[sliceOffset],
19141f551032SValentin Clement                                         operands[sliceOffset + 1],
19151f551032SValentin Clement                                         operands[sliceOffset + 2], zero, i64Ty);
19161f551032SValentin Clement         dest = insertExtent(rewriter, loc, dest, descIdx, extent);
19171f551032SValentin Clement 
19181f551032SValentin Clement         // store step (scaled by shaped extent)
19191f551032SValentin Clement 
19201f551032SValentin Clement         mlir::Value step = hasSubcomp ? stepExpr : prevDim;
19211f551032SValentin Clement         if (hasSlice)
19221f551032SValentin Clement           step = rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, step,
19231f551032SValentin Clement                                                     operands[sliceOffset + 2]);
19241f551032SValentin Clement         dest = insertStride(rewriter, loc, dest, descIdx, step);
19251f551032SValentin Clement         ++descIdx;
19261f551032SValentin Clement       }
19271f551032SValentin Clement 
19281f551032SValentin Clement       // compute the stride and offset for the next natural dimension
19291f551032SValentin Clement       prevDim =
19301f551032SValentin Clement           rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, prevDim, outerExtent);
19311f551032SValentin Clement       if (constRows == 0)
19321f551032SValentin Clement         prevPtrOff = rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, prevPtrOff,
19331f551032SValentin Clement                                                         outerExtent);
19341f551032SValentin Clement 
19351f551032SValentin Clement       // increment iterators
19361f551032SValentin Clement       ++shapeOffset;
19371f551032SValentin Clement       if (hasShift)
19381f551032SValentin Clement         ++shiftOffset;
19391f551032SValentin Clement       if (hasSlice)
19401f551032SValentin Clement         sliceOffset += 3;
19411f551032SValentin Clement     }
19421f551032SValentin Clement     if (hasSlice || hasSubcomp || !xbox.substr().empty()) {
19431f551032SValentin Clement       llvm::SmallVector<mlir::Value> args = {base, ptrOffset};
19441f551032SValentin Clement       args.append(gepArgs.rbegin(), gepArgs.rend());
19451f551032SValentin Clement       if (hasSubcomp) {
19461f551032SValentin Clement         // For each field in the path add the offset to base via the args list.
19471f551032SValentin Clement         // In the most general case, some offsets must be computed since
19481f551032SValentin Clement         // they are not be known until runtime.
19491f551032SValentin Clement         if (fir::hasDynamicSize(fir::unwrapSequenceType(
19501f551032SValentin Clement                 fir::unwrapPassByRefType(xbox.memref().getType()))))
19511f551032SValentin Clement           TODO(loc, "fir.embox codegen dynamic size component in derived type");
19521f551032SValentin Clement         args.append(operands.begin() + xbox.subcomponentOffset(),
19531f551032SValentin Clement                     operands.begin() + xbox.subcomponentOffset() +
19541f551032SValentin Clement                         xbox.subcomponent().size());
19551f551032SValentin Clement       }
19561f551032SValentin Clement       base = rewriter.create<mlir::LLVM::GEPOp>(loc, base.getType(), args);
19571f551032SValentin Clement       if (!xbox.substr().empty())
19581f551032SValentin Clement         base = shiftSubstringBase(rewriter, loc, base,
19591f551032SValentin Clement                                   operands[xbox.substrOffset()]);
19601f551032SValentin Clement     }
19611f551032SValentin Clement     dest = insertBaseAddress(rewriter, loc, dest, base);
19621f551032SValentin Clement     if (isDerivedTypeWithLenParams(boxTy))
19631f551032SValentin Clement       TODO(loc, "fir.embox codegen of derived with length parameters");
19641f551032SValentin Clement 
19651f551032SValentin Clement     mlir::Value result = placeInMemoryIfNotGlobalInit(rewriter, loc, dest);
19661f551032SValentin Clement     rewriter.replaceOp(xbox, result);
19671f551032SValentin Clement     return success();
19681f551032SValentin Clement   }
19691f551032SValentin Clement };
19701f551032SValentin Clement 
1971fa517555SKiran Chandramohan /// Create a new box given a box reference.
1972fa517555SKiran Chandramohan struct XReboxOpConversion : public EmboxCommonConversion<fir::cg::XReboxOp> {
1973fa517555SKiran Chandramohan   using EmboxCommonConversion::EmboxCommonConversion;
1974fa517555SKiran Chandramohan 
1975fa517555SKiran Chandramohan   mlir::LogicalResult
1976fa517555SKiran Chandramohan   matchAndRewrite(fir::cg::XReboxOp rebox, OpAdaptor adaptor,
1977fa517555SKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
1978fa517555SKiran Chandramohan     mlir::Location loc = rebox.getLoc();
1979fa517555SKiran Chandramohan     mlir::Type idxTy = lowerTy().indexType();
1980fa517555SKiran Chandramohan     mlir::Value loweredBox = adaptor.getOperands()[0];
1981fa517555SKiran Chandramohan     mlir::ValueRange operands = adaptor.getOperands();
1982fa517555SKiran Chandramohan 
1983fa517555SKiran Chandramohan     // Create new descriptor and fill its non-shape related data.
1984fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value, 2> lenParams;
1985fa517555SKiran Chandramohan     mlir::Type inputEleTy = getInputEleTy(rebox);
1986fa517555SKiran Chandramohan     if (auto charTy = inputEleTy.dyn_cast<fir::CharacterType>()) {
1987fa517555SKiran Chandramohan       mlir::Value len =
1988fa517555SKiran Chandramohan           loadElementSizeFromBox(loc, idxTy, loweredBox, rewriter);
1989fa517555SKiran Chandramohan       if (charTy.getFKind() != 1) {
1990fa517555SKiran Chandramohan         mlir::Value width =
1991fa517555SKiran Chandramohan             genConstantIndex(loc, idxTy, rewriter, charTy.getFKind());
1992fa517555SKiran Chandramohan         len = rewriter.create<mlir::LLVM::SDivOp>(loc, idxTy, len, width);
1993fa517555SKiran Chandramohan       }
1994fa517555SKiran Chandramohan       lenParams.emplace_back(len);
1995fa517555SKiran Chandramohan     } else if (auto recTy = inputEleTy.dyn_cast<fir::RecordType>()) {
1996fa517555SKiran Chandramohan       if (recTy.getNumLenParams() != 0)
1997fa517555SKiran Chandramohan         TODO(loc, "reboxing descriptor of derived type with length parameters");
1998fa517555SKiran Chandramohan     }
1999fa517555SKiran Chandramohan     auto [boxTy, dest, eleSize] =
2000fa517555SKiran Chandramohan         consDescriptorPrefix(rebox, rewriter, rebox.getOutRank(), lenParams);
2001fa517555SKiran Chandramohan 
2002fa517555SKiran Chandramohan     // Read input extents, strides, and base address
2003fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> inputExtents;
2004fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> inputStrides;
2005fa517555SKiran Chandramohan     const unsigned inputRank = rebox.getRank();
2006fa517555SKiran Chandramohan     for (unsigned i = 0; i < inputRank; ++i) {
2007fa517555SKiran Chandramohan       mlir::Value dim = genConstantIndex(loc, idxTy, rewriter, i);
2008fa517555SKiran Chandramohan       SmallVector<mlir::Value, 3> dimInfo =
2009fa517555SKiran Chandramohan           getDimsFromBox(loc, {idxTy, idxTy, idxTy}, loweredBox, dim, rewriter);
2010fa517555SKiran Chandramohan       inputExtents.emplace_back(dimInfo[1]);
2011fa517555SKiran Chandramohan       inputStrides.emplace_back(dimInfo[2]);
2012fa517555SKiran Chandramohan     }
2013fa517555SKiran Chandramohan 
2014fa517555SKiran Chandramohan     mlir::Type baseTy = getBaseAddrTypeFromBox(loweredBox.getType());
2015fa517555SKiran Chandramohan     mlir::Value baseAddr =
2016fa517555SKiran Chandramohan         loadBaseAddrFromBox(loc, baseTy, loweredBox, rewriter);
2017fa517555SKiran Chandramohan 
2018fa517555SKiran Chandramohan     if (!rebox.slice().empty() || !rebox.subcomponent().empty())
2019fa517555SKiran Chandramohan       return sliceBox(rebox, dest, baseAddr, inputExtents, inputStrides,
2020fa517555SKiran Chandramohan                       operands, rewriter);
2021fa517555SKiran Chandramohan     return reshapeBox(rebox, dest, baseAddr, inputExtents, inputStrides,
2022fa517555SKiran Chandramohan                       operands, rewriter);
2023fa517555SKiran Chandramohan   }
2024fa517555SKiran Chandramohan 
2025fa517555SKiran Chandramohan private:
2026fa517555SKiran Chandramohan   /// Write resulting shape and base address in descriptor, and replace rebox
2027fa517555SKiran Chandramohan   /// op.
2028fa517555SKiran Chandramohan   mlir::LogicalResult
2029fa517555SKiran Chandramohan   finalizeRebox(fir::cg::XReboxOp rebox, mlir::Value dest, mlir::Value base,
2030fa517555SKiran Chandramohan                 mlir::ValueRange lbounds, mlir::ValueRange extents,
2031fa517555SKiran Chandramohan                 mlir::ValueRange strides,
2032fa517555SKiran Chandramohan                 mlir::ConversionPatternRewriter &rewriter) const {
2033fa517555SKiran Chandramohan     mlir::Location loc = rebox.getLoc();
2034fa517555SKiran Chandramohan     mlir::Value one = genConstantIndex(loc, lowerTy().indexType(), rewriter, 1);
2035fa517555SKiran Chandramohan     for (auto iter : llvm::enumerate(llvm::zip(extents, strides))) {
2036fa517555SKiran Chandramohan       unsigned dim = iter.index();
2037fa517555SKiran Chandramohan       mlir::Value lb = lbounds.empty() ? one : lbounds[dim];
2038fa517555SKiran Chandramohan       dest = insertLowerBound(rewriter, loc, dest, dim, lb);
2039fa517555SKiran Chandramohan       dest = insertExtent(rewriter, loc, dest, dim, std::get<0>(iter.value()));
2040fa517555SKiran Chandramohan       dest = insertStride(rewriter, loc, dest, dim, std::get<1>(iter.value()));
2041fa517555SKiran Chandramohan     }
2042fa517555SKiran Chandramohan     dest = insertBaseAddress(rewriter, loc, dest, base);
2043fa517555SKiran Chandramohan     mlir::Value result =
2044fa517555SKiran Chandramohan         placeInMemoryIfNotGlobalInit(rewriter, rebox.getLoc(), dest);
2045fa517555SKiran Chandramohan     rewriter.replaceOp(rebox, result);
2046fa517555SKiran Chandramohan     return success();
2047fa517555SKiran Chandramohan   }
2048fa517555SKiran Chandramohan 
2049fa517555SKiran Chandramohan   // Apply slice given the base address, extents and strides of the input box.
2050fa517555SKiran Chandramohan   mlir::LogicalResult
2051fa517555SKiran Chandramohan   sliceBox(fir::cg::XReboxOp rebox, mlir::Value dest, mlir::Value base,
2052fa517555SKiran Chandramohan            mlir::ValueRange inputExtents, mlir::ValueRange inputStrides,
2053fa517555SKiran Chandramohan            mlir::ValueRange operands,
2054fa517555SKiran Chandramohan            mlir::ConversionPatternRewriter &rewriter) const {
2055fa517555SKiran Chandramohan     mlir::Location loc = rebox.getLoc();
2056fa517555SKiran Chandramohan     mlir::Type voidPtrTy = ::getVoidPtrType(rebox.getContext());
2057fa517555SKiran Chandramohan     mlir::Type idxTy = lowerTy().indexType();
2058fa517555SKiran Chandramohan     mlir::Value zero = genConstantIndex(loc, idxTy, rewriter, 0);
2059fa517555SKiran Chandramohan     // Apply subcomponent and substring shift on base address.
2060fa517555SKiran Chandramohan     if (!rebox.subcomponent().empty() || !rebox.substr().empty()) {
2061fa517555SKiran Chandramohan       // Cast to inputEleTy* so that a GEP can be used.
2062fa517555SKiran Chandramohan       mlir::Type inputEleTy = getInputEleTy(rebox);
2063fa517555SKiran Chandramohan       auto llvmElePtrTy =
2064fa517555SKiran Chandramohan           mlir::LLVM::LLVMPointerType::get(convertType(inputEleTy));
2065fa517555SKiran Chandramohan       base = rewriter.create<mlir::LLVM::BitcastOp>(loc, llvmElePtrTy, base);
2066fa517555SKiran Chandramohan 
2067fa517555SKiran Chandramohan       if (!rebox.subcomponent().empty()) {
2068fa517555SKiran Chandramohan         llvm::SmallVector<mlir::Value> gepOperands = {zero};
2069fa517555SKiran Chandramohan         for (unsigned i = 0; i < rebox.subcomponent().size(); ++i)
2070fa517555SKiran Chandramohan           gepOperands.push_back(operands[rebox.subcomponentOffset() + i]);
2071fa517555SKiran Chandramohan         base = genGEP(loc, llvmElePtrTy, rewriter, base, gepOperands);
2072fa517555SKiran Chandramohan       }
2073fa517555SKiran Chandramohan       if (!rebox.substr().empty())
2074fa517555SKiran Chandramohan         base = shiftSubstringBase(rewriter, loc, base,
2075fa517555SKiran Chandramohan                                   operands[rebox.substrOffset()]);
2076fa517555SKiran Chandramohan     }
2077fa517555SKiran Chandramohan 
2078fa517555SKiran Chandramohan     if (rebox.slice().empty())
2079fa517555SKiran Chandramohan       // The array section is of the form array[%component][substring], keep
2080fa517555SKiran Chandramohan       // the input array extents and strides.
2081fa517555SKiran Chandramohan       return finalizeRebox(rebox, dest, base, /*lbounds*/ llvm::None,
2082fa517555SKiran Chandramohan                            inputExtents, inputStrides, rewriter);
2083fa517555SKiran Chandramohan 
2084fa517555SKiran Chandramohan     // Strides from the fir.box are in bytes.
2085fa517555SKiran Chandramohan     base = rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, base);
2086fa517555SKiran Chandramohan 
2087fa517555SKiran Chandramohan     // The slice is of the form array(i:j:k)[%component]. Compute new extents
2088fa517555SKiran Chandramohan     // and strides.
2089fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> slicedExtents;
2090fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> slicedStrides;
2091fa517555SKiran Chandramohan     mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1);
2092fa517555SKiran Chandramohan     const bool sliceHasOrigins = !rebox.shift().empty();
2093fa517555SKiran Chandramohan     unsigned sliceOps = rebox.sliceOffset();
2094fa517555SKiran Chandramohan     unsigned shiftOps = rebox.shiftOffset();
2095fa517555SKiran Chandramohan     auto strideOps = inputStrides.begin();
2096fa517555SKiran Chandramohan     const unsigned inputRank = inputStrides.size();
2097fa517555SKiran Chandramohan     for (unsigned i = 0; i < inputRank;
2098fa517555SKiran Chandramohan          ++i, ++strideOps, ++shiftOps, sliceOps += 3) {
2099fa517555SKiran Chandramohan       mlir::Value sliceLb =
2100fa517555SKiran Chandramohan           integerCast(loc, rewriter, idxTy, operands[sliceOps]);
2101fa517555SKiran Chandramohan       mlir::Value inputStride = *strideOps; // already idxTy
2102fa517555SKiran Chandramohan       // Apply origin shift: base += (lb-shift)*input_stride
2103fa517555SKiran Chandramohan       mlir::Value sliceOrigin =
2104fa517555SKiran Chandramohan           sliceHasOrigins
2105fa517555SKiran Chandramohan               ? integerCast(loc, rewriter, idxTy, operands[shiftOps])
2106fa517555SKiran Chandramohan               : one;
2107fa517555SKiran Chandramohan       mlir::Value diff =
2108fa517555SKiran Chandramohan           rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, sliceLb, sliceOrigin);
2109fa517555SKiran Chandramohan       mlir::Value offset =
2110fa517555SKiran Chandramohan           rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, inputStride);
2111fa517555SKiran Chandramohan       base = genGEP(loc, voidPtrTy, rewriter, base, offset);
2112fa517555SKiran Chandramohan       // Apply upper bound and step if this is a triplet. Otherwise, the
2113fa517555SKiran Chandramohan       // dimension is dropped and no extents/strides are computed.
2114fa517555SKiran Chandramohan       mlir::Value upper = operands[sliceOps + 1];
2115fa517555SKiran Chandramohan       const bool isTripletSlice =
2116fa517555SKiran Chandramohan           !mlir::isa_and_nonnull<mlir::LLVM::UndefOp>(upper.getDefiningOp());
2117fa517555SKiran Chandramohan       if (isTripletSlice) {
2118fa517555SKiran Chandramohan         mlir::Value step =
2119fa517555SKiran Chandramohan             integerCast(loc, rewriter, idxTy, operands[sliceOps + 2]);
2120fa517555SKiran Chandramohan         // extent = ub-lb+step/step
2121fa517555SKiran Chandramohan         mlir::Value sliceUb = integerCast(loc, rewriter, idxTy, upper);
2122fa517555SKiran Chandramohan         mlir::Value extent = computeTripletExtent(rewriter, loc, sliceLb,
2123fa517555SKiran Chandramohan                                                   sliceUb, step, zero, idxTy);
2124fa517555SKiran Chandramohan         slicedExtents.emplace_back(extent);
2125fa517555SKiran Chandramohan         // stride = step*input_stride
2126fa517555SKiran Chandramohan         mlir::Value stride =
2127fa517555SKiran Chandramohan             rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, step, inputStride);
2128fa517555SKiran Chandramohan         slicedStrides.emplace_back(stride);
2129fa517555SKiran Chandramohan       }
2130fa517555SKiran Chandramohan     }
2131fa517555SKiran Chandramohan     return finalizeRebox(rebox, dest, base, /*lbounds*/ llvm::None,
2132fa517555SKiran Chandramohan                          slicedExtents, slicedStrides, rewriter);
2133fa517555SKiran Chandramohan   }
2134fa517555SKiran Chandramohan 
2135fa517555SKiran Chandramohan   /// Apply a new shape to the data described by a box given the base address,
2136fa517555SKiran Chandramohan   /// extents and strides of the box.
2137fa517555SKiran Chandramohan   mlir::LogicalResult
2138fa517555SKiran Chandramohan   reshapeBox(fir::cg::XReboxOp rebox, mlir::Value dest, mlir::Value base,
2139fa517555SKiran Chandramohan              mlir::ValueRange inputExtents, mlir::ValueRange inputStrides,
2140fa517555SKiran Chandramohan              mlir::ValueRange operands,
2141fa517555SKiran Chandramohan              mlir::ConversionPatternRewriter &rewriter) const {
2142fa517555SKiran Chandramohan     mlir::ValueRange reboxShifts{operands.begin() + rebox.shiftOffset(),
2143fa517555SKiran Chandramohan                                  operands.begin() + rebox.shiftOffset() +
2144fa517555SKiran Chandramohan                                      rebox.shift().size()};
2145fa517555SKiran Chandramohan     if (rebox.shape().empty()) {
2146fa517555SKiran Chandramohan       // Only setting new lower bounds.
2147fa517555SKiran Chandramohan       return finalizeRebox(rebox, dest, base, reboxShifts, inputExtents,
2148fa517555SKiran Chandramohan                            inputStrides, rewriter);
2149fa517555SKiran Chandramohan     }
2150fa517555SKiran Chandramohan 
2151fa517555SKiran Chandramohan     mlir::Location loc = rebox.getLoc();
2152fa517555SKiran Chandramohan     // Strides from the fir.box are in bytes.
2153fa517555SKiran Chandramohan     mlir::Type voidPtrTy = ::getVoidPtrType(rebox.getContext());
2154fa517555SKiran Chandramohan     base = rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, base);
2155fa517555SKiran Chandramohan 
2156fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> newStrides;
2157fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> newExtents;
2158fa517555SKiran Chandramohan     mlir::Type idxTy = lowerTy().indexType();
2159fa517555SKiran Chandramohan     // First stride from input box is kept. The rest is assumed contiguous
2160fa517555SKiran Chandramohan     // (it is not possible to reshape otherwise). If the input is scalar,
2161fa517555SKiran Chandramohan     // which may be OK if all new extents are ones, the stride does not
2162fa517555SKiran Chandramohan     // matter, use one.
2163fa517555SKiran Chandramohan     mlir::Value stride = inputStrides.empty()
2164fa517555SKiran Chandramohan                              ? genConstantIndex(loc, idxTy, rewriter, 1)
2165fa517555SKiran Chandramohan                              : inputStrides[0];
2166fa517555SKiran Chandramohan     for (unsigned i = 0; i < rebox.shape().size(); ++i) {
2167fa517555SKiran Chandramohan       mlir::Value rawExtent = operands[rebox.shapeOffset() + i];
2168fa517555SKiran Chandramohan       mlir::Value extent = integerCast(loc, rewriter, idxTy, rawExtent);
2169fa517555SKiran Chandramohan       newExtents.emplace_back(extent);
2170fa517555SKiran Chandramohan       newStrides.emplace_back(stride);
2171fa517555SKiran Chandramohan       // nextStride = extent * stride;
2172fa517555SKiran Chandramohan       stride = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, extent, stride);
2173fa517555SKiran Chandramohan     }
2174fa517555SKiran Chandramohan     return finalizeRebox(rebox, dest, base, reboxShifts, newExtents, newStrides,
2175fa517555SKiran Chandramohan                          rewriter);
2176fa517555SKiran Chandramohan   }
2177fa517555SKiran Chandramohan 
2178fa517555SKiran Chandramohan   /// Return scalar element type of the input box.
2179fa517555SKiran Chandramohan   static mlir::Type getInputEleTy(fir::cg::XReboxOp rebox) {
2180fa517555SKiran Chandramohan     auto ty = fir::dyn_cast_ptrOrBoxEleTy(rebox.box().getType());
2181fa517555SKiran Chandramohan     if (auto seqTy = ty.dyn_cast<fir::SequenceType>())
2182fa517555SKiran Chandramohan       return seqTy.getEleTy();
2183fa517555SKiran Chandramohan     return ty;
2184fa517555SKiran Chandramohan   }
2185fa517555SKiran Chandramohan };
2186fa517555SKiran Chandramohan 
218754c56347SValentin Clement // Code shared between insert_value and extract_value Ops.
218854c56347SValentin Clement struct ValueOpCommon {
218954c56347SValentin Clement   // Translate the arguments pertaining to any multidimensional array to
219054c56347SValentin Clement   // row-major order for LLVM-IR.
219154c56347SValentin Clement   static void toRowMajor(SmallVectorImpl<mlir::Attribute> &attrs,
219254c56347SValentin Clement                          mlir::Type ty) {
219354c56347SValentin Clement     assert(ty && "type is null");
219454c56347SValentin Clement     const auto end = attrs.size();
219554c56347SValentin Clement     for (std::remove_const_t<decltype(end)> i = 0; i < end; ++i) {
219654c56347SValentin Clement       if (auto seq = ty.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
219754c56347SValentin Clement         const auto dim = getDimension(seq);
219854c56347SValentin Clement         if (dim > 1) {
219954c56347SValentin Clement           auto ub = std::min(i + dim, end);
220054c56347SValentin Clement           std::reverse(attrs.begin() + i, attrs.begin() + ub);
220154c56347SValentin Clement           i += dim - 1;
220254c56347SValentin Clement         }
220354c56347SValentin Clement         ty = getArrayElementType(seq);
220454c56347SValentin Clement       } else if (auto st = ty.dyn_cast<mlir::LLVM::LLVMStructType>()) {
220554c56347SValentin Clement         ty = st.getBody()[attrs[i].cast<mlir::IntegerAttr>().getInt()];
220654c56347SValentin Clement       } else {
220754c56347SValentin Clement         llvm_unreachable("index into invalid type");
220854c56347SValentin Clement       }
220954c56347SValentin Clement     }
221054c56347SValentin Clement   }
221154c56347SValentin Clement 
221254c56347SValentin Clement   static llvm::SmallVector<mlir::Attribute>
221354c56347SValentin Clement   collectIndices(mlir::ConversionPatternRewriter &rewriter,
221454c56347SValentin Clement                  mlir::ArrayAttr arrAttr) {
221554c56347SValentin Clement     llvm::SmallVector<mlir::Attribute> attrs;
221654c56347SValentin Clement     for (auto i = arrAttr.begin(), e = arrAttr.end(); i != e; ++i) {
221754c56347SValentin Clement       if (i->isa<mlir::IntegerAttr>()) {
221854c56347SValentin Clement         attrs.push_back(*i);
221954c56347SValentin Clement       } else {
222054c56347SValentin Clement         auto fieldName = i->cast<mlir::StringAttr>().getValue();
222154c56347SValentin Clement         ++i;
222254c56347SValentin Clement         auto ty = i->cast<mlir::TypeAttr>().getValue();
222354c56347SValentin Clement         auto index = ty.cast<fir::RecordType>().getFieldIndex(fieldName);
222454c56347SValentin Clement         attrs.push_back(mlir::IntegerAttr::get(rewriter.getI32Type(), index));
222554c56347SValentin Clement       }
222654c56347SValentin Clement     }
222754c56347SValentin Clement     return attrs;
222854c56347SValentin Clement   }
222954c56347SValentin Clement 
223054c56347SValentin Clement private:
223154c56347SValentin Clement   static unsigned getDimension(mlir::LLVM::LLVMArrayType ty) {
223254c56347SValentin Clement     unsigned result = 1;
223354c56347SValentin Clement     for (auto eleTy = ty.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>();
223454c56347SValentin Clement          eleTy;
223554c56347SValentin Clement          eleTy = eleTy.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>())
223654c56347SValentin Clement       ++result;
223754c56347SValentin Clement     return result;
223854c56347SValentin Clement   }
223954c56347SValentin Clement 
224054c56347SValentin Clement   static mlir::Type getArrayElementType(mlir::LLVM::LLVMArrayType ty) {
224154c56347SValentin Clement     auto eleTy = ty.getElementType();
224254c56347SValentin Clement     while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>())
224354c56347SValentin Clement       eleTy = arrTy.getElementType();
224454c56347SValentin Clement     return eleTy;
224554c56347SValentin Clement   }
224654c56347SValentin Clement };
224754c56347SValentin Clement 
2248*c2acd453SAlexisPerry namespace {
224954c56347SValentin Clement /// Extract a subobject value from an ssa-value of aggregate type
225054c56347SValentin Clement struct ExtractValueOpConversion
225154c56347SValentin Clement     : public FIROpAndTypeConversion<fir::ExtractValueOp>,
225254c56347SValentin Clement       public ValueOpCommon {
225354c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
225454c56347SValentin Clement 
225554c56347SValentin Clement   mlir::LogicalResult
225654c56347SValentin Clement   doRewrite(fir::ExtractValueOp extractVal, mlir::Type ty, OpAdaptor adaptor,
225754c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
225854c56347SValentin Clement     auto attrs = collectIndices(rewriter, extractVal.coor());
225954c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
226054c56347SValentin Clement     auto position = mlir::ArrayAttr::get(extractVal.getContext(), attrs);
226154c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(
226254c56347SValentin Clement         extractVal, ty, adaptor.getOperands()[0], position);
226354c56347SValentin Clement     return success();
226454c56347SValentin Clement   }
226554c56347SValentin Clement };
226654c56347SValentin Clement 
226754c56347SValentin Clement /// InsertValue is the generalized instruction for the composition of new
226854c56347SValentin Clement /// aggregate type values.
226954c56347SValentin Clement struct InsertValueOpConversion
227054c56347SValentin Clement     : public FIROpAndTypeConversion<fir::InsertValueOp>,
227154c56347SValentin Clement       public ValueOpCommon {
227254c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
227354c56347SValentin Clement 
227454c56347SValentin Clement   mlir::LogicalResult
227554c56347SValentin Clement   doRewrite(fir::InsertValueOp insertVal, mlir::Type ty, OpAdaptor adaptor,
227654c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
227754c56347SValentin Clement     auto attrs = collectIndices(rewriter, insertVal.coor());
227854c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
227954c56347SValentin Clement     auto position = mlir::ArrayAttr::get(insertVal.getContext(), attrs);
228054c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
228154c56347SValentin Clement         insertVal, ty, adaptor.getOperands()[0], adaptor.getOperands()[1],
228254c56347SValentin Clement         position);
228354c56347SValentin Clement     return success();
228454c56347SValentin Clement   }
228554c56347SValentin Clement };
228654c56347SValentin Clement 
22873ae8e442SValentin Clement /// InsertOnRange inserts a value into a sequence over a range of offsets.
22883ae8e442SValentin Clement struct InsertOnRangeOpConversion
22893ae8e442SValentin Clement     : public FIROpAndTypeConversion<fir::InsertOnRangeOp> {
22903ae8e442SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
22913ae8e442SValentin Clement 
22923ae8e442SValentin Clement   // Increments an array of subscripts in a row major fasion.
22933ae8e442SValentin Clement   void incrementSubscripts(const SmallVector<uint64_t> &dims,
22943ae8e442SValentin Clement                            SmallVector<uint64_t> &subscripts) const {
22953ae8e442SValentin Clement     for (size_t i = dims.size(); i > 0; --i) {
22963ae8e442SValentin Clement       if (++subscripts[i - 1] < dims[i - 1]) {
22973ae8e442SValentin Clement         return;
22983ae8e442SValentin Clement       }
22993ae8e442SValentin Clement       subscripts[i - 1] = 0;
23003ae8e442SValentin Clement     }
23013ae8e442SValentin Clement   }
23023ae8e442SValentin Clement 
23033ae8e442SValentin Clement   mlir::LogicalResult
23043ae8e442SValentin Clement   doRewrite(fir::InsertOnRangeOp range, mlir::Type ty, OpAdaptor adaptor,
23053ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
23063ae8e442SValentin Clement 
23073ae8e442SValentin Clement     llvm::SmallVector<uint64_t> dims;
23083ae8e442SValentin Clement     auto type = adaptor.getOperands()[0].getType();
23093ae8e442SValentin Clement 
23103ae8e442SValentin Clement     // Iteratively extract the array dimensions from the type.
23113ae8e442SValentin Clement     while (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
23123ae8e442SValentin Clement       dims.push_back(t.getNumElements());
23133ae8e442SValentin Clement       type = t.getElementType();
23143ae8e442SValentin Clement     }
23153ae8e442SValentin Clement 
23163ae8e442SValentin Clement     SmallVector<uint64_t> lBounds;
23173ae8e442SValentin Clement     SmallVector<uint64_t> uBounds;
23183ae8e442SValentin Clement 
23193ae8e442SValentin Clement     // Unzip the upper and lower bound and convert to a row major format.
23208ec0f221SMehdi Amini     mlir::DenseIntElementsAttr coor = range.coor();
23218ec0f221SMehdi Amini     auto reversedCoor = llvm::reverse(coor.getValues<int64_t>());
23228ec0f221SMehdi Amini     for (auto i = reversedCoor.begin(), e = reversedCoor.end(); i != e; ++i) {
23233ae8e442SValentin Clement       uBounds.push_back(*i++);
23243ae8e442SValentin Clement       lBounds.push_back(*i);
23253ae8e442SValentin Clement     }
23263ae8e442SValentin Clement 
23273ae8e442SValentin Clement     auto &subscripts = lBounds;
23283ae8e442SValentin Clement     auto loc = range.getLoc();
23293ae8e442SValentin Clement     mlir::Value lastOp = adaptor.getOperands()[0];
23303ae8e442SValentin Clement     mlir::Value insertVal = adaptor.getOperands()[1];
23313ae8e442SValentin Clement 
23323ae8e442SValentin Clement     auto i64Ty = rewriter.getI64Type();
23333ae8e442SValentin Clement     while (subscripts != uBounds) {
23343ae8e442SValentin Clement       // Convert uint64_t's to Attribute's.
23353ae8e442SValentin Clement       SmallVector<mlir::Attribute> subscriptAttrs;
23363ae8e442SValentin Clement       for (const auto &subscript : subscripts)
23373ae8e442SValentin Clement         subscriptAttrs.push_back(IntegerAttr::get(i64Ty, subscript));
23383ae8e442SValentin Clement       lastOp = rewriter.create<mlir::LLVM::InsertValueOp>(
23393ae8e442SValentin Clement           loc, ty, lastOp, insertVal,
23403ae8e442SValentin Clement           ArrayAttr::get(range.getContext(), subscriptAttrs));
23413ae8e442SValentin Clement 
23423ae8e442SValentin Clement       incrementSubscripts(dims, subscripts);
23433ae8e442SValentin Clement     }
23443ae8e442SValentin Clement 
23453ae8e442SValentin Clement     // Convert uint64_t's to Attribute's.
23463ae8e442SValentin Clement     SmallVector<mlir::Attribute> subscriptAttrs;
23473ae8e442SValentin Clement     for (const auto &subscript : subscripts)
23483ae8e442SValentin Clement       subscriptAttrs.push_back(
23493ae8e442SValentin Clement           IntegerAttr::get(rewriter.getI64Type(), subscript));
23503ae8e442SValentin Clement     mlir::ArrayRef<mlir::Attribute> arrayRef(subscriptAttrs);
23513ae8e442SValentin Clement 
23523ae8e442SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
23533ae8e442SValentin Clement         range, ty, lastOp, insertVal,
23543ae8e442SValentin Clement         ArrayAttr::get(range.getContext(), arrayRef));
23553ae8e442SValentin Clement 
23563ae8e442SValentin Clement     return success();
23573ae8e442SValentin Clement   }
23583ae8e442SValentin Clement };
2359*c2acd453SAlexisPerry } // namespace
23607b5132daSValentin Clement 
23615d27abe6SValentin Clement /// XArrayCoor is the address arithmetic on a dynamically shaped, sliced,
23625d27abe6SValentin Clement /// shifted etc. array.
23635d27abe6SValentin Clement /// (See the static restriction on coordinate_of.) array_coor determines the
23645d27abe6SValentin Clement /// coordinate (location) of a specific element.
23655d27abe6SValentin Clement struct XArrayCoorOpConversion
23665d27abe6SValentin Clement     : public FIROpAndTypeConversion<fir::cg::XArrayCoorOp> {
23675d27abe6SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
23685d27abe6SValentin Clement 
23695d27abe6SValentin Clement   mlir::LogicalResult
23705d27abe6SValentin Clement   doRewrite(fir::cg::XArrayCoorOp coor, mlir::Type ty, OpAdaptor adaptor,
23715d27abe6SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
23725d27abe6SValentin Clement     auto loc = coor.getLoc();
23735d27abe6SValentin Clement     mlir::ValueRange operands = adaptor.getOperands();
23745d27abe6SValentin Clement     unsigned rank = coor.getRank();
23755d27abe6SValentin Clement     assert(coor.indices().size() == rank);
23765d27abe6SValentin Clement     assert(coor.shape().empty() || coor.shape().size() == rank);
23775d27abe6SValentin Clement     assert(coor.shift().empty() || coor.shift().size() == rank);
23785d27abe6SValentin Clement     assert(coor.slice().empty() || coor.slice().size() == 3 * rank);
23795d27abe6SValentin Clement     mlir::Type idxTy = lowerTy().indexType();
23805d27abe6SValentin Clement     mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1);
23815d27abe6SValentin Clement     mlir::Value prevExt = one;
23825d27abe6SValentin Clement     mlir::Value zero = genConstantIndex(loc, idxTy, rewriter, 0);
23835d27abe6SValentin Clement     mlir::Value offset = zero;
23845d27abe6SValentin Clement     const bool isShifted = !coor.shift().empty();
23855d27abe6SValentin Clement     const bool isSliced = !coor.slice().empty();
23865d27abe6SValentin Clement     const bool baseIsBoxed = coor.memref().getType().isa<fir::BoxType>();
23875d27abe6SValentin Clement 
23885d27abe6SValentin Clement     auto indexOps = coor.indices().begin();
23895d27abe6SValentin Clement     auto shapeOps = coor.shape().begin();
23905d27abe6SValentin Clement     auto shiftOps = coor.shift().begin();
23915d27abe6SValentin Clement     auto sliceOps = coor.slice().begin();
23925d27abe6SValentin Clement     // For each dimension of the array, generate the offset calculation.
23935d27abe6SValentin Clement     for (unsigned i = 0; i < rank;
23945d27abe6SValentin Clement          ++i, ++indexOps, ++shapeOps, ++shiftOps, sliceOps += 3) {
23955d27abe6SValentin Clement       mlir::Value index =
23965d27abe6SValentin Clement           integerCast(loc, rewriter, idxTy, operands[coor.indicesOffset() + i]);
23975d27abe6SValentin Clement       mlir::Value lb = isShifted ? integerCast(loc, rewriter, idxTy,
23985d27abe6SValentin Clement                                                operands[coor.shiftOffset() + i])
23995d27abe6SValentin Clement                                  : one;
24005d27abe6SValentin Clement       mlir::Value step = one;
24015d27abe6SValentin Clement       bool normalSlice = isSliced;
24025d27abe6SValentin Clement       // Compute zero based index in dimension i of the element, applying
24035d27abe6SValentin Clement       // potential triplets and lower bounds.
24045d27abe6SValentin Clement       if (isSliced) {
24055d27abe6SValentin Clement         mlir::Value ub = *(sliceOps + 1);
24065d27abe6SValentin Clement         normalSlice = !mlir::isa_and_nonnull<fir::UndefOp>(ub.getDefiningOp());
24075d27abe6SValentin Clement         if (normalSlice)
24085d27abe6SValentin Clement           step = integerCast(loc, rewriter, idxTy, *(sliceOps + 2));
24095d27abe6SValentin Clement       }
24105d27abe6SValentin Clement       auto idx = rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, index, lb);
24115d27abe6SValentin Clement       mlir::Value diff =
24125d27abe6SValentin Clement           rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, idx, step);
24135d27abe6SValentin Clement       if (normalSlice) {
24145d27abe6SValentin Clement         mlir::Value sliceLb =
24155d27abe6SValentin Clement             integerCast(loc, rewriter, idxTy, operands[coor.sliceOffset() + i]);
24165d27abe6SValentin Clement         auto adj = rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, sliceLb, lb);
24175d27abe6SValentin Clement         diff = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, diff, adj);
24185d27abe6SValentin Clement       }
24195d27abe6SValentin Clement       // Update the offset given the stride and the zero based index `diff`
24205d27abe6SValentin Clement       // that was just computed.
24215d27abe6SValentin Clement       if (baseIsBoxed) {
24225d27abe6SValentin Clement         // Use stride in bytes from the descriptor.
24235d27abe6SValentin Clement         mlir::Value stride =
24245d27abe6SValentin Clement             loadStrideFromBox(loc, adaptor.getOperands()[0], i, rewriter);
24255d27abe6SValentin Clement         auto sc = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, stride);
24265d27abe6SValentin Clement         offset = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, offset);
24275d27abe6SValentin Clement       } else {
24285d27abe6SValentin Clement         // Use stride computed at last iteration.
24295d27abe6SValentin Clement         auto sc = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, prevExt);
24305d27abe6SValentin Clement         offset = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, offset);
24315d27abe6SValentin Clement         // Compute next stride assuming contiguity of the base array
24325d27abe6SValentin Clement         // (in element number).
24335d27abe6SValentin Clement         auto nextExt =
24345d27abe6SValentin Clement             integerCast(loc, rewriter, idxTy, operands[coor.shapeOffset() + i]);
24355d27abe6SValentin Clement         prevExt =
24365d27abe6SValentin Clement             rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, prevExt, nextExt);
24375d27abe6SValentin Clement       }
24385d27abe6SValentin Clement     }
24395d27abe6SValentin Clement 
24405d27abe6SValentin Clement     // Add computed offset to the base address.
24415d27abe6SValentin Clement     if (baseIsBoxed) {
24425d27abe6SValentin Clement       // Working with byte offsets. The base address is read from the fir.box.
24435d27abe6SValentin Clement       // and need to be casted to i8* to do the pointer arithmetic.
24445d27abe6SValentin Clement       mlir::Type baseTy =
24455d27abe6SValentin Clement           getBaseAddrTypeFromBox(adaptor.getOperands()[0].getType());
24465d27abe6SValentin Clement       mlir::Value base =
24475d27abe6SValentin Clement           loadBaseAddrFromBox(loc, baseTy, adaptor.getOperands()[0], rewriter);
24485d27abe6SValentin Clement       mlir::Type voidPtrTy = getVoidPtrType();
24495d27abe6SValentin Clement       base = rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, base);
24505d27abe6SValentin Clement       llvm::SmallVector<mlir::Value> args{base, offset};
24515d27abe6SValentin Clement       auto addr = rewriter.create<mlir::LLVM::GEPOp>(loc, voidPtrTy, args);
24525d27abe6SValentin Clement       if (coor.subcomponent().empty()) {
24535d27abe6SValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(coor, baseTy, addr);
24545d27abe6SValentin Clement         return success();
24555d27abe6SValentin Clement       }
24565d27abe6SValentin Clement       auto casted = rewriter.create<mlir::LLVM::BitcastOp>(loc, baseTy, addr);
24575d27abe6SValentin Clement       args.clear();
24585d27abe6SValentin Clement       args.push_back(casted);
24595d27abe6SValentin Clement       args.push_back(zero);
24605d27abe6SValentin Clement       if (!coor.lenParams().empty()) {
24615d27abe6SValentin Clement         // If type parameters are present, then we don't want to use a GEPOp
24625d27abe6SValentin Clement         // as below, as the LLVM struct type cannot be statically defined.
24635d27abe6SValentin Clement         TODO(loc, "derived type with type parameters");
24645d27abe6SValentin Clement       }
24655d27abe6SValentin Clement       // TODO: array offset subcomponents must be converted to LLVM's
24665d27abe6SValentin Clement       // row-major layout here.
24675d27abe6SValentin Clement       for (auto i = coor.subcomponentOffset(); i != coor.indicesOffset(); ++i)
24685d27abe6SValentin Clement         args.push_back(operands[i]);
24695d27abe6SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(coor, baseTy, args);
24705d27abe6SValentin Clement       return success();
24715d27abe6SValentin Clement     }
24725d27abe6SValentin Clement 
24735d27abe6SValentin Clement     // The array was not boxed, so it must be contiguous. offset is therefore an
24745d27abe6SValentin Clement     // element offset and the base type is kept in the GEP unless the element
24755d27abe6SValentin Clement     // type size is itself dynamic.
24765d27abe6SValentin Clement     mlir::Value base;
24775d27abe6SValentin Clement     if (coor.subcomponent().empty()) {
24785d27abe6SValentin Clement       // No subcomponent.
24795d27abe6SValentin Clement       if (!coor.lenParams().empty()) {
24805d27abe6SValentin Clement         // Type parameters. Adjust element size explicitly.
24815d27abe6SValentin Clement         auto eleTy = fir::dyn_cast_ptrEleTy(coor.getType());
24825d27abe6SValentin Clement         assert(eleTy && "result must be a reference-like type");
24835d27abe6SValentin Clement         if (fir::characterWithDynamicLen(eleTy)) {
24845d27abe6SValentin Clement           assert(coor.lenParams().size() == 1);
24855d27abe6SValentin Clement           auto bitsInChar = lowerTy().getKindMap().getCharacterBitsize(
24865d27abe6SValentin Clement               eleTy.cast<fir::CharacterType>().getFKind());
24875d27abe6SValentin Clement           auto scaling = genConstantIndex(loc, idxTy, rewriter, bitsInChar / 8);
24885d27abe6SValentin Clement           auto scaledBySize =
24895d27abe6SValentin Clement               rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, offset, scaling);
24905d27abe6SValentin Clement           auto length =
24915d27abe6SValentin Clement               integerCast(loc, rewriter, idxTy,
24925d27abe6SValentin Clement                           adaptor.getOperands()[coor.lenParamsOffset()]);
24935d27abe6SValentin Clement           offset = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, scaledBySize,
24945d27abe6SValentin Clement                                                       length);
24955d27abe6SValentin Clement         } else {
24965d27abe6SValentin Clement           TODO(loc, "compute size of derived type with type parameters");
24975d27abe6SValentin Clement         }
24985d27abe6SValentin Clement       }
24995d27abe6SValentin Clement       // Cast the base address to a pointer to T.
25005d27abe6SValentin Clement       base = rewriter.create<mlir::LLVM::BitcastOp>(loc, ty,
25015d27abe6SValentin Clement                                                     adaptor.getOperands()[0]);
25025d27abe6SValentin Clement     } else {
25035d27abe6SValentin Clement       // Operand #0 must have a pointer type. For subcomponent slicing, we
25045d27abe6SValentin Clement       // want to cast away the array type and have a plain struct type.
25055d27abe6SValentin Clement       mlir::Type ty0 = adaptor.getOperands()[0].getType();
25065d27abe6SValentin Clement       auto ptrTy = ty0.dyn_cast<mlir::LLVM::LLVMPointerType>();
25075d27abe6SValentin Clement       assert(ptrTy && "expected pointer type");
25085d27abe6SValentin Clement       mlir::Type eleTy = ptrTy.getElementType();
25095d27abe6SValentin Clement       while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>())
25105d27abe6SValentin Clement         eleTy = arrTy.getElementType();
25115d27abe6SValentin Clement       auto newTy = mlir::LLVM::LLVMPointerType::get(eleTy);
25125d27abe6SValentin Clement       base = rewriter.create<mlir::LLVM::BitcastOp>(loc, newTy,
25135d27abe6SValentin Clement                                                     adaptor.getOperands()[0]);
25145d27abe6SValentin Clement     }
25155d27abe6SValentin Clement     SmallVector<mlir::Value> args = {base, offset};
25165d27abe6SValentin Clement     for (auto i = coor.subcomponentOffset(); i != coor.indicesOffset(); ++i)
25175d27abe6SValentin Clement       args.push_back(operands[i]);
25185d27abe6SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(coor, ty, args);
25195d27abe6SValentin Clement     return success();
25205d27abe6SValentin Clement   }
25215d27abe6SValentin Clement };
25225d27abe6SValentin Clement 
25237b5132daSValentin Clement //
25247b5132daSValentin Clement // Primitive operations on Complex types
25257b5132daSValentin Clement //
25267b5132daSValentin Clement 
25277b5132daSValentin Clement /// Generate inline code for complex addition/subtraction
25287b5132daSValentin Clement template <typename LLVMOP, typename OPTY>
2529*c2acd453SAlexisPerry static mlir::LLVM::InsertValueOp
2530*c2acd453SAlexisPerry complexSum(OPTY sumop, mlir::ValueRange opnds,
25317b5132daSValentin Clement            mlir::ConversionPatternRewriter &rewriter,
25327b5132daSValentin Clement            fir::LLVMTypeConverter &lowering) {
25337b5132daSValentin Clement   mlir::Value a = opnds[0];
25347b5132daSValentin Clement   mlir::Value b = opnds[1];
25357b5132daSValentin Clement   auto loc = sumop.getLoc();
25367b5132daSValentin Clement   auto ctx = sumop.getContext();
25377b5132daSValentin Clement   auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
25387b5132daSValentin Clement   auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
25397b5132daSValentin Clement   mlir::Type eleTy = lowering.convertType(getComplexEleTy(sumop.getType()));
25407b5132daSValentin Clement   mlir::Type ty = lowering.convertType(sumop.getType());
25417b5132daSValentin Clement   auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
25427b5132daSValentin Clement   auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
25437b5132daSValentin Clement   auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
25447b5132daSValentin Clement   auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
25457b5132daSValentin Clement   auto rx = rewriter.create<LLVMOP>(loc, eleTy, x0, x1);
25467b5132daSValentin Clement   auto ry = rewriter.create<LLVMOP>(loc, eleTy, y0, y1);
25477b5132daSValentin Clement   auto r0 = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
25487b5132daSValentin Clement   auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r0, rx, c0);
25497b5132daSValentin Clement   return rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ry, c1);
25507b5132daSValentin Clement }
25517b5132daSValentin Clement 
2552*c2acd453SAlexisPerry namespace {
25537b5132daSValentin Clement struct AddcOpConversion : public FIROpConversion<fir::AddcOp> {
25547b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
25557b5132daSValentin Clement 
25567b5132daSValentin Clement   mlir::LogicalResult
25577b5132daSValentin Clement   matchAndRewrite(fir::AddcOp addc, OpAdaptor adaptor,
25587b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
25597b5132daSValentin Clement     // given: (x + iy) + (x' + iy')
25607b5132daSValentin Clement     // result: (x + x') + i(y + y')
25617b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FAddOp>(addc, adaptor.getOperands(),
25627b5132daSValentin Clement                                             rewriter, lowerTy());
25637b5132daSValentin Clement     rewriter.replaceOp(addc, r.getResult());
25647b5132daSValentin Clement     return success();
25657b5132daSValentin Clement   }
25667b5132daSValentin Clement };
25677b5132daSValentin Clement 
25687b5132daSValentin Clement struct SubcOpConversion : public FIROpConversion<fir::SubcOp> {
25697b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
25707b5132daSValentin Clement 
25717b5132daSValentin Clement   mlir::LogicalResult
25727b5132daSValentin Clement   matchAndRewrite(fir::SubcOp subc, OpAdaptor adaptor,
25737b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
25747b5132daSValentin Clement     // given: (x + iy) - (x' + iy')
25757b5132daSValentin Clement     // result: (x - x') + i(y - y')
25767b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FSubOp>(subc, adaptor.getOperands(),
25777b5132daSValentin Clement                                             rewriter, lowerTy());
25787b5132daSValentin Clement     rewriter.replaceOp(subc, r.getResult());
25797b5132daSValentin Clement     return success();
25807b5132daSValentin Clement   }
25817b5132daSValentin Clement };
25827b5132daSValentin Clement 
25837b5132daSValentin Clement /// Inlined complex multiply
25847b5132daSValentin Clement struct MulcOpConversion : public FIROpConversion<fir::MulcOp> {
25857b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
25867b5132daSValentin Clement 
25877b5132daSValentin Clement   mlir::LogicalResult
25887b5132daSValentin Clement   matchAndRewrite(fir::MulcOp mulc, OpAdaptor adaptor,
25897b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
25907b5132daSValentin Clement     // TODO: Can we use a call to __muldc3 ?
25917b5132daSValentin Clement     // given: (x + iy) * (x' + iy')
25927b5132daSValentin Clement     // result: (xx'-yy')+i(xy'+yx')
25937b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
25947b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
25957b5132daSValentin Clement     auto loc = mulc.getLoc();
25967b5132daSValentin Clement     auto *ctx = mulc.getContext();
25977b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
25987b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
25997b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(mulc.getType()));
26007b5132daSValentin Clement     mlir::Type ty = convertType(mulc.getType());
26017b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
26027b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
26037b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
26047b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
26057b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
26067b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
26077b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
26087b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xy, yx);
26097b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
26107b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, xx, yy);
26117b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
26127b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
26137b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
26147b5132daSValentin Clement     rewriter.replaceOp(mulc, r0.getResult());
26157b5132daSValentin Clement     return success();
26167b5132daSValentin Clement   }
26177b5132daSValentin Clement };
26187b5132daSValentin Clement 
26197b5132daSValentin Clement /// Inlined complex division
26207b5132daSValentin Clement struct DivcOpConversion : public FIROpConversion<fir::DivcOp> {
26217b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
26227b5132daSValentin Clement 
26237b5132daSValentin Clement   mlir::LogicalResult
26247b5132daSValentin Clement   matchAndRewrite(fir::DivcOp divc, OpAdaptor adaptor,
26257b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
26267b5132daSValentin Clement     // TODO: Can we use a call to __divdc3 instead?
26277b5132daSValentin Clement     // Just generate inline code for now.
26287b5132daSValentin Clement     // given: (x + iy) / (x' + iy')
26297b5132daSValentin Clement     // result: ((xx'+yy')/d) + i((yx'-xy')/d) where d = x'x' + y'y'
26307b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
26317b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
26327b5132daSValentin Clement     auto loc = divc.getLoc();
26337b5132daSValentin Clement     auto *ctx = divc.getContext();
26347b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
26357b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
26367b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(divc.getType()));
26377b5132daSValentin Clement     mlir::Type ty = convertType(divc.getType());
26387b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
26397b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
26407b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
26417b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
26427b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
26437b5132daSValentin Clement     auto x1x1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x1, x1);
26447b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
26457b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
26467b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
26477b5132daSValentin Clement     auto y1y1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y1, y1);
26487b5132daSValentin Clement     auto d = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, x1x1, y1y1);
26497b5132daSValentin Clement     auto rrn = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xx, yy);
26507b5132daSValentin Clement     auto rin = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, yx, xy);
26517b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rrn, d);
26527b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rin, d);
26537b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
26547b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
26557b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
26567b5132daSValentin Clement     rewriter.replaceOp(divc, r0.getResult());
26577b5132daSValentin Clement     return success();
26587b5132daSValentin Clement   }
26597b5132daSValentin Clement };
26607b5132daSValentin Clement 
26617b5132daSValentin Clement /// Inlined complex negation
26627b5132daSValentin Clement struct NegcOpConversion : public FIROpConversion<fir::NegcOp> {
26637b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
26647b5132daSValentin Clement 
26657b5132daSValentin Clement   mlir::LogicalResult
26667b5132daSValentin Clement   matchAndRewrite(fir::NegcOp neg, OpAdaptor adaptor,
26677b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
26687b5132daSValentin Clement     // given: -(x + iy)
26697b5132daSValentin Clement     // result: -x - iy
26707b5132daSValentin Clement     auto *ctxt = neg.getContext();
26717b5132daSValentin Clement     auto eleTy = convertType(getComplexEleTy(neg.getType()));
26727b5132daSValentin Clement     auto ty = convertType(neg.getType());
26737b5132daSValentin Clement     auto loc = neg.getLoc();
26747b5132daSValentin Clement     mlir::Value o0 = adaptor.getOperands()[0];
26757b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0));
26767b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1));
26777b5132daSValentin Clement     auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c0);
26787b5132daSValentin Clement     auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c1);
26797b5132daSValentin Clement     auto nrp = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, rp);
26807b5132daSValentin Clement     auto nip = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, ip);
26817b5132daSValentin Clement     auto r = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, o0, nrp, c0);
26827b5132daSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(neg, ty, r, nip, c1);
26837b5132daSValentin Clement     return success();
26847b5132daSValentin Clement   }
26857b5132daSValentin Clement };
26867b5132daSValentin Clement 
26871ed5a90fSValentin Clement /// Conversion pattern for operation that must be dead. The information in these
26881ed5a90fSValentin Clement /// operations is used by other operation. At this point they should not have
26891ed5a90fSValentin Clement /// anymore uses.
26901ed5a90fSValentin Clement /// These operations are normally dead after the pre-codegen pass.
26911ed5a90fSValentin Clement template <typename FromOp>
26921ed5a90fSValentin Clement struct MustBeDeadConversion : public FIROpConversion<FromOp> {
26931ed5a90fSValentin Clement   explicit MustBeDeadConversion(fir::LLVMTypeConverter &lowering)
26941ed5a90fSValentin Clement       : FIROpConversion<FromOp>(lowering) {}
26951ed5a90fSValentin Clement   using OpAdaptor = typename FromOp::Adaptor;
26961ed5a90fSValentin Clement 
26971ed5a90fSValentin Clement   mlir::LogicalResult
26981ed5a90fSValentin Clement   matchAndRewrite(FromOp op, OpAdaptor adaptor,
26991ed5a90fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const final {
27001ed5a90fSValentin Clement     if (!op->getUses().empty())
27011ed5a90fSValentin Clement       return rewriter.notifyMatchFailure(op, "op must be dead");
27021ed5a90fSValentin Clement     rewriter.eraseOp(op);
27031ed5a90fSValentin Clement     return success();
27041ed5a90fSValentin Clement   }
27051ed5a90fSValentin Clement };
27061ed5a90fSValentin Clement 
27071ed5a90fSValentin Clement struct ShapeOpConversion : public MustBeDeadConversion<fir::ShapeOp> {
27081ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
27091ed5a90fSValentin Clement };
27101ed5a90fSValentin Clement 
27111ed5a90fSValentin Clement struct ShapeShiftOpConversion : public MustBeDeadConversion<fir::ShapeShiftOp> {
27121ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
27131ed5a90fSValentin Clement };
27141ed5a90fSValentin Clement 
27151ed5a90fSValentin Clement struct ShiftOpConversion : public MustBeDeadConversion<fir::ShiftOp> {
27161ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
27171ed5a90fSValentin Clement };
27181ed5a90fSValentin Clement 
27191ed5a90fSValentin Clement struct SliceOpConversion : public MustBeDeadConversion<fir::SliceOp> {
27201ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
27211ed5a90fSValentin Clement };
27221ed5a90fSValentin Clement 
2723420ad7ceSAndrzej Warzynski /// `fir.is_present` -->
2724420ad7ceSAndrzej Warzynski /// ```
2725420ad7ceSAndrzej Warzynski ///  %0 = llvm.mlir.constant(0 : i64)
2726420ad7ceSAndrzej Warzynski ///  %1 = llvm.ptrtoint %0
2727420ad7ceSAndrzej Warzynski ///  %2 = llvm.icmp "ne" %1, %0 : i64
2728420ad7ceSAndrzej Warzynski /// ```
2729420ad7ceSAndrzej Warzynski struct IsPresentOpConversion : public FIROpConversion<fir::IsPresentOp> {
2730420ad7ceSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
2731420ad7ceSAndrzej Warzynski 
2732420ad7ceSAndrzej Warzynski   mlir::LogicalResult
2733420ad7ceSAndrzej Warzynski   matchAndRewrite(fir::IsPresentOp isPresent, OpAdaptor adaptor,
2734420ad7ceSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
2735420ad7ceSAndrzej Warzynski     mlir::Type idxTy = lowerTy().indexType();
2736420ad7ceSAndrzej Warzynski     mlir::Location loc = isPresent.getLoc();
2737420ad7ceSAndrzej Warzynski     auto ptr = adaptor.getOperands()[0];
2738420ad7ceSAndrzej Warzynski 
2739420ad7ceSAndrzej Warzynski     if (isPresent.val().getType().isa<fir::BoxCharType>()) {
2740420ad7ceSAndrzej Warzynski       auto structTy = ptr.getType().cast<mlir::LLVM::LLVMStructType>();
2741420ad7ceSAndrzej Warzynski       assert(!structTy.isOpaque() && !structTy.getBody().empty());
2742420ad7ceSAndrzej Warzynski 
2743420ad7ceSAndrzej Warzynski       mlir::Type ty = structTy.getBody()[0];
2744420ad7ceSAndrzej Warzynski       mlir::MLIRContext *ctx = isPresent.getContext();
2745420ad7ceSAndrzej Warzynski       auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
2746420ad7ceSAndrzej Warzynski       ptr = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, ptr, c0);
2747420ad7ceSAndrzej Warzynski     }
2748420ad7ceSAndrzej Warzynski     mlir::LLVM::ConstantOp c0 =
2749420ad7ceSAndrzej Warzynski         genConstantIndex(isPresent.getLoc(), idxTy, rewriter, 0);
2750420ad7ceSAndrzej Warzynski     auto addr = rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, ptr);
2751420ad7ceSAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
2752420ad7ceSAndrzej Warzynski         isPresent, mlir::LLVM::ICmpPredicate::ne, addr, c0);
2753420ad7ceSAndrzej Warzynski 
2754420ad7ceSAndrzej Warzynski     return success();
2755420ad7ceSAndrzej Warzynski   }
2756420ad7ceSAndrzej Warzynski };
27571e77b095SAndrzej Warzynski 
27581e77b095SAndrzej Warzynski /// Convert `!fir.emboxchar<!fir.char<KIND, ?>, #n>` into a sequence of
27591e77b095SAndrzej Warzynski /// instructions that generate `!llvm.struct<(ptr<ik>, i64)>`. The 1st element
27601e77b095SAndrzej Warzynski /// in this struct is a pointer. Its type is determined from `KIND`. The 2nd
27611e77b095SAndrzej Warzynski /// element is the length of the character buffer (`#n`).
27621e77b095SAndrzej Warzynski struct EmboxCharOpConversion : public FIROpConversion<fir::EmboxCharOp> {
27631e77b095SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
27641e77b095SAndrzej Warzynski 
27651e77b095SAndrzej Warzynski   mlir::LogicalResult
27661e77b095SAndrzej Warzynski   matchAndRewrite(fir::EmboxCharOp emboxChar, OpAdaptor adaptor,
27671e77b095SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
27681e77b095SAndrzej Warzynski     mlir::ValueRange operands = adaptor.getOperands();
27691e77b095SAndrzej Warzynski     MLIRContext *ctx = emboxChar.getContext();
27701e77b095SAndrzej Warzynski 
27711e77b095SAndrzej Warzynski     mlir::Value charBuffer = operands[0];
27721e77b095SAndrzej Warzynski     mlir::Value charBufferLen = operands[1];
27731e77b095SAndrzej Warzynski 
27741e77b095SAndrzej Warzynski     mlir::Location loc = emboxChar.getLoc();
27751e77b095SAndrzej Warzynski     mlir::Type llvmStructTy = convertType(emboxChar.getType());
27761e77b095SAndrzej Warzynski     auto llvmStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, llvmStructTy);
27771e77b095SAndrzej Warzynski 
27781e77b095SAndrzej Warzynski     mlir::Type lenTy =
27791e77b095SAndrzej Warzynski         llvmStructTy.cast<mlir::LLVM::LLVMStructType>().getBody()[1];
27801e77b095SAndrzej Warzynski     mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, charBufferLen);
27811e77b095SAndrzej Warzynski 
27821e77b095SAndrzej Warzynski     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
27831e77b095SAndrzej Warzynski     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
27841e77b095SAndrzej Warzynski     auto insertBufferOp = rewriter.create<mlir::LLVM::InsertValueOp>(
27851e77b095SAndrzej Warzynski         loc, llvmStructTy, llvmStruct, charBuffer, c0);
27861e77b095SAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
27871e77b095SAndrzej Warzynski         emboxChar, llvmStructTy, insertBufferOp, lenAfterCast, c1);
27881e77b095SAndrzej Warzynski 
27891e77b095SAndrzej Warzynski     return success();
27901e77b095SAndrzej Warzynski   }
27911e77b095SAndrzej Warzynski };
2792*c2acd453SAlexisPerry } // namespace
279314867ffcSAndrzej Warzynski 
279414867ffcSAndrzej Warzynski /// Construct an `llvm.extractvalue` instruction. It will return value at
279514867ffcSAndrzej Warzynski /// element \p x from  \p tuple.
2796*c2acd453SAlexisPerry static mlir::LLVM::ExtractValueOp
279714867ffcSAndrzej Warzynski genExtractValueWithIndex(mlir::Location loc, mlir::Value tuple, mlir::Type ty,
279814867ffcSAndrzej Warzynski                          mlir::ConversionPatternRewriter &rewriter,
279914867ffcSAndrzej Warzynski                          mlir::MLIRContext *ctx, int x) {
280014867ffcSAndrzej Warzynski   auto cx = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(x));
280114867ffcSAndrzej Warzynski   auto xty = ty.cast<mlir::LLVM::LLVMStructType>().getBody()[x];
280214867ffcSAndrzej Warzynski   return rewriter.create<mlir::LLVM::ExtractValueOp>(loc, xty, tuple, cx);
280314867ffcSAndrzej Warzynski }
280414867ffcSAndrzej Warzynski 
2805*c2acd453SAlexisPerry namespace {
28066c3d7fd4SAndrzej Warzynski /// Convert `!fir.boxchar_len` to  `!llvm.extractvalue` for the 2nd part of the
28076c3d7fd4SAndrzej Warzynski /// boxchar.
28086c3d7fd4SAndrzej Warzynski struct BoxCharLenOpConversion : public FIROpConversion<fir::BoxCharLenOp> {
28096c3d7fd4SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
28106c3d7fd4SAndrzej Warzynski 
28116c3d7fd4SAndrzej Warzynski   mlir::LogicalResult
28126c3d7fd4SAndrzej Warzynski   matchAndRewrite(fir::BoxCharLenOp boxCharLen, OpAdaptor adaptor,
28136c3d7fd4SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
28146c3d7fd4SAndrzej Warzynski     mlir::Value boxChar = adaptor.getOperands()[0];
28156c3d7fd4SAndrzej Warzynski     mlir::Location loc = boxChar.getLoc();
28166c3d7fd4SAndrzej Warzynski     mlir::MLIRContext *ctx = boxChar.getContext();
28176c3d7fd4SAndrzej Warzynski     mlir::Type returnValTy = boxCharLen.getResult().getType();
28186c3d7fd4SAndrzej Warzynski 
28196c3d7fd4SAndrzej Warzynski     constexpr int boxcharLenIdx = 1;
28206c3d7fd4SAndrzej Warzynski     mlir::LLVM::ExtractValueOp len = genExtractValueWithIndex(
28216c3d7fd4SAndrzej Warzynski         loc, boxChar, boxChar.getType(), rewriter, ctx, boxcharLenIdx);
28226c3d7fd4SAndrzej Warzynski     mlir::Value lenAfterCast = integerCast(loc, rewriter, returnValTy, len);
28236c3d7fd4SAndrzej Warzynski     rewriter.replaceOp(boxCharLen, lenAfterCast);
28246c3d7fd4SAndrzej Warzynski 
28256c3d7fd4SAndrzej Warzynski     return success();
28266c3d7fd4SAndrzej Warzynski   }
28276c3d7fd4SAndrzej Warzynski };
28286c3d7fd4SAndrzej Warzynski 
282914867ffcSAndrzej Warzynski /// Convert `fir.unboxchar` into two `llvm.extractvalue` instructions. One for
283014867ffcSAndrzej Warzynski /// the character buffer and one for the buffer length.
283114867ffcSAndrzej Warzynski struct UnboxCharOpConversion : public FIROpConversion<fir::UnboxCharOp> {
283214867ffcSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
283314867ffcSAndrzej Warzynski 
283414867ffcSAndrzej Warzynski   mlir::LogicalResult
283514867ffcSAndrzej Warzynski   matchAndRewrite(fir::UnboxCharOp unboxchar, OpAdaptor adaptor,
283614867ffcSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
283714867ffcSAndrzej Warzynski     MLIRContext *ctx = unboxchar.getContext();
283814867ffcSAndrzej Warzynski 
283914867ffcSAndrzej Warzynski     mlir::Type lenTy = convertType(unboxchar.getType(1));
284014867ffcSAndrzej Warzynski     mlir::Value tuple = adaptor.getOperands()[0];
284114867ffcSAndrzej Warzynski     mlir::Type tupleTy = tuple.getType();
284214867ffcSAndrzej Warzynski 
284314867ffcSAndrzej Warzynski     mlir::Location loc = unboxchar.getLoc();
284414867ffcSAndrzej Warzynski     mlir::Value ptrToBuffer =
284514867ffcSAndrzej Warzynski         genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 0);
284614867ffcSAndrzej Warzynski 
284714867ffcSAndrzej Warzynski     mlir::LLVM::ExtractValueOp len =
284814867ffcSAndrzej Warzynski         genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 1);
284914867ffcSAndrzej Warzynski     mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, len);
285014867ffcSAndrzej Warzynski 
285114867ffcSAndrzej Warzynski     rewriter.replaceOp(unboxchar,
285214867ffcSAndrzej Warzynski                        ArrayRef<mlir::Value>{ptrToBuffer, lenAfterCast});
285314867ffcSAndrzej Warzynski     return success();
285414867ffcSAndrzej Warzynski   }
285514867ffcSAndrzej Warzynski };
285614867ffcSAndrzej Warzynski 
2857cc505c0bSKiran Chandramohan /// Lower `fir.unboxproc` operation. Unbox a procedure box value, yielding its
2858cc505c0bSKiran Chandramohan /// components.
2859cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
2860cc505c0bSKiran Chandramohan struct UnboxProcOpConversion : public FIROpConversion<fir::UnboxProcOp> {
2861cc505c0bSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2862cc505c0bSKiran Chandramohan 
2863cc505c0bSKiran Chandramohan   mlir::LogicalResult
2864cc505c0bSKiran Chandramohan   matchAndRewrite(fir::UnboxProcOp unboxproc, OpAdaptor adaptor,
2865cc505c0bSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
28667ce8c6fcSKiran Chandramohan     TODO(unboxproc.getLoc(), "fir.unboxproc codegen");
28677ce8c6fcSKiran Chandramohan     return failure();
2868cc505c0bSKiran Chandramohan   }
2869cc505c0bSKiran Chandramohan };
2870cc505c0bSKiran Chandramohan 
2871e6c66ef5SAndrzej Warzynski /// Convert `fir.field_index`. The conversion depends on whether the size of
2872e6c66ef5SAndrzej Warzynski /// the record is static or dynamic.
2873e6c66ef5SAndrzej Warzynski struct FieldIndexOpConversion : public FIROpConversion<fir::FieldIndexOp> {
2874e6c66ef5SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
2875e6c66ef5SAndrzej Warzynski 
2876e6c66ef5SAndrzej Warzynski   // NB: most field references should be resolved by this point
2877e6c66ef5SAndrzej Warzynski   mlir::LogicalResult
2878e6c66ef5SAndrzej Warzynski   matchAndRewrite(fir::FieldIndexOp field, OpAdaptor adaptor,
2879e6c66ef5SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
2880e6c66ef5SAndrzej Warzynski     auto recTy = field.on_type().cast<fir::RecordType>();
2881e6c66ef5SAndrzej Warzynski     unsigned index = recTy.getFieldIndex(field.field_id());
2882e6c66ef5SAndrzej Warzynski 
2883e6c66ef5SAndrzej Warzynski     if (!fir::hasDynamicSize(recTy)) {
2884e6c66ef5SAndrzej Warzynski       // Derived type has compile-time constant layout. Return index of the
2885e6c66ef5SAndrzej Warzynski       // component type in the parent type (to be used in GEP).
2886e6c66ef5SAndrzej Warzynski       rewriter.replaceOp(field, mlir::ValueRange{genConstantOffset(
2887e6c66ef5SAndrzej Warzynski                                     field.getLoc(), rewriter, index)});
2888e6c66ef5SAndrzej Warzynski       return success();
2889e6c66ef5SAndrzej Warzynski     }
2890e6c66ef5SAndrzej Warzynski 
2891e6c66ef5SAndrzej Warzynski     // Derived type has compile-time constant layout. Call the compiler
2892e6c66ef5SAndrzej Warzynski     // generated function to determine the byte offset of the field at runtime.
2893e6c66ef5SAndrzej Warzynski     // This returns a non-constant.
2894e6c66ef5SAndrzej Warzynski     FlatSymbolRefAttr symAttr = mlir::SymbolRefAttr::get(
2895e6c66ef5SAndrzej Warzynski         field.getContext(), getOffsetMethodName(recTy, field.field_id()));
2896e6c66ef5SAndrzej Warzynski     NamedAttribute callAttr = rewriter.getNamedAttr("callee", symAttr);
2897e6c66ef5SAndrzej Warzynski     NamedAttribute fieldAttr = rewriter.getNamedAttr(
2898e6c66ef5SAndrzej Warzynski         "field", mlir::IntegerAttr::get(lowerTy().indexType(), index));
2899e6c66ef5SAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
2900e6c66ef5SAndrzej Warzynski         field, lowerTy().offsetType(), adaptor.getOperands(),
2901e6c66ef5SAndrzej Warzynski         llvm::ArrayRef<mlir::NamedAttribute>{callAttr, fieldAttr});
2902e6c66ef5SAndrzej Warzynski     return success();
2903e6c66ef5SAndrzej Warzynski   }
2904e6c66ef5SAndrzej Warzynski 
2905e6c66ef5SAndrzej Warzynski   // Re-Construct the name of the compiler generated method that calculates the
2906e6c66ef5SAndrzej Warzynski   // offset
2907e6c66ef5SAndrzej Warzynski   inline static std::string getOffsetMethodName(fir::RecordType recTy,
2908e6c66ef5SAndrzej Warzynski                                                 llvm::StringRef field) {
2909e6c66ef5SAndrzej Warzynski     return recTy.getName().str() + "P." + field.str() + ".offset";
2910e6c66ef5SAndrzej Warzynski   }
2911e6c66ef5SAndrzej Warzynski };
2912e6c66ef5SAndrzej Warzynski 
2913044d5b5dSValentin Clement } // namespace
2914044d5b5dSValentin Clement 
2915044d5b5dSValentin Clement namespace {
2916044d5b5dSValentin Clement /// Convert FIR dialect to LLVM dialect
2917044d5b5dSValentin Clement ///
2918044d5b5dSValentin Clement /// This pass lowers all FIR dialect operations to LLVM IR dialect. An
2919044d5b5dSValentin Clement /// MLIR pass is used to lower residual Std dialect to LLVM IR dialect.
2920044d5b5dSValentin Clement ///
2921044d5b5dSValentin Clement /// This pass is not complete yet. We are upstreaming it in small patches.
2922044d5b5dSValentin Clement class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> {
2923044d5b5dSValentin Clement public:
2924044d5b5dSValentin Clement   mlir::ModuleOp getModule() { return getOperation(); }
2925044d5b5dSValentin Clement 
2926044d5b5dSValentin Clement   void runOnOperation() override final {
29277b5132daSValentin Clement     auto mod = getModule();
29287b5132daSValentin Clement     if (!forcedTargetTriple.empty()) {
29297b5132daSValentin Clement       fir::setTargetTriple(mod, forcedTargetTriple);
29307b5132daSValentin Clement     }
29317b5132daSValentin Clement 
2932044d5b5dSValentin Clement     auto *context = getModule().getContext();
2933044d5b5dSValentin Clement     fir::LLVMTypeConverter typeConverter{getModule()};
2934044d5b5dSValentin Clement     mlir::OwningRewritePatternList pattern(context);
2935df3b9810SValentin Clement     pattern.insert<
2936420ad7ceSAndrzej Warzynski         AbsentOpConversion, AddcOpConversion, AddrOfOpConversion,
2937*c2acd453SAlexisPerry         AllocaOpConversion, AllocMemOpConversion, BoxAddrOpConversion,
2938*c2acd453SAlexisPerry         BoxCharLenOpConversion, BoxDimsOpConversion, BoxEleSizeOpConversion,
2939*c2acd453SAlexisPerry         BoxIsAllocOpConversion, BoxIsArrayOpConversion, BoxIsPtrOpConversion,
2940*c2acd453SAlexisPerry         BoxProcHostOpConversion, BoxRankOpConversion, BoxTypeDescOpConversion,
2941*c2acd453SAlexisPerry         CallOpConversion, CmpcOpConversion, ConstcOpConversion,
2942*c2acd453SAlexisPerry         ConvertOpConversion, DispatchOpConversion, DispatchTableOpConversion,
2943*c2acd453SAlexisPerry         DTEntryOpConversion, DivcOpConversion, EmboxOpConversion,
2944*c2acd453SAlexisPerry         EmboxCharOpConversion, EmboxProcOpConversion, ExtractValueOpConversion,
2945*c2acd453SAlexisPerry         FieldIndexOpConversion, FirEndOpConversion, FreeMemOpConversion,
2946*c2acd453SAlexisPerry         HasValueOpConversion, GenTypeDescOpConversion, GlobalLenOpConversion,
2947*c2acd453SAlexisPerry         GlobalOpConversion, InsertOnRangeOpConversion, InsertValueOpConversion,
2948*c2acd453SAlexisPerry         IsPresentOpConversion, LenParamIndexOpConversion, LoadOpConversion,
2949*c2acd453SAlexisPerry         NegcOpConversion, NoReassocOpConversion, MulcOpConversion,
2950*c2acd453SAlexisPerry         SelectCaseOpConversion, SelectOpConversion, SelectRankOpConversion,
2951*c2acd453SAlexisPerry         SelectTypeOpConversion, ShapeOpConversion, ShapeShiftOpConversion,
2952*c2acd453SAlexisPerry         ShiftOpConversion, SliceOpConversion, StoreOpConversion,
2953*c2acd453SAlexisPerry         StringLitOpConversion, SubcOpConversion, UnboxCharOpConversion,
2954*c2acd453SAlexisPerry         UnboxProcOpConversion, UndefOpConversion, UnreachableOpConversion,
2955*c2acd453SAlexisPerry         XArrayCoorOpConversion, XEmboxOpConversion, XReboxOpConversion,
2956*c2acd453SAlexisPerry         ZeroOpConversion>(typeConverter);
2957044d5b5dSValentin Clement     mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern);
2958044d5b5dSValentin Clement     mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter,
2959044d5b5dSValentin Clement                                                             pattern);
2960044d5b5dSValentin Clement     mlir::ConversionTarget target{*context};
2961044d5b5dSValentin Clement     target.addLegalDialect<mlir::LLVM::LLVMDialect>();
2962044d5b5dSValentin Clement 
2963044d5b5dSValentin Clement     // required NOPs for applying a full conversion
2964044d5b5dSValentin Clement     target.addLegalOp<mlir::ModuleOp>();
2965044d5b5dSValentin Clement 
2966044d5b5dSValentin Clement     // apply the patterns
2967044d5b5dSValentin Clement     if (mlir::failed(mlir::applyFullConversion(getModule(), target,
2968044d5b5dSValentin Clement                                                std::move(pattern)))) {
2969044d5b5dSValentin Clement       signalPassFailure();
2970044d5b5dSValentin Clement     }
2971044d5b5dSValentin Clement   }
2972044d5b5dSValentin Clement };
2973044d5b5dSValentin Clement } // namespace
2974044d5b5dSValentin Clement 
2975044d5b5dSValentin Clement std::unique_ptr<mlir::Pass> fir::createFIRToLLVMPass() {
2976044d5b5dSValentin Clement   return std::make_unique<FIRToLLVMLowering>();
2977044d5b5dSValentin Clement }
2978