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   }
72c2acd453SAlexisPerry   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 };
612c2acd453SAlexisPerry } // 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 
620c2acd453SAlexisPerry 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 };
884c2acd453SAlexisPerry } // namespace
885c2acd453SAlexisPerry 
886c2acd453SAlexisPerry /// Return the LLVMFuncOp corresponding to the standard malloc call.
887c2acd453SAlexisPerry static mlir::LLVM::LLVMFuncOp
888c2acd453SAlexisPerry getMalloc(fir::AllocMemOp op, mlir::ConversionPatternRewriter &rewriter) {
889c2acd453SAlexisPerry   auto module = op->getParentOfType<mlir::ModuleOp>();
890c2acd453SAlexisPerry   if (mlir::LLVM::LLVMFuncOp mallocFunc =
891c2acd453SAlexisPerry           module.lookupSymbol<mlir::LLVM::LLVMFuncOp>("malloc"))
892c2acd453SAlexisPerry     return mallocFunc;
893c2acd453SAlexisPerry   mlir::OpBuilder moduleBuilder(
894c2acd453SAlexisPerry       op->getParentOfType<mlir::ModuleOp>().getBodyRegion());
895c2acd453SAlexisPerry   auto indexType = mlir::IntegerType::get(op.getContext(), 64);
896c2acd453SAlexisPerry   return moduleBuilder.create<mlir::LLVM::LLVMFuncOp>(
897c2acd453SAlexisPerry       rewriter.getUnknownLoc(), "malloc",
898c2acd453SAlexisPerry       mlir::LLVM::LLVMFunctionType::get(getVoidPtrType(op.getContext()),
899c2acd453SAlexisPerry                                         indexType,
900c2acd453SAlexisPerry                                         /*isVarArg=*/false));
901c2acd453SAlexisPerry }
902c2acd453SAlexisPerry 
903c2acd453SAlexisPerry /// Helper function for generating the LLVM IR that computes the size
904c2acd453SAlexisPerry /// in bytes for a derived type.
905c2acd453SAlexisPerry static mlir::Value
906c2acd453SAlexisPerry computeDerivedTypeSize(mlir::Location loc, mlir::Type ptrTy, mlir::Type idxTy,
907c2acd453SAlexisPerry                        mlir::ConversionPatternRewriter &rewriter) {
908c2acd453SAlexisPerry   auto nullPtr = rewriter.create<mlir::LLVM::NullOp>(loc, ptrTy);
909c2acd453SAlexisPerry   mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1);
910c2acd453SAlexisPerry   llvm::SmallVector<mlir::Value> args{nullPtr, one};
911c2acd453SAlexisPerry   auto gep = rewriter.create<mlir::LLVM::GEPOp>(loc, ptrTy, args);
912c2acd453SAlexisPerry   return rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, gep);
913c2acd453SAlexisPerry }
914c2acd453SAlexisPerry 
915c2acd453SAlexisPerry namespace {
916c2acd453SAlexisPerry /// Lower a `fir.allocmem` instruction into `llvm.call @malloc`
917c2acd453SAlexisPerry struct AllocMemOpConversion : public FIROpConversion<fir::AllocMemOp> {
918c2acd453SAlexisPerry   using FIROpConversion::FIROpConversion;
919c2acd453SAlexisPerry 
920c2acd453SAlexisPerry   mlir::LogicalResult
921c2acd453SAlexisPerry   matchAndRewrite(fir::AllocMemOp heap, OpAdaptor adaptor,
922c2acd453SAlexisPerry                   mlir::ConversionPatternRewriter &rewriter) const override {
923c2acd453SAlexisPerry     mlir::Type ty = convertType(heap.getType());
924c2acd453SAlexisPerry     mlir::LLVM::LLVMFuncOp mallocFunc = getMalloc(heap, rewriter);
925c2acd453SAlexisPerry     mlir::Location loc = heap.getLoc();
926c2acd453SAlexisPerry     auto ity = lowerTy().indexType();
927c2acd453SAlexisPerry     if (auto recTy = fir::unwrapSequenceType(heap.getAllocatedType())
928c2acd453SAlexisPerry                          .dyn_cast<fir::RecordType>())
929c2acd453SAlexisPerry       if (recTy.getNumLenParams() != 0) {
930c2acd453SAlexisPerry         TODO(loc,
931c2acd453SAlexisPerry              "fir.allocmem codegen of derived type with length parameters");
932c2acd453SAlexisPerry         return failure();
933c2acd453SAlexisPerry       }
934c2acd453SAlexisPerry     mlir::Value size = genTypeSizeInBytes(loc, ity, rewriter, ty);
935c2acd453SAlexisPerry     for (mlir::Value opnd : adaptor.getOperands())
936c2acd453SAlexisPerry       size = rewriter.create<mlir::LLVM::MulOp>(
937c2acd453SAlexisPerry           loc, ity, size, integerCast(loc, rewriter, ity, opnd));
938c2acd453SAlexisPerry     heap->setAttr("callee", mlir::SymbolRefAttr::get(mallocFunc));
939c2acd453SAlexisPerry     auto malloc = rewriter.create<mlir::LLVM::CallOp>(
940c2acd453SAlexisPerry         loc, ::getVoidPtrType(heap.getContext()), size, heap->getAttrs());
941c2acd453SAlexisPerry     rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(heap, ty,
942c2acd453SAlexisPerry                                                        malloc.getResult(0));
943c2acd453SAlexisPerry     return success();
944c2acd453SAlexisPerry   }
945c2acd453SAlexisPerry 
946c2acd453SAlexisPerry   // Compute the (allocation) size of the allocmem type in bytes.
947c2acd453SAlexisPerry   mlir::Value genTypeSizeInBytes(mlir::Location loc, mlir::Type idxTy,
948c2acd453SAlexisPerry                                  mlir::ConversionPatternRewriter &rewriter,
949c2acd453SAlexisPerry                                  mlir::Type llTy) const {
950c2acd453SAlexisPerry     // Use the primitive size, if available.
951c2acd453SAlexisPerry     auto ptrTy = llTy.dyn_cast<mlir::LLVM::LLVMPointerType>();
952c2acd453SAlexisPerry     if (auto size =
953c2acd453SAlexisPerry             mlir::LLVM::getPrimitiveTypeSizeInBits(ptrTy.getElementType()))
954c2acd453SAlexisPerry       return genConstantIndex(loc, idxTy, rewriter, size / 8);
955c2acd453SAlexisPerry 
956c2acd453SAlexisPerry     // Otherwise, generate the GEP trick in LLVM IR to compute the size.
957c2acd453SAlexisPerry     return computeDerivedTypeSize(loc, ptrTy, idxTy, rewriter);
958c2acd453SAlexisPerry   }
959c2acd453SAlexisPerry };
960c2acd453SAlexisPerry } // namespace
961c2acd453SAlexisPerry 
962c2acd453SAlexisPerry /// Return the LLVMFuncOp corresponding to the standard free call.
963c2acd453SAlexisPerry static mlir::LLVM::LLVMFuncOp
964c2acd453SAlexisPerry getFree(fir::FreeMemOp op, mlir::ConversionPatternRewriter &rewriter) {
965c2acd453SAlexisPerry   auto module = op->getParentOfType<mlir::ModuleOp>();
966c2acd453SAlexisPerry   if (mlir::LLVM::LLVMFuncOp freeFunc =
967c2acd453SAlexisPerry           module.lookupSymbol<mlir::LLVM::LLVMFuncOp>("free"))
968c2acd453SAlexisPerry     return freeFunc;
969c2acd453SAlexisPerry   mlir::OpBuilder moduleBuilder(module.getBodyRegion());
970c2acd453SAlexisPerry   auto voidType = mlir::LLVM::LLVMVoidType::get(op.getContext());
971c2acd453SAlexisPerry   return moduleBuilder.create<mlir::LLVM::LLVMFuncOp>(
972c2acd453SAlexisPerry       rewriter.getUnknownLoc(), "free",
973c2acd453SAlexisPerry       mlir::LLVM::LLVMFunctionType::get(voidType,
974c2acd453SAlexisPerry                                         getVoidPtrType(op.getContext()),
975c2acd453SAlexisPerry                                         /*isVarArg=*/false));
976c2acd453SAlexisPerry }
977c2acd453SAlexisPerry 
978c2acd453SAlexisPerry namespace {
979c2acd453SAlexisPerry /// Lower a `fir.freemem` instruction into `llvm.call @free`
980c2acd453SAlexisPerry struct FreeMemOpConversion : public FIROpConversion<fir::FreeMemOp> {
981c2acd453SAlexisPerry   using FIROpConversion::FIROpConversion;
982c2acd453SAlexisPerry 
983c2acd453SAlexisPerry   mlir::LogicalResult
984c2acd453SAlexisPerry   matchAndRewrite(fir::FreeMemOp freemem, OpAdaptor adaptor,
985c2acd453SAlexisPerry                   mlir::ConversionPatternRewriter &rewriter) const override {
986c2acd453SAlexisPerry     mlir::LLVM::LLVMFuncOp freeFunc = getFree(freemem, rewriter);
987c2acd453SAlexisPerry     mlir::Location loc = freemem.getLoc();
988c2acd453SAlexisPerry     auto bitcast = rewriter.create<mlir::LLVM::BitcastOp>(
989c2acd453SAlexisPerry         freemem.getLoc(), voidPtrTy(), adaptor.getOperands()[0]);
990c2acd453SAlexisPerry     freemem->setAttr("callee", mlir::SymbolRefAttr::get(freeFunc));
991c2acd453SAlexisPerry     rewriter.create<mlir::LLVM::CallOp>(
992c2acd453SAlexisPerry         loc, mlir::TypeRange{}, mlir::ValueRange{bitcast}, freemem->getAttrs());
993c2acd453SAlexisPerry     rewriter.eraseOp(freemem);
994c2acd453SAlexisPerry     return success();
995c2acd453SAlexisPerry   }
996c2acd453SAlexisPerry };
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(
10633012f35fSJacques Pienaar               vecType.cast<ShapedType>(), constant.getValue());
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 };
1106c2acd453SAlexisPerry } // namespace
1107044d5b5dSValentin Clement 
1108c2acd453SAlexisPerry 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>
1120c2acd453SAlexisPerry 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 
1129c2acd453SAlexisPerry static void genCaseLadderStep(mlir::Location loc, mlir::Value cmp,
1130c2acd453SAlexisPerry                               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 
1140c2acd453SAlexisPerry 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 };
1225c2acd453SAlexisPerry } // namespace
122639f4ef81SValentin Clement 
12278c239909SValentin Clement template <typename OP>
1228c2acd453SAlexisPerry 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 
1275c2acd453SAlexisPerry 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 };
1423c2acd453SAlexisPerry } // 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 
2248c2acd453SAlexisPerry 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 };
2359c2acd453SAlexisPerry } // 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>
2529c2acd453SAlexisPerry static mlir::LLVM::InsertValueOp
2530c2acd453SAlexisPerry 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 
2552c2acd453SAlexisPerry 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 };
2792c2acd453SAlexisPerry } // namespace
279314867ffcSAndrzej Warzynski 
279414867ffcSAndrzej Warzynski /// Construct an `llvm.extractvalue` instruction. It will return value at
279514867ffcSAndrzej Warzynski /// element \p x from  \p tuple.
2796c2acd453SAlexisPerry 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 
2805c2acd453SAlexisPerry 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 
2913*75db341dSAndrzej Warzynski /// Convert to (memory) reference to a reference to a subobject.
2914*75db341dSAndrzej Warzynski /// The coordinate_of op is a Swiss army knife operation that can be used on
2915*75db341dSAndrzej Warzynski /// (memory) references to records, arrays, complex, etc. as well as boxes.
2916*75db341dSAndrzej Warzynski /// With unboxed arrays, there is the restriction that the array have a static
2917*75db341dSAndrzej Warzynski /// shape in all but the last column.
2918*75db341dSAndrzej Warzynski struct CoordinateOpConversion
2919*75db341dSAndrzej Warzynski     : public FIROpAndTypeConversion<fir::CoordinateOp> {
2920*75db341dSAndrzej Warzynski   using FIROpAndTypeConversion::FIROpAndTypeConversion;
2921*75db341dSAndrzej Warzynski 
2922*75db341dSAndrzej Warzynski   mlir::LogicalResult
2923*75db341dSAndrzej Warzynski   doRewrite(fir::CoordinateOp coor, mlir::Type ty, OpAdaptor adaptor,
2924*75db341dSAndrzej Warzynski             mlir::ConversionPatternRewriter &rewriter) const override {
2925*75db341dSAndrzej Warzynski     mlir::ValueRange operands = adaptor.getOperands();
2926*75db341dSAndrzej Warzynski 
2927*75db341dSAndrzej Warzynski     mlir::Location loc = coor.getLoc();
2928*75db341dSAndrzej Warzynski     mlir::Value base = operands[0];
2929*75db341dSAndrzej Warzynski     mlir::Type baseObjectTy = coor.getBaseType();
2930*75db341dSAndrzej Warzynski     mlir::Type objectTy = fir::dyn_cast_ptrOrBoxEleTy(baseObjectTy);
2931*75db341dSAndrzej Warzynski     assert(objectTy && "fir.coordinate_of expects a reference type");
2932*75db341dSAndrzej Warzynski 
2933*75db341dSAndrzej Warzynski     // Complex type - basically, extract the real or imaginary part
2934*75db341dSAndrzej Warzynski     if (fir::isa_complex(objectTy)) {
2935*75db341dSAndrzej Warzynski       mlir::LLVM::ConstantOp c0 =
2936*75db341dSAndrzej Warzynski           genConstantIndex(loc, lowerTy().indexType(), rewriter, 0);
2937*75db341dSAndrzej Warzynski       SmallVector<mlir::Value> offs = {c0, operands[1]};
2938*75db341dSAndrzej Warzynski       mlir::Value gep = genGEP(loc, ty, rewriter, base, offs);
2939*75db341dSAndrzej Warzynski       rewriter.replaceOp(coor, gep);
2940*75db341dSAndrzej Warzynski       return success();
2941*75db341dSAndrzej Warzynski     }
2942*75db341dSAndrzej Warzynski 
2943*75db341dSAndrzej Warzynski     // Box type - get the base pointer from the box
2944*75db341dSAndrzej Warzynski     if (auto boxTy = baseObjectTy.dyn_cast<fir::BoxType>()) {
2945*75db341dSAndrzej Warzynski       doRewriteBox(coor, ty, operands, loc, rewriter);
2946*75db341dSAndrzej Warzynski       return success();
2947*75db341dSAndrzej Warzynski     }
2948*75db341dSAndrzej Warzynski 
2949*75db341dSAndrzej Warzynski     // Sequence type (e.g. fir.array)
2950*75db341dSAndrzej Warzynski     if (auto arrTy = objectTy.dyn_cast<fir::SequenceType>()) {
2951*75db341dSAndrzej Warzynski       doRewriteSequence(loc);
2952*75db341dSAndrzej Warzynski       return success();
2953*75db341dSAndrzej Warzynski     }
2954*75db341dSAndrzej Warzynski 
2955*75db341dSAndrzej Warzynski     return rewriter.notifyMatchFailure(
2956*75db341dSAndrzej Warzynski         coor, "fir.coordinate_of base operand has unsupported type");
2957*75db341dSAndrzej Warzynski   }
2958*75db341dSAndrzej Warzynski 
2959*75db341dSAndrzej Warzynski   unsigned getFieldNumber(fir::RecordType ty, mlir::Value op) const {
2960*75db341dSAndrzej Warzynski     return fir::hasDynamicSize(ty)
2961*75db341dSAndrzej Warzynski                ? op.getDefiningOp()
2962*75db341dSAndrzej Warzynski                      ->getAttrOfType<mlir::IntegerAttr>("field")
2963*75db341dSAndrzej Warzynski                      .getInt()
2964*75db341dSAndrzej Warzynski                : getIntValue(op);
2965*75db341dSAndrzej Warzynski   }
2966*75db341dSAndrzej Warzynski 
2967*75db341dSAndrzej Warzynski   int64_t getIntValue(mlir::Value val) const {
2968*75db341dSAndrzej Warzynski     assert(val && val.dyn_cast<mlir::OpResult>() && "must not be null value");
2969*75db341dSAndrzej Warzynski     mlir::Operation *defop = val.getDefiningOp();
2970*75db341dSAndrzej Warzynski 
2971*75db341dSAndrzej Warzynski     if (auto constOp = dyn_cast<mlir::arith::ConstantIntOp>(defop))
2972*75db341dSAndrzej Warzynski       return constOp.value();
2973*75db341dSAndrzej Warzynski     if (auto llConstOp = dyn_cast<mlir::LLVM::ConstantOp>(defop))
2974*75db341dSAndrzej Warzynski       if (auto attr = llConstOp.value().dyn_cast<mlir::IntegerAttr>())
2975*75db341dSAndrzej Warzynski         return attr.getValue().getSExtValue();
2976*75db341dSAndrzej Warzynski     fir::emitFatalError(val.getLoc(), "must be a constant");
2977*75db341dSAndrzej Warzynski   }
2978*75db341dSAndrzej Warzynski 
2979*75db341dSAndrzej Warzynski private:
2980*75db341dSAndrzej Warzynski   void doRewriteBox(fir::CoordinateOp coor, mlir::Type ty,
2981*75db341dSAndrzej Warzynski                     mlir::ValueRange operands, mlir::Location loc,
2982*75db341dSAndrzej Warzynski                     mlir::ConversionPatternRewriter &rewriter) const {
2983*75db341dSAndrzej Warzynski     mlir::Type boxObjTy = coor.getBaseType();
2984*75db341dSAndrzej Warzynski     assert(boxObjTy.dyn_cast<fir::BoxType>() && "This is not a `fir.box`");
2985*75db341dSAndrzej Warzynski 
2986*75db341dSAndrzej Warzynski     mlir::Value boxBaseAddr = operands[0];
2987*75db341dSAndrzej Warzynski 
2988*75db341dSAndrzej Warzynski     // 1. SPECIAL CASE (uses `fir.len_param_index`):
2989*75db341dSAndrzej Warzynski     //   %box = ... : !fir.box<!fir.type<derived{len1:i32}>>
2990*75db341dSAndrzej Warzynski     //   %lenp = fir.len_param_index len1, !fir.type<derived{len1:i32}>
2991*75db341dSAndrzej Warzynski     //   %addr = coordinate_of %box, %lenp
2992*75db341dSAndrzej Warzynski     if (coor.getNumOperands() == 2) {
2993*75db341dSAndrzej Warzynski       mlir::Operation *coordinateDef = (*coor.coor().begin()).getDefiningOp();
2994*75db341dSAndrzej Warzynski       if (isa_and_nonnull<fir::LenParamIndexOp>(coordinateDef)) {
2995*75db341dSAndrzej Warzynski         TODO(loc,
2996*75db341dSAndrzej Warzynski              "fir.coordinate_of - fir.len_param_index is not supported yet");
2997*75db341dSAndrzej Warzynski       }
2998*75db341dSAndrzej Warzynski     }
2999*75db341dSAndrzej Warzynski 
3000*75db341dSAndrzej Warzynski     // 2. GENERAL CASE:
3001*75db341dSAndrzej Warzynski     // 2.1. (`fir.array`)
3002*75db341dSAndrzej Warzynski     //   %box = ... : !fix.box<!fir.array<?xU>>
3003*75db341dSAndrzej Warzynski     //   %idx = ... : index
3004*75db341dSAndrzej Warzynski     //   %resultAddr = coordinate_of %box, %idx : !fir.ref<U>
3005*75db341dSAndrzej Warzynski     // 2.2 (`fir.derived`)
3006*75db341dSAndrzej Warzynski     //   %box = ... : !fix.box<!fir.type<derived_type{field_1:i32}>>
3007*75db341dSAndrzej Warzynski     //   %idx = ... : i32
3008*75db341dSAndrzej Warzynski     //   %resultAddr = coordinate_of %box, %idx : !fir.ref<i32>
3009*75db341dSAndrzej Warzynski     // 2.3 (`fir.derived` inside `fir.array`)
3010*75db341dSAndrzej Warzynski     //   %box = ... : !fir.box<!fir.array<10 x !fir.type<derived_1{field_1:f32, field_2:f32}>>>
3011*75db341dSAndrzej Warzynski     //   %idx1 = ... : index
3012*75db341dSAndrzej Warzynski     //   %idx2 = ... : i32
3013*75db341dSAndrzej Warzynski     //   %resultAddr = coordinate_of %box, %idx1, %idx2 : !fir.ref<f32>
3014*75db341dSAndrzej Warzynski     // 2.4. TODO: Either document or disable any other case that the following
3015*75db341dSAndrzej Warzynski     //  implementation might convert.
3016*75db341dSAndrzej Warzynski     mlir::LLVM::ConstantOp c0 =
3017*75db341dSAndrzej Warzynski         genConstantIndex(loc, lowerTy().indexType(), rewriter, 0);
3018*75db341dSAndrzej Warzynski     mlir::Value resultAddr =
3019*75db341dSAndrzej Warzynski         loadBaseAddrFromBox(loc, getBaseAddrTypeFromBox(boxBaseAddr.getType()),
3020*75db341dSAndrzej Warzynski                             boxBaseAddr, rewriter);
3021*75db341dSAndrzej Warzynski     auto currentObjTy = fir::dyn_cast_ptrOrBoxEleTy(boxObjTy);
3022*75db341dSAndrzej Warzynski     mlir::Type voidPtrTy = ::getVoidPtrType(coor.getContext());
3023*75db341dSAndrzej Warzynski 
3024*75db341dSAndrzej Warzynski     for (unsigned i = 1, last = operands.size(); i < last; ++i) {
3025*75db341dSAndrzej Warzynski       if (auto arrTy = currentObjTy.dyn_cast<fir::SequenceType>()) {
3026*75db341dSAndrzej Warzynski         if (i != 1)
3027*75db341dSAndrzej Warzynski           TODO(loc, "fir.array nested inside other array and/or derived type");
3028*75db341dSAndrzej Warzynski         // Applies byte strides from the box. Ignore lower bound from box
3029*75db341dSAndrzej Warzynski         // since fir.coordinate_of indexes are zero based. Lowering takes care
3030*75db341dSAndrzej Warzynski         // of lower bound aspects. This both accounts for dynamically sized
3031*75db341dSAndrzej Warzynski         // types and non contiguous arrays.
3032*75db341dSAndrzej Warzynski         auto idxTy = lowerTy().indexType();
3033*75db341dSAndrzej Warzynski         mlir::Value off = genConstantIndex(loc, idxTy, rewriter, 0);
3034*75db341dSAndrzej Warzynski         for (unsigned index = i, lastIndex = i + arrTy.getDimension();
3035*75db341dSAndrzej Warzynski              index < lastIndex; ++index) {
3036*75db341dSAndrzej Warzynski           mlir::Value stride =
3037*75db341dSAndrzej Warzynski               loadStrideFromBox(loc, operands[0], index - i, rewriter);
3038*75db341dSAndrzej Warzynski           auto sc = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy,
3039*75db341dSAndrzej Warzynski                                                        operands[index], stride);
3040*75db341dSAndrzej Warzynski           off = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, off);
3041*75db341dSAndrzej Warzynski         }
3042*75db341dSAndrzej Warzynski         auto voidPtrBase =
3043*75db341dSAndrzej Warzynski             rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, resultAddr);
3044*75db341dSAndrzej Warzynski         SmallVector<mlir::Value> args{voidPtrBase, off};
3045*75db341dSAndrzej Warzynski         resultAddr = rewriter.create<mlir::LLVM::GEPOp>(loc, voidPtrTy, args);
3046*75db341dSAndrzej Warzynski         i += arrTy.getDimension() - 1;
3047*75db341dSAndrzej Warzynski         currentObjTy = arrTy.getEleTy();
3048*75db341dSAndrzej Warzynski       } else if (auto recTy = currentObjTy.dyn_cast<fir::RecordType>()) {
3049*75db341dSAndrzej Warzynski         auto recRefTy =
3050*75db341dSAndrzej Warzynski             mlir::LLVM::LLVMPointerType::get(lowerTy().convertType(recTy));
3051*75db341dSAndrzej Warzynski         mlir::Value nxtOpnd = operands[i];
3052*75db341dSAndrzej Warzynski         auto memObj =
3053*75db341dSAndrzej Warzynski             rewriter.create<mlir::LLVM::BitcastOp>(loc, recRefTy, resultAddr);
3054*75db341dSAndrzej Warzynski         llvm::SmallVector<mlir::Value> args = {memObj, c0, nxtOpnd};
3055*75db341dSAndrzej Warzynski         currentObjTy = recTy.getType(getFieldNumber(recTy, nxtOpnd));
3056*75db341dSAndrzej Warzynski         auto llvmCurrentObjTy = lowerTy().convertType(currentObjTy);
3057*75db341dSAndrzej Warzynski         auto gep = rewriter.create<mlir::LLVM::GEPOp>(
3058*75db341dSAndrzej Warzynski             loc, mlir::LLVM::LLVMPointerType::get(llvmCurrentObjTy), args);
3059*75db341dSAndrzej Warzynski         resultAddr =
3060*75db341dSAndrzej Warzynski             rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, gep);
3061*75db341dSAndrzej Warzynski       } else {
3062*75db341dSAndrzej Warzynski         fir::emitFatalError(loc, "unexpected type in coordinate_of");
3063*75db341dSAndrzej Warzynski       }
3064*75db341dSAndrzej Warzynski     }
3065*75db341dSAndrzej Warzynski 
3066*75db341dSAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(coor, ty, resultAddr);
3067*75db341dSAndrzej Warzynski     return;
3068*75db341dSAndrzej Warzynski   }
3069*75db341dSAndrzej Warzynski 
3070*75db341dSAndrzej Warzynski   void doRewriteSequence(mlir::Location loc) const {
3071*75db341dSAndrzej Warzynski     TODO(loc, "fir.coordinate_of codegen for sequence types");
3072*75db341dSAndrzej Warzynski   }
3073*75db341dSAndrzej Warzynski };
3074*75db341dSAndrzej Warzynski 
3075044d5b5dSValentin Clement } // namespace
3076044d5b5dSValentin Clement 
3077044d5b5dSValentin Clement namespace {
3078044d5b5dSValentin Clement /// Convert FIR dialect to LLVM dialect
3079044d5b5dSValentin Clement ///
3080044d5b5dSValentin Clement /// This pass lowers all FIR dialect operations to LLVM IR dialect. An
3081044d5b5dSValentin Clement /// MLIR pass is used to lower residual Std dialect to LLVM IR dialect.
3082044d5b5dSValentin Clement ///
3083044d5b5dSValentin Clement /// This pass is not complete yet. We are upstreaming it in small patches.
3084044d5b5dSValentin Clement class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> {
3085044d5b5dSValentin Clement public:
3086044d5b5dSValentin Clement   mlir::ModuleOp getModule() { return getOperation(); }
3087044d5b5dSValentin Clement 
3088044d5b5dSValentin Clement   void runOnOperation() override final {
30897b5132daSValentin Clement     auto mod = getModule();
30907b5132daSValentin Clement     if (!forcedTargetTriple.empty()) {
30917b5132daSValentin Clement       fir::setTargetTriple(mod, forcedTargetTriple);
30927b5132daSValentin Clement     }
30937b5132daSValentin Clement 
3094044d5b5dSValentin Clement     auto *context = getModule().getContext();
3095044d5b5dSValentin Clement     fir::LLVMTypeConverter typeConverter{getModule()};
3096044d5b5dSValentin Clement     mlir::OwningRewritePatternList pattern(context);
3097df3b9810SValentin Clement     pattern.insert<
3098420ad7ceSAndrzej Warzynski         AbsentOpConversion, AddcOpConversion, AddrOfOpConversion,
3099c2acd453SAlexisPerry         AllocaOpConversion, AllocMemOpConversion, BoxAddrOpConversion,
3100c2acd453SAlexisPerry         BoxCharLenOpConversion, BoxDimsOpConversion, BoxEleSizeOpConversion,
3101c2acd453SAlexisPerry         BoxIsAllocOpConversion, BoxIsArrayOpConversion, BoxIsPtrOpConversion,
3102c2acd453SAlexisPerry         BoxProcHostOpConversion, BoxRankOpConversion, BoxTypeDescOpConversion,
3103c2acd453SAlexisPerry         CallOpConversion, CmpcOpConversion, ConstcOpConversion,
3104*75db341dSAndrzej Warzynski         ConvertOpConversion, CoordinateOpConversion, DispatchOpConversion, DispatchTableOpConversion,
3105c2acd453SAlexisPerry         DTEntryOpConversion, DivcOpConversion, EmboxOpConversion,
3106c2acd453SAlexisPerry         EmboxCharOpConversion, EmboxProcOpConversion, ExtractValueOpConversion,
3107c2acd453SAlexisPerry         FieldIndexOpConversion, FirEndOpConversion, FreeMemOpConversion,
3108c2acd453SAlexisPerry         HasValueOpConversion, GenTypeDescOpConversion, GlobalLenOpConversion,
3109c2acd453SAlexisPerry         GlobalOpConversion, InsertOnRangeOpConversion, InsertValueOpConversion,
3110c2acd453SAlexisPerry         IsPresentOpConversion, LenParamIndexOpConversion, LoadOpConversion,
3111c2acd453SAlexisPerry         NegcOpConversion, NoReassocOpConversion, MulcOpConversion,
3112c2acd453SAlexisPerry         SelectCaseOpConversion, SelectOpConversion, SelectRankOpConversion,
3113c2acd453SAlexisPerry         SelectTypeOpConversion, ShapeOpConversion, ShapeShiftOpConversion,
3114c2acd453SAlexisPerry         ShiftOpConversion, SliceOpConversion, StoreOpConversion,
3115c2acd453SAlexisPerry         StringLitOpConversion, SubcOpConversion, UnboxCharOpConversion,
3116c2acd453SAlexisPerry         UnboxProcOpConversion, UndefOpConversion, UnreachableOpConversion,
3117c2acd453SAlexisPerry         XArrayCoorOpConversion, XEmboxOpConversion, XReboxOpConversion,
3118c2acd453SAlexisPerry         ZeroOpConversion>(typeConverter);
3119044d5b5dSValentin Clement     mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern);
3120044d5b5dSValentin Clement     mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter,
3121044d5b5dSValentin Clement                                                             pattern);
3122044d5b5dSValentin Clement     mlir::ConversionTarget target{*context};
3123044d5b5dSValentin Clement     target.addLegalDialect<mlir::LLVM::LLVMDialect>();
3124044d5b5dSValentin Clement 
3125044d5b5dSValentin Clement     // required NOPs for applying a full conversion
3126044d5b5dSValentin Clement     target.addLegalOp<mlir::ModuleOp>();
3127044d5b5dSValentin Clement 
3128044d5b5dSValentin Clement     // apply the patterns
3129044d5b5dSValentin Clement     if (mlir::failed(mlir::applyFullConversion(getModule(), target,
3130044d5b5dSValentin Clement                                                std::move(pattern)))) {
3131044d5b5dSValentin Clement       signalPassFailure();
3132044d5b5dSValentin Clement     }
3133044d5b5dSValentin Clement   }
3134044d5b5dSValentin Clement };
3135044d5b5dSValentin Clement } // namespace
3136044d5b5dSValentin Clement 
3137044d5b5dSValentin Clement std::unique_ptr<mlir::Pass> fir::createFIRToLLVMPass() {
3138044d5b5dSValentin Clement   return std::make_unique<FIRToLLVMLowering>();
3139044d5b5dSValentin Clement }
3140