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"
24044d5b5dSValentin Clement #include "mlir/Conversion/LLVMCommon/Pattern.h"
25044d5b5dSValentin Clement #include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h"
26044d5b5dSValentin Clement #include "mlir/IR/BuiltinTypes.h"
273ae8e442SValentin Clement #include "mlir/IR/Matchers.h"
28044d5b5dSValentin Clement #include "mlir/Pass/Pass.h"
29853e79d8SValentin Clement #include "mlir/Target/LLVMIR/ModuleTranslation.h"
30044d5b5dSValentin Clement #include "llvm/ADT/ArrayRef.h"
31044d5b5dSValentin Clement 
32044d5b5dSValentin Clement #define DEBUG_TYPE "flang-codegen"
33044d5b5dSValentin Clement 
34044d5b5dSValentin Clement // fir::LLVMTypeConverter for converting to LLVM IR dialect types.
35044d5b5dSValentin Clement #include "TypeConverter.h"
36044d5b5dSValentin Clement 
37af6ee580SValentin Clement // TODO: This should really be recovered from the specified target.
38af6ee580SValentin Clement static constexpr unsigned defaultAlign = 8;
39af6ee580SValentin Clement 
40b6e44ecdSValentin Clement /// `fir.box` attribute values as defined for CFI_attribute_t in
41b6e44ecdSValentin Clement /// flang/ISO_Fortran_binding.h.
42b6e44ecdSValentin Clement static constexpr unsigned kAttrPointer = CFI_attribute_pointer;
43b6e44ecdSValentin Clement static constexpr unsigned kAttrAllocatable = CFI_attribute_allocatable;
44b6e44ecdSValentin Clement 
45135d5d4aSKiran Chandramohan static inline mlir::Type getVoidPtrType(mlir::MLIRContext *context) {
46fa517555SKiran Chandramohan   return mlir::LLVM::LLVMPointerType::get(mlir::IntegerType::get(context, 8));
47fa517555SKiran Chandramohan }
48fa517555SKiran Chandramohan 
491e6d9c06SDiana Picus static mlir::LLVM::ConstantOp
501e6d9c06SDiana Picus genConstantIndex(mlir::Location loc, mlir::Type ity,
511e6d9c06SDiana Picus                  mlir::ConversionPatternRewriter &rewriter,
521e6d9c06SDiana Picus                  std::int64_t offset) {
531e6d9c06SDiana Picus   auto cattr = rewriter.getI64IntegerAttr(offset);
541e6d9c06SDiana Picus   return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr);
551e6d9c06SDiana Picus }
561e6d9c06SDiana Picus 
5739f4ef81SValentin Clement static Block *createBlock(mlir::ConversionPatternRewriter &rewriter,
5839f4ef81SValentin Clement                           mlir::Block *insertBefore) {
5939f4ef81SValentin Clement   assert(insertBefore && "expected valid insertion block");
6039f4ef81SValentin Clement   return rewriter.createBlock(insertBefore->getParent(),
6139f4ef81SValentin Clement                               mlir::Region::iterator(insertBefore));
6239f4ef81SValentin Clement }
6339f4ef81SValentin Clement 
64044d5b5dSValentin Clement namespace {
65044d5b5dSValentin Clement /// FIR conversion pattern template
66044d5b5dSValentin Clement template <typename FromOp>
67044d5b5dSValentin Clement class FIROpConversion : public mlir::ConvertOpToLLVMPattern<FromOp> {
68044d5b5dSValentin Clement public:
69044d5b5dSValentin Clement   explicit FIROpConversion(fir::LLVMTypeConverter &lowering)
70044d5b5dSValentin Clement       : mlir::ConvertOpToLLVMPattern<FromOp>(lowering) {}
71044d5b5dSValentin Clement 
72044d5b5dSValentin Clement protected:
73044d5b5dSValentin Clement   mlir::Type convertType(mlir::Type ty) const {
74044d5b5dSValentin Clement     return lowerTy().convertType(ty);
75044d5b5dSValentin Clement   }
76c2acd453SAlexisPerry   mlir::Type voidPtrTy() const { return getVoidPtrType(); }
77044d5b5dSValentin Clement 
785d27abe6SValentin Clement   mlir::Type getVoidPtrType() const {
795d27abe6SValentin Clement     return mlir::LLVM::LLVMPointerType::get(
805d27abe6SValentin Clement         mlir::IntegerType::get(&lowerTy().getContext(), 8));
815d27abe6SValentin Clement   }
825d27abe6SValentin Clement 
83df3b9810SValentin Clement   mlir::LLVM::ConstantOp
84af6ee580SValentin Clement   genI32Constant(mlir::Location loc, mlir::ConversionPatternRewriter &rewriter,
85af6ee580SValentin Clement                  int value) const {
86af6ee580SValentin Clement     mlir::Type i32Ty = rewriter.getI32Type();
87af6ee580SValentin Clement     mlir::IntegerAttr attr = rewriter.getI32IntegerAttr(value);
88af6ee580SValentin Clement     return rewriter.create<mlir::LLVM::ConstantOp>(loc, i32Ty, attr);
89af6ee580SValentin Clement   }
90af6ee580SValentin Clement 
91af6ee580SValentin Clement   mlir::LLVM::ConstantOp
92df3b9810SValentin Clement   genConstantOffset(mlir::Location loc,
93df3b9810SValentin Clement                     mlir::ConversionPatternRewriter &rewriter,
94df3b9810SValentin Clement                     int offset) const {
95af6ee580SValentin Clement     mlir::Type ity = lowerTy().offsetType();
96af6ee580SValentin Clement     mlir::IntegerAttr cattr = rewriter.getI32IntegerAttr(offset);
97df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr);
98df3b9810SValentin Clement   }
99df3b9810SValentin Clement 
100*dc48849fSKiran Chandramohan   /// Perform an extension or truncation as needed on an integer value. Lowering
101*dc48849fSKiran Chandramohan   /// to the specific target may involve some sign-extending or truncation of
102*dc48849fSKiran Chandramohan   /// values, particularly to fit them from abstract box types to the
103*dc48849fSKiran Chandramohan   /// appropriate reified structures.
104*dc48849fSKiran Chandramohan   mlir::Value integerCast(mlir::Location loc,
105*dc48849fSKiran Chandramohan                           mlir::ConversionPatternRewriter &rewriter,
106*dc48849fSKiran Chandramohan                           mlir::Type ty, mlir::Value val) const {
107*dc48849fSKiran Chandramohan     auto valTy = val.getType();
108*dc48849fSKiran Chandramohan     // If the value was not yet lowered, lower its type so that it can
109*dc48849fSKiran Chandramohan     // be used in getPrimitiveTypeSizeInBits.
110*dc48849fSKiran Chandramohan     if (!valTy.isa<mlir::IntegerType>())
111*dc48849fSKiran Chandramohan       valTy = convertType(valTy);
112*dc48849fSKiran Chandramohan     auto toSize = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
113*dc48849fSKiran Chandramohan     auto fromSize = mlir::LLVM::getPrimitiveTypeSizeInBits(valTy);
114*dc48849fSKiran Chandramohan     if (toSize < fromSize)
115*dc48849fSKiran Chandramohan       return rewriter.create<mlir::LLVM::TruncOp>(loc, ty, val);
116*dc48849fSKiran Chandramohan     if (toSize > fromSize)
117*dc48849fSKiran Chandramohan       return rewriter.create<mlir::LLVM::SExtOp>(loc, ty, val);
118*dc48849fSKiran Chandramohan     return val;
119*dc48849fSKiran Chandramohan   }
120*dc48849fSKiran Chandramohan 
121b6e44ecdSValentin Clement   /// Construct code sequence to extract the specifc value from a `fir.box`.
122b6e44ecdSValentin Clement   mlir::Value getValueFromBox(mlir::Location loc, mlir::Value box,
123df3b9810SValentin Clement                               mlir::Type resultTy,
124b6e44ecdSValentin Clement                               mlir::ConversionPatternRewriter &rewriter,
125b6e44ecdSValentin Clement                               unsigned boxValue) const {
126df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
127b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp cValuePos =
128b6e44ecdSValentin Clement         genConstantOffset(loc, rewriter, boxValue);
129df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(resultTy);
130df3b9810SValentin Clement     auto p = rewriter.create<mlir::LLVM::GEPOp>(
13130122656SAlex Zinenko         loc, pty, box, mlir::ValueRange{c0, cValuePos});
132df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, resultTy, p);
133df3b9810SValentin Clement   }
134df3b9810SValentin Clement 
135df3b9810SValentin Clement   /// Method to construct code sequence to get the triple for dimension `dim`
136df3b9810SValentin Clement   /// from a box.
137df3b9810SValentin Clement   SmallVector<mlir::Value, 3>
138df3b9810SValentin Clement   getDimsFromBox(mlir::Location loc, ArrayRef<mlir::Type> retTys,
139df3b9810SValentin Clement                  mlir::Value box, mlir::Value dim,
140df3b9810SValentin Clement                  mlir::ConversionPatternRewriter &rewriter) const {
141df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
142df3b9810SValentin Clement     mlir::LLVM::ConstantOp cDims =
143df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kDimsPosInBox);
144df3b9810SValentin Clement     mlir::LLVM::LoadOp l0 =
145df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 0, retTys[0], rewriter);
146df3b9810SValentin Clement     mlir::LLVM::LoadOp l1 =
147df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 1, retTys[1], rewriter);
148df3b9810SValentin Clement     mlir::LLVM::LoadOp l2 =
149df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 2, retTys[2], rewriter);
150df3b9810SValentin Clement     return {l0.getResult(), l1.getResult(), l2.getResult()};
151df3b9810SValentin Clement   }
152df3b9810SValentin Clement 
153df3b9810SValentin Clement   mlir::LLVM::LoadOp
154df3b9810SValentin Clement   loadFromOffset(mlir::Location loc, mlir::Value a, mlir::LLVM::ConstantOp c0,
155df3b9810SValentin Clement                  mlir::LLVM::ConstantOp cDims, mlir::Value dim, int off,
156df3b9810SValentin Clement                  mlir::Type ty,
157df3b9810SValentin Clement                  mlir::ConversionPatternRewriter &rewriter) const {
158df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
159df3b9810SValentin Clement     mlir::LLVM::ConstantOp c = genConstantOffset(loc, rewriter, off);
160df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, a, c0, cDims, dim, c);
161df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
162df3b9810SValentin Clement   }
163df3b9810SValentin Clement 
1645d27abe6SValentin Clement   mlir::Value
1655d27abe6SValentin Clement   loadStrideFromBox(mlir::Location loc, mlir::Value box, unsigned dim,
1665d27abe6SValentin Clement                     mlir::ConversionPatternRewriter &rewriter) const {
1675d27abe6SValentin Clement     auto idxTy = lowerTy().indexType();
1685d27abe6SValentin Clement     auto c0 = genConstantOffset(loc, rewriter, 0);
1695d27abe6SValentin Clement     auto cDims = genConstantOffset(loc, rewriter, kDimsPosInBox);
1705d27abe6SValentin Clement     auto dimValue = genConstantIndex(loc, idxTy, rewriter, dim);
1715d27abe6SValentin Clement     return loadFromOffset(loc, box, c0, cDims, dimValue, kDimStridePos, idxTy,
1725d27abe6SValentin Clement                           rewriter);
1735d27abe6SValentin Clement   }
1745d27abe6SValentin Clement 
175df3b9810SValentin Clement   /// Read base address from a fir.box. Returned address has type ty.
176df3b9810SValentin Clement   mlir::Value
177df3b9810SValentin Clement   loadBaseAddrFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box,
178df3b9810SValentin Clement                       mlir::ConversionPatternRewriter &rewriter) const {
179df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
180df3b9810SValentin Clement     mlir::LLVM::ConstantOp cAddr =
181df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kAddrPosInBox);
182df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
183df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cAddr);
184df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
185df3b9810SValentin Clement   }
186df3b9810SValentin Clement 
187df3b9810SValentin Clement   mlir::Value
188df3b9810SValentin Clement   loadElementSizeFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box,
189df3b9810SValentin Clement                          mlir::ConversionPatternRewriter &rewriter) const {
190df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
191df3b9810SValentin Clement     mlir::LLVM::ConstantOp cElemLen =
192df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kElemLenPosInBox);
193df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
194df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cElemLen);
195df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
196df3b9810SValentin Clement   }
197df3b9810SValentin Clement 
198af6ee580SValentin Clement   // Get the element type given an LLVM type that is of the form
199af6ee580SValentin Clement   // [llvm.ptr](array|struct|vector)+ and the provided indexes.
200af6ee580SValentin Clement   static mlir::Type getBoxEleTy(mlir::Type type,
201af6ee580SValentin Clement                                 llvm::ArrayRef<unsigned> indexes) {
202af6ee580SValentin Clement     if (auto t = type.dyn_cast<mlir::LLVM::LLVMPointerType>())
203af6ee580SValentin Clement       type = t.getElementType();
204af6ee580SValentin Clement     for (auto i : indexes) {
205af6ee580SValentin Clement       if (auto t = type.dyn_cast<mlir::LLVM::LLVMStructType>()) {
206af6ee580SValentin Clement         assert(!t.isOpaque() && i < t.getBody().size());
207af6ee580SValentin Clement         type = t.getBody()[i];
208af6ee580SValentin Clement       } else if (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
209af6ee580SValentin Clement         type = t.getElementType();
210af6ee580SValentin Clement       } else if (auto t = type.dyn_cast<mlir::VectorType>()) {
211af6ee580SValentin Clement         type = t.getElementType();
212af6ee580SValentin Clement       } else {
213af6ee580SValentin Clement         fir::emitFatalError(mlir::UnknownLoc::get(type.getContext()),
214af6ee580SValentin Clement                             "request for invalid box element type");
215af6ee580SValentin Clement       }
216af6ee580SValentin Clement     }
217af6ee580SValentin Clement     return type;
218af6ee580SValentin Clement   }
219af6ee580SValentin Clement 
2205d27abe6SValentin Clement   // Return LLVM type of the base address given the LLVM type
2215d27abe6SValentin Clement   // of the related descriptor (lowered fir.box type).
2225d27abe6SValentin Clement   static mlir::Type getBaseAddrTypeFromBox(mlir::Type type) {
2235d27abe6SValentin Clement     return getBoxEleTy(type, {kAddrPosInBox});
2245d27abe6SValentin Clement   }
2255d27abe6SValentin Clement 
226*dc48849fSKiran Chandramohan   // Load the attribute from the \p box and perform a check against \p maskValue
227*dc48849fSKiran Chandramohan   // The final comparison is implemented as `(attribute & maskValue) != 0`.
228*dc48849fSKiran Chandramohan   mlir::Value genBoxAttributeCheck(mlir::Location loc, mlir::Value box,
229*dc48849fSKiran Chandramohan                                    mlir::ConversionPatternRewriter &rewriter,
230*dc48849fSKiran Chandramohan                                    unsigned maskValue) const {
231*dc48849fSKiran Chandramohan     mlir::Type attrTy = rewriter.getI32Type();
232*dc48849fSKiran Chandramohan     mlir::Value attribute =
233*dc48849fSKiran Chandramohan         getValueFromBox(loc, box, attrTy, rewriter, kAttributePosInBox);
234*dc48849fSKiran Chandramohan     mlir::LLVM::ConstantOp attrMask =
235*dc48849fSKiran Chandramohan         genConstantOffset(loc, rewriter, maskValue);
236*dc48849fSKiran Chandramohan     auto maskRes =
237*dc48849fSKiran Chandramohan         rewriter.create<mlir::LLVM::AndOp>(loc, attrTy, attribute, attrMask);
238*dc48849fSKiran Chandramohan     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
239*dc48849fSKiran Chandramohan     return rewriter.create<mlir::LLVM::ICmpOp>(
240*dc48849fSKiran Chandramohan         loc, mlir::LLVM::ICmpPredicate::ne, maskRes, c0);
241*dc48849fSKiran Chandramohan   }
242*dc48849fSKiran Chandramohan 
243df3b9810SValentin Clement   template <typename... ARGS>
244df3b9810SValentin Clement   mlir::LLVM::GEPOp genGEP(mlir::Location loc, mlir::Type ty,
245df3b9810SValentin Clement                            mlir::ConversionPatternRewriter &rewriter,
246df3b9810SValentin Clement                            mlir::Value base, ARGS... args) const {
247df3b9810SValentin Clement     SmallVector<mlir::Value> cv{args...};
248df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::GEPOp>(loc, ty, base, cv);
249df3b9810SValentin Clement   }
250df3b9810SValentin Clement 
251044d5b5dSValentin Clement   fir::LLVMTypeConverter &lowerTy() const {
252044d5b5dSValentin Clement     return *static_cast<fir::LLVMTypeConverter *>(this->getTypeConverter());
253044d5b5dSValentin Clement   }
254044d5b5dSValentin Clement };
255044d5b5dSValentin Clement 
2563ae8e442SValentin Clement /// FIR conversion pattern template
2573ae8e442SValentin Clement template <typename FromOp>
2583ae8e442SValentin Clement class FIROpAndTypeConversion : public FIROpConversion<FromOp> {
2593ae8e442SValentin Clement public:
2603ae8e442SValentin Clement   using FIROpConversion<FromOp>::FIROpConversion;
2613ae8e442SValentin Clement   using OpAdaptor = typename FromOp::Adaptor;
2623ae8e442SValentin Clement 
2633ae8e442SValentin Clement   mlir::LogicalResult
2643ae8e442SValentin Clement   matchAndRewrite(FromOp op, OpAdaptor adaptor,
2653ae8e442SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const final {
2663ae8e442SValentin Clement     mlir::Type ty = this->convertType(op.getType());
2673ae8e442SValentin Clement     return doRewrite(op, ty, adaptor, rewriter);
2683ae8e442SValentin Clement   }
2693ae8e442SValentin Clement 
2703ae8e442SValentin Clement   virtual mlir::LogicalResult
2713ae8e442SValentin Clement   doRewrite(FromOp addr, mlir::Type ty, OpAdaptor adaptor,
2723ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const = 0;
2733ae8e442SValentin Clement };
2743ae8e442SValentin Clement 
2750c4a7a52SValentin Clement // Lower `fir.address_of` operation to `llvm.address_of` operation.
276044d5b5dSValentin Clement struct AddrOfOpConversion : public FIROpConversion<fir::AddrOfOp> {
277044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
278044d5b5dSValentin Clement 
279044d5b5dSValentin Clement   mlir::LogicalResult
280044d5b5dSValentin Clement   matchAndRewrite(fir::AddrOfOp addr, OpAdaptor adaptor,
281044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
282044d5b5dSValentin Clement     auto ty = convertType(addr.getType());
283044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::AddressOfOp>(
284149ad3d5SShraiysh Vaishay         addr, ty, addr.getSymbol().getRootReference().getValue());
285044d5b5dSValentin Clement     return success();
286044d5b5dSValentin Clement   }
287044d5b5dSValentin Clement };
2881e6d9c06SDiana Picus } // namespace
2891e6d9c06SDiana Picus 
2901e6d9c06SDiana Picus /// Lookup the function to compute the memory size of this parametric derived
2911e6d9c06SDiana Picus /// type. The size of the object may depend on the LEN type parameters of the
2921e6d9c06SDiana Picus /// derived type.
2931e6d9c06SDiana Picus static mlir::LLVM::LLVMFuncOp
2941e6d9c06SDiana Picus getDependentTypeMemSizeFn(fir::RecordType recTy, fir::AllocaOp op,
2951e6d9c06SDiana Picus                           mlir::ConversionPatternRewriter &rewriter) {
2961e6d9c06SDiana Picus   auto module = op->getParentOfType<mlir::ModuleOp>();
2971e6d9c06SDiana Picus   std::string name = recTy.getName().str() + "P.mem.size";
2981e6d9c06SDiana Picus   return module.lookupSymbol<mlir::LLVM::LLVMFuncOp>(name);
2991e6d9c06SDiana Picus }
3001e6d9c06SDiana Picus 
3011e6d9c06SDiana Picus namespace {
3021e6d9c06SDiana Picus /// convert to LLVM IR dialect `alloca`
3031e6d9c06SDiana Picus struct AllocaOpConversion : public FIROpConversion<fir::AllocaOp> {
3041e6d9c06SDiana Picus   using FIROpConversion::FIROpConversion;
3051e6d9c06SDiana Picus 
3061e6d9c06SDiana Picus   mlir::LogicalResult
3071e6d9c06SDiana Picus   matchAndRewrite(fir::AllocaOp alloc, OpAdaptor adaptor,
3081e6d9c06SDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
3091e6d9c06SDiana Picus     mlir::ValueRange operands = adaptor.getOperands();
3101e6d9c06SDiana Picus     auto loc = alloc.getLoc();
3111e6d9c06SDiana Picus     mlir::Type ity = lowerTy().indexType();
3121e6d9c06SDiana Picus     unsigned i = 0;
3131e6d9c06SDiana Picus     mlir::Value size = genConstantIndex(loc, ity, rewriter, 1).getResult();
3141e6d9c06SDiana Picus     mlir::Type ty = convertType(alloc.getType());
3151e6d9c06SDiana Picus     mlir::Type resultTy = ty;
3161e6d9c06SDiana Picus     if (alloc.hasLenParams()) {
3171e6d9c06SDiana Picus       unsigned end = alloc.numLenParams();
3181e6d9c06SDiana Picus       llvm::SmallVector<mlir::Value> lenParams;
3191e6d9c06SDiana Picus       for (; i < end; ++i)
3201e6d9c06SDiana Picus         lenParams.push_back(operands[i]);
3211e6d9c06SDiana Picus       mlir::Type scalarType = fir::unwrapSequenceType(alloc.getInType());
3221e6d9c06SDiana Picus       if (auto chrTy = scalarType.dyn_cast<fir::CharacterType>()) {
3231e6d9c06SDiana Picus         fir::CharacterType rawCharTy = fir::CharacterType::getUnknownLen(
3241e6d9c06SDiana Picus             chrTy.getContext(), chrTy.getFKind());
3251e6d9c06SDiana Picus         ty = mlir::LLVM::LLVMPointerType::get(convertType(rawCharTy));
3261e6d9c06SDiana Picus         assert(end == 1);
3271e6d9c06SDiana Picus         size = integerCast(loc, rewriter, ity, lenParams[0]);
3281e6d9c06SDiana Picus       } else if (auto recTy = scalarType.dyn_cast<fir::RecordType>()) {
3291e6d9c06SDiana Picus         mlir::LLVM::LLVMFuncOp memSizeFn =
3301e6d9c06SDiana Picus             getDependentTypeMemSizeFn(recTy, alloc, rewriter);
3311e6d9c06SDiana Picus         if (!memSizeFn)
3321e6d9c06SDiana Picus           emitError(loc, "did not find allocation function");
3331e6d9c06SDiana Picus         mlir::NamedAttribute attr = rewriter.getNamedAttr(
3341e6d9c06SDiana Picus             "callee", mlir::SymbolRefAttr::get(memSizeFn));
3351e6d9c06SDiana Picus         auto call = rewriter.create<mlir::LLVM::CallOp>(
3361e6d9c06SDiana Picus             loc, ity, lenParams, llvm::ArrayRef<mlir::NamedAttribute>{attr});
3371e6d9c06SDiana Picus         size = call.getResult(0);
3381e6d9c06SDiana Picus         ty = mlir::LLVM::LLVMPointerType::get(
3391e6d9c06SDiana Picus             mlir::IntegerType::get(alloc.getContext(), 8));
3401e6d9c06SDiana Picus       } else {
3411e6d9c06SDiana Picus         return emitError(loc, "unexpected type ")
3421e6d9c06SDiana Picus                << scalarType << " with type parameters";
3431e6d9c06SDiana Picus       }
3441e6d9c06SDiana Picus     }
3451e6d9c06SDiana Picus     if (alloc.hasShapeOperands()) {
3461e6d9c06SDiana Picus       mlir::Type allocEleTy = fir::unwrapRefType(alloc.getType());
3471e6d9c06SDiana Picus       // Scale the size by constant factors encoded in the array type.
348776d0ed6SDiana Picus       // We only do this for arrays that don't have a constant interior, since
349776d0ed6SDiana Picus       // those are the only ones that get decayed to a pointer to the element
350776d0ed6SDiana Picus       // type.
3511e6d9c06SDiana Picus       if (auto seqTy = allocEleTy.dyn_cast<fir::SequenceType>()) {
352776d0ed6SDiana Picus         if (!seqTy.hasConstantInterior()) {
3531e6d9c06SDiana Picus           fir::SequenceType::Extent constSize = 1;
3541e6d9c06SDiana Picus           for (auto extent : seqTy.getShape())
3551e6d9c06SDiana Picus             if (extent != fir::SequenceType::getUnknownExtent())
3561e6d9c06SDiana Picus               constSize *= extent;
3571e6d9c06SDiana Picus           mlir::Value constVal{
3581e6d9c06SDiana Picus               genConstantIndex(loc, ity, rewriter, constSize).getResult()};
3591e6d9c06SDiana Picus           size = rewriter.create<mlir::LLVM::MulOp>(loc, ity, size, constVal);
3601e6d9c06SDiana Picus         }
361776d0ed6SDiana Picus       }
3621e6d9c06SDiana Picus       unsigned end = operands.size();
3631e6d9c06SDiana Picus       for (; i < end; ++i)
3641e6d9c06SDiana Picus         size = rewriter.create<mlir::LLVM::MulOp>(
3651e6d9c06SDiana Picus             loc, ity, size, integerCast(loc, rewriter, ity, operands[i]));
3661e6d9c06SDiana Picus     }
3671e6d9c06SDiana Picus     if (ty == resultTy) {
3681e6d9c06SDiana Picus       // Do not emit the bitcast if ty and resultTy are the same.
3691e6d9c06SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::AllocaOp>(alloc, ty, size,
3701e6d9c06SDiana Picus                                                         alloc->getAttrs());
3711e6d9c06SDiana Picus     } else {
3721e6d9c06SDiana Picus       auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, ty, size,
3731e6d9c06SDiana Picus                                                       alloc->getAttrs());
3741e6d9c06SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(alloc, resultTy, al);
3751e6d9c06SDiana Picus     }
3761e6d9c06SDiana Picus     return success();
3771e6d9c06SDiana Picus   }
3781e6d9c06SDiana Picus };
379*dc48849fSKiran Chandramohan } // namespace
380044d5b5dSValentin Clement 
381*dc48849fSKiran Chandramohan /// Construct an `llvm.extractvalue` instruction. It will return value at
382*dc48849fSKiran Chandramohan /// element \p x from  \p tuple.
383*dc48849fSKiran Chandramohan static mlir::LLVM::ExtractValueOp
384*dc48849fSKiran Chandramohan genExtractValueWithIndex(mlir::Location loc, mlir::Value tuple, mlir::Type ty,
385*dc48849fSKiran Chandramohan                          mlir::ConversionPatternRewriter &rewriter,
386*dc48849fSKiran Chandramohan                          mlir::MLIRContext *ctx, int x) {
387*dc48849fSKiran Chandramohan   auto cx = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(x));
388*dc48849fSKiran Chandramohan   auto xty = ty.cast<mlir::LLVM::LLVMStructType>().getBody()[x];
389*dc48849fSKiran Chandramohan   return rewriter.create<mlir::LLVM::ExtractValueOp>(loc, xty, tuple, cx);
390*dc48849fSKiran Chandramohan }
391*dc48849fSKiran Chandramohan 
392*dc48849fSKiran Chandramohan namespace {
393df3b9810SValentin Clement /// Lower `fir.box_addr` to the sequence of operations to extract the first
394df3b9810SValentin Clement /// element of the box.
395df3b9810SValentin Clement struct BoxAddrOpConversion : public FIROpConversion<fir::BoxAddrOp> {
396df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
397df3b9810SValentin Clement 
398df3b9810SValentin Clement   mlir::LogicalResult
399df3b9810SValentin Clement   matchAndRewrite(fir::BoxAddrOp boxaddr, OpAdaptor adaptor,
400df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
401df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
402df3b9810SValentin Clement     auto loc = boxaddr.getLoc();
403df3b9810SValentin Clement     mlir::Type ty = convertType(boxaddr.getType());
404149ad3d5SShraiysh Vaishay     if (auto argty = boxaddr.getVal().getType().dyn_cast<fir::BoxType>()) {
405df3b9810SValentin Clement       rewriter.replaceOp(boxaddr, loadBaseAddrFromBox(loc, ty, a, rewriter));
406df3b9810SValentin Clement     } else {
407df3b9810SValentin Clement       auto c0attr = rewriter.getI32IntegerAttr(0);
408df3b9810SValentin Clement       auto c0 = mlir::ArrayAttr::get(boxaddr.getContext(), c0attr);
409df3b9810SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(boxaddr, ty, a,
410df3b9810SValentin Clement                                                               c0);
411df3b9810SValentin Clement     }
412df3b9810SValentin Clement     return success();
413df3b9810SValentin Clement   }
414df3b9810SValentin Clement };
415df3b9810SValentin Clement 
416*dc48849fSKiran Chandramohan /// Convert `!fir.boxchar_len` to  `!llvm.extractvalue` for the 2nd part of the
417*dc48849fSKiran Chandramohan /// boxchar.
418*dc48849fSKiran Chandramohan struct BoxCharLenOpConversion : public FIROpConversion<fir::BoxCharLenOp> {
419*dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
420*dc48849fSKiran Chandramohan 
421*dc48849fSKiran Chandramohan   mlir::LogicalResult
422*dc48849fSKiran Chandramohan   matchAndRewrite(fir::BoxCharLenOp boxCharLen, OpAdaptor adaptor,
423*dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
424*dc48849fSKiran Chandramohan     mlir::Value boxChar = adaptor.getOperands()[0];
425*dc48849fSKiran Chandramohan     mlir::Location loc = boxChar.getLoc();
426*dc48849fSKiran Chandramohan     mlir::MLIRContext *ctx = boxChar.getContext();
427*dc48849fSKiran Chandramohan     mlir::Type returnValTy = boxCharLen.getResult().getType();
428*dc48849fSKiran Chandramohan 
429*dc48849fSKiran Chandramohan     constexpr int boxcharLenIdx = 1;
430*dc48849fSKiran Chandramohan     mlir::LLVM::ExtractValueOp len = genExtractValueWithIndex(
431*dc48849fSKiran Chandramohan         loc, boxChar, boxChar.getType(), rewriter, ctx, boxcharLenIdx);
432*dc48849fSKiran Chandramohan     mlir::Value lenAfterCast = integerCast(loc, rewriter, returnValTy, len);
433*dc48849fSKiran Chandramohan     rewriter.replaceOp(boxCharLen, lenAfterCast);
434*dc48849fSKiran Chandramohan 
435*dc48849fSKiran Chandramohan     return success();
436*dc48849fSKiran Chandramohan   }
437*dc48849fSKiran Chandramohan };
438*dc48849fSKiran Chandramohan 
439df3b9810SValentin Clement /// Lower `fir.box_dims` to a sequence of operations to extract the requested
440df3b9810SValentin Clement /// dimension infomartion from the boxed value.
441df3b9810SValentin Clement /// Result in a triple set of GEPs and loads.
442df3b9810SValentin Clement struct BoxDimsOpConversion : public FIROpConversion<fir::BoxDimsOp> {
443df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
444df3b9810SValentin Clement 
445df3b9810SValentin Clement   mlir::LogicalResult
446df3b9810SValentin Clement   matchAndRewrite(fir::BoxDimsOp boxdims, OpAdaptor adaptor,
447df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
448df3b9810SValentin Clement     SmallVector<mlir::Type, 3> resultTypes = {
449df3b9810SValentin Clement         convertType(boxdims.getResult(0).getType()),
450df3b9810SValentin Clement         convertType(boxdims.getResult(1).getType()),
451df3b9810SValentin Clement         convertType(boxdims.getResult(2).getType()),
452df3b9810SValentin Clement     };
453df3b9810SValentin Clement     auto results =
454df3b9810SValentin Clement         getDimsFromBox(boxdims.getLoc(), resultTypes, adaptor.getOperands()[0],
455df3b9810SValentin Clement                        adaptor.getOperands()[1], rewriter);
456df3b9810SValentin Clement     rewriter.replaceOp(boxdims, results);
457df3b9810SValentin Clement     return success();
458df3b9810SValentin Clement   }
459df3b9810SValentin Clement };
460df3b9810SValentin Clement 
461df3b9810SValentin Clement /// Lower `fir.box_elesize` to a sequence of operations ro extract the size of
462df3b9810SValentin Clement /// an element in the boxed value.
463df3b9810SValentin Clement struct BoxEleSizeOpConversion : public FIROpConversion<fir::BoxEleSizeOp> {
464df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
465df3b9810SValentin Clement 
466df3b9810SValentin Clement   mlir::LogicalResult
467df3b9810SValentin Clement   matchAndRewrite(fir::BoxEleSizeOp boxelesz, OpAdaptor adaptor,
468df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
469df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
470df3b9810SValentin Clement     auto loc = boxelesz.getLoc();
471df3b9810SValentin Clement     auto ty = convertType(boxelesz.getType());
472b6e44ecdSValentin Clement     auto elemSize = getValueFromBox(loc, a, ty, rewriter, kElemLenPosInBox);
473b6e44ecdSValentin Clement     rewriter.replaceOp(boxelesz, elemSize);
474b6e44ecdSValentin Clement     return success();
475b6e44ecdSValentin Clement   }
476b6e44ecdSValentin Clement };
477b6e44ecdSValentin Clement 
478b6e44ecdSValentin Clement /// Lower `fir.box_isalloc` to a sequence of operations to determine if the
479b6e44ecdSValentin Clement /// boxed value was from an ALLOCATABLE entity.
480b6e44ecdSValentin Clement struct BoxIsAllocOpConversion : public FIROpConversion<fir::BoxIsAllocOp> {
481b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
482b6e44ecdSValentin Clement 
483b6e44ecdSValentin Clement   mlir::LogicalResult
484b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsAllocOp boxisalloc, OpAdaptor adaptor,
485b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
486b6e44ecdSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
487b6e44ecdSValentin Clement     auto loc = boxisalloc.getLoc();
488b6e44ecdSValentin Clement     mlir::Value check =
489b6e44ecdSValentin Clement         genBoxAttributeCheck(loc, box, rewriter, kAttrAllocatable);
490b6e44ecdSValentin Clement     rewriter.replaceOp(boxisalloc, check);
491b6e44ecdSValentin Clement     return success();
492b6e44ecdSValentin Clement   }
493b6e44ecdSValentin Clement };
494b6e44ecdSValentin Clement 
495b6e44ecdSValentin Clement /// Lower `fir.box_isarray` to a sequence of operations to determine if the
496b6e44ecdSValentin Clement /// boxed is an array.
497b6e44ecdSValentin Clement struct BoxIsArrayOpConversion : public FIROpConversion<fir::BoxIsArrayOp> {
498b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
499b6e44ecdSValentin Clement 
500b6e44ecdSValentin Clement   mlir::LogicalResult
501b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsArrayOp boxisarray, OpAdaptor adaptor,
502b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
503b6e44ecdSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
504b6e44ecdSValentin Clement     auto loc = boxisarray.getLoc();
505b6e44ecdSValentin Clement     auto rank =
506b6e44ecdSValentin Clement         getValueFromBox(loc, a, rewriter.getI32Type(), rewriter, kRankPosInBox);
507b6e44ecdSValentin Clement     auto c0 = genConstantOffset(loc, rewriter, 0);
508b6e44ecdSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
509b6e44ecdSValentin Clement         boxisarray, mlir::LLVM::ICmpPredicate::ne, rank, c0);
510b6e44ecdSValentin Clement     return success();
511b6e44ecdSValentin Clement   }
512b6e44ecdSValentin Clement };
513b6e44ecdSValentin Clement 
514b6e44ecdSValentin Clement /// Lower `fir.box_isptr` to a sequence of operations to determined if the
515b6e44ecdSValentin Clement /// boxed value was from a POINTER entity.
516b6e44ecdSValentin Clement struct BoxIsPtrOpConversion : public FIROpConversion<fir::BoxIsPtrOp> {
517b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
518b6e44ecdSValentin Clement 
519b6e44ecdSValentin Clement   mlir::LogicalResult
520b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsPtrOp boxisptr, OpAdaptor adaptor,
521b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
522b6e44ecdSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
523b6e44ecdSValentin Clement     auto loc = boxisptr.getLoc();
524b6e44ecdSValentin Clement     mlir::Value check = genBoxAttributeCheck(loc, box, rewriter, kAttrPointer);
525b6e44ecdSValentin Clement     rewriter.replaceOp(boxisptr, check);
526df3b9810SValentin Clement     return success();
527df3b9810SValentin Clement   }
528df3b9810SValentin Clement };
529df3b9810SValentin Clement 
530df3b9810SValentin Clement /// Lower `fir.box_rank` to the sequence of operation to extract the rank from
531df3b9810SValentin Clement /// the box.
532df3b9810SValentin Clement struct BoxRankOpConversion : public FIROpConversion<fir::BoxRankOp> {
533df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
534df3b9810SValentin Clement 
535df3b9810SValentin Clement   mlir::LogicalResult
536df3b9810SValentin Clement   matchAndRewrite(fir::BoxRankOp boxrank, OpAdaptor adaptor,
537df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
538df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
539df3b9810SValentin Clement     auto loc = boxrank.getLoc();
540df3b9810SValentin Clement     mlir::Type ty = convertType(boxrank.getType());
541b6e44ecdSValentin Clement     auto result = getValueFromBox(loc, a, ty, rewriter, kRankPosInBox);
542df3b9810SValentin Clement     rewriter.replaceOp(boxrank, result);
543df3b9810SValentin Clement     return success();
544df3b9810SValentin Clement   }
545df3b9810SValentin Clement };
546df3b9810SValentin Clement 
547cc505c0bSKiran Chandramohan /// Lower `fir.boxproc_host` operation. Extracts the host pointer from the
548cc505c0bSKiran Chandramohan /// boxproc.
549cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
550cc505c0bSKiran Chandramohan struct BoxProcHostOpConversion : public FIROpConversion<fir::BoxProcHostOp> {
551cc505c0bSKiran Chandramohan   using FIROpConversion::FIROpConversion;
552cc505c0bSKiran Chandramohan 
553cc505c0bSKiran Chandramohan   mlir::LogicalResult
554cc505c0bSKiran Chandramohan   matchAndRewrite(fir::BoxProcHostOp boxprochost, OpAdaptor adaptor,
555cc505c0bSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
5567ce8c6fcSKiran Chandramohan     TODO(boxprochost.getLoc(), "fir.boxproc_host codegen");
5577ce8c6fcSKiran Chandramohan     return failure();
558cc505c0bSKiran Chandramohan   }
559cc505c0bSKiran Chandramohan };
560cc505c0bSKiran Chandramohan 
561e38ef2ffSValentin Clement /// Lower `fir.box_tdesc` to the sequence of operations to extract the type
562e38ef2ffSValentin Clement /// descriptor from the box.
563e38ef2ffSValentin Clement struct BoxTypeDescOpConversion : public FIROpConversion<fir::BoxTypeDescOp> {
564e38ef2ffSValentin Clement   using FIROpConversion::FIROpConversion;
565e38ef2ffSValentin Clement 
566e38ef2ffSValentin Clement   mlir::LogicalResult
567e38ef2ffSValentin Clement   matchAndRewrite(fir::BoxTypeDescOp boxtypedesc, OpAdaptor adaptor,
568e38ef2ffSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
569e38ef2ffSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
570e38ef2ffSValentin Clement     auto loc = boxtypedesc.getLoc();
571e38ef2ffSValentin Clement     mlir::Type typeTy =
572e38ef2ffSValentin Clement         fir::getDescFieldTypeModel<kTypePosInBox>()(boxtypedesc.getContext());
573e38ef2ffSValentin Clement     auto result = getValueFromBox(loc, box, typeTy, rewriter, kTypePosInBox);
574e38ef2ffSValentin Clement     auto typePtrTy = mlir::LLVM::LLVMPointerType::get(typeTy);
575e38ef2ffSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(boxtypedesc, typePtrTy,
576e38ef2ffSValentin Clement                                                         result);
577e38ef2ffSValentin Clement     return success();
578e38ef2ffSValentin Clement   }
579e38ef2ffSValentin Clement };
580e38ef2ffSValentin Clement 
581*dc48849fSKiran Chandramohan /// Lower `fir.string_lit` to LLVM IR dialect operation.
582*dc48849fSKiran Chandramohan struct StringLitOpConversion : public FIROpConversion<fir::StringLitOp> {
583*dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
584*dc48849fSKiran Chandramohan 
585*dc48849fSKiran Chandramohan   mlir::LogicalResult
586*dc48849fSKiran Chandramohan   matchAndRewrite(fir::StringLitOp constop, OpAdaptor adaptor,
587*dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
588*dc48849fSKiran Chandramohan     auto ty = convertType(constop.getType());
589*dc48849fSKiran Chandramohan     auto attr = constop.getValue();
590*dc48849fSKiran Chandramohan     if (attr.isa<mlir::StringAttr>()) {
591*dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(constop, ty, attr);
592*dc48849fSKiran Chandramohan       return success();
593*dc48849fSKiran Chandramohan     }
594*dc48849fSKiran Chandramohan 
595*dc48849fSKiran Chandramohan     auto arr = attr.cast<mlir::ArrayAttr>();
596*dc48849fSKiran Chandramohan     auto charTy = constop.getType().cast<fir::CharacterType>();
597*dc48849fSKiran Chandramohan     unsigned bits = lowerTy().characterBitsize(charTy);
598*dc48849fSKiran Chandramohan     mlir::Type intTy = rewriter.getIntegerType(bits);
599*dc48849fSKiran Chandramohan     auto attrs = llvm::map_range(
600*dc48849fSKiran Chandramohan         arr.getValue(), [intTy, bits](mlir::Attribute attr) -> Attribute {
601*dc48849fSKiran Chandramohan           return mlir::IntegerAttr::get(
602*dc48849fSKiran Chandramohan               intTy,
603*dc48849fSKiran Chandramohan               attr.cast<mlir::IntegerAttr>().getValue().sextOrTrunc(bits));
604*dc48849fSKiran Chandramohan         });
605*dc48849fSKiran Chandramohan     mlir::Type vecType = mlir::VectorType::get(arr.size(), intTy);
606*dc48849fSKiran Chandramohan     auto denseAttr = mlir::DenseElementsAttr::get(
607*dc48849fSKiran Chandramohan         vecType.cast<mlir::ShapedType>(), llvm::to_vector<8>(attrs));
608*dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(constop, ty,
609*dc48849fSKiran Chandramohan                                                          denseAttr);
610*dc48849fSKiran Chandramohan     return success();
611*dc48849fSKiran Chandramohan   }
612*dc48849fSKiran Chandramohan };
613*dc48849fSKiran Chandramohan 
614ddd11b9aSAndrzej Warzynski // `fir.call` -> `llvm.call`
615ddd11b9aSAndrzej Warzynski struct CallOpConversion : public FIROpConversion<fir::CallOp> {
616ddd11b9aSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
617ddd11b9aSAndrzej Warzynski 
618ddd11b9aSAndrzej Warzynski   mlir::LogicalResult
619ddd11b9aSAndrzej Warzynski   matchAndRewrite(fir::CallOp call, OpAdaptor adaptor,
620ddd11b9aSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
621ddd11b9aSAndrzej Warzynski     SmallVector<mlir::Type> resultTys;
622ddd11b9aSAndrzej Warzynski     for (auto r : call.getResults())
623ddd11b9aSAndrzej Warzynski       resultTys.push_back(convertType(r.getType()));
624ddd11b9aSAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
625ddd11b9aSAndrzej Warzynski         call, resultTys, adaptor.getOperands(), call->getAttrs());
626ddd11b9aSAndrzej Warzynski     return success();
627ddd11b9aSAndrzej Warzynski   }
628ddd11b9aSAndrzej Warzynski };
629c2acd453SAlexisPerry } // namespace
630ddd11b9aSAndrzej Warzynski 
631092cee5fSValentin Clement static mlir::Type getComplexEleTy(mlir::Type complex) {
632092cee5fSValentin Clement   if (auto cc = complex.dyn_cast<mlir::ComplexType>())
633092cee5fSValentin Clement     return cc.getElementType();
634092cee5fSValentin Clement   return complex.cast<fir::ComplexType>().getElementType();
635092cee5fSValentin Clement }
636092cee5fSValentin Clement 
637c2acd453SAlexisPerry namespace {
638f1dfc027SDiana Picus /// Compare complex values
639f1dfc027SDiana Picus ///
640f1dfc027SDiana Picus /// Per 10.1, the only comparisons available are .EQ. (oeq) and .NE. (une).
641f1dfc027SDiana Picus ///
642f1dfc027SDiana Picus /// For completeness, all other comparison are done on the real component only.
643f1dfc027SDiana Picus struct CmpcOpConversion : public FIROpConversion<fir::CmpcOp> {
644f1dfc027SDiana Picus   using FIROpConversion::FIROpConversion;
645f1dfc027SDiana Picus 
646f1dfc027SDiana Picus   mlir::LogicalResult
647f1dfc027SDiana Picus   matchAndRewrite(fir::CmpcOp cmp, OpAdaptor adaptor,
648f1dfc027SDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
649f1dfc027SDiana Picus     mlir::ValueRange operands = adaptor.getOperands();
650f1dfc027SDiana Picus     mlir::MLIRContext *ctxt = cmp.getContext();
651149ad3d5SShraiysh Vaishay     mlir::Type eleTy = convertType(getComplexEleTy(cmp.getLhs().getType()));
652f1dfc027SDiana Picus     mlir::Type resTy = convertType(cmp.getType());
653f1dfc027SDiana Picus     mlir::Location loc = cmp.getLoc();
654f1dfc027SDiana Picus     auto pos0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0));
655f1dfc027SDiana Picus     SmallVector<mlir::Value, 2> rp{rewriter.create<mlir::LLVM::ExtractValueOp>(
656f1dfc027SDiana Picus                                        loc, eleTy, operands[0], pos0),
657f1dfc027SDiana Picus                                    rewriter.create<mlir::LLVM::ExtractValueOp>(
658f1dfc027SDiana Picus                                        loc, eleTy, operands[1], pos0)};
659f1dfc027SDiana Picus     auto rcp =
660f1dfc027SDiana Picus         rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, rp, cmp->getAttrs());
661f1dfc027SDiana Picus     auto pos1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1));
662f1dfc027SDiana Picus     SmallVector<mlir::Value, 2> ip{rewriter.create<mlir::LLVM::ExtractValueOp>(
663f1dfc027SDiana Picus                                        loc, eleTy, operands[0], pos1),
664f1dfc027SDiana Picus                                    rewriter.create<mlir::LLVM::ExtractValueOp>(
665f1dfc027SDiana Picus                                        loc, eleTy, operands[1], pos1)};
666f1dfc027SDiana Picus     auto icp =
667f1dfc027SDiana Picus         rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, ip, cmp->getAttrs());
668f1dfc027SDiana Picus     SmallVector<mlir::Value, 2> cp{rcp, icp};
669f1dfc027SDiana Picus     switch (cmp.getPredicate()) {
670f1dfc027SDiana Picus     case mlir::arith::CmpFPredicate::OEQ: // .EQ.
671f1dfc027SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(cmp, resTy, cp);
672f1dfc027SDiana Picus       break;
673f1dfc027SDiana Picus     case mlir::arith::CmpFPredicate::UNE: // .NE.
674f1dfc027SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(cmp, resTy, cp);
675f1dfc027SDiana Picus       break;
676f1dfc027SDiana Picus     default:
677f1dfc027SDiana Picus       rewriter.replaceOp(cmp, rcp.getResult());
678f1dfc027SDiana Picus       break;
679f1dfc027SDiana Picus     }
680f1dfc027SDiana Picus     return success();
681f1dfc027SDiana Picus   }
682f1dfc027SDiana Picus };
683f1dfc027SDiana Picus 
684e81d73edSDiana Picus /// Lower complex constants
685e81d73edSDiana Picus struct ConstcOpConversion : public FIROpConversion<fir::ConstcOp> {
686e81d73edSDiana Picus   using FIROpConversion::FIROpConversion;
687e81d73edSDiana Picus 
688e81d73edSDiana Picus   mlir::LogicalResult
689e81d73edSDiana Picus   matchAndRewrite(fir::ConstcOp conc, OpAdaptor,
690e81d73edSDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
691e81d73edSDiana Picus     mlir::Location loc = conc.getLoc();
692e81d73edSDiana Picus     mlir::MLIRContext *ctx = conc.getContext();
693e81d73edSDiana Picus     mlir::Type ty = convertType(conc.getType());
694e81d73edSDiana Picus     mlir::Type ety = convertType(getComplexEleTy(conc.getType()));
695e81d73edSDiana Picus     auto realFloatAttr = mlir::FloatAttr::get(ety, getValue(conc.getReal()));
696e81d73edSDiana Picus     auto realPart =
697e81d73edSDiana Picus         rewriter.create<mlir::LLVM::ConstantOp>(loc, ety, realFloatAttr);
698e81d73edSDiana Picus     auto imFloatAttr = mlir::FloatAttr::get(ety, getValue(conc.getImaginary()));
699e81d73edSDiana Picus     auto imPart =
700e81d73edSDiana Picus         rewriter.create<mlir::LLVM::ConstantOp>(loc, ety, imFloatAttr);
701e81d73edSDiana Picus     auto realIndex = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
702e81d73edSDiana Picus     auto imIndex = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
703e81d73edSDiana Picus     auto undef = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
704e81d73edSDiana Picus     auto setReal = rewriter.create<mlir::LLVM::InsertValueOp>(
705e81d73edSDiana Picus         loc, ty, undef, realPart, realIndex);
706e81d73edSDiana Picus     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(conc, ty, setReal,
707e81d73edSDiana Picus                                                            imPart, imIndex);
708e81d73edSDiana Picus     return success();
709e81d73edSDiana Picus   }
710e81d73edSDiana Picus 
711e81d73edSDiana Picus   inline APFloat getValue(mlir::Attribute attr) const {
712e81d73edSDiana Picus     return attr.cast<fir::RealAttr>().getValue();
713e81d73edSDiana Picus   }
714e81d73edSDiana Picus };
715e81d73edSDiana Picus 
716092cee5fSValentin Clement /// convert value of from-type to value of to-type
717092cee5fSValentin Clement struct ConvertOpConversion : public FIROpConversion<fir::ConvertOp> {
718092cee5fSValentin Clement   using FIROpConversion::FIROpConversion;
719092cee5fSValentin Clement 
720092cee5fSValentin Clement   static bool isFloatingPointTy(mlir::Type ty) {
721092cee5fSValentin Clement     return ty.isa<mlir::FloatType>();
722092cee5fSValentin Clement   }
723092cee5fSValentin Clement 
724092cee5fSValentin Clement   mlir::LogicalResult
725092cee5fSValentin Clement   matchAndRewrite(fir::ConvertOp convert, OpAdaptor adaptor,
726092cee5fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
727149ad3d5SShraiysh Vaishay     auto fromTy = convertType(convert.getValue().getType());
728149ad3d5SShraiysh Vaishay     auto toTy = convertType(convert.getRes().getType());
729092cee5fSValentin Clement     mlir::Value op0 = adaptor.getOperands()[0];
730092cee5fSValentin Clement     if (fromTy == toTy) {
731092cee5fSValentin Clement       rewriter.replaceOp(convert, op0);
732092cee5fSValentin Clement       return success();
733092cee5fSValentin Clement     }
734092cee5fSValentin Clement     auto loc = convert.getLoc();
735092cee5fSValentin Clement     auto convertFpToFp = [&](mlir::Value val, unsigned fromBits,
736092cee5fSValentin Clement                              unsigned toBits, mlir::Type toTy) -> mlir::Value {
737092cee5fSValentin Clement       if (fromBits == toBits) {
738092cee5fSValentin Clement         // TODO: Converting between two floating-point representations with the
739092cee5fSValentin Clement         // same bitwidth is not allowed for now.
740092cee5fSValentin Clement         mlir::emitError(loc,
741092cee5fSValentin Clement                         "cannot implicitly convert between two floating-point "
742092cee5fSValentin Clement                         "representations of the same bitwidth");
743092cee5fSValentin Clement         return {};
744092cee5fSValentin Clement       }
745092cee5fSValentin Clement       if (fromBits > toBits)
746092cee5fSValentin Clement         return rewriter.create<mlir::LLVM::FPTruncOp>(loc, toTy, val);
747092cee5fSValentin Clement       return rewriter.create<mlir::LLVM::FPExtOp>(loc, toTy, val);
748092cee5fSValentin Clement     };
749092cee5fSValentin Clement     // Complex to complex conversion.
750149ad3d5SShraiysh Vaishay     if (fir::isa_complex(convert.getValue().getType()) &&
751149ad3d5SShraiysh Vaishay         fir::isa_complex(convert.getRes().getType())) {
752092cee5fSValentin Clement       // Special case: handle the conversion of a complex such that both the
753092cee5fSValentin Clement       // real and imaginary parts are converted together.
754092cee5fSValentin Clement       auto zero = mlir::ArrayAttr::get(convert.getContext(),
755092cee5fSValentin Clement                                        rewriter.getI32IntegerAttr(0));
756092cee5fSValentin Clement       auto one = mlir::ArrayAttr::get(convert.getContext(),
757092cee5fSValentin Clement                                       rewriter.getI32IntegerAttr(1));
758149ad3d5SShraiysh Vaishay       auto ty = convertType(getComplexEleTy(convert.getValue().getType()));
759092cee5fSValentin Clement       auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, zero);
760092cee5fSValentin Clement       auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, one);
761149ad3d5SShraiysh Vaishay       auto nt = convertType(getComplexEleTy(convert.getRes().getType()));
762092cee5fSValentin Clement       auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
763092cee5fSValentin Clement       auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(nt);
764092cee5fSValentin Clement       auto rc = convertFpToFp(rp, fromBits, toBits, nt);
765092cee5fSValentin Clement       auto ic = convertFpToFp(ip, fromBits, toBits, nt);
766092cee5fSValentin Clement       auto un = rewriter.create<mlir::LLVM::UndefOp>(loc, toTy);
767092cee5fSValentin Clement       auto i1 =
768092cee5fSValentin Clement           rewriter.create<mlir::LLVM::InsertValueOp>(loc, toTy, un, rc, zero);
769092cee5fSValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(convert, toTy, i1,
770092cee5fSValentin Clement                                                              ic, one);
771092cee5fSValentin Clement       return mlir::success();
772092cee5fSValentin Clement     }
773092cee5fSValentin Clement     // Floating point to floating point conversion.
774092cee5fSValentin Clement     if (isFloatingPointTy(fromTy)) {
775092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
776092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
777092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
778092cee5fSValentin Clement         auto v = convertFpToFp(op0, fromBits, toBits, toTy);
779092cee5fSValentin Clement         rewriter.replaceOp(convert, v);
780092cee5fSValentin Clement         return mlir::success();
781092cee5fSValentin Clement       }
782092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
783092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::FPToSIOp>(convert, toTy, op0);
784092cee5fSValentin Clement         return mlir::success();
785092cee5fSValentin Clement       }
786092cee5fSValentin Clement     } else if (fromTy.isa<mlir::IntegerType>()) {
787092cee5fSValentin Clement       // Integer to integer conversion.
788092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
789092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
790092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
791092cee5fSValentin Clement         assert(fromBits != toBits);
792092cee5fSValentin Clement         if (fromBits > toBits) {
793092cee5fSValentin Clement           rewriter.replaceOpWithNewOp<mlir::LLVM::TruncOp>(convert, toTy, op0);
794092cee5fSValentin Clement           return mlir::success();
795092cee5fSValentin Clement         }
796092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SExtOp>(convert, toTy, op0);
797092cee5fSValentin Clement         return mlir::success();
798092cee5fSValentin Clement       }
799092cee5fSValentin Clement       // Integer to floating point conversion.
800092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
801092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SIToFPOp>(convert, toTy, op0);
802092cee5fSValentin Clement         return mlir::success();
803092cee5fSValentin Clement       }
804092cee5fSValentin Clement       // Integer to pointer conversion.
805092cee5fSValentin Clement       if (toTy.isa<mlir::LLVM::LLVMPointerType>()) {
806092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(convert, toTy, op0);
807092cee5fSValentin Clement         return mlir::success();
808092cee5fSValentin Clement       }
809092cee5fSValentin Clement     } else if (fromTy.isa<mlir::LLVM::LLVMPointerType>()) {
810092cee5fSValentin Clement       // Pointer to integer conversion.
811092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
812092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::PtrToIntOp>(convert, toTy, op0);
813092cee5fSValentin Clement         return mlir::success();
814092cee5fSValentin Clement       }
815092cee5fSValentin Clement       // Pointer to pointer conversion.
816092cee5fSValentin Clement       if (toTy.isa<mlir::LLVM::LLVMPointerType>()) {
817092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(convert, toTy, op0);
818092cee5fSValentin Clement         return mlir::success();
819092cee5fSValentin Clement       }
820092cee5fSValentin Clement     }
821092cee5fSValentin Clement     return emitError(loc) << "cannot convert " << fromTy << " to " << toTy;
822092cee5fSValentin Clement   }
823092cee5fSValentin Clement };
824092cee5fSValentin Clement 
8259534e361SValentin Clement /// Lower `fir.dispatch` operation. A virtual call to a method in a dispatch
8269534e361SValentin Clement /// table.
8279534e361SValentin Clement struct DispatchOpConversion : public FIROpConversion<fir::DispatchOp> {
8289534e361SValentin Clement   using FIROpConversion::FIROpConversion;
8299534e361SValentin Clement 
8309534e361SValentin Clement   mlir::LogicalResult
8319534e361SValentin Clement   matchAndRewrite(fir::DispatchOp dispatch, OpAdaptor adaptor,
8329534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8337ce8c6fcSKiran Chandramohan     TODO(dispatch.getLoc(), "fir.dispatch codegen");
8347ce8c6fcSKiran Chandramohan     return failure();
8359534e361SValentin Clement   }
8369534e361SValentin Clement };
8379534e361SValentin Clement 
8389534e361SValentin Clement /// Lower `fir.dispatch_table` operation. The dispatch table for a Fortran
8399534e361SValentin Clement /// derived type.
8409534e361SValentin Clement struct DispatchTableOpConversion
8419534e361SValentin Clement     : public FIROpConversion<fir::DispatchTableOp> {
8429534e361SValentin Clement   using FIROpConversion::FIROpConversion;
8439534e361SValentin Clement 
8449534e361SValentin Clement   mlir::LogicalResult
8459534e361SValentin Clement   matchAndRewrite(fir::DispatchTableOp dispTab, OpAdaptor adaptor,
8469534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8477ce8c6fcSKiran Chandramohan     TODO(dispTab.getLoc(), "fir.dispatch_table codegen");
8487ce8c6fcSKiran Chandramohan     return failure();
8499534e361SValentin Clement   }
8509534e361SValentin Clement };
8519534e361SValentin Clement 
8529534e361SValentin Clement /// Lower `fir.dt_entry` operation. An entry in a dispatch table; binds a
8539534e361SValentin Clement /// method-name to a function.
8549534e361SValentin Clement struct DTEntryOpConversion : public FIROpConversion<fir::DTEntryOp> {
8559534e361SValentin Clement   using FIROpConversion::FIROpConversion;
8569534e361SValentin Clement 
8579534e361SValentin Clement   mlir::LogicalResult
8589534e361SValentin Clement   matchAndRewrite(fir::DTEntryOp dtEnt, OpAdaptor adaptor,
8599534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8607ce8c6fcSKiran Chandramohan     TODO(dtEnt.getLoc(), "fir.dt_entry codegen");
8617ce8c6fcSKiran Chandramohan     return failure();
8629534e361SValentin Clement   }
8639534e361SValentin Clement };
8649534e361SValentin Clement 
865677df8c7SValentin Clement /// Lower `fir.global_len` operation.
866677df8c7SValentin Clement struct GlobalLenOpConversion : public FIROpConversion<fir::GlobalLenOp> {
867677df8c7SValentin Clement   using FIROpConversion::FIROpConversion;
868677df8c7SValentin Clement 
869677df8c7SValentin Clement   mlir::LogicalResult
870677df8c7SValentin Clement   matchAndRewrite(fir::GlobalLenOp globalLen, OpAdaptor adaptor,
871677df8c7SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8727ce8c6fcSKiran Chandramohan     TODO(globalLen.getLoc(), "fir.global_len codegen");
8737ce8c6fcSKiran Chandramohan     return failure();
874677df8c7SValentin Clement   }
875677df8c7SValentin Clement };
876677df8c7SValentin Clement 
877cdc476abSDiana Picus /// Lower fir.len_param_index
878cdc476abSDiana Picus struct LenParamIndexOpConversion
879cdc476abSDiana Picus     : public FIROpConversion<fir::LenParamIndexOp> {
880cdc476abSDiana Picus   using FIROpConversion::FIROpConversion;
881cdc476abSDiana Picus 
882cdc476abSDiana Picus   // FIXME: this should be specialized by the runtime target
883cdc476abSDiana Picus   mlir::LogicalResult
884cdc476abSDiana Picus   matchAndRewrite(fir::LenParamIndexOp lenp, OpAdaptor,
885cdc476abSDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
8867ce8c6fcSKiran Chandramohan     TODO(lenp.getLoc(), "fir.len_param_index codegen");
887cdc476abSDiana Picus   }
888cdc476abSDiana Picus };
889cdc476abSDiana Picus 
890*dc48849fSKiran Chandramohan /// Convert `!fir.emboxchar<!fir.char<KIND, ?>, #n>` into a sequence of
891*dc48849fSKiran Chandramohan /// instructions that generate `!llvm.struct<(ptr<ik>, i64)>`. The 1st element
892*dc48849fSKiran Chandramohan /// in this struct is a pointer. Its type is determined from `KIND`. The 2nd
893*dc48849fSKiran Chandramohan /// element is the length of the character buffer (`#n`).
894*dc48849fSKiran Chandramohan struct EmboxCharOpConversion : public FIROpConversion<fir::EmboxCharOp> {
89531246187SValentin Clement   using FIROpConversion::FIROpConversion;
89631246187SValentin Clement 
89731246187SValentin Clement   mlir::LogicalResult
898*dc48849fSKiran Chandramohan   matchAndRewrite(fir::EmboxCharOp emboxChar, OpAdaptor adaptor,
89931246187SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
900*dc48849fSKiran Chandramohan     mlir::ValueRange operands = adaptor.getOperands();
901*dc48849fSKiran Chandramohan     MLIRContext *ctx = emboxChar.getContext();
902*dc48849fSKiran Chandramohan 
903*dc48849fSKiran Chandramohan     mlir::Value charBuffer = operands[0];
904*dc48849fSKiran Chandramohan     mlir::Value charBufferLen = operands[1];
905*dc48849fSKiran Chandramohan 
906*dc48849fSKiran Chandramohan     mlir::Location loc = emboxChar.getLoc();
907*dc48849fSKiran Chandramohan     mlir::Type llvmStructTy = convertType(emboxChar.getType());
908*dc48849fSKiran Chandramohan     auto llvmStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, llvmStructTy);
909*dc48849fSKiran Chandramohan 
910*dc48849fSKiran Chandramohan     mlir::Type lenTy =
911*dc48849fSKiran Chandramohan         llvmStructTy.cast<mlir::LLVM::LLVMStructType>().getBody()[1];
912*dc48849fSKiran Chandramohan     mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, charBufferLen);
913*dc48849fSKiran Chandramohan 
914*dc48849fSKiran Chandramohan     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
915*dc48849fSKiran Chandramohan     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
916*dc48849fSKiran Chandramohan     auto insertBufferOp = rewriter.create<mlir::LLVM::InsertValueOp>(
917*dc48849fSKiran Chandramohan         loc, llvmStructTy, llvmStruct, charBuffer, c0);
918*dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
919*dc48849fSKiran Chandramohan         emboxChar, llvmStructTy, insertBufferOp, lenAfterCast, c1);
920*dc48849fSKiran Chandramohan 
921*dc48849fSKiran Chandramohan     return success();
92231246187SValentin Clement   }
92331246187SValentin Clement };
924c2acd453SAlexisPerry } // namespace
925c2acd453SAlexisPerry 
926c2acd453SAlexisPerry /// Return the LLVMFuncOp corresponding to the standard malloc call.
927c2acd453SAlexisPerry static mlir::LLVM::LLVMFuncOp
928c2acd453SAlexisPerry getMalloc(fir::AllocMemOp op, mlir::ConversionPatternRewriter &rewriter) {
929c2acd453SAlexisPerry   auto module = op->getParentOfType<mlir::ModuleOp>();
930c2acd453SAlexisPerry   if (mlir::LLVM::LLVMFuncOp mallocFunc =
931c2acd453SAlexisPerry           module.lookupSymbol<mlir::LLVM::LLVMFuncOp>("malloc"))
932c2acd453SAlexisPerry     return mallocFunc;
933c2acd453SAlexisPerry   mlir::OpBuilder moduleBuilder(
934c2acd453SAlexisPerry       op->getParentOfType<mlir::ModuleOp>().getBodyRegion());
935c2acd453SAlexisPerry   auto indexType = mlir::IntegerType::get(op.getContext(), 64);
936c2acd453SAlexisPerry   return moduleBuilder.create<mlir::LLVM::LLVMFuncOp>(
937c2acd453SAlexisPerry       rewriter.getUnknownLoc(), "malloc",
938c2acd453SAlexisPerry       mlir::LLVM::LLVMFunctionType::get(getVoidPtrType(op.getContext()),
939c2acd453SAlexisPerry                                         indexType,
940c2acd453SAlexisPerry                                         /*isVarArg=*/false));
941c2acd453SAlexisPerry }
942c2acd453SAlexisPerry 
943c2acd453SAlexisPerry /// Helper function for generating the LLVM IR that computes the size
944c2acd453SAlexisPerry /// in bytes for a derived type.
945c2acd453SAlexisPerry static mlir::Value
946c2acd453SAlexisPerry computeDerivedTypeSize(mlir::Location loc, mlir::Type ptrTy, mlir::Type idxTy,
947c2acd453SAlexisPerry                        mlir::ConversionPatternRewriter &rewriter) {
948c2acd453SAlexisPerry   auto nullPtr = rewriter.create<mlir::LLVM::NullOp>(loc, ptrTy);
949c2acd453SAlexisPerry   mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1);
95030122656SAlex Zinenko   llvm::SmallVector<mlir::Value> args{one};
95130122656SAlex Zinenko   auto gep = rewriter.create<mlir::LLVM::GEPOp>(loc, ptrTy, nullPtr, args);
952c2acd453SAlexisPerry   return rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, gep);
953c2acd453SAlexisPerry }
954c2acd453SAlexisPerry 
955c2acd453SAlexisPerry namespace {
956c2acd453SAlexisPerry /// Lower a `fir.allocmem` instruction into `llvm.call @malloc`
957c2acd453SAlexisPerry struct AllocMemOpConversion : public FIROpConversion<fir::AllocMemOp> {
958c2acd453SAlexisPerry   using FIROpConversion::FIROpConversion;
959c2acd453SAlexisPerry 
960c2acd453SAlexisPerry   mlir::LogicalResult
961c2acd453SAlexisPerry   matchAndRewrite(fir::AllocMemOp heap, OpAdaptor adaptor,
962c2acd453SAlexisPerry                   mlir::ConversionPatternRewriter &rewriter) const override {
963c45bd4b9SEric Schweitz     auto heapTy = heap.getType();
964c45bd4b9SEric Schweitz     auto ty = convertType(heapTy);
965c2acd453SAlexisPerry     mlir::LLVM::LLVMFuncOp mallocFunc = getMalloc(heap, rewriter);
966c2acd453SAlexisPerry     mlir::Location loc = heap.getLoc();
967c2acd453SAlexisPerry     auto ity = lowerTy().indexType();
968c45bd4b9SEric Schweitz     auto dataTy = fir::unwrapRefType(heapTy);
969c45bd4b9SEric Schweitz     if (fir::isRecordWithTypeParameters(fir::unwrapSequenceType(dataTy)))
970c45bd4b9SEric Schweitz       TODO(loc, "fir.allocmem codegen of derived type with length parameters");
971c2acd453SAlexisPerry     mlir::Value size = genTypeSizeInBytes(loc, ity, rewriter, ty);
972c45bd4b9SEric Schweitz     // !fir.array<NxMx!fir.char<K,?>> sets `size` to the width of !fir.char<K>.
973c45bd4b9SEric Schweitz     // So multiply the constant dimensions here.
974c45bd4b9SEric Schweitz     if (fir::hasDynamicSize(dataTy))
975c45bd4b9SEric Schweitz       if (auto seqTy = dataTy.dyn_cast<fir::SequenceType>())
976c45bd4b9SEric Schweitz         if (fir::characterWithDynamicLen(seqTy.getEleTy())) {
977c45bd4b9SEric Schweitz           fir::SequenceType::Extent arrSize = 1;
978c45bd4b9SEric Schweitz           for (auto d : seqTy.getShape())
979c45bd4b9SEric Schweitz             if (d != fir::SequenceType::getUnknownExtent())
980c45bd4b9SEric Schweitz               arrSize *= d;
981c45bd4b9SEric Schweitz           size = rewriter.create<mlir::LLVM::MulOp>(
982c45bd4b9SEric Schweitz               loc, ity, size, genConstantIndex(loc, ity, rewriter, arrSize));
983c45bd4b9SEric Schweitz         }
984c2acd453SAlexisPerry     for (mlir::Value opnd : adaptor.getOperands())
985c2acd453SAlexisPerry       size = rewriter.create<mlir::LLVM::MulOp>(
986c2acd453SAlexisPerry           loc, ity, size, integerCast(loc, rewriter, ity, opnd));
987c2acd453SAlexisPerry     heap->setAttr("callee", mlir::SymbolRefAttr::get(mallocFunc));
988c2acd453SAlexisPerry     auto malloc = rewriter.create<mlir::LLVM::CallOp>(
989c2acd453SAlexisPerry         loc, ::getVoidPtrType(heap.getContext()), size, heap->getAttrs());
990c2acd453SAlexisPerry     rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(heap, ty,
991c2acd453SAlexisPerry                                                        malloc.getResult(0));
992c2acd453SAlexisPerry     return success();
993c2acd453SAlexisPerry   }
994c2acd453SAlexisPerry 
995c2acd453SAlexisPerry   // Compute the (allocation) size of the allocmem type in bytes.
996c2acd453SAlexisPerry   mlir::Value genTypeSizeInBytes(mlir::Location loc, mlir::Type idxTy,
997c2acd453SAlexisPerry                                  mlir::ConversionPatternRewriter &rewriter,
998c2acd453SAlexisPerry                                  mlir::Type llTy) const {
999c2acd453SAlexisPerry     // Use the primitive size, if available.
1000c2acd453SAlexisPerry     auto ptrTy = llTy.dyn_cast<mlir::LLVM::LLVMPointerType>();
1001c2acd453SAlexisPerry     if (auto size =
1002c2acd453SAlexisPerry             mlir::LLVM::getPrimitiveTypeSizeInBits(ptrTy.getElementType()))
1003c2acd453SAlexisPerry       return genConstantIndex(loc, idxTy, rewriter, size / 8);
1004c2acd453SAlexisPerry 
1005c2acd453SAlexisPerry     // Otherwise, generate the GEP trick in LLVM IR to compute the size.
1006c2acd453SAlexisPerry     return computeDerivedTypeSize(loc, ptrTy, idxTy, rewriter);
1007c2acd453SAlexisPerry   }
1008c2acd453SAlexisPerry };
1009c2acd453SAlexisPerry } // namespace
1010c2acd453SAlexisPerry 
1011c2acd453SAlexisPerry /// Return the LLVMFuncOp corresponding to the standard free call.
1012c2acd453SAlexisPerry static mlir::LLVM::LLVMFuncOp
1013c2acd453SAlexisPerry getFree(fir::FreeMemOp op, mlir::ConversionPatternRewriter &rewriter) {
1014c2acd453SAlexisPerry   auto module = op->getParentOfType<mlir::ModuleOp>();
1015c2acd453SAlexisPerry   if (mlir::LLVM::LLVMFuncOp freeFunc =
1016c2acd453SAlexisPerry           module.lookupSymbol<mlir::LLVM::LLVMFuncOp>("free"))
1017c2acd453SAlexisPerry     return freeFunc;
1018c2acd453SAlexisPerry   mlir::OpBuilder moduleBuilder(module.getBodyRegion());
1019c2acd453SAlexisPerry   auto voidType = mlir::LLVM::LLVMVoidType::get(op.getContext());
1020c2acd453SAlexisPerry   return moduleBuilder.create<mlir::LLVM::LLVMFuncOp>(
1021c2acd453SAlexisPerry       rewriter.getUnknownLoc(), "free",
1022c2acd453SAlexisPerry       mlir::LLVM::LLVMFunctionType::get(voidType,
1023c2acd453SAlexisPerry                                         getVoidPtrType(op.getContext()),
1024c2acd453SAlexisPerry                                         /*isVarArg=*/false));
1025c2acd453SAlexisPerry }
1026c2acd453SAlexisPerry 
1027c2acd453SAlexisPerry namespace {
1028c2acd453SAlexisPerry /// Lower a `fir.freemem` instruction into `llvm.call @free`
1029c2acd453SAlexisPerry struct FreeMemOpConversion : public FIROpConversion<fir::FreeMemOp> {
1030c2acd453SAlexisPerry   using FIROpConversion::FIROpConversion;
1031c2acd453SAlexisPerry 
1032c2acd453SAlexisPerry   mlir::LogicalResult
1033c2acd453SAlexisPerry   matchAndRewrite(fir::FreeMemOp freemem, OpAdaptor adaptor,
1034c2acd453SAlexisPerry                   mlir::ConversionPatternRewriter &rewriter) const override {
1035c2acd453SAlexisPerry     mlir::LLVM::LLVMFuncOp freeFunc = getFree(freemem, rewriter);
1036c2acd453SAlexisPerry     mlir::Location loc = freemem.getLoc();
1037c2acd453SAlexisPerry     auto bitcast = rewriter.create<mlir::LLVM::BitcastOp>(
1038c2acd453SAlexisPerry         freemem.getLoc(), voidPtrTy(), adaptor.getOperands()[0]);
1039c2acd453SAlexisPerry     freemem->setAttr("callee", mlir::SymbolRefAttr::get(freeFunc));
1040c2acd453SAlexisPerry     rewriter.create<mlir::LLVM::CallOp>(
1041c2acd453SAlexisPerry         loc, mlir::TypeRange{}, mlir::ValueRange{bitcast}, freemem->getAttrs());
1042c2acd453SAlexisPerry     rewriter.eraseOp(freemem);
1043c2acd453SAlexisPerry     return success();
1044c2acd453SAlexisPerry   }
1045c2acd453SAlexisPerry };
1046c2acd453SAlexisPerry } // namespace
1047044d5b5dSValentin Clement 
1048*dc48849fSKiran Chandramohan namespace {} // namespace
104932e08248SAndrzej Warzynski 
1050af6ee580SValentin Clement /// Common base class for embox to descriptor conversion.
1051af6ee580SValentin Clement template <typename OP>
1052af6ee580SValentin Clement struct EmboxCommonConversion : public FIROpConversion<OP> {
1053af6ee580SValentin Clement   using FIROpConversion<OP>::FIROpConversion;
1054af6ee580SValentin Clement 
1055af6ee580SValentin Clement   // Find the LLVMFuncOp in whose entry block the alloca should be inserted.
1056af6ee580SValentin Clement   // The order to find the LLVMFuncOp is as follows:
1057af6ee580SValentin Clement   // 1. The parent operation of the current block if it is a LLVMFuncOp.
1058af6ee580SValentin Clement   // 2. The first ancestor that is a LLVMFuncOp.
1059af6ee580SValentin Clement   mlir::LLVM::LLVMFuncOp
1060af6ee580SValentin Clement   getFuncForAllocaInsert(mlir::ConversionPatternRewriter &rewriter) const {
1061af6ee580SValentin Clement     mlir::Operation *parentOp = rewriter.getInsertionBlock()->getParentOp();
1062af6ee580SValentin Clement     return mlir::isa<mlir::LLVM::LLVMFuncOp>(parentOp)
1063af6ee580SValentin Clement                ? mlir::cast<mlir::LLVM::LLVMFuncOp>(parentOp)
1064af6ee580SValentin Clement                : parentOp->getParentOfType<mlir::LLVM::LLVMFuncOp>();
1065af6ee580SValentin Clement   }
1066af6ee580SValentin Clement 
1067af6ee580SValentin Clement   // Generate an alloca of size 1 and type \p toTy.
1068af6ee580SValentin Clement   mlir::LLVM::AllocaOp
1069af6ee580SValentin Clement   genAllocaWithType(mlir::Location loc, mlir::Type toTy, unsigned alignment,
1070af6ee580SValentin Clement                     mlir::ConversionPatternRewriter &rewriter) const {
1071af6ee580SValentin Clement     auto thisPt = rewriter.saveInsertionPoint();
1072af6ee580SValentin Clement     mlir::LLVM::LLVMFuncOp func = getFuncForAllocaInsert(rewriter);
1073af6ee580SValentin Clement     rewriter.setInsertionPointToStart(&func.front());
1074af6ee580SValentin Clement     auto size = this->genI32Constant(loc, rewriter, 1);
1075af6ee580SValentin Clement     auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, toTy, size, alignment);
1076af6ee580SValentin Clement     rewriter.restoreInsertionPoint(thisPt);
1077af6ee580SValentin Clement     return al;
1078af6ee580SValentin Clement   }
1079af6ee580SValentin Clement 
1080af6ee580SValentin Clement   static int getCFIAttr(fir::BoxType boxTy) {
1081af6ee580SValentin Clement     auto eleTy = boxTy.getEleTy();
1082af6ee580SValentin Clement     if (eleTy.isa<fir::PointerType>())
1083af6ee580SValentin Clement       return CFI_attribute_pointer;
1084af6ee580SValentin Clement     if (eleTy.isa<fir::HeapType>())
1085af6ee580SValentin Clement       return CFI_attribute_allocatable;
1086af6ee580SValentin Clement     return CFI_attribute_other;
1087af6ee580SValentin Clement   }
1088af6ee580SValentin Clement 
1089af6ee580SValentin Clement   static fir::RecordType unwrapIfDerived(fir::BoxType boxTy) {
1090af6ee580SValentin Clement     return fir::unwrapSequenceType(fir::dyn_cast_ptrOrBoxEleTy(boxTy))
1091af6ee580SValentin Clement         .template dyn_cast<fir::RecordType>();
1092af6ee580SValentin Clement   }
1093af6ee580SValentin Clement   static bool isDerivedTypeWithLenParams(fir::BoxType boxTy) {
1094af6ee580SValentin Clement     auto recTy = unwrapIfDerived(boxTy);
1095af6ee580SValentin Clement     return recTy && recTy.getNumLenParams() > 0;
1096af6ee580SValentin Clement   }
1097af6ee580SValentin Clement   static bool isDerivedType(fir::BoxType boxTy) {
1098af6ee580SValentin Clement     return unwrapIfDerived(boxTy) != nullptr;
1099af6ee580SValentin Clement   }
1100af6ee580SValentin Clement 
1101af6ee580SValentin Clement   // Get the element size and CFI type code of the boxed value.
1102af6ee580SValentin Clement   std::tuple<mlir::Value, mlir::Value> getSizeAndTypeCode(
1103af6ee580SValentin Clement       mlir::Location loc, mlir::ConversionPatternRewriter &rewriter,
1104af6ee580SValentin Clement       mlir::Type boxEleTy, mlir::ValueRange lenParams = {}) const {
1105af6ee580SValentin Clement     auto doInteger =
1106af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1107af6ee580SValentin Clement       int typeCode = fir::integerBitsToTypeCode(width);
1108af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1109af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1110af6ee580SValentin Clement     };
1111af6ee580SValentin Clement     auto doLogical =
1112af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1113af6ee580SValentin Clement       int typeCode = fir::logicalBitsToTypeCode(width);
1114af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1115af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1116af6ee580SValentin Clement     };
1117af6ee580SValentin Clement     auto doFloat = [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1118af6ee580SValentin Clement       int typeCode = fir::realBitsToTypeCode(width);
1119af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1120af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1121af6ee580SValentin Clement     };
1122af6ee580SValentin Clement     auto doComplex =
1123af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1124af6ee580SValentin Clement       auto typeCode = fir::complexBitsToTypeCode(width);
1125af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8 * 2),
1126af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1127af6ee580SValentin Clement     };
1128af6ee580SValentin Clement     auto doCharacter =
1129af6ee580SValentin Clement         [&](unsigned width,
1130af6ee580SValentin Clement             mlir::Value len) -> std::tuple<mlir::Value, mlir::Value> {
1131af6ee580SValentin Clement       auto typeCode = fir::characterBitsToTypeCode(width);
1132af6ee580SValentin Clement       auto typeCodeVal = this->genConstantOffset(loc, rewriter, typeCode);
1133af6ee580SValentin Clement       if (width == 8)
1134af6ee580SValentin Clement         return {len, typeCodeVal};
1135af6ee580SValentin Clement       auto byteWidth = this->genConstantOffset(loc, rewriter, width / 8);
1136af6ee580SValentin Clement       auto i64Ty = mlir::IntegerType::get(&this->lowerTy().getContext(), 64);
1137af6ee580SValentin Clement       auto size =
1138af6ee580SValentin Clement           rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, byteWidth, len);
1139af6ee580SValentin Clement       return {size, typeCodeVal};
1140af6ee580SValentin Clement     };
1141af6ee580SValentin Clement     auto getKindMap = [&]() -> fir::KindMapping & {
1142af6ee580SValentin Clement       return this->lowerTy().getKindMap();
1143af6ee580SValentin Clement     };
1144af6ee580SValentin Clement     // Pointer-like types.
1145af6ee580SValentin Clement     if (auto eleTy = fir::dyn_cast_ptrEleTy(boxEleTy))
1146af6ee580SValentin Clement       boxEleTy = eleTy;
1147af6ee580SValentin Clement     // Integer types.
1148af6ee580SValentin Clement     if (fir::isa_integer(boxEleTy)) {
1149af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::IntegerType>())
1150af6ee580SValentin Clement         return doInteger(ty.getWidth());
1151af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::IntegerType>();
1152af6ee580SValentin Clement       return doInteger(getKindMap().getIntegerBitsize(ty.getFKind()));
1153af6ee580SValentin Clement     }
1154af6ee580SValentin Clement     // Floating point types.
1155af6ee580SValentin Clement     if (fir::isa_real(boxEleTy)) {
1156af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::FloatType>())
1157af6ee580SValentin Clement         return doFloat(ty.getWidth());
1158af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::RealType>();
1159af6ee580SValentin Clement       return doFloat(getKindMap().getRealBitsize(ty.getFKind()));
1160af6ee580SValentin Clement     }
1161af6ee580SValentin Clement     // Complex types.
1162af6ee580SValentin Clement     if (fir::isa_complex(boxEleTy)) {
1163af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::ComplexType>())
1164af6ee580SValentin Clement         return doComplex(
1165af6ee580SValentin Clement             ty.getElementType().cast<mlir::FloatType>().getWidth());
1166af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::ComplexType>();
1167af6ee580SValentin Clement       return doComplex(getKindMap().getRealBitsize(ty.getFKind()));
1168af6ee580SValentin Clement     }
1169af6ee580SValentin Clement     // Character types.
1170af6ee580SValentin Clement     if (auto ty = boxEleTy.dyn_cast<fir::CharacterType>()) {
1171af6ee580SValentin Clement       auto charWidth = getKindMap().getCharacterBitsize(ty.getFKind());
1172af6ee580SValentin Clement       if (ty.getLen() != fir::CharacterType::unknownLen()) {
1173af6ee580SValentin Clement         auto len = this->genConstantOffset(loc, rewriter, ty.getLen());
1174af6ee580SValentin Clement         return doCharacter(charWidth, len);
1175af6ee580SValentin Clement       }
1176af6ee580SValentin Clement       assert(!lenParams.empty());
1177af6ee580SValentin Clement       return doCharacter(charWidth, lenParams.back());
1178af6ee580SValentin Clement     }
1179af6ee580SValentin Clement     // Logical type.
1180af6ee580SValentin Clement     if (auto ty = boxEleTy.dyn_cast<fir::LogicalType>())
1181af6ee580SValentin Clement       return doLogical(getKindMap().getLogicalBitsize(ty.getFKind()));
1182af6ee580SValentin Clement     // Array types.
1183af6ee580SValentin Clement     if (auto seqTy = boxEleTy.dyn_cast<fir::SequenceType>())
1184af6ee580SValentin Clement       return getSizeAndTypeCode(loc, rewriter, seqTy.getEleTy(), lenParams);
1185af6ee580SValentin Clement     // Derived-type types.
1186af6ee580SValentin Clement     if (boxEleTy.isa<fir::RecordType>()) {
1187af6ee580SValentin Clement       auto ptrTy = mlir::LLVM::LLVMPointerType::get(
1188af6ee580SValentin Clement           this->lowerTy().convertType(boxEleTy));
1189af6ee580SValentin Clement       auto nullPtr = rewriter.create<mlir::LLVM::NullOp>(loc, ptrTy);
1190af6ee580SValentin Clement       auto one =
1191af6ee580SValentin Clement           genConstantIndex(loc, this->lowerTy().offsetType(), rewriter, 1);
119230122656SAlex Zinenko       auto gep = rewriter.create<mlir::LLVM::GEPOp>(loc, ptrTy, nullPtr,
119330122656SAlex Zinenko                                                     mlir::ValueRange{one});
1194af6ee580SValentin Clement       auto eleSize = rewriter.create<mlir::LLVM::PtrToIntOp>(
1195af6ee580SValentin Clement           loc, this->lowerTy().indexType(), gep);
1196af6ee580SValentin Clement       return {eleSize,
1197af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, fir::derivedToTypeCode())};
1198af6ee580SValentin Clement     }
1199af6ee580SValentin Clement     // Reference type.
1200af6ee580SValentin Clement     if (fir::isa_ref_type(boxEleTy)) {
1201af6ee580SValentin Clement       // FIXME: use the target pointer size rather than sizeof(void*)
1202af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, sizeof(void *)),
1203af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, CFI_type_cptr)};
1204af6ee580SValentin Clement     }
1205af6ee580SValentin Clement     fir::emitFatalError(loc, "unhandled type in fir.box code generation");
1206af6ee580SValentin Clement   }
1207af6ee580SValentin Clement 
1208af6ee580SValentin Clement   /// Basic pattern to write a field in the descriptor
1209af6ee580SValentin Clement   mlir::Value insertField(mlir::ConversionPatternRewriter &rewriter,
1210af6ee580SValentin Clement                           mlir::Location loc, mlir::Value dest,
1211af6ee580SValentin Clement                           ArrayRef<unsigned> fldIndexes, mlir::Value value,
1212af6ee580SValentin Clement                           bool bitcast = false) const {
1213af6ee580SValentin Clement     auto boxTy = dest.getType();
1214af6ee580SValentin Clement     auto fldTy = this->getBoxEleTy(boxTy, fldIndexes);
1215af6ee580SValentin Clement     if (bitcast)
1216af6ee580SValentin Clement       value = rewriter.create<mlir::LLVM::BitcastOp>(loc, fldTy, value);
1217af6ee580SValentin Clement     else
1218af6ee580SValentin Clement       value = this->integerCast(loc, rewriter, fldTy, value);
1219af6ee580SValentin Clement     SmallVector<mlir::Attribute, 2> attrs;
1220af6ee580SValentin Clement     for (auto i : fldIndexes)
1221af6ee580SValentin Clement       attrs.push_back(rewriter.getI32IntegerAttr(i));
1222af6ee580SValentin Clement     auto indexesAttr = mlir::ArrayAttr::get(rewriter.getContext(), attrs);
1223af6ee580SValentin Clement     return rewriter.create<mlir::LLVM::InsertValueOp>(loc, boxTy, dest, value,
1224af6ee580SValentin Clement                                                       indexesAttr);
1225af6ee580SValentin Clement   }
1226af6ee580SValentin Clement 
1227af6ee580SValentin Clement   inline mlir::Value
1228af6ee580SValentin Clement   insertBaseAddress(mlir::ConversionPatternRewriter &rewriter,
1229af6ee580SValentin Clement                     mlir::Location loc, mlir::Value dest,
1230af6ee580SValentin Clement                     mlir::Value base) const {
12311f551032SValentin Clement     return insertField(rewriter, loc, dest, {kAddrPosInBox}, base,
12321f551032SValentin Clement                        /*bitCast=*/true);
12331f551032SValentin Clement   }
12341f551032SValentin Clement 
12351f551032SValentin Clement   inline mlir::Value insertLowerBound(mlir::ConversionPatternRewriter &rewriter,
12361f551032SValentin Clement                                       mlir::Location loc, mlir::Value dest,
12371f551032SValentin Clement                                       unsigned dim, mlir::Value lb) const {
12381f551032SValentin Clement     return insertField(rewriter, loc, dest,
12391f551032SValentin Clement                        {kDimsPosInBox, dim, kDimLowerBoundPos}, lb);
12401f551032SValentin Clement   }
12411f551032SValentin Clement 
12421f551032SValentin Clement   inline mlir::Value insertExtent(mlir::ConversionPatternRewriter &rewriter,
12431f551032SValentin Clement                                   mlir::Location loc, mlir::Value dest,
12441f551032SValentin Clement                                   unsigned dim, mlir::Value extent) const {
12451f551032SValentin Clement     return insertField(rewriter, loc, dest, {kDimsPosInBox, dim, kDimExtentPos},
12461f551032SValentin Clement                        extent);
12471f551032SValentin Clement   }
12481f551032SValentin Clement 
12491f551032SValentin Clement   inline mlir::Value insertStride(mlir::ConversionPatternRewriter &rewriter,
12501f551032SValentin Clement                                   mlir::Location loc, mlir::Value dest,
12511f551032SValentin Clement                                   unsigned dim, mlir::Value stride) const {
12521f551032SValentin Clement     return insertField(rewriter, loc, dest, {kDimsPosInBox, dim, kDimStridePos},
12531f551032SValentin Clement                        stride);
1254af6ee580SValentin Clement   }
1255af6ee580SValentin Clement 
1256af6ee580SValentin Clement   /// Get the address of the type descriptor global variable that was created by
1257af6ee580SValentin Clement   /// lowering for derived type \p recType.
1258af6ee580SValentin Clement   template <typename BOX>
1259af6ee580SValentin Clement   mlir::Value
1260af6ee580SValentin Clement   getTypeDescriptor(BOX box, mlir::ConversionPatternRewriter &rewriter,
1261af6ee580SValentin Clement                     mlir::Location loc, fir::RecordType recType) const {
126274acd744SValentin Clement     std::string name = recType.translateNameToFrontendMangledName();
1263af6ee580SValentin Clement     auto module = box->template getParentOfType<mlir::ModuleOp>();
1264af6ee580SValentin Clement     if (auto global = module.template lookupSymbol<fir::GlobalOp>(name)) {
1265af6ee580SValentin Clement       auto ty = mlir::LLVM::LLVMPointerType::get(
1266af6ee580SValentin Clement           this->lowerTy().convertType(global.getType()));
1267af6ee580SValentin Clement       return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty,
1268feeee78aSJacques Pienaar                                                       global.getSymName());
1269af6ee580SValentin Clement     }
1270af6ee580SValentin Clement     if (auto global =
1271af6ee580SValentin Clement             module.template lookupSymbol<mlir::LLVM::GlobalOp>(name)) {
1272af6ee580SValentin Clement       // The global may have already been translated to LLVM.
1273af6ee580SValentin Clement       auto ty = mlir::LLVM::LLVMPointerType::get(global.getType());
1274af6ee580SValentin Clement       return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty,
1275feeee78aSJacques Pienaar                                                       global.getSymName());
1276af6ee580SValentin Clement     }
12777dd7ccd2SJean Perier     if (fir::NameUniquer::belongsToModule(
12787dd7ccd2SJean Perier             name, Fortran::semantics::typeInfoBuiltinModule)) {
12797dd7ccd2SJean Perier       // Type info derived types do not have type descriptors since they are the
12807dd7ccd2SJean Perier       // types defining type descriptors.
12815bde97b1SJean Perier       return rewriter.create<mlir::LLVM::NullOp>(
12825bde97b1SJean Perier           loc, ::getVoidPtrType(box.getContext()));
12837dd7ccd2SJean Perier     }
1284af6ee580SValentin Clement     // The global does not exist in the current translation unit, but may be
1285af6ee580SValentin Clement     // defined elsewhere (e.g., type defined in a module).
12867dd7ccd2SJean Perier     // Create an available_externally global to require the symbols to be
1287af6ee580SValentin Clement     // defined elsewhere and to cause link-time failure otherwise.
12885bde97b1SJean Perier     auto i8Ty = rewriter.getIntegerType(8);
1289af6ee580SValentin Clement     mlir::OpBuilder modBuilder(module.getBodyRegion());
12907dd7ccd2SJean Perier     modBuilder.create<mlir::LLVM::GlobalOp>(
12917dd7ccd2SJean Perier         loc, i8Ty, /*isConstant=*/true,
12927dd7ccd2SJean Perier         mlir::LLVM::Linkage::AvailableExternally, name, mlir::Attribute{});
1293af6ee580SValentin Clement     auto ty = mlir::LLVM::LLVMPointerType::get(i8Ty);
1294af6ee580SValentin Clement     return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty, name);
1295af6ee580SValentin Clement   }
1296af6ee580SValentin Clement 
1297af6ee580SValentin Clement   template <typename BOX>
1298af6ee580SValentin Clement   std::tuple<fir::BoxType, mlir::Value, mlir::Value>
1299af6ee580SValentin Clement   consDescriptorPrefix(BOX box, mlir::ConversionPatternRewriter &rewriter,
1300af6ee580SValentin Clement                        unsigned rank, mlir::ValueRange lenParams) const {
1301af6ee580SValentin Clement     auto loc = box.getLoc();
1302af6ee580SValentin Clement     auto boxTy = box.getType().template dyn_cast<fir::BoxType>();
1303af6ee580SValentin Clement     auto convTy = this->lowerTy().convertBoxType(boxTy, rank);
1304af6ee580SValentin Clement     auto llvmBoxPtrTy = convTy.template cast<mlir::LLVM::LLVMPointerType>();
1305af6ee580SValentin Clement     auto llvmBoxTy = llvmBoxPtrTy.getElementType();
1306af6ee580SValentin Clement     mlir::Value descriptor =
1307af6ee580SValentin Clement         rewriter.create<mlir::LLVM::UndefOp>(loc, llvmBoxTy);
1308af6ee580SValentin Clement 
1309af6ee580SValentin Clement     llvm::SmallVector<mlir::Value> typeparams = lenParams;
1310af6ee580SValentin Clement     if constexpr (!std::is_same_v<BOX, fir::EmboxOp>) {
1311af6ee580SValentin Clement       if (!box.substr().empty() && fir::hasDynamicSize(boxTy.getEleTy()))
1312af6ee580SValentin Clement         typeparams.push_back(box.substr()[1]);
1313af6ee580SValentin Clement     }
1314af6ee580SValentin Clement 
1315af6ee580SValentin Clement     // Write each of the fields with the appropriate values
1316af6ee580SValentin Clement     auto [eleSize, cfiTy] =
1317af6ee580SValentin Clement         getSizeAndTypeCode(loc, rewriter, boxTy.getEleTy(), typeparams);
1318af6ee580SValentin Clement     descriptor =
1319af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kElemLenPosInBox}, eleSize);
1320af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kVersionPosInBox},
1321af6ee580SValentin Clement                              this->genI32Constant(loc, rewriter, CFI_VERSION));
1322af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kRankPosInBox},
1323af6ee580SValentin Clement                              this->genI32Constant(loc, rewriter, rank));
1324af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kTypePosInBox}, cfiTy);
1325af6ee580SValentin Clement     descriptor =
1326af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kAttributePosInBox},
1327af6ee580SValentin Clement                     this->genI32Constant(loc, rewriter, getCFIAttr(boxTy)));
1328af6ee580SValentin Clement     const bool hasAddendum = isDerivedType(boxTy);
1329af6ee580SValentin Clement     descriptor =
1330af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kF18AddendumPosInBox},
1331af6ee580SValentin Clement                     this->genI32Constant(loc, rewriter, hasAddendum ? 1 : 0));
1332af6ee580SValentin Clement 
1333af6ee580SValentin Clement     if (hasAddendum) {
1334af6ee580SValentin Clement       auto isArray =
1335af6ee580SValentin Clement           fir::dyn_cast_ptrOrBoxEleTy(boxTy).template isa<fir::SequenceType>();
1336af6ee580SValentin Clement       unsigned typeDescFieldId = isArray ? kOptTypePtrPosInBox : kDimsPosInBox;
1337af6ee580SValentin Clement       auto typeDesc =
1338af6ee580SValentin Clement           getTypeDescriptor(box, rewriter, loc, unwrapIfDerived(boxTy));
1339af6ee580SValentin Clement       descriptor =
1340af6ee580SValentin Clement           insertField(rewriter, loc, descriptor, {typeDescFieldId}, typeDesc,
1341af6ee580SValentin Clement                       /*bitCast=*/true);
1342af6ee580SValentin Clement     }
1343af6ee580SValentin Clement 
1344af6ee580SValentin Clement     return {boxTy, descriptor, eleSize};
1345af6ee580SValentin Clement   }
1346af6ee580SValentin Clement 
13471f551032SValentin Clement   /// Compute the base address of a substring given the base address of a scalar
13481f551032SValentin Clement   /// string and the zero based string lower bound.
13491f551032SValentin Clement   mlir::Value shiftSubstringBase(mlir::ConversionPatternRewriter &rewriter,
13501f551032SValentin Clement                                  mlir::Location loc, mlir::Value base,
13511f551032SValentin Clement                                  mlir::Value lowerBound) const {
13521f551032SValentin Clement     llvm::SmallVector<mlir::Value> gepOperands;
13531f551032SValentin Clement     auto baseType =
13541f551032SValentin Clement         base.getType().cast<mlir::LLVM::LLVMPointerType>().getElementType();
13551f551032SValentin Clement     if (baseType.isa<mlir::LLVM::LLVMArrayType>()) {
13561f551032SValentin Clement       auto idxTy = this->lowerTy().indexType();
13571f551032SValentin Clement       mlir::Value zero = genConstantIndex(loc, idxTy, rewriter, 0);
13581f551032SValentin Clement       gepOperands.push_back(zero);
13591f551032SValentin Clement     }
13601f551032SValentin Clement     gepOperands.push_back(lowerBound);
13611f551032SValentin Clement     return this->genGEP(loc, base.getType(), rewriter, base, gepOperands);
13621f551032SValentin Clement   }
13631f551032SValentin Clement 
1364af6ee580SValentin Clement   /// If the embox is not in a globalOp body, allocate storage for the box;
1365af6ee580SValentin Clement   /// store the value inside and return the generated alloca. Return the input
1366af6ee580SValentin Clement   /// value otherwise.
1367af6ee580SValentin Clement   mlir::Value
1368af6ee580SValentin Clement   placeInMemoryIfNotGlobalInit(mlir::ConversionPatternRewriter &rewriter,
1369af6ee580SValentin Clement                                mlir::Location loc, mlir::Value boxValue) const {
1370af6ee580SValentin Clement     auto *thisBlock = rewriter.getInsertionBlock();
1371af6ee580SValentin Clement     if (thisBlock && mlir::isa<mlir::LLVM::GlobalOp>(thisBlock->getParentOp()))
1372af6ee580SValentin Clement       return boxValue;
1373af6ee580SValentin Clement     auto boxPtrTy = mlir::LLVM::LLVMPointerType::get(boxValue.getType());
1374af6ee580SValentin Clement     auto alloca = genAllocaWithType(loc, boxPtrTy, defaultAlign, rewriter);
1375af6ee580SValentin Clement     rewriter.create<mlir::LLVM::StoreOp>(loc, boxValue, alloca);
1376af6ee580SValentin Clement     return alloca;
1377af6ee580SValentin Clement   }
1378af6ee580SValentin Clement };
1379af6ee580SValentin Clement 
13801f551032SValentin Clement /// Compute the extent of a triplet slice (lb:ub:step).
13811f551032SValentin Clement static mlir::Value
13821f551032SValentin Clement computeTripletExtent(mlir::ConversionPatternRewriter &rewriter,
13831f551032SValentin Clement                      mlir::Location loc, mlir::Value lb, mlir::Value ub,
13841f551032SValentin Clement                      mlir::Value step, mlir::Value zero, mlir::Type type) {
13851f551032SValentin Clement   mlir::Value extent = rewriter.create<mlir::LLVM::SubOp>(loc, type, ub, lb);
13861f551032SValentin Clement   extent = rewriter.create<mlir::LLVM::AddOp>(loc, type, extent, step);
13871f551032SValentin Clement   extent = rewriter.create<mlir::LLVM::SDivOp>(loc, type, extent, step);
13881f551032SValentin Clement   // If the resulting extent is negative (`ub-lb` and `step` have different
13891f551032SValentin Clement   // signs), zero must be returned instead.
13901f551032SValentin Clement   auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
13911f551032SValentin Clement       loc, mlir::LLVM::ICmpPredicate::sgt, extent, zero);
13921f551032SValentin Clement   return rewriter.create<mlir::LLVM::SelectOp>(loc, cmp, extent, zero);
13931f551032SValentin Clement }
13941f551032SValentin Clement 
1395af6ee580SValentin Clement /// Create a generic box on a memory reference. This conversions lowers the
1396af6ee580SValentin Clement /// abstract box to the appropriate, initialized descriptor.
1397af6ee580SValentin Clement struct EmboxOpConversion : public EmboxCommonConversion<fir::EmboxOp> {
1398af6ee580SValentin Clement   using EmboxCommonConversion::EmboxCommonConversion;
1399af6ee580SValentin Clement 
1400af6ee580SValentin Clement   mlir::LogicalResult
1401af6ee580SValentin Clement   matchAndRewrite(fir::EmboxOp embox, OpAdaptor adaptor,
1402af6ee580SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1403af6ee580SValentin Clement     assert(!embox.getShape() && "There should be no dims on this embox op");
1404af6ee580SValentin Clement     auto [boxTy, dest, eleSize] =
1405af6ee580SValentin Clement         consDescriptorPrefix(embox, rewriter, /*rank=*/0,
1406af6ee580SValentin Clement                              /*lenParams=*/adaptor.getOperands().drop_front(1));
1407af6ee580SValentin Clement     dest = insertBaseAddress(rewriter, embox.getLoc(), dest,
1408af6ee580SValentin Clement                              adaptor.getOperands()[0]);
14097ce8c6fcSKiran Chandramohan     if (isDerivedTypeWithLenParams(boxTy)) {
14107ce8c6fcSKiran Chandramohan       TODO(embox.getLoc(),
14117ce8c6fcSKiran Chandramohan            "fir.embox codegen of derived with length parameters");
14127ce8c6fcSKiran Chandramohan       return failure();
14137ce8c6fcSKiran Chandramohan     }
1414af6ee580SValentin Clement     auto result = placeInMemoryIfNotGlobalInit(rewriter, embox.getLoc(), dest);
1415af6ee580SValentin Clement     rewriter.replaceOp(embox, result);
1416af6ee580SValentin Clement     return success();
1417af6ee580SValentin Clement   }
1418af6ee580SValentin Clement };
1419af6ee580SValentin Clement 
14201f551032SValentin Clement /// Create a generic box on a memory reference.
14211f551032SValentin Clement struct XEmboxOpConversion : public EmboxCommonConversion<fir::cg::XEmboxOp> {
14221f551032SValentin Clement   using EmboxCommonConversion::EmboxCommonConversion;
14231f551032SValentin Clement 
14241f551032SValentin Clement   mlir::LogicalResult
14251f551032SValentin Clement   matchAndRewrite(fir::cg::XEmboxOp xbox, OpAdaptor adaptor,
14261f551032SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
14271f551032SValentin Clement     auto [boxTy, dest, eleSize] = consDescriptorPrefix(
14281f551032SValentin Clement         xbox, rewriter, xbox.getOutRank(),
14291f551032SValentin Clement         adaptor.getOperands().drop_front(xbox.lenParamOffset()));
14301f551032SValentin Clement     // Generate the triples in the dims field of the descriptor
14311f551032SValentin Clement     mlir::ValueRange operands = adaptor.getOperands();
14321f551032SValentin Clement     auto i64Ty = mlir::IntegerType::get(xbox.getContext(), 64);
14331f551032SValentin Clement     mlir::Value base = operands[0];
14341f551032SValentin Clement     assert(!xbox.shape().empty() && "must have a shape");
14351f551032SValentin Clement     unsigned shapeOffset = xbox.shapeOffset();
14361f551032SValentin Clement     bool hasShift = !xbox.shift().empty();
14371f551032SValentin Clement     unsigned shiftOffset = xbox.shiftOffset();
14381f551032SValentin Clement     bool hasSlice = !xbox.slice().empty();
14391f551032SValentin Clement     unsigned sliceOffset = xbox.sliceOffset();
14401f551032SValentin Clement     mlir::Location loc = xbox.getLoc();
14411f551032SValentin Clement     mlir::Value zero = genConstantIndex(loc, i64Ty, rewriter, 0);
14421f551032SValentin Clement     mlir::Value one = genConstantIndex(loc, i64Ty, rewriter, 1);
14431f551032SValentin Clement     mlir::Value prevDim = integerCast(loc, rewriter, i64Ty, eleSize);
14441f551032SValentin Clement     mlir::Value prevPtrOff = one;
14451f551032SValentin Clement     mlir::Type eleTy = boxTy.getEleTy();
14461f551032SValentin Clement     const unsigned rank = xbox.getRank();
14471f551032SValentin Clement     llvm::SmallVector<mlir::Value> gepArgs;
14481f551032SValentin Clement     unsigned constRows = 0;
14491f551032SValentin Clement     mlir::Value ptrOffset = zero;
14501f551032SValentin Clement     if (auto memEleTy = fir::dyn_cast_ptrEleTy(xbox.memref().getType()))
14511f551032SValentin Clement       if (auto seqTy = memEleTy.dyn_cast<fir::SequenceType>()) {
14521f551032SValentin Clement         mlir::Type seqEleTy = seqTy.getEleTy();
14531f551032SValentin Clement         // Adjust the element scaling factor if the element is a dependent type.
14541f551032SValentin Clement         if (fir::hasDynamicSize(seqEleTy)) {
14551f551032SValentin Clement           if (fir::isa_char(seqEleTy)) {
14561f551032SValentin Clement             assert(xbox.lenParams().size() == 1);
14571f551032SValentin Clement             prevPtrOff = integerCast(loc, rewriter, i64Ty,
14581f551032SValentin Clement                                      operands[xbox.lenParamOffset()]);
14591f551032SValentin Clement           } else if (seqEleTy.isa<fir::RecordType>()) {
14601f551032SValentin Clement             TODO(loc, "generate call to calculate size of PDT");
14611f551032SValentin Clement           } else {
14621f551032SValentin Clement             return rewriter.notifyMatchFailure(xbox, "unexpected dynamic type");
14631f551032SValentin Clement           }
14641f551032SValentin Clement         } else {
14651f551032SValentin Clement           constRows = seqTy.getConstantRows();
14661f551032SValentin Clement         }
14671f551032SValentin Clement       }
14681f551032SValentin Clement 
14691f551032SValentin Clement     bool hasSubcomp = !xbox.subcomponent().empty();
14701f551032SValentin Clement     mlir::Value stepExpr;
14711f551032SValentin Clement     if (hasSubcomp) {
14721f551032SValentin Clement       // We have a subcomponent. The step value needs to be the number of
14731f551032SValentin Clement       // bytes per element (which is a derived type).
14741f551032SValentin Clement       mlir::Type ty0 = base.getType();
14751f551032SValentin Clement       [[maybe_unused]] auto ptrTy = ty0.dyn_cast<mlir::LLVM::LLVMPointerType>();
14761f551032SValentin Clement       assert(ptrTy && "expected pointer type");
14771f551032SValentin Clement       mlir::Type memEleTy = fir::dyn_cast_ptrEleTy(xbox.memref().getType());
14781f551032SValentin Clement       assert(memEleTy && "expected fir pointer type");
14791f551032SValentin Clement       auto seqTy = memEleTy.dyn_cast<fir::SequenceType>();
14801f551032SValentin Clement       assert(seqTy && "expected sequence type");
14811f551032SValentin Clement       mlir::Type seqEleTy = seqTy.getEleTy();
14821f551032SValentin Clement       auto eleTy = mlir::LLVM::LLVMPointerType::get(convertType(seqEleTy));
14831f551032SValentin Clement       stepExpr = computeDerivedTypeSize(loc, eleTy, i64Ty, rewriter);
14841f551032SValentin Clement     }
14851f551032SValentin Clement 
14861f551032SValentin Clement     // Process the array subspace arguments (shape, shift, etc.), if any,
14871f551032SValentin Clement     // translating everything to values in the descriptor wherever the entity
14881f551032SValentin Clement     // has a dynamic array dimension.
14891f551032SValentin Clement     for (unsigned di = 0, descIdx = 0; di < rank; ++di) {
14901f551032SValentin Clement       mlir::Value extent = operands[shapeOffset];
14911f551032SValentin Clement       mlir::Value outerExtent = extent;
14921f551032SValentin Clement       bool skipNext = false;
14931f551032SValentin Clement       if (hasSlice) {
14941f551032SValentin Clement         mlir::Value off = operands[sliceOffset];
14951f551032SValentin Clement         mlir::Value adj = one;
14961f551032SValentin Clement         if (hasShift)
14971f551032SValentin Clement           adj = operands[shiftOffset];
14981f551032SValentin Clement         auto ao = rewriter.create<mlir::LLVM::SubOp>(loc, i64Ty, off, adj);
14991f551032SValentin Clement         if (constRows > 0) {
15001f551032SValentin Clement           gepArgs.push_back(ao);
15011f551032SValentin Clement           --constRows;
15021f551032SValentin Clement         } else {
15031f551032SValentin Clement           auto dimOff =
15041f551032SValentin Clement               rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, ao, prevPtrOff);
15051f551032SValentin Clement           ptrOffset =
15061f551032SValentin Clement               rewriter.create<mlir::LLVM::AddOp>(loc, i64Ty, dimOff, ptrOffset);
15071f551032SValentin Clement         }
15081f551032SValentin Clement         if (mlir::isa_and_nonnull<fir::UndefOp>(
15091f551032SValentin Clement                 xbox.slice()[3 * di + 1].getDefiningOp())) {
15101f551032SValentin Clement           // This dimension contains a scalar expression in the array slice op.
15111f551032SValentin Clement           // The dimension is loop invariant, will be dropped, and will not
15121f551032SValentin Clement           // appear in the descriptor.
15131f551032SValentin Clement           skipNext = true;
15141f551032SValentin Clement         }
15151f551032SValentin Clement       }
15161f551032SValentin Clement       if (!skipNext) {
15171f551032SValentin Clement         // store lower bound (normally 0)
15181f551032SValentin Clement         mlir::Value lb = zero;
15191f551032SValentin Clement         if (eleTy.isa<fir::PointerType>() || eleTy.isa<fir::HeapType>()) {
15201f551032SValentin Clement           lb = one;
15211f551032SValentin Clement           if (hasShift)
15221f551032SValentin Clement             lb = operands[shiftOffset];
15231f551032SValentin Clement         }
15241f551032SValentin Clement         dest = insertLowerBound(rewriter, loc, dest, descIdx, lb);
15251f551032SValentin Clement 
15261f551032SValentin Clement         // store extent
15271f551032SValentin Clement         if (hasSlice)
15281f551032SValentin Clement           extent = computeTripletExtent(rewriter, loc, operands[sliceOffset],
15291f551032SValentin Clement                                         operands[sliceOffset + 1],
15301f551032SValentin Clement                                         operands[sliceOffset + 2], zero, i64Ty);
15311f551032SValentin Clement         dest = insertExtent(rewriter, loc, dest, descIdx, extent);
15321f551032SValentin Clement 
15331f551032SValentin Clement         // store step (scaled by shaped extent)
15341f551032SValentin Clement 
15351f551032SValentin Clement         mlir::Value step = hasSubcomp ? stepExpr : prevDim;
15361f551032SValentin Clement         if (hasSlice)
15371f551032SValentin Clement           step = rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, step,
15381f551032SValentin Clement                                                     operands[sliceOffset + 2]);
15391f551032SValentin Clement         dest = insertStride(rewriter, loc, dest, descIdx, step);
15401f551032SValentin Clement         ++descIdx;
15411f551032SValentin Clement       }
15421f551032SValentin Clement 
15431f551032SValentin Clement       // compute the stride and offset for the next natural dimension
15441f551032SValentin Clement       prevDim =
15451f551032SValentin Clement           rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, prevDim, outerExtent);
15461f551032SValentin Clement       if (constRows == 0)
15471f551032SValentin Clement         prevPtrOff = rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, prevPtrOff,
15481f551032SValentin Clement                                                         outerExtent);
15491f551032SValentin Clement 
15501f551032SValentin Clement       // increment iterators
15511f551032SValentin Clement       ++shapeOffset;
15521f551032SValentin Clement       if (hasShift)
15531f551032SValentin Clement         ++shiftOffset;
15541f551032SValentin Clement       if (hasSlice)
15551f551032SValentin Clement         sliceOffset += 3;
15561f551032SValentin Clement     }
15571f551032SValentin Clement     if (hasSlice || hasSubcomp || !xbox.substr().empty()) {
155830122656SAlex Zinenko       llvm::SmallVector<mlir::Value> args = {ptrOffset};
15591f551032SValentin Clement       args.append(gepArgs.rbegin(), gepArgs.rend());
15601f551032SValentin Clement       if (hasSubcomp) {
15611f551032SValentin Clement         // For each field in the path add the offset to base via the args list.
15621f551032SValentin Clement         // In the most general case, some offsets must be computed since
15631f551032SValentin Clement         // they are not be known until runtime.
15641f551032SValentin Clement         if (fir::hasDynamicSize(fir::unwrapSequenceType(
15651f551032SValentin Clement                 fir::unwrapPassByRefType(xbox.memref().getType()))))
15661f551032SValentin Clement           TODO(loc, "fir.embox codegen dynamic size component in derived type");
15671f551032SValentin Clement         args.append(operands.begin() + xbox.subcomponentOffset(),
15681f551032SValentin Clement                     operands.begin() + xbox.subcomponentOffset() +
15691f551032SValentin Clement                         xbox.subcomponent().size());
15701f551032SValentin Clement       }
157130122656SAlex Zinenko       base =
157230122656SAlex Zinenko           rewriter.create<mlir::LLVM::GEPOp>(loc, base.getType(), base, args);
15731f551032SValentin Clement       if (!xbox.substr().empty())
15741f551032SValentin Clement         base = shiftSubstringBase(rewriter, loc, base,
15751f551032SValentin Clement                                   operands[xbox.substrOffset()]);
15761f551032SValentin Clement     }
15771f551032SValentin Clement     dest = insertBaseAddress(rewriter, loc, dest, base);
15781f551032SValentin Clement     if (isDerivedTypeWithLenParams(boxTy))
15791f551032SValentin Clement       TODO(loc, "fir.embox codegen of derived with length parameters");
15801f551032SValentin Clement 
15811f551032SValentin Clement     mlir::Value result = placeInMemoryIfNotGlobalInit(rewriter, loc, dest);
15821f551032SValentin Clement     rewriter.replaceOp(xbox, result);
15831f551032SValentin Clement     return success();
15841f551032SValentin Clement   }
15851f551032SValentin Clement };
15861f551032SValentin Clement 
1587fa517555SKiran Chandramohan /// Create a new box given a box reference.
1588fa517555SKiran Chandramohan struct XReboxOpConversion : public EmboxCommonConversion<fir::cg::XReboxOp> {
1589fa517555SKiran Chandramohan   using EmboxCommonConversion::EmboxCommonConversion;
1590fa517555SKiran Chandramohan 
1591fa517555SKiran Chandramohan   mlir::LogicalResult
1592fa517555SKiran Chandramohan   matchAndRewrite(fir::cg::XReboxOp rebox, OpAdaptor adaptor,
1593fa517555SKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
1594fa517555SKiran Chandramohan     mlir::Location loc = rebox.getLoc();
1595fa517555SKiran Chandramohan     mlir::Type idxTy = lowerTy().indexType();
1596fa517555SKiran Chandramohan     mlir::Value loweredBox = adaptor.getOperands()[0];
1597fa517555SKiran Chandramohan     mlir::ValueRange operands = adaptor.getOperands();
1598fa517555SKiran Chandramohan 
1599fa517555SKiran Chandramohan     // Create new descriptor and fill its non-shape related data.
1600fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value, 2> lenParams;
1601fa517555SKiran Chandramohan     mlir::Type inputEleTy = getInputEleTy(rebox);
1602fa517555SKiran Chandramohan     if (auto charTy = inputEleTy.dyn_cast<fir::CharacterType>()) {
1603fa517555SKiran Chandramohan       mlir::Value len =
1604fa517555SKiran Chandramohan           loadElementSizeFromBox(loc, idxTy, loweredBox, rewriter);
1605fa517555SKiran Chandramohan       if (charTy.getFKind() != 1) {
1606fa517555SKiran Chandramohan         mlir::Value width =
1607fa517555SKiran Chandramohan             genConstantIndex(loc, idxTy, rewriter, charTy.getFKind());
1608fa517555SKiran Chandramohan         len = rewriter.create<mlir::LLVM::SDivOp>(loc, idxTy, len, width);
1609fa517555SKiran Chandramohan       }
1610fa517555SKiran Chandramohan       lenParams.emplace_back(len);
1611fa517555SKiran Chandramohan     } else if (auto recTy = inputEleTy.dyn_cast<fir::RecordType>()) {
1612fa517555SKiran Chandramohan       if (recTy.getNumLenParams() != 0)
1613fa517555SKiran Chandramohan         TODO(loc, "reboxing descriptor of derived type with length parameters");
1614fa517555SKiran Chandramohan     }
1615fa517555SKiran Chandramohan     auto [boxTy, dest, eleSize] =
1616fa517555SKiran Chandramohan         consDescriptorPrefix(rebox, rewriter, rebox.getOutRank(), lenParams);
1617fa517555SKiran Chandramohan 
1618fa517555SKiran Chandramohan     // Read input extents, strides, and base address
1619fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> inputExtents;
1620fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> inputStrides;
1621fa517555SKiran Chandramohan     const unsigned inputRank = rebox.getRank();
1622fa517555SKiran Chandramohan     for (unsigned i = 0; i < inputRank; ++i) {
1623fa517555SKiran Chandramohan       mlir::Value dim = genConstantIndex(loc, idxTy, rewriter, i);
1624fa517555SKiran Chandramohan       SmallVector<mlir::Value, 3> dimInfo =
1625fa517555SKiran Chandramohan           getDimsFromBox(loc, {idxTy, idxTy, idxTy}, loweredBox, dim, rewriter);
1626fa517555SKiran Chandramohan       inputExtents.emplace_back(dimInfo[1]);
1627fa517555SKiran Chandramohan       inputStrides.emplace_back(dimInfo[2]);
1628fa517555SKiran Chandramohan     }
1629fa517555SKiran Chandramohan 
1630fa517555SKiran Chandramohan     mlir::Type baseTy = getBaseAddrTypeFromBox(loweredBox.getType());
1631fa517555SKiran Chandramohan     mlir::Value baseAddr =
1632fa517555SKiran Chandramohan         loadBaseAddrFromBox(loc, baseTy, loweredBox, rewriter);
1633fa517555SKiran Chandramohan 
1634fa517555SKiran Chandramohan     if (!rebox.slice().empty() || !rebox.subcomponent().empty())
1635fa517555SKiran Chandramohan       return sliceBox(rebox, dest, baseAddr, inputExtents, inputStrides,
1636fa517555SKiran Chandramohan                       operands, rewriter);
1637fa517555SKiran Chandramohan     return reshapeBox(rebox, dest, baseAddr, inputExtents, inputStrides,
1638fa517555SKiran Chandramohan                       operands, rewriter);
1639fa517555SKiran Chandramohan   }
1640fa517555SKiran Chandramohan 
1641fa517555SKiran Chandramohan private:
1642fa517555SKiran Chandramohan   /// Write resulting shape and base address in descriptor, and replace rebox
1643fa517555SKiran Chandramohan   /// op.
1644fa517555SKiran Chandramohan   mlir::LogicalResult
1645fa517555SKiran Chandramohan   finalizeRebox(fir::cg::XReboxOp rebox, mlir::Value dest, mlir::Value base,
1646fa517555SKiran Chandramohan                 mlir::ValueRange lbounds, mlir::ValueRange extents,
1647fa517555SKiran Chandramohan                 mlir::ValueRange strides,
1648fa517555SKiran Chandramohan                 mlir::ConversionPatternRewriter &rewriter) const {
1649fa517555SKiran Chandramohan     mlir::Location loc = rebox.getLoc();
1650fa517555SKiran Chandramohan     mlir::Value one = genConstantIndex(loc, lowerTy().indexType(), rewriter, 1);
1651fa517555SKiran Chandramohan     for (auto iter : llvm::enumerate(llvm::zip(extents, strides))) {
1652fa517555SKiran Chandramohan       unsigned dim = iter.index();
1653fa517555SKiran Chandramohan       mlir::Value lb = lbounds.empty() ? one : lbounds[dim];
1654fa517555SKiran Chandramohan       dest = insertLowerBound(rewriter, loc, dest, dim, lb);
1655fa517555SKiran Chandramohan       dest = insertExtent(rewriter, loc, dest, dim, std::get<0>(iter.value()));
1656fa517555SKiran Chandramohan       dest = insertStride(rewriter, loc, dest, dim, std::get<1>(iter.value()));
1657fa517555SKiran Chandramohan     }
1658fa517555SKiran Chandramohan     dest = insertBaseAddress(rewriter, loc, dest, base);
1659fa517555SKiran Chandramohan     mlir::Value result =
1660fa517555SKiran Chandramohan         placeInMemoryIfNotGlobalInit(rewriter, rebox.getLoc(), dest);
1661fa517555SKiran Chandramohan     rewriter.replaceOp(rebox, result);
1662fa517555SKiran Chandramohan     return success();
1663fa517555SKiran Chandramohan   }
1664fa517555SKiran Chandramohan 
1665fa517555SKiran Chandramohan   // Apply slice given the base address, extents and strides of the input box.
1666fa517555SKiran Chandramohan   mlir::LogicalResult
1667fa517555SKiran Chandramohan   sliceBox(fir::cg::XReboxOp rebox, mlir::Value dest, mlir::Value base,
1668fa517555SKiran Chandramohan            mlir::ValueRange inputExtents, mlir::ValueRange inputStrides,
1669fa517555SKiran Chandramohan            mlir::ValueRange operands,
1670fa517555SKiran Chandramohan            mlir::ConversionPatternRewriter &rewriter) const {
1671fa517555SKiran Chandramohan     mlir::Location loc = rebox.getLoc();
1672fa517555SKiran Chandramohan     mlir::Type voidPtrTy = ::getVoidPtrType(rebox.getContext());
1673fa517555SKiran Chandramohan     mlir::Type idxTy = lowerTy().indexType();
1674fa517555SKiran Chandramohan     mlir::Value zero = genConstantIndex(loc, idxTy, rewriter, 0);
1675fa517555SKiran Chandramohan     // Apply subcomponent and substring shift on base address.
1676fa517555SKiran Chandramohan     if (!rebox.subcomponent().empty() || !rebox.substr().empty()) {
1677fa517555SKiran Chandramohan       // Cast to inputEleTy* so that a GEP can be used.
1678fa517555SKiran Chandramohan       mlir::Type inputEleTy = getInputEleTy(rebox);
1679fa517555SKiran Chandramohan       auto llvmElePtrTy =
1680fa517555SKiran Chandramohan           mlir::LLVM::LLVMPointerType::get(convertType(inputEleTy));
1681fa517555SKiran Chandramohan       base = rewriter.create<mlir::LLVM::BitcastOp>(loc, llvmElePtrTy, base);
1682fa517555SKiran Chandramohan 
1683fa517555SKiran Chandramohan       if (!rebox.subcomponent().empty()) {
1684fa517555SKiran Chandramohan         llvm::SmallVector<mlir::Value> gepOperands = {zero};
1685fa517555SKiran Chandramohan         for (unsigned i = 0; i < rebox.subcomponent().size(); ++i)
1686fa517555SKiran Chandramohan           gepOperands.push_back(operands[rebox.subcomponentOffset() + i]);
1687fa517555SKiran Chandramohan         base = genGEP(loc, llvmElePtrTy, rewriter, base, gepOperands);
1688fa517555SKiran Chandramohan       }
1689fa517555SKiran Chandramohan       if (!rebox.substr().empty())
1690fa517555SKiran Chandramohan         base = shiftSubstringBase(rewriter, loc, base,
1691fa517555SKiran Chandramohan                                   operands[rebox.substrOffset()]);
1692fa517555SKiran Chandramohan     }
1693fa517555SKiran Chandramohan 
1694fa517555SKiran Chandramohan     if (rebox.slice().empty())
1695fa517555SKiran Chandramohan       // The array section is of the form array[%component][substring], keep
1696fa517555SKiran Chandramohan       // the input array extents and strides.
1697fa517555SKiran Chandramohan       return finalizeRebox(rebox, dest, base, /*lbounds*/ llvm::None,
1698fa517555SKiran Chandramohan                            inputExtents, inputStrides, rewriter);
1699fa517555SKiran Chandramohan 
1700fa517555SKiran Chandramohan     // Strides from the fir.box are in bytes.
1701fa517555SKiran Chandramohan     base = rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, base);
1702fa517555SKiran Chandramohan 
1703fa517555SKiran Chandramohan     // The slice is of the form array(i:j:k)[%component]. Compute new extents
1704fa517555SKiran Chandramohan     // and strides.
1705fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> slicedExtents;
1706fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> slicedStrides;
1707fa517555SKiran Chandramohan     mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1);
1708fa517555SKiran Chandramohan     const bool sliceHasOrigins = !rebox.shift().empty();
1709fa517555SKiran Chandramohan     unsigned sliceOps = rebox.sliceOffset();
1710fa517555SKiran Chandramohan     unsigned shiftOps = rebox.shiftOffset();
1711fa517555SKiran Chandramohan     auto strideOps = inputStrides.begin();
1712fa517555SKiran Chandramohan     const unsigned inputRank = inputStrides.size();
1713fa517555SKiran Chandramohan     for (unsigned i = 0; i < inputRank;
1714fa517555SKiran Chandramohan          ++i, ++strideOps, ++shiftOps, sliceOps += 3) {
1715fa517555SKiran Chandramohan       mlir::Value sliceLb =
1716fa517555SKiran Chandramohan           integerCast(loc, rewriter, idxTy, operands[sliceOps]);
1717fa517555SKiran Chandramohan       mlir::Value inputStride = *strideOps; // already idxTy
1718fa517555SKiran Chandramohan       // Apply origin shift: base += (lb-shift)*input_stride
1719fa517555SKiran Chandramohan       mlir::Value sliceOrigin =
1720fa517555SKiran Chandramohan           sliceHasOrigins
1721fa517555SKiran Chandramohan               ? integerCast(loc, rewriter, idxTy, operands[shiftOps])
1722fa517555SKiran Chandramohan               : one;
1723fa517555SKiran Chandramohan       mlir::Value diff =
1724fa517555SKiran Chandramohan           rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, sliceLb, sliceOrigin);
1725fa517555SKiran Chandramohan       mlir::Value offset =
1726fa517555SKiran Chandramohan           rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, inputStride);
1727fa517555SKiran Chandramohan       base = genGEP(loc, voidPtrTy, rewriter, base, offset);
1728fa517555SKiran Chandramohan       // Apply upper bound and step if this is a triplet. Otherwise, the
1729fa517555SKiran Chandramohan       // dimension is dropped and no extents/strides are computed.
1730fa517555SKiran Chandramohan       mlir::Value upper = operands[sliceOps + 1];
1731fa517555SKiran Chandramohan       const bool isTripletSlice =
1732fa517555SKiran Chandramohan           !mlir::isa_and_nonnull<mlir::LLVM::UndefOp>(upper.getDefiningOp());
1733fa517555SKiran Chandramohan       if (isTripletSlice) {
1734fa517555SKiran Chandramohan         mlir::Value step =
1735fa517555SKiran Chandramohan             integerCast(loc, rewriter, idxTy, operands[sliceOps + 2]);
1736fa517555SKiran Chandramohan         // extent = ub-lb+step/step
1737fa517555SKiran Chandramohan         mlir::Value sliceUb = integerCast(loc, rewriter, idxTy, upper);
1738fa517555SKiran Chandramohan         mlir::Value extent = computeTripletExtent(rewriter, loc, sliceLb,
1739fa517555SKiran Chandramohan                                                   sliceUb, step, zero, idxTy);
1740fa517555SKiran Chandramohan         slicedExtents.emplace_back(extent);
1741fa517555SKiran Chandramohan         // stride = step*input_stride
1742fa517555SKiran Chandramohan         mlir::Value stride =
1743fa517555SKiran Chandramohan             rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, step, inputStride);
1744fa517555SKiran Chandramohan         slicedStrides.emplace_back(stride);
1745fa517555SKiran Chandramohan       }
1746fa517555SKiran Chandramohan     }
1747fa517555SKiran Chandramohan     return finalizeRebox(rebox, dest, base, /*lbounds*/ llvm::None,
1748fa517555SKiran Chandramohan                          slicedExtents, slicedStrides, rewriter);
1749fa517555SKiran Chandramohan   }
1750fa517555SKiran Chandramohan 
1751fa517555SKiran Chandramohan   /// Apply a new shape to the data described by a box given the base address,
1752fa517555SKiran Chandramohan   /// extents and strides of the box.
1753fa517555SKiran Chandramohan   mlir::LogicalResult
1754fa517555SKiran Chandramohan   reshapeBox(fir::cg::XReboxOp rebox, mlir::Value dest, mlir::Value base,
1755fa517555SKiran Chandramohan              mlir::ValueRange inputExtents, mlir::ValueRange inputStrides,
1756fa517555SKiran Chandramohan              mlir::ValueRange operands,
1757fa517555SKiran Chandramohan              mlir::ConversionPatternRewriter &rewriter) const {
1758fa517555SKiran Chandramohan     mlir::ValueRange reboxShifts{operands.begin() + rebox.shiftOffset(),
1759fa517555SKiran Chandramohan                                  operands.begin() + rebox.shiftOffset() +
1760fa517555SKiran Chandramohan                                      rebox.shift().size()};
1761fa517555SKiran Chandramohan     if (rebox.shape().empty()) {
1762fa517555SKiran Chandramohan       // Only setting new lower bounds.
1763fa517555SKiran Chandramohan       return finalizeRebox(rebox, dest, base, reboxShifts, inputExtents,
1764fa517555SKiran Chandramohan                            inputStrides, rewriter);
1765fa517555SKiran Chandramohan     }
1766fa517555SKiran Chandramohan 
1767fa517555SKiran Chandramohan     mlir::Location loc = rebox.getLoc();
1768fa517555SKiran Chandramohan     // Strides from the fir.box are in bytes.
1769fa517555SKiran Chandramohan     mlir::Type voidPtrTy = ::getVoidPtrType(rebox.getContext());
1770fa517555SKiran Chandramohan     base = rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, base);
1771fa517555SKiran Chandramohan 
1772fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> newStrides;
1773fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> newExtents;
1774fa517555SKiran Chandramohan     mlir::Type idxTy = lowerTy().indexType();
1775fa517555SKiran Chandramohan     // First stride from input box is kept. The rest is assumed contiguous
1776fa517555SKiran Chandramohan     // (it is not possible to reshape otherwise). If the input is scalar,
1777fa517555SKiran Chandramohan     // which may be OK if all new extents are ones, the stride does not
1778fa517555SKiran Chandramohan     // matter, use one.
1779fa517555SKiran Chandramohan     mlir::Value stride = inputStrides.empty()
1780fa517555SKiran Chandramohan                              ? genConstantIndex(loc, idxTy, rewriter, 1)
1781fa517555SKiran Chandramohan                              : inputStrides[0];
1782fa517555SKiran Chandramohan     for (unsigned i = 0; i < rebox.shape().size(); ++i) {
1783fa517555SKiran Chandramohan       mlir::Value rawExtent = operands[rebox.shapeOffset() + i];
1784fa517555SKiran Chandramohan       mlir::Value extent = integerCast(loc, rewriter, idxTy, rawExtent);
1785fa517555SKiran Chandramohan       newExtents.emplace_back(extent);
1786fa517555SKiran Chandramohan       newStrides.emplace_back(stride);
1787fa517555SKiran Chandramohan       // nextStride = extent * stride;
1788fa517555SKiran Chandramohan       stride = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, extent, stride);
1789fa517555SKiran Chandramohan     }
1790fa517555SKiran Chandramohan     return finalizeRebox(rebox, dest, base, reboxShifts, newExtents, newStrides,
1791fa517555SKiran Chandramohan                          rewriter);
1792fa517555SKiran Chandramohan   }
1793fa517555SKiran Chandramohan 
1794fa517555SKiran Chandramohan   /// Return scalar element type of the input box.
1795fa517555SKiran Chandramohan   static mlir::Type getInputEleTy(fir::cg::XReboxOp rebox) {
1796fa517555SKiran Chandramohan     auto ty = fir::dyn_cast_ptrOrBoxEleTy(rebox.box().getType());
1797fa517555SKiran Chandramohan     if (auto seqTy = ty.dyn_cast<fir::SequenceType>())
1798fa517555SKiran Chandramohan       return seqTy.getEleTy();
1799fa517555SKiran Chandramohan     return ty;
1800fa517555SKiran Chandramohan   }
1801fa517555SKiran Chandramohan };
1802fa517555SKiran Chandramohan 
1803*dc48849fSKiran Chandramohan /// Lower `fir.emboxproc` operation. Creates a procedure box.
1804*dc48849fSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
1805*dc48849fSKiran Chandramohan struct EmboxProcOpConversion : public FIROpConversion<fir::EmboxProcOp> {
1806*dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
1807*dc48849fSKiran Chandramohan 
1808*dc48849fSKiran Chandramohan   mlir::LogicalResult
1809*dc48849fSKiran Chandramohan   matchAndRewrite(fir::EmboxProcOp emboxproc, OpAdaptor adaptor,
1810*dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
1811*dc48849fSKiran Chandramohan     TODO(emboxproc.getLoc(), "fir.emboxproc codegen");
1812*dc48849fSKiran Chandramohan     return failure();
1813*dc48849fSKiran Chandramohan   }
1814*dc48849fSKiran Chandramohan };
1815*dc48849fSKiran Chandramohan 
181654c56347SValentin Clement // Code shared between insert_value and extract_value Ops.
181754c56347SValentin Clement struct ValueOpCommon {
181854c56347SValentin Clement   // Translate the arguments pertaining to any multidimensional array to
181954c56347SValentin Clement   // row-major order for LLVM-IR.
182054c56347SValentin Clement   static void toRowMajor(SmallVectorImpl<mlir::Attribute> &attrs,
182154c56347SValentin Clement                          mlir::Type ty) {
182254c56347SValentin Clement     assert(ty && "type is null");
182354c56347SValentin Clement     const auto end = attrs.size();
182454c56347SValentin Clement     for (std::remove_const_t<decltype(end)> i = 0; i < end; ++i) {
182554c56347SValentin Clement       if (auto seq = ty.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
182654c56347SValentin Clement         const auto dim = getDimension(seq);
182754c56347SValentin Clement         if (dim > 1) {
182854c56347SValentin Clement           auto ub = std::min(i + dim, end);
182954c56347SValentin Clement           std::reverse(attrs.begin() + i, attrs.begin() + ub);
183054c56347SValentin Clement           i += dim - 1;
183154c56347SValentin Clement         }
183254c56347SValentin Clement         ty = getArrayElementType(seq);
183354c56347SValentin Clement       } else if (auto st = ty.dyn_cast<mlir::LLVM::LLVMStructType>()) {
183454c56347SValentin Clement         ty = st.getBody()[attrs[i].cast<mlir::IntegerAttr>().getInt()];
183554c56347SValentin Clement       } else {
183654c56347SValentin Clement         llvm_unreachable("index into invalid type");
183754c56347SValentin Clement       }
183854c56347SValentin Clement     }
183954c56347SValentin Clement   }
184054c56347SValentin Clement 
184154c56347SValentin Clement   static llvm::SmallVector<mlir::Attribute>
184254c56347SValentin Clement   collectIndices(mlir::ConversionPatternRewriter &rewriter,
184354c56347SValentin Clement                  mlir::ArrayAttr arrAttr) {
184454c56347SValentin Clement     llvm::SmallVector<mlir::Attribute> attrs;
184554c56347SValentin Clement     for (auto i = arrAttr.begin(), e = arrAttr.end(); i != e; ++i) {
184654c56347SValentin Clement       if (i->isa<mlir::IntegerAttr>()) {
184754c56347SValentin Clement         attrs.push_back(*i);
184854c56347SValentin Clement       } else {
184954c56347SValentin Clement         auto fieldName = i->cast<mlir::StringAttr>().getValue();
185054c56347SValentin Clement         ++i;
185154c56347SValentin Clement         auto ty = i->cast<mlir::TypeAttr>().getValue();
185254c56347SValentin Clement         auto index = ty.cast<fir::RecordType>().getFieldIndex(fieldName);
185354c56347SValentin Clement         attrs.push_back(mlir::IntegerAttr::get(rewriter.getI32Type(), index));
185454c56347SValentin Clement       }
185554c56347SValentin Clement     }
185654c56347SValentin Clement     return attrs;
185754c56347SValentin Clement   }
185854c56347SValentin Clement 
185954c56347SValentin Clement private:
186054c56347SValentin Clement   static unsigned getDimension(mlir::LLVM::LLVMArrayType ty) {
186154c56347SValentin Clement     unsigned result = 1;
186254c56347SValentin Clement     for (auto eleTy = ty.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>();
186354c56347SValentin Clement          eleTy;
186454c56347SValentin Clement          eleTy = eleTy.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>())
186554c56347SValentin Clement       ++result;
186654c56347SValentin Clement     return result;
186754c56347SValentin Clement   }
186854c56347SValentin Clement 
186954c56347SValentin Clement   static mlir::Type getArrayElementType(mlir::LLVM::LLVMArrayType ty) {
187054c56347SValentin Clement     auto eleTy = ty.getElementType();
187154c56347SValentin Clement     while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>())
187254c56347SValentin Clement       eleTy = arrTy.getElementType();
187354c56347SValentin Clement     return eleTy;
187454c56347SValentin Clement   }
187554c56347SValentin Clement };
187654c56347SValentin Clement 
1877c2acd453SAlexisPerry namespace {
187854c56347SValentin Clement /// Extract a subobject value from an ssa-value of aggregate type
187954c56347SValentin Clement struct ExtractValueOpConversion
188054c56347SValentin Clement     : public FIROpAndTypeConversion<fir::ExtractValueOp>,
188154c56347SValentin Clement       public ValueOpCommon {
188254c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
188354c56347SValentin Clement 
188454c56347SValentin Clement   mlir::LogicalResult
188554c56347SValentin Clement   doRewrite(fir::ExtractValueOp extractVal, mlir::Type ty, OpAdaptor adaptor,
188654c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
1887149ad3d5SShraiysh Vaishay     auto attrs = collectIndices(rewriter, extractVal.getCoor());
188854c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
188954c56347SValentin Clement     auto position = mlir::ArrayAttr::get(extractVal.getContext(), attrs);
189054c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(
189154c56347SValentin Clement         extractVal, ty, adaptor.getOperands()[0], position);
189254c56347SValentin Clement     return success();
189354c56347SValentin Clement   }
189454c56347SValentin Clement };
189554c56347SValentin Clement 
189654c56347SValentin Clement /// InsertValue is the generalized instruction for the composition of new
189754c56347SValentin Clement /// aggregate type values.
189854c56347SValentin Clement struct InsertValueOpConversion
189954c56347SValentin Clement     : public FIROpAndTypeConversion<fir::InsertValueOp>,
190054c56347SValentin Clement       public ValueOpCommon {
190154c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
190254c56347SValentin Clement 
190354c56347SValentin Clement   mlir::LogicalResult
190454c56347SValentin Clement   doRewrite(fir::InsertValueOp insertVal, mlir::Type ty, OpAdaptor adaptor,
190554c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
1906149ad3d5SShraiysh Vaishay     auto attrs = collectIndices(rewriter, insertVal.getCoor());
190754c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
190854c56347SValentin Clement     auto position = mlir::ArrayAttr::get(insertVal.getContext(), attrs);
190954c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
191054c56347SValentin Clement         insertVal, ty, adaptor.getOperands()[0], adaptor.getOperands()[1],
191154c56347SValentin Clement         position);
191254c56347SValentin Clement     return success();
191354c56347SValentin Clement   }
191454c56347SValentin Clement };
191554c56347SValentin Clement 
19163ae8e442SValentin Clement /// InsertOnRange inserts a value into a sequence over a range of offsets.
19173ae8e442SValentin Clement struct InsertOnRangeOpConversion
19183ae8e442SValentin Clement     : public FIROpAndTypeConversion<fir::InsertOnRangeOp> {
19193ae8e442SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
19203ae8e442SValentin Clement 
19213ae8e442SValentin Clement   // Increments an array of subscripts in a row major fasion.
19223ae8e442SValentin Clement   void incrementSubscripts(const SmallVector<uint64_t> &dims,
19233ae8e442SValentin Clement                            SmallVector<uint64_t> &subscripts) const {
19243ae8e442SValentin Clement     for (size_t i = dims.size(); i > 0; --i) {
19253ae8e442SValentin Clement       if (++subscripts[i - 1] < dims[i - 1]) {
19263ae8e442SValentin Clement         return;
19273ae8e442SValentin Clement       }
19283ae8e442SValentin Clement       subscripts[i - 1] = 0;
19293ae8e442SValentin Clement     }
19303ae8e442SValentin Clement   }
19313ae8e442SValentin Clement 
19323ae8e442SValentin Clement   mlir::LogicalResult
19333ae8e442SValentin Clement   doRewrite(fir::InsertOnRangeOp range, mlir::Type ty, OpAdaptor adaptor,
19343ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
19353ae8e442SValentin Clement 
19363ae8e442SValentin Clement     llvm::SmallVector<uint64_t> dims;
19373ae8e442SValentin Clement     auto type = adaptor.getOperands()[0].getType();
19383ae8e442SValentin Clement 
19393ae8e442SValentin Clement     // Iteratively extract the array dimensions from the type.
19403ae8e442SValentin Clement     while (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
19413ae8e442SValentin Clement       dims.push_back(t.getNumElements());
19423ae8e442SValentin Clement       type = t.getElementType();
19433ae8e442SValentin Clement     }
19443ae8e442SValentin Clement 
19453ae8e442SValentin Clement     SmallVector<uint64_t> lBounds;
19463ae8e442SValentin Clement     SmallVector<uint64_t> uBounds;
19473ae8e442SValentin Clement 
19483ae8e442SValentin Clement     // Unzip the upper and lower bound and convert to a row major format.
1949149ad3d5SShraiysh Vaishay     mlir::DenseIntElementsAttr coor = range.getCoor();
19508ec0f221SMehdi Amini     auto reversedCoor = llvm::reverse(coor.getValues<int64_t>());
19518ec0f221SMehdi Amini     for (auto i = reversedCoor.begin(), e = reversedCoor.end(); i != e; ++i) {
19523ae8e442SValentin Clement       uBounds.push_back(*i++);
19533ae8e442SValentin Clement       lBounds.push_back(*i);
19543ae8e442SValentin Clement     }
19553ae8e442SValentin Clement 
19563ae8e442SValentin Clement     auto &subscripts = lBounds;
19573ae8e442SValentin Clement     auto loc = range.getLoc();
19583ae8e442SValentin Clement     mlir::Value lastOp = adaptor.getOperands()[0];
19593ae8e442SValentin Clement     mlir::Value insertVal = adaptor.getOperands()[1];
19603ae8e442SValentin Clement 
19613ae8e442SValentin Clement     auto i64Ty = rewriter.getI64Type();
19623ae8e442SValentin Clement     while (subscripts != uBounds) {
19633ae8e442SValentin Clement       // Convert uint64_t's to Attribute's.
19643ae8e442SValentin Clement       SmallVector<mlir::Attribute> subscriptAttrs;
19653ae8e442SValentin Clement       for (const auto &subscript : subscripts)
19663ae8e442SValentin Clement         subscriptAttrs.push_back(IntegerAttr::get(i64Ty, subscript));
19673ae8e442SValentin Clement       lastOp = rewriter.create<mlir::LLVM::InsertValueOp>(
19683ae8e442SValentin Clement           loc, ty, lastOp, insertVal,
19693ae8e442SValentin Clement           ArrayAttr::get(range.getContext(), subscriptAttrs));
19703ae8e442SValentin Clement 
19713ae8e442SValentin Clement       incrementSubscripts(dims, subscripts);
19723ae8e442SValentin Clement     }
19733ae8e442SValentin Clement 
19743ae8e442SValentin Clement     // Convert uint64_t's to Attribute's.
19753ae8e442SValentin Clement     SmallVector<mlir::Attribute> subscriptAttrs;
19763ae8e442SValentin Clement     for (const auto &subscript : subscripts)
19773ae8e442SValentin Clement       subscriptAttrs.push_back(
19783ae8e442SValentin Clement           IntegerAttr::get(rewriter.getI64Type(), subscript));
19793ae8e442SValentin Clement     mlir::ArrayRef<mlir::Attribute> arrayRef(subscriptAttrs);
19803ae8e442SValentin Clement 
19813ae8e442SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
19823ae8e442SValentin Clement         range, ty, lastOp, insertVal,
19833ae8e442SValentin Clement         ArrayAttr::get(range.getContext(), arrayRef));
19843ae8e442SValentin Clement 
19853ae8e442SValentin Clement     return success();
19863ae8e442SValentin Clement   }
19873ae8e442SValentin Clement };
1988c2acd453SAlexisPerry } // namespace
19897b5132daSValentin Clement 
1990*dc48849fSKiran Chandramohan namespace {
19915d27abe6SValentin Clement /// XArrayCoor is the address arithmetic on a dynamically shaped, sliced,
19925d27abe6SValentin Clement /// shifted etc. array.
19935d27abe6SValentin Clement /// (See the static restriction on coordinate_of.) array_coor determines the
19945d27abe6SValentin Clement /// coordinate (location) of a specific element.
19955d27abe6SValentin Clement struct XArrayCoorOpConversion
19965d27abe6SValentin Clement     : public FIROpAndTypeConversion<fir::cg::XArrayCoorOp> {
19975d27abe6SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
19985d27abe6SValentin Clement 
19995d27abe6SValentin Clement   mlir::LogicalResult
20005d27abe6SValentin Clement   doRewrite(fir::cg::XArrayCoorOp coor, mlir::Type ty, OpAdaptor adaptor,
20015d27abe6SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
20025d27abe6SValentin Clement     auto loc = coor.getLoc();
20035d27abe6SValentin Clement     mlir::ValueRange operands = adaptor.getOperands();
20045d27abe6SValentin Clement     unsigned rank = coor.getRank();
20055d27abe6SValentin Clement     assert(coor.indices().size() == rank);
20065d27abe6SValentin Clement     assert(coor.shape().empty() || coor.shape().size() == rank);
20075d27abe6SValentin Clement     assert(coor.shift().empty() || coor.shift().size() == rank);
20085d27abe6SValentin Clement     assert(coor.slice().empty() || coor.slice().size() == 3 * rank);
20095d27abe6SValentin Clement     mlir::Type idxTy = lowerTy().indexType();
20105d27abe6SValentin Clement     mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1);
20115d27abe6SValentin Clement     mlir::Value prevExt = one;
20125d27abe6SValentin Clement     mlir::Value zero = genConstantIndex(loc, idxTy, rewriter, 0);
20135d27abe6SValentin Clement     mlir::Value offset = zero;
20145d27abe6SValentin Clement     const bool isShifted = !coor.shift().empty();
20155d27abe6SValentin Clement     const bool isSliced = !coor.slice().empty();
20165d27abe6SValentin Clement     const bool baseIsBoxed = coor.memref().getType().isa<fir::BoxType>();
20175d27abe6SValentin Clement 
20185d27abe6SValentin Clement     auto indexOps = coor.indices().begin();
20195d27abe6SValentin Clement     auto shapeOps = coor.shape().begin();
20205d27abe6SValentin Clement     auto shiftOps = coor.shift().begin();
20215d27abe6SValentin Clement     auto sliceOps = coor.slice().begin();
20225d27abe6SValentin Clement     // For each dimension of the array, generate the offset calculation.
20235d27abe6SValentin Clement     for (unsigned i = 0; i < rank;
20245d27abe6SValentin Clement          ++i, ++indexOps, ++shapeOps, ++shiftOps, sliceOps += 3) {
20255d27abe6SValentin Clement       mlir::Value index =
20265d27abe6SValentin Clement           integerCast(loc, rewriter, idxTy, operands[coor.indicesOffset() + i]);
20275d27abe6SValentin Clement       mlir::Value lb = isShifted ? integerCast(loc, rewriter, idxTy,
20285d27abe6SValentin Clement                                                operands[coor.shiftOffset() + i])
20295d27abe6SValentin Clement                                  : one;
20305d27abe6SValentin Clement       mlir::Value step = one;
20315d27abe6SValentin Clement       bool normalSlice = isSliced;
20325d27abe6SValentin Clement       // Compute zero based index in dimension i of the element, applying
20335d27abe6SValentin Clement       // potential triplets and lower bounds.
20345d27abe6SValentin Clement       if (isSliced) {
20355d27abe6SValentin Clement         mlir::Value ub = *(sliceOps + 1);
20365d27abe6SValentin Clement         normalSlice = !mlir::isa_and_nonnull<fir::UndefOp>(ub.getDefiningOp());
20375d27abe6SValentin Clement         if (normalSlice)
20385d27abe6SValentin Clement           step = integerCast(loc, rewriter, idxTy, *(sliceOps + 2));
20395d27abe6SValentin Clement       }
20405d27abe6SValentin Clement       auto idx = rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, index, lb);
20415d27abe6SValentin Clement       mlir::Value diff =
20425d27abe6SValentin Clement           rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, idx, step);
20435d27abe6SValentin Clement       if (normalSlice) {
20445d27abe6SValentin Clement         mlir::Value sliceLb =
20455d27abe6SValentin Clement             integerCast(loc, rewriter, idxTy, operands[coor.sliceOffset() + i]);
20465d27abe6SValentin Clement         auto adj = rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, sliceLb, lb);
20475d27abe6SValentin Clement         diff = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, diff, adj);
20485d27abe6SValentin Clement       }
20495d27abe6SValentin Clement       // Update the offset given the stride and the zero based index `diff`
20505d27abe6SValentin Clement       // that was just computed.
20515d27abe6SValentin Clement       if (baseIsBoxed) {
20525d27abe6SValentin Clement         // Use stride in bytes from the descriptor.
20535d27abe6SValentin Clement         mlir::Value stride =
20545d27abe6SValentin Clement             loadStrideFromBox(loc, adaptor.getOperands()[0], i, rewriter);
20555d27abe6SValentin Clement         auto sc = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, stride);
20565d27abe6SValentin Clement         offset = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, offset);
20575d27abe6SValentin Clement       } else {
20585d27abe6SValentin Clement         // Use stride computed at last iteration.
20595d27abe6SValentin Clement         auto sc = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, prevExt);
20605d27abe6SValentin Clement         offset = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, offset);
20615d27abe6SValentin Clement         // Compute next stride assuming contiguity of the base array
20625d27abe6SValentin Clement         // (in element number).
20635d27abe6SValentin Clement         auto nextExt =
20645d27abe6SValentin Clement             integerCast(loc, rewriter, idxTy, operands[coor.shapeOffset() + i]);
20655d27abe6SValentin Clement         prevExt =
20665d27abe6SValentin Clement             rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, prevExt, nextExt);
20675d27abe6SValentin Clement       }
20685d27abe6SValentin Clement     }
20695d27abe6SValentin Clement 
20705d27abe6SValentin Clement     // Add computed offset to the base address.
20715d27abe6SValentin Clement     if (baseIsBoxed) {
20725d27abe6SValentin Clement       // Working with byte offsets. The base address is read from the fir.box.
20735d27abe6SValentin Clement       // and need to be casted to i8* to do the pointer arithmetic.
20745d27abe6SValentin Clement       mlir::Type baseTy =
20755d27abe6SValentin Clement           getBaseAddrTypeFromBox(adaptor.getOperands()[0].getType());
20765d27abe6SValentin Clement       mlir::Value base =
20775d27abe6SValentin Clement           loadBaseAddrFromBox(loc, baseTy, adaptor.getOperands()[0], rewriter);
20785d27abe6SValentin Clement       mlir::Type voidPtrTy = getVoidPtrType();
20795d27abe6SValentin Clement       base = rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, base);
208030122656SAlex Zinenko       llvm::SmallVector<mlir::Value> args{offset};
208130122656SAlex Zinenko       auto addr =
208230122656SAlex Zinenko           rewriter.create<mlir::LLVM::GEPOp>(loc, voidPtrTy, base, args);
20835d27abe6SValentin Clement       if (coor.subcomponent().empty()) {
20845d27abe6SValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(coor, baseTy, addr);
20855d27abe6SValentin Clement         return success();
20865d27abe6SValentin Clement       }
20875d27abe6SValentin Clement       auto casted = rewriter.create<mlir::LLVM::BitcastOp>(loc, baseTy, addr);
20885d27abe6SValentin Clement       args.clear();
20895d27abe6SValentin Clement       args.push_back(zero);
20905d27abe6SValentin Clement       if (!coor.lenParams().empty()) {
20915d27abe6SValentin Clement         // If type parameters are present, then we don't want to use a GEPOp
20925d27abe6SValentin Clement         // as below, as the LLVM struct type cannot be statically defined.
20935d27abe6SValentin Clement         TODO(loc, "derived type with type parameters");
20945d27abe6SValentin Clement       }
20955d27abe6SValentin Clement       // TODO: array offset subcomponents must be converted to LLVM's
20965d27abe6SValentin Clement       // row-major layout here.
20975d27abe6SValentin Clement       for (auto i = coor.subcomponentOffset(); i != coor.indicesOffset(); ++i)
20985d27abe6SValentin Clement         args.push_back(operands[i]);
209930122656SAlex Zinenko       rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(coor, baseTy, casted,
210030122656SAlex Zinenko                                                      args);
21015d27abe6SValentin Clement       return success();
21025d27abe6SValentin Clement     }
21035d27abe6SValentin Clement 
21045d27abe6SValentin Clement     // The array was not boxed, so it must be contiguous. offset is therefore an
21055d27abe6SValentin Clement     // element offset and the base type is kept in the GEP unless the element
21065d27abe6SValentin Clement     // type size is itself dynamic.
21075d27abe6SValentin Clement     mlir::Value base;
21085d27abe6SValentin Clement     if (coor.subcomponent().empty()) {
21095d27abe6SValentin Clement       // No subcomponent.
21105d27abe6SValentin Clement       if (!coor.lenParams().empty()) {
21115d27abe6SValentin Clement         // Type parameters. Adjust element size explicitly.
21125d27abe6SValentin Clement         auto eleTy = fir::dyn_cast_ptrEleTy(coor.getType());
21135d27abe6SValentin Clement         assert(eleTy && "result must be a reference-like type");
21145d27abe6SValentin Clement         if (fir::characterWithDynamicLen(eleTy)) {
21155d27abe6SValentin Clement           assert(coor.lenParams().size() == 1);
21165d27abe6SValentin Clement           auto bitsInChar = lowerTy().getKindMap().getCharacterBitsize(
21175d27abe6SValentin Clement               eleTy.cast<fir::CharacterType>().getFKind());
21185d27abe6SValentin Clement           auto scaling = genConstantIndex(loc, idxTy, rewriter, bitsInChar / 8);
21195d27abe6SValentin Clement           auto scaledBySize =
21205d27abe6SValentin Clement               rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, offset, scaling);
21215d27abe6SValentin Clement           auto length =
21225d27abe6SValentin Clement               integerCast(loc, rewriter, idxTy,
21235d27abe6SValentin Clement                           adaptor.getOperands()[coor.lenParamsOffset()]);
21245d27abe6SValentin Clement           offset = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, scaledBySize,
21255d27abe6SValentin Clement                                                       length);
21265d27abe6SValentin Clement         } else {
21275d27abe6SValentin Clement           TODO(loc, "compute size of derived type with type parameters");
21285d27abe6SValentin Clement         }
21295d27abe6SValentin Clement       }
21305d27abe6SValentin Clement       // Cast the base address to a pointer to T.
21315d27abe6SValentin Clement       base = rewriter.create<mlir::LLVM::BitcastOp>(loc, ty,
21325d27abe6SValentin Clement                                                     adaptor.getOperands()[0]);
21335d27abe6SValentin Clement     } else {
21345d27abe6SValentin Clement       // Operand #0 must have a pointer type. For subcomponent slicing, we
21355d27abe6SValentin Clement       // want to cast away the array type and have a plain struct type.
21365d27abe6SValentin Clement       mlir::Type ty0 = adaptor.getOperands()[0].getType();
21375d27abe6SValentin Clement       auto ptrTy = ty0.dyn_cast<mlir::LLVM::LLVMPointerType>();
21385d27abe6SValentin Clement       assert(ptrTy && "expected pointer type");
21395d27abe6SValentin Clement       mlir::Type eleTy = ptrTy.getElementType();
21405d27abe6SValentin Clement       while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>())
21415d27abe6SValentin Clement         eleTy = arrTy.getElementType();
21425d27abe6SValentin Clement       auto newTy = mlir::LLVM::LLVMPointerType::get(eleTy);
21435d27abe6SValentin Clement       base = rewriter.create<mlir::LLVM::BitcastOp>(loc, newTy,
21445d27abe6SValentin Clement                                                     adaptor.getOperands()[0]);
21455d27abe6SValentin Clement     }
214630122656SAlex Zinenko     SmallVector<mlir::Value> args = {offset};
21475d27abe6SValentin Clement     for (auto i = coor.subcomponentOffset(); i != coor.indicesOffset(); ++i)
21485d27abe6SValentin Clement       args.push_back(operands[i]);
214930122656SAlex Zinenko     rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(coor, ty, base, args);
21505d27abe6SValentin Clement     return success();
21515d27abe6SValentin Clement   }
21525d27abe6SValentin Clement };
2153*dc48849fSKiran Chandramohan } // namespace
2154*dc48849fSKiran Chandramohan 
2155*dc48849fSKiran Chandramohan /// Convert to (memory) reference to a reference to a subobject.
2156*dc48849fSKiran Chandramohan /// The coordinate_of op is a Swiss army knife operation that can be used on
2157*dc48849fSKiran Chandramohan /// (memory) references to records, arrays, complex, etc. as well as boxes.
2158*dc48849fSKiran Chandramohan /// With unboxed arrays, there is the restriction that the array have a static
2159*dc48849fSKiran Chandramohan /// shape in all but the last column.
2160*dc48849fSKiran Chandramohan struct CoordinateOpConversion
2161*dc48849fSKiran Chandramohan     : public FIROpAndTypeConversion<fir::CoordinateOp> {
2162*dc48849fSKiran Chandramohan   using FIROpAndTypeConversion::FIROpAndTypeConversion;
2163*dc48849fSKiran Chandramohan 
2164*dc48849fSKiran Chandramohan   mlir::LogicalResult
2165*dc48849fSKiran Chandramohan   doRewrite(fir::CoordinateOp coor, mlir::Type ty, OpAdaptor adaptor,
2166*dc48849fSKiran Chandramohan             mlir::ConversionPatternRewriter &rewriter) const override {
2167*dc48849fSKiran Chandramohan     mlir::ValueRange operands = adaptor.getOperands();
2168*dc48849fSKiran Chandramohan 
2169*dc48849fSKiran Chandramohan     mlir::Location loc = coor.getLoc();
2170*dc48849fSKiran Chandramohan     mlir::Value base = operands[0];
2171*dc48849fSKiran Chandramohan     mlir::Type baseObjectTy = coor.getBaseType();
2172*dc48849fSKiran Chandramohan     mlir::Type objectTy = fir::dyn_cast_ptrOrBoxEleTy(baseObjectTy);
2173*dc48849fSKiran Chandramohan     assert(objectTy && "fir.coordinate_of expects a reference type");
2174*dc48849fSKiran Chandramohan 
2175*dc48849fSKiran Chandramohan     // Complex type - basically, extract the real or imaginary part
2176*dc48849fSKiran Chandramohan     if (fir::isa_complex(objectTy)) {
2177*dc48849fSKiran Chandramohan       mlir::LLVM::ConstantOp c0 =
2178*dc48849fSKiran Chandramohan           genConstantIndex(loc, lowerTy().indexType(), rewriter, 0);
2179*dc48849fSKiran Chandramohan       SmallVector<mlir::Value> offs = {c0, operands[1]};
2180*dc48849fSKiran Chandramohan       mlir::Value gep = genGEP(loc, ty, rewriter, base, offs);
2181*dc48849fSKiran Chandramohan       rewriter.replaceOp(coor, gep);
2182*dc48849fSKiran Chandramohan       return success();
2183*dc48849fSKiran Chandramohan     }
2184*dc48849fSKiran Chandramohan 
2185*dc48849fSKiran Chandramohan     // Boxed type - get the base pointer from the box
2186*dc48849fSKiran Chandramohan     if (baseObjectTy.dyn_cast<fir::BoxType>())
2187*dc48849fSKiran Chandramohan       return doRewriteBox(coor, ty, operands, loc, rewriter);
2188*dc48849fSKiran Chandramohan 
2189*dc48849fSKiran Chandramohan     // Reference or pointer type
2190*dc48849fSKiran Chandramohan     if (baseObjectTy.isa<fir::ReferenceType, fir::PointerType>())
2191*dc48849fSKiran Chandramohan       return doRewriteRefOrPtr(coor, ty, operands, loc, rewriter);
2192*dc48849fSKiran Chandramohan 
2193*dc48849fSKiran Chandramohan     return rewriter.notifyMatchFailure(
2194*dc48849fSKiran Chandramohan         coor, "fir.coordinate_of base operand has unsupported type");
2195*dc48849fSKiran Chandramohan   }
2196*dc48849fSKiran Chandramohan 
2197*dc48849fSKiran Chandramohan   unsigned getFieldNumber(fir::RecordType ty, mlir::Value op) const {
2198*dc48849fSKiran Chandramohan     return fir::hasDynamicSize(ty)
2199*dc48849fSKiran Chandramohan                ? op.getDefiningOp()
2200*dc48849fSKiran Chandramohan                      ->getAttrOfType<mlir::IntegerAttr>("field")
2201*dc48849fSKiran Chandramohan                      .getInt()
2202*dc48849fSKiran Chandramohan                : getIntValue(op);
2203*dc48849fSKiran Chandramohan   }
2204*dc48849fSKiran Chandramohan 
2205*dc48849fSKiran Chandramohan   int64_t getIntValue(mlir::Value val) const {
2206*dc48849fSKiran Chandramohan     assert(val && val.dyn_cast<mlir::OpResult>() && "must not be null value");
2207*dc48849fSKiran Chandramohan     mlir::Operation *defop = val.getDefiningOp();
2208*dc48849fSKiran Chandramohan 
2209*dc48849fSKiran Chandramohan     if (auto constOp = dyn_cast<mlir::arith::ConstantIntOp>(defop))
2210*dc48849fSKiran Chandramohan       return constOp.value();
2211*dc48849fSKiran Chandramohan     if (auto llConstOp = dyn_cast<mlir::LLVM::ConstantOp>(defop))
2212*dc48849fSKiran Chandramohan       if (auto attr = llConstOp.getValue().dyn_cast<mlir::IntegerAttr>())
2213*dc48849fSKiran Chandramohan         return attr.getValue().getSExtValue();
2214*dc48849fSKiran Chandramohan     fir::emitFatalError(val.getLoc(), "must be a constant");
2215*dc48849fSKiran Chandramohan   }
2216*dc48849fSKiran Chandramohan 
2217*dc48849fSKiran Chandramohan   bool hasSubDimensions(mlir::Type type) const {
2218*dc48849fSKiran Chandramohan     return type.isa<fir::SequenceType, fir::RecordType, mlir::TupleType>();
2219*dc48849fSKiran Chandramohan   }
2220*dc48849fSKiran Chandramohan 
2221*dc48849fSKiran Chandramohan   /// Check whether this form of `!fir.coordinate_of` is supported. These
2222*dc48849fSKiran Chandramohan   /// additional checks are required, because we are not yet able to convert
2223*dc48849fSKiran Chandramohan   /// all valid forms of `!fir.coordinate_of`.
2224*dc48849fSKiran Chandramohan   /// TODO: Either implement the unsupported cases or extend the verifier
2225*dc48849fSKiran Chandramohan   /// in FIROps.cpp instead.
2226*dc48849fSKiran Chandramohan   bool supportedCoordinate(mlir::Type type, mlir::ValueRange coors) const {
2227*dc48849fSKiran Chandramohan     const std::size_t numOfCoors = coors.size();
2228*dc48849fSKiran Chandramohan     std::size_t i = 0;
2229*dc48849fSKiran Chandramohan     bool subEle = false;
2230*dc48849fSKiran Chandramohan     bool ptrEle = false;
2231*dc48849fSKiran Chandramohan     for (; i < numOfCoors; ++i) {
2232*dc48849fSKiran Chandramohan       mlir::Value nxtOpnd = coors[i];
2233*dc48849fSKiran Chandramohan       if (auto arrTy = type.dyn_cast<fir::SequenceType>()) {
2234*dc48849fSKiran Chandramohan         subEle = true;
2235*dc48849fSKiran Chandramohan         i += arrTy.getDimension() - 1;
2236*dc48849fSKiran Chandramohan         type = arrTy.getEleTy();
2237*dc48849fSKiran Chandramohan       } else if (auto recTy = type.dyn_cast<fir::RecordType>()) {
2238*dc48849fSKiran Chandramohan         subEle = true;
2239*dc48849fSKiran Chandramohan         type = recTy.getType(getFieldNumber(recTy, nxtOpnd));
2240*dc48849fSKiran Chandramohan       } else if (auto tupTy = type.dyn_cast<mlir::TupleType>()) {
2241*dc48849fSKiran Chandramohan         subEle = true;
2242*dc48849fSKiran Chandramohan         type = tupTy.getType(getIntValue(nxtOpnd));
2243*dc48849fSKiran Chandramohan       } else {
2244*dc48849fSKiran Chandramohan         ptrEle = true;
2245*dc48849fSKiran Chandramohan       }
2246*dc48849fSKiran Chandramohan     }
2247*dc48849fSKiran Chandramohan     if (ptrEle)
2248*dc48849fSKiran Chandramohan       return (!subEle) && (numOfCoors == 1);
2249*dc48849fSKiran Chandramohan     return subEle && (i >= numOfCoors);
2250*dc48849fSKiran Chandramohan   }
2251*dc48849fSKiran Chandramohan 
2252*dc48849fSKiran Chandramohan   /// Walk the abstract memory layout and determine if the path traverses any
2253*dc48849fSKiran Chandramohan   /// array types with unknown shape. Return true iff all the array types have a
2254*dc48849fSKiran Chandramohan   /// constant shape along the path.
2255*dc48849fSKiran Chandramohan   bool arraysHaveKnownShape(mlir::Type type, mlir::ValueRange coors) const {
2256*dc48849fSKiran Chandramohan     const std::size_t sz = coors.size();
2257*dc48849fSKiran Chandramohan     std::size_t i = 0;
2258*dc48849fSKiran Chandramohan     for (; i < sz; ++i) {
2259*dc48849fSKiran Chandramohan       mlir::Value nxtOpnd = coors[i];
2260*dc48849fSKiran Chandramohan       if (auto arrTy = type.dyn_cast<fir::SequenceType>()) {
2261*dc48849fSKiran Chandramohan         if (fir::sequenceWithNonConstantShape(arrTy))
2262*dc48849fSKiran Chandramohan           return false;
2263*dc48849fSKiran Chandramohan         i += arrTy.getDimension() - 1;
2264*dc48849fSKiran Chandramohan         type = arrTy.getEleTy();
2265*dc48849fSKiran Chandramohan       } else if (auto strTy = type.dyn_cast<fir::RecordType>()) {
2266*dc48849fSKiran Chandramohan         type = strTy.getType(getFieldNumber(strTy, nxtOpnd));
2267*dc48849fSKiran Chandramohan       } else if (auto strTy = type.dyn_cast<mlir::TupleType>()) {
2268*dc48849fSKiran Chandramohan         type = strTy.getType(getIntValue(nxtOpnd));
2269*dc48849fSKiran Chandramohan       } else {
2270*dc48849fSKiran Chandramohan         return true;
2271*dc48849fSKiran Chandramohan       }
2272*dc48849fSKiran Chandramohan     }
2273*dc48849fSKiran Chandramohan     return true;
2274*dc48849fSKiran Chandramohan   }
2275*dc48849fSKiran Chandramohan 
2276*dc48849fSKiran Chandramohan private:
2277*dc48849fSKiran Chandramohan   mlir::LogicalResult
2278*dc48849fSKiran Chandramohan   doRewriteBox(fir::CoordinateOp coor, mlir::Type ty, mlir::ValueRange operands,
2279*dc48849fSKiran Chandramohan                mlir::Location loc,
2280*dc48849fSKiran Chandramohan                mlir::ConversionPatternRewriter &rewriter) const {
2281*dc48849fSKiran Chandramohan     mlir::Type boxObjTy = coor.getBaseType();
2282*dc48849fSKiran Chandramohan     assert(boxObjTy.dyn_cast<fir::BoxType>() && "This is not a `fir.box`");
2283*dc48849fSKiran Chandramohan 
2284*dc48849fSKiran Chandramohan     mlir::Value boxBaseAddr = operands[0];
2285*dc48849fSKiran Chandramohan 
2286*dc48849fSKiran Chandramohan     // 1. SPECIAL CASE (uses `fir.len_param_index`):
2287*dc48849fSKiran Chandramohan     //   %box = ... : !fir.box<!fir.type<derived{len1:i32}>>
2288*dc48849fSKiran Chandramohan     //   %lenp = fir.len_param_index len1, !fir.type<derived{len1:i32}>
2289*dc48849fSKiran Chandramohan     //   %addr = coordinate_of %box, %lenp
2290*dc48849fSKiran Chandramohan     if (coor.getNumOperands() == 2) {
2291*dc48849fSKiran Chandramohan       mlir::Operation *coordinateDef =
2292*dc48849fSKiran Chandramohan           (*coor.getCoor().begin()).getDefiningOp();
2293*dc48849fSKiran Chandramohan       if (isa_and_nonnull<fir::LenParamIndexOp>(coordinateDef)) {
2294*dc48849fSKiran Chandramohan         TODO(loc,
2295*dc48849fSKiran Chandramohan              "fir.coordinate_of - fir.len_param_index is not supported yet");
2296*dc48849fSKiran Chandramohan       }
2297*dc48849fSKiran Chandramohan     }
2298*dc48849fSKiran Chandramohan 
2299*dc48849fSKiran Chandramohan     // 2. GENERAL CASE:
2300*dc48849fSKiran Chandramohan     // 2.1. (`fir.array`)
2301*dc48849fSKiran Chandramohan     //   %box = ... : !fix.box<!fir.array<?xU>>
2302*dc48849fSKiran Chandramohan     //   %idx = ... : index
2303*dc48849fSKiran Chandramohan     //   %resultAddr = coordinate_of %box, %idx : !fir.ref<U>
2304*dc48849fSKiran Chandramohan     // 2.2 (`fir.derived`)
2305*dc48849fSKiran Chandramohan     //   %box = ... : !fix.box<!fir.type<derived_type{field_1:i32}>>
2306*dc48849fSKiran Chandramohan     //   %idx = ... : i32
2307*dc48849fSKiran Chandramohan     //   %resultAddr = coordinate_of %box, %idx : !fir.ref<i32>
2308*dc48849fSKiran Chandramohan     // 2.3 (`fir.derived` inside `fir.array`)
2309*dc48849fSKiran Chandramohan     //   %box = ... : !fir.box<!fir.array<10 x !fir.type<derived_1{field_1:f32,
2310*dc48849fSKiran Chandramohan     //   field_2:f32}>>> %idx1 = ... : index %idx2 = ... : i32 %resultAddr =
2311*dc48849fSKiran Chandramohan     //   coordinate_of %box, %idx1, %idx2 : !fir.ref<f32>
2312*dc48849fSKiran Chandramohan     // 2.4. TODO: Either document or disable any other case that the following
2313*dc48849fSKiran Chandramohan     //  implementation might convert.
2314*dc48849fSKiran Chandramohan     mlir::LLVM::ConstantOp c0 =
2315*dc48849fSKiran Chandramohan         genConstantIndex(loc, lowerTy().indexType(), rewriter, 0);
2316*dc48849fSKiran Chandramohan     mlir::Value resultAddr =
2317*dc48849fSKiran Chandramohan         loadBaseAddrFromBox(loc, getBaseAddrTypeFromBox(boxBaseAddr.getType()),
2318*dc48849fSKiran Chandramohan                             boxBaseAddr, rewriter);
2319*dc48849fSKiran Chandramohan     auto currentObjTy = fir::dyn_cast_ptrOrBoxEleTy(boxObjTy);
2320*dc48849fSKiran Chandramohan     mlir::Type voidPtrTy = ::getVoidPtrType(coor.getContext());
2321*dc48849fSKiran Chandramohan 
2322*dc48849fSKiran Chandramohan     for (unsigned i = 1, last = operands.size(); i < last; ++i) {
2323*dc48849fSKiran Chandramohan       if (auto arrTy = currentObjTy.dyn_cast<fir::SequenceType>()) {
2324*dc48849fSKiran Chandramohan         if (i != 1)
2325*dc48849fSKiran Chandramohan           TODO(loc, "fir.array nested inside other array and/or derived type");
2326*dc48849fSKiran Chandramohan         // Applies byte strides from the box. Ignore lower bound from box
2327*dc48849fSKiran Chandramohan         // since fir.coordinate_of indexes are zero based. Lowering takes care
2328*dc48849fSKiran Chandramohan         // of lower bound aspects. This both accounts for dynamically sized
2329*dc48849fSKiran Chandramohan         // types and non contiguous arrays.
2330*dc48849fSKiran Chandramohan         auto idxTy = lowerTy().indexType();
2331*dc48849fSKiran Chandramohan         mlir::Value off = genConstantIndex(loc, idxTy, rewriter, 0);
2332*dc48849fSKiran Chandramohan         for (unsigned index = i, lastIndex = i + arrTy.getDimension();
2333*dc48849fSKiran Chandramohan              index < lastIndex; ++index) {
2334*dc48849fSKiran Chandramohan           mlir::Value stride =
2335*dc48849fSKiran Chandramohan               loadStrideFromBox(loc, operands[0], index - i, rewriter);
2336*dc48849fSKiran Chandramohan           auto sc = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy,
2337*dc48849fSKiran Chandramohan                                                        operands[index], stride);
2338*dc48849fSKiran Chandramohan           off = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, off);
2339*dc48849fSKiran Chandramohan         }
2340*dc48849fSKiran Chandramohan         auto voidPtrBase =
2341*dc48849fSKiran Chandramohan             rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, resultAddr);
2342*dc48849fSKiran Chandramohan         SmallVector<mlir::Value> args{off};
2343*dc48849fSKiran Chandramohan         resultAddr = rewriter.create<mlir::LLVM::GEPOp>(loc, voidPtrTy,
2344*dc48849fSKiran Chandramohan                                                         voidPtrBase, args);
2345*dc48849fSKiran Chandramohan         i += arrTy.getDimension() - 1;
2346*dc48849fSKiran Chandramohan         currentObjTy = arrTy.getEleTy();
2347*dc48849fSKiran Chandramohan       } else if (auto recTy = currentObjTy.dyn_cast<fir::RecordType>()) {
2348*dc48849fSKiran Chandramohan         auto recRefTy =
2349*dc48849fSKiran Chandramohan             mlir::LLVM::LLVMPointerType::get(lowerTy().convertType(recTy));
2350*dc48849fSKiran Chandramohan         mlir::Value nxtOpnd = operands[i];
2351*dc48849fSKiran Chandramohan         auto memObj =
2352*dc48849fSKiran Chandramohan             rewriter.create<mlir::LLVM::BitcastOp>(loc, recRefTy, resultAddr);
2353*dc48849fSKiran Chandramohan         llvm::SmallVector<mlir::Value> args = {c0, nxtOpnd};
2354*dc48849fSKiran Chandramohan         currentObjTy = recTy.getType(getFieldNumber(recTy, nxtOpnd));
2355*dc48849fSKiran Chandramohan         auto llvmCurrentObjTy = lowerTy().convertType(currentObjTy);
2356*dc48849fSKiran Chandramohan         auto gep = rewriter.create<mlir::LLVM::GEPOp>(
2357*dc48849fSKiran Chandramohan             loc, mlir::LLVM::LLVMPointerType::get(llvmCurrentObjTy), memObj,
2358*dc48849fSKiran Chandramohan             args);
2359*dc48849fSKiran Chandramohan         resultAddr =
2360*dc48849fSKiran Chandramohan             rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, gep);
2361*dc48849fSKiran Chandramohan       } else {
2362*dc48849fSKiran Chandramohan         fir::emitFatalError(loc, "unexpected type in coordinate_of");
2363*dc48849fSKiran Chandramohan       }
2364*dc48849fSKiran Chandramohan     }
2365*dc48849fSKiran Chandramohan 
2366*dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(coor, ty, resultAddr);
2367*dc48849fSKiran Chandramohan     return success();
2368*dc48849fSKiran Chandramohan   }
2369*dc48849fSKiran Chandramohan 
2370*dc48849fSKiran Chandramohan   mlir::LogicalResult
2371*dc48849fSKiran Chandramohan   doRewriteRefOrPtr(fir::CoordinateOp coor, mlir::Type ty,
2372*dc48849fSKiran Chandramohan                     mlir::ValueRange operands, mlir::Location loc,
2373*dc48849fSKiran Chandramohan                     mlir::ConversionPatternRewriter &rewriter) const {
2374*dc48849fSKiran Chandramohan     mlir::Type baseObjectTy = coor.getBaseType();
2375*dc48849fSKiran Chandramohan 
2376*dc48849fSKiran Chandramohan     mlir::Type currentObjTy = fir::dyn_cast_ptrOrBoxEleTy(baseObjectTy);
2377*dc48849fSKiran Chandramohan     bool hasSubdimension = hasSubDimensions(currentObjTy);
2378*dc48849fSKiran Chandramohan     bool columnIsDeferred = !hasSubdimension;
2379*dc48849fSKiran Chandramohan 
2380*dc48849fSKiran Chandramohan     if (!supportedCoordinate(currentObjTy, operands.drop_front(1))) {
2381*dc48849fSKiran Chandramohan       TODO(loc, "unsupported combination of coordinate operands");
2382*dc48849fSKiran Chandramohan     }
2383*dc48849fSKiran Chandramohan 
2384*dc48849fSKiran Chandramohan     const bool hasKnownShape =
2385*dc48849fSKiran Chandramohan         arraysHaveKnownShape(currentObjTy, operands.drop_front(1));
2386*dc48849fSKiran Chandramohan 
2387*dc48849fSKiran Chandramohan     // If only the column is `?`, then we can simply place the column value in
2388*dc48849fSKiran Chandramohan     // the 0-th GEP position.
2389*dc48849fSKiran Chandramohan     if (auto arrTy = currentObjTy.dyn_cast<fir::SequenceType>()) {
2390*dc48849fSKiran Chandramohan       if (!hasKnownShape) {
2391*dc48849fSKiran Chandramohan         const unsigned sz = arrTy.getDimension();
2392*dc48849fSKiran Chandramohan         if (arraysHaveKnownShape(arrTy.getEleTy(),
2393*dc48849fSKiran Chandramohan                                  operands.drop_front(1 + sz))) {
2394*dc48849fSKiran Chandramohan           llvm::ArrayRef<int64_t> shape = arrTy.getShape();
2395*dc48849fSKiran Chandramohan           bool allConst = true;
2396*dc48849fSKiran Chandramohan           for (unsigned i = 0; i < sz - 1; ++i) {
2397*dc48849fSKiran Chandramohan             if (shape[i] < 0) {
2398*dc48849fSKiran Chandramohan               allConst = false;
2399*dc48849fSKiran Chandramohan               break;
2400*dc48849fSKiran Chandramohan             }
2401*dc48849fSKiran Chandramohan           }
2402*dc48849fSKiran Chandramohan           if (allConst)
2403*dc48849fSKiran Chandramohan             columnIsDeferred = true;
2404*dc48849fSKiran Chandramohan         }
2405*dc48849fSKiran Chandramohan       }
2406*dc48849fSKiran Chandramohan     }
2407*dc48849fSKiran Chandramohan 
2408*dc48849fSKiran Chandramohan     if (fir::hasDynamicSize(fir::unwrapSequenceType(currentObjTy))) {
2409*dc48849fSKiran Chandramohan       mlir::emitError(
2410*dc48849fSKiran Chandramohan           loc, "fir.coordinate_of with a dynamic element size is unsupported");
2411*dc48849fSKiran Chandramohan       return failure();
2412*dc48849fSKiran Chandramohan     }
2413*dc48849fSKiran Chandramohan 
2414*dc48849fSKiran Chandramohan     if (hasKnownShape || columnIsDeferred) {
2415*dc48849fSKiran Chandramohan       SmallVector<mlir::Value> offs;
2416*dc48849fSKiran Chandramohan       if (hasKnownShape && hasSubdimension) {
2417*dc48849fSKiran Chandramohan         mlir::LLVM::ConstantOp c0 =
2418*dc48849fSKiran Chandramohan             genConstantIndex(loc, lowerTy().indexType(), rewriter, 0);
2419*dc48849fSKiran Chandramohan         offs.push_back(c0);
2420*dc48849fSKiran Chandramohan       }
2421*dc48849fSKiran Chandramohan       const std::size_t sz = operands.size();
2422*dc48849fSKiran Chandramohan       Optional<int> dims;
2423*dc48849fSKiran Chandramohan       SmallVector<mlir::Value> arrIdx;
2424*dc48849fSKiran Chandramohan       for (std::size_t i = 1; i < sz; ++i) {
2425*dc48849fSKiran Chandramohan         mlir::Value nxtOpnd = operands[i];
2426*dc48849fSKiran Chandramohan 
2427*dc48849fSKiran Chandramohan         if (!currentObjTy) {
2428*dc48849fSKiran Chandramohan           mlir::emitError(loc, "invalid coordinate/check failed");
2429*dc48849fSKiran Chandramohan           return failure();
2430*dc48849fSKiran Chandramohan         }
2431*dc48849fSKiran Chandramohan 
2432*dc48849fSKiran Chandramohan         // check if the i-th coordinate relates to an array
2433*dc48849fSKiran Chandramohan         if (dims.hasValue()) {
2434*dc48849fSKiran Chandramohan           arrIdx.push_back(nxtOpnd);
2435*dc48849fSKiran Chandramohan           int dimsLeft = *dims;
2436*dc48849fSKiran Chandramohan           if (dimsLeft > 1) {
2437*dc48849fSKiran Chandramohan             dims = dimsLeft - 1;
2438*dc48849fSKiran Chandramohan             continue;
2439*dc48849fSKiran Chandramohan           }
2440*dc48849fSKiran Chandramohan           currentObjTy = currentObjTy.cast<fir::SequenceType>().getEleTy();
2441*dc48849fSKiran Chandramohan           // append array range in reverse (FIR arrays are column-major)
2442*dc48849fSKiran Chandramohan           offs.append(arrIdx.rbegin(), arrIdx.rend());
2443*dc48849fSKiran Chandramohan           arrIdx.clear();
2444*dc48849fSKiran Chandramohan           dims.reset();
2445*dc48849fSKiran Chandramohan           continue;
2446*dc48849fSKiran Chandramohan         }
2447*dc48849fSKiran Chandramohan         if (auto arrTy = currentObjTy.dyn_cast<fir::SequenceType>()) {
2448*dc48849fSKiran Chandramohan           int d = arrTy.getDimension() - 1;
2449*dc48849fSKiran Chandramohan           if (d > 0) {
2450*dc48849fSKiran Chandramohan             dims = d;
2451*dc48849fSKiran Chandramohan             arrIdx.push_back(nxtOpnd);
2452*dc48849fSKiran Chandramohan             continue;
2453*dc48849fSKiran Chandramohan           }
2454*dc48849fSKiran Chandramohan           currentObjTy = currentObjTy.cast<fir::SequenceType>().getEleTy();
2455*dc48849fSKiran Chandramohan           offs.push_back(nxtOpnd);
2456*dc48849fSKiran Chandramohan           continue;
2457*dc48849fSKiran Chandramohan         }
2458*dc48849fSKiran Chandramohan 
2459*dc48849fSKiran Chandramohan         // check if the i-th coordinate relates to a field
2460*dc48849fSKiran Chandramohan         if (auto recTy = currentObjTy.dyn_cast<fir::RecordType>())
2461*dc48849fSKiran Chandramohan           currentObjTy = recTy.getType(getFieldNumber(recTy, nxtOpnd));
2462*dc48849fSKiran Chandramohan         else if (auto tupTy = currentObjTy.dyn_cast<mlir::TupleType>())
2463*dc48849fSKiran Chandramohan           currentObjTy = tupTy.getType(getIntValue(nxtOpnd));
2464*dc48849fSKiran Chandramohan         else
2465*dc48849fSKiran Chandramohan           currentObjTy = nullptr;
2466*dc48849fSKiran Chandramohan 
2467*dc48849fSKiran Chandramohan         offs.push_back(nxtOpnd);
2468*dc48849fSKiran Chandramohan       }
2469*dc48849fSKiran Chandramohan       if (dims.hasValue())
2470*dc48849fSKiran Chandramohan         offs.append(arrIdx.rbegin(), arrIdx.rend());
2471*dc48849fSKiran Chandramohan       mlir::Value base = operands[0];
2472*dc48849fSKiran Chandramohan       mlir::Value retval = genGEP(loc, ty, rewriter, base, offs);
2473*dc48849fSKiran Chandramohan       rewriter.replaceOp(coor, retval);
2474*dc48849fSKiran Chandramohan       return success();
2475*dc48849fSKiran Chandramohan     }
2476*dc48849fSKiran Chandramohan 
2477*dc48849fSKiran Chandramohan     mlir::emitError(loc, "fir.coordinate_of base operand has unsupported type");
2478*dc48849fSKiran Chandramohan     return failure();
2479*dc48849fSKiran Chandramohan   }
2480*dc48849fSKiran Chandramohan };
2481*dc48849fSKiran Chandramohan 
2482*dc48849fSKiran Chandramohan /// Convert `fir.field_index`. The conversion depends on whether the size of
2483*dc48849fSKiran Chandramohan /// the record is static or dynamic.
2484*dc48849fSKiran Chandramohan struct FieldIndexOpConversion : public FIROpConversion<fir::FieldIndexOp> {
2485*dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2486*dc48849fSKiran Chandramohan 
2487*dc48849fSKiran Chandramohan   // NB: most field references should be resolved by this point
2488*dc48849fSKiran Chandramohan   mlir::LogicalResult
2489*dc48849fSKiran Chandramohan   matchAndRewrite(fir::FieldIndexOp field, OpAdaptor adaptor,
2490*dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2491*dc48849fSKiran Chandramohan     auto recTy = field.getOnType().cast<fir::RecordType>();
2492*dc48849fSKiran Chandramohan     unsigned index = recTy.getFieldIndex(field.getFieldId());
2493*dc48849fSKiran Chandramohan 
2494*dc48849fSKiran Chandramohan     if (!fir::hasDynamicSize(recTy)) {
2495*dc48849fSKiran Chandramohan       // Derived type has compile-time constant layout. Return index of the
2496*dc48849fSKiran Chandramohan       // component type in the parent type (to be used in GEP).
2497*dc48849fSKiran Chandramohan       rewriter.replaceOp(field, mlir::ValueRange{genConstantOffset(
2498*dc48849fSKiran Chandramohan                                     field.getLoc(), rewriter, index)});
2499*dc48849fSKiran Chandramohan       return success();
2500*dc48849fSKiran Chandramohan     }
2501*dc48849fSKiran Chandramohan 
2502*dc48849fSKiran Chandramohan     // Derived type has compile-time constant layout. Call the compiler
2503*dc48849fSKiran Chandramohan     // generated function to determine the byte offset of the field at runtime.
2504*dc48849fSKiran Chandramohan     // This returns a non-constant.
2505*dc48849fSKiran Chandramohan     FlatSymbolRefAttr symAttr = mlir::SymbolRefAttr::get(
2506*dc48849fSKiran Chandramohan         field.getContext(), getOffsetMethodName(recTy, field.getFieldId()));
2507*dc48849fSKiran Chandramohan     NamedAttribute callAttr = rewriter.getNamedAttr("callee", symAttr);
2508*dc48849fSKiran Chandramohan     NamedAttribute fieldAttr = rewriter.getNamedAttr(
2509*dc48849fSKiran Chandramohan         "field", mlir::IntegerAttr::get(lowerTy().indexType(), index));
2510*dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
2511*dc48849fSKiran Chandramohan         field, lowerTy().offsetType(), adaptor.getOperands(),
2512*dc48849fSKiran Chandramohan         llvm::ArrayRef<mlir::NamedAttribute>{callAttr, fieldAttr});
2513*dc48849fSKiran Chandramohan     return success();
2514*dc48849fSKiran Chandramohan   }
2515*dc48849fSKiran Chandramohan 
2516*dc48849fSKiran Chandramohan   // Re-Construct the name of the compiler generated method that calculates the
2517*dc48849fSKiran Chandramohan   // offset
2518*dc48849fSKiran Chandramohan   inline static std::string getOffsetMethodName(fir::RecordType recTy,
2519*dc48849fSKiran Chandramohan                                                 llvm::StringRef field) {
2520*dc48849fSKiran Chandramohan     return recTy.getName().str() + "P." + field.str() + ".offset";
2521*dc48849fSKiran Chandramohan   }
2522*dc48849fSKiran Chandramohan };
2523*dc48849fSKiran Chandramohan 
2524*dc48849fSKiran Chandramohan /// Convert `fir.end`
2525*dc48849fSKiran Chandramohan struct FirEndOpConversion : public FIROpConversion<fir::FirEndOp> {
2526*dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2527*dc48849fSKiran Chandramohan 
2528*dc48849fSKiran Chandramohan   mlir::LogicalResult
2529*dc48849fSKiran Chandramohan   matchAndRewrite(fir::FirEndOp firEnd, OpAdaptor,
2530*dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2531*dc48849fSKiran Chandramohan     TODO(firEnd.getLoc(), "fir.end codegen");
2532*dc48849fSKiran Chandramohan     return failure();
2533*dc48849fSKiran Chandramohan   }
2534*dc48849fSKiran Chandramohan };
2535*dc48849fSKiran Chandramohan 
2536*dc48849fSKiran Chandramohan /// Lower `fir.gentypedesc` to a global constant.
2537*dc48849fSKiran Chandramohan struct GenTypeDescOpConversion : public FIROpConversion<fir::GenTypeDescOp> {
2538*dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2539*dc48849fSKiran Chandramohan 
2540*dc48849fSKiran Chandramohan   mlir::LogicalResult
2541*dc48849fSKiran Chandramohan   matchAndRewrite(fir::GenTypeDescOp gentypedesc, OpAdaptor adaptor,
2542*dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2543*dc48849fSKiran Chandramohan     TODO(gentypedesc.getLoc(), "fir.gentypedesc codegen");
2544*dc48849fSKiran Chandramohan     return failure();
2545*dc48849fSKiran Chandramohan   }
2546*dc48849fSKiran Chandramohan };
2547*dc48849fSKiran Chandramohan 
2548*dc48849fSKiran Chandramohan /// Lower `fir.has_value` operation to `llvm.return` operation.
2549*dc48849fSKiran Chandramohan struct HasValueOpConversion : public FIROpConversion<fir::HasValueOp> {
2550*dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2551*dc48849fSKiran Chandramohan 
2552*dc48849fSKiran Chandramohan   mlir::LogicalResult
2553*dc48849fSKiran Chandramohan   matchAndRewrite(fir::HasValueOp op, OpAdaptor adaptor,
2554*dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2555*dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, adaptor.getOperands());
2556*dc48849fSKiran Chandramohan     return success();
2557*dc48849fSKiran Chandramohan   }
2558*dc48849fSKiran Chandramohan };
2559*dc48849fSKiran Chandramohan 
2560*dc48849fSKiran Chandramohan /// Lower `fir.global` operation to `llvm.global` operation.
2561*dc48849fSKiran Chandramohan /// `fir.insert_on_range` operations are replaced with constant dense attribute
2562*dc48849fSKiran Chandramohan /// if they are applied on the full range.
2563*dc48849fSKiran Chandramohan struct GlobalOpConversion : public FIROpConversion<fir::GlobalOp> {
2564*dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2565*dc48849fSKiran Chandramohan 
2566*dc48849fSKiran Chandramohan   mlir::LogicalResult
2567*dc48849fSKiran Chandramohan   matchAndRewrite(fir::GlobalOp global, OpAdaptor adaptor,
2568*dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2569*dc48849fSKiran Chandramohan     auto tyAttr = convertType(global.getType());
2570*dc48849fSKiran Chandramohan     if (global.getType().isa<fir::BoxType>())
2571*dc48849fSKiran Chandramohan       tyAttr = tyAttr.cast<mlir::LLVM::LLVMPointerType>().getElementType();
2572*dc48849fSKiran Chandramohan     auto loc = global.getLoc();
2573*dc48849fSKiran Chandramohan     mlir::Attribute initAttr{};
2574*dc48849fSKiran Chandramohan     if (global.getInitVal())
2575*dc48849fSKiran Chandramohan       initAttr = global.getInitVal().getValue();
2576*dc48849fSKiran Chandramohan     auto linkage = convertLinkage(global.getLinkName());
2577*dc48849fSKiran Chandramohan     auto isConst = global.getConstant().hasValue();
2578*dc48849fSKiran Chandramohan     auto g = rewriter.create<mlir::LLVM::GlobalOp>(
2579*dc48849fSKiran Chandramohan         loc, tyAttr, isConst, linkage, global.getSymName(), initAttr);
2580*dc48849fSKiran Chandramohan     auto &gr = g.getInitializerRegion();
2581*dc48849fSKiran Chandramohan     rewriter.inlineRegionBefore(global.getRegion(), gr, gr.end());
2582*dc48849fSKiran Chandramohan     if (!gr.empty()) {
2583*dc48849fSKiran Chandramohan       // Replace insert_on_range with a constant dense attribute if the
2584*dc48849fSKiran Chandramohan       // initialization is on the full range.
2585*dc48849fSKiran Chandramohan       auto insertOnRangeOps = gr.front().getOps<fir::InsertOnRangeOp>();
2586*dc48849fSKiran Chandramohan       for (auto insertOp : insertOnRangeOps) {
2587*dc48849fSKiran Chandramohan         if (isFullRange(insertOp.getCoor(), insertOp.getType())) {
2588*dc48849fSKiran Chandramohan           auto seqTyAttr = convertType(insertOp.getType());
2589*dc48849fSKiran Chandramohan           auto *op = insertOp.getVal().getDefiningOp();
2590*dc48849fSKiran Chandramohan           auto constant = mlir::dyn_cast<mlir::arith::ConstantOp>(op);
2591*dc48849fSKiran Chandramohan           if (!constant) {
2592*dc48849fSKiran Chandramohan             auto convertOp = mlir::dyn_cast<fir::ConvertOp>(op);
2593*dc48849fSKiran Chandramohan             if (!convertOp)
2594*dc48849fSKiran Chandramohan               continue;
2595*dc48849fSKiran Chandramohan             constant = cast<mlir::arith::ConstantOp>(
2596*dc48849fSKiran Chandramohan                 convertOp.getValue().getDefiningOp());
2597*dc48849fSKiran Chandramohan           }
2598*dc48849fSKiran Chandramohan           mlir::Type vecType = mlir::VectorType::get(
2599*dc48849fSKiran Chandramohan               insertOp.getType().getShape(), constant.getType());
2600*dc48849fSKiran Chandramohan           auto denseAttr = mlir::DenseElementsAttr::get(
2601*dc48849fSKiran Chandramohan               vecType.cast<ShapedType>(), constant.getValue());
2602*dc48849fSKiran Chandramohan           rewriter.setInsertionPointAfter(insertOp);
2603*dc48849fSKiran Chandramohan           rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(
2604*dc48849fSKiran Chandramohan               insertOp, seqTyAttr, denseAttr);
2605*dc48849fSKiran Chandramohan         }
2606*dc48849fSKiran Chandramohan       }
2607*dc48849fSKiran Chandramohan     }
2608*dc48849fSKiran Chandramohan     rewriter.eraseOp(global);
2609*dc48849fSKiran Chandramohan     return success();
2610*dc48849fSKiran Chandramohan   }
2611*dc48849fSKiran Chandramohan 
2612*dc48849fSKiran Chandramohan   bool isFullRange(mlir::DenseIntElementsAttr indexes,
2613*dc48849fSKiran Chandramohan                    fir::SequenceType seqTy) const {
2614*dc48849fSKiran Chandramohan     auto extents = seqTy.getShape();
2615*dc48849fSKiran Chandramohan     if (indexes.size() / 2 != static_cast<int64_t>(extents.size()))
2616*dc48849fSKiran Chandramohan       return false;
2617*dc48849fSKiran Chandramohan     auto cur_index = indexes.value_begin<int64_t>();
2618*dc48849fSKiran Chandramohan     for (unsigned i = 0; i < indexes.size(); i += 2) {
2619*dc48849fSKiran Chandramohan       if (*(cur_index++) != 0)
2620*dc48849fSKiran Chandramohan         return false;
2621*dc48849fSKiran Chandramohan       if (*(cur_index++) != extents[i / 2] - 1)
2622*dc48849fSKiran Chandramohan         return false;
2623*dc48849fSKiran Chandramohan     }
2624*dc48849fSKiran Chandramohan     return true;
2625*dc48849fSKiran Chandramohan   }
2626*dc48849fSKiran Chandramohan 
2627*dc48849fSKiran Chandramohan   // TODO: String comparaison should be avoided. Replace linkName with an
2628*dc48849fSKiran Chandramohan   // enumeration.
2629*dc48849fSKiran Chandramohan   mlir::LLVM::Linkage convertLinkage(Optional<StringRef> optLinkage) const {
2630*dc48849fSKiran Chandramohan     if (optLinkage.hasValue()) {
2631*dc48849fSKiran Chandramohan       auto name = optLinkage.getValue();
2632*dc48849fSKiran Chandramohan       if (name == "internal")
2633*dc48849fSKiran Chandramohan         return mlir::LLVM::Linkage::Internal;
2634*dc48849fSKiran Chandramohan       if (name == "linkonce")
2635*dc48849fSKiran Chandramohan         return mlir::LLVM::Linkage::Linkonce;
2636*dc48849fSKiran Chandramohan       if (name == "common")
2637*dc48849fSKiran Chandramohan         return mlir::LLVM::Linkage::Common;
2638*dc48849fSKiran Chandramohan       if (name == "weak")
2639*dc48849fSKiran Chandramohan         return mlir::LLVM::Linkage::Weak;
2640*dc48849fSKiran Chandramohan     }
2641*dc48849fSKiran Chandramohan     return mlir::LLVM::Linkage::External;
2642*dc48849fSKiran Chandramohan   }
2643*dc48849fSKiran Chandramohan };
2644*dc48849fSKiran Chandramohan 
2645*dc48849fSKiran Chandramohan /// `fir.load` --> `llvm.load`
2646*dc48849fSKiran Chandramohan struct LoadOpConversion : public FIROpConversion<fir::LoadOp> {
2647*dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2648*dc48849fSKiran Chandramohan 
2649*dc48849fSKiran Chandramohan   mlir::LogicalResult
2650*dc48849fSKiran Chandramohan   matchAndRewrite(fir::LoadOp load, OpAdaptor adaptor,
2651*dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2652*dc48849fSKiran Chandramohan     // fir.box is a special case because it is considered as an ssa values in
2653*dc48849fSKiran Chandramohan     // fir, but it is lowered as a pointer to a descriptor. So fir.ref<fir.box>
2654*dc48849fSKiran Chandramohan     // and fir.box end up being the same llvm types and loading a
2655*dc48849fSKiran Chandramohan     // fir.ref<fir.box> is actually a no op in LLVM.
2656*dc48849fSKiran Chandramohan     if (load.getType().isa<fir::BoxType>()) {
2657*dc48849fSKiran Chandramohan       rewriter.replaceOp(load, adaptor.getOperands()[0]);
2658*dc48849fSKiran Chandramohan     } else {
2659*dc48849fSKiran Chandramohan       mlir::Type ty = convertType(load.getType());
2660*dc48849fSKiran Chandramohan       ArrayRef<NamedAttribute> at = load->getAttrs();
2661*dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::LoadOp>(
2662*dc48849fSKiran Chandramohan           load, ty, adaptor.getOperands(), at);
2663*dc48849fSKiran Chandramohan     }
2664*dc48849fSKiran Chandramohan     return success();
2665*dc48849fSKiran Chandramohan   }
2666*dc48849fSKiran Chandramohan };
2667*dc48849fSKiran Chandramohan 
2668*dc48849fSKiran Chandramohan /// Lower `fir.no_reassoc` to LLVM IR dialect.
2669*dc48849fSKiran Chandramohan /// TODO: how do we want to enforce this in LLVM-IR? Can we manipulate the fast
2670*dc48849fSKiran Chandramohan /// math flags?
2671*dc48849fSKiran Chandramohan struct NoReassocOpConversion : public FIROpConversion<fir::NoReassocOp> {
2672*dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2673*dc48849fSKiran Chandramohan 
2674*dc48849fSKiran Chandramohan   mlir::LogicalResult
2675*dc48849fSKiran Chandramohan   matchAndRewrite(fir::NoReassocOp noreassoc, OpAdaptor adaptor,
2676*dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2677*dc48849fSKiran Chandramohan     rewriter.replaceOp(noreassoc, adaptor.getOperands()[0]);
2678*dc48849fSKiran Chandramohan     return success();
2679*dc48849fSKiran Chandramohan   }
2680*dc48849fSKiran Chandramohan };
2681*dc48849fSKiran Chandramohan 
2682*dc48849fSKiran Chandramohan static void genCondBrOp(mlir::Location loc, mlir::Value cmp, mlir::Block *dest,
2683*dc48849fSKiran Chandramohan                         Optional<mlir::ValueRange> destOps,
2684*dc48849fSKiran Chandramohan                         mlir::ConversionPatternRewriter &rewriter,
2685*dc48849fSKiran Chandramohan                         mlir::Block *newBlock) {
2686*dc48849fSKiran Chandramohan   if (destOps.hasValue())
2687*dc48849fSKiran Chandramohan     rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, destOps.getValue(),
2688*dc48849fSKiran Chandramohan                                           newBlock, mlir::ValueRange());
2689*dc48849fSKiran Chandramohan   else
2690*dc48849fSKiran Chandramohan     rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, newBlock);
2691*dc48849fSKiran Chandramohan }
2692*dc48849fSKiran Chandramohan 
2693*dc48849fSKiran Chandramohan template <typename A, typename B>
2694*dc48849fSKiran Chandramohan static void genBrOp(A caseOp, mlir::Block *dest, Optional<B> destOps,
2695*dc48849fSKiran Chandramohan                     mlir::ConversionPatternRewriter &rewriter) {
2696*dc48849fSKiran Chandramohan   if (destOps.hasValue())
2697*dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, destOps.getValue(),
2698*dc48849fSKiran Chandramohan                                                   dest);
2699*dc48849fSKiran Chandramohan   else
2700*dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, llvm::None, dest);
2701*dc48849fSKiran Chandramohan }
2702*dc48849fSKiran Chandramohan 
2703*dc48849fSKiran Chandramohan static void genCaseLadderStep(mlir::Location loc, mlir::Value cmp,
2704*dc48849fSKiran Chandramohan                               mlir::Block *dest,
2705*dc48849fSKiran Chandramohan                               Optional<mlir::ValueRange> destOps,
2706*dc48849fSKiran Chandramohan                               mlir::ConversionPatternRewriter &rewriter) {
2707*dc48849fSKiran Chandramohan   auto *thisBlock = rewriter.getInsertionBlock();
2708*dc48849fSKiran Chandramohan   auto *newBlock = createBlock(rewriter, dest);
2709*dc48849fSKiran Chandramohan   rewriter.setInsertionPointToEnd(thisBlock);
2710*dc48849fSKiran Chandramohan   genCondBrOp(loc, cmp, dest, destOps, rewriter, newBlock);
2711*dc48849fSKiran Chandramohan   rewriter.setInsertionPointToEnd(newBlock);
2712*dc48849fSKiran Chandramohan }
2713*dc48849fSKiran Chandramohan 
2714*dc48849fSKiran Chandramohan /// Conversion of `fir.select_case`
2715*dc48849fSKiran Chandramohan ///
2716*dc48849fSKiran Chandramohan /// The `fir.select_case` operation is converted to a if-then-else ladder.
2717*dc48849fSKiran Chandramohan /// Depending on the case condition type, one or several comparison and
2718*dc48849fSKiran Chandramohan /// conditional branching can be generated.
2719*dc48849fSKiran Chandramohan ///
2720*dc48849fSKiran Chandramohan /// A a point value case such as `case(4)`, a lower bound case such as
2721*dc48849fSKiran Chandramohan /// `case(5:)` or an upper bound case such as `case(:3)` are converted to a
2722*dc48849fSKiran Chandramohan /// simple comparison between the selector value and the constant value in the
2723*dc48849fSKiran Chandramohan /// case. The block associated with the case condition is then executed if
2724*dc48849fSKiran Chandramohan /// the comparison succeed otherwise it branch to the next block with the
2725*dc48849fSKiran Chandramohan /// comparison for the the next case conditon.
2726*dc48849fSKiran Chandramohan ///
2727*dc48849fSKiran Chandramohan /// A closed interval case condition such as `case(7:10)` is converted with a
2728*dc48849fSKiran Chandramohan /// first comparison and conditional branching for the lower bound. If
2729*dc48849fSKiran Chandramohan /// successful, it branch to a second block with the comparison for the
2730*dc48849fSKiran Chandramohan /// upper bound in the same case condition.
2731*dc48849fSKiran Chandramohan ///
2732*dc48849fSKiran Chandramohan /// TODO: lowering of CHARACTER type cases is not handled yet.
2733*dc48849fSKiran Chandramohan struct SelectCaseOpConversion : public FIROpConversion<fir::SelectCaseOp> {
2734*dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2735*dc48849fSKiran Chandramohan 
2736*dc48849fSKiran Chandramohan   mlir::LogicalResult
2737*dc48849fSKiran Chandramohan   matchAndRewrite(fir::SelectCaseOp caseOp, OpAdaptor adaptor,
2738*dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2739*dc48849fSKiran Chandramohan     unsigned conds = caseOp.getNumConditions();
2740*dc48849fSKiran Chandramohan     llvm::ArrayRef<mlir::Attribute> cases = caseOp.getCases().getValue();
2741*dc48849fSKiran Chandramohan     // Type can be CHARACTER, INTEGER, or LOGICAL (C1145)
2742*dc48849fSKiran Chandramohan     auto ty = caseOp.getSelector().getType();
2743*dc48849fSKiran Chandramohan     if (ty.isa<fir::CharacterType>()) {
2744*dc48849fSKiran Chandramohan       TODO(caseOp.getLoc(), "fir.select_case codegen with character type");
2745*dc48849fSKiran Chandramohan       return failure();
2746*dc48849fSKiran Chandramohan     }
2747*dc48849fSKiran Chandramohan     mlir::Value selector = caseOp.getSelector(adaptor.getOperands());
2748*dc48849fSKiran Chandramohan     auto loc = caseOp.getLoc();
2749*dc48849fSKiran Chandramohan     for (unsigned t = 0; t != conds; ++t) {
2750*dc48849fSKiran Chandramohan       mlir::Block *dest = caseOp.getSuccessor(t);
2751*dc48849fSKiran Chandramohan       llvm::Optional<mlir::ValueRange> destOps =
2752*dc48849fSKiran Chandramohan           caseOp.getSuccessorOperands(adaptor.getOperands(), t);
2753*dc48849fSKiran Chandramohan       llvm::Optional<mlir::ValueRange> cmpOps =
2754*dc48849fSKiran Chandramohan           *caseOp.getCompareOperands(adaptor.getOperands(), t);
2755*dc48849fSKiran Chandramohan       mlir::Value caseArg = *(cmpOps.getValue().begin());
2756*dc48849fSKiran Chandramohan       mlir::Attribute attr = cases[t];
2757*dc48849fSKiran Chandramohan       if (attr.isa<fir::PointIntervalAttr>()) {
2758*dc48849fSKiran Chandramohan         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
2759*dc48849fSKiran Chandramohan             loc, mlir::LLVM::ICmpPredicate::eq, selector, caseArg);
2760*dc48849fSKiran Chandramohan         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
2761*dc48849fSKiran Chandramohan         continue;
2762*dc48849fSKiran Chandramohan       }
2763*dc48849fSKiran Chandramohan       if (attr.isa<fir::LowerBoundAttr>()) {
2764*dc48849fSKiran Chandramohan         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
2765*dc48849fSKiran Chandramohan             loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector);
2766*dc48849fSKiran Chandramohan         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
2767*dc48849fSKiran Chandramohan         continue;
2768*dc48849fSKiran Chandramohan       }
2769*dc48849fSKiran Chandramohan       if (attr.isa<fir::UpperBoundAttr>()) {
2770*dc48849fSKiran Chandramohan         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
2771*dc48849fSKiran Chandramohan             loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg);
2772*dc48849fSKiran Chandramohan         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
2773*dc48849fSKiran Chandramohan         continue;
2774*dc48849fSKiran Chandramohan       }
2775*dc48849fSKiran Chandramohan       if (attr.isa<fir::ClosedIntervalAttr>()) {
2776*dc48849fSKiran Chandramohan         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
2777*dc48849fSKiran Chandramohan             loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector);
2778*dc48849fSKiran Chandramohan         auto *thisBlock = rewriter.getInsertionBlock();
2779*dc48849fSKiran Chandramohan         auto *newBlock1 = createBlock(rewriter, dest);
2780*dc48849fSKiran Chandramohan         auto *newBlock2 = createBlock(rewriter, dest);
2781*dc48849fSKiran Chandramohan         rewriter.setInsertionPointToEnd(thisBlock);
2782*dc48849fSKiran Chandramohan         rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, newBlock1, newBlock2);
2783*dc48849fSKiran Chandramohan         rewriter.setInsertionPointToEnd(newBlock1);
2784*dc48849fSKiran Chandramohan         mlir::Value caseArg0 = *(cmpOps.getValue().begin() + 1);
2785*dc48849fSKiran Chandramohan         auto cmp0 = rewriter.create<mlir::LLVM::ICmpOp>(
2786*dc48849fSKiran Chandramohan             loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg0);
2787*dc48849fSKiran Chandramohan         genCondBrOp(loc, cmp0, dest, destOps, rewriter, newBlock2);
2788*dc48849fSKiran Chandramohan         rewriter.setInsertionPointToEnd(newBlock2);
2789*dc48849fSKiran Chandramohan         continue;
2790*dc48849fSKiran Chandramohan       }
2791*dc48849fSKiran Chandramohan       assert(attr.isa<mlir::UnitAttr>());
2792*dc48849fSKiran Chandramohan       assert((t + 1 == conds) && "unit must be last");
2793*dc48849fSKiran Chandramohan       genBrOp(caseOp, dest, destOps, rewriter);
2794*dc48849fSKiran Chandramohan     }
2795*dc48849fSKiran Chandramohan     return success();
2796*dc48849fSKiran Chandramohan   }
2797*dc48849fSKiran Chandramohan };
2798*dc48849fSKiran Chandramohan 
2799*dc48849fSKiran Chandramohan template <typename OP>
2800*dc48849fSKiran Chandramohan static void selectMatchAndRewrite(fir::LLVMTypeConverter &lowering, OP select,
2801*dc48849fSKiran Chandramohan                                   typename OP::Adaptor adaptor,
2802*dc48849fSKiran Chandramohan                                   mlir::ConversionPatternRewriter &rewriter) {
2803*dc48849fSKiran Chandramohan   unsigned conds = select.getNumConditions();
2804*dc48849fSKiran Chandramohan   auto cases = select.getCases().getValue();
2805*dc48849fSKiran Chandramohan   mlir::Value selector = adaptor.getSelector();
2806*dc48849fSKiran Chandramohan   auto loc = select.getLoc();
2807*dc48849fSKiran Chandramohan   assert(conds > 0 && "select must have cases");
2808*dc48849fSKiran Chandramohan 
2809*dc48849fSKiran Chandramohan   llvm::SmallVector<mlir::Block *> destinations;
2810*dc48849fSKiran Chandramohan   llvm::SmallVector<mlir::ValueRange> destinationsOperands;
2811*dc48849fSKiran Chandramohan   mlir::Block *defaultDestination;
2812*dc48849fSKiran Chandramohan   mlir::ValueRange defaultOperands;
2813*dc48849fSKiran Chandramohan   llvm::SmallVector<int32_t> caseValues;
2814*dc48849fSKiran Chandramohan 
2815*dc48849fSKiran Chandramohan   for (unsigned t = 0; t != conds; ++t) {
2816*dc48849fSKiran Chandramohan     mlir::Block *dest = select.getSuccessor(t);
2817*dc48849fSKiran Chandramohan     auto destOps = select.getSuccessorOperands(adaptor.getOperands(), t);
2818*dc48849fSKiran Chandramohan     const mlir::Attribute &attr = cases[t];
2819*dc48849fSKiran Chandramohan     if (auto intAttr = attr.template dyn_cast<mlir::IntegerAttr>()) {
2820*dc48849fSKiran Chandramohan       destinations.push_back(dest);
2821*dc48849fSKiran Chandramohan       destinationsOperands.push_back(destOps.hasValue() ? *destOps
2822*dc48849fSKiran Chandramohan                                                         : ValueRange());
2823*dc48849fSKiran Chandramohan       caseValues.push_back(intAttr.getInt());
2824*dc48849fSKiran Chandramohan       continue;
2825*dc48849fSKiran Chandramohan     }
2826*dc48849fSKiran Chandramohan     assert(attr.template dyn_cast_or_null<mlir::UnitAttr>());
2827*dc48849fSKiran Chandramohan     assert((t + 1 == conds) && "unit must be last");
2828*dc48849fSKiran Chandramohan     defaultDestination = dest;
2829*dc48849fSKiran Chandramohan     defaultOperands = destOps.hasValue() ? *destOps : ValueRange();
2830*dc48849fSKiran Chandramohan   }
2831*dc48849fSKiran Chandramohan 
2832*dc48849fSKiran Chandramohan   // LLVM::SwitchOp takes a i32 type for the selector.
2833*dc48849fSKiran Chandramohan   if (select.getSelector().getType() != rewriter.getI32Type())
2834*dc48849fSKiran Chandramohan     selector =
2835*dc48849fSKiran Chandramohan         rewriter.create<LLVM::TruncOp>(loc, rewriter.getI32Type(), selector);
2836*dc48849fSKiran Chandramohan 
2837*dc48849fSKiran Chandramohan   rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>(
2838*dc48849fSKiran Chandramohan       select, selector,
2839*dc48849fSKiran Chandramohan       /*defaultDestination=*/defaultDestination,
2840*dc48849fSKiran Chandramohan       /*defaultOperands=*/defaultOperands,
2841*dc48849fSKiran Chandramohan       /*caseValues=*/caseValues,
2842*dc48849fSKiran Chandramohan       /*caseDestinations=*/destinations,
2843*dc48849fSKiran Chandramohan       /*caseOperands=*/destinationsOperands,
2844*dc48849fSKiran Chandramohan       /*branchWeights=*/ArrayRef<int32_t>());
2845*dc48849fSKiran Chandramohan }
2846*dc48849fSKiran Chandramohan 
2847*dc48849fSKiran Chandramohan /// conversion of fir::SelectOp to an if-then-else ladder
2848*dc48849fSKiran Chandramohan struct SelectOpConversion : public FIROpConversion<fir::SelectOp> {
2849*dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2850*dc48849fSKiran Chandramohan 
2851*dc48849fSKiran Chandramohan   mlir::LogicalResult
2852*dc48849fSKiran Chandramohan   matchAndRewrite(fir::SelectOp op, OpAdaptor adaptor,
2853*dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2854*dc48849fSKiran Chandramohan     selectMatchAndRewrite<fir::SelectOp>(lowerTy(), op, adaptor, rewriter);
2855*dc48849fSKiran Chandramohan     return success();
2856*dc48849fSKiran Chandramohan   }
2857*dc48849fSKiran Chandramohan };
2858*dc48849fSKiran Chandramohan 
2859*dc48849fSKiran Chandramohan /// conversion of fir::SelectRankOp to an if-then-else ladder
2860*dc48849fSKiran Chandramohan struct SelectRankOpConversion : public FIROpConversion<fir::SelectRankOp> {
2861*dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2862*dc48849fSKiran Chandramohan 
2863*dc48849fSKiran Chandramohan   mlir::LogicalResult
2864*dc48849fSKiran Chandramohan   matchAndRewrite(fir::SelectRankOp op, OpAdaptor adaptor,
2865*dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2866*dc48849fSKiran Chandramohan     selectMatchAndRewrite<fir::SelectRankOp>(lowerTy(), op, adaptor, rewriter);
2867*dc48849fSKiran Chandramohan     return success();
2868*dc48849fSKiran Chandramohan   }
2869*dc48849fSKiran Chandramohan };
2870*dc48849fSKiran Chandramohan 
2871*dc48849fSKiran Chandramohan /// Lower `fir.select_type` to LLVM IR dialect.
2872*dc48849fSKiran Chandramohan struct SelectTypeOpConversion : public FIROpConversion<fir::SelectTypeOp> {
2873*dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2874*dc48849fSKiran Chandramohan 
2875*dc48849fSKiran Chandramohan   mlir::LogicalResult
2876*dc48849fSKiran Chandramohan   matchAndRewrite(fir::SelectTypeOp select, OpAdaptor adaptor,
2877*dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2878*dc48849fSKiran Chandramohan     mlir::emitError(select.getLoc(),
2879*dc48849fSKiran Chandramohan                     "fir.select_type should have already been converted");
2880*dc48849fSKiran Chandramohan     return failure();
2881*dc48849fSKiran Chandramohan   }
2882*dc48849fSKiran Chandramohan };
2883*dc48849fSKiran Chandramohan 
2884*dc48849fSKiran Chandramohan /// `fir.store` --> `llvm.store`
2885*dc48849fSKiran Chandramohan struct StoreOpConversion : public FIROpConversion<fir::StoreOp> {
2886*dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2887*dc48849fSKiran Chandramohan 
2888*dc48849fSKiran Chandramohan   mlir::LogicalResult
2889*dc48849fSKiran Chandramohan   matchAndRewrite(fir::StoreOp store, OpAdaptor adaptor,
2890*dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2891*dc48849fSKiran Chandramohan     if (store.getValue().getType().isa<fir::BoxType>()) {
2892*dc48849fSKiran Chandramohan       // fir.box value is actually in memory, load it first before storing it.
2893*dc48849fSKiran Chandramohan       mlir::Location loc = store.getLoc();
2894*dc48849fSKiran Chandramohan       mlir::Type boxPtrTy = adaptor.getOperands()[0].getType();
2895*dc48849fSKiran Chandramohan       auto val = rewriter.create<mlir::LLVM::LoadOp>(
2896*dc48849fSKiran Chandramohan           loc, boxPtrTy.cast<mlir::LLVM::LLVMPointerType>().getElementType(),
2897*dc48849fSKiran Chandramohan           adaptor.getOperands()[0]);
2898*dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
2899*dc48849fSKiran Chandramohan           store, val, adaptor.getOperands()[1]);
2900*dc48849fSKiran Chandramohan     } else {
2901*dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
2902*dc48849fSKiran Chandramohan           store, adaptor.getOperands()[0], adaptor.getOperands()[1]);
2903*dc48849fSKiran Chandramohan     }
2904*dc48849fSKiran Chandramohan     return success();
2905*dc48849fSKiran Chandramohan   }
2906*dc48849fSKiran Chandramohan };
2907*dc48849fSKiran Chandramohan 
2908*dc48849fSKiran Chandramohan namespace {
2909*dc48849fSKiran Chandramohan 
2910*dc48849fSKiran Chandramohan /// Convert `fir.unboxchar` into two `llvm.extractvalue` instructions. One for
2911*dc48849fSKiran Chandramohan /// the character buffer and one for the buffer length.
2912*dc48849fSKiran Chandramohan struct UnboxCharOpConversion : public FIROpConversion<fir::UnboxCharOp> {
2913*dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2914*dc48849fSKiran Chandramohan 
2915*dc48849fSKiran Chandramohan   mlir::LogicalResult
2916*dc48849fSKiran Chandramohan   matchAndRewrite(fir::UnboxCharOp unboxchar, OpAdaptor adaptor,
2917*dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2918*dc48849fSKiran Chandramohan     MLIRContext *ctx = unboxchar.getContext();
2919*dc48849fSKiran Chandramohan 
2920*dc48849fSKiran Chandramohan     mlir::Type lenTy = convertType(unboxchar.getType(1));
2921*dc48849fSKiran Chandramohan     mlir::Value tuple = adaptor.getOperands()[0];
2922*dc48849fSKiran Chandramohan     mlir::Type tupleTy = tuple.getType();
2923*dc48849fSKiran Chandramohan 
2924*dc48849fSKiran Chandramohan     mlir::Location loc = unboxchar.getLoc();
2925*dc48849fSKiran Chandramohan     mlir::Value ptrToBuffer =
2926*dc48849fSKiran Chandramohan         genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 0);
2927*dc48849fSKiran Chandramohan 
2928*dc48849fSKiran Chandramohan     mlir::LLVM::ExtractValueOp len =
2929*dc48849fSKiran Chandramohan         genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 1);
2930*dc48849fSKiran Chandramohan     mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, len);
2931*dc48849fSKiran Chandramohan 
2932*dc48849fSKiran Chandramohan     rewriter.replaceOp(unboxchar,
2933*dc48849fSKiran Chandramohan                        ArrayRef<mlir::Value>{ptrToBuffer, lenAfterCast});
2934*dc48849fSKiran Chandramohan     return success();
2935*dc48849fSKiran Chandramohan   }
2936*dc48849fSKiran Chandramohan };
2937*dc48849fSKiran Chandramohan 
2938*dc48849fSKiran Chandramohan /// Lower `fir.unboxproc` operation. Unbox a procedure box value, yielding its
2939*dc48849fSKiran Chandramohan /// components.
2940*dc48849fSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
2941*dc48849fSKiran Chandramohan struct UnboxProcOpConversion : public FIROpConversion<fir::UnboxProcOp> {
2942*dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2943*dc48849fSKiran Chandramohan 
2944*dc48849fSKiran Chandramohan   mlir::LogicalResult
2945*dc48849fSKiran Chandramohan   matchAndRewrite(fir::UnboxProcOp unboxproc, OpAdaptor adaptor,
2946*dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2947*dc48849fSKiran Chandramohan     TODO(unboxproc.getLoc(), "fir.unboxproc codegen");
2948*dc48849fSKiran Chandramohan     return failure();
2949*dc48849fSKiran Chandramohan   }
2950*dc48849fSKiran Chandramohan };
2951*dc48849fSKiran Chandramohan 
2952*dc48849fSKiran Chandramohan /// convert to LLVM IR dialect `undef`
2953*dc48849fSKiran Chandramohan struct UndefOpConversion : public FIROpConversion<fir::UndefOp> {
2954*dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2955*dc48849fSKiran Chandramohan 
2956*dc48849fSKiran Chandramohan   mlir::LogicalResult
2957*dc48849fSKiran Chandramohan   matchAndRewrite(fir::UndefOp undef, OpAdaptor,
2958*dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2959*dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::UndefOp>(
2960*dc48849fSKiran Chandramohan         undef, convertType(undef.getType()));
2961*dc48849fSKiran Chandramohan     return success();
2962*dc48849fSKiran Chandramohan   }
2963*dc48849fSKiran Chandramohan };
2964*dc48849fSKiran Chandramohan 
2965*dc48849fSKiran Chandramohan struct ZeroOpConversion : public FIROpConversion<fir::ZeroOp> {
2966*dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2967*dc48849fSKiran Chandramohan 
2968*dc48849fSKiran Chandramohan   mlir::LogicalResult
2969*dc48849fSKiran Chandramohan   matchAndRewrite(fir::ZeroOp zero, OpAdaptor,
2970*dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2971*dc48849fSKiran Chandramohan     mlir::Type ty = convertType(zero.getType());
2972*dc48849fSKiran Chandramohan     if (ty.isa<mlir::LLVM::LLVMPointerType>()) {
2973*dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(zero, ty);
2974*dc48849fSKiran Chandramohan     } else if (ty.isa<mlir::IntegerType>()) {
2975*dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
2976*dc48849fSKiran Chandramohan           zero, ty, mlir::IntegerAttr::get(zero.getType(), 0));
2977*dc48849fSKiran Chandramohan     } else if (mlir::LLVM::isCompatibleFloatingPointType(ty)) {
2978*dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
2979*dc48849fSKiran Chandramohan           zero, ty, mlir::FloatAttr::get(zero.getType(), 0.0));
2980*dc48849fSKiran Chandramohan     } else {
2981*dc48849fSKiran Chandramohan       // TODO: create ConstantAggregateZero for FIR aggregate/array types.
2982*dc48849fSKiran Chandramohan       return rewriter.notifyMatchFailure(
2983*dc48849fSKiran Chandramohan           zero,
2984*dc48849fSKiran Chandramohan           "conversion of fir.zero with aggregate type not implemented yet");
2985*dc48849fSKiran Chandramohan     }
2986*dc48849fSKiran Chandramohan     return success();
2987*dc48849fSKiran Chandramohan   }
2988*dc48849fSKiran Chandramohan };
2989*dc48849fSKiran Chandramohan 
2990*dc48849fSKiran Chandramohan /// `fir.unreachable` --> `llvm.unreachable`
2991*dc48849fSKiran Chandramohan struct UnreachableOpConversion : public FIROpConversion<fir::UnreachableOp> {
2992*dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2993*dc48849fSKiran Chandramohan 
2994*dc48849fSKiran Chandramohan   mlir::LogicalResult
2995*dc48849fSKiran Chandramohan   matchAndRewrite(fir::UnreachableOp unreach, OpAdaptor adaptor,
2996*dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2997*dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(unreach);
2998*dc48849fSKiran Chandramohan     return success();
2999*dc48849fSKiran Chandramohan   }
3000*dc48849fSKiran Chandramohan };
3001*dc48849fSKiran Chandramohan 
3002*dc48849fSKiran Chandramohan /// `fir.is_present` -->
3003*dc48849fSKiran Chandramohan /// ```
3004*dc48849fSKiran Chandramohan ///  %0 = llvm.mlir.constant(0 : i64)
3005*dc48849fSKiran Chandramohan ///  %1 = llvm.ptrtoint %0
3006*dc48849fSKiran Chandramohan ///  %2 = llvm.icmp "ne" %1, %0 : i64
3007*dc48849fSKiran Chandramohan /// ```
3008*dc48849fSKiran Chandramohan struct IsPresentOpConversion : public FIROpConversion<fir::IsPresentOp> {
3009*dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3010*dc48849fSKiran Chandramohan 
3011*dc48849fSKiran Chandramohan   mlir::LogicalResult
3012*dc48849fSKiran Chandramohan   matchAndRewrite(fir::IsPresentOp isPresent, OpAdaptor adaptor,
3013*dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3014*dc48849fSKiran Chandramohan     mlir::Type idxTy = lowerTy().indexType();
3015*dc48849fSKiran Chandramohan     mlir::Location loc = isPresent.getLoc();
3016*dc48849fSKiran Chandramohan     auto ptr = adaptor.getOperands()[0];
3017*dc48849fSKiran Chandramohan 
3018*dc48849fSKiran Chandramohan     if (isPresent.getVal().getType().isa<fir::BoxCharType>()) {
3019*dc48849fSKiran Chandramohan       auto structTy = ptr.getType().cast<mlir::LLVM::LLVMStructType>();
3020*dc48849fSKiran Chandramohan       assert(!structTy.isOpaque() && !structTy.getBody().empty());
3021*dc48849fSKiran Chandramohan 
3022*dc48849fSKiran Chandramohan       mlir::Type ty = structTy.getBody()[0];
3023*dc48849fSKiran Chandramohan       mlir::MLIRContext *ctx = isPresent.getContext();
3024*dc48849fSKiran Chandramohan       auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
3025*dc48849fSKiran Chandramohan       ptr = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, ptr, c0);
3026*dc48849fSKiran Chandramohan     }
3027*dc48849fSKiran Chandramohan     mlir::LLVM::ConstantOp c0 =
3028*dc48849fSKiran Chandramohan         genConstantIndex(isPresent.getLoc(), idxTy, rewriter, 0);
3029*dc48849fSKiran Chandramohan     auto addr = rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, ptr);
3030*dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
3031*dc48849fSKiran Chandramohan         isPresent, mlir::LLVM::ICmpPredicate::ne, addr, c0);
3032*dc48849fSKiran Chandramohan 
3033*dc48849fSKiran Chandramohan     return success();
3034*dc48849fSKiran Chandramohan   }
3035*dc48849fSKiran Chandramohan };
3036*dc48849fSKiran Chandramohan 
3037*dc48849fSKiran Chandramohan /// Create value signaling an absent optional argument in a call, e.g.
3038*dc48849fSKiran Chandramohan /// `fir.absent !fir.ref<i64>` -->  `llvm.mlir.null : !llvm.ptr<i64>`
3039*dc48849fSKiran Chandramohan struct AbsentOpConversion : public FIROpConversion<fir::AbsentOp> {
3040*dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3041*dc48849fSKiran Chandramohan 
3042*dc48849fSKiran Chandramohan   mlir::LogicalResult
3043*dc48849fSKiran Chandramohan   matchAndRewrite(fir::AbsentOp absent, OpAdaptor,
3044*dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3045*dc48849fSKiran Chandramohan     mlir::Type ty = convertType(absent.getType());
3046*dc48849fSKiran Chandramohan     mlir::Location loc = absent.getLoc();
3047*dc48849fSKiran Chandramohan 
3048*dc48849fSKiran Chandramohan     if (absent.getType().isa<fir::BoxCharType>()) {
3049*dc48849fSKiran Chandramohan       auto structTy = ty.cast<mlir::LLVM::LLVMStructType>();
3050*dc48849fSKiran Chandramohan       assert(!structTy.isOpaque() && !structTy.getBody().empty());
3051*dc48849fSKiran Chandramohan       auto undefStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
3052*dc48849fSKiran Chandramohan       auto nullField =
3053*dc48849fSKiran Chandramohan           rewriter.create<mlir::LLVM::NullOp>(loc, structTy.getBody()[0]);
3054*dc48849fSKiran Chandramohan       mlir::MLIRContext *ctx = absent.getContext();
3055*dc48849fSKiran Chandramohan       auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
3056*dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
3057*dc48849fSKiran Chandramohan           absent, ty, undefStruct, nullField, c0);
3058*dc48849fSKiran Chandramohan     } else {
3059*dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(absent, ty);
3060*dc48849fSKiran Chandramohan     }
3061*dc48849fSKiran Chandramohan     return success();
3062*dc48849fSKiran Chandramohan   }
3063*dc48849fSKiran Chandramohan };
30645d27abe6SValentin Clement 
30657b5132daSValentin Clement //
30667b5132daSValentin Clement // Primitive operations on Complex types
30677b5132daSValentin Clement //
30687b5132daSValentin Clement 
30697b5132daSValentin Clement /// Generate inline code for complex addition/subtraction
30707b5132daSValentin Clement template <typename LLVMOP, typename OPTY>
3071c2acd453SAlexisPerry static mlir::LLVM::InsertValueOp
3072c2acd453SAlexisPerry complexSum(OPTY sumop, mlir::ValueRange opnds,
30737b5132daSValentin Clement            mlir::ConversionPatternRewriter &rewriter,
30747b5132daSValentin Clement            fir::LLVMTypeConverter &lowering) {
30757b5132daSValentin Clement   mlir::Value a = opnds[0];
30767b5132daSValentin Clement   mlir::Value b = opnds[1];
30777b5132daSValentin Clement   auto loc = sumop.getLoc();
30787b5132daSValentin Clement   auto ctx = sumop.getContext();
30797b5132daSValentin Clement   auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
30807b5132daSValentin Clement   auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
30817b5132daSValentin Clement   mlir::Type eleTy = lowering.convertType(getComplexEleTy(sumop.getType()));
30827b5132daSValentin Clement   mlir::Type ty = lowering.convertType(sumop.getType());
30837b5132daSValentin Clement   auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
30847b5132daSValentin Clement   auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
30857b5132daSValentin Clement   auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
30867b5132daSValentin Clement   auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
30877b5132daSValentin Clement   auto rx = rewriter.create<LLVMOP>(loc, eleTy, x0, x1);
30887b5132daSValentin Clement   auto ry = rewriter.create<LLVMOP>(loc, eleTy, y0, y1);
30897b5132daSValentin Clement   auto r0 = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
30907b5132daSValentin Clement   auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r0, rx, c0);
30917b5132daSValentin Clement   return rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ry, c1);
30927b5132daSValentin Clement }
3093*dc48849fSKiran Chandramohan } // namespace
30947b5132daSValentin Clement 
3095c2acd453SAlexisPerry namespace {
30967b5132daSValentin Clement struct AddcOpConversion : public FIROpConversion<fir::AddcOp> {
30977b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
30987b5132daSValentin Clement 
30997b5132daSValentin Clement   mlir::LogicalResult
31007b5132daSValentin Clement   matchAndRewrite(fir::AddcOp addc, OpAdaptor adaptor,
31017b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
31027b5132daSValentin Clement     // given: (x + iy) + (x' + iy')
31037b5132daSValentin Clement     // result: (x + x') + i(y + y')
31047b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FAddOp>(addc, adaptor.getOperands(),
31057b5132daSValentin Clement                                             rewriter, lowerTy());
31067b5132daSValentin Clement     rewriter.replaceOp(addc, r.getResult());
31077b5132daSValentin Clement     return success();
31087b5132daSValentin Clement   }
31097b5132daSValentin Clement };
31107b5132daSValentin Clement 
31117b5132daSValentin Clement struct SubcOpConversion : public FIROpConversion<fir::SubcOp> {
31127b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
31137b5132daSValentin Clement 
31147b5132daSValentin Clement   mlir::LogicalResult
31157b5132daSValentin Clement   matchAndRewrite(fir::SubcOp subc, OpAdaptor adaptor,
31167b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
31177b5132daSValentin Clement     // given: (x + iy) - (x' + iy')
31187b5132daSValentin Clement     // result: (x - x') + i(y - y')
31197b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FSubOp>(subc, adaptor.getOperands(),
31207b5132daSValentin Clement                                             rewriter, lowerTy());
31217b5132daSValentin Clement     rewriter.replaceOp(subc, r.getResult());
31227b5132daSValentin Clement     return success();
31237b5132daSValentin Clement   }
31247b5132daSValentin Clement };
31257b5132daSValentin Clement 
31267b5132daSValentin Clement /// Inlined complex multiply
31277b5132daSValentin Clement struct MulcOpConversion : public FIROpConversion<fir::MulcOp> {
31287b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
31297b5132daSValentin Clement 
31307b5132daSValentin Clement   mlir::LogicalResult
31317b5132daSValentin Clement   matchAndRewrite(fir::MulcOp mulc, OpAdaptor adaptor,
31327b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
31337b5132daSValentin Clement     // TODO: Can we use a call to __muldc3 ?
31347b5132daSValentin Clement     // given: (x + iy) * (x' + iy')
31357b5132daSValentin Clement     // result: (xx'-yy')+i(xy'+yx')
31367b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
31377b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
31387b5132daSValentin Clement     auto loc = mulc.getLoc();
31397b5132daSValentin Clement     auto *ctx = mulc.getContext();
31407b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
31417b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
31427b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(mulc.getType()));
31437b5132daSValentin Clement     mlir::Type ty = convertType(mulc.getType());
31447b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
31457b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
31467b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
31477b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
31487b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
31497b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
31507b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
31517b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xy, yx);
31527b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
31537b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, xx, yy);
31547b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
31557b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
31567b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
31577b5132daSValentin Clement     rewriter.replaceOp(mulc, r0.getResult());
31587b5132daSValentin Clement     return success();
31597b5132daSValentin Clement   }
31607b5132daSValentin Clement };
31617b5132daSValentin Clement 
31627b5132daSValentin Clement /// Inlined complex division
31637b5132daSValentin Clement struct DivcOpConversion : public FIROpConversion<fir::DivcOp> {
31647b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
31657b5132daSValentin Clement 
31667b5132daSValentin Clement   mlir::LogicalResult
31677b5132daSValentin Clement   matchAndRewrite(fir::DivcOp divc, OpAdaptor adaptor,
31687b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
31697b5132daSValentin Clement     // TODO: Can we use a call to __divdc3 instead?
31707b5132daSValentin Clement     // Just generate inline code for now.
31717b5132daSValentin Clement     // given: (x + iy) / (x' + iy')
31727b5132daSValentin Clement     // result: ((xx'+yy')/d) + i((yx'-xy')/d) where d = x'x' + y'y'
31737b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
31747b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
31757b5132daSValentin Clement     auto loc = divc.getLoc();
31767b5132daSValentin Clement     auto *ctx = divc.getContext();
31777b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
31787b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
31797b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(divc.getType()));
31807b5132daSValentin Clement     mlir::Type ty = convertType(divc.getType());
31817b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
31827b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
31837b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
31847b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
31857b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
31867b5132daSValentin Clement     auto x1x1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x1, x1);
31877b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
31887b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
31897b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
31907b5132daSValentin Clement     auto y1y1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y1, y1);
31917b5132daSValentin Clement     auto d = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, x1x1, y1y1);
31927b5132daSValentin Clement     auto rrn = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xx, yy);
31937b5132daSValentin Clement     auto rin = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, yx, xy);
31947b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rrn, d);
31957b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rin, d);
31967b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
31977b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
31987b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
31997b5132daSValentin Clement     rewriter.replaceOp(divc, r0.getResult());
32007b5132daSValentin Clement     return success();
32017b5132daSValentin Clement   }
32027b5132daSValentin Clement };
32037b5132daSValentin Clement 
32047b5132daSValentin Clement /// Inlined complex negation
32057b5132daSValentin Clement struct NegcOpConversion : public FIROpConversion<fir::NegcOp> {
32067b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
32077b5132daSValentin Clement 
32087b5132daSValentin Clement   mlir::LogicalResult
32097b5132daSValentin Clement   matchAndRewrite(fir::NegcOp neg, OpAdaptor adaptor,
32107b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
32117b5132daSValentin Clement     // given: -(x + iy)
32127b5132daSValentin Clement     // result: -x - iy
32137b5132daSValentin Clement     auto *ctxt = neg.getContext();
32147b5132daSValentin Clement     auto eleTy = convertType(getComplexEleTy(neg.getType()));
32157b5132daSValentin Clement     auto ty = convertType(neg.getType());
32167b5132daSValentin Clement     auto loc = neg.getLoc();
32177b5132daSValentin Clement     mlir::Value o0 = adaptor.getOperands()[0];
32187b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0));
32197b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1));
32207b5132daSValentin Clement     auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c0);
32217b5132daSValentin Clement     auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c1);
32227b5132daSValentin Clement     auto nrp = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, rp);
32237b5132daSValentin Clement     auto nip = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, ip);
32247b5132daSValentin Clement     auto r = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, o0, nrp, c0);
32257b5132daSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(neg, ty, r, nip, c1);
32267b5132daSValentin Clement     return success();
32277b5132daSValentin Clement   }
32287b5132daSValentin Clement };
32297b5132daSValentin Clement 
32301ed5a90fSValentin Clement /// Conversion pattern for operation that must be dead. The information in these
32311ed5a90fSValentin Clement /// operations is used by other operation. At this point they should not have
32321ed5a90fSValentin Clement /// anymore uses.
32331ed5a90fSValentin Clement /// These operations are normally dead after the pre-codegen pass.
32341ed5a90fSValentin Clement template <typename FromOp>
32351ed5a90fSValentin Clement struct MustBeDeadConversion : public FIROpConversion<FromOp> {
32361ed5a90fSValentin Clement   explicit MustBeDeadConversion(fir::LLVMTypeConverter &lowering)
32371ed5a90fSValentin Clement       : FIROpConversion<FromOp>(lowering) {}
32381ed5a90fSValentin Clement   using OpAdaptor = typename FromOp::Adaptor;
32391ed5a90fSValentin Clement 
32401ed5a90fSValentin Clement   mlir::LogicalResult
32411ed5a90fSValentin Clement   matchAndRewrite(FromOp op, OpAdaptor adaptor,
32421ed5a90fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const final {
32431ed5a90fSValentin Clement     if (!op->getUses().empty())
32441ed5a90fSValentin Clement       return rewriter.notifyMatchFailure(op, "op must be dead");
32451ed5a90fSValentin Clement     rewriter.eraseOp(op);
32461ed5a90fSValentin Clement     return success();
32471ed5a90fSValentin Clement   }
32481ed5a90fSValentin Clement };
32491ed5a90fSValentin Clement 
32501ed5a90fSValentin Clement struct ShapeOpConversion : public MustBeDeadConversion<fir::ShapeOp> {
32511ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
32521ed5a90fSValentin Clement };
32531ed5a90fSValentin Clement 
32541ed5a90fSValentin Clement struct ShapeShiftOpConversion : public MustBeDeadConversion<fir::ShapeShiftOp> {
32551ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
32561ed5a90fSValentin Clement };
32571ed5a90fSValentin Clement 
32581ed5a90fSValentin Clement struct ShiftOpConversion : public MustBeDeadConversion<fir::ShiftOp> {
32591ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
32601ed5a90fSValentin Clement };
32611ed5a90fSValentin Clement 
32621ed5a90fSValentin Clement struct SliceOpConversion : public MustBeDeadConversion<fir::SliceOp> {
32631ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
32641ed5a90fSValentin Clement };
32651ed5a90fSValentin Clement 
3266044d5b5dSValentin Clement } // namespace
3267044d5b5dSValentin Clement 
3268044d5b5dSValentin Clement namespace {
3269044d5b5dSValentin Clement /// Convert FIR dialect to LLVM dialect
3270044d5b5dSValentin Clement ///
3271044d5b5dSValentin Clement /// This pass lowers all FIR dialect operations to LLVM IR dialect. An
3272044d5b5dSValentin Clement /// MLIR pass is used to lower residual Std dialect to LLVM IR dialect.
3273044d5b5dSValentin Clement ///
3274044d5b5dSValentin Clement /// This pass is not complete yet. We are upstreaming it in small patches.
3275044d5b5dSValentin Clement class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> {
3276044d5b5dSValentin Clement public:
3277044d5b5dSValentin Clement   mlir::ModuleOp getModule() { return getOperation(); }
3278044d5b5dSValentin Clement 
3279044d5b5dSValentin Clement   void runOnOperation() override final {
32807b5132daSValentin Clement     auto mod = getModule();
32817b5132daSValentin Clement     if (!forcedTargetTriple.empty()) {
32827b5132daSValentin Clement       fir::setTargetTriple(mod, forcedTargetTriple);
32837b5132daSValentin Clement     }
32847b5132daSValentin Clement 
3285044d5b5dSValentin Clement     auto *context = getModule().getContext();
3286044d5b5dSValentin Clement     fir::LLVMTypeConverter typeConverter{getModule()};
32879f85c198SRiver Riddle     mlir::RewritePatternSet pattern(context);
3288df3b9810SValentin Clement     pattern.insert<
3289420ad7ceSAndrzej Warzynski         AbsentOpConversion, AddcOpConversion, AddrOfOpConversion,
3290c2acd453SAlexisPerry         AllocaOpConversion, AllocMemOpConversion, BoxAddrOpConversion,
3291c2acd453SAlexisPerry         BoxCharLenOpConversion, BoxDimsOpConversion, BoxEleSizeOpConversion,
3292c2acd453SAlexisPerry         BoxIsAllocOpConversion, BoxIsArrayOpConversion, BoxIsPtrOpConversion,
3293c2acd453SAlexisPerry         BoxProcHostOpConversion, BoxRankOpConversion, BoxTypeDescOpConversion,
3294c2acd453SAlexisPerry         CallOpConversion, CmpcOpConversion, ConstcOpConversion,
3295e6e7da55SAndrzej Warzynski         ConvertOpConversion, CoordinateOpConversion, DispatchOpConversion,
3296e6e7da55SAndrzej Warzynski         DispatchTableOpConversion, DTEntryOpConversion, DivcOpConversion,
3297e6e7da55SAndrzej Warzynski         EmboxOpConversion, EmboxCharOpConversion, EmboxProcOpConversion,
3298e6e7da55SAndrzej Warzynski         ExtractValueOpConversion, FieldIndexOpConversion, FirEndOpConversion,
3299*dc48849fSKiran Chandramohan         FreeMemOpConversion, GenTypeDescOpConversion, GlobalLenOpConversion,
3300*dc48849fSKiran Chandramohan         GlobalOpConversion, HasValueOpConversion, InsertOnRangeOpConversion,
3301e6e7da55SAndrzej Warzynski         InsertValueOpConversion, IsPresentOpConversion,
3302*dc48849fSKiran Chandramohan         LenParamIndexOpConversion, LoadOpConversion, MulcOpConversion,
3303*dc48849fSKiran Chandramohan         NegcOpConversion, NoReassocOpConversion, SelectCaseOpConversion,
3304e6e7da55SAndrzej Warzynski         SelectOpConversion, SelectRankOpConversion, SelectTypeOpConversion,
3305e6e7da55SAndrzej Warzynski         ShapeOpConversion, ShapeShiftOpConversion, ShiftOpConversion,
3306e6e7da55SAndrzej Warzynski         SliceOpConversion, StoreOpConversion, StringLitOpConversion,
3307e6e7da55SAndrzej Warzynski         SubcOpConversion, UnboxCharOpConversion, UnboxProcOpConversion,
3308e6e7da55SAndrzej Warzynski         UndefOpConversion, UnreachableOpConversion, XArrayCoorOpConversion,
3309e6e7da55SAndrzej Warzynski         XEmboxOpConversion, XReboxOpConversion, ZeroOpConversion>(
3310e6e7da55SAndrzej Warzynski         typeConverter);
3311044d5b5dSValentin Clement     mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern);
3312044d5b5dSValentin Clement     mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter,
3313044d5b5dSValentin Clement                                                             pattern);
3314ace01605SRiver Riddle     mlir::cf::populateControlFlowToLLVMConversionPatterns(typeConverter,
3315ace01605SRiver Riddle                                                           pattern);
3316044d5b5dSValentin Clement     mlir::ConversionTarget target{*context};
3317044d5b5dSValentin Clement     target.addLegalDialect<mlir::LLVM::LLVMDialect>();
3318044d5b5dSValentin Clement 
3319044d5b5dSValentin Clement     // required NOPs for applying a full conversion
3320044d5b5dSValentin Clement     target.addLegalOp<mlir::ModuleOp>();
3321044d5b5dSValentin Clement 
3322044d5b5dSValentin Clement     // apply the patterns
3323044d5b5dSValentin Clement     if (mlir::failed(mlir::applyFullConversion(getModule(), target,
3324044d5b5dSValentin Clement                                                std::move(pattern)))) {
3325044d5b5dSValentin Clement       signalPassFailure();
3326044d5b5dSValentin Clement     }
3327044d5b5dSValentin Clement   }
3328044d5b5dSValentin Clement };
3329853e79d8SValentin Clement 
3330853e79d8SValentin Clement /// Lower from LLVM IR dialect to proper LLVM-IR and dump the module
3331853e79d8SValentin Clement struct LLVMIRLoweringPass
3332853e79d8SValentin Clement     : public mlir::PassWrapper<LLVMIRLoweringPass,
3333853e79d8SValentin Clement                                mlir::OperationPass<mlir::ModuleOp>> {
3334853e79d8SValentin Clement   using Printer = fir::LLVMIRLoweringPrinter;
3335853e79d8SValentin Clement   LLVMIRLoweringPass(raw_ostream &output, Printer p)
3336853e79d8SValentin Clement       : output{output}, printer{p} {}
3337853e79d8SValentin Clement 
3338853e79d8SValentin Clement   mlir::ModuleOp getModule() { return getOperation(); }
3339853e79d8SValentin Clement 
3340853e79d8SValentin Clement   void runOnOperation() override final {
3341853e79d8SValentin Clement     auto *ctx = getModule().getContext();
3342853e79d8SValentin Clement     auto optName = getModule().getName();
3343853e79d8SValentin Clement     llvm::LLVMContext llvmCtx;
3344853e79d8SValentin Clement     if (auto llvmModule = mlir::translateModuleToLLVMIR(
3345853e79d8SValentin Clement             getModule(), llvmCtx, optName ? *optName : "FIRModule")) {
3346853e79d8SValentin Clement       printer(*llvmModule, output);
3347853e79d8SValentin Clement       return;
3348853e79d8SValentin Clement     }
3349853e79d8SValentin Clement 
3350853e79d8SValentin Clement     mlir::emitError(mlir::UnknownLoc::get(ctx), "could not emit LLVM-IR\n");
3351853e79d8SValentin Clement     signalPassFailure();
3352853e79d8SValentin Clement   }
3353853e79d8SValentin Clement 
3354853e79d8SValentin Clement private:
3355853e79d8SValentin Clement   raw_ostream &output;
3356853e79d8SValentin Clement   Printer printer;
3357853e79d8SValentin Clement };
3358853e79d8SValentin Clement 
3359044d5b5dSValentin Clement } // namespace
3360044d5b5dSValentin Clement 
3361044d5b5dSValentin Clement std::unique_ptr<mlir::Pass> fir::createFIRToLLVMPass() {
3362044d5b5dSValentin Clement   return std::make_unique<FIRToLLVMLowering>();
3363044d5b5dSValentin Clement }
3364853e79d8SValentin Clement 
3365853e79d8SValentin Clement std::unique_ptr<mlir::Pass>
3366853e79d8SValentin Clement fir::createLLVMDialectToLLVMPass(raw_ostream &output,
3367853e79d8SValentin Clement                                  fir::LLVMIRLoweringPrinter printer) {
3368853e79d8SValentin Clement   return std::make_unique<LLVMIRLoweringPass>(output, printer);
3369853e79d8SValentin Clement }
3370