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"
197dd7ccd2SJean Perier #include "flang/Optimizer/Support/InternalNames.h"
20af6ee580SValentin Clement #include "flang/Optimizer/Support/TypeCode.h"
217dd7ccd2SJean Perier #include "flang/Semantics/runtime-type-info.h"
22044d5b5dSValentin Clement #include "mlir/Conversion/ArithmeticToLLVM/ArithmeticToLLVM.h"
23ace01605SRiver Riddle #include "mlir/Conversion/ControlFlowToLLVM/ControlFlowToLLVM.h"
245a7b9194SRiver Riddle #include "mlir/Conversion/FuncToLLVM/ConvertFuncToLLVM.h"
25044d5b5dSValentin Clement #include "mlir/Conversion/LLVMCommon/Pattern.h"
26c6ac9370SKiran Chandramohan #include "mlir/Conversion/OpenMPToLLVM/ConvertOpenMPToLLVM.h"
27044d5b5dSValentin Clement #include "mlir/IR/BuiltinTypes.h"
283ae8e442SValentin Clement #include "mlir/IR/Matchers.h"
29044d5b5dSValentin Clement #include "mlir/Pass/Pass.h"
30853e79d8SValentin Clement #include "mlir/Target/LLVMIR/ModuleTranslation.h"
31044d5b5dSValentin Clement #include "llvm/ADT/ArrayRef.h"
32044d5b5dSValentin Clement 
33044d5b5dSValentin Clement #define DEBUG_TYPE "flang-codegen"
34044d5b5dSValentin Clement 
35044d5b5dSValentin Clement // fir::LLVMTypeConverter for converting to LLVM IR dialect types.
36044d5b5dSValentin Clement #include "TypeConverter.h"
37044d5b5dSValentin Clement 
38af6ee580SValentin Clement // TODO: This should really be recovered from the specified target.
39af6ee580SValentin Clement static constexpr unsigned defaultAlign = 8;
40af6ee580SValentin Clement 
41b6e44ecdSValentin Clement /// `fir.box` attribute values as defined for CFI_attribute_t in
42b6e44ecdSValentin Clement /// flang/ISO_Fortran_binding.h.
43b6e44ecdSValentin Clement static constexpr unsigned kAttrPointer = CFI_attribute_pointer;
44b6e44ecdSValentin Clement static constexpr unsigned kAttrAllocatable = CFI_attribute_allocatable;
45b6e44ecdSValentin Clement 
46135d5d4aSKiran Chandramohan static inline mlir::Type getVoidPtrType(mlir::MLIRContext *context) {
47fa517555SKiran Chandramohan   return mlir::LLVM::LLVMPointerType::get(mlir::IntegerType::get(context, 8));
48fa517555SKiran Chandramohan }
49fa517555SKiran Chandramohan 
501e6d9c06SDiana Picus static mlir::LLVM::ConstantOp
511e6d9c06SDiana Picus genConstantIndex(mlir::Location loc, mlir::Type ity,
521e6d9c06SDiana Picus                  mlir::ConversionPatternRewriter &rewriter,
531e6d9c06SDiana Picus                  std::int64_t offset) {
541e6d9c06SDiana Picus   auto cattr = rewriter.getI64IntegerAttr(offset);
551e6d9c06SDiana Picus   return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr);
561e6d9c06SDiana Picus }
571e6d9c06SDiana Picus 
5844e58509SEric Schweitz static mlir::Block *createBlock(mlir::ConversionPatternRewriter &rewriter,
5939f4ef81SValentin Clement                                 mlir::Block *insertBefore) {
6039f4ef81SValentin Clement   assert(insertBefore && "expected valid insertion block");
6139f4ef81SValentin Clement   return rewriter.createBlock(insertBefore->getParent(),
6239f4ef81SValentin Clement                               mlir::Region::iterator(insertBefore));
6339f4ef81SValentin Clement }
6439f4ef81SValentin Clement 
65044d5b5dSValentin Clement namespace {
66044d5b5dSValentin Clement /// FIR conversion pattern template
67044d5b5dSValentin Clement template <typename FromOp>
68044d5b5dSValentin Clement class FIROpConversion : public mlir::ConvertOpToLLVMPattern<FromOp> {
69044d5b5dSValentin Clement public:
70013160f6SJean Perier   explicit FIROpConversion(fir::LLVMTypeConverter &lowering,
71013160f6SJean Perier                            const fir::FIRToLLVMPassOptions &options)
72013160f6SJean Perier       : mlir::ConvertOpToLLVMPattern<FromOp>(lowering), options(options) {}
73044d5b5dSValentin Clement 
74044d5b5dSValentin Clement protected:
75044d5b5dSValentin Clement   mlir::Type convertType(mlir::Type ty) const {
76044d5b5dSValentin Clement     return lowerTy().convertType(ty);
77044d5b5dSValentin Clement   }
78c2acd453SAlexisPerry   mlir::Type voidPtrTy() const { return getVoidPtrType(); }
79044d5b5dSValentin Clement 
805d27abe6SValentin Clement   mlir::Type getVoidPtrType() const {
815d27abe6SValentin Clement     return mlir::LLVM::LLVMPointerType::get(
825d27abe6SValentin Clement         mlir::IntegerType::get(&lowerTy().getContext(), 8));
835d27abe6SValentin Clement   }
845d27abe6SValentin Clement 
85df3b9810SValentin Clement   mlir::LLVM::ConstantOp
86af6ee580SValentin Clement   genI32Constant(mlir::Location loc, mlir::ConversionPatternRewriter &rewriter,
87af6ee580SValentin Clement                  int value) const {
88af6ee580SValentin Clement     mlir::Type i32Ty = rewriter.getI32Type();
89af6ee580SValentin Clement     mlir::IntegerAttr attr = rewriter.getI32IntegerAttr(value);
90af6ee580SValentin Clement     return rewriter.create<mlir::LLVM::ConstantOp>(loc, i32Ty, attr);
91af6ee580SValentin Clement   }
92af6ee580SValentin Clement 
93af6ee580SValentin Clement   mlir::LLVM::ConstantOp
94df3b9810SValentin Clement   genConstantOffset(mlir::Location loc,
95df3b9810SValentin Clement                     mlir::ConversionPatternRewriter &rewriter,
96df3b9810SValentin Clement                     int offset) const {
97af6ee580SValentin Clement     mlir::Type ity = lowerTy().offsetType();
98af6ee580SValentin Clement     mlir::IntegerAttr cattr = rewriter.getI32IntegerAttr(offset);
99df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr);
100df3b9810SValentin Clement   }
101df3b9810SValentin Clement 
102dc48849fSKiran Chandramohan   /// Perform an extension or truncation as needed on an integer value. Lowering
103dc48849fSKiran Chandramohan   /// to the specific target may involve some sign-extending or truncation of
104dc48849fSKiran Chandramohan   /// values, particularly to fit them from abstract box types to the
105dc48849fSKiran Chandramohan   /// appropriate reified structures.
106dc48849fSKiran Chandramohan   mlir::Value integerCast(mlir::Location loc,
107dc48849fSKiran Chandramohan                           mlir::ConversionPatternRewriter &rewriter,
108dc48849fSKiran Chandramohan                           mlir::Type ty, mlir::Value val) const {
109dc48849fSKiran Chandramohan     auto valTy = val.getType();
110dc48849fSKiran Chandramohan     // If the value was not yet lowered, lower its type so that it can
111dc48849fSKiran Chandramohan     // be used in getPrimitiveTypeSizeInBits.
112dc48849fSKiran Chandramohan     if (!valTy.isa<mlir::IntegerType>())
113dc48849fSKiran Chandramohan       valTy = convertType(valTy);
114dc48849fSKiran Chandramohan     auto toSize = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
115dc48849fSKiran Chandramohan     auto fromSize = mlir::LLVM::getPrimitiveTypeSizeInBits(valTy);
116dc48849fSKiran Chandramohan     if (toSize < fromSize)
117dc48849fSKiran Chandramohan       return rewriter.create<mlir::LLVM::TruncOp>(loc, ty, val);
118dc48849fSKiran Chandramohan     if (toSize > fromSize)
119dc48849fSKiran Chandramohan       return rewriter.create<mlir::LLVM::SExtOp>(loc, ty, val);
120dc48849fSKiran Chandramohan     return val;
121dc48849fSKiran Chandramohan   }
122dc48849fSKiran Chandramohan 
123b6e44ecdSValentin Clement   /// Construct code sequence to extract the specifc value from a `fir.box`.
124b6e44ecdSValentin Clement   mlir::Value getValueFromBox(mlir::Location loc, mlir::Value box,
125df3b9810SValentin Clement                               mlir::Type resultTy,
126b6e44ecdSValentin Clement                               mlir::ConversionPatternRewriter &rewriter,
127b6e44ecdSValentin Clement                               unsigned boxValue) const {
128df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
129b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp cValuePos =
130b6e44ecdSValentin Clement         genConstantOffset(loc, rewriter, boxValue);
131df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(resultTy);
132df3b9810SValentin Clement     auto p = rewriter.create<mlir::LLVM::GEPOp>(
13330122656SAlex Zinenko         loc, pty, box, mlir::ValueRange{c0, cValuePos});
134df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, resultTy, p);
135df3b9810SValentin Clement   }
136df3b9810SValentin Clement 
137df3b9810SValentin Clement   /// Method to construct code sequence to get the triple for dimension `dim`
138df3b9810SValentin Clement   /// from a box.
13944e58509SEric Schweitz   llvm::SmallVector<mlir::Value, 3>
14044e58509SEric Schweitz   getDimsFromBox(mlir::Location loc, llvm::ArrayRef<mlir::Type> retTys,
141df3b9810SValentin Clement                  mlir::Value box, mlir::Value dim,
142df3b9810SValentin Clement                  mlir::ConversionPatternRewriter &rewriter) const {
143df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
144df3b9810SValentin Clement     mlir::LLVM::ConstantOp cDims =
145df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kDimsPosInBox);
146df3b9810SValentin Clement     mlir::LLVM::LoadOp l0 =
147df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 0, retTys[0], rewriter);
148df3b9810SValentin Clement     mlir::LLVM::LoadOp l1 =
149df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 1, retTys[1], rewriter);
150df3b9810SValentin Clement     mlir::LLVM::LoadOp l2 =
151df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 2, retTys[2], rewriter);
152df3b9810SValentin Clement     return {l0.getResult(), l1.getResult(), l2.getResult()};
153df3b9810SValentin Clement   }
154df3b9810SValentin Clement 
155df3b9810SValentin Clement   mlir::LLVM::LoadOp
156df3b9810SValentin Clement   loadFromOffset(mlir::Location loc, mlir::Value a, mlir::LLVM::ConstantOp c0,
157df3b9810SValentin Clement                  mlir::LLVM::ConstantOp cDims, mlir::Value dim, int off,
158df3b9810SValentin Clement                  mlir::Type ty,
159df3b9810SValentin Clement                  mlir::ConversionPatternRewriter &rewriter) const {
160df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
161df3b9810SValentin Clement     mlir::LLVM::ConstantOp c = genConstantOffset(loc, rewriter, off);
162df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, a, c0, cDims, dim, c);
163df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
164df3b9810SValentin Clement   }
165df3b9810SValentin Clement 
1665d27abe6SValentin Clement   mlir::Value
1675d27abe6SValentin Clement   loadStrideFromBox(mlir::Location loc, mlir::Value box, unsigned dim,
1685d27abe6SValentin Clement                     mlir::ConversionPatternRewriter &rewriter) const {
1695d27abe6SValentin Clement     auto idxTy = lowerTy().indexType();
1705d27abe6SValentin Clement     auto c0 = genConstantOffset(loc, rewriter, 0);
1715d27abe6SValentin Clement     auto cDims = genConstantOffset(loc, rewriter, kDimsPosInBox);
1725d27abe6SValentin Clement     auto dimValue = genConstantIndex(loc, idxTy, rewriter, dim);
1735d27abe6SValentin Clement     return loadFromOffset(loc, box, c0, cDims, dimValue, kDimStridePos, idxTy,
1745d27abe6SValentin Clement                           rewriter);
1755d27abe6SValentin Clement   }
1765d27abe6SValentin Clement 
177df3b9810SValentin Clement   /// Read base address from a fir.box. Returned address has type ty.
178df3b9810SValentin Clement   mlir::Value
179df3b9810SValentin Clement   loadBaseAddrFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box,
180df3b9810SValentin Clement                       mlir::ConversionPatternRewriter &rewriter) const {
181df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
182df3b9810SValentin Clement     mlir::LLVM::ConstantOp cAddr =
183df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kAddrPosInBox);
184df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
185df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cAddr);
186df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
187df3b9810SValentin Clement   }
188df3b9810SValentin Clement 
189df3b9810SValentin Clement   mlir::Value
190df3b9810SValentin Clement   loadElementSizeFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box,
191df3b9810SValentin Clement                          mlir::ConversionPatternRewriter &rewriter) const {
192df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
193df3b9810SValentin Clement     mlir::LLVM::ConstantOp cElemLen =
194df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kElemLenPosInBox);
195df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
196df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cElemLen);
197df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
198df3b9810SValentin Clement   }
199df3b9810SValentin Clement 
200af6ee580SValentin Clement   // Get the element type given an LLVM type that is of the form
201af6ee580SValentin Clement   // [llvm.ptr](array|struct|vector)+ and the provided indexes.
202af6ee580SValentin Clement   static mlir::Type getBoxEleTy(mlir::Type type,
203af6ee580SValentin Clement                                 llvm::ArrayRef<unsigned> indexes) {
204af6ee580SValentin Clement     if (auto t = type.dyn_cast<mlir::LLVM::LLVMPointerType>())
205af6ee580SValentin Clement       type = t.getElementType();
206af6ee580SValentin Clement     for (auto i : indexes) {
207af6ee580SValentin Clement       if (auto t = type.dyn_cast<mlir::LLVM::LLVMStructType>()) {
208af6ee580SValentin Clement         assert(!t.isOpaque() && i < t.getBody().size());
209af6ee580SValentin Clement         type = t.getBody()[i];
210af6ee580SValentin Clement       } else if (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
211af6ee580SValentin Clement         type = t.getElementType();
212af6ee580SValentin Clement       } else if (auto t = type.dyn_cast<mlir::VectorType>()) {
213af6ee580SValentin Clement         type = t.getElementType();
214af6ee580SValentin Clement       } else {
215af6ee580SValentin Clement         fir::emitFatalError(mlir::UnknownLoc::get(type.getContext()),
216af6ee580SValentin Clement                             "request for invalid box element type");
217af6ee580SValentin Clement       }
218af6ee580SValentin Clement     }
219af6ee580SValentin Clement     return type;
220af6ee580SValentin Clement   }
221af6ee580SValentin Clement 
2225d27abe6SValentin Clement   // Return LLVM type of the base address given the LLVM type
2235d27abe6SValentin Clement   // of the related descriptor (lowered fir.box type).
2245d27abe6SValentin Clement   static mlir::Type getBaseAddrTypeFromBox(mlir::Type type) {
2255d27abe6SValentin Clement     return getBoxEleTy(type, {kAddrPosInBox});
2265d27abe6SValentin Clement   }
2275d27abe6SValentin Clement 
228dc48849fSKiran Chandramohan   // Load the attribute from the \p box and perform a check against \p maskValue
229dc48849fSKiran Chandramohan   // The final comparison is implemented as `(attribute & maskValue) != 0`.
230dc48849fSKiran Chandramohan   mlir::Value genBoxAttributeCheck(mlir::Location loc, mlir::Value box,
231dc48849fSKiran Chandramohan                                    mlir::ConversionPatternRewriter &rewriter,
232dc48849fSKiran Chandramohan                                    unsigned maskValue) const {
233dc48849fSKiran Chandramohan     mlir::Type attrTy = rewriter.getI32Type();
234dc48849fSKiran Chandramohan     mlir::Value attribute =
235dc48849fSKiran Chandramohan         getValueFromBox(loc, box, attrTy, rewriter, kAttributePosInBox);
236dc48849fSKiran Chandramohan     mlir::LLVM::ConstantOp attrMask =
237dc48849fSKiran Chandramohan         genConstantOffset(loc, rewriter, maskValue);
238dc48849fSKiran Chandramohan     auto maskRes =
239dc48849fSKiran Chandramohan         rewriter.create<mlir::LLVM::AndOp>(loc, attrTy, attribute, attrMask);
240dc48849fSKiran Chandramohan     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
241dc48849fSKiran Chandramohan     return rewriter.create<mlir::LLVM::ICmpOp>(
242dc48849fSKiran Chandramohan         loc, mlir::LLVM::ICmpPredicate::ne, maskRes, c0);
243dc48849fSKiran Chandramohan   }
244dc48849fSKiran Chandramohan 
245df3b9810SValentin Clement   template <typename... ARGS>
246df3b9810SValentin Clement   mlir::LLVM::GEPOp genGEP(mlir::Location loc, mlir::Type ty,
247df3b9810SValentin Clement                            mlir::ConversionPatternRewriter &rewriter,
248df3b9810SValentin Clement                            mlir::Value base, ARGS... args) const {
24944e58509SEric Schweitz     llvm::SmallVector<mlir::Value> cv{args...};
250df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::GEPOp>(loc, ty, base, cv);
251df3b9810SValentin Clement   }
252df3b9810SValentin Clement 
253044d5b5dSValentin Clement   fir::LLVMTypeConverter &lowerTy() const {
254044d5b5dSValentin Clement     return *static_cast<fir::LLVMTypeConverter *>(this->getTypeConverter());
255044d5b5dSValentin Clement   }
256013160f6SJean Perier 
257013160f6SJean Perier   const fir::FIRToLLVMPassOptions &options;
258044d5b5dSValentin Clement };
259044d5b5dSValentin Clement 
2603ae8e442SValentin Clement /// FIR conversion pattern template
2613ae8e442SValentin Clement template <typename FromOp>
2623ae8e442SValentin Clement class FIROpAndTypeConversion : public FIROpConversion<FromOp> {
2633ae8e442SValentin Clement public:
2643ae8e442SValentin Clement   using FIROpConversion<FromOp>::FIROpConversion;
2653ae8e442SValentin Clement   using OpAdaptor = typename FromOp::Adaptor;
2663ae8e442SValentin Clement 
2673ae8e442SValentin Clement   mlir::LogicalResult
2683ae8e442SValentin Clement   matchAndRewrite(FromOp op, OpAdaptor adaptor,
2693ae8e442SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const final {
2703ae8e442SValentin Clement     mlir::Type ty = this->convertType(op.getType());
2713ae8e442SValentin Clement     return doRewrite(op, ty, adaptor, rewriter);
2723ae8e442SValentin Clement   }
2733ae8e442SValentin Clement 
2743ae8e442SValentin Clement   virtual mlir::LogicalResult
2753ae8e442SValentin Clement   doRewrite(FromOp addr, mlir::Type ty, OpAdaptor adaptor,
2763ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const = 0;
2773ae8e442SValentin Clement };
2783ae8e442SValentin Clement 
2790c4a7a52SValentin Clement // Lower `fir.address_of` operation to `llvm.address_of` operation.
280044d5b5dSValentin Clement struct AddrOfOpConversion : public FIROpConversion<fir::AddrOfOp> {
281044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
282044d5b5dSValentin Clement 
283044d5b5dSValentin Clement   mlir::LogicalResult
284044d5b5dSValentin Clement   matchAndRewrite(fir::AddrOfOp addr, OpAdaptor adaptor,
285044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
286044d5b5dSValentin Clement     auto ty = convertType(addr.getType());
287044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::AddressOfOp>(
288149ad3d5SShraiysh Vaishay         addr, ty, addr.getSymbol().getRootReference().getValue());
28944e58509SEric Schweitz     return mlir::success();
290044d5b5dSValentin Clement   }
291044d5b5dSValentin Clement };
2921e6d9c06SDiana Picus } // namespace
2931e6d9c06SDiana Picus 
2941e6d9c06SDiana Picus /// Lookup the function to compute the memory size of this parametric derived
2951e6d9c06SDiana Picus /// type. The size of the object may depend on the LEN type parameters of the
2961e6d9c06SDiana Picus /// derived type.
2971e6d9c06SDiana Picus static mlir::LLVM::LLVMFuncOp
2981e6d9c06SDiana Picus getDependentTypeMemSizeFn(fir::RecordType recTy, fir::AllocaOp op,
2991e6d9c06SDiana Picus                           mlir::ConversionPatternRewriter &rewriter) {
3001e6d9c06SDiana Picus   auto module = op->getParentOfType<mlir::ModuleOp>();
3011e6d9c06SDiana Picus   std::string name = recTy.getName().str() + "P.mem.size";
3021e6d9c06SDiana Picus   return module.lookupSymbol<mlir::LLVM::LLVMFuncOp>(name);
3031e6d9c06SDiana Picus }
3041e6d9c06SDiana Picus 
305*ac0f4c8fSPeixinQiao // Compute the alloc scale size (constant factors encoded in the array type).
306*ac0f4c8fSPeixinQiao // We do this for arrays without a constant interior or arrays of character with
307*ac0f4c8fSPeixinQiao // dynamic length arrays, since those are the only ones that get decayed to a
308*ac0f4c8fSPeixinQiao // pointer to the element type.
309*ac0f4c8fSPeixinQiao template <typename OP>
310*ac0f4c8fSPeixinQiao static mlir::Value
311*ac0f4c8fSPeixinQiao genAllocationScaleSize(OP op, mlir::Type ity,
312*ac0f4c8fSPeixinQiao                        mlir::ConversionPatternRewriter &rewriter) {
313*ac0f4c8fSPeixinQiao   mlir::Location loc = op.getLoc();
314*ac0f4c8fSPeixinQiao   mlir::Type dataTy = op.getInType();
315*ac0f4c8fSPeixinQiao   mlir::Type scalarType = fir::unwrapSequenceType(dataTy);
316*ac0f4c8fSPeixinQiao   auto seqTy = dataTy.dyn_cast<fir::SequenceType>();
317*ac0f4c8fSPeixinQiao   if ((op.hasShapeOperands() && seqTy && !seqTy.hasConstantInterior()) ||
318*ac0f4c8fSPeixinQiao       (seqTy && fir::characterWithDynamicLen(scalarType))) {
319*ac0f4c8fSPeixinQiao     fir::SequenceType::Extent constSize = 1;
320*ac0f4c8fSPeixinQiao     for (auto extent : seqTy.getShape())
321*ac0f4c8fSPeixinQiao       if (extent != fir::SequenceType::getUnknownExtent())
322*ac0f4c8fSPeixinQiao         constSize *= extent;
323*ac0f4c8fSPeixinQiao     if (constSize != 1) {
324*ac0f4c8fSPeixinQiao       mlir::Value constVal{
325*ac0f4c8fSPeixinQiao           genConstantIndex(loc, ity, rewriter, constSize).getResult()};
326*ac0f4c8fSPeixinQiao       return constVal;
327*ac0f4c8fSPeixinQiao     }
328*ac0f4c8fSPeixinQiao   }
329*ac0f4c8fSPeixinQiao   return nullptr;
330*ac0f4c8fSPeixinQiao }
331*ac0f4c8fSPeixinQiao 
3321e6d9c06SDiana Picus namespace {
3331e6d9c06SDiana Picus /// convert to LLVM IR dialect `alloca`
3341e6d9c06SDiana Picus struct AllocaOpConversion : public FIROpConversion<fir::AllocaOp> {
3351e6d9c06SDiana Picus   using FIROpConversion::FIROpConversion;
3361e6d9c06SDiana Picus 
3371e6d9c06SDiana Picus   mlir::LogicalResult
3381e6d9c06SDiana Picus   matchAndRewrite(fir::AllocaOp alloc, OpAdaptor adaptor,
3391e6d9c06SDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
3401e6d9c06SDiana Picus     mlir::ValueRange operands = adaptor.getOperands();
3411e6d9c06SDiana Picus     auto loc = alloc.getLoc();
3421e6d9c06SDiana Picus     mlir::Type ity = lowerTy().indexType();
3431e6d9c06SDiana Picus     unsigned i = 0;
3441e6d9c06SDiana Picus     mlir::Value size = genConstantIndex(loc, ity, rewriter, 1).getResult();
3451e6d9c06SDiana Picus     mlir::Type ty = convertType(alloc.getType());
3461e6d9c06SDiana Picus     mlir::Type resultTy = ty;
3471e6d9c06SDiana Picus     if (alloc.hasLenParams()) {
3481e6d9c06SDiana Picus       unsigned end = alloc.numLenParams();
3491e6d9c06SDiana Picus       llvm::SmallVector<mlir::Value> lenParams;
3501e6d9c06SDiana Picus       for (; i < end; ++i)
3511e6d9c06SDiana Picus         lenParams.push_back(operands[i]);
3521e6d9c06SDiana Picus       mlir::Type scalarType = fir::unwrapSequenceType(alloc.getInType());
3531e6d9c06SDiana Picus       if (auto chrTy = scalarType.dyn_cast<fir::CharacterType>()) {
3541e6d9c06SDiana Picus         fir::CharacterType rawCharTy = fir::CharacterType::getUnknownLen(
3551e6d9c06SDiana Picus             chrTy.getContext(), chrTy.getFKind());
3561e6d9c06SDiana Picus         ty = mlir::LLVM::LLVMPointerType::get(convertType(rawCharTy));
3571e6d9c06SDiana Picus         assert(end == 1);
3581e6d9c06SDiana Picus         size = integerCast(loc, rewriter, ity, lenParams[0]);
3591e6d9c06SDiana Picus       } else if (auto recTy = scalarType.dyn_cast<fir::RecordType>()) {
3601e6d9c06SDiana Picus         mlir::LLVM::LLVMFuncOp memSizeFn =
3611e6d9c06SDiana Picus             getDependentTypeMemSizeFn(recTy, alloc, rewriter);
3621e6d9c06SDiana Picus         if (!memSizeFn)
3631e6d9c06SDiana Picus           emitError(loc, "did not find allocation function");
3641e6d9c06SDiana Picus         mlir::NamedAttribute attr = rewriter.getNamedAttr(
3651e6d9c06SDiana Picus             "callee", mlir::SymbolRefAttr::get(memSizeFn));
3661e6d9c06SDiana Picus         auto call = rewriter.create<mlir::LLVM::CallOp>(
3671e6d9c06SDiana Picus             loc, ity, lenParams, llvm::ArrayRef<mlir::NamedAttribute>{attr});
3681e6d9c06SDiana Picus         size = call.getResult(0);
3691e6d9c06SDiana Picus         ty = mlir::LLVM::LLVMPointerType::get(
3701e6d9c06SDiana Picus             mlir::IntegerType::get(alloc.getContext(), 8));
3711e6d9c06SDiana Picus       } else {
3721e6d9c06SDiana Picus         return emitError(loc, "unexpected type ")
3731e6d9c06SDiana Picus                << scalarType << " with type parameters";
3741e6d9c06SDiana Picus       }
3751e6d9c06SDiana Picus     }
376*ac0f4c8fSPeixinQiao     if (auto scaleSize = genAllocationScaleSize(alloc, ity, rewriter))
377*ac0f4c8fSPeixinQiao       size = rewriter.create<mlir::LLVM::MulOp>(loc, ity, size, scaleSize);
3781e6d9c06SDiana Picus     if (alloc.hasShapeOperands()) {
3791e6d9c06SDiana Picus       unsigned end = operands.size();
3801e6d9c06SDiana Picus       for (; i < end; ++i)
3811e6d9c06SDiana Picus         size = rewriter.create<mlir::LLVM::MulOp>(
3821e6d9c06SDiana Picus             loc, ity, size, integerCast(loc, rewriter, ity, operands[i]));
3831e6d9c06SDiana Picus     }
3841e6d9c06SDiana Picus     if (ty == resultTy) {
3851e6d9c06SDiana Picus       // Do not emit the bitcast if ty and resultTy are the same.
3861e6d9c06SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::AllocaOp>(alloc, ty, size,
3871e6d9c06SDiana Picus                                                         alloc->getAttrs());
3881e6d9c06SDiana Picus     } else {
3891e6d9c06SDiana Picus       auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, ty, size,
3901e6d9c06SDiana Picus                                                       alloc->getAttrs());
3911e6d9c06SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(alloc, resultTy, al);
3921e6d9c06SDiana Picus     }
39344e58509SEric Schweitz     return mlir::success();
3941e6d9c06SDiana Picus   }
3951e6d9c06SDiana Picus };
396dc48849fSKiran Chandramohan } // namespace
397044d5b5dSValentin Clement 
398dc48849fSKiran Chandramohan /// Construct an `llvm.extractvalue` instruction. It will return value at
399dc48849fSKiran Chandramohan /// element \p x from  \p tuple.
400dc48849fSKiran Chandramohan static mlir::LLVM::ExtractValueOp
401dc48849fSKiran Chandramohan genExtractValueWithIndex(mlir::Location loc, mlir::Value tuple, mlir::Type ty,
402dc48849fSKiran Chandramohan                          mlir::ConversionPatternRewriter &rewriter,
403dc48849fSKiran Chandramohan                          mlir::MLIRContext *ctx, int x) {
404dc48849fSKiran Chandramohan   auto cx = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(x));
405dc48849fSKiran Chandramohan   auto xty = ty.cast<mlir::LLVM::LLVMStructType>().getBody()[x];
406dc48849fSKiran Chandramohan   return rewriter.create<mlir::LLVM::ExtractValueOp>(loc, xty, tuple, cx);
407dc48849fSKiran Chandramohan }
408dc48849fSKiran Chandramohan 
409dc48849fSKiran Chandramohan namespace {
410df3b9810SValentin Clement /// Lower `fir.box_addr` to the sequence of operations to extract the first
411df3b9810SValentin Clement /// element of the box.
412df3b9810SValentin Clement struct BoxAddrOpConversion : public FIROpConversion<fir::BoxAddrOp> {
413df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
414df3b9810SValentin Clement 
415df3b9810SValentin Clement   mlir::LogicalResult
416df3b9810SValentin Clement   matchAndRewrite(fir::BoxAddrOp boxaddr, OpAdaptor adaptor,
417df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
418df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
419df3b9810SValentin Clement     auto loc = boxaddr.getLoc();
420df3b9810SValentin Clement     mlir::Type ty = convertType(boxaddr.getType());
421149ad3d5SShraiysh Vaishay     if (auto argty = boxaddr.getVal().getType().dyn_cast<fir::BoxType>()) {
422df3b9810SValentin Clement       rewriter.replaceOp(boxaddr, loadBaseAddrFromBox(loc, ty, a, rewriter));
423df3b9810SValentin Clement     } else {
424df3b9810SValentin Clement       auto c0attr = rewriter.getI32IntegerAttr(0);
425df3b9810SValentin Clement       auto c0 = mlir::ArrayAttr::get(boxaddr.getContext(), c0attr);
426df3b9810SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(boxaddr, ty, a,
427df3b9810SValentin Clement                                                               c0);
428df3b9810SValentin Clement     }
42944e58509SEric Schweitz     return mlir::success();
430df3b9810SValentin Clement   }
431df3b9810SValentin Clement };
432df3b9810SValentin Clement 
433dc48849fSKiran Chandramohan /// Convert `!fir.boxchar_len` to  `!llvm.extractvalue` for the 2nd part of the
434dc48849fSKiran Chandramohan /// boxchar.
435dc48849fSKiran Chandramohan struct BoxCharLenOpConversion : public FIROpConversion<fir::BoxCharLenOp> {
436dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
437dc48849fSKiran Chandramohan 
438dc48849fSKiran Chandramohan   mlir::LogicalResult
439dc48849fSKiran Chandramohan   matchAndRewrite(fir::BoxCharLenOp boxCharLen, OpAdaptor adaptor,
440dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
441dc48849fSKiran Chandramohan     mlir::Value boxChar = adaptor.getOperands()[0];
442dc48849fSKiran Chandramohan     mlir::Location loc = boxChar.getLoc();
443dc48849fSKiran Chandramohan     mlir::MLIRContext *ctx = boxChar.getContext();
444dc48849fSKiran Chandramohan     mlir::Type returnValTy = boxCharLen.getResult().getType();
445dc48849fSKiran Chandramohan 
446dc48849fSKiran Chandramohan     constexpr int boxcharLenIdx = 1;
447dc48849fSKiran Chandramohan     mlir::LLVM::ExtractValueOp len = genExtractValueWithIndex(
448dc48849fSKiran Chandramohan         loc, boxChar, boxChar.getType(), rewriter, ctx, boxcharLenIdx);
449dc48849fSKiran Chandramohan     mlir::Value lenAfterCast = integerCast(loc, rewriter, returnValTy, len);
450dc48849fSKiran Chandramohan     rewriter.replaceOp(boxCharLen, lenAfterCast);
451dc48849fSKiran Chandramohan 
45244e58509SEric Schweitz     return mlir::success();
453dc48849fSKiran Chandramohan   }
454dc48849fSKiran Chandramohan };
455dc48849fSKiran Chandramohan 
456df3b9810SValentin Clement /// Lower `fir.box_dims` to a sequence of operations to extract the requested
457df3b9810SValentin Clement /// dimension infomartion from the boxed value.
458df3b9810SValentin Clement /// Result in a triple set of GEPs and loads.
459df3b9810SValentin Clement struct BoxDimsOpConversion : public FIROpConversion<fir::BoxDimsOp> {
460df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
461df3b9810SValentin Clement 
462df3b9810SValentin Clement   mlir::LogicalResult
463df3b9810SValentin Clement   matchAndRewrite(fir::BoxDimsOp boxdims, OpAdaptor adaptor,
464df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
46544e58509SEric Schweitz     llvm::SmallVector<mlir::Type, 3> resultTypes = {
466df3b9810SValentin Clement         convertType(boxdims.getResult(0).getType()),
467df3b9810SValentin Clement         convertType(boxdims.getResult(1).getType()),
468df3b9810SValentin Clement         convertType(boxdims.getResult(2).getType()),
469df3b9810SValentin Clement     };
470df3b9810SValentin Clement     auto results =
471df3b9810SValentin Clement         getDimsFromBox(boxdims.getLoc(), resultTypes, adaptor.getOperands()[0],
472df3b9810SValentin Clement                        adaptor.getOperands()[1], rewriter);
473df3b9810SValentin Clement     rewriter.replaceOp(boxdims, results);
47444e58509SEric Schweitz     return mlir::success();
475df3b9810SValentin Clement   }
476df3b9810SValentin Clement };
477df3b9810SValentin Clement 
478df3b9810SValentin Clement /// Lower `fir.box_elesize` to a sequence of operations ro extract the size of
479df3b9810SValentin Clement /// an element in the boxed value.
480df3b9810SValentin Clement struct BoxEleSizeOpConversion : public FIROpConversion<fir::BoxEleSizeOp> {
481df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
482df3b9810SValentin Clement 
483df3b9810SValentin Clement   mlir::LogicalResult
484df3b9810SValentin Clement   matchAndRewrite(fir::BoxEleSizeOp boxelesz, OpAdaptor adaptor,
485df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
486df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
487df3b9810SValentin Clement     auto loc = boxelesz.getLoc();
488df3b9810SValentin Clement     auto ty = convertType(boxelesz.getType());
489b6e44ecdSValentin Clement     auto elemSize = getValueFromBox(loc, a, ty, rewriter, kElemLenPosInBox);
490b6e44ecdSValentin Clement     rewriter.replaceOp(boxelesz, elemSize);
49144e58509SEric Schweitz     return mlir::success();
492b6e44ecdSValentin Clement   }
493b6e44ecdSValentin Clement };
494b6e44ecdSValentin Clement 
495b6e44ecdSValentin Clement /// Lower `fir.box_isalloc` to a sequence of operations to determine if the
496b6e44ecdSValentin Clement /// boxed value was from an ALLOCATABLE entity.
497b6e44ecdSValentin Clement struct BoxIsAllocOpConversion : public FIROpConversion<fir::BoxIsAllocOp> {
498b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
499b6e44ecdSValentin Clement 
500b6e44ecdSValentin Clement   mlir::LogicalResult
501b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsAllocOp boxisalloc, OpAdaptor adaptor,
502b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
503b6e44ecdSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
504b6e44ecdSValentin Clement     auto loc = boxisalloc.getLoc();
505b6e44ecdSValentin Clement     mlir::Value check =
506b6e44ecdSValentin Clement         genBoxAttributeCheck(loc, box, rewriter, kAttrAllocatable);
507b6e44ecdSValentin Clement     rewriter.replaceOp(boxisalloc, check);
50844e58509SEric Schweitz     return mlir::success();
509b6e44ecdSValentin Clement   }
510b6e44ecdSValentin Clement };
511b6e44ecdSValentin Clement 
512b6e44ecdSValentin Clement /// Lower `fir.box_isarray` to a sequence of operations to determine if the
513b6e44ecdSValentin Clement /// boxed is an array.
514b6e44ecdSValentin Clement struct BoxIsArrayOpConversion : public FIROpConversion<fir::BoxIsArrayOp> {
515b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
516b6e44ecdSValentin Clement 
517b6e44ecdSValentin Clement   mlir::LogicalResult
518b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsArrayOp boxisarray, OpAdaptor adaptor,
519b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
520b6e44ecdSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
521b6e44ecdSValentin Clement     auto loc = boxisarray.getLoc();
522b6e44ecdSValentin Clement     auto rank =
523b6e44ecdSValentin Clement         getValueFromBox(loc, a, rewriter.getI32Type(), rewriter, kRankPosInBox);
524b6e44ecdSValentin Clement     auto c0 = genConstantOffset(loc, rewriter, 0);
525b6e44ecdSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
526b6e44ecdSValentin Clement         boxisarray, mlir::LLVM::ICmpPredicate::ne, rank, c0);
52744e58509SEric Schweitz     return mlir::success();
528b6e44ecdSValentin Clement   }
529b6e44ecdSValentin Clement };
530b6e44ecdSValentin Clement 
531b6e44ecdSValentin Clement /// Lower `fir.box_isptr` to a sequence of operations to determined if the
532b6e44ecdSValentin Clement /// boxed value was from a POINTER entity.
533b6e44ecdSValentin Clement struct BoxIsPtrOpConversion : public FIROpConversion<fir::BoxIsPtrOp> {
534b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
535b6e44ecdSValentin Clement 
536b6e44ecdSValentin Clement   mlir::LogicalResult
537b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsPtrOp boxisptr, OpAdaptor adaptor,
538b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
539b6e44ecdSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
540b6e44ecdSValentin Clement     auto loc = boxisptr.getLoc();
541b6e44ecdSValentin Clement     mlir::Value check = genBoxAttributeCheck(loc, box, rewriter, kAttrPointer);
542b6e44ecdSValentin Clement     rewriter.replaceOp(boxisptr, check);
54344e58509SEric Schweitz     return mlir::success();
544df3b9810SValentin Clement   }
545df3b9810SValentin Clement };
546df3b9810SValentin Clement 
547df3b9810SValentin Clement /// Lower `fir.box_rank` to the sequence of operation to extract the rank from
548df3b9810SValentin Clement /// the box.
549df3b9810SValentin Clement struct BoxRankOpConversion : public FIROpConversion<fir::BoxRankOp> {
550df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
551df3b9810SValentin Clement 
552df3b9810SValentin Clement   mlir::LogicalResult
553df3b9810SValentin Clement   matchAndRewrite(fir::BoxRankOp boxrank, OpAdaptor adaptor,
554df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
555df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
556df3b9810SValentin Clement     auto loc = boxrank.getLoc();
557df3b9810SValentin Clement     mlir::Type ty = convertType(boxrank.getType());
558b6e44ecdSValentin Clement     auto result = getValueFromBox(loc, a, ty, rewriter, kRankPosInBox);
559df3b9810SValentin Clement     rewriter.replaceOp(boxrank, result);
56044e58509SEric Schweitz     return mlir::success();
561df3b9810SValentin Clement   }
562df3b9810SValentin Clement };
563df3b9810SValentin Clement 
564cc505c0bSKiran Chandramohan /// Lower `fir.boxproc_host` operation. Extracts the host pointer from the
565cc505c0bSKiran Chandramohan /// boxproc.
566cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
567cc505c0bSKiran Chandramohan struct BoxProcHostOpConversion : public FIROpConversion<fir::BoxProcHostOp> {
568cc505c0bSKiran Chandramohan   using FIROpConversion::FIROpConversion;
569cc505c0bSKiran Chandramohan 
570cc505c0bSKiran Chandramohan   mlir::LogicalResult
571cc505c0bSKiran Chandramohan   matchAndRewrite(fir::BoxProcHostOp boxprochost, OpAdaptor adaptor,
572cc505c0bSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
5737ce8c6fcSKiran Chandramohan     TODO(boxprochost.getLoc(), "fir.boxproc_host codegen");
57444e58509SEric Schweitz     return mlir::failure();
575cc505c0bSKiran Chandramohan   }
576cc505c0bSKiran Chandramohan };
577cc505c0bSKiran Chandramohan 
578e38ef2ffSValentin Clement /// Lower `fir.box_tdesc` to the sequence of operations to extract the type
579e38ef2ffSValentin Clement /// descriptor from the box.
580e38ef2ffSValentin Clement struct BoxTypeDescOpConversion : public FIROpConversion<fir::BoxTypeDescOp> {
581e38ef2ffSValentin Clement   using FIROpConversion::FIROpConversion;
582e38ef2ffSValentin Clement 
583e38ef2ffSValentin Clement   mlir::LogicalResult
584e38ef2ffSValentin Clement   matchAndRewrite(fir::BoxTypeDescOp boxtypedesc, OpAdaptor adaptor,
585e38ef2ffSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
586e38ef2ffSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
587e38ef2ffSValentin Clement     auto loc = boxtypedesc.getLoc();
588e38ef2ffSValentin Clement     mlir::Type typeTy =
589e38ef2ffSValentin Clement         fir::getDescFieldTypeModel<kTypePosInBox>()(boxtypedesc.getContext());
590e38ef2ffSValentin Clement     auto result = getValueFromBox(loc, box, typeTy, rewriter, kTypePosInBox);
591e38ef2ffSValentin Clement     auto typePtrTy = mlir::LLVM::LLVMPointerType::get(typeTy);
592e38ef2ffSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(boxtypedesc, typePtrTy,
593e38ef2ffSValentin Clement                                                         result);
59444e58509SEric Schweitz     return mlir::success();
595e38ef2ffSValentin Clement   }
596e38ef2ffSValentin Clement };
597e38ef2ffSValentin Clement 
598dc48849fSKiran Chandramohan /// Lower `fir.string_lit` to LLVM IR dialect operation.
599dc48849fSKiran Chandramohan struct StringLitOpConversion : public FIROpConversion<fir::StringLitOp> {
600dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
601dc48849fSKiran Chandramohan 
602dc48849fSKiran Chandramohan   mlir::LogicalResult
603dc48849fSKiran Chandramohan   matchAndRewrite(fir::StringLitOp constop, OpAdaptor adaptor,
604dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
605dc48849fSKiran Chandramohan     auto ty = convertType(constop.getType());
606dc48849fSKiran Chandramohan     auto attr = constop.getValue();
607dc48849fSKiran Chandramohan     if (attr.isa<mlir::StringAttr>()) {
608dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(constop, ty, attr);
60944e58509SEric Schweitz       return mlir::success();
610dc48849fSKiran Chandramohan     }
611dc48849fSKiran Chandramohan 
612dc48849fSKiran Chandramohan     auto charTy = constop.getType().cast<fir::CharacterType>();
613dc48849fSKiran Chandramohan     unsigned bits = lowerTy().characterBitsize(charTy);
614dc48849fSKiran Chandramohan     mlir::Type intTy = rewriter.getIntegerType(bits);
615e0c782bdSValentin Clement     mlir::Location loc = constop.getLoc();
616e0c782bdSValentin Clement     mlir::Value cst = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
617e0c782bdSValentin Clement     if (auto arr = attr.dyn_cast<mlir::DenseElementsAttr>()) {
618e0c782bdSValentin Clement       cst = rewriter.create<mlir::LLVM::ConstantOp>(loc, ty, arr);
619e0c782bdSValentin Clement     } else if (auto arr = attr.dyn_cast<mlir::ArrayAttr>()) {
620e0c782bdSValentin Clement       for (auto a : llvm::enumerate(arr.getValue())) {
621e0c782bdSValentin Clement         // convert each character to a precise bitsize
622e0c782bdSValentin Clement         auto elemAttr = mlir::IntegerAttr::get(
623dc48849fSKiran Chandramohan             intTy,
624e0c782bdSValentin Clement             a.value().cast<mlir::IntegerAttr>().getValue().zextOrTrunc(bits));
625e0c782bdSValentin Clement         auto elemCst =
626e0c782bdSValentin Clement             rewriter.create<mlir::LLVM::ConstantOp>(loc, intTy, elemAttr);
627e0c782bdSValentin Clement         auto index = mlir::ArrayAttr::get(
628e0c782bdSValentin Clement             constop.getContext(), rewriter.getI32IntegerAttr(a.index()));
629e0c782bdSValentin Clement         cst = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, cst, elemCst,
630e0c782bdSValentin Clement                                                          index);
631e0c782bdSValentin Clement       }
632e0c782bdSValentin Clement     } else {
63344e58509SEric Schweitz       return mlir::failure();
634e0c782bdSValentin Clement     }
635e0c782bdSValentin Clement     rewriter.replaceOp(constop, cst);
63644e58509SEric Schweitz     return mlir::success();
637dc48849fSKiran Chandramohan   }
638dc48849fSKiran Chandramohan };
639dc48849fSKiran Chandramohan 
640ddd11b9aSAndrzej Warzynski // `fir.call` -> `llvm.call`
641ddd11b9aSAndrzej Warzynski struct CallOpConversion : public FIROpConversion<fir::CallOp> {
642ddd11b9aSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
643ddd11b9aSAndrzej Warzynski 
644ddd11b9aSAndrzej Warzynski   mlir::LogicalResult
645ddd11b9aSAndrzej Warzynski   matchAndRewrite(fir::CallOp call, OpAdaptor adaptor,
646ddd11b9aSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
64744e58509SEric Schweitz     llvm::SmallVector<mlir::Type> resultTys;
648ddd11b9aSAndrzej Warzynski     for (auto r : call.getResults())
649ddd11b9aSAndrzej Warzynski       resultTys.push_back(convertType(r.getType()));
650ddd11b9aSAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
651ddd11b9aSAndrzej Warzynski         call, resultTys, adaptor.getOperands(), call->getAttrs());
65244e58509SEric Schweitz     return mlir::success();
653ddd11b9aSAndrzej Warzynski   }
654ddd11b9aSAndrzej Warzynski };
655c2acd453SAlexisPerry } // namespace
656ddd11b9aSAndrzej Warzynski 
657092cee5fSValentin Clement static mlir::Type getComplexEleTy(mlir::Type complex) {
658092cee5fSValentin Clement   if (auto cc = complex.dyn_cast<mlir::ComplexType>())
659092cee5fSValentin Clement     return cc.getElementType();
660092cee5fSValentin Clement   return complex.cast<fir::ComplexType>().getElementType();
661092cee5fSValentin Clement }
662092cee5fSValentin Clement 
663c2acd453SAlexisPerry namespace {
664f1dfc027SDiana Picus /// Compare complex values
665f1dfc027SDiana Picus ///
666f1dfc027SDiana Picus /// Per 10.1, the only comparisons available are .EQ. (oeq) and .NE. (une).
667f1dfc027SDiana Picus ///
668f1dfc027SDiana Picus /// For completeness, all other comparison are done on the real component only.
669f1dfc027SDiana Picus struct CmpcOpConversion : public FIROpConversion<fir::CmpcOp> {
670f1dfc027SDiana Picus   using FIROpConversion::FIROpConversion;
671f1dfc027SDiana Picus 
672f1dfc027SDiana Picus   mlir::LogicalResult
673f1dfc027SDiana Picus   matchAndRewrite(fir::CmpcOp cmp, OpAdaptor adaptor,
674f1dfc027SDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
675f1dfc027SDiana Picus     mlir::ValueRange operands = adaptor.getOperands();
676f1dfc027SDiana Picus     mlir::MLIRContext *ctxt = cmp.getContext();
677149ad3d5SShraiysh Vaishay     mlir::Type eleTy = convertType(getComplexEleTy(cmp.getLhs().getType()));
678f1dfc027SDiana Picus     mlir::Type resTy = convertType(cmp.getType());
679f1dfc027SDiana Picus     mlir::Location loc = cmp.getLoc();
680f1dfc027SDiana Picus     auto pos0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0));
68144e58509SEric Schweitz     llvm::SmallVector<mlir::Value, 2> rp{
68244e58509SEric Schweitz         rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, operands[0],
68344e58509SEric Schweitz                                                     pos0),
68444e58509SEric Schweitz         rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, operands[1],
68544e58509SEric Schweitz                                                     pos0)};
686f1dfc027SDiana Picus     auto rcp =
687f1dfc027SDiana Picus         rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, rp, cmp->getAttrs());
688f1dfc027SDiana Picus     auto pos1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1));
68944e58509SEric Schweitz     llvm::SmallVector<mlir::Value, 2> ip{
69044e58509SEric Schweitz         rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, operands[0],
69144e58509SEric Schweitz                                                     pos1),
69244e58509SEric Schweitz         rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, operands[1],
69344e58509SEric Schweitz                                                     pos1)};
694f1dfc027SDiana Picus     auto icp =
695f1dfc027SDiana Picus         rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, ip, cmp->getAttrs());
69644e58509SEric Schweitz     llvm::SmallVector<mlir::Value, 2> cp{rcp, icp};
697f1dfc027SDiana Picus     switch (cmp.getPredicate()) {
698f1dfc027SDiana Picus     case mlir::arith::CmpFPredicate::OEQ: // .EQ.
699f1dfc027SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(cmp, resTy, cp);
700f1dfc027SDiana Picus       break;
701f1dfc027SDiana Picus     case mlir::arith::CmpFPredicate::UNE: // .NE.
702f1dfc027SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(cmp, resTy, cp);
703f1dfc027SDiana Picus       break;
704f1dfc027SDiana Picus     default:
705f1dfc027SDiana Picus       rewriter.replaceOp(cmp, rcp.getResult());
706f1dfc027SDiana Picus       break;
707f1dfc027SDiana Picus     }
70844e58509SEric Schweitz     return mlir::success();
709f1dfc027SDiana Picus   }
710f1dfc027SDiana Picus };
711f1dfc027SDiana Picus 
712e81d73edSDiana Picus /// Lower complex constants
713e81d73edSDiana Picus struct ConstcOpConversion : public FIROpConversion<fir::ConstcOp> {
714e81d73edSDiana Picus   using FIROpConversion::FIROpConversion;
715e81d73edSDiana Picus 
716e81d73edSDiana Picus   mlir::LogicalResult
717e81d73edSDiana Picus   matchAndRewrite(fir::ConstcOp conc, OpAdaptor,
718e81d73edSDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
719e81d73edSDiana Picus     mlir::Location loc = conc.getLoc();
720e81d73edSDiana Picus     mlir::MLIRContext *ctx = conc.getContext();
721e81d73edSDiana Picus     mlir::Type ty = convertType(conc.getType());
722e81d73edSDiana Picus     mlir::Type ety = convertType(getComplexEleTy(conc.getType()));
723e81d73edSDiana Picus     auto realFloatAttr = mlir::FloatAttr::get(ety, getValue(conc.getReal()));
724e81d73edSDiana Picus     auto realPart =
725e81d73edSDiana Picus         rewriter.create<mlir::LLVM::ConstantOp>(loc, ety, realFloatAttr);
726e81d73edSDiana Picus     auto imFloatAttr = mlir::FloatAttr::get(ety, getValue(conc.getImaginary()));
727e81d73edSDiana Picus     auto imPart =
728e81d73edSDiana Picus         rewriter.create<mlir::LLVM::ConstantOp>(loc, ety, imFloatAttr);
729e81d73edSDiana Picus     auto realIndex = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
730e81d73edSDiana Picus     auto imIndex = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
731e81d73edSDiana Picus     auto undef = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
732e81d73edSDiana Picus     auto setReal = rewriter.create<mlir::LLVM::InsertValueOp>(
733e81d73edSDiana Picus         loc, ty, undef, realPart, realIndex);
734e81d73edSDiana Picus     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(conc, ty, setReal,
735e81d73edSDiana Picus                                                            imPart, imIndex);
73644e58509SEric Schweitz     return mlir::success();
737e81d73edSDiana Picus   }
738e81d73edSDiana Picus 
73944e58509SEric Schweitz   inline llvm::APFloat getValue(mlir::Attribute attr) const {
740e81d73edSDiana Picus     return attr.cast<fir::RealAttr>().getValue();
741e81d73edSDiana Picus   }
742e81d73edSDiana Picus };
743e81d73edSDiana Picus 
744092cee5fSValentin Clement /// convert value of from-type to value of to-type
745092cee5fSValentin Clement struct ConvertOpConversion : public FIROpConversion<fir::ConvertOp> {
746092cee5fSValentin Clement   using FIROpConversion::FIROpConversion;
747092cee5fSValentin Clement 
748092cee5fSValentin Clement   static bool isFloatingPointTy(mlir::Type ty) {
749092cee5fSValentin Clement     return ty.isa<mlir::FloatType>();
750092cee5fSValentin Clement   }
751092cee5fSValentin Clement 
752092cee5fSValentin Clement   mlir::LogicalResult
753092cee5fSValentin Clement   matchAndRewrite(fir::ConvertOp convert, OpAdaptor adaptor,
754092cee5fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
7553b7ec85aSJean Perier     auto fromFirTy = convert.getValue().getType();
7563b7ec85aSJean Perier     auto toFirTy = convert.getRes().getType();
7573b7ec85aSJean Perier     auto fromTy = convertType(fromFirTy);
7583b7ec85aSJean Perier     auto toTy = convertType(toFirTy);
759092cee5fSValentin Clement     mlir::Value op0 = adaptor.getOperands()[0];
760092cee5fSValentin Clement     if (fromTy == toTy) {
761092cee5fSValentin Clement       rewriter.replaceOp(convert, op0);
76244e58509SEric Schweitz       return mlir::success();
763092cee5fSValentin Clement     }
764092cee5fSValentin Clement     auto loc = convert.getLoc();
765092cee5fSValentin Clement     auto convertFpToFp = [&](mlir::Value val, unsigned fromBits,
766092cee5fSValentin Clement                              unsigned toBits, mlir::Type toTy) -> mlir::Value {
767092cee5fSValentin Clement       if (fromBits == toBits) {
768092cee5fSValentin Clement         // TODO: Converting between two floating-point representations with the
769092cee5fSValentin Clement         // same bitwidth is not allowed for now.
770092cee5fSValentin Clement         mlir::emitError(loc,
771092cee5fSValentin Clement                         "cannot implicitly convert between two floating-point "
772092cee5fSValentin Clement                         "representations of the same bitwidth");
773092cee5fSValentin Clement         return {};
774092cee5fSValentin Clement       }
775092cee5fSValentin Clement       if (fromBits > toBits)
776092cee5fSValentin Clement         return rewriter.create<mlir::LLVM::FPTruncOp>(loc, toTy, val);
777092cee5fSValentin Clement       return rewriter.create<mlir::LLVM::FPExtOp>(loc, toTy, val);
778092cee5fSValentin Clement     };
779092cee5fSValentin Clement     // Complex to complex conversion.
7803b7ec85aSJean Perier     if (fir::isa_complex(fromFirTy) && fir::isa_complex(toFirTy)) {
781092cee5fSValentin Clement       // Special case: handle the conversion of a complex such that both the
782092cee5fSValentin Clement       // real and imaginary parts are converted together.
783092cee5fSValentin Clement       auto zero = mlir::ArrayAttr::get(convert.getContext(),
784092cee5fSValentin Clement                                        rewriter.getI32IntegerAttr(0));
785092cee5fSValentin Clement       auto one = mlir::ArrayAttr::get(convert.getContext(),
786092cee5fSValentin Clement                                       rewriter.getI32IntegerAttr(1));
787149ad3d5SShraiysh Vaishay       auto ty = convertType(getComplexEleTy(convert.getValue().getType()));
788092cee5fSValentin Clement       auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, zero);
789092cee5fSValentin Clement       auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, one);
790149ad3d5SShraiysh Vaishay       auto nt = convertType(getComplexEleTy(convert.getRes().getType()));
791092cee5fSValentin Clement       auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
792092cee5fSValentin Clement       auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(nt);
793092cee5fSValentin Clement       auto rc = convertFpToFp(rp, fromBits, toBits, nt);
794092cee5fSValentin Clement       auto ic = convertFpToFp(ip, fromBits, toBits, nt);
795092cee5fSValentin Clement       auto un = rewriter.create<mlir::LLVM::UndefOp>(loc, toTy);
796092cee5fSValentin Clement       auto i1 =
797092cee5fSValentin Clement           rewriter.create<mlir::LLVM::InsertValueOp>(loc, toTy, un, rc, zero);
798092cee5fSValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(convert, toTy, i1,
799092cee5fSValentin Clement                                                              ic, one);
800092cee5fSValentin Clement       return mlir::success();
801092cee5fSValentin Clement     }
8023b7ec85aSJean Perier 
8033b7ec85aSJean Perier     // Follow UNIX F77 convention for logicals:
8043b7ec85aSJean Perier     // 1. underlying integer is not zero => logical is .TRUE.
8053b7ec85aSJean Perier     // 2. logical is .TRUE. => set underlying integer to 1.
8063b7ec85aSJean Perier     auto i1Type = mlir::IntegerType::get(convert.getContext(), 1);
8073b7ec85aSJean Perier     if (fromFirTy.isa<fir::LogicalType>() && toFirTy == i1Type) {
8083b7ec85aSJean Perier       mlir::Value zero = genConstantIndex(loc, fromTy, rewriter, 0);
8093b7ec85aSJean Perier       rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
8103b7ec85aSJean Perier           convert, mlir::LLVM::ICmpPredicate::ne, op0, zero);
8113b7ec85aSJean Perier       return mlir::success();
8123b7ec85aSJean Perier     }
8133b7ec85aSJean Perier     if (fromFirTy == i1Type && toFirTy.isa<fir::LogicalType>()) {
8143b7ec85aSJean Perier       rewriter.replaceOpWithNewOp<mlir::LLVM::ZExtOp>(convert, toTy, op0);
8153b7ec85aSJean Perier       return mlir::success();
8163b7ec85aSJean Perier     }
8173b7ec85aSJean Perier 
818092cee5fSValentin Clement     // Floating point to floating point conversion.
819092cee5fSValentin Clement     if (isFloatingPointTy(fromTy)) {
820092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
821092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
822092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
823092cee5fSValentin Clement         auto v = convertFpToFp(op0, fromBits, toBits, toTy);
824092cee5fSValentin Clement         rewriter.replaceOp(convert, v);
825092cee5fSValentin Clement         return mlir::success();
826092cee5fSValentin Clement       }
827092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
828092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::FPToSIOp>(convert, toTy, op0);
829092cee5fSValentin Clement         return mlir::success();
830092cee5fSValentin Clement       }
831092cee5fSValentin Clement     } else if (fromTy.isa<mlir::IntegerType>()) {
832092cee5fSValentin Clement       // Integer to integer conversion.
833092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
834092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
835092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
836092cee5fSValentin Clement         assert(fromBits != toBits);
837092cee5fSValentin Clement         if (fromBits > toBits) {
838092cee5fSValentin Clement           rewriter.replaceOpWithNewOp<mlir::LLVM::TruncOp>(convert, toTy, op0);
839092cee5fSValentin Clement           return mlir::success();
840092cee5fSValentin Clement         }
841092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SExtOp>(convert, toTy, op0);
842092cee5fSValentin Clement         return mlir::success();
843092cee5fSValentin Clement       }
844092cee5fSValentin Clement       // Integer to floating point conversion.
845092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
846092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SIToFPOp>(convert, toTy, op0);
847092cee5fSValentin Clement         return mlir::success();
848092cee5fSValentin Clement       }
849092cee5fSValentin Clement       // Integer to pointer conversion.
850092cee5fSValentin Clement       if (toTy.isa<mlir::LLVM::LLVMPointerType>()) {
851092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(convert, toTy, op0);
852092cee5fSValentin Clement         return mlir::success();
853092cee5fSValentin Clement       }
854092cee5fSValentin Clement     } else if (fromTy.isa<mlir::LLVM::LLVMPointerType>()) {
855092cee5fSValentin Clement       // Pointer to integer conversion.
856092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
857092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::PtrToIntOp>(convert, toTy, op0);
858092cee5fSValentin Clement         return mlir::success();
859092cee5fSValentin Clement       }
860092cee5fSValentin Clement       // Pointer to pointer conversion.
861092cee5fSValentin Clement       if (toTy.isa<mlir::LLVM::LLVMPointerType>()) {
862092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(convert, toTy, op0);
863092cee5fSValentin Clement         return mlir::success();
864092cee5fSValentin Clement       }
865092cee5fSValentin Clement     }
866092cee5fSValentin Clement     return emitError(loc) << "cannot convert " << fromTy << " to " << toTy;
867092cee5fSValentin Clement   }
868092cee5fSValentin Clement };
869092cee5fSValentin Clement 
8709534e361SValentin Clement /// Lower `fir.dispatch` operation. A virtual call to a method in a dispatch
8719534e361SValentin Clement /// table.
8729534e361SValentin Clement struct DispatchOpConversion : public FIROpConversion<fir::DispatchOp> {
8739534e361SValentin Clement   using FIROpConversion::FIROpConversion;
8749534e361SValentin Clement 
8759534e361SValentin Clement   mlir::LogicalResult
8769534e361SValentin Clement   matchAndRewrite(fir::DispatchOp dispatch, OpAdaptor adaptor,
8779534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8787ce8c6fcSKiran Chandramohan     TODO(dispatch.getLoc(), "fir.dispatch codegen");
87944e58509SEric Schweitz     return mlir::failure();
8809534e361SValentin Clement   }
8819534e361SValentin Clement };
8829534e361SValentin Clement 
8839534e361SValentin Clement /// Lower `fir.dispatch_table` operation. The dispatch table for a Fortran
8849534e361SValentin Clement /// derived type.
8859534e361SValentin Clement struct DispatchTableOpConversion
8869534e361SValentin Clement     : public FIROpConversion<fir::DispatchTableOp> {
8879534e361SValentin Clement   using FIROpConversion::FIROpConversion;
8889534e361SValentin Clement 
8899534e361SValentin Clement   mlir::LogicalResult
8909534e361SValentin Clement   matchAndRewrite(fir::DispatchTableOp dispTab, OpAdaptor adaptor,
8919534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8927ce8c6fcSKiran Chandramohan     TODO(dispTab.getLoc(), "fir.dispatch_table codegen");
89344e58509SEric Schweitz     return mlir::failure();
8949534e361SValentin Clement   }
8959534e361SValentin Clement };
8969534e361SValentin Clement 
8979534e361SValentin Clement /// Lower `fir.dt_entry` operation. An entry in a dispatch table; binds a
8989534e361SValentin Clement /// method-name to a function.
8999534e361SValentin Clement struct DTEntryOpConversion : public FIROpConversion<fir::DTEntryOp> {
9009534e361SValentin Clement   using FIROpConversion::FIROpConversion;
9019534e361SValentin Clement 
9029534e361SValentin Clement   mlir::LogicalResult
9039534e361SValentin Clement   matchAndRewrite(fir::DTEntryOp dtEnt, OpAdaptor adaptor,
9049534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
9057ce8c6fcSKiran Chandramohan     TODO(dtEnt.getLoc(), "fir.dt_entry codegen");
90644e58509SEric Schweitz     return mlir::failure();
9079534e361SValentin Clement   }
9089534e361SValentin Clement };
9099534e361SValentin Clement 
910677df8c7SValentin Clement /// Lower `fir.global_len` operation.
911677df8c7SValentin Clement struct GlobalLenOpConversion : public FIROpConversion<fir::GlobalLenOp> {
912677df8c7SValentin Clement   using FIROpConversion::FIROpConversion;
913677df8c7SValentin Clement 
914677df8c7SValentin Clement   mlir::LogicalResult
915677df8c7SValentin Clement   matchAndRewrite(fir::GlobalLenOp globalLen, OpAdaptor adaptor,
916677df8c7SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
9177ce8c6fcSKiran Chandramohan     TODO(globalLen.getLoc(), "fir.global_len codegen");
91844e58509SEric Schweitz     return mlir::failure();
919677df8c7SValentin Clement   }
920677df8c7SValentin Clement };
921677df8c7SValentin Clement 
922cdc476abSDiana Picus /// Lower fir.len_param_index
923cdc476abSDiana Picus struct LenParamIndexOpConversion
924cdc476abSDiana Picus     : public FIROpConversion<fir::LenParamIndexOp> {
925cdc476abSDiana Picus   using FIROpConversion::FIROpConversion;
926cdc476abSDiana Picus 
927cdc476abSDiana Picus   // FIXME: this should be specialized by the runtime target
928cdc476abSDiana Picus   mlir::LogicalResult
929cdc476abSDiana Picus   matchAndRewrite(fir::LenParamIndexOp lenp, OpAdaptor,
930cdc476abSDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
9317ce8c6fcSKiran Chandramohan     TODO(lenp.getLoc(), "fir.len_param_index codegen");
932cdc476abSDiana Picus   }
933cdc476abSDiana Picus };
934cdc476abSDiana Picus 
935dc48849fSKiran Chandramohan /// Convert `!fir.emboxchar<!fir.char<KIND, ?>, #n>` into a sequence of
936dc48849fSKiran Chandramohan /// instructions that generate `!llvm.struct<(ptr<ik>, i64)>`. The 1st element
937dc48849fSKiran Chandramohan /// in this struct is a pointer. Its type is determined from `KIND`. The 2nd
938dc48849fSKiran Chandramohan /// element is the length of the character buffer (`#n`).
939dc48849fSKiran Chandramohan struct EmboxCharOpConversion : public FIROpConversion<fir::EmboxCharOp> {
94031246187SValentin Clement   using FIROpConversion::FIROpConversion;
94131246187SValentin Clement 
94231246187SValentin Clement   mlir::LogicalResult
943dc48849fSKiran Chandramohan   matchAndRewrite(fir::EmboxCharOp emboxChar, OpAdaptor adaptor,
94431246187SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
945dc48849fSKiran Chandramohan     mlir::ValueRange operands = adaptor.getOperands();
94644e58509SEric Schweitz     auto *ctx = emboxChar.getContext();
947dc48849fSKiran Chandramohan 
948dc48849fSKiran Chandramohan     mlir::Value charBuffer = operands[0];
949dc48849fSKiran Chandramohan     mlir::Value charBufferLen = operands[1];
950dc48849fSKiran Chandramohan 
951dc48849fSKiran Chandramohan     mlir::Location loc = emboxChar.getLoc();
952dc48849fSKiran Chandramohan     mlir::Type llvmStructTy = convertType(emboxChar.getType());
953dc48849fSKiran Chandramohan     auto llvmStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, llvmStructTy);
954dc48849fSKiran Chandramohan 
955dc48849fSKiran Chandramohan     mlir::Type lenTy =
956dc48849fSKiran Chandramohan         llvmStructTy.cast<mlir::LLVM::LLVMStructType>().getBody()[1];
957dc48849fSKiran Chandramohan     mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, charBufferLen);
958dc48849fSKiran Chandramohan 
959dc48849fSKiran Chandramohan     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
960dc48849fSKiran Chandramohan     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
961dc48849fSKiran Chandramohan     auto insertBufferOp = rewriter.create<mlir::LLVM::InsertValueOp>(
962dc48849fSKiran Chandramohan         loc, llvmStructTy, llvmStruct, charBuffer, c0);
963dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
964dc48849fSKiran Chandramohan         emboxChar, llvmStructTy, insertBufferOp, lenAfterCast, c1);
965dc48849fSKiran Chandramohan 
96644e58509SEric Schweitz     return mlir::success();
96731246187SValentin Clement   }
96831246187SValentin Clement };
969c2acd453SAlexisPerry } // namespace
970c2acd453SAlexisPerry 
971c2acd453SAlexisPerry /// Return the LLVMFuncOp corresponding to the standard malloc call.
972c2acd453SAlexisPerry static mlir::LLVM::LLVMFuncOp
973c2acd453SAlexisPerry getMalloc(fir::AllocMemOp op, mlir::ConversionPatternRewriter &rewriter) {
974c2acd453SAlexisPerry   auto module = op->getParentOfType<mlir::ModuleOp>();
975c2acd453SAlexisPerry   if (mlir::LLVM::LLVMFuncOp mallocFunc =
976c2acd453SAlexisPerry           module.lookupSymbol<mlir::LLVM::LLVMFuncOp>("malloc"))
977c2acd453SAlexisPerry     return mallocFunc;
978c2acd453SAlexisPerry   mlir::OpBuilder moduleBuilder(
979c2acd453SAlexisPerry       op->getParentOfType<mlir::ModuleOp>().getBodyRegion());
980c2acd453SAlexisPerry   auto indexType = mlir::IntegerType::get(op.getContext(), 64);
981c2acd453SAlexisPerry   return moduleBuilder.create<mlir::LLVM::LLVMFuncOp>(
982c2acd453SAlexisPerry       rewriter.getUnknownLoc(), "malloc",
983c2acd453SAlexisPerry       mlir::LLVM::LLVMFunctionType::get(getVoidPtrType(op.getContext()),
984c2acd453SAlexisPerry                                         indexType,
985c2acd453SAlexisPerry                                         /*isVarArg=*/false));
986c2acd453SAlexisPerry }
987c2acd453SAlexisPerry 
988c2acd453SAlexisPerry /// Helper function for generating the LLVM IR that computes the size
989c2acd453SAlexisPerry /// in bytes for a derived type.
990c2acd453SAlexisPerry static mlir::Value
991c2acd453SAlexisPerry computeDerivedTypeSize(mlir::Location loc, mlir::Type ptrTy, mlir::Type idxTy,
992c2acd453SAlexisPerry                        mlir::ConversionPatternRewriter &rewriter) {
993c2acd453SAlexisPerry   auto nullPtr = rewriter.create<mlir::LLVM::NullOp>(loc, ptrTy);
994c2acd453SAlexisPerry   mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1);
99530122656SAlex Zinenko   llvm::SmallVector<mlir::Value> args{one};
99630122656SAlex Zinenko   auto gep = rewriter.create<mlir::LLVM::GEPOp>(loc, ptrTy, nullPtr, args);
997c2acd453SAlexisPerry   return rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, gep);
998c2acd453SAlexisPerry }
999c2acd453SAlexisPerry 
1000c2acd453SAlexisPerry namespace {
1001c2acd453SAlexisPerry /// Lower a `fir.allocmem` instruction into `llvm.call @malloc`
1002c2acd453SAlexisPerry struct AllocMemOpConversion : public FIROpConversion<fir::AllocMemOp> {
1003c2acd453SAlexisPerry   using FIROpConversion::FIROpConversion;
1004c2acd453SAlexisPerry 
1005c2acd453SAlexisPerry   mlir::LogicalResult
1006c2acd453SAlexisPerry   matchAndRewrite(fir::AllocMemOp heap, OpAdaptor adaptor,
1007c2acd453SAlexisPerry                   mlir::ConversionPatternRewriter &rewriter) const override {
1008c45bd4b9SEric Schweitz     auto heapTy = heap.getType();
1009c45bd4b9SEric Schweitz     auto ty = convertType(heapTy);
1010c2acd453SAlexisPerry     mlir::LLVM::LLVMFuncOp mallocFunc = getMalloc(heap, rewriter);
1011c2acd453SAlexisPerry     mlir::Location loc = heap.getLoc();
1012c2acd453SAlexisPerry     auto ity = lowerTy().indexType();
1013c45bd4b9SEric Schweitz     auto dataTy = fir::unwrapRefType(heapTy);
1014c45bd4b9SEric Schweitz     if (fir::isRecordWithTypeParameters(fir::unwrapSequenceType(dataTy)))
1015c45bd4b9SEric Schweitz       TODO(loc, "fir.allocmem codegen of derived type with length parameters");
1016c2acd453SAlexisPerry     mlir::Value size = genTypeSizeInBytes(loc, ity, rewriter, ty);
1017*ac0f4c8fSPeixinQiao     if (auto scaleSize = genAllocationScaleSize(heap, ity, rewriter))
1018*ac0f4c8fSPeixinQiao       size = rewriter.create<mlir::LLVM::MulOp>(loc, ity, size, scaleSize);
1019c2acd453SAlexisPerry     for (mlir::Value opnd : adaptor.getOperands())
1020c2acd453SAlexisPerry       size = rewriter.create<mlir::LLVM::MulOp>(
1021c2acd453SAlexisPerry           loc, ity, size, integerCast(loc, rewriter, ity, opnd));
1022c2acd453SAlexisPerry     heap->setAttr("callee", mlir::SymbolRefAttr::get(mallocFunc));
1023c2acd453SAlexisPerry     auto malloc = rewriter.create<mlir::LLVM::CallOp>(
1024c2acd453SAlexisPerry         loc, ::getVoidPtrType(heap.getContext()), size, heap->getAttrs());
1025c2acd453SAlexisPerry     rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(heap, ty,
1026c2acd453SAlexisPerry                                                        malloc.getResult(0));
102744e58509SEric Schweitz     return mlir::success();
1028c2acd453SAlexisPerry   }
1029c2acd453SAlexisPerry 
1030c2acd453SAlexisPerry   // Compute the (allocation) size of the allocmem type in bytes.
1031c2acd453SAlexisPerry   mlir::Value genTypeSizeInBytes(mlir::Location loc, mlir::Type idxTy,
1032c2acd453SAlexisPerry                                  mlir::ConversionPatternRewriter &rewriter,
1033c2acd453SAlexisPerry                                  mlir::Type llTy) const {
1034c2acd453SAlexisPerry     // Use the primitive size, if available.
1035c2acd453SAlexisPerry     auto ptrTy = llTy.dyn_cast<mlir::LLVM::LLVMPointerType>();
1036c2acd453SAlexisPerry     if (auto size =
1037c2acd453SAlexisPerry             mlir::LLVM::getPrimitiveTypeSizeInBits(ptrTy.getElementType()))
1038c2acd453SAlexisPerry       return genConstantIndex(loc, idxTy, rewriter, size / 8);
1039c2acd453SAlexisPerry 
1040c2acd453SAlexisPerry     // Otherwise, generate the GEP trick in LLVM IR to compute the size.
1041c2acd453SAlexisPerry     return computeDerivedTypeSize(loc, ptrTy, idxTy, rewriter);
1042c2acd453SAlexisPerry   }
1043c2acd453SAlexisPerry };
1044c2acd453SAlexisPerry } // namespace
1045c2acd453SAlexisPerry 
1046c2acd453SAlexisPerry /// Return the LLVMFuncOp corresponding to the standard free call.
1047c2acd453SAlexisPerry static mlir::LLVM::LLVMFuncOp
1048c2acd453SAlexisPerry getFree(fir::FreeMemOp op, mlir::ConversionPatternRewriter &rewriter) {
1049c2acd453SAlexisPerry   auto module = op->getParentOfType<mlir::ModuleOp>();
1050c2acd453SAlexisPerry   if (mlir::LLVM::LLVMFuncOp freeFunc =
1051c2acd453SAlexisPerry           module.lookupSymbol<mlir::LLVM::LLVMFuncOp>("free"))
1052c2acd453SAlexisPerry     return freeFunc;
1053c2acd453SAlexisPerry   mlir::OpBuilder moduleBuilder(module.getBodyRegion());
1054c2acd453SAlexisPerry   auto voidType = mlir::LLVM::LLVMVoidType::get(op.getContext());
1055c2acd453SAlexisPerry   return moduleBuilder.create<mlir::LLVM::LLVMFuncOp>(
1056c2acd453SAlexisPerry       rewriter.getUnknownLoc(), "free",
1057c2acd453SAlexisPerry       mlir::LLVM::LLVMFunctionType::get(voidType,
1058c2acd453SAlexisPerry                                         getVoidPtrType(op.getContext()),
1059c2acd453SAlexisPerry                                         /*isVarArg=*/false));
1060c2acd453SAlexisPerry }
1061c2acd453SAlexisPerry 
1062c2acd453SAlexisPerry namespace {
1063c2acd453SAlexisPerry /// Lower a `fir.freemem` instruction into `llvm.call @free`
1064c2acd453SAlexisPerry struct FreeMemOpConversion : public FIROpConversion<fir::FreeMemOp> {
1065c2acd453SAlexisPerry   using FIROpConversion::FIROpConversion;
1066c2acd453SAlexisPerry 
1067c2acd453SAlexisPerry   mlir::LogicalResult
1068c2acd453SAlexisPerry   matchAndRewrite(fir::FreeMemOp freemem, OpAdaptor adaptor,
1069c2acd453SAlexisPerry                   mlir::ConversionPatternRewriter &rewriter) const override {
1070c2acd453SAlexisPerry     mlir::LLVM::LLVMFuncOp freeFunc = getFree(freemem, rewriter);
1071c2acd453SAlexisPerry     mlir::Location loc = freemem.getLoc();
1072c2acd453SAlexisPerry     auto bitcast = rewriter.create<mlir::LLVM::BitcastOp>(
1073c2acd453SAlexisPerry         freemem.getLoc(), voidPtrTy(), adaptor.getOperands()[0]);
1074c2acd453SAlexisPerry     freemem->setAttr("callee", mlir::SymbolRefAttr::get(freeFunc));
1075c2acd453SAlexisPerry     rewriter.create<mlir::LLVM::CallOp>(
1076c2acd453SAlexisPerry         loc, mlir::TypeRange{}, mlir::ValueRange{bitcast}, freemem->getAttrs());
1077c2acd453SAlexisPerry     rewriter.eraseOp(freemem);
107844e58509SEric Schweitz     return mlir::success();
1079c2acd453SAlexisPerry   }
1080c2acd453SAlexisPerry };
1081c2acd453SAlexisPerry } // namespace
1082044d5b5dSValentin Clement 
1083dc48849fSKiran Chandramohan namespace {} // namespace
108432e08248SAndrzej Warzynski 
1085af6ee580SValentin Clement /// Common base class for embox to descriptor conversion.
1086af6ee580SValentin Clement template <typename OP>
1087af6ee580SValentin Clement struct EmboxCommonConversion : public FIROpConversion<OP> {
1088af6ee580SValentin Clement   using FIROpConversion<OP>::FIROpConversion;
1089af6ee580SValentin Clement 
1090af6ee580SValentin Clement   // Find the LLVMFuncOp in whose entry block the alloca should be inserted.
1091af6ee580SValentin Clement   // The order to find the LLVMFuncOp is as follows:
1092af6ee580SValentin Clement   // 1. The parent operation of the current block if it is a LLVMFuncOp.
1093af6ee580SValentin Clement   // 2. The first ancestor that is a LLVMFuncOp.
1094af6ee580SValentin Clement   mlir::LLVM::LLVMFuncOp
1095af6ee580SValentin Clement   getFuncForAllocaInsert(mlir::ConversionPatternRewriter &rewriter) const {
1096af6ee580SValentin Clement     mlir::Operation *parentOp = rewriter.getInsertionBlock()->getParentOp();
1097af6ee580SValentin Clement     return mlir::isa<mlir::LLVM::LLVMFuncOp>(parentOp)
1098af6ee580SValentin Clement                ? mlir::cast<mlir::LLVM::LLVMFuncOp>(parentOp)
1099af6ee580SValentin Clement                : parentOp->getParentOfType<mlir::LLVM::LLVMFuncOp>();
1100af6ee580SValentin Clement   }
1101af6ee580SValentin Clement 
1102af6ee580SValentin Clement   // Generate an alloca of size 1 and type \p toTy.
1103af6ee580SValentin Clement   mlir::LLVM::AllocaOp
1104af6ee580SValentin Clement   genAllocaWithType(mlir::Location loc, mlir::Type toTy, unsigned alignment,
1105af6ee580SValentin Clement                     mlir::ConversionPatternRewriter &rewriter) const {
1106af6ee580SValentin Clement     auto thisPt = rewriter.saveInsertionPoint();
1107af6ee580SValentin Clement     mlir::LLVM::LLVMFuncOp func = getFuncForAllocaInsert(rewriter);
1108af6ee580SValentin Clement     rewriter.setInsertionPointToStart(&func.front());
1109af6ee580SValentin Clement     auto size = this->genI32Constant(loc, rewriter, 1);
1110af6ee580SValentin Clement     auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, toTy, size, alignment);
1111af6ee580SValentin Clement     rewriter.restoreInsertionPoint(thisPt);
1112af6ee580SValentin Clement     return al;
1113af6ee580SValentin Clement   }
1114af6ee580SValentin Clement 
1115af6ee580SValentin Clement   static int getCFIAttr(fir::BoxType boxTy) {
1116af6ee580SValentin Clement     auto eleTy = boxTy.getEleTy();
1117af6ee580SValentin Clement     if (eleTy.isa<fir::PointerType>())
1118af6ee580SValentin Clement       return CFI_attribute_pointer;
1119af6ee580SValentin Clement     if (eleTy.isa<fir::HeapType>())
1120af6ee580SValentin Clement       return CFI_attribute_allocatable;
1121af6ee580SValentin Clement     return CFI_attribute_other;
1122af6ee580SValentin Clement   }
1123af6ee580SValentin Clement 
1124af6ee580SValentin Clement   static fir::RecordType unwrapIfDerived(fir::BoxType boxTy) {
1125af6ee580SValentin Clement     return fir::unwrapSequenceType(fir::dyn_cast_ptrOrBoxEleTy(boxTy))
1126af6ee580SValentin Clement         .template dyn_cast<fir::RecordType>();
1127af6ee580SValentin Clement   }
1128af6ee580SValentin Clement   static bool isDerivedTypeWithLenParams(fir::BoxType boxTy) {
1129af6ee580SValentin Clement     auto recTy = unwrapIfDerived(boxTy);
1130af6ee580SValentin Clement     return recTy && recTy.getNumLenParams() > 0;
1131af6ee580SValentin Clement   }
1132af6ee580SValentin Clement   static bool isDerivedType(fir::BoxType boxTy) {
1133af6ee580SValentin Clement     return unwrapIfDerived(boxTy) != nullptr;
1134af6ee580SValentin Clement   }
1135af6ee580SValentin Clement 
1136af6ee580SValentin Clement   // Get the element size and CFI type code of the boxed value.
1137af6ee580SValentin Clement   std::tuple<mlir::Value, mlir::Value> getSizeAndTypeCode(
1138af6ee580SValentin Clement       mlir::Location loc, mlir::ConversionPatternRewriter &rewriter,
1139af6ee580SValentin Clement       mlir::Type boxEleTy, mlir::ValueRange lenParams = {}) const {
1140af6ee580SValentin Clement     auto doInteger =
1141af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1142af6ee580SValentin Clement       int typeCode = fir::integerBitsToTypeCode(width);
1143af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1144af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1145af6ee580SValentin Clement     };
1146af6ee580SValentin Clement     auto doLogical =
1147af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1148af6ee580SValentin Clement       int typeCode = fir::logicalBitsToTypeCode(width);
1149af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1150af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1151af6ee580SValentin Clement     };
1152af6ee580SValentin Clement     auto doFloat = [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1153af6ee580SValentin Clement       int typeCode = fir::realBitsToTypeCode(width);
1154af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1155af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1156af6ee580SValentin Clement     };
1157af6ee580SValentin Clement     auto doComplex =
1158af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1159af6ee580SValentin Clement       auto typeCode = fir::complexBitsToTypeCode(width);
1160af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8 * 2),
1161af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1162af6ee580SValentin Clement     };
1163af6ee580SValentin Clement     auto doCharacter =
1164af6ee580SValentin Clement         [&](unsigned width,
1165af6ee580SValentin Clement             mlir::Value len) -> std::tuple<mlir::Value, mlir::Value> {
1166af6ee580SValentin Clement       auto typeCode = fir::characterBitsToTypeCode(width);
1167af6ee580SValentin Clement       auto typeCodeVal = this->genConstantOffset(loc, rewriter, typeCode);
1168af6ee580SValentin Clement       if (width == 8)
1169af6ee580SValentin Clement         return {len, typeCodeVal};
1170af6ee580SValentin Clement       auto byteWidth = this->genConstantOffset(loc, rewriter, width / 8);
1171af6ee580SValentin Clement       auto i64Ty = mlir::IntegerType::get(&this->lowerTy().getContext(), 64);
1172af6ee580SValentin Clement       auto size =
1173af6ee580SValentin Clement           rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, byteWidth, len);
1174af6ee580SValentin Clement       return {size, typeCodeVal};
1175af6ee580SValentin Clement     };
1176af6ee580SValentin Clement     auto getKindMap = [&]() -> fir::KindMapping & {
1177af6ee580SValentin Clement       return this->lowerTy().getKindMap();
1178af6ee580SValentin Clement     };
1179af6ee580SValentin Clement     // Pointer-like types.
1180af6ee580SValentin Clement     if (auto eleTy = fir::dyn_cast_ptrEleTy(boxEleTy))
1181af6ee580SValentin Clement       boxEleTy = eleTy;
1182af6ee580SValentin Clement     // Integer types.
1183af6ee580SValentin Clement     if (fir::isa_integer(boxEleTy)) {
1184af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::IntegerType>())
1185af6ee580SValentin Clement         return doInteger(ty.getWidth());
1186af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::IntegerType>();
1187af6ee580SValentin Clement       return doInteger(getKindMap().getIntegerBitsize(ty.getFKind()));
1188af6ee580SValentin Clement     }
1189af6ee580SValentin Clement     // Floating point types.
1190af6ee580SValentin Clement     if (fir::isa_real(boxEleTy)) {
1191af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::FloatType>())
1192af6ee580SValentin Clement         return doFloat(ty.getWidth());
1193af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::RealType>();
1194af6ee580SValentin Clement       return doFloat(getKindMap().getRealBitsize(ty.getFKind()));
1195af6ee580SValentin Clement     }
1196af6ee580SValentin Clement     // Complex types.
1197af6ee580SValentin Clement     if (fir::isa_complex(boxEleTy)) {
1198af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::ComplexType>())
1199af6ee580SValentin Clement         return doComplex(
1200af6ee580SValentin Clement             ty.getElementType().cast<mlir::FloatType>().getWidth());
1201af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::ComplexType>();
1202af6ee580SValentin Clement       return doComplex(getKindMap().getRealBitsize(ty.getFKind()));
1203af6ee580SValentin Clement     }
1204af6ee580SValentin Clement     // Character types.
1205af6ee580SValentin Clement     if (auto ty = boxEleTy.dyn_cast<fir::CharacterType>()) {
1206af6ee580SValentin Clement       auto charWidth = getKindMap().getCharacterBitsize(ty.getFKind());
1207af6ee580SValentin Clement       if (ty.getLen() != fir::CharacterType::unknownLen()) {
1208af6ee580SValentin Clement         auto len = this->genConstantOffset(loc, rewriter, ty.getLen());
1209af6ee580SValentin Clement         return doCharacter(charWidth, len);
1210af6ee580SValentin Clement       }
1211af6ee580SValentin Clement       assert(!lenParams.empty());
1212af6ee580SValentin Clement       return doCharacter(charWidth, lenParams.back());
1213af6ee580SValentin Clement     }
1214af6ee580SValentin Clement     // Logical type.
1215af6ee580SValentin Clement     if (auto ty = boxEleTy.dyn_cast<fir::LogicalType>())
1216af6ee580SValentin Clement       return doLogical(getKindMap().getLogicalBitsize(ty.getFKind()));
1217af6ee580SValentin Clement     // Array types.
1218af6ee580SValentin Clement     if (auto seqTy = boxEleTy.dyn_cast<fir::SequenceType>())
1219af6ee580SValentin Clement       return getSizeAndTypeCode(loc, rewriter, seqTy.getEleTy(), lenParams);
1220af6ee580SValentin Clement     // Derived-type types.
1221af6ee580SValentin Clement     if (boxEleTy.isa<fir::RecordType>()) {
1222af6ee580SValentin Clement       auto ptrTy = mlir::LLVM::LLVMPointerType::get(
1223af6ee580SValentin Clement           this->lowerTy().convertType(boxEleTy));
1224af6ee580SValentin Clement       auto nullPtr = rewriter.create<mlir::LLVM::NullOp>(loc, ptrTy);
1225af6ee580SValentin Clement       auto one =
1226af6ee580SValentin Clement           genConstantIndex(loc, this->lowerTy().offsetType(), rewriter, 1);
122730122656SAlex Zinenko       auto gep = rewriter.create<mlir::LLVM::GEPOp>(loc, ptrTy, nullPtr,
122830122656SAlex Zinenko                                                     mlir::ValueRange{one});
1229af6ee580SValentin Clement       auto eleSize = rewriter.create<mlir::LLVM::PtrToIntOp>(
1230af6ee580SValentin Clement           loc, this->lowerTy().indexType(), gep);
1231af6ee580SValentin Clement       return {eleSize,
1232af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, fir::derivedToTypeCode())};
1233af6ee580SValentin Clement     }
1234af6ee580SValentin Clement     // Reference type.
1235af6ee580SValentin Clement     if (fir::isa_ref_type(boxEleTy)) {
1236af6ee580SValentin Clement       // FIXME: use the target pointer size rather than sizeof(void*)
1237af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, sizeof(void *)),
1238af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, CFI_type_cptr)};
1239af6ee580SValentin Clement     }
1240af6ee580SValentin Clement     fir::emitFatalError(loc, "unhandled type in fir.box code generation");
1241af6ee580SValentin Clement   }
1242af6ee580SValentin Clement 
1243af6ee580SValentin Clement   /// Basic pattern to write a field in the descriptor
1244af6ee580SValentin Clement   mlir::Value insertField(mlir::ConversionPatternRewriter &rewriter,
1245af6ee580SValentin Clement                           mlir::Location loc, mlir::Value dest,
124644e58509SEric Schweitz                           llvm::ArrayRef<unsigned> fldIndexes,
124744e58509SEric Schweitz                           mlir::Value value, bool bitcast = false) const {
1248af6ee580SValentin Clement     auto boxTy = dest.getType();
1249af6ee580SValentin Clement     auto fldTy = this->getBoxEleTy(boxTy, fldIndexes);
1250af6ee580SValentin Clement     if (bitcast)
1251af6ee580SValentin Clement       value = rewriter.create<mlir::LLVM::BitcastOp>(loc, fldTy, value);
1252af6ee580SValentin Clement     else
1253af6ee580SValentin Clement       value = this->integerCast(loc, rewriter, fldTy, value);
125444e58509SEric Schweitz     llvm::SmallVector<mlir::Attribute, 2> attrs;
1255af6ee580SValentin Clement     for (auto i : fldIndexes)
1256af6ee580SValentin Clement       attrs.push_back(rewriter.getI32IntegerAttr(i));
1257af6ee580SValentin Clement     auto indexesAttr = mlir::ArrayAttr::get(rewriter.getContext(), attrs);
1258af6ee580SValentin Clement     return rewriter.create<mlir::LLVM::InsertValueOp>(loc, boxTy, dest, value,
1259af6ee580SValentin Clement                                                       indexesAttr);
1260af6ee580SValentin Clement   }
1261af6ee580SValentin Clement 
1262af6ee580SValentin Clement   inline mlir::Value
1263af6ee580SValentin Clement   insertBaseAddress(mlir::ConversionPatternRewriter &rewriter,
1264af6ee580SValentin Clement                     mlir::Location loc, mlir::Value dest,
1265af6ee580SValentin Clement                     mlir::Value base) const {
12661f551032SValentin Clement     return insertField(rewriter, loc, dest, {kAddrPosInBox}, base,
12671f551032SValentin Clement                        /*bitCast=*/true);
12681f551032SValentin Clement   }
12691f551032SValentin Clement 
12701f551032SValentin Clement   inline mlir::Value insertLowerBound(mlir::ConversionPatternRewriter &rewriter,
12711f551032SValentin Clement                                       mlir::Location loc, mlir::Value dest,
12721f551032SValentin Clement                                       unsigned dim, mlir::Value lb) const {
12731f551032SValentin Clement     return insertField(rewriter, loc, dest,
12741f551032SValentin Clement                        {kDimsPosInBox, dim, kDimLowerBoundPos}, lb);
12751f551032SValentin Clement   }
12761f551032SValentin Clement 
12771f551032SValentin Clement   inline mlir::Value insertExtent(mlir::ConversionPatternRewriter &rewriter,
12781f551032SValentin Clement                                   mlir::Location loc, mlir::Value dest,
12791f551032SValentin Clement                                   unsigned dim, mlir::Value extent) const {
12801f551032SValentin Clement     return insertField(rewriter, loc, dest, {kDimsPosInBox, dim, kDimExtentPos},
12811f551032SValentin Clement                        extent);
12821f551032SValentin Clement   }
12831f551032SValentin Clement 
12841f551032SValentin Clement   inline mlir::Value insertStride(mlir::ConversionPatternRewriter &rewriter,
12851f551032SValentin Clement                                   mlir::Location loc, mlir::Value dest,
12861f551032SValentin Clement                                   unsigned dim, mlir::Value stride) const {
12871f551032SValentin Clement     return insertField(rewriter, loc, dest, {kDimsPosInBox, dim, kDimStridePos},
12881f551032SValentin Clement                        stride);
1289af6ee580SValentin Clement   }
1290af6ee580SValentin Clement 
1291af6ee580SValentin Clement   /// Get the address of the type descriptor global variable that was created by
1292af6ee580SValentin Clement   /// lowering for derived type \p recType.
1293af6ee580SValentin Clement   template <typename BOX>
1294af6ee580SValentin Clement   mlir::Value
1295af6ee580SValentin Clement   getTypeDescriptor(BOX box, mlir::ConversionPatternRewriter &rewriter,
1296af6ee580SValentin Clement                     mlir::Location loc, fir::RecordType recType) const {
1297013160f6SJean Perier     std::string name =
1298013160f6SJean Perier         fir::NameUniquer::getTypeDescriptorName(recType.getName());
1299af6ee580SValentin Clement     auto module = box->template getParentOfType<mlir::ModuleOp>();
1300af6ee580SValentin Clement     if (auto global = module.template lookupSymbol<fir::GlobalOp>(name)) {
1301af6ee580SValentin Clement       auto ty = mlir::LLVM::LLVMPointerType::get(
1302af6ee580SValentin Clement           this->lowerTy().convertType(global.getType()));
1303af6ee580SValentin Clement       return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty,
1304feeee78aSJacques Pienaar                                                       global.getSymName());
1305af6ee580SValentin Clement     }
1306af6ee580SValentin Clement     if (auto global =
1307af6ee580SValentin Clement             module.template lookupSymbol<mlir::LLVM::GlobalOp>(name)) {
1308af6ee580SValentin Clement       // The global may have already been translated to LLVM.
1309af6ee580SValentin Clement       auto ty = mlir::LLVM::LLVMPointerType::get(global.getType());
1310af6ee580SValentin Clement       return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty,
1311feeee78aSJacques Pienaar                                                       global.getSymName());
1312af6ee580SValentin Clement     }
13137dd7ccd2SJean Perier     // Type info derived types do not have type descriptors since they are the
13147dd7ccd2SJean Perier     // types defining type descriptors.
1315013160f6SJean Perier     if (!this->options.ignoreMissingTypeDescriptors &&
1316013160f6SJean Perier         !fir::NameUniquer::belongsToModule(
1317013160f6SJean Perier             name, Fortran::semantics::typeInfoBuiltinModule))
1318013160f6SJean Perier       fir::emitFatalError(
1319013160f6SJean Perier           loc, "runtime derived type info descriptor was not generated");
13205bde97b1SJean Perier     return rewriter.create<mlir::LLVM::NullOp>(
13215bde97b1SJean Perier         loc, ::getVoidPtrType(box.getContext()));
13227dd7ccd2SJean Perier   }
1323af6ee580SValentin Clement 
1324af6ee580SValentin Clement   template <typename BOX>
1325af6ee580SValentin Clement   std::tuple<fir::BoxType, mlir::Value, mlir::Value>
1326af6ee580SValentin Clement   consDescriptorPrefix(BOX box, mlir::ConversionPatternRewriter &rewriter,
1327af6ee580SValentin Clement                        unsigned rank, mlir::ValueRange lenParams) const {
1328af6ee580SValentin Clement     auto loc = box.getLoc();
1329af6ee580SValentin Clement     auto boxTy = box.getType().template dyn_cast<fir::BoxType>();
1330af6ee580SValentin Clement     auto convTy = this->lowerTy().convertBoxType(boxTy, rank);
1331af6ee580SValentin Clement     auto llvmBoxPtrTy = convTy.template cast<mlir::LLVM::LLVMPointerType>();
1332af6ee580SValentin Clement     auto llvmBoxTy = llvmBoxPtrTy.getElementType();
1333af6ee580SValentin Clement     mlir::Value descriptor =
1334af6ee580SValentin Clement         rewriter.create<mlir::LLVM::UndefOp>(loc, llvmBoxTy);
1335af6ee580SValentin Clement 
1336af6ee580SValentin Clement     llvm::SmallVector<mlir::Value> typeparams = lenParams;
1337af6ee580SValentin Clement     if constexpr (!std::is_same_v<BOX, fir::EmboxOp>) {
1338af6ee580SValentin Clement       if (!box.substr().empty() && fir::hasDynamicSize(boxTy.getEleTy()))
1339af6ee580SValentin Clement         typeparams.push_back(box.substr()[1]);
1340af6ee580SValentin Clement     }
1341af6ee580SValentin Clement 
1342af6ee580SValentin Clement     // Write each of the fields with the appropriate values
1343af6ee580SValentin Clement     auto [eleSize, cfiTy] =
1344af6ee580SValentin Clement         getSizeAndTypeCode(loc, rewriter, boxTy.getEleTy(), typeparams);
1345af6ee580SValentin Clement     descriptor =
1346af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kElemLenPosInBox}, eleSize);
1347af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kVersionPosInBox},
1348af6ee580SValentin Clement                              this->genI32Constant(loc, rewriter, CFI_VERSION));
1349af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kRankPosInBox},
1350af6ee580SValentin Clement                              this->genI32Constant(loc, rewriter, rank));
1351af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kTypePosInBox}, cfiTy);
1352af6ee580SValentin Clement     descriptor =
1353af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kAttributePosInBox},
1354af6ee580SValentin Clement                     this->genI32Constant(loc, rewriter, getCFIAttr(boxTy)));
1355af6ee580SValentin Clement     const bool hasAddendum = isDerivedType(boxTy);
1356af6ee580SValentin Clement     descriptor =
1357af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kF18AddendumPosInBox},
1358af6ee580SValentin Clement                     this->genI32Constant(loc, rewriter, hasAddendum ? 1 : 0));
1359af6ee580SValentin Clement 
1360af6ee580SValentin Clement     if (hasAddendum) {
1361af6ee580SValentin Clement       auto isArray =
1362af6ee580SValentin Clement           fir::dyn_cast_ptrOrBoxEleTy(boxTy).template isa<fir::SequenceType>();
1363af6ee580SValentin Clement       unsigned typeDescFieldId = isArray ? kOptTypePtrPosInBox : kDimsPosInBox;
1364af6ee580SValentin Clement       auto typeDesc =
1365af6ee580SValentin Clement           getTypeDescriptor(box, rewriter, loc, unwrapIfDerived(boxTy));
1366af6ee580SValentin Clement       descriptor =
1367af6ee580SValentin Clement           insertField(rewriter, loc, descriptor, {typeDescFieldId}, typeDesc,
1368af6ee580SValentin Clement                       /*bitCast=*/true);
1369af6ee580SValentin Clement     }
1370af6ee580SValentin Clement 
1371af6ee580SValentin Clement     return {boxTy, descriptor, eleSize};
1372af6ee580SValentin Clement   }
1373af6ee580SValentin Clement 
13741f551032SValentin Clement   /// Compute the base address of a substring given the base address of a scalar
13751f551032SValentin Clement   /// string and the zero based string lower bound.
13761f551032SValentin Clement   mlir::Value shiftSubstringBase(mlir::ConversionPatternRewriter &rewriter,
13771f551032SValentin Clement                                  mlir::Location loc, mlir::Value base,
13781f551032SValentin Clement                                  mlir::Value lowerBound) const {
13791f551032SValentin Clement     llvm::SmallVector<mlir::Value> gepOperands;
13801f551032SValentin Clement     auto baseType =
13811f551032SValentin Clement         base.getType().cast<mlir::LLVM::LLVMPointerType>().getElementType();
13821f551032SValentin Clement     if (baseType.isa<mlir::LLVM::LLVMArrayType>()) {
13831f551032SValentin Clement       auto idxTy = this->lowerTy().indexType();
13841f551032SValentin Clement       mlir::Value zero = genConstantIndex(loc, idxTy, rewriter, 0);
13851f551032SValentin Clement       gepOperands.push_back(zero);
13861f551032SValentin Clement     }
13871f551032SValentin Clement     gepOperands.push_back(lowerBound);
13881f551032SValentin Clement     return this->genGEP(loc, base.getType(), rewriter, base, gepOperands);
13891f551032SValentin Clement   }
13901f551032SValentin Clement 
1391af6ee580SValentin Clement   /// If the embox is not in a globalOp body, allocate storage for the box;
1392af6ee580SValentin Clement   /// store the value inside and return the generated alloca. Return the input
1393af6ee580SValentin Clement   /// value otherwise.
1394af6ee580SValentin Clement   mlir::Value
1395af6ee580SValentin Clement   placeInMemoryIfNotGlobalInit(mlir::ConversionPatternRewriter &rewriter,
1396af6ee580SValentin Clement                                mlir::Location loc, mlir::Value boxValue) const {
1397af6ee580SValentin Clement     auto *thisBlock = rewriter.getInsertionBlock();
1398af6ee580SValentin Clement     if (thisBlock && mlir::isa<mlir::LLVM::GlobalOp>(thisBlock->getParentOp()))
1399af6ee580SValentin Clement       return boxValue;
1400af6ee580SValentin Clement     auto boxPtrTy = mlir::LLVM::LLVMPointerType::get(boxValue.getType());
1401af6ee580SValentin Clement     auto alloca = genAllocaWithType(loc, boxPtrTy, defaultAlign, rewriter);
1402af6ee580SValentin Clement     rewriter.create<mlir::LLVM::StoreOp>(loc, boxValue, alloca);
1403af6ee580SValentin Clement     return alloca;
1404af6ee580SValentin Clement   }
1405af6ee580SValentin Clement };
1406af6ee580SValentin Clement 
14071f551032SValentin Clement /// Compute the extent of a triplet slice (lb:ub:step).
14081f551032SValentin Clement static mlir::Value
14091f551032SValentin Clement computeTripletExtent(mlir::ConversionPatternRewriter &rewriter,
14101f551032SValentin Clement                      mlir::Location loc, mlir::Value lb, mlir::Value ub,
14111f551032SValentin Clement                      mlir::Value step, mlir::Value zero, mlir::Type type) {
14121f551032SValentin Clement   mlir::Value extent = rewriter.create<mlir::LLVM::SubOp>(loc, type, ub, lb);
14131f551032SValentin Clement   extent = rewriter.create<mlir::LLVM::AddOp>(loc, type, extent, step);
14141f551032SValentin Clement   extent = rewriter.create<mlir::LLVM::SDivOp>(loc, type, extent, step);
14151f551032SValentin Clement   // If the resulting extent is negative (`ub-lb` and `step` have different
14161f551032SValentin Clement   // signs), zero must be returned instead.
14171f551032SValentin Clement   auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
14181f551032SValentin Clement       loc, mlir::LLVM::ICmpPredicate::sgt, extent, zero);
14191f551032SValentin Clement   return rewriter.create<mlir::LLVM::SelectOp>(loc, cmp, extent, zero);
14201f551032SValentin Clement }
14211f551032SValentin Clement 
1422af6ee580SValentin Clement /// Create a generic box on a memory reference. This conversions lowers the
1423af6ee580SValentin Clement /// abstract box to the appropriate, initialized descriptor.
1424af6ee580SValentin Clement struct EmboxOpConversion : public EmboxCommonConversion<fir::EmboxOp> {
1425af6ee580SValentin Clement   using EmboxCommonConversion::EmboxCommonConversion;
1426af6ee580SValentin Clement 
1427af6ee580SValentin Clement   mlir::LogicalResult
1428af6ee580SValentin Clement   matchAndRewrite(fir::EmboxOp embox, OpAdaptor adaptor,
1429af6ee580SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1430af6ee580SValentin Clement     assert(!embox.getShape() && "There should be no dims on this embox op");
1431af6ee580SValentin Clement     auto [boxTy, dest, eleSize] =
1432af6ee580SValentin Clement         consDescriptorPrefix(embox, rewriter, /*rank=*/0,
1433af6ee580SValentin Clement                              /*lenParams=*/adaptor.getOperands().drop_front(1));
1434af6ee580SValentin Clement     dest = insertBaseAddress(rewriter, embox.getLoc(), dest,
1435af6ee580SValentin Clement                              adaptor.getOperands()[0]);
14367ce8c6fcSKiran Chandramohan     if (isDerivedTypeWithLenParams(boxTy)) {
14377ce8c6fcSKiran Chandramohan       TODO(embox.getLoc(),
14387ce8c6fcSKiran Chandramohan            "fir.embox codegen of derived with length parameters");
143944e58509SEric Schweitz       return mlir::failure();
14407ce8c6fcSKiran Chandramohan     }
1441af6ee580SValentin Clement     auto result = placeInMemoryIfNotGlobalInit(rewriter, embox.getLoc(), dest);
1442af6ee580SValentin Clement     rewriter.replaceOp(embox, result);
144344e58509SEric Schweitz     return mlir::success();
1444af6ee580SValentin Clement   }
1445af6ee580SValentin Clement };
1446af6ee580SValentin Clement 
14471f551032SValentin Clement /// Create a generic box on a memory reference.
14481f551032SValentin Clement struct XEmboxOpConversion : public EmboxCommonConversion<fir::cg::XEmboxOp> {
14491f551032SValentin Clement   using EmboxCommonConversion::EmboxCommonConversion;
14501f551032SValentin Clement 
14511f551032SValentin Clement   mlir::LogicalResult
14521f551032SValentin Clement   matchAndRewrite(fir::cg::XEmboxOp xbox, OpAdaptor adaptor,
14531f551032SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
14541f551032SValentin Clement     auto [boxTy, dest, eleSize] = consDescriptorPrefix(
14551f551032SValentin Clement         xbox, rewriter, xbox.getOutRank(),
14561f551032SValentin Clement         adaptor.getOperands().drop_front(xbox.lenParamOffset()));
14571f551032SValentin Clement     // Generate the triples in the dims field of the descriptor
14581f551032SValentin Clement     mlir::ValueRange operands = adaptor.getOperands();
14591f551032SValentin Clement     auto i64Ty = mlir::IntegerType::get(xbox.getContext(), 64);
14601f551032SValentin Clement     mlir::Value base = operands[0];
14611f551032SValentin Clement     assert(!xbox.shape().empty() && "must have a shape");
14621f551032SValentin Clement     unsigned shapeOffset = xbox.shapeOffset();
14631f551032SValentin Clement     bool hasShift = !xbox.shift().empty();
14641f551032SValentin Clement     unsigned shiftOffset = xbox.shiftOffset();
14651f551032SValentin Clement     bool hasSlice = !xbox.slice().empty();
14661f551032SValentin Clement     unsigned sliceOffset = xbox.sliceOffset();
14671f551032SValentin Clement     mlir::Location loc = xbox.getLoc();
14681f551032SValentin Clement     mlir::Value zero = genConstantIndex(loc, i64Ty, rewriter, 0);
14691f551032SValentin Clement     mlir::Value one = genConstantIndex(loc, i64Ty, rewriter, 1);
14701f551032SValentin Clement     mlir::Value prevDim = integerCast(loc, rewriter, i64Ty, eleSize);
14711f551032SValentin Clement     mlir::Value prevPtrOff = one;
14721f551032SValentin Clement     mlir::Type eleTy = boxTy.getEleTy();
14731f551032SValentin Clement     const unsigned rank = xbox.getRank();
14741f551032SValentin Clement     llvm::SmallVector<mlir::Value> gepArgs;
14751f551032SValentin Clement     unsigned constRows = 0;
14761f551032SValentin Clement     mlir::Value ptrOffset = zero;
14771f551032SValentin Clement     if (auto memEleTy = fir::dyn_cast_ptrEleTy(xbox.memref().getType()))
14781f551032SValentin Clement       if (auto seqTy = memEleTy.dyn_cast<fir::SequenceType>()) {
14791f551032SValentin Clement         mlir::Type seqEleTy = seqTy.getEleTy();
14801f551032SValentin Clement         // Adjust the element scaling factor if the element is a dependent type.
14811f551032SValentin Clement         if (fir::hasDynamicSize(seqEleTy)) {
14821f551032SValentin Clement           if (fir::isa_char(seqEleTy)) {
14831f551032SValentin Clement             assert(xbox.lenParams().size() == 1);
14841f551032SValentin Clement             prevPtrOff = integerCast(loc, rewriter, i64Ty,
14851f551032SValentin Clement                                      operands[xbox.lenParamOffset()]);
14861f551032SValentin Clement           } else if (seqEleTy.isa<fir::RecordType>()) {
14871f551032SValentin Clement             TODO(loc, "generate call to calculate size of PDT");
14881f551032SValentin Clement           } else {
14891f551032SValentin Clement             return rewriter.notifyMatchFailure(xbox, "unexpected dynamic type");
14901f551032SValentin Clement           }
14911f551032SValentin Clement         } else {
14921f551032SValentin Clement           constRows = seqTy.getConstantRows();
14931f551032SValentin Clement         }
14941f551032SValentin Clement       }
14951f551032SValentin Clement 
14961f551032SValentin Clement     bool hasSubcomp = !xbox.subcomponent().empty();
1497bb3afae9SJean Perier     if (!xbox.substr().empty())
1498bb3afae9SJean Perier       TODO(loc, "codegen of fir.embox with substring");
1499bb3afae9SJean Perier 
15001f551032SValentin Clement     mlir::Value stepExpr;
15011f551032SValentin Clement     if (hasSubcomp) {
15021f551032SValentin Clement       // We have a subcomponent. The step value needs to be the number of
15031f551032SValentin Clement       // bytes per element (which is a derived type).
15041f551032SValentin Clement       mlir::Type ty0 = base.getType();
15051f551032SValentin Clement       [[maybe_unused]] auto ptrTy = ty0.dyn_cast<mlir::LLVM::LLVMPointerType>();
15061f551032SValentin Clement       assert(ptrTy && "expected pointer type");
15071f551032SValentin Clement       mlir::Type memEleTy = fir::dyn_cast_ptrEleTy(xbox.memref().getType());
15081f551032SValentin Clement       assert(memEleTy && "expected fir pointer type");
15091f551032SValentin Clement       auto seqTy = memEleTy.dyn_cast<fir::SequenceType>();
15101f551032SValentin Clement       assert(seqTy && "expected sequence type");
15111f551032SValentin Clement       mlir::Type seqEleTy = seqTy.getEleTy();
15121f551032SValentin Clement       auto eleTy = mlir::LLVM::LLVMPointerType::get(convertType(seqEleTy));
15131f551032SValentin Clement       stepExpr = computeDerivedTypeSize(loc, eleTy, i64Ty, rewriter);
15141f551032SValentin Clement     }
15151f551032SValentin Clement 
15161f551032SValentin Clement     // Process the array subspace arguments (shape, shift, etc.), if any,
15171f551032SValentin Clement     // translating everything to values in the descriptor wherever the entity
15181f551032SValentin Clement     // has a dynamic array dimension.
15191f551032SValentin Clement     for (unsigned di = 0, descIdx = 0; di < rank; ++di) {
15201f551032SValentin Clement       mlir::Value extent = operands[shapeOffset];
15211f551032SValentin Clement       mlir::Value outerExtent = extent;
15221f551032SValentin Clement       bool skipNext = false;
15231f551032SValentin Clement       if (hasSlice) {
15241f551032SValentin Clement         mlir::Value off = operands[sliceOffset];
15251f551032SValentin Clement         mlir::Value adj = one;
15261f551032SValentin Clement         if (hasShift)
15271f551032SValentin Clement           adj = operands[shiftOffset];
15281f551032SValentin Clement         auto ao = rewriter.create<mlir::LLVM::SubOp>(loc, i64Ty, off, adj);
15291f551032SValentin Clement         if (constRows > 0) {
15301f551032SValentin Clement           gepArgs.push_back(ao);
15311f551032SValentin Clement         } else {
15321f551032SValentin Clement           auto dimOff =
15331f551032SValentin Clement               rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, ao, prevPtrOff);
15341f551032SValentin Clement           ptrOffset =
15351f551032SValentin Clement               rewriter.create<mlir::LLVM::AddOp>(loc, i64Ty, dimOff, ptrOffset);
15361f551032SValentin Clement         }
15371f551032SValentin Clement         if (mlir::isa_and_nonnull<fir::UndefOp>(
15381f551032SValentin Clement                 xbox.slice()[3 * di + 1].getDefiningOp())) {
15391f551032SValentin Clement           // This dimension contains a scalar expression in the array slice op.
15401f551032SValentin Clement           // The dimension is loop invariant, will be dropped, and will not
15411f551032SValentin Clement           // appear in the descriptor.
15421f551032SValentin Clement           skipNext = true;
15431f551032SValentin Clement         }
15441f551032SValentin Clement       }
15451f551032SValentin Clement       if (!skipNext) {
15461f551032SValentin Clement         if (hasSlice)
15471f551032SValentin Clement           extent = computeTripletExtent(rewriter, loc, operands[sliceOffset],
15481f551032SValentin Clement                                         operands[sliceOffset + 1],
15491f551032SValentin Clement                                         operands[sliceOffset + 2], zero, i64Ty);
1550d3bc3a04SJean Perier         // store lower bound (normally 0) for BIND(C) interoperability.
1551d3bc3a04SJean Perier         mlir::Value lb = zero;
1552d3bc3a04SJean Perier         const bool isaPointerOrAllocatable =
1553d3bc3a04SJean Perier             eleTy.isa<fir::PointerType>() || eleTy.isa<fir::HeapType>();
1554d3bc3a04SJean Perier         // Lower bound is defaults to 1 for POINTER, ALLOCATABLE, and
1555d3bc3a04SJean Perier         // denormalized descriptors.
1556d3bc3a04SJean Perier         if (isaPointerOrAllocatable || !normalizedLowerBound(xbox)) {
1557d3bc3a04SJean Perier           lb = one;
1558bb3afae9SJean Perier           // If there is a shifted origin, and no fir.slice, and this is not
1559bb3afae9SJean Perier           // a normalized descriptor then use the value from the shift op as
1560bb3afae9SJean Perier           // the lower bound.
1561bb3afae9SJean Perier           if (hasShift && !(hasSlice || hasSubcomp)) {
1562d3bc3a04SJean Perier             lb = operands[shiftOffset];
1563d3bc3a04SJean Perier             auto extentIsEmpty = rewriter.create<mlir::LLVM::ICmpOp>(
1564d3bc3a04SJean Perier                 loc, mlir::LLVM::ICmpPredicate::eq, extent, zero);
1565d3bc3a04SJean Perier             lb = rewriter.create<mlir::LLVM::SelectOp>(loc, extentIsEmpty, one,
1566d3bc3a04SJean Perier                                                        lb);
1567d3bc3a04SJean Perier           }
1568d3bc3a04SJean Perier         }
1569d3bc3a04SJean Perier         dest = insertLowerBound(rewriter, loc, dest, descIdx, lb);
1570d3bc3a04SJean Perier 
15711f551032SValentin Clement         dest = insertExtent(rewriter, loc, dest, descIdx, extent);
15721f551032SValentin Clement 
15731f551032SValentin Clement         // store step (scaled by shaped extent)
15741f551032SValentin Clement 
15751f551032SValentin Clement         mlir::Value step = hasSubcomp ? stepExpr : prevDim;
15761f551032SValentin Clement         if (hasSlice)
15771f551032SValentin Clement           step = rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, step,
15781f551032SValentin Clement                                                     operands[sliceOffset + 2]);
15791f551032SValentin Clement         dest = insertStride(rewriter, loc, dest, descIdx, step);
15801f551032SValentin Clement         ++descIdx;
15811f551032SValentin Clement       }
15821f551032SValentin Clement 
15831f551032SValentin Clement       // compute the stride and offset for the next natural dimension
15841f551032SValentin Clement       prevDim =
15851f551032SValentin Clement           rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, prevDim, outerExtent);
15861f551032SValentin Clement       if (constRows == 0)
15871f551032SValentin Clement         prevPtrOff = rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, prevPtrOff,
15881f551032SValentin Clement                                                         outerExtent);
15890601a0dcSJean Perier       else
15900601a0dcSJean Perier         --constRows;
15911f551032SValentin Clement 
15921f551032SValentin Clement       // increment iterators
15931f551032SValentin Clement       ++shapeOffset;
15941f551032SValentin Clement       if (hasShift)
15951f551032SValentin Clement         ++shiftOffset;
15961f551032SValentin Clement       if (hasSlice)
15971f551032SValentin Clement         sliceOffset += 3;
15981f551032SValentin Clement     }
15991f551032SValentin Clement     if (hasSlice || hasSubcomp || !xbox.substr().empty()) {
160030122656SAlex Zinenko       llvm::SmallVector<mlir::Value> args = {ptrOffset};
16011f551032SValentin Clement       args.append(gepArgs.rbegin(), gepArgs.rend());
16021f551032SValentin Clement       if (hasSubcomp) {
16031f551032SValentin Clement         // For each field in the path add the offset to base via the args list.
16041f551032SValentin Clement         // In the most general case, some offsets must be computed since
16051f551032SValentin Clement         // they are not be known until runtime.
16061f551032SValentin Clement         if (fir::hasDynamicSize(fir::unwrapSequenceType(
16071f551032SValentin Clement                 fir::unwrapPassByRefType(xbox.memref().getType()))))
16081f551032SValentin Clement           TODO(loc, "fir.embox codegen dynamic size component in derived type");
16091f551032SValentin Clement         args.append(operands.begin() + xbox.subcomponentOffset(),
16101f551032SValentin Clement                     operands.begin() + xbox.subcomponentOffset() +
16111f551032SValentin Clement                         xbox.subcomponent().size());
16121f551032SValentin Clement       }
161330122656SAlex Zinenko       base =
161430122656SAlex Zinenko           rewriter.create<mlir::LLVM::GEPOp>(loc, base.getType(), base, args);
16151f551032SValentin Clement       if (!xbox.substr().empty())
16161f551032SValentin Clement         base = shiftSubstringBase(rewriter, loc, base,
16171f551032SValentin Clement                                   operands[xbox.substrOffset()]);
16181f551032SValentin Clement     }
16191f551032SValentin Clement     dest = insertBaseAddress(rewriter, loc, dest, base);
16201f551032SValentin Clement     if (isDerivedTypeWithLenParams(boxTy))
16211f551032SValentin Clement       TODO(loc, "fir.embox codegen of derived with length parameters");
16221f551032SValentin Clement 
16231f551032SValentin Clement     mlir::Value result = placeInMemoryIfNotGlobalInit(rewriter, loc, dest);
16241f551032SValentin Clement     rewriter.replaceOp(xbox, result);
162544e58509SEric Schweitz     return mlir::success();
16261f551032SValentin Clement   }
1627d3bc3a04SJean Perier 
1628d3bc3a04SJean Perier   /// Return true if `xbox` has a normalized lower bounds attribute. A box value
1629d3bc3a04SJean Perier   /// that is neither a POINTER nor an ALLOCATABLE should be normalized to a
1630d3bc3a04SJean Perier   /// zero origin lower bound for interoperability with BIND(C).
1631d3bc3a04SJean Perier   inline static bool normalizedLowerBound(fir::cg::XEmboxOp xbox) {
1632d3bc3a04SJean Perier     return xbox->hasAttr(fir::getNormalizedLowerBoundAttrName());
1633d3bc3a04SJean Perier   }
16341f551032SValentin Clement };
16351f551032SValentin Clement 
1636fa517555SKiran Chandramohan /// Create a new box given a box reference.
1637fa517555SKiran Chandramohan struct XReboxOpConversion : public EmboxCommonConversion<fir::cg::XReboxOp> {
1638fa517555SKiran Chandramohan   using EmboxCommonConversion::EmboxCommonConversion;
1639fa517555SKiran Chandramohan 
1640fa517555SKiran Chandramohan   mlir::LogicalResult
1641fa517555SKiran Chandramohan   matchAndRewrite(fir::cg::XReboxOp rebox, OpAdaptor adaptor,
1642fa517555SKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
1643fa517555SKiran Chandramohan     mlir::Location loc = rebox.getLoc();
1644fa517555SKiran Chandramohan     mlir::Type idxTy = lowerTy().indexType();
1645fa517555SKiran Chandramohan     mlir::Value loweredBox = adaptor.getOperands()[0];
1646fa517555SKiran Chandramohan     mlir::ValueRange operands = adaptor.getOperands();
1647fa517555SKiran Chandramohan 
1648fa517555SKiran Chandramohan     // Create new descriptor and fill its non-shape related data.
1649fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value, 2> lenParams;
1650fa517555SKiran Chandramohan     mlir::Type inputEleTy = getInputEleTy(rebox);
1651fa517555SKiran Chandramohan     if (auto charTy = inputEleTy.dyn_cast<fir::CharacterType>()) {
1652fa517555SKiran Chandramohan       mlir::Value len =
1653fa517555SKiran Chandramohan           loadElementSizeFromBox(loc, idxTy, loweredBox, rewriter);
1654fa517555SKiran Chandramohan       if (charTy.getFKind() != 1) {
1655fa517555SKiran Chandramohan         mlir::Value width =
1656fa517555SKiran Chandramohan             genConstantIndex(loc, idxTy, rewriter, charTy.getFKind());
1657fa517555SKiran Chandramohan         len = rewriter.create<mlir::LLVM::SDivOp>(loc, idxTy, len, width);
1658fa517555SKiran Chandramohan       }
1659fa517555SKiran Chandramohan       lenParams.emplace_back(len);
1660fa517555SKiran Chandramohan     } else if (auto recTy = inputEleTy.dyn_cast<fir::RecordType>()) {
1661fa517555SKiran Chandramohan       if (recTy.getNumLenParams() != 0)
1662fa517555SKiran Chandramohan         TODO(loc, "reboxing descriptor of derived type with length parameters");
1663fa517555SKiran Chandramohan     }
1664fa517555SKiran Chandramohan     auto [boxTy, dest, eleSize] =
1665fa517555SKiran Chandramohan         consDescriptorPrefix(rebox, rewriter, rebox.getOutRank(), lenParams);
1666fa517555SKiran Chandramohan 
1667fa517555SKiran Chandramohan     // Read input extents, strides, and base address
1668fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> inputExtents;
1669fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> inputStrides;
1670fa517555SKiran Chandramohan     const unsigned inputRank = rebox.getRank();
1671fa517555SKiran Chandramohan     for (unsigned i = 0; i < inputRank; ++i) {
1672fa517555SKiran Chandramohan       mlir::Value dim = genConstantIndex(loc, idxTy, rewriter, i);
167344e58509SEric Schweitz       llvm::SmallVector<mlir::Value, 3> dimInfo =
1674fa517555SKiran Chandramohan           getDimsFromBox(loc, {idxTy, idxTy, idxTy}, loweredBox, dim, rewriter);
1675fa517555SKiran Chandramohan       inputExtents.emplace_back(dimInfo[1]);
1676fa517555SKiran Chandramohan       inputStrides.emplace_back(dimInfo[2]);
1677fa517555SKiran Chandramohan     }
1678fa517555SKiran Chandramohan 
1679fa517555SKiran Chandramohan     mlir::Type baseTy = getBaseAddrTypeFromBox(loweredBox.getType());
1680fa517555SKiran Chandramohan     mlir::Value baseAddr =
1681fa517555SKiran Chandramohan         loadBaseAddrFromBox(loc, baseTy, loweredBox, rewriter);
1682fa517555SKiran Chandramohan 
1683fa517555SKiran Chandramohan     if (!rebox.slice().empty() || !rebox.subcomponent().empty())
1684fa517555SKiran Chandramohan       return sliceBox(rebox, dest, baseAddr, inputExtents, inputStrides,
1685fa517555SKiran Chandramohan                       operands, rewriter);
1686fa517555SKiran Chandramohan     return reshapeBox(rebox, dest, baseAddr, inputExtents, inputStrides,
1687fa517555SKiran Chandramohan                       operands, rewriter);
1688fa517555SKiran Chandramohan   }
1689fa517555SKiran Chandramohan 
1690fa517555SKiran Chandramohan private:
1691fa517555SKiran Chandramohan   /// Write resulting shape and base address in descriptor, and replace rebox
1692fa517555SKiran Chandramohan   /// op.
1693fa517555SKiran Chandramohan   mlir::LogicalResult
1694fa517555SKiran Chandramohan   finalizeRebox(fir::cg::XReboxOp rebox, mlir::Value dest, mlir::Value base,
1695fa517555SKiran Chandramohan                 mlir::ValueRange lbounds, mlir::ValueRange extents,
1696fa517555SKiran Chandramohan                 mlir::ValueRange strides,
1697fa517555SKiran Chandramohan                 mlir::ConversionPatternRewriter &rewriter) const {
1698fa517555SKiran Chandramohan     mlir::Location loc = rebox.getLoc();
1699d3bc3a04SJean Perier     mlir::Value zero =
1700d3bc3a04SJean Perier         genConstantIndex(loc, lowerTy().indexType(), rewriter, 0);
1701fa517555SKiran Chandramohan     mlir::Value one = genConstantIndex(loc, lowerTy().indexType(), rewriter, 1);
1702fa517555SKiran Chandramohan     for (auto iter : llvm::enumerate(llvm::zip(extents, strides))) {
1703d3bc3a04SJean Perier       mlir::Value extent = std::get<0>(iter.value());
1704fa517555SKiran Chandramohan       unsigned dim = iter.index();
1705d3bc3a04SJean Perier       mlir::Value lb = one;
1706d3bc3a04SJean Perier       if (!lbounds.empty()) {
1707d3bc3a04SJean Perier         lb = lbounds[dim];
1708d3bc3a04SJean Perier         auto extentIsEmpty = rewriter.create<mlir::LLVM::ICmpOp>(
1709d3bc3a04SJean Perier             loc, mlir::LLVM::ICmpPredicate::eq, extent, zero);
1710d3bc3a04SJean Perier         lb = rewriter.create<mlir::LLVM::SelectOp>(loc, extentIsEmpty, one, lb);
1711d3bc3a04SJean Perier       };
1712fa517555SKiran Chandramohan       dest = insertLowerBound(rewriter, loc, dest, dim, lb);
1713d3bc3a04SJean Perier       dest = insertExtent(rewriter, loc, dest, dim, extent);
1714fa517555SKiran Chandramohan       dest = insertStride(rewriter, loc, dest, dim, std::get<1>(iter.value()));
1715fa517555SKiran Chandramohan     }
1716fa517555SKiran Chandramohan     dest = insertBaseAddress(rewriter, loc, dest, base);
1717fa517555SKiran Chandramohan     mlir::Value result =
1718fa517555SKiran Chandramohan         placeInMemoryIfNotGlobalInit(rewriter, rebox.getLoc(), dest);
1719fa517555SKiran Chandramohan     rewriter.replaceOp(rebox, result);
172044e58509SEric Schweitz     return mlir::success();
1721fa517555SKiran Chandramohan   }
1722fa517555SKiran Chandramohan 
1723fa517555SKiran Chandramohan   // Apply slice given the base address, extents and strides of the input box.
1724fa517555SKiran Chandramohan   mlir::LogicalResult
1725fa517555SKiran Chandramohan   sliceBox(fir::cg::XReboxOp rebox, mlir::Value dest, mlir::Value base,
1726fa517555SKiran Chandramohan            mlir::ValueRange inputExtents, mlir::ValueRange inputStrides,
1727fa517555SKiran Chandramohan            mlir::ValueRange operands,
1728fa517555SKiran Chandramohan            mlir::ConversionPatternRewriter &rewriter) const {
1729fa517555SKiran Chandramohan     mlir::Location loc = rebox.getLoc();
1730fa517555SKiran Chandramohan     mlir::Type voidPtrTy = ::getVoidPtrType(rebox.getContext());
1731fa517555SKiran Chandramohan     mlir::Type idxTy = lowerTy().indexType();
1732fa517555SKiran Chandramohan     mlir::Value zero = genConstantIndex(loc, idxTy, rewriter, 0);
1733fa517555SKiran Chandramohan     // Apply subcomponent and substring shift on base address.
1734fa517555SKiran Chandramohan     if (!rebox.subcomponent().empty() || !rebox.substr().empty()) {
1735fa517555SKiran Chandramohan       // Cast to inputEleTy* so that a GEP can be used.
1736fa517555SKiran Chandramohan       mlir::Type inputEleTy = getInputEleTy(rebox);
1737fa517555SKiran Chandramohan       auto llvmElePtrTy =
1738fa517555SKiran Chandramohan           mlir::LLVM::LLVMPointerType::get(convertType(inputEleTy));
1739fa517555SKiran Chandramohan       base = rewriter.create<mlir::LLVM::BitcastOp>(loc, llvmElePtrTy, base);
1740fa517555SKiran Chandramohan 
1741fa517555SKiran Chandramohan       if (!rebox.subcomponent().empty()) {
1742fa517555SKiran Chandramohan         llvm::SmallVector<mlir::Value> gepOperands = {zero};
1743fa517555SKiran Chandramohan         for (unsigned i = 0; i < rebox.subcomponent().size(); ++i)
1744fa517555SKiran Chandramohan           gepOperands.push_back(operands[rebox.subcomponentOffset() + i]);
1745fa517555SKiran Chandramohan         base = genGEP(loc, llvmElePtrTy, rewriter, base, gepOperands);
1746fa517555SKiran Chandramohan       }
1747fa517555SKiran Chandramohan       if (!rebox.substr().empty())
1748fa517555SKiran Chandramohan         base = shiftSubstringBase(rewriter, loc, base,
1749fa517555SKiran Chandramohan                                   operands[rebox.substrOffset()]);
1750fa517555SKiran Chandramohan     }
1751fa517555SKiran Chandramohan 
1752fa517555SKiran Chandramohan     if (rebox.slice().empty())
1753fa517555SKiran Chandramohan       // The array section is of the form array[%component][substring], keep
1754fa517555SKiran Chandramohan       // the input array extents and strides.
1755fa517555SKiran Chandramohan       return finalizeRebox(rebox, dest, base, /*lbounds*/ llvm::None,
1756fa517555SKiran Chandramohan                            inputExtents, inputStrides, rewriter);
1757fa517555SKiran Chandramohan 
1758fa517555SKiran Chandramohan     // Strides from the fir.box are in bytes.
1759fa517555SKiran Chandramohan     base = rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, base);
1760fa517555SKiran Chandramohan 
1761fa517555SKiran Chandramohan     // The slice is of the form array(i:j:k)[%component]. Compute new extents
1762fa517555SKiran Chandramohan     // and strides.
1763fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> slicedExtents;
1764fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> slicedStrides;
1765fa517555SKiran Chandramohan     mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1);
1766fa517555SKiran Chandramohan     const bool sliceHasOrigins = !rebox.shift().empty();
1767fa517555SKiran Chandramohan     unsigned sliceOps = rebox.sliceOffset();
1768fa517555SKiran Chandramohan     unsigned shiftOps = rebox.shiftOffset();
1769fa517555SKiran Chandramohan     auto strideOps = inputStrides.begin();
1770fa517555SKiran Chandramohan     const unsigned inputRank = inputStrides.size();
1771fa517555SKiran Chandramohan     for (unsigned i = 0; i < inputRank;
1772fa517555SKiran Chandramohan          ++i, ++strideOps, ++shiftOps, sliceOps += 3) {
1773fa517555SKiran Chandramohan       mlir::Value sliceLb =
1774fa517555SKiran Chandramohan           integerCast(loc, rewriter, idxTy, operands[sliceOps]);
1775fa517555SKiran Chandramohan       mlir::Value inputStride = *strideOps; // already idxTy
1776fa517555SKiran Chandramohan       // Apply origin shift: base += (lb-shift)*input_stride
1777fa517555SKiran Chandramohan       mlir::Value sliceOrigin =
1778fa517555SKiran Chandramohan           sliceHasOrigins
1779fa517555SKiran Chandramohan               ? integerCast(loc, rewriter, idxTy, operands[shiftOps])
1780fa517555SKiran Chandramohan               : one;
1781fa517555SKiran Chandramohan       mlir::Value diff =
1782fa517555SKiran Chandramohan           rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, sliceLb, sliceOrigin);
1783fa517555SKiran Chandramohan       mlir::Value offset =
1784fa517555SKiran Chandramohan           rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, inputStride);
1785fa517555SKiran Chandramohan       base = genGEP(loc, voidPtrTy, rewriter, base, offset);
1786fa517555SKiran Chandramohan       // Apply upper bound and step if this is a triplet. Otherwise, the
1787fa517555SKiran Chandramohan       // dimension is dropped and no extents/strides are computed.
1788fa517555SKiran Chandramohan       mlir::Value upper = operands[sliceOps + 1];
1789fa517555SKiran Chandramohan       const bool isTripletSlice =
1790fa517555SKiran Chandramohan           !mlir::isa_and_nonnull<mlir::LLVM::UndefOp>(upper.getDefiningOp());
1791fa517555SKiran Chandramohan       if (isTripletSlice) {
1792fa517555SKiran Chandramohan         mlir::Value step =
1793fa517555SKiran Chandramohan             integerCast(loc, rewriter, idxTy, operands[sliceOps + 2]);
1794fa517555SKiran Chandramohan         // extent = ub-lb+step/step
1795fa517555SKiran Chandramohan         mlir::Value sliceUb = integerCast(loc, rewriter, idxTy, upper);
1796fa517555SKiran Chandramohan         mlir::Value extent = computeTripletExtent(rewriter, loc, sliceLb,
1797fa517555SKiran Chandramohan                                                   sliceUb, step, zero, idxTy);
1798fa517555SKiran Chandramohan         slicedExtents.emplace_back(extent);
1799fa517555SKiran Chandramohan         // stride = step*input_stride
1800fa517555SKiran Chandramohan         mlir::Value stride =
1801fa517555SKiran Chandramohan             rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, step, inputStride);
1802fa517555SKiran Chandramohan         slicedStrides.emplace_back(stride);
1803fa517555SKiran Chandramohan       }
1804fa517555SKiran Chandramohan     }
1805fa517555SKiran Chandramohan     return finalizeRebox(rebox, dest, base, /*lbounds*/ llvm::None,
1806fa517555SKiran Chandramohan                          slicedExtents, slicedStrides, rewriter);
1807fa517555SKiran Chandramohan   }
1808fa517555SKiran Chandramohan 
1809fa517555SKiran Chandramohan   /// Apply a new shape to the data described by a box given the base address,
1810fa517555SKiran Chandramohan   /// extents and strides of the box.
1811fa517555SKiran Chandramohan   mlir::LogicalResult
1812fa517555SKiran Chandramohan   reshapeBox(fir::cg::XReboxOp rebox, mlir::Value dest, mlir::Value base,
1813fa517555SKiran Chandramohan              mlir::ValueRange inputExtents, mlir::ValueRange inputStrides,
1814fa517555SKiran Chandramohan              mlir::ValueRange operands,
1815fa517555SKiran Chandramohan              mlir::ConversionPatternRewriter &rewriter) const {
1816fa517555SKiran Chandramohan     mlir::ValueRange reboxShifts{operands.begin() + rebox.shiftOffset(),
1817fa517555SKiran Chandramohan                                  operands.begin() + rebox.shiftOffset() +
1818fa517555SKiran Chandramohan                                      rebox.shift().size()};
1819fa517555SKiran Chandramohan     if (rebox.shape().empty()) {
1820fa517555SKiran Chandramohan       // Only setting new lower bounds.
1821fa517555SKiran Chandramohan       return finalizeRebox(rebox, dest, base, reboxShifts, inputExtents,
1822fa517555SKiran Chandramohan                            inputStrides, rewriter);
1823fa517555SKiran Chandramohan     }
1824fa517555SKiran Chandramohan 
1825fa517555SKiran Chandramohan     mlir::Location loc = rebox.getLoc();
1826fa517555SKiran Chandramohan     // Strides from the fir.box are in bytes.
1827fa517555SKiran Chandramohan     mlir::Type voidPtrTy = ::getVoidPtrType(rebox.getContext());
1828fa517555SKiran Chandramohan     base = rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, base);
1829fa517555SKiran Chandramohan 
1830fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> newStrides;
1831fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> newExtents;
1832fa517555SKiran Chandramohan     mlir::Type idxTy = lowerTy().indexType();
1833fa517555SKiran Chandramohan     // First stride from input box is kept. The rest is assumed contiguous
1834fa517555SKiran Chandramohan     // (it is not possible to reshape otherwise). If the input is scalar,
1835fa517555SKiran Chandramohan     // which may be OK if all new extents are ones, the stride does not
1836fa517555SKiran Chandramohan     // matter, use one.
1837fa517555SKiran Chandramohan     mlir::Value stride = inputStrides.empty()
1838fa517555SKiran Chandramohan                              ? genConstantIndex(loc, idxTy, rewriter, 1)
1839fa517555SKiran Chandramohan                              : inputStrides[0];
1840fa517555SKiran Chandramohan     for (unsigned i = 0; i < rebox.shape().size(); ++i) {
1841fa517555SKiran Chandramohan       mlir::Value rawExtent = operands[rebox.shapeOffset() + i];
1842fa517555SKiran Chandramohan       mlir::Value extent = integerCast(loc, rewriter, idxTy, rawExtent);
1843fa517555SKiran Chandramohan       newExtents.emplace_back(extent);
1844fa517555SKiran Chandramohan       newStrides.emplace_back(stride);
1845fa517555SKiran Chandramohan       // nextStride = extent * stride;
1846fa517555SKiran Chandramohan       stride = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, extent, stride);
1847fa517555SKiran Chandramohan     }
1848fa517555SKiran Chandramohan     return finalizeRebox(rebox, dest, base, reboxShifts, newExtents, newStrides,
1849fa517555SKiran Chandramohan                          rewriter);
1850fa517555SKiran Chandramohan   }
1851fa517555SKiran Chandramohan 
1852fa517555SKiran Chandramohan   /// Return scalar element type of the input box.
1853fa517555SKiran Chandramohan   static mlir::Type getInputEleTy(fir::cg::XReboxOp rebox) {
1854fa517555SKiran Chandramohan     auto ty = fir::dyn_cast_ptrOrBoxEleTy(rebox.box().getType());
1855fa517555SKiran Chandramohan     if (auto seqTy = ty.dyn_cast<fir::SequenceType>())
1856fa517555SKiran Chandramohan       return seqTy.getEleTy();
1857fa517555SKiran Chandramohan     return ty;
1858fa517555SKiran Chandramohan   }
1859fa517555SKiran Chandramohan };
1860fa517555SKiran Chandramohan 
1861dc48849fSKiran Chandramohan /// Lower `fir.emboxproc` operation. Creates a procedure box.
1862dc48849fSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
1863dc48849fSKiran Chandramohan struct EmboxProcOpConversion : public FIROpConversion<fir::EmboxProcOp> {
1864dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
1865dc48849fSKiran Chandramohan 
1866dc48849fSKiran Chandramohan   mlir::LogicalResult
1867dc48849fSKiran Chandramohan   matchAndRewrite(fir::EmboxProcOp emboxproc, OpAdaptor adaptor,
1868dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
1869dc48849fSKiran Chandramohan     TODO(emboxproc.getLoc(), "fir.emboxproc codegen");
187044e58509SEric Schweitz     return mlir::failure();
1871dc48849fSKiran Chandramohan   }
1872dc48849fSKiran Chandramohan };
1873dc48849fSKiran Chandramohan 
187454c56347SValentin Clement // Code shared between insert_value and extract_value Ops.
187554c56347SValentin Clement struct ValueOpCommon {
187654c56347SValentin Clement   // Translate the arguments pertaining to any multidimensional array to
187754c56347SValentin Clement   // row-major order for LLVM-IR.
187844e58509SEric Schweitz   static void toRowMajor(llvm::SmallVectorImpl<mlir::Attribute> &attrs,
187954c56347SValentin Clement                          mlir::Type ty) {
188054c56347SValentin Clement     assert(ty && "type is null");
188154c56347SValentin Clement     const auto end = attrs.size();
188254c56347SValentin Clement     for (std::remove_const_t<decltype(end)> i = 0; i < end; ++i) {
188354c56347SValentin Clement       if (auto seq = ty.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
188454c56347SValentin Clement         const auto dim = getDimension(seq);
188554c56347SValentin Clement         if (dim > 1) {
188654c56347SValentin Clement           auto ub = std::min(i + dim, end);
188754c56347SValentin Clement           std::reverse(attrs.begin() + i, attrs.begin() + ub);
188854c56347SValentin Clement           i += dim - 1;
188954c56347SValentin Clement         }
189054c56347SValentin Clement         ty = getArrayElementType(seq);
189154c56347SValentin Clement       } else if (auto st = ty.dyn_cast<mlir::LLVM::LLVMStructType>()) {
189254c56347SValentin Clement         ty = st.getBody()[attrs[i].cast<mlir::IntegerAttr>().getInt()];
189354c56347SValentin Clement       } else {
189454c56347SValentin Clement         llvm_unreachable("index into invalid type");
189554c56347SValentin Clement       }
189654c56347SValentin Clement     }
189754c56347SValentin Clement   }
189854c56347SValentin Clement 
189954c56347SValentin Clement   static llvm::SmallVector<mlir::Attribute>
190054c56347SValentin Clement   collectIndices(mlir::ConversionPatternRewriter &rewriter,
190154c56347SValentin Clement                  mlir::ArrayAttr arrAttr) {
190254c56347SValentin Clement     llvm::SmallVector<mlir::Attribute> attrs;
190354c56347SValentin Clement     for (auto i = arrAttr.begin(), e = arrAttr.end(); i != e; ++i) {
190454c56347SValentin Clement       if (i->isa<mlir::IntegerAttr>()) {
190554c56347SValentin Clement         attrs.push_back(*i);
190654c56347SValentin Clement       } else {
190754c56347SValentin Clement         auto fieldName = i->cast<mlir::StringAttr>().getValue();
190854c56347SValentin Clement         ++i;
190954c56347SValentin Clement         auto ty = i->cast<mlir::TypeAttr>().getValue();
191054c56347SValentin Clement         auto index = ty.cast<fir::RecordType>().getFieldIndex(fieldName);
191154c56347SValentin Clement         attrs.push_back(mlir::IntegerAttr::get(rewriter.getI32Type(), index));
191254c56347SValentin Clement       }
191354c56347SValentin Clement     }
191454c56347SValentin Clement     return attrs;
191554c56347SValentin Clement   }
191654c56347SValentin Clement 
191754c56347SValentin Clement private:
191854c56347SValentin Clement   static unsigned getDimension(mlir::LLVM::LLVMArrayType ty) {
191954c56347SValentin Clement     unsigned result = 1;
192054c56347SValentin Clement     for (auto eleTy = ty.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>();
192154c56347SValentin Clement          eleTy;
192254c56347SValentin Clement          eleTy = eleTy.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>())
192354c56347SValentin Clement       ++result;
192454c56347SValentin Clement     return result;
192554c56347SValentin Clement   }
192654c56347SValentin Clement 
192754c56347SValentin Clement   static mlir::Type getArrayElementType(mlir::LLVM::LLVMArrayType ty) {
192854c56347SValentin Clement     auto eleTy = ty.getElementType();
192954c56347SValentin Clement     while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>())
193054c56347SValentin Clement       eleTy = arrTy.getElementType();
193154c56347SValentin Clement     return eleTy;
193254c56347SValentin Clement   }
193354c56347SValentin Clement };
193454c56347SValentin Clement 
1935c2acd453SAlexisPerry namespace {
193654c56347SValentin Clement /// Extract a subobject value from an ssa-value of aggregate type
193754c56347SValentin Clement struct ExtractValueOpConversion
193854c56347SValentin Clement     : public FIROpAndTypeConversion<fir::ExtractValueOp>,
193954c56347SValentin Clement       public ValueOpCommon {
194054c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
194154c56347SValentin Clement 
194254c56347SValentin Clement   mlir::LogicalResult
194354c56347SValentin Clement   doRewrite(fir::ExtractValueOp extractVal, mlir::Type ty, OpAdaptor adaptor,
194454c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
1945149ad3d5SShraiysh Vaishay     auto attrs = collectIndices(rewriter, extractVal.getCoor());
194654c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
194754c56347SValentin Clement     auto position = mlir::ArrayAttr::get(extractVal.getContext(), attrs);
194854c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(
194954c56347SValentin Clement         extractVal, ty, adaptor.getOperands()[0], position);
195044e58509SEric Schweitz     return mlir::success();
195154c56347SValentin Clement   }
195254c56347SValentin Clement };
195354c56347SValentin Clement 
195454c56347SValentin Clement /// InsertValue is the generalized instruction for the composition of new
195554c56347SValentin Clement /// aggregate type values.
195654c56347SValentin Clement struct InsertValueOpConversion
195754c56347SValentin Clement     : public FIROpAndTypeConversion<fir::InsertValueOp>,
195854c56347SValentin Clement       public ValueOpCommon {
195954c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
196054c56347SValentin Clement 
196154c56347SValentin Clement   mlir::LogicalResult
196254c56347SValentin Clement   doRewrite(fir::InsertValueOp insertVal, mlir::Type ty, OpAdaptor adaptor,
196354c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
1964149ad3d5SShraiysh Vaishay     auto attrs = collectIndices(rewriter, insertVal.getCoor());
196554c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
196654c56347SValentin Clement     auto position = mlir::ArrayAttr::get(insertVal.getContext(), attrs);
196754c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
196854c56347SValentin Clement         insertVal, ty, adaptor.getOperands()[0], adaptor.getOperands()[1],
196954c56347SValentin Clement         position);
197044e58509SEric Schweitz     return mlir::success();
197154c56347SValentin Clement   }
197254c56347SValentin Clement };
197354c56347SValentin Clement 
19743ae8e442SValentin Clement /// InsertOnRange inserts a value into a sequence over a range of offsets.
19753ae8e442SValentin Clement struct InsertOnRangeOpConversion
19763ae8e442SValentin Clement     : public FIROpAndTypeConversion<fir::InsertOnRangeOp> {
19773ae8e442SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
19783ae8e442SValentin Clement 
19793ae8e442SValentin Clement   // Increments an array of subscripts in a row major fasion.
198044e58509SEric Schweitz   void incrementSubscripts(const llvm::SmallVector<uint64_t> &dims,
198144e58509SEric Schweitz                            llvm::SmallVector<uint64_t> &subscripts) const {
19823ae8e442SValentin Clement     for (size_t i = dims.size(); i > 0; --i) {
19833ae8e442SValentin Clement       if (++subscripts[i - 1] < dims[i - 1]) {
19843ae8e442SValentin Clement         return;
19853ae8e442SValentin Clement       }
19863ae8e442SValentin Clement       subscripts[i - 1] = 0;
19873ae8e442SValentin Clement     }
19883ae8e442SValentin Clement   }
19893ae8e442SValentin Clement 
19903ae8e442SValentin Clement   mlir::LogicalResult
19913ae8e442SValentin Clement   doRewrite(fir::InsertOnRangeOp range, mlir::Type ty, OpAdaptor adaptor,
19923ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
19933ae8e442SValentin Clement 
19943ae8e442SValentin Clement     llvm::SmallVector<uint64_t> dims;
19953ae8e442SValentin Clement     auto type = adaptor.getOperands()[0].getType();
19963ae8e442SValentin Clement 
19973ae8e442SValentin Clement     // Iteratively extract the array dimensions from the type.
19983ae8e442SValentin Clement     while (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
19993ae8e442SValentin Clement       dims.push_back(t.getNumElements());
20003ae8e442SValentin Clement       type = t.getElementType();
20013ae8e442SValentin Clement     }
20023ae8e442SValentin Clement 
200344e58509SEric Schweitz     llvm::SmallVector<uint64_t> lBounds;
200444e58509SEric Schweitz     llvm::SmallVector<uint64_t> uBounds;
20053ae8e442SValentin Clement 
20063ae8e442SValentin Clement     // Unzip the upper and lower bound and convert to a row major format.
2007149ad3d5SShraiysh Vaishay     mlir::DenseIntElementsAttr coor = range.getCoor();
20088ec0f221SMehdi Amini     auto reversedCoor = llvm::reverse(coor.getValues<int64_t>());
20098ec0f221SMehdi Amini     for (auto i = reversedCoor.begin(), e = reversedCoor.end(); i != e; ++i) {
20103ae8e442SValentin Clement       uBounds.push_back(*i++);
20113ae8e442SValentin Clement       lBounds.push_back(*i);
20123ae8e442SValentin Clement     }
20133ae8e442SValentin Clement 
20143ae8e442SValentin Clement     auto &subscripts = lBounds;
20153ae8e442SValentin Clement     auto loc = range.getLoc();
20163ae8e442SValentin Clement     mlir::Value lastOp = adaptor.getOperands()[0];
20173ae8e442SValentin Clement     mlir::Value insertVal = adaptor.getOperands()[1];
20183ae8e442SValentin Clement 
20193ae8e442SValentin Clement     auto i64Ty = rewriter.getI64Type();
20203ae8e442SValentin Clement     while (subscripts != uBounds) {
20213ae8e442SValentin Clement       // Convert uint64_t's to Attribute's.
202244e58509SEric Schweitz       llvm::SmallVector<mlir::Attribute> subscriptAttrs;
20233ae8e442SValentin Clement       for (const auto &subscript : subscripts)
202444e58509SEric Schweitz         subscriptAttrs.push_back(mlir::IntegerAttr::get(i64Ty, subscript));
20253ae8e442SValentin Clement       lastOp = rewriter.create<mlir::LLVM::InsertValueOp>(
20263ae8e442SValentin Clement           loc, ty, lastOp, insertVal,
202744e58509SEric Schweitz           mlir::ArrayAttr::get(range.getContext(), subscriptAttrs));
20283ae8e442SValentin Clement 
20293ae8e442SValentin Clement       incrementSubscripts(dims, subscripts);
20303ae8e442SValentin Clement     }
20313ae8e442SValentin Clement 
20323ae8e442SValentin Clement     // Convert uint64_t's to Attribute's.
203344e58509SEric Schweitz     llvm::SmallVector<mlir::Attribute> subscriptAttrs;
20343ae8e442SValentin Clement     for (const auto &subscript : subscripts)
20353ae8e442SValentin Clement       subscriptAttrs.push_back(
203644e58509SEric Schweitz           mlir::IntegerAttr::get(rewriter.getI64Type(), subscript));
20373ae8e442SValentin Clement     mlir::ArrayRef<mlir::Attribute> arrayRef(subscriptAttrs);
20383ae8e442SValentin Clement 
20393ae8e442SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
20403ae8e442SValentin Clement         range, ty, lastOp, insertVal,
204144e58509SEric Schweitz         mlir::ArrayAttr::get(range.getContext(), arrayRef));
20423ae8e442SValentin Clement 
204344e58509SEric Schweitz     return mlir::success();
20443ae8e442SValentin Clement   }
20453ae8e442SValentin Clement };
2046c2acd453SAlexisPerry } // namespace
20477b5132daSValentin Clement 
2048dc48849fSKiran Chandramohan namespace {
20495d27abe6SValentin Clement /// XArrayCoor is the address arithmetic on a dynamically shaped, sliced,
20505d27abe6SValentin Clement /// shifted etc. array.
20515d27abe6SValentin Clement /// (See the static restriction on coordinate_of.) array_coor determines the
20525d27abe6SValentin Clement /// coordinate (location) of a specific element.
20535d27abe6SValentin Clement struct XArrayCoorOpConversion
20545d27abe6SValentin Clement     : public FIROpAndTypeConversion<fir::cg::XArrayCoorOp> {
20555d27abe6SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
20565d27abe6SValentin Clement 
20575d27abe6SValentin Clement   mlir::LogicalResult
20585d27abe6SValentin Clement   doRewrite(fir::cg::XArrayCoorOp coor, mlir::Type ty, OpAdaptor adaptor,
20595d27abe6SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
20605d27abe6SValentin Clement     auto loc = coor.getLoc();
20615d27abe6SValentin Clement     mlir::ValueRange operands = adaptor.getOperands();
20625d27abe6SValentin Clement     unsigned rank = coor.getRank();
20635d27abe6SValentin Clement     assert(coor.indices().size() == rank);
20645d27abe6SValentin Clement     assert(coor.shape().empty() || coor.shape().size() == rank);
20655d27abe6SValentin Clement     assert(coor.shift().empty() || coor.shift().size() == rank);
20665d27abe6SValentin Clement     assert(coor.slice().empty() || coor.slice().size() == 3 * rank);
20675d27abe6SValentin Clement     mlir::Type idxTy = lowerTy().indexType();
20685d27abe6SValentin Clement     mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1);
20695d27abe6SValentin Clement     mlir::Value prevExt = one;
20705d27abe6SValentin Clement     mlir::Value zero = genConstantIndex(loc, idxTy, rewriter, 0);
20715d27abe6SValentin Clement     mlir::Value offset = zero;
20725d27abe6SValentin Clement     const bool isShifted = !coor.shift().empty();
20735d27abe6SValentin Clement     const bool isSliced = !coor.slice().empty();
20745d27abe6SValentin Clement     const bool baseIsBoxed = coor.memref().getType().isa<fir::BoxType>();
20755d27abe6SValentin Clement 
20765d27abe6SValentin Clement     auto indexOps = coor.indices().begin();
20775d27abe6SValentin Clement     auto shapeOps = coor.shape().begin();
20785d27abe6SValentin Clement     auto shiftOps = coor.shift().begin();
20795d27abe6SValentin Clement     auto sliceOps = coor.slice().begin();
20805d27abe6SValentin Clement     // For each dimension of the array, generate the offset calculation.
20815d27abe6SValentin Clement     for (unsigned i = 0; i < rank;
20825d27abe6SValentin Clement          ++i, ++indexOps, ++shapeOps, ++shiftOps, sliceOps += 3) {
20835d27abe6SValentin Clement       mlir::Value index =
20845d27abe6SValentin Clement           integerCast(loc, rewriter, idxTy, operands[coor.indicesOffset() + i]);
20855d27abe6SValentin Clement       mlir::Value lb = isShifted ? integerCast(loc, rewriter, idxTy,
20865d27abe6SValentin Clement                                                operands[coor.shiftOffset() + i])
20875d27abe6SValentin Clement                                  : one;
20885d27abe6SValentin Clement       mlir::Value step = one;
20895d27abe6SValentin Clement       bool normalSlice = isSliced;
20905d27abe6SValentin Clement       // Compute zero based index in dimension i of the element, applying
20915d27abe6SValentin Clement       // potential triplets and lower bounds.
20925d27abe6SValentin Clement       if (isSliced) {
20935d27abe6SValentin Clement         mlir::Value ub = *(sliceOps + 1);
20945d27abe6SValentin Clement         normalSlice = !mlir::isa_and_nonnull<fir::UndefOp>(ub.getDefiningOp());
20955d27abe6SValentin Clement         if (normalSlice)
20965d27abe6SValentin Clement           step = integerCast(loc, rewriter, idxTy, *(sliceOps + 2));
20975d27abe6SValentin Clement       }
20985d27abe6SValentin Clement       auto idx = rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, index, lb);
20995d27abe6SValentin Clement       mlir::Value diff =
21005d27abe6SValentin Clement           rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, idx, step);
21015d27abe6SValentin Clement       if (normalSlice) {
21025d27abe6SValentin Clement         mlir::Value sliceLb =
21035d27abe6SValentin Clement             integerCast(loc, rewriter, idxTy, operands[coor.sliceOffset() + i]);
21045d27abe6SValentin Clement         auto adj = rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, sliceLb, lb);
21055d27abe6SValentin Clement         diff = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, diff, adj);
21065d27abe6SValentin Clement       }
21075d27abe6SValentin Clement       // Update the offset given the stride and the zero based index `diff`
21085d27abe6SValentin Clement       // that was just computed.
21095d27abe6SValentin Clement       if (baseIsBoxed) {
21105d27abe6SValentin Clement         // Use stride in bytes from the descriptor.
21115d27abe6SValentin Clement         mlir::Value stride =
21125d27abe6SValentin Clement             loadStrideFromBox(loc, adaptor.getOperands()[0], i, rewriter);
21135d27abe6SValentin Clement         auto sc = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, stride);
21145d27abe6SValentin Clement         offset = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, offset);
21155d27abe6SValentin Clement       } else {
21165d27abe6SValentin Clement         // Use stride computed at last iteration.
21175d27abe6SValentin Clement         auto sc = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, prevExt);
21185d27abe6SValentin Clement         offset = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, offset);
21195d27abe6SValentin Clement         // Compute next stride assuming contiguity of the base array
21205d27abe6SValentin Clement         // (in element number).
21215d27abe6SValentin Clement         auto nextExt =
21225d27abe6SValentin Clement             integerCast(loc, rewriter, idxTy, operands[coor.shapeOffset() + i]);
21235d27abe6SValentin Clement         prevExt =
21245d27abe6SValentin Clement             rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, prevExt, nextExt);
21255d27abe6SValentin Clement       }
21265d27abe6SValentin Clement     }
21275d27abe6SValentin Clement 
21285d27abe6SValentin Clement     // Add computed offset to the base address.
21295d27abe6SValentin Clement     if (baseIsBoxed) {
21305d27abe6SValentin Clement       // Working with byte offsets. The base address is read from the fir.box.
21315d27abe6SValentin Clement       // and need to be casted to i8* to do the pointer arithmetic.
21325d27abe6SValentin Clement       mlir::Type baseTy =
21335d27abe6SValentin Clement           getBaseAddrTypeFromBox(adaptor.getOperands()[0].getType());
21345d27abe6SValentin Clement       mlir::Value base =
21355d27abe6SValentin Clement           loadBaseAddrFromBox(loc, baseTy, adaptor.getOperands()[0], rewriter);
21365d27abe6SValentin Clement       mlir::Type voidPtrTy = getVoidPtrType();
21375d27abe6SValentin Clement       base = rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, base);
213830122656SAlex Zinenko       llvm::SmallVector<mlir::Value> args{offset};
213930122656SAlex Zinenko       auto addr =
214030122656SAlex Zinenko           rewriter.create<mlir::LLVM::GEPOp>(loc, voidPtrTy, base, args);
21415d27abe6SValentin Clement       if (coor.subcomponent().empty()) {
21425d27abe6SValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(coor, baseTy, addr);
214344e58509SEric Schweitz         return mlir::success();
21445d27abe6SValentin Clement       }
21455d27abe6SValentin Clement       auto casted = rewriter.create<mlir::LLVM::BitcastOp>(loc, baseTy, addr);
21465d27abe6SValentin Clement       args.clear();
21475d27abe6SValentin Clement       args.push_back(zero);
21485d27abe6SValentin Clement       if (!coor.lenParams().empty()) {
21495d27abe6SValentin Clement         // If type parameters are present, then we don't want to use a GEPOp
21505d27abe6SValentin Clement         // as below, as the LLVM struct type cannot be statically defined.
21515d27abe6SValentin Clement         TODO(loc, "derived type with type parameters");
21525d27abe6SValentin Clement       }
21535d27abe6SValentin Clement       // TODO: array offset subcomponents must be converted to LLVM's
21545d27abe6SValentin Clement       // row-major layout here.
21555d27abe6SValentin Clement       for (auto i = coor.subcomponentOffset(); i != coor.indicesOffset(); ++i)
21565d27abe6SValentin Clement         args.push_back(operands[i]);
215730122656SAlex Zinenko       rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(coor, baseTy, casted,
215830122656SAlex Zinenko                                                      args);
215944e58509SEric Schweitz       return mlir::success();
21605d27abe6SValentin Clement     }
21615d27abe6SValentin Clement 
21625d27abe6SValentin Clement     // The array was not boxed, so it must be contiguous. offset is therefore an
21635d27abe6SValentin Clement     // element offset and the base type is kept in the GEP unless the element
21645d27abe6SValentin Clement     // type size is itself dynamic.
21655d27abe6SValentin Clement     mlir::Value base;
21665d27abe6SValentin Clement     if (coor.subcomponent().empty()) {
21675d27abe6SValentin Clement       // No subcomponent.
21685d27abe6SValentin Clement       if (!coor.lenParams().empty()) {
21695d27abe6SValentin Clement         // Type parameters. Adjust element size explicitly.
21705d27abe6SValentin Clement         auto eleTy = fir::dyn_cast_ptrEleTy(coor.getType());
21715d27abe6SValentin Clement         assert(eleTy && "result must be a reference-like type");
21725d27abe6SValentin Clement         if (fir::characterWithDynamicLen(eleTy)) {
21735d27abe6SValentin Clement           assert(coor.lenParams().size() == 1);
21745d27abe6SValentin Clement           auto bitsInChar = lowerTy().getKindMap().getCharacterBitsize(
21755d27abe6SValentin Clement               eleTy.cast<fir::CharacterType>().getFKind());
21765d27abe6SValentin Clement           auto scaling = genConstantIndex(loc, idxTy, rewriter, bitsInChar / 8);
21775d27abe6SValentin Clement           auto scaledBySize =
21785d27abe6SValentin Clement               rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, offset, scaling);
21795d27abe6SValentin Clement           auto length =
21805d27abe6SValentin Clement               integerCast(loc, rewriter, idxTy,
21815d27abe6SValentin Clement                           adaptor.getOperands()[coor.lenParamsOffset()]);
21825d27abe6SValentin Clement           offset = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, scaledBySize,
21835d27abe6SValentin Clement                                                       length);
21845d27abe6SValentin Clement         } else {
21855d27abe6SValentin Clement           TODO(loc, "compute size of derived type with type parameters");
21865d27abe6SValentin Clement         }
21875d27abe6SValentin Clement       }
21885d27abe6SValentin Clement       // Cast the base address to a pointer to T.
21895d27abe6SValentin Clement       base = rewriter.create<mlir::LLVM::BitcastOp>(loc, ty,
21905d27abe6SValentin Clement                                                     adaptor.getOperands()[0]);
21915d27abe6SValentin Clement     } else {
21925d27abe6SValentin Clement       // Operand #0 must have a pointer type. For subcomponent slicing, we
21935d27abe6SValentin Clement       // want to cast away the array type and have a plain struct type.
21945d27abe6SValentin Clement       mlir::Type ty0 = adaptor.getOperands()[0].getType();
21955d27abe6SValentin Clement       auto ptrTy = ty0.dyn_cast<mlir::LLVM::LLVMPointerType>();
21965d27abe6SValentin Clement       assert(ptrTy && "expected pointer type");
21975d27abe6SValentin Clement       mlir::Type eleTy = ptrTy.getElementType();
21985d27abe6SValentin Clement       while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>())
21995d27abe6SValentin Clement         eleTy = arrTy.getElementType();
22005d27abe6SValentin Clement       auto newTy = mlir::LLVM::LLVMPointerType::get(eleTy);
22015d27abe6SValentin Clement       base = rewriter.create<mlir::LLVM::BitcastOp>(loc, newTy,
22025d27abe6SValentin Clement                                                     adaptor.getOperands()[0]);
22035d27abe6SValentin Clement     }
220444e58509SEric Schweitz     llvm::SmallVector<mlir::Value> args = {offset};
22055d27abe6SValentin Clement     for (auto i = coor.subcomponentOffset(); i != coor.indicesOffset(); ++i)
22065d27abe6SValentin Clement       args.push_back(operands[i]);
220730122656SAlex Zinenko     rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(coor, ty, base, args);
220844e58509SEric Schweitz     return mlir::success();
22095d27abe6SValentin Clement   }
22105d27abe6SValentin Clement };
2211dc48849fSKiran Chandramohan } // namespace
2212dc48849fSKiran Chandramohan 
2213dc48849fSKiran Chandramohan /// Convert to (memory) reference to a reference to a subobject.
2214dc48849fSKiran Chandramohan /// The coordinate_of op is a Swiss army knife operation that can be used on
2215dc48849fSKiran Chandramohan /// (memory) references to records, arrays, complex, etc. as well as boxes.
2216dc48849fSKiran Chandramohan /// With unboxed arrays, there is the restriction that the array have a static
2217dc48849fSKiran Chandramohan /// shape in all but the last column.
2218dc48849fSKiran Chandramohan struct CoordinateOpConversion
2219dc48849fSKiran Chandramohan     : public FIROpAndTypeConversion<fir::CoordinateOp> {
2220dc48849fSKiran Chandramohan   using FIROpAndTypeConversion::FIROpAndTypeConversion;
2221dc48849fSKiran Chandramohan 
2222dc48849fSKiran Chandramohan   mlir::LogicalResult
2223dc48849fSKiran Chandramohan   doRewrite(fir::CoordinateOp coor, mlir::Type ty, OpAdaptor adaptor,
2224dc48849fSKiran Chandramohan             mlir::ConversionPatternRewriter &rewriter) const override {
2225dc48849fSKiran Chandramohan     mlir::ValueRange operands = adaptor.getOperands();
2226dc48849fSKiran Chandramohan 
2227dc48849fSKiran Chandramohan     mlir::Location loc = coor.getLoc();
2228dc48849fSKiran Chandramohan     mlir::Value base = operands[0];
2229dc48849fSKiran Chandramohan     mlir::Type baseObjectTy = coor.getBaseType();
2230dc48849fSKiran Chandramohan     mlir::Type objectTy = fir::dyn_cast_ptrOrBoxEleTy(baseObjectTy);
2231dc48849fSKiran Chandramohan     assert(objectTy && "fir.coordinate_of expects a reference type");
2232dc48849fSKiran Chandramohan 
2233dc48849fSKiran Chandramohan     // Complex type - basically, extract the real or imaginary part
2234dc48849fSKiran Chandramohan     if (fir::isa_complex(objectTy)) {
2235dc48849fSKiran Chandramohan       mlir::LLVM::ConstantOp c0 =
2236dc48849fSKiran Chandramohan           genConstantIndex(loc, lowerTy().indexType(), rewriter, 0);
223703efa5a3SAndrzej Warzynski       llvm::SmallVector<mlir::Value> offs = {c0, operands[1]};
2238dc48849fSKiran Chandramohan       mlir::Value gep = genGEP(loc, ty, rewriter, base, offs);
2239dc48849fSKiran Chandramohan       rewriter.replaceOp(coor, gep);
224044e58509SEric Schweitz       return mlir::success();
2241dc48849fSKiran Chandramohan     }
2242dc48849fSKiran Chandramohan 
2243dc48849fSKiran Chandramohan     // Boxed type - get the base pointer from the box
2244dc48849fSKiran Chandramohan     if (baseObjectTy.dyn_cast<fir::BoxType>())
2245dc48849fSKiran Chandramohan       return doRewriteBox(coor, ty, operands, loc, rewriter);
2246dc48849fSKiran Chandramohan 
224703efa5a3SAndrzej Warzynski     // Reference, pointer or a heap type
224803efa5a3SAndrzej Warzynski     if (baseObjectTy.isa<fir::ReferenceType, fir::PointerType, fir::HeapType>())
2249dc48849fSKiran Chandramohan       return doRewriteRefOrPtr(coor, ty, operands, loc, rewriter);
2250dc48849fSKiran Chandramohan 
2251dc48849fSKiran Chandramohan     return rewriter.notifyMatchFailure(
2252dc48849fSKiran Chandramohan         coor, "fir.coordinate_of base operand has unsupported type");
2253dc48849fSKiran Chandramohan   }
2254dc48849fSKiran Chandramohan 
225503efa5a3SAndrzej Warzynski   static unsigned getFieldNumber(fir::RecordType ty, mlir::Value op) {
2256dc48849fSKiran Chandramohan     return fir::hasDynamicSize(ty)
2257dc48849fSKiran Chandramohan                ? op.getDefiningOp()
2258dc48849fSKiran Chandramohan                      ->getAttrOfType<mlir::IntegerAttr>("field")
2259dc48849fSKiran Chandramohan                      .getInt()
2260dc48849fSKiran Chandramohan                : getIntValue(op);
2261dc48849fSKiran Chandramohan   }
2262dc48849fSKiran Chandramohan 
226303efa5a3SAndrzej Warzynski   static int64_t getIntValue(mlir::Value val) {
2264dc48849fSKiran Chandramohan     assert(val && val.dyn_cast<mlir::OpResult>() && "must not be null value");
2265dc48849fSKiran Chandramohan     mlir::Operation *defop = val.getDefiningOp();
2266dc48849fSKiran Chandramohan 
226744e58509SEric Schweitz     if (auto constOp = mlir::dyn_cast<mlir::arith::ConstantIntOp>(defop))
2268dc48849fSKiran Chandramohan       return constOp.value();
226944e58509SEric Schweitz     if (auto llConstOp = mlir::dyn_cast<mlir::LLVM::ConstantOp>(defop))
2270dc48849fSKiran Chandramohan       if (auto attr = llConstOp.getValue().dyn_cast<mlir::IntegerAttr>())
2271dc48849fSKiran Chandramohan         return attr.getValue().getSExtValue();
2272dc48849fSKiran Chandramohan     fir::emitFatalError(val.getLoc(), "must be a constant");
2273dc48849fSKiran Chandramohan   }
2274dc48849fSKiran Chandramohan 
227503efa5a3SAndrzej Warzynski   static bool hasSubDimensions(mlir::Type type) {
2276dc48849fSKiran Chandramohan     return type.isa<fir::SequenceType, fir::RecordType, mlir::TupleType>();
2277dc48849fSKiran Chandramohan   }
2278dc48849fSKiran Chandramohan 
2279dc48849fSKiran Chandramohan   /// Check whether this form of `!fir.coordinate_of` is supported. These
2280dc48849fSKiran Chandramohan   /// additional checks are required, because we are not yet able to convert
2281dc48849fSKiran Chandramohan   /// all valid forms of `!fir.coordinate_of`.
2282dc48849fSKiran Chandramohan   /// TODO: Either implement the unsupported cases or extend the verifier
2283dc48849fSKiran Chandramohan   /// in FIROps.cpp instead.
228403efa5a3SAndrzej Warzynski   static bool supportedCoordinate(mlir::Type type, mlir::ValueRange coors) {
2285dc48849fSKiran Chandramohan     const std::size_t numOfCoors = coors.size();
2286dc48849fSKiran Chandramohan     std::size_t i = 0;
2287dc48849fSKiran Chandramohan     bool subEle = false;
2288dc48849fSKiran Chandramohan     bool ptrEle = false;
2289dc48849fSKiran Chandramohan     for (; i < numOfCoors; ++i) {
2290dc48849fSKiran Chandramohan       mlir::Value nxtOpnd = coors[i];
2291dc48849fSKiran Chandramohan       if (auto arrTy = type.dyn_cast<fir::SequenceType>()) {
2292dc48849fSKiran Chandramohan         subEle = true;
2293dc48849fSKiran Chandramohan         i += arrTy.getDimension() - 1;
2294dc48849fSKiran Chandramohan         type = arrTy.getEleTy();
2295dc48849fSKiran Chandramohan       } else if (auto recTy = type.dyn_cast<fir::RecordType>()) {
2296dc48849fSKiran Chandramohan         subEle = true;
2297dc48849fSKiran Chandramohan         type = recTy.getType(getFieldNumber(recTy, nxtOpnd));
2298dc48849fSKiran Chandramohan       } else if (auto tupTy = type.dyn_cast<mlir::TupleType>()) {
2299dc48849fSKiran Chandramohan         subEle = true;
2300dc48849fSKiran Chandramohan         type = tupTy.getType(getIntValue(nxtOpnd));
2301dc48849fSKiran Chandramohan       } else {
2302dc48849fSKiran Chandramohan         ptrEle = true;
2303dc48849fSKiran Chandramohan       }
2304dc48849fSKiran Chandramohan     }
2305dc48849fSKiran Chandramohan     if (ptrEle)
2306dc48849fSKiran Chandramohan       return (!subEle) && (numOfCoors == 1);
2307dc48849fSKiran Chandramohan     return subEle && (i >= numOfCoors);
2308dc48849fSKiran Chandramohan   }
2309dc48849fSKiran Chandramohan 
2310dc48849fSKiran Chandramohan   /// Walk the abstract memory layout and determine if the path traverses any
2311dc48849fSKiran Chandramohan   /// array types with unknown shape. Return true iff all the array types have a
2312dc48849fSKiran Chandramohan   /// constant shape along the path.
231303efa5a3SAndrzej Warzynski   static bool arraysHaveKnownShape(mlir::Type type, mlir::ValueRange coors) {
231403efa5a3SAndrzej Warzynski     for (std::size_t i = 0, sz = coors.size(); i < sz; ++i) {
2315dc48849fSKiran Chandramohan       mlir::Value nxtOpnd = coors[i];
2316dc48849fSKiran Chandramohan       if (auto arrTy = type.dyn_cast<fir::SequenceType>()) {
2317dc48849fSKiran Chandramohan         if (fir::sequenceWithNonConstantShape(arrTy))
2318dc48849fSKiran Chandramohan           return false;
2319dc48849fSKiran Chandramohan         i += arrTy.getDimension() - 1;
2320dc48849fSKiran Chandramohan         type = arrTy.getEleTy();
2321dc48849fSKiran Chandramohan       } else if (auto strTy = type.dyn_cast<fir::RecordType>()) {
2322dc48849fSKiran Chandramohan         type = strTy.getType(getFieldNumber(strTy, nxtOpnd));
2323dc48849fSKiran Chandramohan       } else if (auto strTy = type.dyn_cast<mlir::TupleType>()) {
2324dc48849fSKiran Chandramohan         type = strTy.getType(getIntValue(nxtOpnd));
2325dc48849fSKiran Chandramohan       } else {
2326dc48849fSKiran Chandramohan         return true;
2327dc48849fSKiran Chandramohan       }
2328dc48849fSKiran Chandramohan     }
2329dc48849fSKiran Chandramohan     return true;
2330dc48849fSKiran Chandramohan   }
2331dc48849fSKiran Chandramohan 
2332dc48849fSKiran Chandramohan private:
2333dc48849fSKiran Chandramohan   mlir::LogicalResult
2334dc48849fSKiran Chandramohan   doRewriteBox(fir::CoordinateOp coor, mlir::Type ty, mlir::ValueRange operands,
2335dc48849fSKiran Chandramohan                mlir::Location loc,
2336dc48849fSKiran Chandramohan                mlir::ConversionPatternRewriter &rewriter) const {
2337dc48849fSKiran Chandramohan     mlir::Type boxObjTy = coor.getBaseType();
2338dc48849fSKiran Chandramohan     assert(boxObjTy.dyn_cast<fir::BoxType>() && "This is not a `fir.box`");
2339dc48849fSKiran Chandramohan 
2340dc48849fSKiran Chandramohan     mlir::Value boxBaseAddr = operands[0];
2341dc48849fSKiran Chandramohan 
2342dc48849fSKiran Chandramohan     // 1. SPECIAL CASE (uses `fir.len_param_index`):
2343dc48849fSKiran Chandramohan     //   %box = ... : !fir.box<!fir.type<derived{len1:i32}>>
2344dc48849fSKiran Chandramohan     //   %lenp = fir.len_param_index len1, !fir.type<derived{len1:i32}>
2345dc48849fSKiran Chandramohan     //   %addr = coordinate_of %box, %lenp
2346dc48849fSKiran Chandramohan     if (coor.getNumOperands() == 2) {
2347dc48849fSKiran Chandramohan       mlir::Operation *coordinateDef =
2348dc48849fSKiran Chandramohan           (*coor.getCoor().begin()).getDefiningOp();
234944e58509SEric Schweitz       if (mlir::isa_and_nonnull<fir::LenParamIndexOp>(coordinateDef))
2350dc48849fSKiran Chandramohan         TODO(loc,
2351dc48849fSKiran Chandramohan              "fir.coordinate_of - fir.len_param_index is not supported yet");
2352dc48849fSKiran Chandramohan     }
2353dc48849fSKiran Chandramohan 
2354dc48849fSKiran Chandramohan     // 2. GENERAL CASE:
2355dc48849fSKiran Chandramohan     // 2.1. (`fir.array`)
2356dc48849fSKiran Chandramohan     //   %box = ... : !fix.box<!fir.array<?xU>>
2357dc48849fSKiran Chandramohan     //   %idx = ... : index
2358dc48849fSKiran Chandramohan     //   %resultAddr = coordinate_of %box, %idx : !fir.ref<U>
2359dc48849fSKiran Chandramohan     // 2.2 (`fir.derived`)
2360dc48849fSKiran Chandramohan     //   %box = ... : !fix.box<!fir.type<derived_type{field_1:i32}>>
2361dc48849fSKiran Chandramohan     //   %idx = ... : i32
2362dc48849fSKiran Chandramohan     //   %resultAddr = coordinate_of %box, %idx : !fir.ref<i32>
2363dc48849fSKiran Chandramohan     // 2.3 (`fir.derived` inside `fir.array`)
2364dc48849fSKiran Chandramohan     //   %box = ... : !fir.box<!fir.array<10 x !fir.type<derived_1{field_1:f32,
2365dc48849fSKiran Chandramohan     //   field_2:f32}>>> %idx1 = ... : index %idx2 = ... : i32 %resultAddr =
2366dc48849fSKiran Chandramohan     //   coordinate_of %box, %idx1, %idx2 : !fir.ref<f32>
2367dc48849fSKiran Chandramohan     // 2.4. TODO: Either document or disable any other case that the following
2368dc48849fSKiran Chandramohan     //  implementation might convert.
2369dc48849fSKiran Chandramohan     mlir::LLVM::ConstantOp c0 =
2370dc48849fSKiran Chandramohan         genConstantIndex(loc, lowerTy().indexType(), rewriter, 0);
2371dc48849fSKiran Chandramohan     mlir::Value resultAddr =
2372dc48849fSKiran Chandramohan         loadBaseAddrFromBox(loc, getBaseAddrTypeFromBox(boxBaseAddr.getType()),
2373dc48849fSKiran Chandramohan                             boxBaseAddr, rewriter);
237403efa5a3SAndrzej Warzynski     // Component Type
237503efa5a3SAndrzej Warzynski     auto cpnTy = fir::dyn_cast_ptrOrBoxEleTy(boxObjTy);
2376dc48849fSKiran Chandramohan     mlir::Type voidPtrTy = ::getVoidPtrType(coor.getContext());
2377dc48849fSKiran Chandramohan 
2378dc48849fSKiran Chandramohan     for (unsigned i = 1, last = operands.size(); i < last; ++i) {
237903efa5a3SAndrzej Warzynski       if (auto arrTy = cpnTy.dyn_cast<fir::SequenceType>()) {
2380dc48849fSKiran Chandramohan         if (i != 1)
2381dc48849fSKiran Chandramohan           TODO(loc, "fir.array nested inside other array and/or derived type");
2382dc48849fSKiran Chandramohan         // Applies byte strides from the box. Ignore lower bound from box
2383dc48849fSKiran Chandramohan         // since fir.coordinate_of indexes are zero based. Lowering takes care
2384dc48849fSKiran Chandramohan         // of lower bound aspects. This both accounts for dynamically sized
2385dc48849fSKiran Chandramohan         // types and non contiguous arrays.
2386dc48849fSKiran Chandramohan         auto idxTy = lowerTy().indexType();
2387dc48849fSKiran Chandramohan         mlir::Value off = genConstantIndex(loc, idxTy, rewriter, 0);
2388dc48849fSKiran Chandramohan         for (unsigned index = i, lastIndex = i + arrTy.getDimension();
2389dc48849fSKiran Chandramohan              index < lastIndex; ++index) {
2390dc48849fSKiran Chandramohan           mlir::Value stride =
2391dc48849fSKiran Chandramohan               loadStrideFromBox(loc, operands[0], index - i, rewriter);
2392dc48849fSKiran Chandramohan           auto sc = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy,
2393dc48849fSKiran Chandramohan                                                        operands[index], stride);
2394dc48849fSKiran Chandramohan           off = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, off);
2395dc48849fSKiran Chandramohan         }
2396dc48849fSKiran Chandramohan         auto voidPtrBase =
2397dc48849fSKiran Chandramohan             rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, resultAddr);
239844e58509SEric Schweitz         llvm::SmallVector<mlir::Value> args{off};
2399dc48849fSKiran Chandramohan         resultAddr = rewriter.create<mlir::LLVM::GEPOp>(loc, voidPtrTy,
2400dc48849fSKiran Chandramohan                                                         voidPtrBase, args);
2401dc48849fSKiran Chandramohan         i += arrTy.getDimension() - 1;
240203efa5a3SAndrzej Warzynski         cpnTy = arrTy.getEleTy();
240303efa5a3SAndrzej Warzynski       } else if (auto recTy = cpnTy.dyn_cast<fir::RecordType>()) {
2404dc48849fSKiran Chandramohan         auto recRefTy =
2405dc48849fSKiran Chandramohan             mlir::LLVM::LLVMPointerType::get(lowerTy().convertType(recTy));
2406dc48849fSKiran Chandramohan         mlir::Value nxtOpnd = operands[i];
2407dc48849fSKiran Chandramohan         auto memObj =
2408dc48849fSKiran Chandramohan             rewriter.create<mlir::LLVM::BitcastOp>(loc, recRefTy, resultAddr);
2409dc48849fSKiran Chandramohan         llvm::SmallVector<mlir::Value> args = {c0, nxtOpnd};
241003efa5a3SAndrzej Warzynski         cpnTy = recTy.getType(getFieldNumber(recTy, nxtOpnd));
241103efa5a3SAndrzej Warzynski         auto llvmCurrentObjTy = lowerTy().convertType(cpnTy);
2412dc48849fSKiran Chandramohan         auto gep = rewriter.create<mlir::LLVM::GEPOp>(
2413dc48849fSKiran Chandramohan             loc, mlir::LLVM::LLVMPointerType::get(llvmCurrentObjTy), memObj,
2414dc48849fSKiran Chandramohan             args);
2415dc48849fSKiran Chandramohan         resultAddr =
2416dc48849fSKiran Chandramohan             rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, gep);
2417dc48849fSKiran Chandramohan       } else {
2418dc48849fSKiran Chandramohan         fir::emitFatalError(loc, "unexpected type in coordinate_of");
2419dc48849fSKiran Chandramohan       }
2420dc48849fSKiran Chandramohan     }
2421dc48849fSKiran Chandramohan 
2422dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(coor, ty, resultAddr);
242344e58509SEric Schweitz     return mlir::success();
2424dc48849fSKiran Chandramohan   }
2425dc48849fSKiran Chandramohan 
2426dc48849fSKiran Chandramohan   mlir::LogicalResult
2427dc48849fSKiran Chandramohan   doRewriteRefOrPtr(fir::CoordinateOp coor, mlir::Type ty,
2428dc48849fSKiran Chandramohan                     mlir::ValueRange operands, mlir::Location loc,
2429dc48849fSKiran Chandramohan                     mlir::ConversionPatternRewriter &rewriter) const {
2430dc48849fSKiran Chandramohan     mlir::Type baseObjectTy = coor.getBaseType();
2431dc48849fSKiran Chandramohan 
243203efa5a3SAndrzej Warzynski     // Component Type
243303efa5a3SAndrzej Warzynski     mlir::Type cpnTy = fir::dyn_cast_ptrOrBoxEleTy(baseObjectTy);
243403efa5a3SAndrzej Warzynski     bool hasSubdimension = hasSubDimensions(cpnTy);
2435dc48849fSKiran Chandramohan     bool columnIsDeferred = !hasSubdimension;
2436dc48849fSKiran Chandramohan 
243703efa5a3SAndrzej Warzynski     if (!supportedCoordinate(cpnTy, operands.drop_front(1)))
2438dc48849fSKiran Chandramohan       TODO(loc, "unsupported combination of coordinate operands");
2439dc48849fSKiran Chandramohan 
2440dc48849fSKiran Chandramohan     const bool hasKnownShape =
244103efa5a3SAndrzej Warzynski         arraysHaveKnownShape(cpnTy, operands.drop_front(1));
2442dc48849fSKiran Chandramohan 
2443dc48849fSKiran Chandramohan     // If only the column is `?`, then we can simply place the column value in
2444dc48849fSKiran Chandramohan     // the 0-th GEP position.
244503efa5a3SAndrzej Warzynski     if (auto arrTy = cpnTy.dyn_cast<fir::SequenceType>()) {
2446dc48849fSKiran Chandramohan       if (!hasKnownShape) {
2447dc48849fSKiran Chandramohan         const unsigned sz = arrTy.getDimension();
2448dc48849fSKiran Chandramohan         if (arraysHaveKnownShape(arrTy.getEleTy(),
2449dc48849fSKiran Chandramohan                                  operands.drop_front(1 + sz))) {
245003efa5a3SAndrzej Warzynski           fir::SequenceType::ShapeRef shape = arrTy.getShape();
2451dc48849fSKiran Chandramohan           bool allConst = true;
2452dc48849fSKiran Chandramohan           for (unsigned i = 0; i < sz - 1; ++i) {
2453dc48849fSKiran Chandramohan             if (shape[i] < 0) {
2454dc48849fSKiran Chandramohan               allConst = false;
2455dc48849fSKiran Chandramohan               break;
2456dc48849fSKiran Chandramohan             }
2457dc48849fSKiran Chandramohan           }
2458dc48849fSKiran Chandramohan           if (allConst)
2459dc48849fSKiran Chandramohan             columnIsDeferred = true;
2460dc48849fSKiran Chandramohan         }
2461dc48849fSKiran Chandramohan       }
2462dc48849fSKiran Chandramohan     }
2463dc48849fSKiran Chandramohan 
246403efa5a3SAndrzej Warzynski     if (fir::hasDynamicSize(fir::unwrapSequenceType(cpnTy)))
246503efa5a3SAndrzej Warzynski       return mlir::emitError(
2466dc48849fSKiran Chandramohan           loc, "fir.coordinate_of with a dynamic element size is unsupported");
2467dc48849fSKiran Chandramohan 
2468dc48849fSKiran Chandramohan     if (hasKnownShape || columnIsDeferred) {
246944e58509SEric Schweitz       llvm::SmallVector<mlir::Value> offs;
2470dc48849fSKiran Chandramohan       if (hasKnownShape && hasSubdimension) {
2471dc48849fSKiran Chandramohan         mlir::LLVM::ConstantOp c0 =
2472dc48849fSKiran Chandramohan             genConstantIndex(loc, lowerTy().indexType(), rewriter, 0);
2473dc48849fSKiran Chandramohan         offs.push_back(c0);
2474dc48849fSKiran Chandramohan       }
247544e58509SEric Schweitz       llvm::Optional<int> dims;
247644e58509SEric Schweitz       llvm::SmallVector<mlir::Value> arrIdx;
247703efa5a3SAndrzej Warzynski       for (std::size_t i = 1, sz = operands.size(); i < sz; ++i) {
2478dc48849fSKiran Chandramohan         mlir::Value nxtOpnd = operands[i];
2479dc48849fSKiran Chandramohan 
248003efa5a3SAndrzej Warzynski         if (!cpnTy)
248103efa5a3SAndrzej Warzynski           return mlir::emitError(loc, "invalid coordinate/check failed");
2482dc48849fSKiran Chandramohan 
2483dc48849fSKiran Chandramohan         // check if the i-th coordinate relates to an array
2484dc48849fSKiran Chandramohan         if (dims.hasValue()) {
2485dc48849fSKiran Chandramohan           arrIdx.push_back(nxtOpnd);
2486dc48849fSKiran Chandramohan           int dimsLeft = *dims;
2487dc48849fSKiran Chandramohan           if (dimsLeft > 1) {
2488dc48849fSKiran Chandramohan             dims = dimsLeft - 1;
2489dc48849fSKiran Chandramohan             continue;
2490dc48849fSKiran Chandramohan           }
249103efa5a3SAndrzej Warzynski           cpnTy = cpnTy.cast<fir::SequenceType>().getEleTy();
2492dc48849fSKiran Chandramohan           // append array range in reverse (FIR arrays are column-major)
2493dc48849fSKiran Chandramohan           offs.append(arrIdx.rbegin(), arrIdx.rend());
2494dc48849fSKiran Chandramohan           arrIdx.clear();
2495dc48849fSKiran Chandramohan           dims.reset();
2496dc48849fSKiran Chandramohan           continue;
2497dc48849fSKiran Chandramohan         }
249803efa5a3SAndrzej Warzynski         if (auto arrTy = cpnTy.dyn_cast<fir::SequenceType>()) {
2499dc48849fSKiran Chandramohan           int d = arrTy.getDimension() - 1;
2500dc48849fSKiran Chandramohan           if (d > 0) {
2501dc48849fSKiran Chandramohan             dims = d;
2502dc48849fSKiran Chandramohan             arrIdx.push_back(nxtOpnd);
2503dc48849fSKiran Chandramohan             continue;
2504dc48849fSKiran Chandramohan           }
250503efa5a3SAndrzej Warzynski           cpnTy = cpnTy.cast<fir::SequenceType>().getEleTy();
2506dc48849fSKiran Chandramohan           offs.push_back(nxtOpnd);
2507dc48849fSKiran Chandramohan           continue;
2508dc48849fSKiran Chandramohan         }
2509dc48849fSKiran Chandramohan 
2510dc48849fSKiran Chandramohan         // check if the i-th coordinate relates to a field
251103efa5a3SAndrzej Warzynski         if (auto recTy = cpnTy.dyn_cast<fir::RecordType>())
251203efa5a3SAndrzej Warzynski           cpnTy = recTy.getType(getFieldNumber(recTy, nxtOpnd));
251303efa5a3SAndrzej Warzynski         else if (auto tupTy = cpnTy.dyn_cast<mlir::TupleType>())
251403efa5a3SAndrzej Warzynski           cpnTy = tupTy.getType(getIntValue(nxtOpnd));
2515dc48849fSKiran Chandramohan         else
251603efa5a3SAndrzej Warzynski           cpnTy = nullptr;
2517dc48849fSKiran Chandramohan 
2518dc48849fSKiran Chandramohan         offs.push_back(nxtOpnd);
2519dc48849fSKiran Chandramohan       }
2520dc48849fSKiran Chandramohan       if (dims.hasValue())
2521dc48849fSKiran Chandramohan         offs.append(arrIdx.rbegin(), arrIdx.rend());
2522dc48849fSKiran Chandramohan       mlir::Value base = operands[0];
2523dc48849fSKiran Chandramohan       mlir::Value retval = genGEP(loc, ty, rewriter, base, offs);
2524dc48849fSKiran Chandramohan       rewriter.replaceOp(coor, retval);
252544e58509SEric Schweitz       return mlir::success();
2526dc48849fSKiran Chandramohan     }
2527dc48849fSKiran Chandramohan 
252803efa5a3SAndrzej Warzynski     return mlir::emitError(
252903efa5a3SAndrzej Warzynski         loc, "fir.coordinate_of base operand has unsupported type");
2530dc48849fSKiran Chandramohan   }
2531dc48849fSKiran Chandramohan };
2532dc48849fSKiran Chandramohan 
2533dc48849fSKiran Chandramohan /// Convert `fir.field_index`. The conversion depends on whether the size of
2534dc48849fSKiran Chandramohan /// the record is static or dynamic.
2535dc48849fSKiran Chandramohan struct FieldIndexOpConversion : public FIROpConversion<fir::FieldIndexOp> {
2536dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2537dc48849fSKiran Chandramohan 
2538dc48849fSKiran Chandramohan   // NB: most field references should be resolved by this point
2539dc48849fSKiran Chandramohan   mlir::LogicalResult
2540dc48849fSKiran Chandramohan   matchAndRewrite(fir::FieldIndexOp field, OpAdaptor adaptor,
2541dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2542dc48849fSKiran Chandramohan     auto recTy = field.getOnType().cast<fir::RecordType>();
2543dc48849fSKiran Chandramohan     unsigned index = recTy.getFieldIndex(field.getFieldId());
2544dc48849fSKiran Chandramohan 
2545dc48849fSKiran Chandramohan     if (!fir::hasDynamicSize(recTy)) {
2546dc48849fSKiran Chandramohan       // Derived type has compile-time constant layout. Return index of the
2547dc48849fSKiran Chandramohan       // component type in the parent type (to be used in GEP).
2548dc48849fSKiran Chandramohan       rewriter.replaceOp(field, mlir::ValueRange{genConstantOffset(
2549dc48849fSKiran Chandramohan                                     field.getLoc(), rewriter, index)});
255044e58509SEric Schweitz       return mlir::success();
2551dc48849fSKiran Chandramohan     }
2552dc48849fSKiran Chandramohan 
2553dc48849fSKiran Chandramohan     // Derived type has compile-time constant layout. Call the compiler
2554dc48849fSKiran Chandramohan     // generated function to determine the byte offset of the field at runtime.
2555dc48849fSKiran Chandramohan     // This returns a non-constant.
255644e58509SEric Schweitz     mlir::FlatSymbolRefAttr symAttr = mlir::SymbolRefAttr::get(
2557dc48849fSKiran Chandramohan         field.getContext(), getOffsetMethodName(recTy, field.getFieldId()));
255844e58509SEric Schweitz     mlir::NamedAttribute callAttr = rewriter.getNamedAttr("callee", symAttr);
255944e58509SEric Schweitz     mlir::NamedAttribute fieldAttr = rewriter.getNamedAttr(
2560dc48849fSKiran Chandramohan         "field", mlir::IntegerAttr::get(lowerTy().indexType(), index));
2561dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
2562dc48849fSKiran Chandramohan         field, lowerTy().offsetType(), adaptor.getOperands(),
2563dc48849fSKiran Chandramohan         llvm::ArrayRef<mlir::NamedAttribute>{callAttr, fieldAttr});
256444e58509SEric Schweitz     return mlir::success();
2565dc48849fSKiran Chandramohan   }
2566dc48849fSKiran Chandramohan 
2567dc48849fSKiran Chandramohan   // Re-Construct the name of the compiler generated method that calculates the
2568dc48849fSKiran Chandramohan   // offset
2569dc48849fSKiran Chandramohan   inline static std::string getOffsetMethodName(fir::RecordType recTy,
2570dc48849fSKiran Chandramohan                                                 llvm::StringRef field) {
2571dc48849fSKiran Chandramohan     return recTy.getName().str() + "P." + field.str() + ".offset";
2572dc48849fSKiran Chandramohan   }
2573dc48849fSKiran Chandramohan };
2574dc48849fSKiran Chandramohan 
2575dc48849fSKiran Chandramohan /// Convert `fir.end`
2576dc48849fSKiran Chandramohan struct FirEndOpConversion : public FIROpConversion<fir::FirEndOp> {
2577dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2578dc48849fSKiran Chandramohan 
2579dc48849fSKiran Chandramohan   mlir::LogicalResult
2580dc48849fSKiran Chandramohan   matchAndRewrite(fir::FirEndOp firEnd, OpAdaptor,
2581dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2582dc48849fSKiran Chandramohan     TODO(firEnd.getLoc(), "fir.end codegen");
258344e58509SEric Schweitz     return mlir::failure();
2584dc48849fSKiran Chandramohan   }
2585dc48849fSKiran Chandramohan };
2586dc48849fSKiran Chandramohan 
2587dc48849fSKiran Chandramohan /// Lower `fir.gentypedesc` to a global constant.
2588dc48849fSKiran Chandramohan struct GenTypeDescOpConversion : public FIROpConversion<fir::GenTypeDescOp> {
2589dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2590dc48849fSKiran Chandramohan 
2591dc48849fSKiran Chandramohan   mlir::LogicalResult
2592dc48849fSKiran Chandramohan   matchAndRewrite(fir::GenTypeDescOp gentypedesc, OpAdaptor adaptor,
2593dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2594dc48849fSKiran Chandramohan     TODO(gentypedesc.getLoc(), "fir.gentypedesc codegen");
259544e58509SEric Schweitz     return mlir::failure();
2596dc48849fSKiran Chandramohan   }
2597dc48849fSKiran Chandramohan };
2598dc48849fSKiran Chandramohan 
2599dc48849fSKiran Chandramohan /// Lower `fir.has_value` operation to `llvm.return` operation.
2600dc48849fSKiran Chandramohan struct HasValueOpConversion : public FIROpConversion<fir::HasValueOp> {
2601dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2602dc48849fSKiran Chandramohan 
2603dc48849fSKiran Chandramohan   mlir::LogicalResult
2604dc48849fSKiran Chandramohan   matchAndRewrite(fir::HasValueOp op, OpAdaptor adaptor,
2605dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
260644e58509SEric Schweitz     rewriter.replaceOpWithNewOp<mlir::LLVM::ReturnOp>(op,
260744e58509SEric Schweitz                                                       adaptor.getOperands());
260844e58509SEric Schweitz     return mlir::success();
2609dc48849fSKiran Chandramohan   }
2610dc48849fSKiran Chandramohan };
2611dc48849fSKiran Chandramohan 
2612dc48849fSKiran Chandramohan /// Lower `fir.global` operation to `llvm.global` operation.
2613dc48849fSKiran Chandramohan /// `fir.insert_on_range` operations are replaced with constant dense attribute
2614dc48849fSKiran Chandramohan /// if they are applied on the full range.
2615dc48849fSKiran Chandramohan struct GlobalOpConversion : public FIROpConversion<fir::GlobalOp> {
2616dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2617dc48849fSKiran Chandramohan 
2618dc48849fSKiran Chandramohan   mlir::LogicalResult
2619dc48849fSKiran Chandramohan   matchAndRewrite(fir::GlobalOp global, OpAdaptor adaptor,
2620dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2621dc48849fSKiran Chandramohan     auto tyAttr = convertType(global.getType());
2622dc48849fSKiran Chandramohan     if (global.getType().isa<fir::BoxType>())
2623dc48849fSKiran Chandramohan       tyAttr = tyAttr.cast<mlir::LLVM::LLVMPointerType>().getElementType();
2624dc48849fSKiran Chandramohan     auto loc = global.getLoc();
2625dc48849fSKiran Chandramohan     mlir::Attribute initAttr{};
2626dc48849fSKiran Chandramohan     if (global.getInitVal())
2627dc48849fSKiran Chandramohan       initAttr = global.getInitVal().getValue();
2628dc48849fSKiran Chandramohan     auto linkage = convertLinkage(global.getLinkName());
2629dc48849fSKiran Chandramohan     auto isConst = global.getConstant().hasValue();
2630dc48849fSKiran Chandramohan     auto g = rewriter.create<mlir::LLVM::GlobalOp>(
2631dc48849fSKiran Chandramohan         loc, tyAttr, isConst, linkage, global.getSymName(), initAttr);
2632dc48849fSKiran Chandramohan     auto &gr = g.getInitializerRegion();
2633dc48849fSKiran Chandramohan     rewriter.inlineRegionBefore(global.getRegion(), gr, gr.end());
2634dc48849fSKiran Chandramohan     if (!gr.empty()) {
2635dc48849fSKiran Chandramohan       // Replace insert_on_range with a constant dense attribute if the
2636dc48849fSKiran Chandramohan       // initialization is on the full range.
2637dc48849fSKiran Chandramohan       auto insertOnRangeOps = gr.front().getOps<fir::InsertOnRangeOp>();
2638dc48849fSKiran Chandramohan       for (auto insertOp : insertOnRangeOps) {
2639dc48849fSKiran Chandramohan         if (isFullRange(insertOp.getCoor(), insertOp.getType())) {
2640dc48849fSKiran Chandramohan           auto seqTyAttr = convertType(insertOp.getType());
2641dc48849fSKiran Chandramohan           auto *op = insertOp.getVal().getDefiningOp();
2642dc48849fSKiran Chandramohan           auto constant = mlir::dyn_cast<mlir::arith::ConstantOp>(op);
2643dc48849fSKiran Chandramohan           if (!constant) {
2644dc48849fSKiran Chandramohan             auto convertOp = mlir::dyn_cast<fir::ConvertOp>(op);
2645dc48849fSKiran Chandramohan             if (!convertOp)
2646dc48849fSKiran Chandramohan               continue;
264744e58509SEric Schweitz             constant = mlir::cast<mlir::arith::ConstantOp>(
2648dc48849fSKiran Chandramohan                 convertOp.getValue().getDefiningOp());
2649dc48849fSKiran Chandramohan           }
2650dc48849fSKiran Chandramohan           mlir::Type vecType = mlir::VectorType::get(
2651dc48849fSKiran Chandramohan               insertOp.getType().getShape(), constant.getType());
2652dc48849fSKiran Chandramohan           auto denseAttr = mlir::DenseElementsAttr::get(
265344e58509SEric Schweitz               vecType.cast<mlir::ShapedType>(), constant.getValue());
2654dc48849fSKiran Chandramohan           rewriter.setInsertionPointAfter(insertOp);
2655dc48849fSKiran Chandramohan           rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(
2656dc48849fSKiran Chandramohan               insertOp, seqTyAttr, denseAttr);
2657dc48849fSKiran Chandramohan         }
2658dc48849fSKiran Chandramohan       }
2659dc48849fSKiran Chandramohan     }
2660dc48849fSKiran Chandramohan     rewriter.eraseOp(global);
266144e58509SEric Schweitz     return mlir::success();
2662dc48849fSKiran Chandramohan   }
2663dc48849fSKiran Chandramohan 
2664dc48849fSKiran Chandramohan   bool isFullRange(mlir::DenseIntElementsAttr indexes,
2665dc48849fSKiran Chandramohan                    fir::SequenceType seqTy) const {
2666dc48849fSKiran Chandramohan     auto extents = seqTy.getShape();
2667dc48849fSKiran Chandramohan     if (indexes.size() / 2 != static_cast<int64_t>(extents.size()))
2668dc48849fSKiran Chandramohan       return false;
2669dc48849fSKiran Chandramohan     auto cur_index = indexes.value_begin<int64_t>();
2670dc48849fSKiran Chandramohan     for (unsigned i = 0; i < indexes.size(); i += 2) {
2671dc48849fSKiran Chandramohan       if (*(cur_index++) != 0)
2672dc48849fSKiran Chandramohan         return false;
2673dc48849fSKiran Chandramohan       if (*(cur_index++) != extents[i / 2] - 1)
2674dc48849fSKiran Chandramohan         return false;
2675dc48849fSKiran Chandramohan     }
2676dc48849fSKiran Chandramohan     return true;
2677dc48849fSKiran Chandramohan   }
2678dc48849fSKiran Chandramohan 
2679dc48849fSKiran Chandramohan   // TODO: String comparaison should be avoided. Replace linkName with an
2680dc48849fSKiran Chandramohan   // enumeration.
268144e58509SEric Schweitz   mlir::LLVM::Linkage
268244e58509SEric Schweitz   convertLinkage(llvm::Optional<llvm::StringRef> optLinkage) const {
2683dc48849fSKiran Chandramohan     if (optLinkage.hasValue()) {
2684dc48849fSKiran Chandramohan       auto name = optLinkage.getValue();
2685dc48849fSKiran Chandramohan       if (name == "internal")
2686dc48849fSKiran Chandramohan         return mlir::LLVM::Linkage::Internal;
2687dc48849fSKiran Chandramohan       if (name == "linkonce")
2688dc48849fSKiran Chandramohan         return mlir::LLVM::Linkage::Linkonce;
268930a0fbf5SJean Perier       if (name == "linkonce_odr")
269030a0fbf5SJean Perier         return mlir::LLVM::Linkage::LinkonceODR;
2691dc48849fSKiran Chandramohan       if (name == "common")
2692dc48849fSKiran Chandramohan         return mlir::LLVM::Linkage::Common;
2693dc48849fSKiran Chandramohan       if (name == "weak")
2694dc48849fSKiran Chandramohan         return mlir::LLVM::Linkage::Weak;
2695dc48849fSKiran Chandramohan     }
2696dc48849fSKiran Chandramohan     return mlir::LLVM::Linkage::External;
2697dc48849fSKiran Chandramohan   }
2698dc48849fSKiran Chandramohan };
2699dc48849fSKiran Chandramohan 
2700dc48849fSKiran Chandramohan /// `fir.load` --> `llvm.load`
2701dc48849fSKiran Chandramohan struct LoadOpConversion : public FIROpConversion<fir::LoadOp> {
2702dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2703dc48849fSKiran Chandramohan 
2704dc48849fSKiran Chandramohan   mlir::LogicalResult
2705dc48849fSKiran Chandramohan   matchAndRewrite(fir::LoadOp load, OpAdaptor adaptor,
2706dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2707dc48849fSKiran Chandramohan     // fir.box is a special case because it is considered as an ssa values in
2708dc48849fSKiran Chandramohan     // fir, but it is lowered as a pointer to a descriptor. So fir.ref<fir.box>
2709dc48849fSKiran Chandramohan     // and fir.box end up being the same llvm types and loading a
2710dc48849fSKiran Chandramohan     // fir.ref<fir.box> is actually a no op in LLVM.
2711dc48849fSKiran Chandramohan     if (load.getType().isa<fir::BoxType>()) {
2712dc48849fSKiran Chandramohan       rewriter.replaceOp(load, adaptor.getOperands()[0]);
2713dc48849fSKiran Chandramohan     } else {
2714dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::LoadOp>(
271544e58509SEric Schweitz           load, convertType(load.getType()), adaptor.getOperands(),
271644e58509SEric Schweitz           load->getAttrs());
2717dc48849fSKiran Chandramohan     }
271844e58509SEric Schweitz     return mlir::success();
2719dc48849fSKiran Chandramohan   }
2720dc48849fSKiran Chandramohan };
2721dc48849fSKiran Chandramohan 
2722dc48849fSKiran Chandramohan /// Lower `fir.no_reassoc` to LLVM IR dialect.
2723dc48849fSKiran Chandramohan /// TODO: how do we want to enforce this in LLVM-IR? Can we manipulate the fast
2724dc48849fSKiran Chandramohan /// math flags?
2725dc48849fSKiran Chandramohan struct NoReassocOpConversion : public FIROpConversion<fir::NoReassocOp> {
2726dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2727dc48849fSKiran Chandramohan 
2728dc48849fSKiran Chandramohan   mlir::LogicalResult
2729dc48849fSKiran Chandramohan   matchAndRewrite(fir::NoReassocOp noreassoc, OpAdaptor adaptor,
2730dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2731dc48849fSKiran Chandramohan     rewriter.replaceOp(noreassoc, adaptor.getOperands()[0]);
273244e58509SEric Schweitz     return mlir::success();
2733dc48849fSKiran Chandramohan   }
2734dc48849fSKiran Chandramohan };
2735dc48849fSKiran Chandramohan 
2736dc48849fSKiran Chandramohan static void genCondBrOp(mlir::Location loc, mlir::Value cmp, mlir::Block *dest,
273744e58509SEric Schweitz                         llvm::Optional<mlir::ValueRange> destOps,
2738dc48849fSKiran Chandramohan                         mlir::ConversionPatternRewriter &rewriter,
2739dc48849fSKiran Chandramohan                         mlir::Block *newBlock) {
2740dc48849fSKiran Chandramohan   if (destOps.hasValue())
2741dc48849fSKiran Chandramohan     rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, destOps.getValue(),
2742dc48849fSKiran Chandramohan                                           newBlock, mlir::ValueRange());
2743dc48849fSKiran Chandramohan   else
2744dc48849fSKiran Chandramohan     rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, newBlock);
2745dc48849fSKiran Chandramohan }
2746dc48849fSKiran Chandramohan 
2747dc48849fSKiran Chandramohan template <typename A, typename B>
274844e58509SEric Schweitz static void genBrOp(A caseOp, mlir::Block *dest, llvm::Optional<B> destOps,
2749dc48849fSKiran Chandramohan                     mlir::ConversionPatternRewriter &rewriter) {
2750dc48849fSKiran Chandramohan   if (destOps.hasValue())
2751dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, destOps.getValue(),
2752dc48849fSKiran Chandramohan                                                   dest);
2753dc48849fSKiran Chandramohan   else
2754dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, llvm::None, dest);
2755dc48849fSKiran Chandramohan }
2756dc48849fSKiran Chandramohan 
2757dc48849fSKiran Chandramohan static void genCaseLadderStep(mlir::Location loc, mlir::Value cmp,
2758dc48849fSKiran Chandramohan                               mlir::Block *dest,
275944e58509SEric Schweitz                               llvm::Optional<mlir::ValueRange> destOps,
2760dc48849fSKiran Chandramohan                               mlir::ConversionPatternRewriter &rewriter) {
2761dc48849fSKiran Chandramohan   auto *thisBlock = rewriter.getInsertionBlock();
2762dc48849fSKiran Chandramohan   auto *newBlock = createBlock(rewriter, dest);
2763dc48849fSKiran Chandramohan   rewriter.setInsertionPointToEnd(thisBlock);
2764dc48849fSKiran Chandramohan   genCondBrOp(loc, cmp, dest, destOps, rewriter, newBlock);
2765dc48849fSKiran Chandramohan   rewriter.setInsertionPointToEnd(newBlock);
2766dc48849fSKiran Chandramohan }
2767dc48849fSKiran Chandramohan 
2768dc48849fSKiran Chandramohan /// Conversion of `fir.select_case`
2769dc48849fSKiran Chandramohan ///
2770dc48849fSKiran Chandramohan /// The `fir.select_case` operation is converted to a if-then-else ladder.
2771dc48849fSKiran Chandramohan /// Depending on the case condition type, one or several comparison and
2772dc48849fSKiran Chandramohan /// conditional branching can be generated.
2773dc48849fSKiran Chandramohan ///
2774dc48849fSKiran Chandramohan /// A a point value case such as `case(4)`, a lower bound case such as
2775dc48849fSKiran Chandramohan /// `case(5:)` or an upper bound case such as `case(:3)` are converted to a
2776dc48849fSKiran Chandramohan /// simple comparison between the selector value and the constant value in the
2777dc48849fSKiran Chandramohan /// case. The block associated with the case condition is then executed if
2778dc48849fSKiran Chandramohan /// the comparison succeed otherwise it branch to the next block with the
2779dc48849fSKiran Chandramohan /// comparison for the the next case conditon.
2780dc48849fSKiran Chandramohan ///
2781dc48849fSKiran Chandramohan /// A closed interval case condition such as `case(7:10)` is converted with a
2782dc48849fSKiran Chandramohan /// first comparison and conditional branching for the lower bound. If
2783dc48849fSKiran Chandramohan /// successful, it branch to a second block with the comparison for the
2784dc48849fSKiran Chandramohan /// upper bound in the same case condition.
2785dc48849fSKiran Chandramohan ///
2786dc48849fSKiran Chandramohan /// TODO: lowering of CHARACTER type cases is not handled yet.
2787dc48849fSKiran Chandramohan struct SelectCaseOpConversion : public FIROpConversion<fir::SelectCaseOp> {
2788dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2789dc48849fSKiran Chandramohan 
2790dc48849fSKiran Chandramohan   mlir::LogicalResult
2791dc48849fSKiran Chandramohan   matchAndRewrite(fir::SelectCaseOp caseOp, OpAdaptor adaptor,
2792dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2793dc48849fSKiran Chandramohan     unsigned conds = caseOp.getNumConditions();
2794dc48849fSKiran Chandramohan     llvm::ArrayRef<mlir::Attribute> cases = caseOp.getCases().getValue();
2795dc48849fSKiran Chandramohan     // Type can be CHARACTER, INTEGER, or LOGICAL (C1145)
2796dc48849fSKiran Chandramohan     auto ty = caseOp.getSelector().getType();
2797dc48849fSKiran Chandramohan     if (ty.isa<fir::CharacterType>()) {
2798dc48849fSKiran Chandramohan       TODO(caseOp.getLoc(), "fir.select_case codegen with character type");
279944e58509SEric Schweitz       return mlir::failure();
2800dc48849fSKiran Chandramohan     }
2801dc48849fSKiran Chandramohan     mlir::Value selector = caseOp.getSelector(adaptor.getOperands());
2802dc48849fSKiran Chandramohan     auto loc = caseOp.getLoc();
2803dc48849fSKiran Chandramohan     for (unsigned t = 0; t != conds; ++t) {
2804dc48849fSKiran Chandramohan       mlir::Block *dest = caseOp.getSuccessor(t);
2805dc48849fSKiran Chandramohan       llvm::Optional<mlir::ValueRange> destOps =
2806dc48849fSKiran Chandramohan           caseOp.getSuccessorOperands(adaptor.getOperands(), t);
2807dc48849fSKiran Chandramohan       llvm::Optional<mlir::ValueRange> cmpOps =
2808dc48849fSKiran Chandramohan           *caseOp.getCompareOperands(adaptor.getOperands(), t);
2809dc48849fSKiran Chandramohan       mlir::Value caseArg = *(cmpOps.getValue().begin());
2810dc48849fSKiran Chandramohan       mlir::Attribute attr = cases[t];
2811dc48849fSKiran Chandramohan       if (attr.isa<fir::PointIntervalAttr>()) {
2812dc48849fSKiran Chandramohan         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
2813dc48849fSKiran Chandramohan             loc, mlir::LLVM::ICmpPredicate::eq, selector, caseArg);
2814dc48849fSKiran Chandramohan         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
2815dc48849fSKiran Chandramohan         continue;
2816dc48849fSKiran Chandramohan       }
2817dc48849fSKiran Chandramohan       if (attr.isa<fir::LowerBoundAttr>()) {
2818dc48849fSKiran Chandramohan         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
2819dc48849fSKiran Chandramohan             loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector);
2820dc48849fSKiran Chandramohan         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
2821dc48849fSKiran Chandramohan         continue;
2822dc48849fSKiran Chandramohan       }
2823dc48849fSKiran Chandramohan       if (attr.isa<fir::UpperBoundAttr>()) {
2824dc48849fSKiran Chandramohan         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
2825dc48849fSKiran Chandramohan             loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg);
2826dc48849fSKiran Chandramohan         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
2827dc48849fSKiran Chandramohan         continue;
2828dc48849fSKiran Chandramohan       }
2829dc48849fSKiran Chandramohan       if (attr.isa<fir::ClosedIntervalAttr>()) {
2830dc48849fSKiran Chandramohan         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
2831dc48849fSKiran Chandramohan             loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector);
2832dc48849fSKiran Chandramohan         auto *thisBlock = rewriter.getInsertionBlock();
2833dc48849fSKiran Chandramohan         auto *newBlock1 = createBlock(rewriter, dest);
2834dc48849fSKiran Chandramohan         auto *newBlock2 = createBlock(rewriter, dest);
2835dc48849fSKiran Chandramohan         rewriter.setInsertionPointToEnd(thisBlock);
2836dc48849fSKiran Chandramohan         rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, newBlock1, newBlock2);
2837dc48849fSKiran Chandramohan         rewriter.setInsertionPointToEnd(newBlock1);
2838dc48849fSKiran Chandramohan         mlir::Value caseArg0 = *(cmpOps.getValue().begin() + 1);
2839dc48849fSKiran Chandramohan         auto cmp0 = rewriter.create<mlir::LLVM::ICmpOp>(
2840dc48849fSKiran Chandramohan             loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg0);
2841dc48849fSKiran Chandramohan         genCondBrOp(loc, cmp0, dest, destOps, rewriter, newBlock2);
2842dc48849fSKiran Chandramohan         rewriter.setInsertionPointToEnd(newBlock2);
2843dc48849fSKiran Chandramohan         continue;
2844dc48849fSKiran Chandramohan       }
2845dc48849fSKiran Chandramohan       assert(attr.isa<mlir::UnitAttr>());
2846dc48849fSKiran Chandramohan       assert((t + 1 == conds) && "unit must be last");
2847dc48849fSKiran Chandramohan       genBrOp(caseOp, dest, destOps, rewriter);
2848dc48849fSKiran Chandramohan     }
284944e58509SEric Schweitz     return mlir::success();
2850dc48849fSKiran Chandramohan   }
2851dc48849fSKiran Chandramohan };
2852dc48849fSKiran Chandramohan 
2853dc48849fSKiran Chandramohan template <typename OP>
2854dc48849fSKiran Chandramohan static void selectMatchAndRewrite(fir::LLVMTypeConverter &lowering, OP select,
2855dc48849fSKiran Chandramohan                                   typename OP::Adaptor adaptor,
2856dc48849fSKiran Chandramohan                                   mlir::ConversionPatternRewriter &rewriter) {
2857dc48849fSKiran Chandramohan   unsigned conds = select.getNumConditions();
2858dc48849fSKiran Chandramohan   auto cases = select.getCases().getValue();
2859dc48849fSKiran Chandramohan   mlir::Value selector = adaptor.getSelector();
2860dc48849fSKiran Chandramohan   auto loc = select.getLoc();
2861dc48849fSKiran Chandramohan   assert(conds > 0 && "select must have cases");
2862dc48849fSKiran Chandramohan 
2863dc48849fSKiran Chandramohan   llvm::SmallVector<mlir::Block *> destinations;
2864dc48849fSKiran Chandramohan   llvm::SmallVector<mlir::ValueRange> destinationsOperands;
2865dc48849fSKiran Chandramohan   mlir::Block *defaultDestination;
2866dc48849fSKiran Chandramohan   mlir::ValueRange defaultOperands;
2867dc48849fSKiran Chandramohan   llvm::SmallVector<int32_t> caseValues;
2868dc48849fSKiran Chandramohan 
2869dc48849fSKiran Chandramohan   for (unsigned t = 0; t != conds; ++t) {
2870dc48849fSKiran Chandramohan     mlir::Block *dest = select.getSuccessor(t);
2871dc48849fSKiran Chandramohan     auto destOps = select.getSuccessorOperands(adaptor.getOperands(), t);
2872dc48849fSKiran Chandramohan     const mlir::Attribute &attr = cases[t];
2873dc48849fSKiran Chandramohan     if (auto intAttr = attr.template dyn_cast<mlir::IntegerAttr>()) {
2874dc48849fSKiran Chandramohan       destinations.push_back(dest);
2875dc48849fSKiran Chandramohan       destinationsOperands.push_back(destOps.hasValue() ? *destOps
287644e58509SEric Schweitz                                                         : mlir::ValueRange{});
2877dc48849fSKiran Chandramohan       caseValues.push_back(intAttr.getInt());
2878dc48849fSKiran Chandramohan       continue;
2879dc48849fSKiran Chandramohan     }
2880dc48849fSKiran Chandramohan     assert(attr.template dyn_cast_or_null<mlir::UnitAttr>());
2881dc48849fSKiran Chandramohan     assert((t + 1 == conds) && "unit must be last");
2882dc48849fSKiran Chandramohan     defaultDestination = dest;
288344e58509SEric Schweitz     defaultOperands = destOps.hasValue() ? *destOps : mlir::ValueRange{};
2884dc48849fSKiran Chandramohan   }
2885dc48849fSKiran Chandramohan 
2886dc48849fSKiran Chandramohan   // LLVM::SwitchOp takes a i32 type for the selector.
2887dc48849fSKiran Chandramohan   if (select.getSelector().getType() != rewriter.getI32Type())
288844e58509SEric Schweitz     selector = rewriter.create<mlir::LLVM::TruncOp>(loc, rewriter.getI32Type(),
288944e58509SEric Schweitz                                                     selector);
2890dc48849fSKiran Chandramohan 
2891dc48849fSKiran Chandramohan   rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>(
2892dc48849fSKiran Chandramohan       select, selector,
2893dc48849fSKiran Chandramohan       /*defaultDestination=*/defaultDestination,
2894dc48849fSKiran Chandramohan       /*defaultOperands=*/defaultOperands,
2895dc48849fSKiran Chandramohan       /*caseValues=*/caseValues,
2896dc48849fSKiran Chandramohan       /*caseDestinations=*/destinations,
2897dc48849fSKiran Chandramohan       /*caseOperands=*/destinationsOperands,
289844e58509SEric Schweitz       /*branchWeights=*/llvm::ArrayRef<std::int32_t>());
2899dc48849fSKiran Chandramohan }
2900dc48849fSKiran Chandramohan 
2901dc48849fSKiran Chandramohan /// conversion of fir::SelectOp to an if-then-else ladder
2902dc48849fSKiran Chandramohan struct SelectOpConversion : public FIROpConversion<fir::SelectOp> {
2903dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2904dc48849fSKiran Chandramohan 
2905dc48849fSKiran Chandramohan   mlir::LogicalResult
2906dc48849fSKiran Chandramohan   matchAndRewrite(fir::SelectOp op, OpAdaptor adaptor,
2907dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2908dc48849fSKiran Chandramohan     selectMatchAndRewrite<fir::SelectOp>(lowerTy(), op, adaptor, rewriter);
290944e58509SEric Schweitz     return mlir::success();
2910dc48849fSKiran Chandramohan   }
2911dc48849fSKiran Chandramohan };
2912dc48849fSKiran Chandramohan 
2913dc48849fSKiran Chandramohan /// conversion of fir::SelectRankOp to an if-then-else ladder
2914dc48849fSKiran Chandramohan struct SelectRankOpConversion : public FIROpConversion<fir::SelectRankOp> {
2915dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2916dc48849fSKiran Chandramohan 
2917dc48849fSKiran Chandramohan   mlir::LogicalResult
2918dc48849fSKiran Chandramohan   matchAndRewrite(fir::SelectRankOp op, OpAdaptor adaptor,
2919dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2920dc48849fSKiran Chandramohan     selectMatchAndRewrite<fir::SelectRankOp>(lowerTy(), op, adaptor, rewriter);
292144e58509SEric Schweitz     return mlir::success();
2922dc48849fSKiran Chandramohan   }
2923dc48849fSKiran Chandramohan };
2924dc48849fSKiran Chandramohan 
2925dc48849fSKiran Chandramohan /// Lower `fir.select_type` to LLVM IR dialect.
2926dc48849fSKiran Chandramohan struct SelectTypeOpConversion : public FIROpConversion<fir::SelectTypeOp> {
2927dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2928dc48849fSKiran Chandramohan 
2929dc48849fSKiran Chandramohan   mlir::LogicalResult
2930dc48849fSKiran Chandramohan   matchAndRewrite(fir::SelectTypeOp select, OpAdaptor adaptor,
2931dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2932dc48849fSKiran Chandramohan     mlir::emitError(select.getLoc(),
2933dc48849fSKiran Chandramohan                     "fir.select_type should have already been converted");
293444e58509SEric Schweitz     return mlir::failure();
2935dc48849fSKiran Chandramohan   }
2936dc48849fSKiran Chandramohan };
2937dc48849fSKiran Chandramohan 
2938dc48849fSKiran Chandramohan /// `fir.store` --> `llvm.store`
2939dc48849fSKiran Chandramohan struct StoreOpConversion : public FIROpConversion<fir::StoreOp> {
2940dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2941dc48849fSKiran Chandramohan 
2942dc48849fSKiran Chandramohan   mlir::LogicalResult
2943dc48849fSKiran Chandramohan   matchAndRewrite(fir::StoreOp store, OpAdaptor adaptor,
2944dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2945dc48849fSKiran Chandramohan     if (store.getValue().getType().isa<fir::BoxType>()) {
2946dc48849fSKiran Chandramohan       // fir.box value is actually in memory, load it first before storing it.
2947dc48849fSKiran Chandramohan       mlir::Location loc = store.getLoc();
2948dc48849fSKiran Chandramohan       mlir::Type boxPtrTy = adaptor.getOperands()[0].getType();
2949dc48849fSKiran Chandramohan       auto val = rewriter.create<mlir::LLVM::LoadOp>(
2950dc48849fSKiran Chandramohan           loc, boxPtrTy.cast<mlir::LLVM::LLVMPointerType>().getElementType(),
2951dc48849fSKiran Chandramohan           adaptor.getOperands()[0]);
2952dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
2953dc48849fSKiran Chandramohan           store, val, adaptor.getOperands()[1]);
2954dc48849fSKiran Chandramohan     } else {
2955dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
2956dc48849fSKiran Chandramohan           store, adaptor.getOperands()[0], adaptor.getOperands()[1]);
2957dc48849fSKiran Chandramohan     }
295844e58509SEric Schweitz     return mlir::success();
2959dc48849fSKiran Chandramohan   }
2960dc48849fSKiran Chandramohan };
2961dc48849fSKiran Chandramohan 
2962dc48849fSKiran Chandramohan namespace {
2963dc48849fSKiran Chandramohan 
2964dc48849fSKiran Chandramohan /// Convert `fir.unboxchar` into two `llvm.extractvalue` instructions. One for
2965dc48849fSKiran Chandramohan /// the character buffer and one for the buffer length.
2966dc48849fSKiran Chandramohan struct UnboxCharOpConversion : public FIROpConversion<fir::UnboxCharOp> {
2967dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2968dc48849fSKiran Chandramohan 
2969dc48849fSKiran Chandramohan   mlir::LogicalResult
2970dc48849fSKiran Chandramohan   matchAndRewrite(fir::UnboxCharOp unboxchar, OpAdaptor adaptor,
2971dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
297244e58509SEric Schweitz     auto *ctx = unboxchar.getContext();
2973dc48849fSKiran Chandramohan 
2974dc48849fSKiran Chandramohan     mlir::Type lenTy = convertType(unboxchar.getType(1));
2975dc48849fSKiran Chandramohan     mlir::Value tuple = adaptor.getOperands()[0];
2976dc48849fSKiran Chandramohan     mlir::Type tupleTy = tuple.getType();
2977dc48849fSKiran Chandramohan 
2978dc48849fSKiran Chandramohan     mlir::Location loc = unboxchar.getLoc();
2979dc48849fSKiran Chandramohan     mlir::Value ptrToBuffer =
2980dc48849fSKiran Chandramohan         genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 0);
2981dc48849fSKiran Chandramohan 
2982dc48849fSKiran Chandramohan     mlir::LLVM::ExtractValueOp len =
2983dc48849fSKiran Chandramohan         genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 1);
2984dc48849fSKiran Chandramohan     mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, len);
2985dc48849fSKiran Chandramohan 
2986dc48849fSKiran Chandramohan     rewriter.replaceOp(unboxchar,
298744e58509SEric Schweitz                        llvm::ArrayRef<mlir::Value>{ptrToBuffer, lenAfterCast});
298844e58509SEric Schweitz     return mlir::success();
2989dc48849fSKiran Chandramohan   }
2990dc48849fSKiran Chandramohan };
2991dc48849fSKiran Chandramohan 
2992dc48849fSKiran Chandramohan /// Lower `fir.unboxproc` operation. Unbox a procedure box value, yielding its
2993dc48849fSKiran Chandramohan /// components.
2994dc48849fSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
2995dc48849fSKiran Chandramohan struct UnboxProcOpConversion : public FIROpConversion<fir::UnboxProcOp> {
2996dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2997dc48849fSKiran Chandramohan 
2998dc48849fSKiran Chandramohan   mlir::LogicalResult
2999dc48849fSKiran Chandramohan   matchAndRewrite(fir::UnboxProcOp unboxproc, OpAdaptor adaptor,
3000dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3001dc48849fSKiran Chandramohan     TODO(unboxproc.getLoc(), "fir.unboxproc codegen");
300244e58509SEric Schweitz     return mlir::failure();
3003dc48849fSKiran Chandramohan   }
3004dc48849fSKiran Chandramohan };
3005dc48849fSKiran Chandramohan 
3006dc48849fSKiran Chandramohan /// convert to LLVM IR dialect `undef`
3007dc48849fSKiran Chandramohan struct UndefOpConversion : public FIROpConversion<fir::UndefOp> {
3008dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3009dc48849fSKiran Chandramohan 
3010dc48849fSKiran Chandramohan   mlir::LogicalResult
3011dc48849fSKiran Chandramohan   matchAndRewrite(fir::UndefOp undef, OpAdaptor,
3012dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3013dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::UndefOp>(
3014dc48849fSKiran Chandramohan         undef, convertType(undef.getType()));
301544e58509SEric Schweitz     return mlir::success();
3016dc48849fSKiran Chandramohan   }
3017dc48849fSKiran Chandramohan };
3018dc48849fSKiran Chandramohan 
3019dc48849fSKiran Chandramohan struct ZeroOpConversion : public FIROpConversion<fir::ZeroOp> {
3020dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3021dc48849fSKiran Chandramohan 
3022dc48849fSKiran Chandramohan   mlir::LogicalResult
3023dc48849fSKiran Chandramohan   matchAndRewrite(fir::ZeroOp zero, OpAdaptor,
3024dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3025dc48849fSKiran Chandramohan     mlir::Type ty = convertType(zero.getType());
3026dc48849fSKiran Chandramohan     if (ty.isa<mlir::LLVM::LLVMPointerType>()) {
3027dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(zero, ty);
3028dc48849fSKiran Chandramohan     } else if (ty.isa<mlir::IntegerType>()) {
3029dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
3030dc48849fSKiran Chandramohan           zero, ty, mlir::IntegerAttr::get(zero.getType(), 0));
3031dc48849fSKiran Chandramohan     } else if (mlir::LLVM::isCompatibleFloatingPointType(ty)) {
3032dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
3033dc48849fSKiran Chandramohan           zero, ty, mlir::FloatAttr::get(zero.getType(), 0.0));
3034dc48849fSKiran Chandramohan     } else {
3035dc48849fSKiran Chandramohan       // TODO: create ConstantAggregateZero for FIR aggregate/array types.
3036dc48849fSKiran Chandramohan       return rewriter.notifyMatchFailure(
3037dc48849fSKiran Chandramohan           zero,
3038dc48849fSKiran Chandramohan           "conversion of fir.zero with aggregate type not implemented yet");
3039dc48849fSKiran Chandramohan     }
304044e58509SEric Schweitz     return mlir::success();
3041dc48849fSKiran Chandramohan   }
3042dc48849fSKiran Chandramohan };
3043dc48849fSKiran Chandramohan 
3044dc48849fSKiran Chandramohan /// `fir.unreachable` --> `llvm.unreachable`
3045dc48849fSKiran Chandramohan struct UnreachableOpConversion : public FIROpConversion<fir::UnreachableOp> {
3046dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3047dc48849fSKiran Chandramohan 
3048dc48849fSKiran Chandramohan   mlir::LogicalResult
3049dc48849fSKiran Chandramohan   matchAndRewrite(fir::UnreachableOp unreach, OpAdaptor adaptor,
3050dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3051dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(unreach);
305244e58509SEric Schweitz     return mlir::success();
3053dc48849fSKiran Chandramohan   }
3054dc48849fSKiran Chandramohan };
3055dc48849fSKiran Chandramohan 
3056dc48849fSKiran Chandramohan /// `fir.is_present` -->
3057dc48849fSKiran Chandramohan /// ```
3058dc48849fSKiran Chandramohan ///  %0 = llvm.mlir.constant(0 : i64)
3059dc48849fSKiran Chandramohan ///  %1 = llvm.ptrtoint %0
3060dc48849fSKiran Chandramohan ///  %2 = llvm.icmp "ne" %1, %0 : i64
3061dc48849fSKiran Chandramohan /// ```
3062dc48849fSKiran Chandramohan struct IsPresentOpConversion : public FIROpConversion<fir::IsPresentOp> {
3063dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3064dc48849fSKiran Chandramohan 
3065dc48849fSKiran Chandramohan   mlir::LogicalResult
3066dc48849fSKiran Chandramohan   matchAndRewrite(fir::IsPresentOp isPresent, OpAdaptor adaptor,
3067dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3068dc48849fSKiran Chandramohan     mlir::Type idxTy = lowerTy().indexType();
3069dc48849fSKiran Chandramohan     mlir::Location loc = isPresent.getLoc();
3070dc48849fSKiran Chandramohan     auto ptr = adaptor.getOperands()[0];
3071dc48849fSKiran Chandramohan 
3072dc48849fSKiran Chandramohan     if (isPresent.getVal().getType().isa<fir::BoxCharType>()) {
3073dc48849fSKiran Chandramohan       auto structTy = ptr.getType().cast<mlir::LLVM::LLVMStructType>();
3074dc48849fSKiran Chandramohan       assert(!structTy.isOpaque() && !structTy.getBody().empty());
3075dc48849fSKiran Chandramohan 
3076dc48849fSKiran Chandramohan       mlir::Type ty = structTy.getBody()[0];
3077dc48849fSKiran Chandramohan       mlir::MLIRContext *ctx = isPresent.getContext();
3078dc48849fSKiran Chandramohan       auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
3079dc48849fSKiran Chandramohan       ptr = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, ptr, c0);
3080dc48849fSKiran Chandramohan     }
3081dc48849fSKiran Chandramohan     mlir::LLVM::ConstantOp c0 =
3082dc48849fSKiran Chandramohan         genConstantIndex(isPresent.getLoc(), idxTy, rewriter, 0);
3083dc48849fSKiran Chandramohan     auto addr = rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, ptr);
3084dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
3085dc48849fSKiran Chandramohan         isPresent, mlir::LLVM::ICmpPredicate::ne, addr, c0);
3086dc48849fSKiran Chandramohan 
308744e58509SEric Schweitz     return mlir::success();
3088dc48849fSKiran Chandramohan   }
3089dc48849fSKiran Chandramohan };
3090dc48849fSKiran Chandramohan 
3091dc48849fSKiran Chandramohan /// Create value signaling an absent optional argument in a call, e.g.
3092dc48849fSKiran Chandramohan /// `fir.absent !fir.ref<i64>` -->  `llvm.mlir.null : !llvm.ptr<i64>`
3093dc48849fSKiran Chandramohan struct AbsentOpConversion : public FIROpConversion<fir::AbsentOp> {
3094dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3095dc48849fSKiran Chandramohan 
3096dc48849fSKiran Chandramohan   mlir::LogicalResult
3097dc48849fSKiran Chandramohan   matchAndRewrite(fir::AbsentOp absent, OpAdaptor,
3098dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3099dc48849fSKiran Chandramohan     mlir::Type ty = convertType(absent.getType());
3100dc48849fSKiran Chandramohan     mlir::Location loc = absent.getLoc();
3101dc48849fSKiran Chandramohan 
3102dc48849fSKiran Chandramohan     if (absent.getType().isa<fir::BoxCharType>()) {
3103dc48849fSKiran Chandramohan       auto structTy = ty.cast<mlir::LLVM::LLVMStructType>();
3104dc48849fSKiran Chandramohan       assert(!structTy.isOpaque() && !structTy.getBody().empty());
3105dc48849fSKiran Chandramohan       auto undefStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
3106dc48849fSKiran Chandramohan       auto nullField =
3107dc48849fSKiran Chandramohan           rewriter.create<mlir::LLVM::NullOp>(loc, structTy.getBody()[0]);
3108dc48849fSKiran Chandramohan       mlir::MLIRContext *ctx = absent.getContext();
3109dc48849fSKiran Chandramohan       auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
3110dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
3111dc48849fSKiran Chandramohan           absent, ty, undefStruct, nullField, c0);
3112dc48849fSKiran Chandramohan     } else {
3113dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(absent, ty);
3114dc48849fSKiran Chandramohan     }
311544e58509SEric Schweitz     return mlir::success();
3116dc48849fSKiran Chandramohan   }
3117dc48849fSKiran Chandramohan };
31185d27abe6SValentin Clement 
31197b5132daSValentin Clement //
31207b5132daSValentin Clement // Primitive operations on Complex types
31217b5132daSValentin Clement //
31227b5132daSValentin Clement 
31237b5132daSValentin Clement /// Generate inline code for complex addition/subtraction
31247b5132daSValentin Clement template <typename LLVMOP, typename OPTY>
3125c2acd453SAlexisPerry static mlir::LLVM::InsertValueOp
3126c2acd453SAlexisPerry complexSum(OPTY sumop, mlir::ValueRange opnds,
31277b5132daSValentin Clement            mlir::ConversionPatternRewriter &rewriter,
31287b5132daSValentin Clement            fir::LLVMTypeConverter &lowering) {
31297b5132daSValentin Clement   mlir::Value a = opnds[0];
31307b5132daSValentin Clement   mlir::Value b = opnds[1];
31317b5132daSValentin Clement   auto loc = sumop.getLoc();
31327b5132daSValentin Clement   auto ctx = sumop.getContext();
31337b5132daSValentin Clement   auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
31347b5132daSValentin Clement   auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
31357b5132daSValentin Clement   mlir::Type eleTy = lowering.convertType(getComplexEleTy(sumop.getType()));
31367b5132daSValentin Clement   mlir::Type ty = lowering.convertType(sumop.getType());
31377b5132daSValentin Clement   auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
31387b5132daSValentin Clement   auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
31397b5132daSValentin Clement   auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
31407b5132daSValentin Clement   auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
31417b5132daSValentin Clement   auto rx = rewriter.create<LLVMOP>(loc, eleTy, x0, x1);
31427b5132daSValentin Clement   auto ry = rewriter.create<LLVMOP>(loc, eleTy, y0, y1);
31437b5132daSValentin Clement   auto r0 = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
31447b5132daSValentin Clement   auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r0, rx, c0);
31457b5132daSValentin Clement   return rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ry, c1);
31467b5132daSValentin Clement }
3147dc48849fSKiran Chandramohan } // namespace
31487b5132daSValentin Clement 
3149c2acd453SAlexisPerry namespace {
31507b5132daSValentin Clement struct AddcOpConversion : public FIROpConversion<fir::AddcOp> {
31517b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
31527b5132daSValentin Clement 
31537b5132daSValentin Clement   mlir::LogicalResult
31547b5132daSValentin Clement   matchAndRewrite(fir::AddcOp addc, OpAdaptor adaptor,
31557b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
31567b5132daSValentin Clement     // given: (x + iy) + (x' + iy')
31577b5132daSValentin Clement     // result: (x + x') + i(y + y')
31587b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FAddOp>(addc, adaptor.getOperands(),
31597b5132daSValentin Clement                                             rewriter, lowerTy());
31607b5132daSValentin Clement     rewriter.replaceOp(addc, r.getResult());
316144e58509SEric Schweitz     return mlir::success();
31627b5132daSValentin Clement   }
31637b5132daSValentin Clement };
31647b5132daSValentin Clement 
31657b5132daSValentin Clement struct SubcOpConversion : public FIROpConversion<fir::SubcOp> {
31667b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
31677b5132daSValentin Clement 
31687b5132daSValentin Clement   mlir::LogicalResult
31697b5132daSValentin Clement   matchAndRewrite(fir::SubcOp subc, OpAdaptor adaptor,
31707b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
31717b5132daSValentin Clement     // given: (x + iy) - (x' + iy')
31727b5132daSValentin Clement     // result: (x - x') + i(y - y')
31737b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FSubOp>(subc, adaptor.getOperands(),
31747b5132daSValentin Clement                                             rewriter, lowerTy());
31757b5132daSValentin Clement     rewriter.replaceOp(subc, r.getResult());
317644e58509SEric Schweitz     return mlir::success();
31777b5132daSValentin Clement   }
31787b5132daSValentin Clement };
31797b5132daSValentin Clement 
31807b5132daSValentin Clement /// Inlined complex multiply
31817b5132daSValentin Clement struct MulcOpConversion : public FIROpConversion<fir::MulcOp> {
31827b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
31837b5132daSValentin Clement 
31847b5132daSValentin Clement   mlir::LogicalResult
31857b5132daSValentin Clement   matchAndRewrite(fir::MulcOp mulc, OpAdaptor adaptor,
31867b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
31877b5132daSValentin Clement     // TODO: Can we use a call to __muldc3 ?
31887b5132daSValentin Clement     // given: (x + iy) * (x' + iy')
31897b5132daSValentin Clement     // result: (xx'-yy')+i(xy'+yx')
31907b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
31917b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
31927b5132daSValentin Clement     auto loc = mulc.getLoc();
31937b5132daSValentin Clement     auto *ctx = mulc.getContext();
31947b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
31957b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
31967b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(mulc.getType()));
31977b5132daSValentin Clement     mlir::Type ty = convertType(mulc.getType());
31987b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
31997b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
32007b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
32017b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
32027b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
32037b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
32047b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
32057b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xy, yx);
32067b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
32077b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, xx, yy);
32087b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
32097b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
32107b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
32117b5132daSValentin Clement     rewriter.replaceOp(mulc, r0.getResult());
321244e58509SEric Schweitz     return mlir::success();
32137b5132daSValentin Clement   }
32147b5132daSValentin Clement };
32157b5132daSValentin Clement 
32167b5132daSValentin Clement /// Inlined complex division
32177b5132daSValentin Clement struct DivcOpConversion : public FIROpConversion<fir::DivcOp> {
32187b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
32197b5132daSValentin Clement 
32207b5132daSValentin Clement   mlir::LogicalResult
32217b5132daSValentin Clement   matchAndRewrite(fir::DivcOp divc, OpAdaptor adaptor,
32227b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
32237b5132daSValentin Clement     // TODO: Can we use a call to __divdc3 instead?
32247b5132daSValentin Clement     // Just generate inline code for now.
32257b5132daSValentin Clement     // given: (x + iy) / (x' + iy')
32267b5132daSValentin Clement     // result: ((xx'+yy')/d) + i((yx'-xy')/d) where d = x'x' + y'y'
32277b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
32287b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
32297b5132daSValentin Clement     auto loc = divc.getLoc();
32307b5132daSValentin Clement     auto *ctx = divc.getContext();
32317b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
32327b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
32337b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(divc.getType()));
32347b5132daSValentin Clement     mlir::Type ty = convertType(divc.getType());
32357b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
32367b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
32377b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
32387b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
32397b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
32407b5132daSValentin Clement     auto x1x1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x1, x1);
32417b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
32427b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
32437b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
32447b5132daSValentin Clement     auto y1y1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y1, y1);
32457b5132daSValentin Clement     auto d = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, x1x1, y1y1);
32467b5132daSValentin Clement     auto rrn = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xx, yy);
32477b5132daSValentin Clement     auto rin = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, yx, xy);
32487b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rrn, d);
32497b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rin, d);
32507b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
32517b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
32527b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
32537b5132daSValentin Clement     rewriter.replaceOp(divc, r0.getResult());
325444e58509SEric Schweitz     return mlir::success();
32557b5132daSValentin Clement   }
32567b5132daSValentin Clement };
32577b5132daSValentin Clement 
32587b5132daSValentin Clement /// Inlined complex negation
32597b5132daSValentin Clement struct NegcOpConversion : public FIROpConversion<fir::NegcOp> {
32607b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
32617b5132daSValentin Clement 
32627b5132daSValentin Clement   mlir::LogicalResult
32637b5132daSValentin Clement   matchAndRewrite(fir::NegcOp neg, OpAdaptor adaptor,
32647b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
32657b5132daSValentin Clement     // given: -(x + iy)
32667b5132daSValentin Clement     // result: -x - iy
32677b5132daSValentin Clement     auto *ctxt = neg.getContext();
32687b5132daSValentin Clement     auto eleTy = convertType(getComplexEleTy(neg.getType()));
32697b5132daSValentin Clement     auto ty = convertType(neg.getType());
32707b5132daSValentin Clement     auto loc = neg.getLoc();
32717b5132daSValentin Clement     mlir::Value o0 = adaptor.getOperands()[0];
32727b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0));
32737b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1));
32747b5132daSValentin Clement     auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c0);
32757b5132daSValentin Clement     auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c1);
32767b5132daSValentin Clement     auto nrp = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, rp);
32777b5132daSValentin Clement     auto nip = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, ip);
32787b5132daSValentin Clement     auto r = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, o0, nrp, c0);
32797b5132daSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(neg, ty, r, nip, c1);
328044e58509SEric Schweitz     return mlir::success();
32817b5132daSValentin Clement   }
32827b5132daSValentin Clement };
32837b5132daSValentin Clement 
32841ed5a90fSValentin Clement /// Conversion pattern for operation that must be dead. The information in these
32851ed5a90fSValentin Clement /// operations is used by other operation. At this point they should not have
32861ed5a90fSValentin Clement /// anymore uses.
32871ed5a90fSValentin Clement /// These operations are normally dead after the pre-codegen pass.
32881ed5a90fSValentin Clement template <typename FromOp>
32891ed5a90fSValentin Clement struct MustBeDeadConversion : public FIROpConversion<FromOp> {
3290013160f6SJean Perier   explicit MustBeDeadConversion(fir::LLVMTypeConverter &lowering,
3291013160f6SJean Perier                                 const fir::FIRToLLVMPassOptions &options)
3292013160f6SJean Perier       : FIROpConversion<FromOp>(lowering, options) {}
32931ed5a90fSValentin Clement   using OpAdaptor = typename FromOp::Adaptor;
32941ed5a90fSValentin Clement 
32951ed5a90fSValentin Clement   mlir::LogicalResult
32961ed5a90fSValentin Clement   matchAndRewrite(FromOp op, OpAdaptor adaptor,
32971ed5a90fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const final {
32981ed5a90fSValentin Clement     if (!op->getUses().empty())
32991ed5a90fSValentin Clement       return rewriter.notifyMatchFailure(op, "op must be dead");
33001ed5a90fSValentin Clement     rewriter.eraseOp(op);
330144e58509SEric Schweitz     return mlir::success();
33021ed5a90fSValentin Clement   }
33031ed5a90fSValentin Clement };
33041ed5a90fSValentin Clement 
33051ed5a90fSValentin Clement struct ShapeOpConversion : public MustBeDeadConversion<fir::ShapeOp> {
33061ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
33071ed5a90fSValentin Clement };
33081ed5a90fSValentin Clement 
33091ed5a90fSValentin Clement struct ShapeShiftOpConversion : public MustBeDeadConversion<fir::ShapeShiftOp> {
33101ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
33111ed5a90fSValentin Clement };
33121ed5a90fSValentin Clement 
33131ed5a90fSValentin Clement struct ShiftOpConversion : public MustBeDeadConversion<fir::ShiftOp> {
33141ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
33151ed5a90fSValentin Clement };
33161ed5a90fSValentin Clement 
33171ed5a90fSValentin Clement struct SliceOpConversion : public MustBeDeadConversion<fir::SliceOp> {
33181ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
33191ed5a90fSValentin Clement };
33201ed5a90fSValentin Clement 
3321044d5b5dSValentin Clement } // namespace
3322044d5b5dSValentin Clement 
3323044d5b5dSValentin Clement namespace {
3324044d5b5dSValentin Clement /// Convert FIR dialect to LLVM dialect
3325044d5b5dSValentin Clement ///
3326044d5b5dSValentin Clement /// This pass lowers all FIR dialect operations to LLVM IR dialect. An
3327044d5b5dSValentin Clement /// MLIR pass is used to lower residual Std dialect to LLVM IR dialect.
3328044d5b5dSValentin Clement ///
3329044d5b5dSValentin Clement /// This pass is not complete yet. We are upstreaming it in small patches.
3330044d5b5dSValentin Clement class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> {
3331044d5b5dSValentin Clement public:
3332013160f6SJean Perier   FIRToLLVMLowering() = default;
3333013160f6SJean Perier   FIRToLLVMLowering(fir::FIRToLLVMPassOptions options) : options{options} {}
3334044d5b5dSValentin Clement   mlir::ModuleOp getModule() { return getOperation(); }
3335044d5b5dSValentin Clement 
3336044d5b5dSValentin Clement   void runOnOperation() override final {
33377b5132daSValentin Clement     auto mod = getModule();
333844e58509SEric Schweitz     if (!forcedTargetTriple.empty())
33397b5132daSValentin Clement       fir::setTargetTriple(mod, forcedTargetTriple);
33407b5132daSValentin Clement 
3341044d5b5dSValentin Clement     auto *context = getModule().getContext();
3342044d5b5dSValentin Clement     fir::LLVMTypeConverter typeConverter{getModule()};
33439f85c198SRiver Riddle     mlir::RewritePatternSet pattern(context);
3344df3b9810SValentin Clement     pattern.insert<
3345420ad7ceSAndrzej Warzynski         AbsentOpConversion, AddcOpConversion, AddrOfOpConversion,
3346c2acd453SAlexisPerry         AllocaOpConversion, AllocMemOpConversion, BoxAddrOpConversion,
3347c2acd453SAlexisPerry         BoxCharLenOpConversion, BoxDimsOpConversion, BoxEleSizeOpConversion,
3348c2acd453SAlexisPerry         BoxIsAllocOpConversion, BoxIsArrayOpConversion, BoxIsPtrOpConversion,
3349c2acd453SAlexisPerry         BoxProcHostOpConversion, BoxRankOpConversion, BoxTypeDescOpConversion,
3350c2acd453SAlexisPerry         CallOpConversion, CmpcOpConversion, ConstcOpConversion,
3351e6e7da55SAndrzej Warzynski         ConvertOpConversion, CoordinateOpConversion, DispatchOpConversion,
3352e6e7da55SAndrzej Warzynski         DispatchTableOpConversion, DTEntryOpConversion, DivcOpConversion,
3353e6e7da55SAndrzej Warzynski         EmboxOpConversion, EmboxCharOpConversion, EmboxProcOpConversion,
3354e6e7da55SAndrzej Warzynski         ExtractValueOpConversion, FieldIndexOpConversion, FirEndOpConversion,
3355dc48849fSKiran Chandramohan         FreeMemOpConversion, GenTypeDescOpConversion, GlobalLenOpConversion,
3356dc48849fSKiran Chandramohan         GlobalOpConversion, HasValueOpConversion, InsertOnRangeOpConversion,
3357e6e7da55SAndrzej Warzynski         InsertValueOpConversion, IsPresentOpConversion,
3358dc48849fSKiran Chandramohan         LenParamIndexOpConversion, LoadOpConversion, MulcOpConversion,
3359dc48849fSKiran Chandramohan         NegcOpConversion, NoReassocOpConversion, SelectCaseOpConversion,
3360e6e7da55SAndrzej Warzynski         SelectOpConversion, SelectRankOpConversion, SelectTypeOpConversion,
3361e6e7da55SAndrzej Warzynski         ShapeOpConversion, ShapeShiftOpConversion, ShiftOpConversion,
3362e6e7da55SAndrzej Warzynski         SliceOpConversion, StoreOpConversion, StringLitOpConversion,
3363e6e7da55SAndrzej Warzynski         SubcOpConversion, UnboxCharOpConversion, UnboxProcOpConversion,
3364e6e7da55SAndrzej Warzynski         UndefOpConversion, UnreachableOpConversion, XArrayCoorOpConversion,
3365013160f6SJean Perier         XEmboxOpConversion, XReboxOpConversion, ZeroOpConversion>(typeConverter,
3366013160f6SJean Perier                                                                   options);
33675a7b9194SRiver Riddle     mlir::populateFuncToLLVMConversionPatterns(typeConverter, pattern);
3368c6ac9370SKiran Chandramohan     mlir::populateOpenMPToLLVMConversionPatterns(typeConverter, pattern);
3369044d5b5dSValentin Clement     mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter,
3370044d5b5dSValentin Clement                                                             pattern);
3371ace01605SRiver Riddle     mlir::cf::populateControlFlowToLLVMConversionPatterns(typeConverter,
3372ace01605SRiver Riddle                                                           pattern);
3373044d5b5dSValentin Clement     mlir::ConversionTarget target{*context};
3374044d5b5dSValentin Clement     target.addLegalDialect<mlir::LLVM::LLVMDialect>();
3375c6ac9370SKiran Chandramohan     // The OpenMP dialect is legal for Operations without regions, for those
3376c6ac9370SKiran Chandramohan     // which contains regions it is legal if the region contains only the
337700c511b3SNimish Mishra     // LLVM dialect. Add OpenMP dialect as a legal dialect for conversion and
337800c511b3SNimish Mishra     // legalize conversion of OpenMP operations without regions.
337900c511b3SNimish Mishra     mlir::configureOpenMPToLLVMConversionLegality(target, typeConverter);
3380c6ac9370SKiran Chandramohan     target.addLegalDialect<mlir::omp::OpenMPDialect>();
3381044d5b5dSValentin Clement 
3382044d5b5dSValentin Clement     // required NOPs for applying a full conversion
3383044d5b5dSValentin Clement     target.addLegalOp<mlir::ModuleOp>();
3384044d5b5dSValentin Clement 
3385044d5b5dSValentin Clement     // apply the patterns
3386044d5b5dSValentin Clement     if (mlir::failed(mlir::applyFullConversion(getModule(), target,
3387044d5b5dSValentin Clement                                                std::move(pattern)))) {
3388044d5b5dSValentin Clement       signalPassFailure();
3389044d5b5dSValentin Clement     }
3390044d5b5dSValentin Clement   }
3391013160f6SJean Perier 
3392013160f6SJean Perier private:
3393013160f6SJean Perier   fir::FIRToLLVMPassOptions options;
3394044d5b5dSValentin Clement };
3395853e79d8SValentin Clement 
3396853e79d8SValentin Clement /// Lower from LLVM IR dialect to proper LLVM-IR and dump the module
3397853e79d8SValentin Clement struct LLVMIRLoweringPass
3398853e79d8SValentin Clement     : public mlir::PassWrapper<LLVMIRLoweringPass,
3399853e79d8SValentin Clement                                mlir::OperationPass<mlir::ModuleOp>> {
34005e50dd04SRiver Riddle   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(LLVMIRLoweringPass)
34015e50dd04SRiver Riddle 
340244e58509SEric Schweitz   LLVMIRLoweringPass(llvm::raw_ostream &output, fir::LLVMIRLoweringPrinter p)
3403853e79d8SValentin Clement       : output{output}, printer{p} {}
3404853e79d8SValentin Clement 
3405853e79d8SValentin Clement   mlir::ModuleOp getModule() { return getOperation(); }
3406853e79d8SValentin Clement 
3407853e79d8SValentin Clement   void runOnOperation() override final {
3408853e79d8SValentin Clement     auto *ctx = getModule().getContext();
3409853e79d8SValentin Clement     auto optName = getModule().getName();
3410853e79d8SValentin Clement     llvm::LLVMContext llvmCtx;
3411853e79d8SValentin Clement     if (auto llvmModule = mlir::translateModuleToLLVMIR(
3412853e79d8SValentin Clement             getModule(), llvmCtx, optName ? *optName : "FIRModule")) {
3413853e79d8SValentin Clement       printer(*llvmModule, output);
3414853e79d8SValentin Clement       return;
3415853e79d8SValentin Clement     }
3416853e79d8SValentin Clement 
3417853e79d8SValentin Clement     mlir::emitError(mlir::UnknownLoc::get(ctx), "could not emit LLVM-IR\n");
3418853e79d8SValentin Clement     signalPassFailure();
3419853e79d8SValentin Clement   }
3420853e79d8SValentin Clement 
3421853e79d8SValentin Clement private:
342244e58509SEric Schweitz   llvm::raw_ostream &output;
342344e58509SEric Schweitz   fir::LLVMIRLoweringPrinter printer;
3424853e79d8SValentin Clement };
3425853e79d8SValentin Clement 
3426044d5b5dSValentin Clement } // namespace
3427044d5b5dSValentin Clement 
3428044d5b5dSValentin Clement std::unique_ptr<mlir::Pass> fir::createFIRToLLVMPass() {
3429044d5b5dSValentin Clement   return std::make_unique<FIRToLLVMLowering>();
3430044d5b5dSValentin Clement }
3431853e79d8SValentin Clement 
3432853e79d8SValentin Clement std::unique_ptr<mlir::Pass>
343344e58509SEric Schweitz fir::createFIRToLLVMPass(fir::FIRToLLVMPassOptions options) {
3434013160f6SJean Perier   return std::make_unique<FIRToLLVMLowering>(options);
3435013160f6SJean Perier }
3436013160f6SJean Perier 
3437013160f6SJean Perier std::unique_ptr<mlir::Pass>
343844e58509SEric Schweitz fir::createLLVMDialectToLLVMPass(llvm::raw_ostream &output,
3439853e79d8SValentin Clement                                  fir::LLVMIRLoweringPrinter printer) {
3440853e79d8SValentin Clement   return std::make_unique<LLVMIRLoweringPass>(output, printer);
3441853e79d8SValentin Clement }
3442