1044d5b5dSValentin Clement //===-- CodeGen.cpp -- bridge to lower to LLVM ----------------------------===//
2044d5b5dSValentin Clement //
3044d5b5dSValentin Clement // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4044d5b5dSValentin Clement // See https://llvm.org/LICENSE.txt for license information.
5044d5b5dSValentin Clement // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6044d5b5dSValentin Clement //
7044d5b5dSValentin Clement //===----------------------------------------------------------------------===//
8044d5b5dSValentin Clement //
9044d5b5dSValentin Clement // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10044d5b5dSValentin Clement //
11044d5b5dSValentin Clement //===----------------------------------------------------------------------===//
12044d5b5dSValentin Clement 
13044d5b5dSValentin Clement #include "flang/Optimizer/CodeGen/CodeGen.h"
141f551032SValentin Clement #include "CGOps.h"
15044d5b5dSValentin Clement #include "PassDetail.h"
16b6e44ecdSValentin Clement #include "flang/ISO_Fortran_binding.h"
1739f4ef81SValentin Clement #include "flang/Optimizer/Dialect/FIRAttr.h"
18044d5b5dSValentin Clement #include "flang/Optimizer/Dialect/FIROps.h"
197dd7ccd2SJean Perier #include "flang/Optimizer/Support/InternalNames.h"
20af6ee580SValentin Clement #include "flang/Optimizer/Support/TypeCode.h"
217dd7ccd2SJean Perier #include "flang/Semantics/runtime-type-info.h"
22044d5b5dSValentin Clement #include "mlir/Conversion/ArithmeticToLLVM/ArithmeticToLLVM.h"
23ace01605SRiver Riddle #include "mlir/Conversion/ControlFlowToLLVM/ControlFlowToLLVM.h"
245a7b9194SRiver Riddle #include "mlir/Conversion/FuncToLLVM/ConvertFuncToLLVM.h"
25044d5b5dSValentin Clement #include "mlir/Conversion/LLVMCommon/Pattern.h"
269f356579SSlava Zakharin #include "mlir/Conversion/MathToLLVM/MathToLLVM.h"
279f356579SSlava Zakharin #include "mlir/Conversion/MathToLibm/MathToLibm.h"
28c6ac9370SKiran Chandramohan #include "mlir/Conversion/OpenMPToLLVM/ConvertOpenMPToLLVM.h"
29044d5b5dSValentin Clement #include "mlir/IR/BuiltinTypes.h"
303ae8e442SValentin Clement #include "mlir/IR/Matchers.h"
31044d5b5dSValentin Clement #include "mlir/Pass/Pass.h"
32853e79d8SValentin Clement #include "mlir/Target/LLVMIR/ModuleTranslation.h"
33044d5b5dSValentin Clement #include "llvm/ADT/ArrayRef.h"
34044d5b5dSValentin Clement 
35044d5b5dSValentin Clement #define DEBUG_TYPE "flang-codegen"
36044d5b5dSValentin Clement 
37044d5b5dSValentin Clement // fir::LLVMTypeConverter for converting to LLVM IR dialect types.
38044d5b5dSValentin Clement #include "TypeConverter.h"
39044d5b5dSValentin Clement 
40af6ee580SValentin Clement // TODO: This should really be recovered from the specified target.
41af6ee580SValentin Clement static constexpr unsigned defaultAlign = 8;
42af6ee580SValentin Clement 
43b6e44ecdSValentin Clement /// `fir.box` attribute values as defined for CFI_attribute_t in
44b6e44ecdSValentin Clement /// flang/ISO_Fortran_binding.h.
45b6e44ecdSValentin Clement static constexpr unsigned kAttrPointer = CFI_attribute_pointer;
46b6e44ecdSValentin Clement static constexpr unsigned kAttrAllocatable = CFI_attribute_allocatable;
47b6e44ecdSValentin Clement 
48135d5d4aSKiran Chandramohan static inline mlir::Type getVoidPtrType(mlir::MLIRContext *context) {
49fa517555SKiran Chandramohan   return mlir::LLVM::LLVMPointerType::get(mlir::IntegerType::get(context, 8));
50fa517555SKiran Chandramohan }
51fa517555SKiran Chandramohan 
521e6d9c06SDiana Picus static mlir::LLVM::ConstantOp
531e6d9c06SDiana Picus genConstantIndex(mlir::Location loc, mlir::Type ity,
541e6d9c06SDiana Picus                  mlir::ConversionPatternRewriter &rewriter,
551e6d9c06SDiana Picus                  std::int64_t offset) {
561e6d9c06SDiana Picus   auto cattr = rewriter.getI64IntegerAttr(offset);
571e6d9c06SDiana Picus   return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr);
581e6d9c06SDiana Picus }
591e6d9c06SDiana Picus 
6044e58509SEric Schweitz static mlir::Block *createBlock(mlir::ConversionPatternRewriter &rewriter,
6139f4ef81SValentin Clement                                 mlir::Block *insertBefore) {
6239f4ef81SValentin Clement   assert(insertBefore && "expected valid insertion block");
6339f4ef81SValentin Clement   return rewriter.createBlock(insertBefore->getParent(),
6439f4ef81SValentin Clement                               mlir::Region::iterator(insertBefore));
6539f4ef81SValentin Clement }
6639f4ef81SValentin Clement 
67044d5b5dSValentin Clement namespace {
68044d5b5dSValentin Clement /// FIR conversion pattern template
69044d5b5dSValentin Clement template <typename FromOp>
70044d5b5dSValentin Clement class FIROpConversion : public mlir::ConvertOpToLLVMPattern<FromOp> {
71044d5b5dSValentin Clement public:
72013160f6SJean Perier   explicit FIROpConversion(fir::LLVMTypeConverter &lowering,
73013160f6SJean Perier                            const fir::FIRToLLVMPassOptions &options)
74013160f6SJean Perier       : mlir::ConvertOpToLLVMPattern<FromOp>(lowering), options(options) {}
75044d5b5dSValentin Clement 
76044d5b5dSValentin Clement protected:
77044d5b5dSValentin Clement   mlir::Type convertType(mlir::Type ty) const {
78044d5b5dSValentin Clement     return lowerTy().convertType(ty);
79044d5b5dSValentin Clement   }
80c2acd453SAlexisPerry   mlir::Type voidPtrTy() const { return getVoidPtrType(); }
81044d5b5dSValentin Clement 
825d27abe6SValentin Clement   mlir::Type getVoidPtrType() const {
835d27abe6SValentin Clement     return mlir::LLVM::LLVMPointerType::get(
845d27abe6SValentin Clement         mlir::IntegerType::get(&lowerTy().getContext(), 8));
855d27abe6SValentin Clement   }
865d27abe6SValentin Clement 
87df3b9810SValentin Clement   mlir::LLVM::ConstantOp
88af6ee580SValentin Clement   genI32Constant(mlir::Location loc, mlir::ConversionPatternRewriter &rewriter,
89af6ee580SValentin Clement                  int value) const {
90af6ee580SValentin Clement     mlir::Type i32Ty = rewriter.getI32Type();
91af6ee580SValentin Clement     mlir::IntegerAttr attr = rewriter.getI32IntegerAttr(value);
92af6ee580SValentin Clement     return rewriter.create<mlir::LLVM::ConstantOp>(loc, i32Ty, attr);
93af6ee580SValentin Clement   }
94af6ee580SValentin Clement 
95af6ee580SValentin Clement   mlir::LLVM::ConstantOp
96df3b9810SValentin Clement   genConstantOffset(mlir::Location loc,
97df3b9810SValentin Clement                     mlir::ConversionPatternRewriter &rewriter,
98df3b9810SValentin Clement                     int offset) const {
99af6ee580SValentin Clement     mlir::Type ity = lowerTy().offsetType();
100af6ee580SValentin Clement     mlir::IntegerAttr cattr = rewriter.getI32IntegerAttr(offset);
101df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr);
102df3b9810SValentin Clement   }
103df3b9810SValentin Clement 
104dc48849fSKiran Chandramohan   /// Perform an extension or truncation as needed on an integer value. Lowering
105dc48849fSKiran Chandramohan   /// to the specific target may involve some sign-extending or truncation of
106dc48849fSKiran Chandramohan   /// values, particularly to fit them from abstract box types to the
107dc48849fSKiran Chandramohan   /// appropriate reified structures.
108dc48849fSKiran Chandramohan   mlir::Value integerCast(mlir::Location loc,
109dc48849fSKiran Chandramohan                           mlir::ConversionPatternRewriter &rewriter,
110dc48849fSKiran Chandramohan                           mlir::Type ty, mlir::Value val) const {
111dc48849fSKiran Chandramohan     auto valTy = val.getType();
112dc48849fSKiran Chandramohan     // If the value was not yet lowered, lower its type so that it can
113dc48849fSKiran Chandramohan     // be used in getPrimitiveTypeSizeInBits.
114dc48849fSKiran Chandramohan     if (!valTy.isa<mlir::IntegerType>())
115dc48849fSKiran Chandramohan       valTy = convertType(valTy);
116dc48849fSKiran Chandramohan     auto toSize = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
117dc48849fSKiran Chandramohan     auto fromSize = mlir::LLVM::getPrimitiveTypeSizeInBits(valTy);
118dc48849fSKiran Chandramohan     if (toSize < fromSize)
119dc48849fSKiran Chandramohan       return rewriter.create<mlir::LLVM::TruncOp>(loc, ty, val);
120dc48849fSKiran Chandramohan     if (toSize > fromSize)
121dc48849fSKiran Chandramohan       return rewriter.create<mlir::LLVM::SExtOp>(loc, ty, val);
122dc48849fSKiran Chandramohan     return val;
123dc48849fSKiran Chandramohan   }
124dc48849fSKiran Chandramohan 
125b6e44ecdSValentin Clement   /// Construct code sequence to extract the specifc value from a `fir.box`.
126b6e44ecdSValentin Clement   mlir::Value getValueFromBox(mlir::Location loc, mlir::Value box,
127df3b9810SValentin Clement                               mlir::Type resultTy,
128b6e44ecdSValentin Clement                               mlir::ConversionPatternRewriter &rewriter,
129b6e44ecdSValentin Clement                               unsigned boxValue) const {
130df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
131b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp cValuePos =
132b6e44ecdSValentin Clement         genConstantOffset(loc, rewriter, boxValue);
133df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(resultTy);
134df3b9810SValentin Clement     auto p = rewriter.create<mlir::LLVM::GEPOp>(
13530122656SAlex Zinenko         loc, pty, box, mlir::ValueRange{c0, cValuePos});
136df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, resultTy, p);
137df3b9810SValentin Clement   }
138df3b9810SValentin Clement 
139df3b9810SValentin Clement   /// Method to construct code sequence to get the triple for dimension `dim`
140df3b9810SValentin Clement   /// from a box.
14144e58509SEric Schweitz   llvm::SmallVector<mlir::Value, 3>
14244e58509SEric Schweitz   getDimsFromBox(mlir::Location loc, llvm::ArrayRef<mlir::Type> retTys,
143df3b9810SValentin Clement                  mlir::Value box, mlir::Value dim,
144df3b9810SValentin Clement                  mlir::ConversionPatternRewriter &rewriter) const {
145df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
146df3b9810SValentin Clement     mlir::LLVM::ConstantOp cDims =
147df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kDimsPosInBox);
148df3b9810SValentin Clement     mlir::LLVM::LoadOp l0 =
149df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 0, retTys[0], rewriter);
150df3b9810SValentin Clement     mlir::LLVM::LoadOp l1 =
151df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 1, retTys[1], rewriter);
152df3b9810SValentin Clement     mlir::LLVM::LoadOp l2 =
153df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 2, retTys[2], rewriter);
154df3b9810SValentin Clement     return {l0.getResult(), l1.getResult(), l2.getResult()};
155df3b9810SValentin Clement   }
156df3b9810SValentin Clement 
157df3b9810SValentin Clement   mlir::LLVM::LoadOp
158df3b9810SValentin Clement   loadFromOffset(mlir::Location loc, mlir::Value a, mlir::LLVM::ConstantOp c0,
159df3b9810SValentin Clement                  mlir::LLVM::ConstantOp cDims, mlir::Value dim, int off,
160df3b9810SValentin Clement                  mlir::Type ty,
161df3b9810SValentin Clement                  mlir::ConversionPatternRewriter &rewriter) const {
162df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
163df3b9810SValentin Clement     mlir::LLVM::ConstantOp c = genConstantOffset(loc, rewriter, off);
164df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, a, c0, cDims, dim, c);
165df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
166df3b9810SValentin Clement   }
167df3b9810SValentin Clement 
1685d27abe6SValentin Clement   mlir::Value
1695d27abe6SValentin Clement   loadStrideFromBox(mlir::Location loc, mlir::Value box, unsigned dim,
1705d27abe6SValentin Clement                     mlir::ConversionPatternRewriter &rewriter) const {
1715d27abe6SValentin Clement     auto idxTy = lowerTy().indexType();
1725d27abe6SValentin Clement     auto c0 = genConstantOffset(loc, rewriter, 0);
1735d27abe6SValentin Clement     auto cDims = genConstantOffset(loc, rewriter, kDimsPosInBox);
1745d27abe6SValentin Clement     auto dimValue = genConstantIndex(loc, idxTy, rewriter, dim);
1755d27abe6SValentin Clement     return loadFromOffset(loc, box, c0, cDims, dimValue, kDimStridePos, idxTy,
1765d27abe6SValentin Clement                           rewriter);
1775d27abe6SValentin Clement   }
1785d27abe6SValentin Clement 
179df3b9810SValentin Clement   /// Read base address from a fir.box. Returned address has type ty.
180df3b9810SValentin Clement   mlir::Value
181df3b9810SValentin Clement   loadBaseAddrFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box,
182df3b9810SValentin Clement                       mlir::ConversionPatternRewriter &rewriter) const {
183df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
184df3b9810SValentin Clement     mlir::LLVM::ConstantOp cAddr =
185df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kAddrPosInBox);
186df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
187df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cAddr);
188df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
189df3b9810SValentin Clement   }
190df3b9810SValentin Clement 
191df3b9810SValentin Clement   mlir::Value
192df3b9810SValentin Clement   loadElementSizeFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box,
193df3b9810SValentin Clement                          mlir::ConversionPatternRewriter &rewriter) const {
194df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
195df3b9810SValentin Clement     mlir::LLVM::ConstantOp cElemLen =
196df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kElemLenPosInBox);
197df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
198df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cElemLen);
199df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
200df3b9810SValentin Clement   }
201df3b9810SValentin Clement 
202af6ee580SValentin Clement   // Get the element type given an LLVM type that is of the form
203af6ee580SValentin Clement   // [llvm.ptr](array|struct|vector)+ and the provided indexes.
204af6ee580SValentin Clement   static mlir::Type getBoxEleTy(mlir::Type type,
205af6ee580SValentin Clement                                 llvm::ArrayRef<unsigned> indexes) {
206af6ee580SValentin Clement     if (auto t = type.dyn_cast<mlir::LLVM::LLVMPointerType>())
207af6ee580SValentin Clement       type = t.getElementType();
208af6ee580SValentin Clement     for (auto i : indexes) {
209af6ee580SValentin Clement       if (auto t = type.dyn_cast<mlir::LLVM::LLVMStructType>()) {
210af6ee580SValentin Clement         assert(!t.isOpaque() && i < t.getBody().size());
211af6ee580SValentin Clement         type = t.getBody()[i];
212af6ee580SValentin Clement       } else if (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
213af6ee580SValentin Clement         type = t.getElementType();
214af6ee580SValentin Clement       } else if (auto t = type.dyn_cast<mlir::VectorType>()) {
215af6ee580SValentin Clement         type = t.getElementType();
216af6ee580SValentin Clement       } else {
217af6ee580SValentin Clement         fir::emitFatalError(mlir::UnknownLoc::get(type.getContext()),
218af6ee580SValentin Clement                             "request for invalid box element type");
219af6ee580SValentin Clement       }
220af6ee580SValentin Clement     }
221af6ee580SValentin Clement     return type;
222af6ee580SValentin Clement   }
223af6ee580SValentin Clement 
2245d27abe6SValentin Clement   // Return LLVM type of the base address given the LLVM type
2255d27abe6SValentin Clement   // of the related descriptor (lowered fir.box type).
2265d27abe6SValentin Clement   static mlir::Type getBaseAddrTypeFromBox(mlir::Type type) {
2275d27abe6SValentin Clement     return getBoxEleTy(type, {kAddrPosInBox});
2285d27abe6SValentin Clement   }
2295d27abe6SValentin Clement 
230dc48849fSKiran Chandramohan   // Load the attribute from the \p box and perform a check against \p maskValue
231dc48849fSKiran Chandramohan   // The final comparison is implemented as `(attribute & maskValue) != 0`.
232dc48849fSKiran Chandramohan   mlir::Value genBoxAttributeCheck(mlir::Location loc, mlir::Value box,
233dc48849fSKiran Chandramohan                                    mlir::ConversionPatternRewriter &rewriter,
234dc48849fSKiran Chandramohan                                    unsigned maskValue) const {
235dc48849fSKiran Chandramohan     mlir::Type attrTy = rewriter.getI32Type();
236dc48849fSKiran Chandramohan     mlir::Value attribute =
237dc48849fSKiran Chandramohan         getValueFromBox(loc, box, attrTy, rewriter, kAttributePosInBox);
238dc48849fSKiran Chandramohan     mlir::LLVM::ConstantOp attrMask =
239dc48849fSKiran Chandramohan         genConstantOffset(loc, rewriter, maskValue);
240dc48849fSKiran Chandramohan     auto maskRes =
241dc48849fSKiran Chandramohan         rewriter.create<mlir::LLVM::AndOp>(loc, attrTy, attribute, attrMask);
242dc48849fSKiran Chandramohan     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
243dc48849fSKiran Chandramohan     return rewriter.create<mlir::LLVM::ICmpOp>(
244dc48849fSKiran Chandramohan         loc, mlir::LLVM::ICmpPredicate::ne, maskRes, c0);
245dc48849fSKiran Chandramohan   }
246dc48849fSKiran Chandramohan 
247df3b9810SValentin Clement   template <typename... ARGS>
248df3b9810SValentin Clement   mlir::LLVM::GEPOp genGEP(mlir::Location loc, mlir::Type ty,
249df3b9810SValentin Clement                            mlir::ConversionPatternRewriter &rewriter,
250df3b9810SValentin Clement                            mlir::Value base, ARGS... args) const {
251575c9d6dSValentin Clement     llvm::SmallVector<mlir::Value> cv = {args...};
252df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::GEPOp>(loc, ty, base, cv);
253df3b9810SValentin Clement   }
254df3b9810SValentin Clement 
255044d5b5dSValentin Clement   fir::LLVMTypeConverter &lowerTy() const {
256044d5b5dSValentin Clement     return *static_cast<fir::LLVMTypeConverter *>(this->getTypeConverter());
257044d5b5dSValentin Clement   }
258013160f6SJean Perier 
259013160f6SJean Perier   const fir::FIRToLLVMPassOptions &options;
260044d5b5dSValentin Clement };
261044d5b5dSValentin Clement 
2623ae8e442SValentin Clement /// FIR conversion pattern template
2633ae8e442SValentin Clement template <typename FromOp>
2643ae8e442SValentin Clement class FIROpAndTypeConversion : public FIROpConversion<FromOp> {
2653ae8e442SValentin Clement public:
2663ae8e442SValentin Clement   using FIROpConversion<FromOp>::FIROpConversion;
2673ae8e442SValentin Clement   using OpAdaptor = typename FromOp::Adaptor;
2683ae8e442SValentin Clement 
2693ae8e442SValentin Clement   mlir::LogicalResult
2703ae8e442SValentin Clement   matchAndRewrite(FromOp op, OpAdaptor adaptor,
2713ae8e442SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const final {
2723ae8e442SValentin Clement     mlir::Type ty = this->convertType(op.getType());
2733ae8e442SValentin Clement     return doRewrite(op, ty, adaptor, rewriter);
2743ae8e442SValentin Clement   }
2753ae8e442SValentin Clement 
2763ae8e442SValentin Clement   virtual mlir::LogicalResult
2773ae8e442SValentin Clement   doRewrite(FromOp addr, mlir::Type ty, OpAdaptor adaptor,
2783ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const = 0;
2793ae8e442SValentin Clement };
280575c9d6dSValentin Clement } // namespace
2813ae8e442SValentin Clement 
282575c9d6dSValentin Clement namespace {
283575c9d6dSValentin Clement /// Lower `fir.address_of` operation to `llvm.address_of` operation.
284044d5b5dSValentin Clement struct AddrOfOpConversion : public FIROpConversion<fir::AddrOfOp> {
285044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
286044d5b5dSValentin Clement 
287044d5b5dSValentin Clement   mlir::LogicalResult
288044d5b5dSValentin Clement   matchAndRewrite(fir::AddrOfOp addr, OpAdaptor adaptor,
289044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
290044d5b5dSValentin Clement     auto ty = convertType(addr.getType());
291044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::AddressOfOp>(
292149ad3d5SShraiysh Vaishay         addr, ty, addr.getSymbol().getRootReference().getValue());
29344e58509SEric Schweitz     return mlir::success();
294044d5b5dSValentin Clement   }
295044d5b5dSValentin Clement };
2961e6d9c06SDiana Picus } // namespace
2971e6d9c06SDiana Picus 
2981e6d9c06SDiana Picus /// Lookup the function to compute the memory size of this parametric derived
2991e6d9c06SDiana Picus /// type. The size of the object may depend on the LEN type parameters of the
3001e6d9c06SDiana Picus /// derived type.
3011e6d9c06SDiana Picus static mlir::LLVM::LLVMFuncOp
3021e6d9c06SDiana Picus getDependentTypeMemSizeFn(fir::RecordType recTy, fir::AllocaOp op,
3031e6d9c06SDiana Picus                           mlir::ConversionPatternRewriter &rewriter) {
3041e6d9c06SDiana Picus   auto module = op->getParentOfType<mlir::ModuleOp>();
3051e6d9c06SDiana Picus   std::string name = recTy.getName().str() + "P.mem.size";
306575c9d6dSValentin Clement   if (auto memSizeFunc = module.lookupSymbol<mlir::LLVM::LLVMFuncOp>(name))
307575c9d6dSValentin Clement     return memSizeFunc;
308575c9d6dSValentin Clement   TODO(op.getLoc(), "did not find allocation function");
3091e6d9c06SDiana Picus }
3101e6d9c06SDiana Picus 
311ac0f4c8fSPeixinQiao // Compute the alloc scale size (constant factors encoded in the array type).
312ac0f4c8fSPeixinQiao // We do this for arrays without a constant interior or arrays of character with
313ac0f4c8fSPeixinQiao // dynamic length arrays, since those are the only ones that get decayed to a
314ac0f4c8fSPeixinQiao // pointer to the element type.
315ac0f4c8fSPeixinQiao template <typename OP>
316ac0f4c8fSPeixinQiao static mlir::Value
317ac0f4c8fSPeixinQiao genAllocationScaleSize(OP op, mlir::Type ity,
318ac0f4c8fSPeixinQiao                        mlir::ConversionPatternRewriter &rewriter) {
319ac0f4c8fSPeixinQiao   mlir::Location loc = op.getLoc();
320ac0f4c8fSPeixinQiao   mlir::Type dataTy = op.getInType();
321ac0f4c8fSPeixinQiao   mlir::Type scalarType = fir::unwrapSequenceType(dataTy);
322ac0f4c8fSPeixinQiao   auto seqTy = dataTy.dyn_cast<fir::SequenceType>();
323ac0f4c8fSPeixinQiao   if ((op.hasShapeOperands() && seqTy && !seqTy.hasConstantInterior()) ||
324ac0f4c8fSPeixinQiao       (seqTy && fir::characterWithDynamicLen(scalarType))) {
325ac0f4c8fSPeixinQiao     fir::SequenceType::Extent constSize = 1;
326ac0f4c8fSPeixinQiao     for (auto extent : seqTy.getShape())
327ac0f4c8fSPeixinQiao       if (extent != fir::SequenceType::getUnknownExtent())
328ac0f4c8fSPeixinQiao         constSize *= extent;
329ac0f4c8fSPeixinQiao     if (constSize != 1) {
330ac0f4c8fSPeixinQiao       mlir::Value constVal{
331ac0f4c8fSPeixinQiao           genConstantIndex(loc, ity, rewriter, constSize).getResult()};
332ac0f4c8fSPeixinQiao       return constVal;
333ac0f4c8fSPeixinQiao     }
334ac0f4c8fSPeixinQiao   }
335ac0f4c8fSPeixinQiao   return nullptr;
336ac0f4c8fSPeixinQiao }
337ac0f4c8fSPeixinQiao 
3381e6d9c06SDiana Picus namespace {
3391e6d9c06SDiana Picus /// convert to LLVM IR dialect `alloca`
3401e6d9c06SDiana Picus struct AllocaOpConversion : public FIROpConversion<fir::AllocaOp> {
3411e6d9c06SDiana Picus   using FIROpConversion::FIROpConversion;
3421e6d9c06SDiana Picus 
3431e6d9c06SDiana Picus   mlir::LogicalResult
3441e6d9c06SDiana Picus   matchAndRewrite(fir::AllocaOp alloc, OpAdaptor adaptor,
3451e6d9c06SDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
3461e6d9c06SDiana Picus     mlir::ValueRange operands = adaptor.getOperands();
3471e6d9c06SDiana Picus     auto loc = alloc.getLoc();
3481e6d9c06SDiana Picus     mlir::Type ity = lowerTy().indexType();
3491e6d9c06SDiana Picus     unsigned i = 0;
3501e6d9c06SDiana Picus     mlir::Value size = genConstantIndex(loc, ity, rewriter, 1).getResult();
3511e6d9c06SDiana Picus     mlir::Type ty = convertType(alloc.getType());
3521e6d9c06SDiana Picus     mlir::Type resultTy = ty;
3531e6d9c06SDiana Picus     if (alloc.hasLenParams()) {
3541e6d9c06SDiana Picus       unsigned end = alloc.numLenParams();
3551e6d9c06SDiana Picus       llvm::SmallVector<mlir::Value> lenParams;
3561e6d9c06SDiana Picus       for (; i < end; ++i)
3571e6d9c06SDiana Picus         lenParams.push_back(operands[i]);
3581e6d9c06SDiana Picus       mlir::Type scalarType = fir::unwrapSequenceType(alloc.getInType());
3591e6d9c06SDiana Picus       if (auto chrTy = scalarType.dyn_cast<fir::CharacterType>()) {
3601e6d9c06SDiana Picus         fir::CharacterType rawCharTy = fir::CharacterType::getUnknownLen(
3611e6d9c06SDiana Picus             chrTy.getContext(), chrTy.getFKind());
3621e6d9c06SDiana Picus         ty = mlir::LLVM::LLVMPointerType::get(convertType(rawCharTy));
3631e6d9c06SDiana Picus         assert(end == 1);
3641e6d9c06SDiana Picus         size = integerCast(loc, rewriter, ity, lenParams[0]);
3651e6d9c06SDiana Picus       } else if (auto recTy = scalarType.dyn_cast<fir::RecordType>()) {
3661e6d9c06SDiana Picus         mlir::LLVM::LLVMFuncOp memSizeFn =
3671e6d9c06SDiana Picus             getDependentTypeMemSizeFn(recTy, alloc, rewriter);
3681e6d9c06SDiana Picus         if (!memSizeFn)
3691e6d9c06SDiana Picus           emitError(loc, "did not find allocation function");
3701e6d9c06SDiana Picus         mlir::NamedAttribute attr = rewriter.getNamedAttr(
3711e6d9c06SDiana Picus             "callee", mlir::SymbolRefAttr::get(memSizeFn));
3721e6d9c06SDiana Picus         auto call = rewriter.create<mlir::LLVM::CallOp>(
3731e6d9c06SDiana Picus             loc, ity, lenParams, llvm::ArrayRef<mlir::NamedAttribute>{attr});
3741e6d9c06SDiana Picus         size = call.getResult(0);
375575c9d6dSValentin Clement         ty = ::getVoidPtrType(alloc.getContext());
3761e6d9c06SDiana Picus       } else {
3771e6d9c06SDiana Picus         return emitError(loc, "unexpected type ")
3781e6d9c06SDiana Picus                << scalarType << " with type parameters";
3791e6d9c06SDiana Picus       }
3801e6d9c06SDiana Picus     }
381ac0f4c8fSPeixinQiao     if (auto scaleSize = genAllocationScaleSize(alloc, ity, rewriter))
382ac0f4c8fSPeixinQiao       size = rewriter.create<mlir::LLVM::MulOp>(loc, ity, size, scaleSize);
3831e6d9c06SDiana Picus     if (alloc.hasShapeOperands()) {
3841e6d9c06SDiana Picus       unsigned end = operands.size();
3851e6d9c06SDiana Picus       for (; i < end; ++i)
3861e6d9c06SDiana Picus         size = rewriter.create<mlir::LLVM::MulOp>(
3871e6d9c06SDiana Picus             loc, ity, size, integerCast(loc, rewriter, ity, operands[i]));
3881e6d9c06SDiana Picus     }
3891e6d9c06SDiana Picus     if (ty == resultTy) {
3901e6d9c06SDiana Picus       // Do not emit the bitcast if ty and resultTy are the same.
3911e6d9c06SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::AllocaOp>(alloc, ty, size,
3921e6d9c06SDiana Picus                                                         alloc->getAttrs());
3931e6d9c06SDiana Picus     } else {
3941e6d9c06SDiana Picus       auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, ty, size,
3951e6d9c06SDiana Picus                                                       alloc->getAttrs());
3961e6d9c06SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(alloc, resultTy, al);
3971e6d9c06SDiana Picus     }
39844e58509SEric Schweitz     return mlir::success();
3991e6d9c06SDiana Picus   }
4001e6d9c06SDiana Picus };
401dc48849fSKiran Chandramohan } // namespace
402044d5b5dSValentin Clement 
403dc48849fSKiran Chandramohan /// Construct an `llvm.extractvalue` instruction. It will return value at
404dc48849fSKiran Chandramohan /// element \p x from  \p tuple.
405dc48849fSKiran Chandramohan static mlir::LLVM::ExtractValueOp
406dc48849fSKiran Chandramohan genExtractValueWithIndex(mlir::Location loc, mlir::Value tuple, mlir::Type ty,
407dc48849fSKiran Chandramohan                          mlir::ConversionPatternRewriter &rewriter,
408dc48849fSKiran Chandramohan                          mlir::MLIRContext *ctx, int x) {
409dc48849fSKiran Chandramohan   auto cx = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(x));
410dc48849fSKiran Chandramohan   auto xty = ty.cast<mlir::LLVM::LLVMStructType>().getBody()[x];
411dc48849fSKiran Chandramohan   return rewriter.create<mlir::LLVM::ExtractValueOp>(loc, xty, tuple, cx);
412dc48849fSKiran Chandramohan }
413dc48849fSKiran Chandramohan 
414dc48849fSKiran Chandramohan namespace {
415df3b9810SValentin Clement /// Lower `fir.box_addr` to the sequence of operations to extract the first
416df3b9810SValentin Clement /// element of the box.
417df3b9810SValentin Clement struct BoxAddrOpConversion : public FIROpConversion<fir::BoxAddrOp> {
418df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
419df3b9810SValentin Clement 
420df3b9810SValentin Clement   mlir::LogicalResult
421df3b9810SValentin Clement   matchAndRewrite(fir::BoxAddrOp boxaddr, OpAdaptor adaptor,
422df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
423df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
424df3b9810SValentin Clement     auto loc = boxaddr.getLoc();
425df3b9810SValentin Clement     mlir::Type ty = convertType(boxaddr.getType());
426149ad3d5SShraiysh Vaishay     if (auto argty = boxaddr.getVal().getType().dyn_cast<fir::BoxType>()) {
427df3b9810SValentin Clement       rewriter.replaceOp(boxaddr, loadBaseAddrFromBox(loc, ty, a, rewriter));
428df3b9810SValentin Clement     } else {
429df3b9810SValentin Clement       auto c0attr = rewriter.getI32IntegerAttr(0);
430df3b9810SValentin Clement       auto c0 = mlir::ArrayAttr::get(boxaddr.getContext(), c0attr);
431df3b9810SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(boxaddr, ty, a,
432df3b9810SValentin Clement                                                               c0);
433df3b9810SValentin Clement     }
43444e58509SEric Schweitz     return mlir::success();
435df3b9810SValentin Clement   }
436df3b9810SValentin Clement };
437df3b9810SValentin Clement 
438dc48849fSKiran Chandramohan /// Convert `!fir.boxchar_len` to  `!llvm.extractvalue` for the 2nd part of the
439dc48849fSKiran Chandramohan /// boxchar.
440dc48849fSKiran Chandramohan struct BoxCharLenOpConversion : public FIROpConversion<fir::BoxCharLenOp> {
441dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
442dc48849fSKiran Chandramohan 
443dc48849fSKiran Chandramohan   mlir::LogicalResult
444dc48849fSKiran Chandramohan   matchAndRewrite(fir::BoxCharLenOp boxCharLen, OpAdaptor adaptor,
445dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
446dc48849fSKiran Chandramohan     mlir::Value boxChar = adaptor.getOperands()[0];
447dc48849fSKiran Chandramohan     mlir::Location loc = boxChar.getLoc();
448dc48849fSKiran Chandramohan     mlir::MLIRContext *ctx = boxChar.getContext();
449dc48849fSKiran Chandramohan     mlir::Type returnValTy = boxCharLen.getResult().getType();
450dc48849fSKiran Chandramohan 
451dc48849fSKiran Chandramohan     constexpr int boxcharLenIdx = 1;
452dc48849fSKiran Chandramohan     mlir::LLVM::ExtractValueOp len = genExtractValueWithIndex(
453dc48849fSKiran Chandramohan         loc, boxChar, boxChar.getType(), rewriter, ctx, boxcharLenIdx);
454dc48849fSKiran Chandramohan     mlir::Value lenAfterCast = integerCast(loc, rewriter, returnValTy, len);
455dc48849fSKiran Chandramohan     rewriter.replaceOp(boxCharLen, lenAfterCast);
456dc48849fSKiran Chandramohan 
45744e58509SEric Schweitz     return mlir::success();
458dc48849fSKiran Chandramohan   }
459dc48849fSKiran Chandramohan };
460dc48849fSKiran Chandramohan 
461df3b9810SValentin Clement /// Lower `fir.box_dims` to a sequence of operations to extract the requested
462df3b9810SValentin Clement /// dimension infomartion from the boxed value.
463df3b9810SValentin Clement /// Result in a triple set of GEPs and loads.
464df3b9810SValentin Clement struct BoxDimsOpConversion : public FIROpConversion<fir::BoxDimsOp> {
465df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
466df3b9810SValentin Clement 
467df3b9810SValentin Clement   mlir::LogicalResult
468df3b9810SValentin Clement   matchAndRewrite(fir::BoxDimsOp boxdims, OpAdaptor adaptor,
469df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
47044e58509SEric Schweitz     llvm::SmallVector<mlir::Type, 3> resultTypes = {
471df3b9810SValentin Clement         convertType(boxdims.getResult(0).getType()),
472df3b9810SValentin Clement         convertType(boxdims.getResult(1).getType()),
473df3b9810SValentin Clement         convertType(boxdims.getResult(2).getType()),
474df3b9810SValentin Clement     };
475df3b9810SValentin Clement     auto results =
476df3b9810SValentin Clement         getDimsFromBox(boxdims.getLoc(), resultTypes, adaptor.getOperands()[0],
477df3b9810SValentin Clement                        adaptor.getOperands()[1], rewriter);
478df3b9810SValentin Clement     rewriter.replaceOp(boxdims, results);
47944e58509SEric Schweitz     return mlir::success();
480df3b9810SValentin Clement   }
481df3b9810SValentin Clement };
482df3b9810SValentin Clement 
483df3b9810SValentin Clement /// Lower `fir.box_elesize` to a sequence of operations ro extract the size of
484df3b9810SValentin Clement /// an element in the boxed value.
485df3b9810SValentin Clement struct BoxEleSizeOpConversion : public FIROpConversion<fir::BoxEleSizeOp> {
486df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
487df3b9810SValentin Clement 
488df3b9810SValentin Clement   mlir::LogicalResult
489df3b9810SValentin Clement   matchAndRewrite(fir::BoxEleSizeOp boxelesz, OpAdaptor adaptor,
490df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
491df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
492df3b9810SValentin Clement     auto loc = boxelesz.getLoc();
493df3b9810SValentin Clement     auto ty = convertType(boxelesz.getType());
494b6e44ecdSValentin Clement     auto elemSize = getValueFromBox(loc, a, ty, rewriter, kElemLenPosInBox);
495b6e44ecdSValentin Clement     rewriter.replaceOp(boxelesz, elemSize);
49644e58509SEric Schweitz     return mlir::success();
497b6e44ecdSValentin Clement   }
498b6e44ecdSValentin Clement };
499b6e44ecdSValentin Clement 
500b6e44ecdSValentin Clement /// Lower `fir.box_isalloc` to a sequence of operations to determine if the
501b6e44ecdSValentin Clement /// boxed value was from an ALLOCATABLE entity.
502b6e44ecdSValentin Clement struct BoxIsAllocOpConversion : public FIROpConversion<fir::BoxIsAllocOp> {
503b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
504b6e44ecdSValentin Clement 
505b6e44ecdSValentin Clement   mlir::LogicalResult
506b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsAllocOp boxisalloc, OpAdaptor adaptor,
507b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
508b6e44ecdSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
509b6e44ecdSValentin Clement     auto loc = boxisalloc.getLoc();
510b6e44ecdSValentin Clement     mlir::Value check =
511b6e44ecdSValentin Clement         genBoxAttributeCheck(loc, box, rewriter, kAttrAllocatable);
512b6e44ecdSValentin Clement     rewriter.replaceOp(boxisalloc, check);
51344e58509SEric Schweitz     return mlir::success();
514b6e44ecdSValentin Clement   }
515b6e44ecdSValentin Clement };
516b6e44ecdSValentin Clement 
517b6e44ecdSValentin Clement /// Lower `fir.box_isarray` to a sequence of operations to determine if the
518b6e44ecdSValentin Clement /// boxed is an array.
519b6e44ecdSValentin Clement struct BoxIsArrayOpConversion : public FIROpConversion<fir::BoxIsArrayOp> {
520b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
521b6e44ecdSValentin Clement 
522b6e44ecdSValentin Clement   mlir::LogicalResult
523b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsArrayOp boxisarray, OpAdaptor adaptor,
524b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
525b6e44ecdSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
526b6e44ecdSValentin Clement     auto loc = boxisarray.getLoc();
527b6e44ecdSValentin Clement     auto rank =
528b6e44ecdSValentin Clement         getValueFromBox(loc, a, rewriter.getI32Type(), rewriter, kRankPosInBox);
529b6e44ecdSValentin Clement     auto c0 = genConstantOffset(loc, rewriter, 0);
530b6e44ecdSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
531b6e44ecdSValentin Clement         boxisarray, mlir::LLVM::ICmpPredicate::ne, rank, c0);
53244e58509SEric Schweitz     return mlir::success();
533b6e44ecdSValentin Clement   }
534b6e44ecdSValentin Clement };
535b6e44ecdSValentin Clement 
536b6e44ecdSValentin Clement /// Lower `fir.box_isptr` to a sequence of operations to determined if the
537b6e44ecdSValentin Clement /// boxed value was from a POINTER entity.
538b6e44ecdSValentin Clement struct BoxIsPtrOpConversion : public FIROpConversion<fir::BoxIsPtrOp> {
539b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
540b6e44ecdSValentin Clement 
541b6e44ecdSValentin Clement   mlir::LogicalResult
542b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsPtrOp boxisptr, OpAdaptor adaptor,
543b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
544b6e44ecdSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
545b6e44ecdSValentin Clement     auto loc = boxisptr.getLoc();
546b6e44ecdSValentin Clement     mlir::Value check = genBoxAttributeCheck(loc, box, rewriter, kAttrPointer);
547b6e44ecdSValentin Clement     rewriter.replaceOp(boxisptr, check);
54844e58509SEric Schweitz     return mlir::success();
549df3b9810SValentin Clement   }
550df3b9810SValentin Clement };
551df3b9810SValentin Clement 
552df3b9810SValentin Clement /// Lower `fir.box_rank` to the sequence of operation to extract the rank from
553df3b9810SValentin Clement /// the box.
554df3b9810SValentin Clement struct BoxRankOpConversion : public FIROpConversion<fir::BoxRankOp> {
555df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
556df3b9810SValentin Clement 
557df3b9810SValentin Clement   mlir::LogicalResult
558df3b9810SValentin Clement   matchAndRewrite(fir::BoxRankOp boxrank, OpAdaptor adaptor,
559df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
560df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
561df3b9810SValentin Clement     auto loc = boxrank.getLoc();
562df3b9810SValentin Clement     mlir::Type ty = convertType(boxrank.getType());
563b6e44ecdSValentin Clement     auto result = getValueFromBox(loc, a, ty, rewriter, kRankPosInBox);
564df3b9810SValentin Clement     rewriter.replaceOp(boxrank, result);
56544e58509SEric Schweitz     return mlir::success();
566df3b9810SValentin Clement   }
567df3b9810SValentin Clement };
568df3b9810SValentin Clement 
569cc505c0bSKiran Chandramohan /// Lower `fir.boxproc_host` operation. Extracts the host pointer from the
570cc505c0bSKiran Chandramohan /// boxproc.
571cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
572cc505c0bSKiran Chandramohan struct BoxProcHostOpConversion : public FIROpConversion<fir::BoxProcHostOp> {
573cc505c0bSKiran Chandramohan   using FIROpConversion::FIROpConversion;
574cc505c0bSKiran Chandramohan 
575cc505c0bSKiran Chandramohan   mlir::LogicalResult
576cc505c0bSKiran Chandramohan   matchAndRewrite(fir::BoxProcHostOp boxprochost, OpAdaptor adaptor,
577cc505c0bSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
5787ce8c6fcSKiran Chandramohan     TODO(boxprochost.getLoc(), "fir.boxproc_host codegen");
57944e58509SEric Schweitz     return mlir::failure();
580cc505c0bSKiran Chandramohan   }
581cc505c0bSKiran Chandramohan };
582cc505c0bSKiran Chandramohan 
583e38ef2ffSValentin Clement /// Lower `fir.box_tdesc` to the sequence of operations to extract the type
584e38ef2ffSValentin Clement /// descriptor from the box.
585e38ef2ffSValentin Clement struct BoxTypeDescOpConversion : public FIROpConversion<fir::BoxTypeDescOp> {
586e38ef2ffSValentin Clement   using FIROpConversion::FIROpConversion;
587e38ef2ffSValentin Clement 
588e38ef2ffSValentin Clement   mlir::LogicalResult
589e38ef2ffSValentin Clement   matchAndRewrite(fir::BoxTypeDescOp boxtypedesc, OpAdaptor adaptor,
590e38ef2ffSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
591e38ef2ffSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
592e38ef2ffSValentin Clement     auto loc = boxtypedesc.getLoc();
593e38ef2ffSValentin Clement     mlir::Type typeTy =
594e38ef2ffSValentin Clement         fir::getDescFieldTypeModel<kTypePosInBox>()(boxtypedesc.getContext());
595e38ef2ffSValentin Clement     auto result = getValueFromBox(loc, box, typeTy, rewriter, kTypePosInBox);
596e38ef2ffSValentin Clement     auto typePtrTy = mlir::LLVM::LLVMPointerType::get(typeTy);
597e38ef2ffSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(boxtypedesc, typePtrTy,
598e38ef2ffSValentin Clement                                                         result);
59944e58509SEric Schweitz     return mlir::success();
600e38ef2ffSValentin Clement   }
601e38ef2ffSValentin Clement };
602e38ef2ffSValentin Clement 
603dc48849fSKiran Chandramohan /// Lower `fir.string_lit` to LLVM IR dialect operation.
604dc48849fSKiran Chandramohan struct StringLitOpConversion : public FIROpConversion<fir::StringLitOp> {
605dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
606dc48849fSKiran Chandramohan 
607dc48849fSKiran Chandramohan   mlir::LogicalResult
608dc48849fSKiran Chandramohan   matchAndRewrite(fir::StringLitOp constop, OpAdaptor adaptor,
609dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
610dc48849fSKiran Chandramohan     auto ty = convertType(constop.getType());
611dc48849fSKiran Chandramohan     auto attr = constop.getValue();
612dc48849fSKiran Chandramohan     if (attr.isa<mlir::StringAttr>()) {
613dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(constop, ty, attr);
61444e58509SEric Schweitz       return mlir::success();
615dc48849fSKiran Chandramohan     }
616dc48849fSKiran Chandramohan 
617dc48849fSKiran Chandramohan     auto charTy = constop.getType().cast<fir::CharacterType>();
618dc48849fSKiran Chandramohan     unsigned bits = lowerTy().characterBitsize(charTy);
619dc48849fSKiran Chandramohan     mlir::Type intTy = rewriter.getIntegerType(bits);
620e0c782bdSValentin Clement     mlir::Location loc = constop.getLoc();
621e0c782bdSValentin Clement     mlir::Value cst = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
622e0c782bdSValentin Clement     if (auto arr = attr.dyn_cast<mlir::DenseElementsAttr>()) {
623e0c782bdSValentin Clement       cst = rewriter.create<mlir::LLVM::ConstantOp>(loc, ty, arr);
624e0c782bdSValentin Clement     } else if (auto arr = attr.dyn_cast<mlir::ArrayAttr>()) {
625e0c782bdSValentin Clement       for (auto a : llvm::enumerate(arr.getValue())) {
626e0c782bdSValentin Clement         // convert each character to a precise bitsize
627e0c782bdSValentin Clement         auto elemAttr = mlir::IntegerAttr::get(
628dc48849fSKiran Chandramohan             intTy,
629e0c782bdSValentin Clement             a.value().cast<mlir::IntegerAttr>().getValue().zextOrTrunc(bits));
630e0c782bdSValentin Clement         auto elemCst =
631e0c782bdSValentin Clement             rewriter.create<mlir::LLVM::ConstantOp>(loc, intTy, elemAttr);
632e0c782bdSValentin Clement         auto index = mlir::ArrayAttr::get(
633e0c782bdSValentin Clement             constop.getContext(), rewriter.getI32IntegerAttr(a.index()));
634e0c782bdSValentin Clement         cst = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, cst, elemCst,
635e0c782bdSValentin Clement                                                          index);
636e0c782bdSValentin Clement       }
637e0c782bdSValentin Clement     } else {
63844e58509SEric Schweitz       return mlir::failure();
639e0c782bdSValentin Clement     }
640e0c782bdSValentin Clement     rewriter.replaceOp(constop, cst);
64144e58509SEric Schweitz     return mlir::success();
642dc48849fSKiran Chandramohan   }
643dc48849fSKiran Chandramohan };
644dc48849fSKiran Chandramohan 
645575c9d6dSValentin Clement /// `fir.call` -> `llvm.call`
646ddd11b9aSAndrzej Warzynski struct CallOpConversion : public FIROpConversion<fir::CallOp> {
647ddd11b9aSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
648ddd11b9aSAndrzej Warzynski 
649ddd11b9aSAndrzej Warzynski   mlir::LogicalResult
650ddd11b9aSAndrzej Warzynski   matchAndRewrite(fir::CallOp call, OpAdaptor adaptor,
651ddd11b9aSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
65244e58509SEric Schweitz     llvm::SmallVector<mlir::Type> resultTys;
653ddd11b9aSAndrzej Warzynski     for (auto r : call.getResults())
654ddd11b9aSAndrzej Warzynski       resultTys.push_back(convertType(r.getType()));
655ddd11b9aSAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
656ddd11b9aSAndrzej Warzynski         call, resultTys, adaptor.getOperands(), call->getAttrs());
65744e58509SEric Schweitz     return mlir::success();
658ddd11b9aSAndrzej Warzynski   }
659ddd11b9aSAndrzej Warzynski };
660c2acd453SAlexisPerry } // namespace
661ddd11b9aSAndrzej Warzynski 
662092cee5fSValentin Clement static mlir::Type getComplexEleTy(mlir::Type complex) {
663092cee5fSValentin Clement   if (auto cc = complex.dyn_cast<mlir::ComplexType>())
664092cee5fSValentin Clement     return cc.getElementType();
665092cee5fSValentin Clement   return complex.cast<fir::ComplexType>().getElementType();
666092cee5fSValentin Clement }
667092cee5fSValentin Clement 
668c2acd453SAlexisPerry namespace {
669f1dfc027SDiana Picus /// Compare complex values
670f1dfc027SDiana Picus ///
671f1dfc027SDiana Picus /// Per 10.1, the only comparisons available are .EQ. (oeq) and .NE. (une).
672f1dfc027SDiana Picus ///
673f1dfc027SDiana Picus /// For completeness, all other comparison are done on the real component only.
674f1dfc027SDiana Picus struct CmpcOpConversion : public FIROpConversion<fir::CmpcOp> {
675f1dfc027SDiana Picus   using FIROpConversion::FIROpConversion;
676f1dfc027SDiana Picus 
677f1dfc027SDiana Picus   mlir::LogicalResult
678f1dfc027SDiana Picus   matchAndRewrite(fir::CmpcOp cmp, OpAdaptor adaptor,
679f1dfc027SDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
680f1dfc027SDiana Picus     mlir::ValueRange operands = adaptor.getOperands();
681f1dfc027SDiana Picus     mlir::MLIRContext *ctxt = cmp.getContext();
682149ad3d5SShraiysh Vaishay     mlir::Type eleTy = convertType(getComplexEleTy(cmp.getLhs().getType()));
683f1dfc027SDiana Picus     mlir::Type resTy = convertType(cmp.getType());
684f1dfc027SDiana Picus     mlir::Location loc = cmp.getLoc();
685f1dfc027SDiana Picus     auto pos0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0));
686575c9d6dSValentin Clement     llvm::SmallVector<mlir::Value, 2> rp = {
68744e58509SEric Schweitz         rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, operands[0],
68844e58509SEric Schweitz                                                     pos0),
68944e58509SEric Schweitz         rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, operands[1],
69044e58509SEric Schweitz                                                     pos0)};
691f1dfc027SDiana Picus     auto rcp =
692f1dfc027SDiana Picus         rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, rp, cmp->getAttrs());
693f1dfc027SDiana Picus     auto pos1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1));
694575c9d6dSValentin Clement     llvm::SmallVector<mlir::Value, 2> ip = {
69544e58509SEric Schweitz         rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, operands[0],
69644e58509SEric Schweitz                                                     pos1),
69744e58509SEric Schweitz         rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, operands[1],
69844e58509SEric Schweitz                                                     pos1)};
699f1dfc027SDiana Picus     auto icp =
700f1dfc027SDiana Picus         rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, ip, cmp->getAttrs());
701575c9d6dSValentin Clement     llvm::SmallVector<mlir::Value, 2> cp = {rcp, icp};
702f1dfc027SDiana Picus     switch (cmp.getPredicate()) {
703f1dfc027SDiana Picus     case mlir::arith::CmpFPredicate::OEQ: // .EQ.
704f1dfc027SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(cmp, resTy, cp);
705f1dfc027SDiana Picus       break;
706f1dfc027SDiana Picus     case mlir::arith::CmpFPredicate::UNE: // .NE.
707f1dfc027SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(cmp, resTy, cp);
708f1dfc027SDiana Picus       break;
709f1dfc027SDiana Picus     default:
710f1dfc027SDiana Picus       rewriter.replaceOp(cmp, rcp.getResult());
711f1dfc027SDiana Picus       break;
712f1dfc027SDiana Picus     }
71344e58509SEric Schweitz     return mlir::success();
714f1dfc027SDiana Picus   }
715f1dfc027SDiana Picus };
716f1dfc027SDiana Picus 
717e81d73edSDiana Picus /// Lower complex constants
718e81d73edSDiana Picus struct ConstcOpConversion : public FIROpConversion<fir::ConstcOp> {
719e81d73edSDiana Picus   using FIROpConversion::FIROpConversion;
720e81d73edSDiana Picus 
721e81d73edSDiana Picus   mlir::LogicalResult
722e81d73edSDiana Picus   matchAndRewrite(fir::ConstcOp conc, OpAdaptor,
723e81d73edSDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
724e81d73edSDiana Picus     mlir::Location loc = conc.getLoc();
725e81d73edSDiana Picus     mlir::MLIRContext *ctx = conc.getContext();
726e81d73edSDiana Picus     mlir::Type ty = convertType(conc.getType());
727e81d73edSDiana Picus     mlir::Type ety = convertType(getComplexEleTy(conc.getType()));
728e81d73edSDiana Picus     auto realFloatAttr = mlir::FloatAttr::get(ety, getValue(conc.getReal()));
729e81d73edSDiana Picus     auto realPart =
730e81d73edSDiana Picus         rewriter.create<mlir::LLVM::ConstantOp>(loc, ety, realFloatAttr);
731e81d73edSDiana Picus     auto imFloatAttr = mlir::FloatAttr::get(ety, getValue(conc.getImaginary()));
732e81d73edSDiana Picus     auto imPart =
733e81d73edSDiana Picus         rewriter.create<mlir::LLVM::ConstantOp>(loc, ety, imFloatAttr);
734e81d73edSDiana Picus     auto realIndex = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
735e81d73edSDiana Picus     auto imIndex = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
736e81d73edSDiana Picus     auto undef = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
737e81d73edSDiana Picus     auto setReal = rewriter.create<mlir::LLVM::InsertValueOp>(
738e81d73edSDiana Picus         loc, ty, undef, realPart, realIndex);
739e81d73edSDiana Picus     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(conc, ty, setReal,
740e81d73edSDiana Picus                                                            imPart, imIndex);
74144e58509SEric Schweitz     return mlir::success();
742e81d73edSDiana Picus   }
743e81d73edSDiana Picus 
74444e58509SEric Schweitz   inline llvm::APFloat getValue(mlir::Attribute attr) const {
745e81d73edSDiana Picus     return attr.cast<fir::RealAttr>().getValue();
746e81d73edSDiana Picus   }
747e81d73edSDiana Picus };
748e81d73edSDiana Picus 
749092cee5fSValentin Clement /// convert value of from-type to value of to-type
750092cee5fSValentin Clement struct ConvertOpConversion : public FIROpConversion<fir::ConvertOp> {
751092cee5fSValentin Clement   using FIROpConversion::FIROpConversion;
752092cee5fSValentin Clement 
753092cee5fSValentin Clement   static bool isFloatingPointTy(mlir::Type ty) {
754092cee5fSValentin Clement     return ty.isa<mlir::FloatType>();
755092cee5fSValentin Clement   }
756092cee5fSValentin Clement 
757092cee5fSValentin Clement   mlir::LogicalResult
758092cee5fSValentin Clement   matchAndRewrite(fir::ConvertOp convert, OpAdaptor adaptor,
759092cee5fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
7603b7ec85aSJean Perier     auto fromFirTy = convert.getValue().getType();
7613b7ec85aSJean Perier     auto toFirTy = convert.getRes().getType();
7623b7ec85aSJean Perier     auto fromTy = convertType(fromFirTy);
7633b7ec85aSJean Perier     auto toTy = convertType(toFirTy);
764092cee5fSValentin Clement     mlir::Value op0 = adaptor.getOperands()[0];
765092cee5fSValentin Clement     if (fromTy == toTy) {
766092cee5fSValentin Clement       rewriter.replaceOp(convert, op0);
76744e58509SEric Schweitz       return mlir::success();
768092cee5fSValentin Clement     }
769092cee5fSValentin Clement     auto loc = convert.getLoc();
770092cee5fSValentin Clement     auto convertFpToFp = [&](mlir::Value val, unsigned fromBits,
771092cee5fSValentin Clement                              unsigned toBits, mlir::Type toTy) -> mlir::Value {
772092cee5fSValentin Clement       if (fromBits == toBits) {
773092cee5fSValentin Clement         // TODO: Converting between two floating-point representations with the
774092cee5fSValentin Clement         // same bitwidth is not allowed for now.
775092cee5fSValentin Clement         mlir::emitError(loc,
776092cee5fSValentin Clement                         "cannot implicitly convert between two floating-point "
777092cee5fSValentin Clement                         "representations of the same bitwidth");
778092cee5fSValentin Clement         return {};
779092cee5fSValentin Clement       }
780092cee5fSValentin Clement       if (fromBits > toBits)
781092cee5fSValentin Clement         return rewriter.create<mlir::LLVM::FPTruncOp>(loc, toTy, val);
782092cee5fSValentin Clement       return rewriter.create<mlir::LLVM::FPExtOp>(loc, toTy, val);
783092cee5fSValentin Clement     };
784092cee5fSValentin Clement     // Complex to complex conversion.
7853b7ec85aSJean Perier     if (fir::isa_complex(fromFirTy) && fir::isa_complex(toFirTy)) {
786092cee5fSValentin Clement       // Special case: handle the conversion of a complex such that both the
787092cee5fSValentin Clement       // real and imaginary parts are converted together.
788092cee5fSValentin Clement       auto zero = mlir::ArrayAttr::get(convert.getContext(),
789092cee5fSValentin Clement                                        rewriter.getI32IntegerAttr(0));
790092cee5fSValentin Clement       auto one = mlir::ArrayAttr::get(convert.getContext(),
791092cee5fSValentin Clement                                       rewriter.getI32IntegerAttr(1));
792149ad3d5SShraiysh Vaishay       auto ty = convertType(getComplexEleTy(convert.getValue().getType()));
793092cee5fSValentin Clement       auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, zero);
794092cee5fSValentin Clement       auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, one);
795149ad3d5SShraiysh Vaishay       auto nt = convertType(getComplexEleTy(convert.getRes().getType()));
796092cee5fSValentin Clement       auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
797092cee5fSValentin Clement       auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(nt);
798092cee5fSValentin Clement       auto rc = convertFpToFp(rp, fromBits, toBits, nt);
799092cee5fSValentin Clement       auto ic = convertFpToFp(ip, fromBits, toBits, nt);
800092cee5fSValentin Clement       auto un = rewriter.create<mlir::LLVM::UndefOp>(loc, toTy);
801092cee5fSValentin Clement       auto i1 =
802092cee5fSValentin Clement           rewriter.create<mlir::LLVM::InsertValueOp>(loc, toTy, un, rc, zero);
803092cee5fSValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(convert, toTy, i1,
804092cee5fSValentin Clement                                                              ic, one);
805092cee5fSValentin Clement       return mlir::success();
806092cee5fSValentin Clement     }
8073b7ec85aSJean Perier 
8083b7ec85aSJean Perier     // Follow UNIX F77 convention for logicals:
8093b7ec85aSJean Perier     // 1. underlying integer is not zero => logical is .TRUE.
8103b7ec85aSJean Perier     // 2. logical is .TRUE. => set underlying integer to 1.
8113b7ec85aSJean Perier     auto i1Type = mlir::IntegerType::get(convert.getContext(), 1);
8123b7ec85aSJean Perier     if (fromFirTy.isa<fir::LogicalType>() && toFirTy == i1Type) {
8133b7ec85aSJean Perier       mlir::Value zero = genConstantIndex(loc, fromTy, rewriter, 0);
8143b7ec85aSJean Perier       rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
8153b7ec85aSJean Perier           convert, mlir::LLVM::ICmpPredicate::ne, op0, zero);
8163b7ec85aSJean Perier       return mlir::success();
8173b7ec85aSJean Perier     }
8183b7ec85aSJean Perier     if (fromFirTy == i1Type && toFirTy.isa<fir::LogicalType>()) {
8193b7ec85aSJean Perier       rewriter.replaceOpWithNewOp<mlir::LLVM::ZExtOp>(convert, toTy, op0);
8203b7ec85aSJean Perier       return mlir::success();
8213b7ec85aSJean Perier     }
8223b7ec85aSJean Perier 
823092cee5fSValentin Clement     // Floating point to floating point conversion.
824092cee5fSValentin Clement     if (isFloatingPointTy(fromTy)) {
825092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
826092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
827092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
828092cee5fSValentin Clement         auto v = convertFpToFp(op0, fromBits, toBits, toTy);
829092cee5fSValentin Clement         rewriter.replaceOp(convert, v);
830092cee5fSValentin Clement         return mlir::success();
831092cee5fSValentin Clement       }
832092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
833092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::FPToSIOp>(convert, toTy, op0);
834092cee5fSValentin Clement         return mlir::success();
835092cee5fSValentin Clement       }
836092cee5fSValentin Clement     } else if (fromTy.isa<mlir::IntegerType>()) {
837092cee5fSValentin Clement       // Integer to integer conversion.
838092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
839092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
840092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
841092cee5fSValentin Clement         assert(fromBits != toBits);
842092cee5fSValentin Clement         if (fromBits > toBits) {
843092cee5fSValentin Clement           rewriter.replaceOpWithNewOp<mlir::LLVM::TruncOp>(convert, toTy, op0);
844092cee5fSValentin Clement           return mlir::success();
845092cee5fSValentin Clement         }
846092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SExtOp>(convert, toTy, op0);
847092cee5fSValentin Clement         return mlir::success();
848092cee5fSValentin Clement       }
849092cee5fSValentin Clement       // Integer to floating point conversion.
850092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
851092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SIToFPOp>(convert, toTy, op0);
852092cee5fSValentin Clement         return mlir::success();
853092cee5fSValentin Clement       }
854092cee5fSValentin Clement       // Integer to pointer conversion.
855092cee5fSValentin Clement       if (toTy.isa<mlir::LLVM::LLVMPointerType>()) {
856092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(convert, toTy, op0);
857092cee5fSValentin Clement         return mlir::success();
858092cee5fSValentin Clement       }
859092cee5fSValentin Clement     } else if (fromTy.isa<mlir::LLVM::LLVMPointerType>()) {
860092cee5fSValentin Clement       // Pointer to integer conversion.
861092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
862092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::PtrToIntOp>(convert, toTy, op0);
863092cee5fSValentin Clement         return mlir::success();
864092cee5fSValentin Clement       }
865092cee5fSValentin Clement       // Pointer to pointer conversion.
866092cee5fSValentin Clement       if (toTy.isa<mlir::LLVM::LLVMPointerType>()) {
867092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(convert, toTy, op0);
868092cee5fSValentin Clement         return mlir::success();
869092cee5fSValentin Clement       }
870092cee5fSValentin Clement     }
871092cee5fSValentin Clement     return emitError(loc) << "cannot convert " << fromTy << " to " << toTy;
872092cee5fSValentin Clement   }
873092cee5fSValentin Clement };
874092cee5fSValentin Clement 
8759534e361SValentin Clement /// Lower `fir.dispatch` operation. A virtual call to a method in a dispatch
8769534e361SValentin Clement /// table.
8779534e361SValentin Clement struct DispatchOpConversion : public FIROpConversion<fir::DispatchOp> {
8789534e361SValentin Clement   using FIROpConversion::FIROpConversion;
8799534e361SValentin Clement 
8809534e361SValentin Clement   mlir::LogicalResult
8819534e361SValentin Clement   matchAndRewrite(fir::DispatchOp dispatch, OpAdaptor adaptor,
8829534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8837ce8c6fcSKiran Chandramohan     TODO(dispatch.getLoc(), "fir.dispatch codegen");
88444e58509SEric Schweitz     return mlir::failure();
8859534e361SValentin Clement   }
8869534e361SValentin Clement };
8879534e361SValentin Clement 
8889534e361SValentin Clement /// Lower `fir.dispatch_table` operation. The dispatch table for a Fortran
8899534e361SValentin Clement /// derived type.
8909534e361SValentin Clement struct DispatchTableOpConversion
8919534e361SValentin Clement     : public FIROpConversion<fir::DispatchTableOp> {
8929534e361SValentin Clement   using FIROpConversion::FIROpConversion;
8939534e361SValentin Clement 
8949534e361SValentin Clement   mlir::LogicalResult
8959534e361SValentin Clement   matchAndRewrite(fir::DispatchTableOp dispTab, OpAdaptor adaptor,
8969534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8977ce8c6fcSKiran Chandramohan     TODO(dispTab.getLoc(), "fir.dispatch_table codegen");
89844e58509SEric Schweitz     return mlir::failure();
8999534e361SValentin Clement   }
9009534e361SValentin Clement };
9019534e361SValentin Clement 
9029534e361SValentin Clement /// Lower `fir.dt_entry` operation. An entry in a dispatch table; binds a
9039534e361SValentin Clement /// method-name to a function.
9049534e361SValentin Clement struct DTEntryOpConversion : public FIROpConversion<fir::DTEntryOp> {
9059534e361SValentin Clement   using FIROpConversion::FIROpConversion;
9069534e361SValentin Clement 
9079534e361SValentin Clement   mlir::LogicalResult
9089534e361SValentin Clement   matchAndRewrite(fir::DTEntryOp dtEnt, OpAdaptor adaptor,
9099534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
9107ce8c6fcSKiran Chandramohan     TODO(dtEnt.getLoc(), "fir.dt_entry codegen");
91144e58509SEric Schweitz     return mlir::failure();
9129534e361SValentin Clement   }
9139534e361SValentin Clement };
9149534e361SValentin Clement 
915677df8c7SValentin Clement /// Lower `fir.global_len` operation.
916677df8c7SValentin Clement struct GlobalLenOpConversion : public FIROpConversion<fir::GlobalLenOp> {
917677df8c7SValentin Clement   using FIROpConversion::FIROpConversion;
918677df8c7SValentin Clement 
919677df8c7SValentin Clement   mlir::LogicalResult
920677df8c7SValentin Clement   matchAndRewrite(fir::GlobalLenOp globalLen, OpAdaptor adaptor,
921677df8c7SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
9227ce8c6fcSKiran Chandramohan     TODO(globalLen.getLoc(), "fir.global_len codegen");
92344e58509SEric Schweitz     return mlir::failure();
924677df8c7SValentin Clement   }
925677df8c7SValentin Clement };
926677df8c7SValentin Clement 
927cdc476abSDiana Picus /// Lower fir.len_param_index
928cdc476abSDiana Picus struct LenParamIndexOpConversion
929cdc476abSDiana Picus     : public FIROpConversion<fir::LenParamIndexOp> {
930cdc476abSDiana Picus   using FIROpConversion::FIROpConversion;
931cdc476abSDiana Picus 
932cdc476abSDiana Picus   // FIXME: this should be specialized by the runtime target
933cdc476abSDiana Picus   mlir::LogicalResult
934cdc476abSDiana Picus   matchAndRewrite(fir::LenParamIndexOp lenp, OpAdaptor,
935cdc476abSDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
9367ce8c6fcSKiran Chandramohan     TODO(lenp.getLoc(), "fir.len_param_index codegen");
937cdc476abSDiana Picus   }
938cdc476abSDiana Picus };
939cdc476abSDiana Picus 
940dc48849fSKiran Chandramohan /// Convert `!fir.emboxchar<!fir.char<KIND, ?>, #n>` into a sequence of
941dc48849fSKiran Chandramohan /// instructions that generate `!llvm.struct<(ptr<ik>, i64)>`. The 1st element
942dc48849fSKiran Chandramohan /// in this struct is a pointer. Its type is determined from `KIND`. The 2nd
943dc48849fSKiran Chandramohan /// element is the length of the character buffer (`#n`).
944dc48849fSKiran Chandramohan struct EmboxCharOpConversion : public FIROpConversion<fir::EmboxCharOp> {
94531246187SValentin Clement   using FIROpConversion::FIROpConversion;
94631246187SValentin Clement 
94731246187SValentin Clement   mlir::LogicalResult
948dc48849fSKiran Chandramohan   matchAndRewrite(fir::EmboxCharOp emboxChar, OpAdaptor adaptor,
94931246187SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
950dc48849fSKiran Chandramohan     mlir::ValueRange operands = adaptor.getOperands();
95144e58509SEric Schweitz     auto *ctx = emboxChar.getContext();
952dc48849fSKiran Chandramohan 
953dc48849fSKiran Chandramohan     mlir::Value charBuffer = operands[0];
954dc48849fSKiran Chandramohan     mlir::Value charBufferLen = operands[1];
955dc48849fSKiran Chandramohan 
956dc48849fSKiran Chandramohan     mlir::Location loc = emboxChar.getLoc();
957dc48849fSKiran Chandramohan     mlir::Type llvmStructTy = convertType(emboxChar.getType());
958dc48849fSKiran Chandramohan     auto llvmStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, llvmStructTy);
959dc48849fSKiran Chandramohan 
960dc48849fSKiran Chandramohan     mlir::Type lenTy =
961dc48849fSKiran Chandramohan         llvmStructTy.cast<mlir::LLVM::LLVMStructType>().getBody()[1];
962dc48849fSKiran Chandramohan     mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, charBufferLen);
963dc48849fSKiran Chandramohan 
964dc48849fSKiran Chandramohan     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
965dc48849fSKiran Chandramohan     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
966dc48849fSKiran Chandramohan     auto insertBufferOp = rewriter.create<mlir::LLVM::InsertValueOp>(
967dc48849fSKiran Chandramohan         loc, llvmStructTy, llvmStruct, charBuffer, c0);
968dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
969dc48849fSKiran Chandramohan         emboxChar, llvmStructTy, insertBufferOp, lenAfterCast, c1);
970dc48849fSKiran Chandramohan 
97144e58509SEric Schweitz     return mlir::success();
97231246187SValentin Clement   }
97331246187SValentin Clement };
974c2acd453SAlexisPerry } // namespace
975c2acd453SAlexisPerry 
976c2acd453SAlexisPerry /// Return the LLVMFuncOp corresponding to the standard malloc call.
977c2acd453SAlexisPerry static mlir::LLVM::LLVMFuncOp
978c2acd453SAlexisPerry getMalloc(fir::AllocMemOp op, mlir::ConversionPatternRewriter &rewriter) {
979c2acd453SAlexisPerry   auto module = op->getParentOfType<mlir::ModuleOp>();
980c2acd453SAlexisPerry   if (mlir::LLVM::LLVMFuncOp mallocFunc =
981c2acd453SAlexisPerry           module.lookupSymbol<mlir::LLVM::LLVMFuncOp>("malloc"))
982c2acd453SAlexisPerry     return mallocFunc;
983c2acd453SAlexisPerry   mlir::OpBuilder moduleBuilder(
984c2acd453SAlexisPerry       op->getParentOfType<mlir::ModuleOp>().getBodyRegion());
985c2acd453SAlexisPerry   auto indexType = mlir::IntegerType::get(op.getContext(), 64);
986c2acd453SAlexisPerry   return moduleBuilder.create<mlir::LLVM::LLVMFuncOp>(
987c2acd453SAlexisPerry       rewriter.getUnknownLoc(), "malloc",
988c2acd453SAlexisPerry       mlir::LLVM::LLVMFunctionType::get(getVoidPtrType(op.getContext()),
989c2acd453SAlexisPerry                                         indexType,
990c2acd453SAlexisPerry                                         /*isVarArg=*/false));
991c2acd453SAlexisPerry }
992c2acd453SAlexisPerry 
993c2acd453SAlexisPerry /// Helper function for generating the LLVM IR that computes the size
994c2acd453SAlexisPerry /// in bytes for a derived type.
995c2acd453SAlexisPerry static mlir::Value
996c2acd453SAlexisPerry computeDerivedTypeSize(mlir::Location loc, mlir::Type ptrTy, mlir::Type idxTy,
997c2acd453SAlexisPerry                        mlir::ConversionPatternRewriter &rewriter) {
998c2acd453SAlexisPerry   auto nullPtr = rewriter.create<mlir::LLVM::NullOp>(loc, ptrTy);
999c2acd453SAlexisPerry   mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1);
1000575c9d6dSValentin Clement   llvm::SmallVector<mlir::Value> args = {one};
100130122656SAlex Zinenko   auto gep = rewriter.create<mlir::LLVM::GEPOp>(loc, ptrTy, nullPtr, args);
1002c2acd453SAlexisPerry   return rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, gep);
1003c2acd453SAlexisPerry }
1004c2acd453SAlexisPerry 
1005c2acd453SAlexisPerry namespace {
1006c2acd453SAlexisPerry /// Lower a `fir.allocmem` instruction into `llvm.call @malloc`
1007c2acd453SAlexisPerry struct AllocMemOpConversion : public FIROpConversion<fir::AllocMemOp> {
1008c2acd453SAlexisPerry   using FIROpConversion::FIROpConversion;
1009c2acd453SAlexisPerry 
1010c2acd453SAlexisPerry   mlir::LogicalResult
1011c2acd453SAlexisPerry   matchAndRewrite(fir::AllocMemOp heap, OpAdaptor adaptor,
1012c2acd453SAlexisPerry                   mlir::ConversionPatternRewriter &rewriter) const override {
1013575c9d6dSValentin Clement     mlir::Type heapTy = heap.getType();
1014575c9d6dSValentin Clement     mlir::Type ty = convertType(heapTy);
1015c2acd453SAlexisPerry     mlir::LLVM::LLVMFuncOp mallocFunc = getMalloc(heap, rewriter);
1016c2acd453SAlexisPerry     mlir::Location loc = heap.getLoc();
1017c2acd453SAlexisPerry     auto ity = lowerTy().indexType();
1018575c9d6dSValentin Clement     mlir::Type dataTy = fir::unwrapRefType(heapTy);
1019c45bd4b9SEric Schweitz     if (fir::isRecordWithTypeParameters(fir::unwrapSequenceType(dataTy)))
1020c45bd4b9SEric Schweitz       TODO(loc, "fir.allocmem codegen of derived type with length parameters");
1021c2acd453SAlexisPerry     mlir::Value size = genTypeSizeInBytes(loc, ity, rewriter, ty);
1022ac0f4c8fSPeixinQiao     if (auto scaleSize = genAllocationScaleSize(heap, ity, rewriter))
1023ac0f4c8fSPeixinQiao       size = rewriter.create<mlir::LLVM::MulOp>(loc, ity, size, scaleSize);
1024c2acd453SAlexisPerry     for (mlir::Value opnd : adaptor.getOperands())
1025c2acd453SAlexisPerry       size = rewriter.create<mlir::LLVM::MulOp>(
1026c2acd453SAlexisPerry           loc, ity, size, integerCast(loc, rewriter, ity, opnd));
1027c2acd453SAlexisPerry     heap->setAttr("callee", mlir::SymbolRefAttr::get(mallocFunc));
1028c2acd453SAlexisPerry     auto malloc = rewriter.create<mlir::LLVM::CallOp>(
1029c2acd453SAlexisPerry         loc, ::getVoidPtrType(heap.getContext()), size, heap->getAttrs());
1030c2acd453SAlexisPerry     rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(heap, ty,
1031c2acd453SAlexisPerry                                                        malloc.getResult(0));
103244e58509SEric Schweitz     return mlir::success();
1033c2acd453SAlexisPerry   }
1034c2acd453SAlexisPerry 
1035c2acd453SAlexisPerry   // Compute the (allocation) size of the allocmem type in bytes.
1036c2acd453SAlexisPerry   mlir::Value genTypeSizeInBytes(mlir::Location loc, mlir::Type idxTy,
1037c2acd453SAlexisPerry                                  mlir::ConversionPatternRewriter &rewriter,
1038c2acd453SAlexisPerry                                  mlir::Type llTy) const {
1039c2acd453SAlexisPerry     // Use the primitive size, if available.
1040c2acd453SAlexisPerry     auto ptrTy = llTy.dyn_cast<mlir::LLVM::LLVMPointerType>();
1041c2acd453SAlexisPerry     if (auto size =
1042c2acd453SAlexisPerry             mlir::LLVM::getPrimitiveTypeSizeInBits(ptrTy.getElementType()))
1043c2acd453SAlexisPerry       return genConstantIndex(loc, idxTy, rewriter, size / 8);
1044c2acd453SAlexisPerry 
1045c2acd453SAlexisPerry     // Otherwise, generate the GEP trick in LLVM IR to compute the size.
1046c2acd453SAlexisPerry     return computeDerivedTypeSize(loc, ptrTy, idxTy, rewriter);
1047c2acd453SAlexisPerry   }
1048c2acd453SAlexisPerry };
1049c2acd453SAlexisPerry } // namespace
1050c2acd453SAlexisPerry 
1051c2acd453SAlexisPerry /// Return the LLVMFuncOp corresponding to the standard free call.
1052c2acd453SAlexisPerry static mlir::LLVM::LLVMFuncOp
1053c2acd453SAlexisPerry getFree(fir::FreeMemOp op, mlir::ConversionPatternRewriter &rewriter) {
1054c2acd453SAlexisPerry   auto module = op->getParentOfType<mlir::ModuleOp>();
1055c2acd453SAlexisPerry   if (mlir::LLVM::LLVMFuncOp freeFunc =
1056c2acd453SAlexisPerry           module.lookupSymbol<mlir::LLVM::LLVMFuncOp>("free"))
1057c2acd453SAlexisPerry     return freeFunc;
1058c2acd453SAlexisPerry   mlir::OpBuilder moduleBuilder(module.getBodyRegion());
1059c2acd453SAlexisPerry   auto voidType = mlir::LLVM::LLVMVoidType::get(op.getContext());
1060c2acd453SAlexisPerry   return moduleBuilder.create<mlir::LLVM::LLVMFuncOp>(
1061c2acd453SAlexisPerry       rewriter.getUnknownLoc(), "free",
1062c2acd453SAlexisPerry       mlir::LLVM::LLVMFunctionType::get(voidType,
1063c2acd453SAlexisPerry                                         getVoidPtrType(op.getContext()),
1064c2acd453SAlexisPerry                                         /*isVarArg=*/false));
1065c2acd453SAlexisPerry }
1066c2acd453SAlexisPerry 
1067b094c737SJean Perier static unsigned getDimension(mlir::LLVM::LLVMArrayType ty) {
1068b094c737SJean Perier   unsigned result = 1;
1069b094c737SJean Perier   for (auto eleTy = ty.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>();
1070b094c737SJean Perier        eleTy;
1071b094c737SJean Perier        eleTy = eleTy.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>())
1072b094c737SJean Perier     ++result;
1073b094c737SJean Perier   return result;
1074b094c737SJean Perier }
1075b094c737SJean Perier 
1076c2acd453SAlexisPerry namespace {
1077c2acd453SAlexisPerry /// Lower a `fir.freemem` instruction into `llvm.call @free`
1078c2acd453SAlexisPerry struct FreeMemOpConversion : public FIROpConversion<fir::FreeMemOp> {
1079c2acd453SAlexisPerry   using FIROpConversion::FIROpConversion;
1080c2acd453SAlexisPerry 
1081c2acd453SAlexisPerry   mlir::LogicalResult
1082c2acd453SAlexisPerry   matchAndRewrite(fir::FreeMemOp freemem, OpAdaptor adaptor,
1083c2acd453SAlexisPerry                   mlir::ConversionPatternRewriter &rewriter) const override {
1084c2acd453SAlexisPerry     mlir::LLVM::LLVMFuncOp freeFunc = getFree(freemem, rewriter);
1085c2acd453SAlexisPerry     mlir::Location loc = freemem.getLoc();
1086c2acd453SAlexisPerry     auto bitcast = rewriter.create<mlir::LLVM::BitcastOp>(
1087c2acd453SAlexisPerry         freemem.getLoc(), voidPtrTy(), adaptor.getOperands()[0]);
1088c2acd453SAlexisPerry     freemem->setAttr("callee", mlir::SymbolRefAttr::get(freeFunc));
1089c2acd453SAlexisPerry     rewriter.create<mlir::LLVM::CallOp>(
1090c2acd453SAlexisPerry         loc, mlir::TypeRange{}, mlir::ValueRange{bitcast}, freemem->getAttrs());
1091c2acd453SAlexisPerry     rewriter.eraseOp(freemem);
109244e58509SEric Schweitz     return mlir::success();
1093c2acd453SAlexisPerry   }
1094c2acd453SAlexisPerry };
1095c2acd453SAlexisPerry } // namespace
1096044d5b5dSValentin Clement 
1097af6ee580SValentin Clement /// Common base class for embox to descriptor conversion.
1098af6ee580SValentin Clement template <typename OP>
1099af6ee580SValentin Clement struct EmboxCommonConversion : public FIROpConversion<OP> {
1100af6ee580SValentin Clement   using FIROpConversion<OP>::FIROpConversion;
1101af6ee580SValentin Clement 
1102af6ee580SValentin Clement   // Find the LLVMFuncOp in whose entry block the alloca should be inserted.
1103af6ee580SValentin Clement   // The order to find the LLVMFuncOp is as follows:
1104af6ee580SValentin Clement   // 1. The parent operation of the current block if it is a LLVMFuncOp.
1105af6ee580SValentin Clement   // 2. The first ancestor that is a LLVMFuncOp.
1106af6ee580SValentin Clement   mlir::LLVM::LLVMFuncOp
1107af6ee580SValentin Clement   getFuncForAllocaInsert(mlir::ConversionPatternRewriter &rewriter) const {
1108af6ee580SValentin Clement     mlir::Operation *parentOp = rewriter.getInsertionBlock()->getParentOp();
1109af6ee580SValentin Clement     return mlir::isa<mlir::LLVM::LLVMFuncOp>(parentOp)
1110af6ee580SValentin Clement                ? mlir::cast<mlir::LLVM::LLVMFuncOp>(parentOp)
1111af6ee580SValentin Clement                : parentOp->getParentOfType<mlir::LLVM::LLVMFuncOp>();
1112af6ee580SValentin Clement   }
1113af6ee580SValentin Clement 
1114af6ee580SValentin Clement   // Generate an alloca of size 1 and type \p toTy.
1115af6ee580SValentin Clement   mlir::LLVM::AllocaOp
1116af6ee580SValentin Clement   genAllocaWithType(mlir::Location loc, mlir::Type toTy, unsigned alignment,
1117af6ee580SValentin Clement                     mlir::ConversionPatternRewriter &rewriter) const {
1118af6ee580SValentin Clement     auto thisPt = rewriter.saveInsertionPoint();
1119af6ee580SValentin Clement     mlir::LLVM::LLVMFuncOp func = getFuncForAllocaInsert(rewriter);
1120af6ee580SValentin Clement     rewriter.setInsertionPointToStart(&func.front());
1121af6ee580SValentin Clement     auto size = this->genI32Constant(loc, rewriter, 1);
1122af6ee580SValentin Clement     auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, toTy, size, alignment);
1123af6ee580SValentin Clement     rewriter.restoreInsertionPoint(thisPt);
1124af6ee580SValentin Clement     return al;
1125af6ee580SValentin Clement   }
1126af6ee580SValentin Clement 
1127af6ee580SValentin Clement   static int getCFIAttr(fir::BoxType boxTy) {
1128af6ee580SValentin Clement     auto eleTy = boxTy.getEleTy();
1129af6ee580SValentin Clement     if (eleTy.isa<fir::PointerType>())
1130af6ee580SValentin Clement       return CFI_attribute_pointer;
1131af6ee580SValentin Clement     if (eleTy.isa<fir::HeapType>())
1132af6ee580SValentin Clement       return CFI_attribute_allocatable;
1133af6ee580SValentin Clement     return CFI_attribute_other;
1134af6ee580SValentin Clement   }
1135af6ee580SValentin Clement 
1136af6ee580SValentin Clement   static fir::RecordType unwrapIfDerived(fir::BoxType boxTy) {
1137af6ee580SValentin Clement     return fir::unwrapSequenceType(fir::dyn_cast_ptrOrBoxEleTy(boxTy))
1138af6ee580SValentin Clement         .template dyn_cast<fir::RecordType>();
1139af6ee580SValentin Clement   }
1140af6ee580SValentin Clement   static bool isDerivedTypeWithLenParams(fir::BoxType boxTy) {
1141af6ee580SValentin Clement     auto recTy = unwrapIfDerived(boxTy);
1142af6ee580SValentin Clement     return recTy && recTy.getNumLenParams() > 0;
1143af6ee580SValentin Clement   }
1144af6ee580SValentin Clement   static bool isDerivedType(fir::BoxType boxTy) {
1145575c9d6dSValentin Clement     return static_cast<bool>(unwrapIfDerived(boxTy));
1146af6ee580SValentin Clement   }
1147af6ee580SValentin Clement 
1148af6ee580SValentin Clement   // Get the element size and CFI type code of the boxed value.
1149af6ee580SValentin Clement   std::tuple<mlir::Value, mlir::Value> getSizeAndTypeCode(
1150af6ee580SValentin Clement       mlir::Location loc, mlir::ConversionPatternRewriter &rewriter,
1151af6ee580SValentin Clement       mlir::Type boxEleTy, mlir::ValueRange lenParams = {}) const {
1152af6ee580SValentin Clement     auto doInteger =
1153af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1154af6ee580SValentin Clement       int typeCode = fir::integerBitsToTypeCode(width);
1155af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1156af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1157af6ee580SValentin Clement     };
1158af6ee580SValentin Clement     auto doLogical =
1159af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1160af6ee580SValentin Clement       int typeCode = fir::logicalBitsToTypeCode(width);
1161af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1162af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1163af6ee580SValentin Clement     };
1164af6ee580SValentin Clement     auto doFloat = [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1165af6ee580SValentin Clement       int typeCode = fir::realBitsToTypeCode(width);
1166af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1167af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1168af6ee580SValentin Clement     };
1169af6ee580SValentin Clement     auto doComplex =
1170af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1171af6ee580SValentin Clement       auto typeCode = fir::complexBitsToTypeCode(width);
1172af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8 * 2),
1173af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1174af6ee580SValentin Clement     };
1175af6ee580SValentin Clement     auto doCharacter =
1176af6ee580SValentin Clement         [&](unsigned width,
1177af6ee580SValentin Clement             mlir::Value len) -> std::tuple<mlir::Value, mlir::Value> {
1178af6ee580SValentin Clement       auto typeCode = fir::characterBitsToTypeCode(width);
1179af6ee580SValentin Clement       auto typeCodeVal = this->genConstantOffset(loc, rewriter, typeCode);
1180af6ee580SValentin Clement       if (width == 8)
1181af6ee580SValentin Clement         return {len, typeCodeVal};
1182af6ee580SValentin Clement       auto i64Ty = mlir::IntegerType::get(&this->lowerTy().getContext(), 64);
11836c89c531SEric Schweitz       auto byteWidth = genConstantIndex(loc, i64Ty, rewriter, width / 8);
11846c89c531SEric Schweitz       auto len64 = FIROpConversion<OP>::integerCast(loc, rewriter, i64Ty, len);
1185af6ee580SValentin Clement       auto size =
11866c89c531SEric Schweitz           rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, byteWidth, len64);
1187af6ee580SValentin Clement       return {size, typeCodeVal};
1188af6ee580SValentin Clement     };
1189af6ee580SValentin Clement     auto getKindMap = [&]() -> fir::KindMapping & {
1190af6ee580SValentin Clement       return this->lowerTy().getKindMap();
1191af6ee580SValentin Clement     };
1192af6ee580SValentin Clement     // Pointer-like types.
1193af6ee580SValentin Clement     if (auto eleTy = fir::dyn_cast_ptrEleTy(boxEleTy))
1194af6ee580SValentin Clement       boxEleTy = eleTy;
1195af6ee580SValentin Clement     // Integer types.
1196af6ee580SValentin Clement     if (fir::isa_integer(boxEleTy)) {
1197af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::IntegerType>())
1198af6ee580SValentin Clement         return doInteger(ty.getWidth());
1199af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::IntegerType>();
1200af6ee580SValentin Clement       return doInteger(getKindMap().getIntegerBitsize(ty.getFKind()));
1201af6ee580SValentin Clement     }
1202af6ee580SValentin Clement     // Floating point types.
1203af6ee580SValentin Clement     if (fir::isa_real(boxEleTy)) {
1204af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::FloatType>())
1205af6ee580SValentin Clement         return doFloat(ty.getWidth());
1206af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::RealType>();
1207af6ee580SValentin Clement       return doFloat(getKindMap().getRealBitsize(ty.getFKind()));
1208af6ee580SValentin Clement     }
1209af6ee580SValentin Clement     // Complex types.
1210af6ee580SValentin Clement     if (fir::isa_complex(boxEleTy)) {
1211af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::ComplexType>())
1212af6ee580SValentin Clement         return doComplex(
1213af6ee580SValentin Clement             ty.getElementType().cast<mlir::FloatType>().getWidth());
1214af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::ComplexType>();
1215af6ee580SValentin Clement       return doComplex(getKindMap().getRealBitsize(ty.getFKind()));
1216af6ee580SValentin Clement     }
1217af6ee580SValentin Clement     // Character types.
1218af6ee580SValentin Clement     if (auto ty = boxEleTy.dyn_cast<fir::CharacterType>()) {
1219af6ee580SValentin Clement       auto charWidth = getKindMap().getCharacterBitsize(ty.getFKind());
1220af6ee580SValentin Clement       if (ty.getLen() != fir::CharacterType::unknownLen()) {
1221af6ee580SValentin Clement         auto len = this->genConstantOffset(loc, rewriter, ty.getLen());
1222af6ee580SValentin Clement         return doCharacter(charWidth, len);
1223af6ee580SValentin Clement       }
1224af6ee580SValentin Clement       assert(!lenParams.empty());
1225af6ee580SValentin Clement       return doCharacter(charWidth, lenParams.back());
1226af6ee580SValentin Clement     }
1227af6ee580SValentin Clement     // Logical type.
1228af6ee580SValentin Clement     if (auto ty = boxEleTy.dyn_cast<fir::LogicalType>())
1229af6ee580SValentin Clement       return doLogical(getKindMap().getLogicalBitsize(ty.getFKind()));
1230af6ee580SValentin Clement     // Array types.
1231af6ee580SValentin Clement     if (auto seqTy = boxEleTy.dyn_cast<fir::SequenceType>())
1232af6ee580SValentin Clement       return getSizeAndTypeCode(loc, rewriter, seqTy.getEleTy(), lenParams);
1233af6ee580SValentin Clement     // Derived-type types.
1234af6ee580SValentin Clement     if (boxEleTy.isa<fir::RecordType>()) {
1235af6ee580SValentin Clement       auto ptrTy = mlir::LLVM::LLVMPointerType::get(
1236af6ee580SValentin Clement           this->lowerTy().convertType(boxEleTy));
1237af6ee580SValentin Clement       auto nullPtr = rewriter.create<mlir::LLVM::NullOp>(loc, ptrTy);
1238af6ee580SValentin Clement       auto one =
1239af6ee580SValentin Clement           genConstantIndex(loc, this->lowerTy().offsetType(), rewriter, 1);
124030122656SAlex Zinenko       auto gep = rewriter.create<mlir::LLVM::GEPOp>(loc, ptrTy, nullPtr,
124130122656SAlex Zinenko                                                     mlir::ValueRange{one});
1242af6ee580SValentin Clement       auto eleSize = rewriter.create<mlir::LLVM::PtrToIntOp>(
1243af6ee580SValentin Clement           loc, this->lowerTy().indexType(), gep);
1244af6ee580SValentin Clement       return {eleSize,
1245af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, fir::derivedToTypeCode())};
1246af6ee580SValentin Clement     }
1247af6ee580SValentin Clement     // Reference type.
1248af6ee580SValentin Clement     if (fir::isa_ref_type(boxEleTy)) {
1249af6ee580SValentin Clement       // FIXME: use the target pointer size rather than sizeof(void*)
1250af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, sizeof(void *)),
1251af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, CFI_type_cptr)};
1252af6ee580SValentin Clement     }
1253af6ee580SValentin Clement     fir::emitFatalError(loc, "unhandled type in fir.box code generation");
1254af6ee580SValentin Clement   }
1255af6ee580SValentin Clement 
1256af6ee580SValentin Clement   /// Basic pattern to write a field in the descriptor
1257af6ee580SValentin Clement   mlir::Value insertField(mlir::ConversionPatternRewriter &rewriter,
1258af6ee580SValentin Clement                           mlir::Location loc, mlir::Value dest,
125944e58509SEric Schweitz                           llvm::ArrayRef<unsigned> fldIndexes,
126044e58509SEric Schweitz                           mlir::Value value, bool bitcast = false) const {
1261af6ee580SValentin Clement     auto boxTy = dest.getType();
1262af6ee580SValentin Clement     auto fldTy = this->getBoxEleTy(boxTy, fldIndexes);
1263af6ee580SValentin Clement     if (bitcast)
1264af6ee580SValentin Clement       value = rewriter.create<mlir::LLVM::BitcastOp>(loc, fldTy, value);
1265af6ee580SValentin Clement     else
1266af6ee580SValentin Clement       value = this->integerCast(loc, rewriter, fldTy, value);
126744e58509SEric Schweitz     llvm::SmallVector<mlir::Attribute, 2> attrs;
1268af6ee580SValentin Clement     for (auto i : fldIndexes)
1269af6ee580SValentin Clement       attrs.push_back(rewriter.getI32IntegerAttr(i));
1270af6ee580SValentin Clement     auto indexesAttr = mlir::ArrayAttr::get(rewriter.getContext(), attrs);
1271af6ee580SValentin Clement     return rewriter.create<mlir::LLVM::InsertValueOp>(loc, boxTy, dest, value,
1272af6ee580SValentin Clement                                                       indexesAttr);
1273af6ee580SValentin Clement   }
1274af6ee580SValentin Clement 
1275af6ee580SValentin Clement   inline mlir::Value
1276af6ee580SValentin Clement   insertBaseAddress(mlir::ConversionPatternRewriter &rewriter,
1277af6ee580SValentin Clement                     mlir::Location loc, mlir::Value dest,
1278af6ee580SValentin Clement                     mlir::Value base) const {
12791f551032SValentin Clement     return insertField(rewriter, loc, dest, {kAddrPosInBox}, base,
12801f551032SValentin Clement                        /*bitCast=*/true);
12811f551032SValentin Clement   }
12821f551032SValentin Clement 
12831f551032SValentin Clement   inline mlir::Value insertLowerBound(mlir::ConversionPatternRewriter &rewriter,
12841f551032SValentin Clement                                       mlir::Location loc, mlir::Value dest,
12851f551032SValentin Clement                                       unsigned dim, mlir::Value lb) const {
12861f551032SValentin Clement     return insertField(rewriter, loc, dest,
12871f551032SValentin Clement                        {kDimsPosInBox, dim, kDimLowerBoundPos}, lb);
12881f551032SValentin Clement   }
12891f551032SValentin Clement 
12901f551032SValentin Clement   inline mlir::Value insertExtent(mlir::ConversionPatternRewriter &rewriter,
12911f551032SValentin Clement                                   mlir::Location loc, mlir::Value dest,
12921f551032SValentin Clement                                   unsigned dim, mlir::Value extent) const {
12931f551032SValentin Clement     return insertField(rewriter, loc, dest, {kDimsPosInBox, dim, kDimExtentPos},
12941f551032SValentin Clement                        extent);
12951f551032SValentin Clement   }
12961f551032SValentin Clement 
12971f551032SValentin Clement   inline mlir::Value insertStride(mlir::ConversionPatternRewriter &rewriter,
12981f551032SValentin Clement                                   mlir::Location loc, mlir::Value dest,
12991f551032SValentin Clement                                   unsigned dim, mlir::Value stride) const {
13001f551032SValentin Clement     return insertField(rewriter, loc, dest, {kDimsPosInBox, dim, kDimStridePos},
13011f551032SValentin Clement                        stride);
1302af6ee580SValentin Clement   }
1303af6ee580SValentin Clement 
1304af6ee580SValentin Clement   /// Get the address of the type descriptor global variable that was created by
1305af6ee580SValentin Clement   /// lowering for derived type \p recType.
1306af6ee580SValentin Clement   template <typename BOX>
1307af6ee580SValentin Clement   mlir::Value
1308af6ee580SValentin Clement   getTypeDescriptor(BOX box, mlir::ConversionPatternRewriter &rewriter,
1309af6ee580SValentin Clement                     mlir::Location loc, fir::RecordType recType) const {
1310013160f6SJean Perier     std::string name =
1311013160f6SJean Perier         fir::NameUniquer::getTypeDescriptorName(recType.getName());
1312af6ee580SValentin Clement     auto module = box->template getParentOfType<mlir::ModuleOp>();
1313af6ee580SValentin Clement     if (auto global = module.template lookupSymbol<fir::GlobalOp>(name)) {
1314af6ee580SValentin Clement       auto ty = mlir::LLVM::LLVMPointerType::get(
1315af6ee580SValentin Clement           this->lowerTy().convertType(global.getType()));
1316af6ee580SValentin Clement       return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty,
1317feeee78aSJacques Pienaar                                                       global.getSymName());
1318af6ee580SValentin Clement     }
1319af6ee580SValentin Clement     if (auto global =
1320af6ee580SValentin Clement             module.template lookupSymbol<mlir::LLVM::GlobalOp>(name)) {
1321af6ee580SValentin Clement       // The global may have already been translated to LLVM.
1322af6ee580SValentin Clement       auto ty = mlir::LLVM::LLVMPointerType::get(global.getType());
1323af6ee580SValentin Clement       return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty,
1324feeee78aSJacques Pienaar                                                       global.getSymName());
1325af6ee580SValentin Clement     }
13267dd7ccd2SJean Perier     // Type info derived types do not have type descriptors since they are the
13277dd7ccd2SJean Perier     // types defining type descriptors.
1328013160f6SJean Perier     if (!this->options.ignoreMissingTypeDescriptors &&
1329013160f6SJean Perier         !fir::NameUniquer::belongsToModule(
1330013160f6SJean Perier             name, Fortran::semantics::typeInfoBuiltinModule))
1331013160f6SJean Perier       fir::emitFatalError(
1332013160f6SJean Perier           loc, "runtime derived type info descriptor was not generated");
13335bde97b1SJean Perier     return rewriter.create<mlir::LLVM::NullOp>(
13345bde97b1SJean Perier         loc, ::getVoidPtrType(box.getContext()));
13357dd7ccd2SJean Perier   }
1336af6ee580SValentin Clement 
1337af6ee580SValentin Clement   template <typename BOX>
1338af6ee580SValentin Clement   std::tuple<fir::BoxType, mlir::Value, mlir::Value>
1339af6ee580SValentin Clement   consDescriptorPrefix(BOX box, mlir::ConversionPatternRewriter &rewriter,
1340af6ee580SValentin Clement                        unsigned rank, mlir::ValueRange lenParams) const {
1341af6ee580SValentin Clement     auto loc = box.getLoc();
1342af6ee580SValentin Clement     auto boxTy = box.getType().template dyn_cast<fir::BoxType>();
1343af6ee580SValentin Clement     auto convTy = this->lowerTy().convertBoxType(boxTy, rank);
1344af6ee580SValentin Clement     auto llvmBoxPtrTy = convTy.template cast<mlir::LLVM::LLVMPointerType>();
1345af6ee580SValentin Clement     auto llvmBoxTy = llvmBoxPtrTy.getElementType();
1346af6ee580SValentin Clement     mlir::Value descriptor =
1347af6ee580SValentin Clement         rewriter.create<mlir::LLVM::UndefOp>(loc, llvmBoxTy);
1348af6ee580SValentin Clement 
1349af6ee580SValentin Clement     llvm::SmallVector<mlir::Value> typeparams = lenParams;
1350af6ee580SValentin Clement     if constexpr (!std::is_same_v<BOX, fir::EmboxOp>) {
1351af6ee580SValentin Clement       if (!box.substr().empty() && fir::hasDynamicSize(boxTy.getEleTy()))
1352af6ee580SValentin Clement         typeparams.push_back(box.substr()[1]);
1353af6ee580SValentin Clement     }
1354af6ee580SValentin Clement 
1355af6ee580SValentin Clement     // Write each of the fields with the appropriate values
1356af6ee580SValentin Clement     auto [eleSize, cfiTy] =
1357af6ee580SValentin Clement         getSizeAndTypeCode(loc, rewriter, boxTy.getEleTy(), typeparams);
1358af6ee580SValentin Clement     descriptor =
1359af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kElemLenPosInBox}, eleSize);
1360af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kVersionPosInBox},
1361af6ee580SValentin Clement                              this->genI32Constant(loc, rewriter, CFI_VERSION));
1362af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kRankPosInBox},
1363af6ee580SValentin Clement                              this->genI32Constant(loc, rewriter, rank));
1364af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kTypePosInBox}, cfiTy);
1365af6ee580SValentin Clement     descriptor =
1366af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kAttributePosInBox},
1367af6ee580SValentin Clement                     this->genI32Constant(loc, rewriter, getCFIAttr(boxTy)));
1368af6ee580SValentin Clement     const bool hasAddendum = isDerivedType(boxTy);
1369af6ee580SValentin Clement     descriptor =
1370af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kF18AddendumPosInBox},
1371af6ee580SValentin Clement                     this->genI32Constant(loc, rewriter, hasAddendum ? 1 : 0));
1372af6ee580SValentin Clement 
1373af6ee580SValentin Clement     if (hasAddendum) {
1374af6ee580SValentin Clement       auto isArray =
1375af6ee580SValentin Clement           fir::dyn_cast_ptrOrBoxEleTy(boxTy).template isa<fir::SequenceType>();
1376af6ee580SValentin Clement       unsigned typeDescFieldId = isArray ? kOptTypePtrPosInBox : kDimsPosInBox;
1377af6ee580SValentin Clement       auto typeDesc =
1378af6ee580SValentin Clement           getTypeDescriptor(box, rewriter, loc, unwrapIfDerived(boxTy));
1379af6ee580SValentin Clement       descriptor =
1380af6ee580SValentin Clement           insertField(rewriter, loc, descriptor, {typeDescFieldId}, typeDesc,
1381af6ee580SValentin Clement                       /*bitCast=*/true);
1382af6ee580SValentin Clement     }
1383af6ee580SValentin Clement 
1384af6ee580SValentin Clement     return {boxTy, descriptor, eleSize};
1385af6ee580SValentin Clement   }
1386af6ee580SValentin Clement 
13871f551032SValentin Clement   /// Compute the base address of a substring given the base address of a scalar
13881f551032SValentin Clement   /// string and the zero based string lower bound.
13891f551032SValentin Clement   mlir::Value shiftSubstringBase(mlir::ConversionPatternRewriter &rewriter,
13901f551032SValentin Clement                                  mlir::Location loc, mlir::Value base,
13911f551032SValentin Clement                                  mlir::Value lowerBound) const {
13921f551032SValentin Clement     llvm::SmallVector<mlir::Value> gepOperands;
13931f551032SValentin Clement     auto baseType =
13941f551032SValentin Clement         base.getType().cast<mlir::LLVM::LLVMPointerType>().getElementType();
1395b094c737SJean Perier     if (auto arrayType = baseType.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
1396b094c737SJean Perier       // FIXME: The baseType should be the array element type here, meaning
1397b094c737SJean Perier       // there should at most be one dimension (constant length characters are
1398b094c737SJean Perier       // lowered to LLVM as an array of length one characters.). However, using
1399b094c737SJean Perier       // the character type in the GEP does not lead to correct GEPs when llvm
1400b094c737SJean Perier       // opaque pointers are enabled.
14011f551032SValentin Clement       auto idxTy = this->lowerTy().indexType();
1402b094c737SJean Perier       gepOperands.append(getDimension(arrayType),
1403b094c737SJean Perier                          genConstantIndex(loc, idxTy, rewriter, 0));
14041f551032SValentin Clement       gepOperands.push_back(lowerBound);
14056c89c531SEric Schweitz     } else {
14066c89c531SEric Schweitz       gepOperands.push_back(lowerBound);
14076c89c531SEric Schweitz     }
14081f551032SValentin Clement     return this->genGEP(loc, base.getType(), rewriter, base, gepOperands);
14091f551032SValentin Clement   }
14101f551032SValentin Clement 
1411af6ee580SValentin Clement   /// If the embox is not in a globalOp body, allocate storage for the box;
1412af6ee580SValentin Clement   /// store the value inside and return the generated alloca. Return the input
1413af6ee580SValentin Clement   /// value otherwise.
1414af6ee580SValentin Clement   mlir::Value
1415af6ee580SValentin Clement   placeInMemoryIfNotGlobalInit(mlir::ConversionPatternRewriter &rewriter,
1416af6ee580SValentin Clement                                mlir::Location loc, mlir::Value boxValue) const {
1417af6ee580SValentin Clement     auto *thisBlock = rewriter.getInsertionBlock();
1418af6ee580SValentin Clement     if (thisBlock && mlir::isa<mlir::LLVM::GlobalOp>(thisBlock->getParentOp()))
1419af6ee580SValentin Clement       return boxValue;
1420af6ee580SValentin Clement     auto boxPtrTy = mlir::LLVM::LLVMPointerType::get(boxValue.getType());
1421af6ee580SValentin Clement     auto alloca = genAllocaWithType(loc, boxPtrTy, defaultAlign, rewriter);
1422af6ee580SValentin Clement     rewriter.create<mlir::LLVM::StoreOp>(loc, boxValue, alloca);
1423af6ee580SValentin Clement     return alloca;
1424af6ee580SValentin Clement   }
1425af6ee580SValentin Clement };
1426af6ee580SValentin Clement 
14271f551032SValentin Clement /// Compute the extent of a triplet slice (lb:ub:step).
14281f551032SValentin Clement static mlir::Value
14291f551032SValentin Clement computeTripletExtent(mlir::ConversionPatternRewriter &rewriter,
14301f551032SValentin Clement                      mlir::Location loc, mlir::Value lb, mlir::Value ub,
14311f551032SValentin Clement                      mlir::Value step, mlir::Value zero, mlir::Type type) {
14321f551032SValentin Clement   mlir::Value extent = rewriter.create<mlir::LLVM::SubOp>(loc, type, ub, lb);
14331f551032SValentin Clement   extent = rewriter.create<mlir::LLVM::AddOp>(loc, type, extent, step);
14341f551032SValentin Clement   extent = rewriter.create<mlir::LLVM::SDivOp>(loc, type, extent, step);
14351f551032SValentin Clement   // If the resulting extent is negative (`ub-lb` and `step` have different
14361f551032SValentin Clement   // signs), zero must be returned instead.
14371f551032SValentin Clement   auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
14381f551032SValentin Clement       loc, mlir::LLVM::ICmpPredicate::sgt, extent, zero);
14391f551032SValentin Clement   return rewriter.create<mlir::LLVM::SelectOp>(loc, cmp, extent, zero);
14401f551032SValentin Clement }
14411f551032SValentin Clement 
1442af6ee580SValentin Clement /// Create a generic box on a memory reference. This conversions lowers the
1443af6ee580SValentin Clement /// abstract box to the appropriate, initialized descriptor.
1444af6ee580SValentin Clement struct EmboxOpConversion : public EmboxCommonConversion<fir::EmboxOp> {
1445af6ee580SValentin Clement   using EmboxCommonConversion::EmboxCommonConversion;
1446af6ee580SValentin Clement 
1447af6ee580SValentin Clement   mlir::LogicalResult
1448af6ee580SValentin Clement   matchAndRewrite(fir::EmboxOp embox, OpAdaptor adaptor,
1449af6ee580SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
145012d26ce9SValentin Clement     mlir::ValueRange operands = adaptor.getOperands();
1451af6ee580SValentin Clement     assert(!embox.getShape() && "There should be no dims on this embox op");
145212d26ce9SValentin Clement     auto [boxTy, dest, eleSize] = consDescriptorPrefix(
145312d26ce9SValentin Clement         embox, rewriter, /*rank=*/0, /*lenParams=*/operands.drop_front(1));
145412d26ce9SValentin Clement     dest = insertBaseAddress(rewriter, embox.getLoc(), dest, operands[0]);
14557ce8c6fcSKiran Chandramohan     if (isDerivedTypeWithLenParams(boxTy)) {
14567ce8c6fcSKiran Chandramohan       TODO(embox.getLoc(),
14577ce8c6fcSKiran Chandramohan            "fir.embox codegen of derived with length parameters");
145844e58509SEric Schweitz       return mlir::failure();
14597ce8c6fcSKiran Chandramohan     }
1460af6ee580SValentin Clement     auto result = placeInMemoryIfNotGlobalInit(rewriter, embox.getLoc(), dest);
1461af6ee580SValentin Clement     rewriter.replaceOp(embox, result);
146244e58509SEric Schweitz     return mlir::success();
1463af6ee580SValentin Clement   }
1464af6ee580SValentin Clement };
1465af6ee580SValentin Clement 
14661f551032SValentin Clement /// Create a generic box on a memory reference.
14671f551032SValentin Clement struct XEmboxOpConversion : public EmboxCommonConversion<fir::cg::XEmboxOp> {
14681f551032SValentin Clement   using EmboxCommonConversion::EmboxCommonConversion;
14691f551032SValentin Clement 
14701f551032SValentin Clement   mlir::LogicalResult
14711f551032SValentin Clement   matchAndRewrite(fir::cg::XEmboxOp xbox, OpAdaptor adaptor,
14721f551032SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
14731f551032SValentin Clement     mlir::ValueRange operands = adaptor.getOperands();
147412d26ce9SValentin Clement     auto [boxTy, dest, eleSize] =
147512d26ce9SValentin Clement         consDescriptorPrefix(xbox, rewriter, xbox.getOutRank(),
147612d26ce9SValentin Clement                              operands.drop_front(xbox.lenParamOffset()));
147712d26ce9SValentin Clement     // Generate the triples in the dims field of the descriptor
14781f551032SValentin Clement     auto i64Ty = mlir::IntegerType::get(xbox.getContext(), 64);
14791f551032SValentin Clement     mlir::Value base = operands[0];
14801f551032SValentin Clement     assert(!xbox.shape().empty() && "must have a shape");
14811f551032SValentin Clement     unsigned shapeOffset = xbox.shapeOffset();
14821f551032SValentin Clement     bool hasShift = !xbox.shift().empty();
14831f551032SValentin Clement     unsigned shiftOffset = xbox.shiftOffset();
14841f551032SValentin Clement     bool hasSlice = !xbox.slice().empty();
14851f551032SValentin Clement     unsigned sliceOffset = xbox.sliceOffset();
14861f551032SValentin Clement     mlir::Location loc = xbox.getLoc();
14871f551032SValentin Clement     mlir::Value zero = genConstantIndex(loc, i64Ty, rewriter, 0);
14881f551032SValentin Clement     mlir::Value one = genConstantIndex(loc, i64Ty, rewriter, 1);
14891f551032SValentin Clement     mlir::Value prevPtrOff = one;
14901f551032SValentin Clement     mlir::Type eleTy = boxTy.getEleTy();
14911f551032SValentin Clement     const unsigned rank = xbox.getRank();
14921f551032SValentin Clement     llvm::SmallVector<mlir::Value> gepArgs;
14931f551032SValentin Clement     unsigned constRows = 0;
14941f551032SValentin Clement     mlir::Value ptrOffset = zero;
14956c89c531SEric Schweitz     mlir::Type memEleTy = fir::dyn_cast_ptrEleTy(xbox.memref().getType());
14966c89c531SEric Schweitz     assert(memEleTy.isa<fir::SequenceType>());
14976c89c531SEric Schweitz     auto seqTy = memEleTy.cast<fir::SequenceType>();
14981f551032SValentin Clement     mlir::Type seqEleTy = seqTy.getEleTy();
14991f551032SValentin Clement     // Adjust the element scaling factor if the element is a dependent type.
15001f551032SValentin Clement     if (fir::hasDynamicSize(seqEleTy)) {
15016c89c531SEric Schweitz       if (auto charTy = seqEleTy.dyn_cast<fir::CharacterType>()) {
15021f551032SValentin Clement         assert(xbox.lenParams().size() == 1);
15036c89c531SEric Schweitz         mlir::LLVM::ConstantOp charSize = genConstantIndex(
15046c89c531SEric Schweitz             loc, i64Ty, rewriter, lowerTy().characterBitsize(charTy) / 8);
15056c89c531SEric Schweitz         mlir::Value castedLen =
15066c89c531SEric Schweitz             integerCast(loc, rewriter, i64Ty, operands[xbox.lenParamOffset()]);
15076c89c531SEric Schweitz         auto byteOffset =
15086c89c531SEric Schweitz             rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, charSize, castedLen);
15096c89c531SEric Schweitz         prevPtrOff = integerCast(loc, rewriter, i64Ty, byteOffset);
15101f551032SValentin Clement       } else if (seqEleTy.isa<fir::RecordType>()) {
15116c89c531SEric Schweitz         // prevPtrOff = ;
15121f551032SValentin Clement         TODO(loc, "generate call to calculate size of PDT");
15131f551032SValentin Clement       } else {
15146c89c531SEric Schweitz         fir::emitFatalError(loc, "unexpected dynamic type");
15151f551032SValentin Clement       }
15161f551032SValentin Clement     } else {
15171f551032SValentin Clement       constRows = seqTy.getConstantRows();
15181f551032SValentin Clement     }
15191f551032SValentin Clement 
15206c89c531SEric Schweitz     const auto hasSubcomp = !xbox.subcomponent().empty();
15216c89c531SEric Schweitz     const bool hasSubstr = !xbox.substr().empty();
15226c89c531SEric Schweitz     /// Compute initial element stride that will be use to compute the step in
15236c89c531SEric Schweitz     /// each dimension.
15246c89c531SEric Schweitz     mlir::Value prevDimByteStride = integerCast(loc, rewriter, i64Ty, eleSize);
15251f551032SValentin Clement     if (hasSubcomp) {
15261f551032SValentin Clement       // We have a subcomponent. The step value needs to be the number of
15271f551032SValentin Clement       // bytes per element (which is a derived type).
15281f551032SValentin Clement       auto eleTy = mlir::LLVM::LLVMPointerType::get(convertType(seqEleTy));
15296c89c531SEric Schweitz       prevDimByteStride = computeDerivedTypeSize(loc, eleTy, i64Ty, rewriter);
15306c89c531SEric Schweitz     } else if (hasSubstr) {
15316c89c531SEric Schweitz       // We have a substring. The step value needs to be the number of bytes
15326c89c531SEric Schweitz       // per CHARACTER element.
15336c89c531SEric Schweitz       auto charTy = seqEleTy.cast<fir::CharacterType>();
15346c89c531SEric Schweitz       if (fir::hasDynamicSize(charTy)) {
15356c89c531SEric Schweitz         prevDimByteStride = prevPtrOff;
15366c89c531SEric Schweitz       } else {
15376c89c531SEric Schweitz         prevDimByteStride = genConstantIndex(
15386c89c531SEric Schweitz             loc, i64Ty, rewriter,
15396c89c531SEric Schweitz             charTy.getLen() * lowerTy().characterBitsize(charTy) / 8);
15406c89c531SEric Schweitz       }
15411f551032SValentin Clement     }
15421f551032SValentin Clement 
15431f551032SValentin Clement     // Process the array subspace arguments (shape, shift, etc.), if any,
15441f551032SValentin Clement     // translating everything to values in the descriptor wherever the entity
15451f551032SValentin Clement     // has a dynamic array dimension.
15461f551032SValentin Clement     for (unsigned di = 0, descIdx = 0; di < rank; ++di) {
15471f551032SValentin Clement       mlir::Value extent = operands[shapeOffset];
15481f551032SValentin Clement       mlir::Value outerExtent = extent;
15491f551032SValentin Clement       bool skipNext = false;
15501f551032SValentin Clement       if (hasSlice) {
15511f551032SValentin Clement         mlir::Value off = operands[sliceOffset];
15521f551032SValentin Clement         mlir::Value adj = one;
15531f551032SValentin Clement         if (hasShift)
15541f551032SValentin Clement           adj = operands[shiftOffset];
15551f551032SValentin Clement         auto ao = rewriter.create<mlir::LLVM::SubOp>(loc, i64Ty, off, adj);
15561f551032SValentin Clement         if (constRows > 0) {
15571f551032SValentin Clement           gepArgs.push_back(ao);
15581f551032SValentin Clement         } else {
15591f551032SValentin Clement           auto dimOff =
15601f551032SValentin Clement               rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, ao, prevPtrOff);
15611f551032SValentin Clement           ptrOffset =
15621f551032SValentin Clement               rewriter.create<mlir::LLVM::AddOp>(loc, i64Ty, dimOff, ptrOffset);
15631f551032SValentin Clement         }
15641f551032SValentin Clement         if (mlir::isa_and_nonnull<fir::UndefOp>(
15651f551032SValentin Clement                 xbox.slice()[3 * di + 1].getDefiningOp())) {
15661f551032SValentin Clement           // This dimension contains a scalar expression in the array slice op.
15671f551032SValentin Clement           // The dimension is loop invariant, will be dropped, and will not
15681f551032SValentin Clement           // appear in the descriptor.
15691f551032SValentin Clement           skipNext = true;
15701f551032SValentin Clement         }
15711f551032SValentin Clement       }
15721f551032SValentin Clement       if (!skipNext) {
15736c89c531SEric Schweitz         // store extent
15741f551032SValentin Clement         if (hasSlice)
15751f551032SValentin Clement           extent = computeTripletExtent(rewriter, loc, operands[sliceOffset],
15761f551032SValentin Clement                                         operands[sliceOffset + 1],
15771f551032SValentin Clement                                         operands[sliceOffset + 2], zero, i64Ty);
15786c89c531SEric Schweitz         // Lower bound is normalized to 0 for BIND(C) interoperability.
1579d3bc3a04SJean Perier         mlir::Value lb = zero;
1580d3bc3a04SJean Perier         const bool isaPointerOrAllocatable =
1581d3bc3a04SJean Perier             eleTy.isa<fir::PointerType>() || eleTy.isa<fir::HeapType>();
1582d3bc3a04SJean Perier         // Lower bound is defaults to 1 for POINTER, ALLOCATABLE, and
1583d3bc3a04SJean Perier         // denormalized descriptors.
15846c89c531SEric Schweitz         if (isaPointerOrAllocatable || !normalizedLowerBound(xbox))
1585d3bc3a04SJean Perier           lb = one;
1586bb3afae9SJean Perier         // If there is a shifted origin, and no fir.slice, and this is not
1587bb3afae9SJean Perier         // a normalized descriptor then use the value from the shift op as
1588bb3afae9SJean Perier         // the lower bound.
15896c89c531SEric Schweitz         if (hasShift && !(hasSlice || hasSubcomp || hasSubstr) &&
15906c89c531SEric Schweitz             (isaPointerOrAllocatable || !normalizedLowerBound(xbox))) {
1591d3bc3a04SJean Perier           lb = operands[shiftOffset];
1592d3bc3a04SJean Perier           auto extentIsEmpty = rewriter.create<mlir::LLVM::ICmpOp>(
1593d3bc3a04SJean Perier               loc, mlir::LLVM::ICmpPredicate::eq, extent, zero);
1594d3bc3a04SJean Perier           lb = rewriter.create<mlir::LLVM::SelectOp>(loc, extentIsEmpty, one,
1595d3bc3a04SJean Perier                                                      lb);
1596d3bc3a04SJean Perier         }
1597d3bc3a04SJean Perier         dest = insertLowerBound(rewriter, loc, dest, descIdx, lb);
1598d3bc3a04SJean Perier 
15991f551032SValentin Clement         dest = insertExtent(rewriter, loc, dest, descIdx, extent);
16001f551032SValentin Clement 
16011f551032SValentin Clement         // store step (scaled by shaped extent)
16026c89c531SEric Schweitz         mlir::Value step = prevDimByteStride;
16031f551032SValentin Clement         if (hasSlice)
16041f551032SValentin Clement           step = rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, step,
16051f551032SValentin Clement                                                     operands[sliceOffset + 2]);
16061f551032SValentin Clement         dest = insertStride(rewriter, loc, dest, descIdx, step);
16071f551032SValentin Clement         ++descIdx;
16081f551032SValentin Clement       }
16091f551032SValentin Clement 
16101f551032SValentin Clement       // compute the stride and offset for the next natural dimension
16116c89c531SEric Schweitz       prevDimByteStride = rewriter.create<mlir::LLVM::MulOp>(
16126c89c531SEric Schweitz           loc, i64Ty, prevDimByteStride, outerExtent);
16131f551032SValentin Clement       if (constRows == 0)
16141f551032SValentin Clement         prevPtrOff = rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, prevPtrOff,
16151f551032SValentin Clement                                                         outerExtent);
16160601a0dcSJean Perier       else
16170601a0dcSJean Perier         --constRows;
16181f551032SValentin Clement 
16191f551032SValentin Clement       // increment iterators
16201f551032SValentin Clement       ++shapeOffset;
16211f551032SValentin Clement       if (hasShift)
16221f551032SValentin Clement         ++shiftOffset;
16231f551032SValentin Clement       if (hasSlice)
16241f551032SValentin Clement         sliceOffset += 3;
16251f551032SValentin Clement     }
16266c89c531SEric Schweitz     if (hasSlice || hasSubcomp || hasSubstr) {
162730122656SAlex Zinenko       llvm::SmallVector<mlir::Value> args = {ptrOffset};
16281f551032SValentin Clement       args.append(gepArgs.rbegin(), gepArgs.rend());
16291f551032SValentin Clement       if (hasSubcomp) {
16301f551032SValentin Clement         // For each field in the path add the offset to base via the args list.
16311f551032SValentin Clement         // In the most general case, some offsets must be computed since
16321f551032SValentin Clement         // they are not be known until runtime.
16331f551032SValentin Clement         if (fir::hasDynamicSize(fir::unwrapSequenceType(
16341f551032SValentin Clement                 fir::unwrapPassByRefType(xbox.memref().getType()))))
16351f551032SValentin Clement           TODO(loc, "fir.embox codegen dynamic size component in derived type");
16361f551032SValentin Clement         args.append(operands.begin() + xbox.subcomponentOffset(),
16371f551032SValentin Clement                     operands.begin() + xbox.subcomponentOffset() +
16381f551032SValentin Clement                         xbox.subcomponent().size());
16391f551032SValentin Clement       }
164030122656SAlex Zinenko       base =
164130122656SAlex Zinenko           rewriter.create<mlir::LLVM::GEPOp>(loc, base.getType(), base, args);
16426c89c531SEric Schweitz       if (hasSubstr)
16431f551032SValentin Clement         base = shiftSubstringBase(rewriter, loc, base,
16441f551032SValentin Clement                                   operands[xbox.substrOffset()]);
16451f551032SValentin Clement     }
16461f551032SValentin Clement     dest = insertBaseAddress(rewriter, loc, dest, base);
16471f551032SValentin Clement     if (isDerivedTypeWithLenParams(boxTy))
16481f551032SValentin Clement       TODO(loc, "fir.embox codegen of derived with length parameters");
16491f551032SValentin Clement 
16501f551032SValentin Clement     mlir::Value result = placeInMemoryIfNotGlobalInit(rewriter, loc, dest);
16511f551032SValentin Clement     rewriter.replaceOp(xbox, result);
165244e58509SEric Schweitz     return mlir::success();
16531f551032SValentin Clement   }
1654d3bc3a04SJean Perier 
1655d3bc3a04SJean Perier   /// Return true if `xbox` has a normalized lower bounds attribute. A box value
1656d3bc3a04SJean Perier   /// that is neither a POINTER nor an ALLOCATABLE should be normalized to a
1657d3bc3a04SJean Perier   /// zero origin lower bound for interoperability with BIND(C).
1658d3bc3a04SJean Perier   inline static bool normalizedLowerBound(fir::cg::XEmboxOp xbox) {
1659d3bc3a04SJean Perier     return xbox->hasAttr(fir::getNormalizedLowerBoundAttrName());
1660d3bc3a04SJean Perier   }
16611f551032SValentin Clement };
16621f551032SValentin Clement 
1663fa517555SKiran Chandramohan /// Create a new box given a box reference.
1664fa517555SKiran Chandramohan struct XReboxOpConversion : public EmboxCommonConversion<fir::cg::XReboxOp> {
1665fa517555SKiran Chandramohan   using EmboxCommonConversion::EmboxCommonConversion;
1666fa517555SKiran Chandramohan 
1667fa517555SKiran Chandramohan   mlir::LogicalResult
1668fa517555SKiran Chandramohan   matchAndRewrite(fir::cg::XReboxOp rebox, OpAdaptor adaptor,
1669fa517555SKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
1670fa517555SKiran Chandramohan     mlir::Location loc = rebox.getLoc();
1671fa517555SKiran Chandramohan     mlir::Type idxTy = lowerTy().indexType();
1672fa517555SKiran Chandramohan     mlir::Value loweredBox = adaptor.getOperands()[0];
1673fa517555SKiran Chandramohan     mlir::ValueRange operands = adaptor.getOperands();
1674fa517555SKiran Chandramohan 
1675fa517555SKiran Chandramohan     // Create new descriptor and fill its non-shape related data.
1676fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value, 2> lenParams;
1677fa517555SKiran Chandramohan     mlir::Type inputEleTy = getInputEleTy(rebox);
1678fa517555SKiran Chandramohan     if (auto charTy = inputEleTy.dyn_cast<fir::CharacterType>()) {
1679fa517555SKiran Chandramohan       mlir::Value len =
1680fa517555SKiran Chandramohan           loadElementSizeFromBox(loc, idxTy, loweredBox, rewriter);
1681fa517555SKiran Chandramohan       if (charTy.getFKind() != 1) {
1682fa517555SKiran Chandramohan         mlir::Value width =
1683fa517555SKiran Chandramohan             genConstantIndex(loc, idxTy, rewriter, charTy.getFKind());
1684fa517555SKiran Chandramohan         len = rewriter.create<mlir::LLVM::SDivOp>(loc, idxTy, len, width);
1685fa517555SKiran Chandramohan       }
1686fa517555SKiran Chandramohan       lenParams.emplace_back(len);
1687fa517555SKiran Chandramohan     } else if (auto recTy = inputEleTy.dyn_cast<fir::RecordType>()) {
1688fa517555SKiran Chandramohan       if (recTy.getNumLenParams() != 0)
1689fa517555SKiran Chandramohan         TODO(loc, "reboxing descriptor of derived type with length parameters");
1690fa517555SKiran Chandramohan     }
1691fa517555SKiran Chandramohan     auto [boxTy, dest, eleSize] =
1692fa517555SKiran Chandramohan         consDescriptorPrefix(rebox, rewriter, rebox.getOutRank(), lenParams);
1693fa517555SKiran Chandramohan 
1694fa517555SKiran Chandramohan     // Read input extents, strides, and base address
1695fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> inputExtents;
1696fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> inputStrides;
1697fa517555SKiran Chandramohan     const unsigned inputRank = rebox.getRank();
1698fa517555SKiran Chandramohan     for (unsigned i = 0; i < inputRank; ++i) {
1699fa517555SKiran Chandramohan       mlir::Value dim = genConstantIndex(loc, idxTy, rewriter, i);
170044e58509SEric Schweitz       llvm::SmallVector<mlir::Value, 3> dimInfo =
1701fa517555SKiran Chandramohan           getDimsFromBox(loc, {idxTy, idxTy, idxTy}, loweredBox, dim, rewriter);
1702fa517555SKiran Chandramohan       inputExtents.emplace_back(dimInfo[1]);
1703fa517555SKiran Chandramohan       inputStrides.emplace_back(dimInfo[2]);
1704fa517555SKiran Chandramohan     }
1705fa517555SKiran Chandramohan 
1706fa517555SKiran Chandramohan     mlir::Type baseTy = getBaseAddrTypeFromBox(loweredBox.getType());
1707fa517555SKiran Chandramohan     mlir::Value baseAddr =
1708fa517555SKiran Chandramohan         loadBaseAddrFromBox(loc, baseTy, loweredBox, rewriter);
1709fa517555SKiran Chandramohan 
1710fa517555SKiran Chandramohan     if (!rebox.slice().empty() || !rebox.subcomponent().empty())
1711fa517555SKiran Chandramohan       return sliceBox(rebox, dest, baseAddr, inputExtents, inputStrides,
1712fa517555SKiran Chandramohan                       operands, rewriter);
1713fa517555SKiran Chandramohan     return reshapeBox(rebox, dest, baseAddr, inputExtents, inputStrides,
1714fa517555SKiran Chandramohan                       operands, rewriter);
1715fa517555SKiran Chandramohan   }
1716fa517555SKiran Chandramohan 
1717fa517555SKiran Chandramohan private:
1718fa517555SKiran Chandramohan   /// Write resulting shape and base address in descriptor, and replace rebox
1719fa517555SKiran Chandramohan   /// op.
1720fa517555SKiran Chandramohan   mlir::LogicalResult
1721fa517555SKiran Chandramohan   finalizeRebox(fir::cg::XReboxOp rebox, mlir::Value dest, mlir::Value base,
1722fa517555SKiran Chandramohan                 mlir::ValueRange lbounds, mlir::ValueRange extents,
1723fa517555SKiran Chandramohan                 mlir::ValueRange strides,
1724fa517555SKiran Chandramohan                 mlir::ConversionPatternRewriter &rewriter) const {
1725fa517555SKiran Chandramohan     mlir::Location loc = rebox.getLoc();
1726d3bc3a04SJean Perier     mlir::Value zero =
1727d3bc3a04SJean Perier         genConstantIndex(loc, lowerTy().indexType(), rewriter, 0);
1728fa517555SKiran Chandramohan     mlir::Value one = genConstantIndex(loc, lowerTy().indexType(), rewriter, 1);
1729fa517555SKiran Chandramohan     for (auto iter : llvm::enumerate(llvm::zip(extents, strides))) {
1730d3bc3a04SJean Perier       mlir::Value extent = std::get<0>(iter.value());
1731fa517555SKiran Chandramohan       unsigned dim = iter.index();
1732d3bc3a04SJean Perier       mlir::Value lb = one;
1733d3bc3a04SJean Perier       if (!lbounds.empty()) {
1734d3bc3a04SJean Perier         lb = lbounds[dim];
1735d3bc3a04SJean Perier         auto extentIsEmpty = rewriter.create<mlir::LLVM::ICmpOp>(
1736d3bc3a04SJean Perier             loc, mlir::LLVM::ICmpPredicate::eq, extent, zero);
1737d3bc3a04SJean Perier         lb = rewriter.create<mlir::LLVM::SelectOp>(loc, extentIsEmpty, one, lb);
1738d3bc3a04SJean Perier       };
1739fa517555SKiran Chandramohan       dest = insertLowerBound(rewriter, loc, dest, dim, lb);
1740d3bc3a04SJean Perier       dest = insertExtent(rewriter, loc, dest, dim, extent);
1741fa517555SKiran Chandramohan       dest = insertStride(rewriter, loc, dest, dim, std::get<1>(iter.value()));
1742fa517555SKiran Chandramohan     }
1743fa517555SKiran Chandramohan     dest = insertBaseAddress(rewriter, loc, dest, base);
1744fa517555SKiran Chandramohan     mlir::Value result =
1745fa517555SKiran Chandramohan         placeInMemoryIfNotGlobalInit(rewriter, rebox.getLoc(), dest);
1746fa517555SKiran Chandramohan     rewriter.replaceOp(rebox, result);
174744e58509SEric Schweitz     return mlir::success();
1748fa517555SKiran Chandramohan   }
1749fa517555SKiran Chandramohan 
1750fa517555SKiran Chandramohan   // Apply slice given the base address, extents and strides of the input box.
1751fa517555SKiran Chandramohan   mlir::LogicalResult
1752fa517555SKiran Chandramohan   sliceBox(fir::cg::XReboxOp rebox, mlir::Value dest, mlir::Value base,
1753fa517555SKiran Chandramohan            mlir::ValueRange inputExtents, mlir::ValueRange inputStrides,
1754fa517555SKiran Chandramohan            mlir::ValueRange operands,
1755fa517555SKiran Chandramohan            mlir::ConversionPatternRewriter &rewriter) const {
1756fa517555SKiran Chandramohan     mlir::Location loc = rebox.getLoc();
1757fa517555SKiran Chandramohan     mlir::Type voidPtrTy = ::getVoidPtrType(rebox.getContext());
1758fa517555SKiran Chandramohan     mlir::Type idxTy = lowerTy().indexType();
1759fa517555SKiran Chandramohan     mlir::Value zero = genConstantIndex(loc, idxTy, rewriter, 0);
1760fa517555SKiran Chandramohan     // Apply subcomponent and substring shift on base address.
1761fa517555SKiran Chandramohan     if (!rebox.subcomponent().empty() || !rebox.substr().empty()) {
1762fa517555SKiran Chandramohan       // Cast to inputEleTy* so that a GEP can be used.
1763fa517555SKiran Chandramohan       mlir::Type inputEleTy = getInputEleTy(rebox);
1764fa517555SKiran Chandramohan       auto llvmElePtrTy =
1765fa517555SKiran Chandramohan           mlir::LLVM::LLVMPointerType::get(convertType(inputEleTy));
1766fa517555SKiran Chandramohan       base = rewriter.create<mlir::LLVM::BitcastOp>(loc, llvmElePtrTy, base);
1767fa517555SKiran Chandramohan 
1768fa517555SKiran Chandramohan       if (!rebox.subcomponent().empty()) {
1769fa517555SKiran Chandramohan         llvm::SmallVector<mlir::Value> gepOperands = {zero};
1770fa517555SKiran Chandramohan         for (unsigned i = 0; i < rebox.subcomponent().size(); ++i)
1771fa517555SKiran Chandramohan           gepOperands.push_back(operands[rebox.subcomponentOffset() + i]);
1772fa517555SKiran Chandramohan         base = genGEP(loc, llvmElePtrTy, rewriter, base, gepOperands);
1773fa517555SKiran Chandramohan       }
1774fa517555SKiran Chandramohan       if (!rebox.substr().empty())
1775fa517555SKiran Chandramohan         base = shiftSubstringBase(rewriter, loc, base,
1776fa517555SKiran Chandramohan                                   operands[rebox.substrOffset()]);
1777fa517555SKiran Chandramohan     }
1778fa517555SKiran Chandramohan 
1779fa517555SKiran Chandramohan     if (rebox.slice().empty())
1780fa517555SKiran Chandramohan       // The array section is of the form array[%component][substring], keep
1781fa517555SKiran Chandramohan       // the input array extents and strides.
1782fa517555SKiran Chandramohan       return finalizeRebox(rebox, dest, base, /*lbounds*/ llvm::None,
1783fa517555SKiran Chandramohan                            inputExtents, inputStrides, rewriter);
1784fa517555SKiran Chandramohan 
1785fa517555SKiran Chandramohan     // Strides from the fir.box are in bytes.
1786fa517555SKiran Chandramohan     base = rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, base);
1787fa517555SKiran Chandramohan 
1788fa517555SKiran Chandramohan     // The slice is of the form array(i:j:k)[%component]. Compute new extents
1789fa517555SKiran Chandramohan     // and strides.
1790fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> slicedExtents;
1791fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> slicedStrides;
1792fa517555SKiran Chandramohan     mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1);
1793fa517555SKiran Chandramohan     const bool sliceHasOrigins = !rebox.shift().empty();
1794fa517555SKiran Chandramohan     unsigned sliceOps = rebox.sliceOffset();
1795fa517555SKiran Chandramohan     unsigned shiftOps = rebox.shiftOffset();
1796fa517555SKiran Chandramohan     auto strideOps = inputStrides.begin();
1797fa517555SKiran Chandramohan     const unsigned inputRank = inputStrides.size();
1798fa517555SKiran Chandramohan     for (unsigned i = 0; i < inputRank;
1799fa517555SKiran Chandramohan          ++i, ++strideOps, ++shiftOps, sliceOps += 3) {
1800fa517555SKiran Chandramohan       mlir::Value sliceLb =
1801fa517555SKiran Chandramohan           integerCast(loc, rewriter, idxTy, operands[sliceOps]);
1802fa517555SKiran Chandramohan       mlir::Value inputStride = *strideOps; // already idxTy
1803fa517555SKiran Chandramohan       // Apply origin shift: base += (lb-shift)*input_stride
1804fa517555SKiran Chandramohan       mlir::Value sliceOrigin =
1805fa517555SKiran Chandramohan           sliceHasOrigins
1806fa517555SKiran Chandramohan               ? integerCast(loc, rewriter, idxTy, operands[shiftOps])
1807fa517555SKiran Chandramohan               : one;
1808fa517555SKiran Chandramohan       mlir::Value diff =
1809fa517555SKiran Chandramohan           rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, sliceLb, sliceOrigin);
1810fa517555SKiran Chandramohan       mlir::Value offset =
1811fa517555SKiran Chandramohan           rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, inputStride);
1812fa517555SKiran Chandramohan       base = genGEP(loc, voidPtrTy, rewriter, base, offset);
1813fa517555SKiran Chandramohan       // Apply upper bound and step if this is a triplet. Otherwise, the
1814fa517555SKiran Chandramohan       // dimension is dropped and no extents/strides are computed.
1815fa517555SKiran Chandramohan       mlir::Value upper = operands[sliceOps + 1];
1816fa517555SKiran Chandramohan       const bool isTripletSlice =
1817fa517555SKiran Chandramohan           !mlir::isa_and_nonnull<mlir::LLVM::UndefOp>(upper.getDefiningOp());
1818fa517555SKiran Chandramohan       if (isTripletSlice) {
1819fa517555SKiran Chandramohan         mlir::Value step =
1820fa517555SKiran Chandramohan             integerCast(loc, rewriter, idxTy, operands[sliceOps + 2]);
1821fa517555SKiran Chandramohan         // extent = ub-lb+step/step
1822fa517555SKiran Chandramohan         mlir::Value sliceUb = integerCast(loc, rewriter, idxTy, upper);
1823fa517555SKiran Chandramohan         mlir::Value extent = computeTripletExtent(rewriter, loc, sliceLb,
1824fa517555SKiran Chandramohan                                                   sliceUb, step, zero, idxTy);
1825fa517555SKiran Chandramohan         slicedExtents.emplace_back(extent);
1826fa517555SKiran Chandramohan         // stride = step*input_stride
1827fa517555SKiran Chandramohan         mlir::Value stride =
1828fa517555SKiran Chandramohan             rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, step, inputStride);
1829fa517555SKiran Chandramohan         slicedStrides.emplace_back(stride);
1830fa517555SKiran Chandramohan       }
1831fa517555SKiran Chandramohan     }
1832fa517555SKiran Chandramohan     return finalizeRebox(rebox, dest, base, /*lbounds*/ llvm::None,
1833fa517555SKiran Chandramohan                          slicedExtents, slicedStrides, rewriter);
1834fa517555SKiran Chandramohan   }
1835fa517555SKiran Chandramohan 
1836fa517555SKiran Chandramohan   /// Apply a new shape to the data described by a box given the base address,
1837fa517555SKiran Chandramohan   /// extents and strides of the box.
1838fa517555SKiran Chandramohan   mlir::LogicalResult
1839fa517555SKiran Chandramohan   reshapeBox(fir::cg::XReboxOp rebox, mlir::Value dest, mlir::Value base,
1840fa517555SKiran Chandramohan              mlir::ValueRange inputExtents, mlir::ValueRange inputStrides,
1841fa517555SKiran Chandramohan              mlir::ValueRange operands,
1842fa517555SKiran Chandramohan              mlir::ConversionPatternRewriter &rewriter) const {
1843fa517555SKiran Chandramohan     mlir::ValueRange reboxShifts{operands.begin() + rebox.shiftOffset(),
1844fa517555SKiran Chandramohan                                  operands.begin() + rebox.shiftOffset() +
1845fa517555SKiran Chandramohan                                      rebox.shift().size()};
1846fa517555SKiran Chandramohan     if (rebox.shape().empty()) {
1847fa517555SKiran Chandramohan       // Only setting new lower bounds.
1848fa517555SKiran Chandramohan       return finalizeRebox(rebox, dest, base, reboxShifts, inputExtents,
1849fa517555SKiran Chandramohan                            inputStrides, rewriter);
1850fa517555SKiran Chandramohan     }
1851fa517555SKiran Chandramohan 
1852fa517555SKiran Chandramohan     mlir::Location loc = rebox.getLoc();
1853fa517555SKiran Chandramohan     // Strides from the fir.box are in bytes.
1854fa517555SKiran Chandramohan     mlir::Type voidPtrTy = ::getVoidPtrType(rebox.getContext());
1855fa517555SKiran Chandramohan     base = rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, base);
1856fa517555SKiran Chandramohan 
1857fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> newStrides;
1858fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> newExtents;
1859fa517555SKiran Chandramohan     mlir::Type idxTy = lowerTy().indexType();
1860fa517555SKiran Chandramohan     // First stride from input box is kept. The rest is assumed contiguous
1861fa517555SKiran Chandramohan     // (it is not possible to reshape otherwise). If the input is scalar,
1862fa517555SKiran Chandramohan     // which may be OK if all new extents are ones, the stride does not
1863fa517555SKiran Chandramohan     // matter, use one.
1864fa517555SKiran Chandramohan     mlir::Value stride = inputStrides.empty()
1865fa517555SKiran Chandramohan                              ? genConstantIndex(loc, idxTy, rewriter, 1)
1866fa517555SKiran Chandramohan                              : inputStrides[0];
1867fa517555SKiran Chandramohan     for (unsigned i = 0; i < rebox.shape().size(); ++i) {
1868fa517555SKiran Chandramohan       mlir::Value rawExtent = operands[rebox.shapeOffset() + i];
1869fa517555SKiran Chandramohan       mlir::Value extent = integerCast(loc, rewriter, idxTy, rawExtent);
1870fa517555SKiran Chandramohan       newExtents.emplace_back(extent);
1871fa517555SKiran Chandramohan       newStrides.emplace_back(stride);
1872fa517555SKiran Chandramohan       // nextStride = extent * stride;
1873fa517555SKiran Chandramohan       stride = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, extent, stride);
1874fa517555SKiran Chandramohan     }
1875fa517555SKiran Chandramohan     return finalizeRebox(rebox, dest, base, reboxShifts, newExtents, newStrides,
1876fa517555SKiran Chandramohan                          rewriter);
1877fa517555SKiran Chandramohan   }
1878fa517555SKiran Chandramohan 
1879fa517555SKiran Chandramohan   /// Return scalar element type of the input box.
1880fa517555SKiran Chandramohan   static mlir::Type getInputEleTy(fir::cg::XReboxOp rebox) {
1881fa517555SKiran Chandramohan     auto ty = fir::dyn_cast_ptrOrBoxEleTy(rebox.box().getType());
1882fa517555SKiran Chandramohan     if (auto seqTy = ty.dyn_cast<fir::SequenceType>())
1883fa517555SKiran Chandramohan       return seqTy.getEleTy();
1884fa517555SKiran Chandramohan     return ty;
1885fa517555SKiran Chandramohan   }
1886fa517555SKiran Chandramohan };
1887fa517555SKiran Chandramohan 
1888dc48849fSKiran Chandramohan /// Lower `fir.emboxproc` operation. Creates a procedure box.
1889dc48849fSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
1890dc48849fSKiran Chandramohan struct EmboxProcOpConversion : public FIROpConversion<fir::EmboxProcOp> {
1891dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
1892dc48849fSKiran Chandramohan 
1893dc48849fSKiran Chandramohan   mlir::LogicalResult
1894dc48849fSKiran Chandramohan   matchAndRewrite(fir::EmboxProcOp emboxproc, OpAdaptor adaptor,
1895dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
1896dc48849fSKiran Chandramohan     TODO(emboxproc.getLoc(), "fir.emboxproc codegen");
189744e58509SEric Schweitz     return mlir::failure();
1898dc48849fSKiran Chandramohan   }
1899dc48849fSKiran Chandramohan };
1900dc48849fSKiran Chandramohan 
190154c56347SValentin Clement // Code shared between insert_value and extract_value Ops.
190254c56347SValentin Clement struct ValueOpCommon {
190354c56347SValentin Clement   // Translate the arguments pertaining to any multidimensional array to
190454c56347SValentin Clement   // row-major order for LLVM-IR.
190544e58509SEric Schweitz   static void toRowMajor(llvm::SmallVectorImpl<mlir::Attribute> &attrs,
190654c56347SValentin Clement                          mlir::Type ty) {
190754c56347SValentin Clement     assert(ty && "type is null");
190854c56347SValentin Clement     const auto end = attrs.size();
190954c56347SValentin Clement     for (std::remove_const_t<decltype(end)> i = 0; i < end; ++i) {
191054c56347SValentin Clement       if (auto seq = ty.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
191154c56347SValentin Clement         const auto dim = getDimension(seq);
191254c56347SValentin Clement         if (dim > 1) {
191354c56347SValentin Clement           auto ub = std::min(i + dim, end);
191454c56347SValentin Clement           std::reverse(attrs.begin() + i, attrs.begin() + ub);
191554c56347SValentin Clement           i += dim - 1;
191654c56347SValentin Clement         }
191754c56347SValentin Clement         ty = getArrayElementType(seq);
191854c56347SValentin Clement       } else if (auto st = ty.dyn_cast<mlir::LLVM::LLVMStructType>()) {
191954c56347SValentin Clement         ty = st.getBody()[attrs[i].cast<mlir::IntegerAttr>().getInt()];
192054c56347SValentin Clement       } else {
192154c56347SValentin Clement         llvm_unreachable("index into invalid type");
192254c56347SValentin Clement       }
192354c56347SValentin Clement     }
192454c56347SValentin Clement   }
192554c56347SValentin Clement 
192654c56347SValentin Clement   static llvm::SmallVector<mlir::Attribute>
192754c56347SValentin Clement   collectIndices(mlir::ConversionPatternRewriter &rewriter,
192854c56347SValentin Clement                  mlir::ArrayAttr arrAttr) {
192954c56347SValentin Clement     llvm::SmallVector<mlir::Attribute> attrs;
193054c56347SValentin Clement     for (auto i = arrAttr.begin(), e = arrAttr.end(); i != e; ++i) {
193154c56347SValentin Clement       if (i->isa<mlir::IntegerAttr>()) {
193254c56347SValentin Clement         attrs.push_back(*i);
193354c56347SValentin Clement       } else {
193454c56347SValentin Clement         auto fieldName = i->cast<mlir::StringAttr>().getValue();
193554c56347SValentin Clement         ++i;
193654c56347SValentin Clement         auto ty = i->cast<mlir::TypeAttr>().getValue();
193754c56347SValentin Clement         auto index = ty.cast<fir::RecordType>().getFieldIndex(fieldName);
193854c56347SValentin Clement         attrs.push_back(mlir::IntegerAttr::get(rewriter.getI32Type(), index));
193954c56347SValentin Clement       }
194054c56347SValentin Clement     }
194154c56347SValentin Clement     return attrs;
194254c56347SValentin Clement   }
194354c56347SValentin Clement 
194454c56347SValentin Clement private:
194554c56347SValentin Clement   static mlir::Type getArrayElementType(mlir::LLVM::LLVMArrayType ty) {
194654c56347SValentin Clement     auto eleTy = ty.getElementType();
194754c56347SValentin Clement     while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>())
194854c56347SValentin Clement       eleTy = arrTy.getElementType();
194954c56347SValentin Clement     return eleTy;
195054c56347SValentin Clement   }
195154c56347SValentin Clement };
195254c56347SValentin Clement 
1953c2acd453SAlexisPerry namespace {
195454c56347SValentin Clement /// Extract a subobject value from an ssa-value of aggregate type
195554c56347SValentin Clement struct ExtractValueOpConversion
195654c56347SValentin Clement     : public FIROpAndTypeConversion<fir::ExtractValueOp>,
195754c56347SValentin Clement       public ValueOpCommon {
195854c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
195954c56347SValentin Clement 
196054c56347SValentin Clement   mlir::LogicalResult
196154c56347SValentin Clement   doRewrite(fir::ExtractValueOp extractVal, mlir::Type ty, OpAdaptor adaptor,
196254c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
196312d26ce9SValentin Clement     mlir::ValueRange operands = adaptor.getOperands();
1964149ad3d5SShraiysh Vaishay     auto attrs = collectIndices(rewriter, extractVal.getCoor());
196512d26ce9SValentin Clement     toRowMajor(attrs, operands[0].getType());
196654c56347SValentin Clement     auto position = mlir::ArrayAttr::get(extractVal.getContext(), attrs);
196754c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(
196812d26ce9SValentin Clement         extractVal, ty, operands[0], position);
196944e58509SEric Schweitz     return mlir::success();
197054c56347SValentin Clement   }
197154c56347SValentin Clement };
197254c56347SValentin Clement 
197354c56347SValentin Clement /// InsertValue is the generalized instruction for the composition of new
197454c56347SValentin Clement /// aggregate type values.
197554c56347SValentin Clement struct InsertValueOpConversion
197654c56347SValentin Clement     : public FIROpAndTypeConversion<fir::InsertValueOp>,
197754c56347SValentin Clement       public ValueOpCommon {
197854c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
197954c56347SValentin Clement 
198054c56347SValentin Clement   mlir::LogicalResult
198154c56347SValentin Clement   doRewrite(fir::InsertValueOp insertVal, mlir::Type ty, OpAdaptor adaptor,
198254c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
198312d26ce9SValentin Clement     mlir::ValueRange operands = adaptor.getOperands();
1984149ad3d5SShraiysh Vaishay     auto attrs = collectIndices(rewriter, insertVal.getCoor());
198512d26ce9SValentin Clement     toRowMajor(attrs, operands[0].getType());
198654c56347SValentin Clement     auto position = mlir::ArrayAttr::get(insertVal.getContext(), attrs);
198754c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
198812d26ce9SValentin Clement         insertVal, ty, operands[0], operands[1], position);
198944e58509SEric Schweitz     return mlir::success();
199054c56347SValentin Clement   }
199154c56347SValentin Clement };
199254c56347SValentin Clement 
19933ae8e442SValentin Clement /// InsertOnRange inserts a value into a sequence over a range of offsets.
19943ae8e442SValentin Clement struct InsertOnRangeOpConversion
19953ae8e442SValentin Clement     : public FIROpAndTypeConversion<fir::InsertOnRangeOp> {
19963ae8e442SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
19973ae8e442SValentin Clement 
19983ae8e442SValentin Clement   // Increments an array of subscripts in a row major fasion.
199944e58509SEric Schweitz   void incrementSubscripts(const llvm::SmallVector<uint64_t> &dims,
200044e58509SEric Schweitz                            llvm::SmallVector<uint64_t> &subscripts) const {
20013ae8e442SValentin Clement     for (size_t i = dims.size(); i > 0; --i) {
20023ae8e442SValentin Clement       if (++subscripts[i - 1] < dims[i - 1]) {
20033ae8e442SValentin Clement         return;
20043ae8e442SValentin Clement       }
20053ae8e442SValentin Clement       subscripts[i - 1] = 0;
20063ae8e442SValentin Clement     }
20073ae8e442SValentin Clement   }
20083ae8e442SValentin Clement 
20093ae8e442SValentin Clement   mlir::LogicalResult
20103ae8e442SValentin Clement   doRewrite(fir::InsertOnRangeOp range, mlir::Type ty, OpAdaptor adaptor,
20113ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
20123ae8e442SValentin Clement 
20133ae8e442SValentin Clement     llvm::SmallVector<uint64_t> dims;
20143ae8e442SValentin Clement     auto type = adaptor.getOperands()[0].getType();
20153ae8e442SValentin Clement 
20163ae8e442SValentin Clement     // Iteratively extract the array dimensions from the type.
20173ae8e442SValentin Clement     while (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
20183ae8e442SValentin Clement       dims.push_back(t.getNumElements());
20193ae8e442SValentin Clement       type = t.getElementType();
20203ae8e442SValentin Clement     }
20213ae8e442SValentin Clement 
2022575c9d6dSValentin Clement     llvm::SmallVector<std::uint64_t> lBounds;
2023575c9d6dSValentin Clement     llvm::SmallVector<std::uint64_t> uBounds;
20243ae8e442SValentin Clement 
20253ae8e442SValentin Clement     // Unzip the upper and lower bound and convert to a row major format.
2026149ad3d5SShraiysh Vaishay     mlir::DenseIntElementsAttr coor = range.getCoor();
20278ec0f221SMehdi Amini     auto reversedCoor = llvm::reverse(coor.getValues<int64_t>());
20288ec0f221SMehdi Amini     for (auto i = reversedCoor.begin(), e = reversedCoor.end(); i != e; ++i) {
20293ae8e442SValentin Clement       uBounds.push_back(*i++);
20303ae8e442SValentin Clement       lBounds.push_back(*i);
20313ae8e442SValentin Clement     }
20323ae8e442SValentin Clement 
20333ae8e442SValentin Clement     auto &subscripts = lBounds;
20343ae8e442SValentin Clement     auto loc = range.getLoc();
20353ae8e442SValentin Clement     mlir::Value lastOp = adaptor.getOperands()[0];
20363ae8e442SValentin Clement     mlir::Value insertVal = adaptor.getOperands()[1];
20373ae8e442SValentin Clement 
20383ae8e442SValentin Clement     auto i64Ty = rewriter.getI64Type();
20393ae8e442SValentin Clement     while (subscripts != uBounds) {
20403ae8e442SValentin Clement       // Convert uint64_t's to Attribute's.
204144e58509SEric Schweitz       llvm::SmallVector<mlir::Attribute> subscriptAttrs;
20423ae8e442SValentin Clement       for (const auto &subscript : subscripts)
204344e58509SEric Schweitz         subscriptAttrs.push_back(mlir::IntegerAttr::get(i64Ty, subscript));
20443ae8e442SValentin Clement       lastOp = rewriter.create<mlir::LLVM::InsertValueOp>(
20453ae8e442SValentin Clement           loc, ty, lastOp, insertVal,
204644e58509SEric Schweitz           mlir::ArrayAttr::get(range.getContext(), subscriptAttrs));
20473ae8e442SValentin Clement 
20483ae8e442SValentin Clement       incrementSubscripts(dims, subscripts);
20493ae8e442SValentin Clement     }
20503ae8e442SValentin Clement 
20513ae8e442SValentin Clement     // Convert uint64_t's to Attribute's.
205244e58509SEric Schweitz     llvm::SmallVector<mlir::Attribute> subscriptAttrs;
20533ae8e442SValentin Clement     for (const auto &subscript : subscripts)
20543ae8e442SValentin Clement       subscriptAttrs.push_back(
205544e58509SEric Schweitz           mlir::IntegerAttr::get(rewriter.getI64Type(), subscript));
20563ae8e442SValentin Clement     mlir::ArrayRef<mlir::Attribute> arrayRef(subscriptAttrs);
20573ae8e442SValentin Clement 
20583ae8e442SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
20593ae8e442SValentin Clement         range, ty, lastOp, insertVal,
206044e58509SEric Schweitz         mlir::ArrayAttr::get(range.getContext(), arrayRef));
20613ae8e442SValentin Clement 
206244e58509SEric Schweitz     return mlir::success();
20633ae8e442SValentin Clement   }
20643ae8e442SValentin Clement };
2065c2acd453SAlexisPerry } // namespace
20667b5132daSValentin Clement 
2067dc48849fSKiran Chandramohan namespace {
20685d27abe6SValentin Clement /// XArrayCoor is the address arithmetic on a dynamically shaped, sliced,
20695d27abe6SValentin Clement /// shifted etc. array.
20705d27abe6SValentin Clement /// (See the static restriction on coordinate_of.) array_coor determines the
20715d27abe6SValentin Clement /// coordinate (location) of a specific element.
20725d27abe6SValentin Clement struct XArrayCoorOpConversion
20735d27abe6SValentin Clement     : public FIROpAndTypeConversion<fir::cg::XArrayCoorOp> {
20745d27abe6SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
20755d27abe6SValentin Clement 
20765d27abe6SValentin Clement   mlir::LogicalResult
20775d27abe6SValentin Clement   doRewrite(fir::cg::XArrayCoorOp coor, mlir::Type ty, OpAdaptor adaptor,
20785d27abe6SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
20795d27abe6SValentin Clement     auto loc = coor.getLoc();
20805d27abe6SValentin Clement     mlir::ValueRange operands = adaptor.getOperands();
20815d27abe6SValentin Clement     unsigned rank = coor.getRank();
20825d27abe6SValentin Clement     assert(coor.indices().size() == rank);
20835d27abe6SValentin Clement     assert(coor.shape().empty() || coor.shape().size() == rank);
20845d27abe6SValentin Clement     assert(coor.shift().empty() || coor.shift().size() == rank);
20855d27abe6SValentin Clement     assert(coor.slice().empty() || coor.slice().size() == 3 * rank);
20865d27abe6SValentin Clement     mlir::Type idxTy = lowerTy().indexType();
2087914b9eecSKiran Chandramohan     unsigned indexOffset = coor.indicesOffset();
2088914b9eecSKiran Chandramohan     unsigned shapeOffset = coor.shapeOffset();
2089914b9eecSKiran Chandramohan     unsigned shiftOffset = coor.shiftOffset();
2090914b9eecSKiran Chandramohan     unsigned sliceOffset = coor.sliceOffset();
2091914b9eecSKiran Chandramohan     auto sliceOps = coor.slice().begin();
20925d27abe6SValentin Clement     mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1);
20935d27abe6SValentin Clement     mlir::Value prevExt = one;
20945d27abe6SValentin Clement     mlir::Value zero = genConstantIndex(loc, idxTy, rewriter, 0);
20955d27abe6SValentin Clement     mlir::Value offset = zero;
20965d27abe6SValentin Clement     const bool isShifted = !coor.shift().empty();
20975d27abe6SValentin Clement     const bool isSliced = !coor.slice().empty();
20985d27abe6SValentin Clement     const bool baseIsBoxed = coor.memref().getType().isa<fir::BoxType>();
20995d27abe6SValentin Clement 
21005d27abe6SValentin Clement     // For each dimension of the array, generate the offset calculation.
2101914b9eecSKiran Chandramohan     for (unsigned i = 0; i < rank; ++i, ++indexOffset, ++shapeOffset,
2102914b9eecSKiran Chandramohan                   ++shiftOffset, sliceOffset += 3, sliceOps += 3) {
21035d27abe6SValentin Clement       mlir::Value index =
2104914b9eecSKiran Chandramohan           integerCast(loc, rewriter, idxTy, operands[indexOffset]);
2105914b9eecSKiran Chandramohan       mlir::Value lb =
2106914b9eecSKiran Chandramohan           isShifted ? integerCast(loc, rewriter, idxTy, operands[shiftOffset])
21075d27abe6SValentin Clement                     : one;
21085d27abe6SValentin Clement       mlir::Value step = one;
21095d27abe6SValentin Clement       bool normalSlice = isSliced;
21105d27abe6SValentin Clement       // Compute zero based index in dimension i of the element, applying
21115d27abe6SValentin Clement       // potential triplets and lower bounds.
21125d27abe6SValentin Clement       if (isSliced) {
2113914b9eecSKiran Chandramohan         mlir::Value originalUb = *(sliceOps + 1);
2114914b9eecSKiran Chandramohan         normalSlice =
2115914b9eecSKiran Chandramohan             !mlir::isa_and_nonnull<fir::UndefOp>(originalUb.getDefiningOp());
21165d27abe6SValentin Clement         if (normalSlice)
2117914b9eecSKiran Chandramohan           step = integerCast(loc, rewriter, idxTy, operands[sliceOffset + 2]);
21185d27abe6SValentin Clement       }
21195d27abe6SValentin Clement       auto idx = rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, index, lb);
21205d27abe6SValentin Clement       mlir::Value diff =
21215d27abe6SValentin Clement           rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, idx, step);
21225d27abe6SValentin Clement       if (normalSlice) {
21235d27abe6SValentin Clement         mlir::Value sliceLb =
2124914b9eecSKiran Chandramohan             integerCast(loc, rewriter, idxTy, operands[sliceOffset]);
21255d27abe6SValentin Clement         auto adj = rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, sliceLb, lb);
21265d27abe6SValentin Clement         diff = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, diff, adj);
21275d27abe6SValentin Clement       }
21285d27abe6SValentin Clement       // Update the offset given the stride and the zero based index `diff`
21295d27abe6SValentin Clement       // that was just computed.
21305d27abe6SValentin Clement       if (baseIsBoxed) {
21315d27abe6SValentin Clement         // Use stride in bytes from the descriptor.
213212d26ce9SValentin Clement         mlir::Value stride = loadStrideFromBox(loc, operands[0], i, rewriter);
21335d27abe6SValentin Clement         auto sc = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, stride);
21345d27abe6SValentin Clement         offset = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, offset);
21355d27abe6SValentin Clement       } else {
21365d27abe6SValentin Clement         // Use stride computed at last iteration.
21375d27abe6SValentin Clement         auto sc = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, prevExt);
21385d27abe6SValentin Clement         offset = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, offset);
21395d27abe6SValentin Clement         // Compute next stride assuming contiguity of the base array
21405d27abe6SValentin Clement         // (in element number).
2141914b9eecSKiran Chandramohan         auto nextExt = integerCast(loc, rewriter, idxTy, operands[shapeOffset]);
21425d27abe6SValentin Clement         prevExt =
21435d27abe6SValentin Clement             rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, prevExt, nextExt);
21445d27abe6SValentin Clement       }
21455d27abe6SValentin Clement     }
21465d27abe6SValentin Clement 
21475d27abe6SValentin Clement     // Add computed offset to the base address.
21485d27abe6SValentin Clement     if (baseIsBoxed) {
21495d27abe6SValentin Clement       // Working with byte offsets. The base address is read from the fir.box.
21505d27abe6SValentin Clement       // and need to be casted to i8* to do the pointer arithmetic.
215112d26ce9SValentin Clement       mlir::Type baseTy = getBaseAddrTypeFromBox(operands[0].getType());
21525d27abe6SValentin Clement       mlir::Value base =
215312d26ce9SValentin Clement           loadBaseAddrFromBox(loc, baseTy, operands[0], rewriter);
21545d27abe6SValentin Clement       mlir::Type voidPtrTy = getVoidPtrType();
21555d27abe6SValentin Clement       base = rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, base);
215630122656SAlex Zinenko       llvm::SmallVector<mlir::Value> args{offset};
215730122656SAlex Zinenko       auto addr =
215830122656SAlex Zinenko           rewriter.create<mlir::LLVM::GEPOp>(loc, voidPtrTy, base, args);
21595d27abe6SValentin Clement       if (coor.subcomponent().empty()) {
216012d26ce9SValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(coor, ty, addr);
216144e58509SEric Schweitz         return mlir::success();
21625d27abe6SValentin Clement       }
21635d27abe6SValentin Clement       auto casted = rewriter.create<mlir::LLVM::BitcastOp>(loc, baseTy, addr);
21645d27abe6SValentin Clement       args.clear();
21655d27abe6SValentin Clement       args.push_back(zero);
21665d27abe6SValentin Clement       if (!coor.lenParams().empty()) {
21675d27abe6SValentin Clement         // If type parameters are present, then we don't want to use a GEPOp
21685d27abe6SValentin Clement         // as below, as the LLVM struct type cannot be statically defined.
21695d27abe6SValentin Clement         TODO(loc, "derived type with type parameters");
21705d27abe6SValentin Clement       }
21715d27abe6SValentin Clement       // TODO: array offset subcomponents must be converted to LLVM's
21725d27abe6SValentin Clement       // row-major layout here.
21735d27abe6SValentin Clement       for (auto i = coor.subcomponentOffset(); i != coor.indicesOffset(); ++i)
21745d27abe6SValentin Clement         args.push_back(operands[i]);
217512d26ce9SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(coor, ty, casted, args);
217644e58509SEric Schweitz       return mlir::success();
21775d27abe6SValentin Clement     }
21785d27abe6SValentin Clement 
21795d27abe6SValentin Clement     // The array was not boxed, so it must be contiguous. offset is therefore an
21805d27abe6SValentin Clement     // element offset and the base type is kept in the GEP unless the element
21815d27abe6SValentin Clement     // type size is itself dynamic.
21825d27abe6SValentin Clement     mlir::Value base;
21835d27abe6SValentin Clement     if (coor.subcomponent().empty()) {
21845d27abe6SValentin Clement       // No subcomponent.
21855d27abe6SValentin Clement       if (!coor.lenParams().empty()) {
21865d27abe6SValentin Clement         // Type parameters. Adjust element size explicitly.
21875d27abe6SValentin Clement         auto eleTy = fir::dyn_cast_ptrEleTy(coor.getType());
21885d27abe6SValentin Clement         assert(eleTy && "result must be a reference-like type");
21895d27abe6SValentin Clement         if (fir::characterWithDynamicLen(eleTy)) {
21905d27abe6SValentin Clement           assert(coor.lenParams().size() == 1);
2191649439e7SValentin Clement           auto length = integerCast(loc, rewriter, idxTy,
2192649439e7SValentin Clement                                     operands[coor.lenParamsOffset()]);
2193649439e7SValentin Clement           offset =
2194649439e7SValentin Clement               rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, offset, length);
21955d27abe6SValentin Clement         } else {
21965d27abe6SValentin Clement           TODO(loc, "compute size of derived type with type parameters");
21975d27abe6SValentin Clement         }
21985d27abe6SValentin Clement       }
21995d27abe6SValentin Clement       // Cast the base address to a pointer to T.
220012d26ce9SValentin Clement       base = rewriter.create<mlir::LLVM::BitcastOp>(loc, ty, operands[0]);
22015d27abe6SValentin Clement     } else {
22025d27abe6SValentin Clement       // Operand #0 must have a pointer type. For subcomponent slicing, we
22035d27abe6SValentin Clement       // want to cast away the array type and have a plain struct type.
220412d26ce9SValentin Clement       mlir::Type ty0 = operands[0].getType();
22055d27abe6SValentin Clement       auto ptrTy = ty0.dyn_cast<mlir::LLVM::LLVMPointerType>();
22065d27abe6SValentin Clement       assert(ptrTy && "expected pointer type");
22075d27abe6SValentin Clement       mlir::Type eleTy = ptrTy.getElementType();
22085d27abe6SValentin Clement       while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>())
22095d27abe6SValentin Clement         eleTy = arrTy.getElementType();
22105d27abe6SValentin Clement       auto newTy = mlir::LLVM::LLVMPointerType::get(eleTy);
221112d26ce9SValentin Clement       base = rewriter.create<mlir::LLVM::BitcastOp>(loc, newTy, operands[0]);
22125d27abe6SValentin Clement     }
221344e58509SEric Schweitz     llvm::SmallVector<mlir::Value> args = {offset};
22145d27abe6SValentin Clement     for (auto i = coor.subcomponentOffset(); i != coor.indicesOffset(); ++i)
22155d27abe6SValentin Clement       args.push_back(operands[i]);
221630122656SAlex Zinenko     rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(coor, ty, base, args);
221744e58509SEric Schweitz     return mlir::success();
22185d27abe6SValentin Clement   }
22195d27abe6SValentin Clement };
2220dc48849fSKiran Chandramohan } // namespace
2221dc48849fSKiran Chandramohan 
2222dc48849fSKiran Chandramohan /// Convert to (memory) reference to a reference to a subobject.
2223dc48849fSKiran Chandramohan /// The coordinate_of op is a Swiss army knife operation that can be used on
2224dc48849fSKiran Chandramohan /// (memory) references to records, arrays, complex, etc. as well as boxes.
2225dc48849fSKiran Chandramohan /// With unboxed arrays, there is the restriction that the array have a static
2226dc48849fSKiran Chandramohan /// shape in all but the last column.
2227dc48849fSKiran Chandramohan struct CoordinateOpConversion
2228dc48849fSKiran Chandramohan     : public FIROpAndTypeConversion<fir::CoordinateOp> {
2229dc48849fSKiran Chandramohan   using FIROpAndTypeConversion::FIROpAndTypeConversion;
2230dc48849fSKiran Chandramohan 
2231dc48849fSKiran Chandramohan   mlir::LogicalResult
2232dc48849fSKiran Chandramohan   doRewrite(fir::CoordinateOp coor, mlir::Type ty, OpAdaptor adaptor,
2233dc48849fSKiran Chandramohan             mlir::ConversionPatternRewriter &rewriter) const override {
2234dc48849fSKiran Chandramohan     mlir::ValueRange operands = adaptor.getOperands();
2235dc48849fSKiran Chandramohan 
2236dc48849fSKiran Chandramohan     mlir::Location loc = coor.getLoc();
2237dc48849fSKiran Chandramohan     mlir::Value base = operands[0];
2238dc48849fSKiran Chandramohan     mlir::Type baseObjectTy = coor.getBaseType();
2239dc48849fSKiran Chandramohan     mlir::Type objectTy = fir::dyn_cast_ptrOrBoxEleTy(baseObjectTy);
2240dc48849fSKiran Chandramohan     assert(objectTy && "fir.coordinate_of expects a reference type");
2241dc48849fSKiran Chandramohan 
2242dc48849fSKiran Chandramohan     // Complex type - basically, extract the real or imaginary part
2243dc48849fSKiran Chandramohan     if (fir::isa_complex(objectTy)) {
2244dc48849fSKiran Chandramohan       mlir::LLVM::ConstantOp c0 =
2245dc48849fSKiran Chandramohan           genConstantIndex(loc, lowerTy().indexType(), rewriter, 0);
224603efa5a3SAndrzej Warzynski       llvm::SmallVector<mlir::Value> offs = {c0, operands[1]};
2247dc48849fSKiran Chandramohan       mlir::Value gep = genGEP(loc, ty, rewriter, base, offs);
2248dc48849fSKiran Chandramohan       rewriter.replaceOp(coor, gep);
224944e58509SEric Schweitz       return mlir::success();
2250dc48849fSKiran Chandramohan     }
2251dc48849fSKiran Chandramohan 
2252dc48849fSKiran Chandramohan     // Boxed type - get the base pointer from the box
2253dc48849fSKiran Chandramohan     if (baseObjectTy.dyn_cast<fir::BoxType>())
2254dc48849fSKiran Chandramohan       return doRewriteBox(coor, ty, operands, loc, rewriter);
2255dc48849fSKiran Chandramohan 
225603efa5a3SAndrzej Warzynski     // Reference, pointer or a heap type
225703efa5a3SAndrzej Warzynski     if (baseObjectTy.isa<fir::ReferenceType, fir::PointerType, fir::HeapType>())
2258dc48849fSKiran Chandramohan       return doRewriteRefOrPtr(coor, ty, operands, loc, rewriter);
2259dc48849fSKiran Chandramohan 
2260dc48849fSKiran Chandramohan     return rewriter.notifyMatchFailure(
2261dc48849fSKiran Chandramohan         coor, "fir.coordinate_of base operand has unsupported type");
2262dc48849fSKiran Chandramohan   }
2263dc48849fSKiran Chandramohan 
226403efa5a3SAndrzej Warzynski   static unsigned getFieldNumber(fir::RecordType ty, mlir::Value op) {
2265dc48849fSKiran Chandramohan     return fir::hasDynamicSize(ty)
2266dc48849fSKiran Chandramohan                ? op.getDefiningOp()
2267dc48849fSKiran Chandramohan                      ->getAttrOfType<mlir::IntegerAttr>("field")
2268dc48849fSKiran Chandramohan                      .getInt()
2269dc48849fSKiran Chandramohan                : getIntValue(op);
2270dc48849fSKiran Chandramohan   }
2271dc48849fSKiran Chandramohan 
227203efa5a3SAndrzej Warzynski   static int64_t getIntValue(mlir::Value val) {
2273dc48849fSKiran Chandramohan     assert(val && val.dyn_cast<mlir::OpResult>() && "must not be null value");
2274dc48849fSKiran Chandramohan     mlir::Operation *defop = val.getDefiningOp();
2275dc48849fSKiran Chandramohan 
227644e58509SEric Schweitz     if (auto constOp = mlir::dyn_cast<mlir::arith::ConstantIntOp>(defop))
2277dc48849fSKiran Chandramohan       return constOp.value();
227844e58509SEric Schweitz     if (auto llConstOp = mlir::dyn_cast<mlir::LLVM::ConstantOp>(defop))
2279dc48849fSKiran Chandramohan       if (auto attr = llConstOp.getValue().dyn_cast<mlir::IntegerAttr>())
2280dc48849fSKiran Chandramohan         return attr.getValue().getSExtValue();
2281dc48849fSKiran Chandramohan     fir::emitFatalError(val.getLoc(), "must be a constant");
2282dc48849fSKiran Chandramohan   }
2283dc48849fSKiran Chandramohan 
228403efa5a3SAndrzej Warzynski   static bool hasSubDimensions(mlir::Type type) {
2285dc48849fSKiran Chandramohan     return type.isa<fir::SequenceType, fir::RecordType, mlir::TupleType>();
2286dc48849fSKiran Chandramohan   }
2287dc48849fSKiran Chandramohan 
2288dc48849fSKiran Chandramohan   /// Check whether this form of `!fir.coordinate_of` is supported. These
2289dc48849fSKiran Chandramohan   /// additional checks are required, because we are not yet able to convert
2290dc48849fSKiran Chandramohan   /// all valid forms of `!fir.coordinate_of`.
2291dc48849fSKiran Chandramohan   /// TODO: Either implement the unsupported cases or extend the verifier
2292dc48849fSKiran Chandramohan   /// in FIROps.cpp instead.
229303efa5a3SAndrzej Warzynski   static bool supportedCoordinate(mlir::Type type, mlir::ValueRange coors) {
2294dc48849fSKiran Chandramohan     const std::size_t numOfCoors = coors.size();
2295dc48849fSKiran Chandramohan     std::size_t i = 0;
2296dc48849fSKiran Chandramohan     bool subEle = false;
2297dc48849fSKiran Chandramohan     bool ptrEle = false;
2298dc48849fSKiran Chandramohan     for (; i < numOfCoors; ++i) {
2299dc48849fSKiran Chandramohan       mlir::Value nxtOpnd = coors[i];
2300dc48849fSKiran Chandramohan       if (auto arrTy = type.dyn_cast<fir::SequenceType>()) {
2301dc48849fSKiran Chandramohan         subEle = true;
2302dc48849fSKiran Chandramohan         i += arrTy.getDimension() - 1;
2303dc48849fSKiran Chandramohan         type = arrTy.getEleTy();
2304dc48849fSKiran Chandramohan       } else if (auto recTy = type.dyn_cast<fir::RecordType>()) {
2305dc48849fSKiran Chandramohan         subEle = true;
2306dc48849fSKiran Chandramohan         type = recTy.getType(getFieldNumber(recTy, nxtOpnd));
2307dc48849fSKiran Chandramohan       } else if (auto tupTy = type.dyn_cast<mlir::TupleType>()) {
2308dc48849fSKiran Chandramohan         subEle = true;
2309dc48849fSKiran Chandramohan         type = tupTy.getType(getIntValue(nxtOpnd));
2310dc48849fSKiran Chandramohan       } else {
2311dc48849fSKiran Chandramohan         ptrEle = true;
2312dc48849fSKiran Chandramohan       }
2313dc48849fSKiran Chandramohan     }
2314dc48849fSKiran Chandramohan     if (ptrEle)
2315dc48849fSKiran Chandramohan       return (!subEle) && (numOfCoors == 1);
2316dc48849fSKiran Chandramohan     return subEle && (i >= numOfCoors);
2317dc48849fSKiran Chandramohan   }
2318dc48849fSKiran Chandramohan 
2319dc48849fSKiran Chandramohan   /// Walk the abstract memory layout and determine if the path traverses any
2320dc48849fSKiran Chandramohan   /// array types with unknown shape. Return true iff all the array types have a
2321dc48849fSKiran Chandramohan   /// constant shape along the path.
232203efa5a3SAndrzej Warzynski   static bool arraysHaveKnownShape(mlir::Type type, mlir::ValueRange coors) {
232303efa5a3SAndrzej Warzynski     for (std::size_t i = 0, sz = coors.size(); i < sz; ++i) {
2324dc48849fSKiran Chandramohan       mlir::Value nxtOpnd = coors[i];
2325dc48849fSKiran Chandramohan       if (auto arrTy = type.dyn_cast<fir::SequenceType>()) {
2326dc48849fSKiran Chandramohan         if (fir::sequenceWithNonConstantShape(arrTy))
2327dc48849fSKiran Chandramohan           return false;
2328dc48849fSKiran Chandramohan         i += arrTy.getDimension() - 1;
2329dc48849fSKiran Chandramohan         type = arrTy.getEleTy();
2330dc48849fSKiran Chandramohan       } else if (auto strTy = type.dyn_cast<fir::RecordType>()) {
2331dc48849fSKiran Chandramohan         type = strTy.getType(getFieldNumber(strTy, nxtOpnd));
2332dc48849fSKiran Chandramohan       } else if (auto strTy = type.dyn_cast<mlir::TupleType>()) {
2333dc48849fSKiran Chandramohan         type = strTy.getType(getIntValue(nxtOpnd));
2334dc48849fSKiran Chandramohan       } else {
2335dc48849fSKiran Chandramohan         return true;
2336dc48849fSKiran Chandramohan       }
2337dc48849fSKiran Chandramohan     }
2338dc48849fSKiran Chandramohan     return true;
2339dc48849fSKiran Chandramohan   }
2340dc48849fSKiran Chandramohan 
2341dc48849fSKiran Chandramohan private:
2342dc48849fSKiran Chandramohan   mlir::LogicalResult
2343dc48849fSKiran Chandramohan   doRewriteBox(fir::CoordinateOp coor, mlir::Type ty, mlir::ValueRange operands,
2344dc48849fSKiran Chandramohan                mlir::Location loc,
2345dc48849fSKiran Chandramohan                mlir::ConversionPatternRewriter &rewriter) const {
2346dc48849fSKiran Chandramohan     mlir::Type boxObjTy = coor.getBaseType();
2347dc48849fSKiran Chandramohan     assert(boxObjTy.dyn_cast<fir::BoxType>() && "This is not a `fir.box`");
2348dc48849fSKiran Chandramohan 
2349dc48849fSKiran Chandramohan     mlir::Value boxBaseAddr = operands[0];
2350dc48849fSKiran Chandramohan 
2351dc48849fSKiran Chandramohan     // 1. SPECIAL CASE (uses `fir.len_param_index`):
2352dc48849fSKiran Chandramohan     //   %box = ... : !fir.box<!fir.type<derived{len1:i32}>>
2353dc48849fSKiran Chandramohan     //   %lenp = fir.len_param_index len1, !fir.type<derived{len1:i32}>
2354dc48849fSKiran Chandramohan     //   %addr = coordinate_of %box, %lenp
2355dc48849fSKiran Chandramohan     if (coor.getNumOperands() == 2) {
2356dc48849fSKiran Chandramohan       mlir::Operation *coordinateDef =
2357dc48849fSKiran Chandramohan           (*coor.getCoor().begin()).getDefiningOp();
235844e58509SEric Schweitz       if (mlir::isa_and_nonnull<fir::LenParamIndexOp>(coordinateDef))
2359dc48849fSKiran Chandramohan         TODO(loc,
2360dc48849fSKiran Chandramohan              "fir.coordinate_of - fir.len_param_index is not supported yet");
2361dc48849fSKiran Chandramohan     }
2362dc48849fSKiran Chandramohan 
2363dc48849fSKiran Chandramohan     // 2. GENERAL CASE:
2364dc48849fSKiran Chandramohan     // 2.1. (`fir.array`)
2365dc48849fSKiran Chandramohan     //   %box = ... : !fix.box<!fir.array<?xU>>
2366dc48849fSKiran Chandramohan     //   %idx = ... : index
2367dc48849fSKiran Chandramohan     //   %resultAddr = coordinate_of %box, %idx : !fir.ref<U>
2368dc48849fSKiran Chandramohan     // 2.2 (`fir.derived`)
2369dc48849fSKiran Chandramohan     //   %box = ... : !fix.box<!fir.type<derived_type{field_1:i32}>>
2370dc48849fSKiran Chandramohan     //   %idx = ... : i32
2371dc48849fSKiran Chandramohan     //   %resultAddr = coordinate_of %box, %idx : !fir.ref<i32>
2372dc48849fSKiran Chandramohan     // 2.3 (`fir.derived` inside `fir.array`)
2373dc48849fSKiran Chandramohan     //   %box = ... : !fir.box<!fir.array<10 x !fir.type<derived_1{field_1:f32,
2374dc48849fSKiran Chandramohan     //   field_2:f32}>>> %idx1 = ... : index %idx2 = ... : i32 %resultAddr =
2375dc48849fSKiran Chandramohan     //   coordinate_of %box, %idx1, %idx2 : !fir.ref<f32>
2376dc48849fSKiran Chandramohan     // 2.4. TODO: Either document or disable any other case that the following
2377dc48849fSKiran Chandramohan     //  implementation might convert.
2378dc48849fSKiran Chandramohan     mlir::LLVM::ConstantOp c0 =
2379dc48849fSKiran Chandramohan         genConstantIndex(loc, lowerTy().indexType(), rewriter, 0);
2380dc48849fSKiran Chandramohan     mlir::Value resultAddr =
2381dc48849fSKiran Chandramohan         loadBaseAddrFromBox(loc, getBaseAddrTypeFromBox(boxBaseAddr.getType()),
2382dc48849fSKiran Chandramohan                             boxBaseAddr, rewriter);
238303efa5a3SAndrzej Warzynski     // Component Type
238403efa5a3SAndrzej Warzynski     auto cpnTy = fir::dyn_cast_ptrOrBoxEleTy(boxObjTy);
2385dc48849fSKiran Chandramohan     mlir::Type voidPtrTy = ::getVoidPtrType(coor.getContext());
2386dc48849fSKiran Chandramohan 
2387dc48849fSKiran Chandramohan     for (unsigned i = 1, last = operands.size(); i < last; ++i) {
238803efa5a3SAndrzej Warzynski       if (auto arrTy = cpnTy.dyn_cast<fir::SequenceType>()) {
2389dc48849fSKiran Chandramohan         if (i != 1)
2390dc48849fSKiran Chandramohan           TODO(loc, "fir.array nested inside other array and/or derived type");
2391dc48849fSKiran Chandramohan         // Applies byte strides from the box. Ignore lower bound from box
2392dc48849fSKiran Chandramohan         // since fir.coordinate_of indexes are zero based. Lowering takes care
2393dc48849fSKiran Chandramohan         // of lower bound aspects. This both accounts for dynamically sized
2394dc48849fSKiran Chandramohan         // types and non contiguous arrays.
2395dc48849fSKiran Chandramohan         auto idxTy = lowerTy().indexType();
2396dc48849fSKiran Chandramohan         mlir::Value off = genConstantIndex(loc, idxTy, rewriter, 0);
2397dc48849fSKiran Chandramohan         for (unsigned index = i, lastIndex = i + arrTy.getDimension();
2398dc48849fSKiran Chandramohan              index < lastIndex; ++index) {
2399dc48849fSKiran Chandramohan           mlir::Value stride =
2400dc48849fSKiran Chandramohan               loadStrideFromBox(loc, operands[0], index - i, rewriter);
2401dc48849fSKiran Chandramohan           auto sc = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy,
2402dc48849fSKiran Chandramohan                                                        operands[index], stride);
2403dc48849fSKiran Chandramohan           off = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, off);
2404dc48849fSKiran Chandramohan         }
2405dc48849fSKiran Chandramohan         auto voidPtrBase =
2406dc48849fSKiran Chandramohan             rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, resultAddr);
2407575c9d6dSValentin Clement         llvm::SmallVector<mlir::Value> args = {off};
2408dc48849fSKiran Chandramohan         resultAddr = rewriter.create<mlir::LLVM::GEPOp>(loc, voidPtrTy,
2409dc48849fSKiran Chandramohan                                                         voidPtrBase, args);
2410dc48849fSKiran Chandramohan         i += arrTy.getDimension() - 1;
241103efa5a3SAndrzej Warzynski         cpnTy = arrTy.getEleTy();
241203efa5a3SAndrzej Warzynski       } else if (auto recTy = cpnTy.dyn_cast<fir::RecordType>()) {
2413dc48849fSKiran Chandramohan         auto recRefTy =
2414dc48849fSKiran Chandramohan             mlir::LLVM::LLVMPointerType::get(lowerTy().convertType(recTy));
2415dc48849fSKiran Chandramohan         mlir::Value nxtOpnd = operands[i];
2416dc48849fSKiran Chandramohan         auto memObj =
2417dc48849fSKiran Chandramohan             rewriter.create<mlir::LLVM::BitcastOp>(loc, recRefTy, resultAddr);
2418dc48849fSKiran Chandramohan         llvm::SmallVector<mlir::Value> args = {c0, nxtOpnd};
241903efa5a3SAndrzej Warzynski         cpnTy = recTy.getType(getFieldNumber(recTy, nxtOpnd));
242003efa5a3SAndrzej Warzynski         auto llvmCurrentObjTy = lowerTy().convertType(cpnTy);
2421dc48849fSKiran Chandramohan         auto gep = rewriter.create<mlir::LLVM::GEPOp>(
2422dc48849fSKiran Chandramohan             loc, mlir::LLVM::LLVMPointerType::get(llvmCurrentObjTy), memObj,
2423dc48849fSKiran Chandramohan             args);
2424dc48849fSKiran Chandramohan         resultAddr =
2425dc48849fSKiran Chandramohan             rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, gep);
2426dc48849fSKiran Chandramohan       } else {
2427dc48849fSKiran Chandramohan         fir::emitFatalError(loc, "unexpected type in coordinate_of");
2428dc48849fSKiran Chandramohan       }
2429dc48849fSKiran Chandramohan     }
2430dc48849fSKiran Chandramohan 
2431dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(coor, ty, resultAddr);
243244e58509SEric Schweitz     return mlir::success();
2433dc48849fSKiran Chandramohan   }
2434dc48849fSKiran Chandramohan 
2435dc48849fSKiran Chandramohan   mlir::LogicalResult
2436dc48849fSKiran Chandramohan   doRewriteRefOrPtr(fir::CoordinateOp coor, mlir::Type ty,
2437dc48849fSKiran Chandramohan                     mlir::ValueRange operands, mlir::Location loc,
2438dc48849fSKiran Chandramohan                     mlir::ConversionPatternRewriter &rewriter) const {
2439dc48849fSKiran Chandramohan     mlir::Type baseObjectTy = coor.getBaseType();
2440dc48849fSKiran Chandramohan 
244103efa5a3SAndrzej Warzynski     // Component Type
244203efa5a3SAndrzej Warzynski     mlir::Type cpnTy = fir::dyn_cast_ptrOrBoxEleTy(baseObjectTy);
244303efa5a3SAndrzej Warzynski     bool hasSubdimension = hasSubDimensions(cpnTy);
2444dc48849fSKiran Chandramohan     bool columnIsDeferred = !hasSubdimension;
2445dc48849fSKiran Chandramohan 
244603efa5a3SAndrzej Warzynski     if (!supportedCoordinate(cpnTy, operands.drop_front(1)))
2447dc48849fSKiran Chandramohan       TODO(loc, "unsupported combination of coordinate operands");
2448dc48849fSKiran Chandramohan 
2449dc48849fSKiran Chandramohan     const bool hasKnownShape =
245003efa5a3SAndrzej Warzynski         arraysHaveKnownShape(cpnTy, operands.drop_front(1));
2451dc48849fSKiran Chandramohan 
2452dc48849fSKiran Chandramohan     // If only the column is `?`, then we can simply place the column value in
2453dc48849fSKiran Chandramohan     // the 0-th GEP position.
245403efa5a3SAndrzej Warzynski     if (auto arrTy = cpnTy.dyn_cast<fir::SequenceType>()) {
2455dc48849fSKiran Chandramohan       if (!hasKnownShape) {
2456dc48849fSKiran Chandramohan         const unsigned sz = arrTy.getDimension();
2457dc48849fSKiran Chandramohan         if (arraysHaveKnownShape(arrTy.getEleTy(),
2458dc48849fSKiran Chandramohan                                  operands.drop_front(1 + sz))) {
245903efa5a3SAndrzej Warzynski           fir::SequenceType::ShapeRef shape = arrTy.getShape();
2460dc48849fSKiran Chandramohan           bool allConst = true;
2461dc48849fSKiran Chandramohan           for (unsigned i = 0; i < sz - 1; ++i) {
2462dc48849fSKiran Chandramohan             if (shape[i] < 0) {
2463dc48849fSKiran Chandramohan               allConst = false;
2464dc48849fSKiran Chandramohan               break;
2465dc48849fSKiran Chandramohan             }
2466dc48849fSKiran Chandramohan           }
2467dc48849fSKiran Chandramohan           if (allConst)
2468dc48849fSKiran Chandramohan             columnIsDeferred = true;
2469dc48849fSKiran Chandramohan         }
2470dc48849fSKiran Chandramohan       }
2471dc48849fSKiran Chandramohan     }
2472dc48849fSKiran Chandramohan 
247303efa5a3SAndrzej Warzynski     if (fir::hasDynamicSize(fir::unwrapSequenceType(cpnTy)))
247403efa5a3SAndrzej Warzynski       return mlir::emitError(
2475dc48849fSKiran Chandramohan           loc, "fir.coordinate_of with a dynamic element size is unsupported");
2476dc48849fSKiran Chandramohan 
2477dc48849fSKiran Chandramohan     if (hasKnownShape || columnIsDeferred) {
247844e58509SEric Schweitz       llvm::SmallVector<mlir::Value> offs;
2479dc48849fSKiran Chandramohan       if (hasKnownShape && hasSubdimension) {
2480dc48849fSKiran Chandramohan         mlir::LLVM::ConstantOp c0 =
2481dc48849fSKiran Chandramohan             genConstantIndex(loc, lowerTy().indexType(), rewriter, 0);
2482dc48849fSKiran Chandramohan         offs.push_back(c0);
2483dc48849fSKiran Chandramohan       }
248444e58509SEric Schweitz       llvm::Optional<int> dims;
248544e58509SEric Schweitz       llvm::SmallVector<mlir::Value> arrIdx;
248603efa5a3SAndrzej Warzynski       for (std::size_t i = 1, sz = operands.size(); i < sz; ++i) {
2487dc48849fSKiran Chandramohan         mlir::Value nxtOpnd = operands[i];
2488dc48849fSKiran Chandramohan 
248903efa5a3SAndrzej Warzynski         if (!cpnTy)
249003efa5a3SAndrzej Warzynski           return mlir::emitError(loc, "invalid coordinate/check failed");
2491dc48849fSKiran Chandramohan 
2492dc48849fSKiran Chandramohan         // check if the i-th coordinate relates to an array
24935413bf1bSKazu Hirata         if (dims) {
2494dc48849fSKiran Chandramohan           arrIdx.push_back(nxtOpnd);
2495dc48849fSKiran Chandramohan           int dimsLeft = *dims;
2496dc48849fSKiran Chandramohan           if (dimsLeft > 1) {
2497dc48849fSKiran Chandramohan             dims = dimsLeft - 1;
2498dc48849fSKiran Chandramohan             continue;
2499dc48849fSKiran Chandramohan           }
250003efa5a3SAndrzej Warzynski           cpnTy = cpnTy.cast<fir::SequenceType>().getEleTy();
2501dc48849fSKiran Chandramohan           // append array range in reverse (FIR arrays are column-major)
2502dc48849fSKiran Chandramohan           offs.append(arrIdx.rbegin(), arrIdx.rend());
2503dc48849fSKiran Chandramohan           arrIdx.clear();
2504dc48849fSKiran Chandramohan           dims.reset();
2505dc48849fSKiran Chandramohan           continue;
2506dc48849fSKiran Chandramohan         }
250703efa5a3SAndrzej Warzynski         if (auto arrTy = cpnTy.dyn_cast<fir::SequenceType>()) {
2508dc48849fSKiran Chandramohan           int d = arrTy.getDimension() - 1;
2509dc48849fSKiran Chandramohan           if (d > 0) {
2510dc48849fSKiran Chandramohan             dims = d;
2511dc48849fSKiran Chandramohan             arrIdx.push_back(nxtOpnd);
2512dc48849fSKiran Chandramohan             continue;
2513dc48849fSKiran Chandramohan           }
251403efa5a3SAndrzej Warzynski           cpnTy = cpnTy.cast<fir::SequenceType>().getEleTy();
2515dc48849fSKiran Chandramohan           offs.push_back(nxtOpnd);
2516dc48849fSKiran Chandramohan           continue;
2517dc48849fSKiran Chandramohan         }
2518dc48849fSKiran Chandramohan 
2519dc48849fSKiran Chandramohan         // check if the i-th coordinate relates to a field
252003efa5a3SAndrzej Warzynski         if (auto recTy = cpnTy.dyn_cast<fir::RecordType>())
252103efa5a3SAndrzej Warzynski           cpnTy = recTy.getType(getFieldNumber(recTy, nxtOpnd));
252203efa5a3SAndrzej Warzynski         else if (auto tupTy = cpnTy.dyn_cast<mlir::TupleType>())
252303efa5a3SAndrzej Warzynski           cpnTy = tupTy.getType(getIntValue(nxtOpnd));
2524dc48849fSKiran Chandramohan         else
252503efa5a3SAndrzej Warzynski           cpnTy = nullptr;
2526dc48849fSKiran Chandramohan 
2527dc48849fSKiran Chandramohan         offs.push_back(nxtOpnd);
2528dc48849fSKiran Chandramohan       }
25295413bf1bSKazu Hirata       if (dims)
2530dc48849fSKiran Chandramohan         offs.append(arrIdx.rbegin(), arrIdx.rend());
2531dc48849fSKiran Chandramohan       mlir::Value base = operands[0];
2532dc48849fSKiran Chandramohan       mlir::Value retval = genGEP(loc, ty, rewriter, base, offs);
2533dc48849fSKiran Chandramohan       rewriter.replaceOp(coor, retval);
253444e58509SEric Schweitz       return mlir::success();
2535dc48849fSKiran Chandramohan     }
2536dc48849fSKiran Chandramohan 
253703efa5a3SAndrzej Warzynski     return mlir::emitError(
253803efa5a3SAndrzej Warzynski         loc, "fir.coordinate_of base operand has unsupported type");
2539dc48849fSKiran Chandramohan   }
2540dc48849fSKiran Chandramohan };
2541dc48849fSKiran Chandramohan 
2542dc48849fSKiran Chandramohan /// Convert `fir.field_index`. The conversion depends on whether the size of
2543dc48849fSKiran Chandramohan /// the record is static or dynamic.
2544dc48849fSKiran Chandramohan struct FieldIndexOpConversion : public FIROpConversion<fir::FieldIndexOp> {
2545dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2546dc48849fSKiran Chandramohan 
2547dc48849fSKiran Chandramohan   // NB: most field references should be resolved by this point
2548dc48849fSKiran Chandramohan   mlir::LogicalResult
2549dc48849fSKiran Chandramohan   matchAndRewrite(fir::FieldIndexOp field, OpAdaptor adaptor,
2550dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2551dc48849fSKiran Chandramohan     auto recTy = field.getOnType().cast<fir::RecordType>();
2552dc48849fSKiran Chandramohan     unsigned index = recTy.getFieldIndex(field.getFieldId());
2553dc48849fSKiran Chandramohan 
2554dc48849fSKiran Chandramohan     if (!fir::hasDynamicSize(recTy)) {
2555dc48849fSKiran Chandramohan       // Derived type has compile-time constant layout. Return index of the
2556dc48849fSKiran Chandramohan       // component type in the parent type (to be used in GEP).
2557dc48849fSKiran Chandramohan       rewriter.replaceOp(field, mlir::ValueRange{genConstantOffset(
2558dc48849fSKiran Chandramohan                                     field.getLoc(), rewriter, index)});
255944e58509SEric Schweitz       return mlir::success();
2560dc48849fSKiran Chandramohan     }
2561dc48849fSKiran Chandramohan 
2562dc48849fSKiran Chandramohan     // Derived type has compile-time constant layout. Call the compiler
2563dc48849fSKiran Chandramohan     // generated function to determine the byte offset of the field at runtime.
2564dc48849fSKiran Chandramohan     // This returns a non-constant.
256544e58509SEric Schweitz     mlir::FlatSymbolRefAttr symAttr = mlir::SymbolRefAttr::get(
2566dc48849fSKiran Chandramohan         field.getContext(), getOffsetMethodName(recTy, field.getFieldId()));
256744e58509SEric Schweitz     mlir::NamedAttribute callAttr = rewriter.getNamedAttr("callee", symAttr);
256844e58509SEric Schweitz     mlir::NamedAttribute fieldAttr = rewriter.getNamedAttr(
2569dc48849fSKiran Chandramohan         "field", mlir::IntegerAttr::get(lowerTy().indexType(), index));
2570dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
2571dc48849fSKiran Chandramohan         field, lowerTy().offsetType(), adaptor.getOperands(),
2572dc48849fSKiran Chandramohan         llvm::ArrayRef<mlir::NamedAttribute>{callAttr, fieldAttr});
257344e58509SEric Schweitz     return mlir::success();
2574dc48849fSKiran Chandramohan   }
2575dc48849fSKiran Chandramohan 
2576dc48849fSKiran Chandramohan   // Re-Construct the name of the compiler generated method that calculates the
2577dc48849fSKiran Chandramohan   // offset
2578dc48849fSKiran Chandramohan   inline static std::string getOffsetMethodName(fir::RecordType recTy,
2579dc48849fSKiran Chandramohan                                                 llvm::StringRef field) {
2580dc48849fSKiran Chandramohan     return recTy.getName().str() + "P." + field.str() + ".offset";
2581dc48849fSKiran Chandramohan   }
2582dc48849fSKiran Chandramohan };
2583dc48849fSKiran Chandramohan 
2584dc48849fSKiran Chandramohan /// Convert `fir.end`
2585dc48849fSKiran Chandramohan struct FirEndOpConversion : public FIROpConversion<fir::FirEndOp> {
2586dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2587dc48849fSKiran Chandramohan 
2588dc48849fSKiran Chandramohan   mlir::LogicalResult
2589dc48849fSKiran Chandramohan   matchAndRewrite(fir::FirEndOp firEnd, OpAdaptor,
2590dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2591dc48849fSKiran Chandramohan     TODO(firEnd.getLoc(), "fir.end codegen");
259244e58509SEric Schweitz     return mlir::failure();
2593dc48849fSKiran Chandramohan   }
2594dc48849fSKiran Chandramohan };
2595dc48849fSKiran Chandramohan 
2596dc48849fSKiran Chandramohan /// Lower `fir.gentypedesc` to a global constant.
2597dc48849fSKiran Chandramohan struct GenTypeDescOpConversion : public FIROpConversion<fir::GenTypeDescOp> {
2598dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2599dc48849fSKiran Chandramohan 
2600dc48849fSKiran Chandramohan   mlir::LogicalResult
2601dc48849fSKiran Chandramohan   matchAndRewrite(fir::GenTypeDescOp gentypedesc, OpAdaptor adaptor,
2602dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2603dc48849fSKiran Chandramohan     TODO(gentypedesc.getLoc(), "fir.gentypedesc codegen");
260444e58509SEric Schweitz     return mlir::failure();
2605dc48849fSKiran Chandramohan   }
2606dc48849fSKiran Chandramohan };
2607dc48849fSKiran Chandramohan 
2608dc48849fSKiran Chandramohan /// Lower `fir.has_value` operation to `llvm.return` operation.
2609dc48849fSKiran Chandramohan struct HasValueOpConversion : public FIROpConversion<fir::HasValueOp> {
2610dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2611dc48849fSKiran Chandramohan 
2612dc48849fSKiran Chandramohan   mlir::LogicalResult
2613dc48849fSKiran Chandramohan   matchAndRewrite(fir::HasValueOp op, OpAdaptor adaptor,
2614dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
261544e58509SEric Schweitz     rewriter.replaceOpWithNewOp<mlir::LLVM::ReturnOp>(op,
261644e58509SEric Schweitz                                                       adaptor.getOperands());
261744e58509SEric Schweitz     return mlir::success();
2618dc48849fSKiran Chandramohan   }
2619dc48849fSKiran Chandramohan };
2620dc48849fSKiran Chandramohan 
2621dc48849fSKiran Chandramohan /// Lower `fir.global` operation to `llvm.global` operation.
2622dc48849fSKiran Chandramohan /// `fir.insert_on_range` operations are replaced with constant dense attribute
2623dc48849fSKiran Chandramohan /// if they are applied on the full range.
2624dc48849fSKiran Chandramohan struct GlobalOpConversion : public FIROpConversion<fir::GlobalOp> {
2625dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2626dc48849fSKiran Chandramohan 
2627dc48849fSKiran Chandramohan   mlir::LogicalResult
2628dc48849fSKiran Chandramohan   matchAndRewrite(fir::GlobalOp global, OpAdaptor adaptor,
2629dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2630dc48849fSKiran Chandramohan     auto tyAttr = convertType(global.getType());
2631dc48849fSKiran Chandramohan     if (global.getType().isa<fir::BoxType>())
2632dc48849fSKiran Chandramohan       tyAttr = tyAttr.cast<mlir::LLVM::LLVMPointerType>().getElementType();
2633dc48849fSKiran Chandramohan     auto loc = global.getLoc();
2634575c9d6dSValentin Clement     mlir::Attribute initAttr;
2635dc48849fSKiran Chandramohan     if (global.getInitVal())
26363b7c3a65SKazu Hirata       initAttr = global.getInitVal().getValue();
2637dc48849fSKiran Chandramohan     auto linkage = convertLinkage(global.getLinkName());
2638*c82fb16fSKazu Hirata     auto isConst = global.getConstant().has_value();
2639dc48849fSKiran Chandramohan     auto g = rewriter.create<mlir::LLVM::GlobalOp>(
2640dc48849fSKiran Chandramohan         loc, tyAttr, isConst, linkage, global.getSymName(), initAttr);
2641dc48849fSKiran Chandramohan     auto &gr = g.getInitializerRegion();
2642dc48849fSKiran Chandramohan     rewriter.inlineRegionBefore(global.getRegion(), gr, gr.end());
2643dc48849fSKiran Chandramohan     if (!gr.empty()) {
2644dc48849fSKiran Chandramohan       // Replace insert_on_range with a constant dense attribute if the
2645dc48849fSKiran Chandramohan       // initialization is on the full range.
2646dc48849fSKiran Chandramohan       auto insertOnRangeOps = gr.front().getOps<fir::InsertOnRangeOp>();
2647dc48849fSKiran Chandramohan       for (auto insertOp : insertOnRangeOps) {
2648dc48849fSKiran Chandramohan         if (isFullRange(insertOp.getCoor(), insertOp.getType())) {
2649dc48849fSKiran Chandramohan           auto seqTyAttr = convertType(insertOp.getType());
2650dc48849fSKiran Chandramohan           auto *op = insertOp.getVal().getDefiningOp();
2651dc48849fSKiran Chandramohan           auto constant = mlir::dyn_cast<mlir::arith::ConstantOp>(op);
2652dc48849fSKiran Chandramohan           if (!constant) {
2653dc48849fSKiran Chandramohan             auto convertOp = mlir::dyn_cast<fir::ConvertOp>(op);
2654dc48849fSKiran Chandramohan             if (!convertOp)
2655dc48849fSKiran Chandramohan               continue;
265644e58509SEric Schweitz             constant = mlir::cast<mlir::arith::ConstantOp>(
2657dc48849fSKiran Chandramohan                 convertOp.getValue().getDefiningOp());
2658dc48849fSKiran Chandramohan           }
2659dc48849fSKiran Chandramohan           mlir::Type vecType = mlir::VectorType::get(
2660dc48849fSKiran Chandramohan               insertOp.getType().getShape(), constant.getType());
2661dc48849fSKiran Chandramohan           auto denseAttr = mlir::DenseElementsAttr::get(
266244e58509SEric Schweitz               vecType.cast<mlir::ShapedType>(), constant.getValue());
2663dc48849fSKiran Chandramohan           rewriter.setInsertionPointAfter(insertOp);
2664dc48849fSKiran Chandramohan           rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(
2665dc48849fSKiran Chandramohan               insertOp, seqTyAttr, denseAttr);
2666dc48849fSKiran Chandramohan         }
2667dc48849fSKiran Chandramohan       }
2668dc48849fSKiran Chandramohan     }
2669dc48849fSKiran Chandramohan     rewriter.eraseOp(global);
267044e58509SEric Schweitz     return mlir::success();
2671dc48849fSKiran Chandramohan   }
2672dc48849fSKiran Chandramohan 
2673dc48849fSKiran Chandramohan   bool isFullRange(mlir::DenseIntElementsAttr indexes,
2674dc48849fSKiran Chandramohan                    fir::SequenceType seqTy) const {
2675dc48849fSKiran Chandramohan     auto extents = seqTy.getShape();
2676dc48849fSKiran Chandramohan     if (indexes.size() / 2 != static_cast<int64_t>(extents.size()))
2677dc48849fSKiran Chandramohan       return false;
2678dc48849fSKiran Chandramohan     auto cur_index = indexes.value_begin<int64_t>();
2679dc48849fSKiran Chandramohan     for (unsigned i = 0; i < indexes.size(); i += 2) {
2680dc48849fSKiran Chandramohan       if (*(cur_index++) != 0)
2681dc48849fSKiran Chandramohan         return false;
2682dc48849fSKiran Chandramohan       if (*(cur_index++) != extents[i / 2] - 1)
2683dc48849fSKiran Chandramohan         return false;
2684dc48849fSKiran Chandramohan     }
2685dc48849fSKiran Chandramohan     return true;
2686dc48849fSKiran Chandramohan   }
2687dc48849fSKiran Chandramohan 
2688dc48849fSKiran Chandramohan   // TODO: String comparaison should be avoided. Replace linkName with an
2689dc48849fSKiran Chandramohan   // enumeration.
269044e58509SEric Schweitz   mlir::LLVM::Linkage
269144e58509SEric Schweitz   convertLinkage(llvm::Optional<llvm::StringRef> optLinkage) const {
269286b8c1d9SKazu Hirata     if (optLinkage) {
26933b7c3a65SKazu Hirata       auto name = optLinkage.getValue();
2694dc48849fSKiran Chandramohan       if (name == "internal")
2695dc48849fSKiran Chandramohan         return mlir::LLVM::Linkage::Internal;
2696dc48849fSKiran Chandramohan       if (name == "linkonce")
2697dc48849fSKiran Chandramohan         return mlir::LLVM::Linkage::Linkonce;
269830a0fbf5SJean Perier       if (name == "linkonce_odr")
269930a0fbf5SJean Perier         return mlir::LLVM::Linkage::LinkonceODR;
2700dc48849fSKiran Chandramohan       if (name == "common")
2701dc48849fSKiran Chandramohan         return mlir::LLVM::Linkage::Common;
2702dc48849fSKiran Chandramohan       if (name == "weak")
2703dc48849fSKiran Chandramohan         return mlir::LLVM::Linkage::Weak;
2704dc48849fSKiran Chandramohan     }
2705dc48849fSKiran Chandramohan     return mlir::LLVM::Linkage::External;
2706dc48849fSKiran Chandramohan   }
2707dc48849fSKiran Chandramohan };
2708dc48849fSKiran Chandramohan 
2709dc48849fSKiran Chandramohan /// `fir.load` --> `llvm.load`
2710dc48849fSKiran Chandramohan struct LoadOpConversion : public FIROpConversion<fir::LoadOp> {
2711dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2712dc48849fSKiran Chandramohan 
2713dc48849fSKiran Chandramohan   mlir::LogicalResult
2714dc48849fSKiran Chandramohan   matchAndRewrite(fir::LoadOp load, OpAdaptor adaptor,
2715dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2716dc48849fSKiran Chandramohan     // fir.box is a special case because it is considered as an ssa values in
2717dc48849fSKiran Chandramohan     // fir, but it is lowered as a pointer to a descriptor. So fir.ref<fir.box>
2718dc48849fSKiran Chandramohan     // and fir.box end up being the same llvm types and loading a
2719dc48849fSKiran Chandramohan     // fir.ref<fir.box> is actually a no op in LLVM.
2720dc48849fSKiran Chandramohan     if (load.getType().isa<fir::BoxType>()) {
2721dc48849fSKiran Chandramohan       rewriter.replaceOp(load, adaptor.getOperands()[0]);
2722dc48849fSKiran Chandramohan     } else {
2723dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::LoadOp>(
272444e58509SEric Schweitz           load, convertType(load.getType()), adaptor.getOperands(),
272544e58509SEric Schweitz           load->getAttrs());
2726dc48849fSKiran Chandramohan     }
272744e58509SEric Schweitz     return mlir::success();
2728dc48849fSKiran Chandramohan   }
2729dc48849fSKiran Chandramohan };
2730dc48849fSKiran Chandramohan 
2731dc48849fSKiran Chandramohan /// Lower `fir.no_reassoc` to LLVM IR dialect.
2732dc48849fSKiran Chandramohan /// TODO: how do we want to enforce this in LLVM-IR? Can we manipulate the fast
2733dc48849fSKiran Chandramohan /// math flags?
2734dc48849fSKiran Chandramohan struct NoReassocOpConversion : public FIROpConversion<fir::NoReassocOp> {
2735dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2736dc48849fSKiran Chandramohan 
2737dc48849fSKiran Chandramohan   mlir::LogicalResult
2738dc48849fSKiran Chandramohan   matchAndRewrite(fir::NoReassocOp noreassoc, OpAdaptor adaptor,
2739dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2740dc48849fSKiran Chandramohan     rewriter.replaceOp(noreassoc, adaptor.getOperands()[0]);
274144e58509SEric Schweitz     return mlir::success();
2742dc48849fSKiran Chandramohan   }
2743dc48849fSKiran Chandramohan };
2744dc48849fSKiran Chandramohan 
2745dc48849fSKiran Chandramohan static void genCondBrOp(mlir::Location loc, mlir::Value cmp, mlir::Block *dest,
274644e58509SEric Schweitz                         llvm::Optional<mlir::ValueRange> destOps,
2747dc48849fSKiran Chandramohan                         mlir::ConversionPatternRewriter &rewriter,
2748dc48849fSKiran Chandramohan                         mlir::Block *newBlock) {
274986b8c1d9SKazu Hirata   if (destOps)
27503b7c3a65SKazu Hirata     rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, destOps.getValue(),
27513b7c3a65SKazu Hirata                                           newBlock, mlir::ValueRange());
2752dc48849fSKiran Chandramohan   else
2753dc48849fSKiran Chandramohan     rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, newBlock);
2754dc48849fSKiran Chandramohan }
2755dc48849fSKiran Chandramohan 
2756dc48849fSKiran Chandramohan template <typename A, typename B>
275744e58509SEric Schweitz static void genBrOp(A caseOp, mlir::Block *dest, llvm::Optional<B> destOps,
2758dc48849fSKiran Chandramohan                     mlir::ConversionPatternRewriter &rewriter) {
275986b8c1d9SKazu Hirata   if (destOps)
27603b7c3a65SKazu Hirata     rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, destOps.getValue(),
27613b7c3a65SKazu Hirata                                                   dest);
2762dc48849fSKiran Chandramohan   else
2763dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, llvm::None, dest);
2764dc48849fSKiran Chandramohan }
2765dc48849fSKiran Chandramohan 
2766dc48849fSKiran Chandramohan static void genCaseLadderStep(mlir::Location loc, mlir::Value cmp,
2767dc48849fSKiran Chandramohan                               mlir::Block *dest,
276844e58509SEric Schweitz                               llvm::Optional<mlir::ValueRange> destOps,
2769dc48849fSKiran Chandramohan                               mlir::ConversionPatternRewriter &rewriter) {
2770dc48849fSKiran Chandramohan   auto *thisBlock = rewriter.getInsertionBlock();
2771dc48849fSKiran Chandramohan   auto *newBlock = createBlock(rewriter, dest);
2772dc48849fSKiran Chandramohan   rewriter.setInsertionPointToEnd(thisBlock);
2773dc48849fSKiran Chandramohan   genCondBrOp(loc, cmp, dest, destOps, rewriter, newBlock);
2774dc48849fSKiran Chandramohan   rewriter.setInsertionPointToEnd(newBlock);
2775dc48849fSKiran Chandramohan }
2776dc48849fSKiran Chandramohan 
2777dc48849fSKiran Chandramohan /// Conversion of `fir.select_case`
2778dc48849fSKiran Chandramohan ///
2779dc48849fSKiran Chandramohan /// The `fir.select_case` operation is converted to a if-then-else ladder.
2780dc48849fSKiran Chandramohan /// Depending on the case condition type, one or several comparison and
2781dc48849fSKiran Chandramohan /// conditional branching can be generated.
2782dc48849fSKiran Chandramohan ///
2783dc48849fSKiran Chandramohan /// A a point value case such as `case(4)`, a lower bound case such as
2784dc48849fSKiran Chandramohan /// `case(5:)` or an upper bound case such as `case(:3)` are converted to a
2785dc48849fSKiran Chandramohan /// simple comparison between the selector value and the constant value in the
2786dc48849fSKiran Chandramohan /// case. The block associated with the case condition is then executed if
2787dc48849fSKiran Chandramohan /// the comparison succeed otherwise it branch to the next block with the
2788dc48849fSKiran Chandramohan /// comparison for the the next case conditon.
2789dc48849fSKiran Chandramohan ///
2790dc48849fSKiran Chandramohan /// A closed interval case condition such as `case(7:10)` is converted with a
2791dc48849fSKiran Chandramohan /// first comparison and conditional branching for the lower bound. If
2792dc48849fSKiran Chandramohan /// successful, it branch to a second block with the comparison for the
2793dc48849fSKiran Chandramohan /// upper bound in the same case condition.
2794dc48849fSKiran Chandramohan ///
2795dc48849fSKiran Chandramohan /// TODO: lowering of CHARACTER type cases is not handled yet.
2796dc48849fSKiran Chandramohan struct SelectCaseOpConversion : public FIROpConversion<fir::SelectCaseOp> {
2797dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2798dc48849fSKiran Chandramohan 
2799dc48849fSKiran Chandramohan   mlir::LogicalResult
2800dc48849fSKiran Chandramohan   matchAndRewrite(fir::SelectCaseOp caseOp, OpAdaptor adaptor,
2801dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2802dc48849fSKiran Chandramohan     unsigned conds = caseOp.getNumConditions();
2803dc48849fSKiran Chandramohan     llvm::ArrayRef<mlir::Attribute> cases = caseOp.getCases().getValue();
2804dc48849fSKiran Chandramohan     // Type can be CHARACTER, INTEGER, or LOGICAL (C1145)
2805dc48849fSKiran Chandramohan     auto ty = caseOp.getSelector().getType();
2806dc48849fSKiran Chandramohan     if (ty.isa<fir::CharacterType>()) {
2807dc48849fSKiran Chandramohan       TODO(caseOp.getLoc(), "fir.select_case codegen with character type");
280844e58509SEric Schweitz       return mlir::failure();
2809dc48849fSKiran Chandramohan     }
2810dc48849fSKiran Chandramohan     mlir::Value selector = caseOp.getSelector(adaptor.getOperands());
2811dc48849fSKiran Chandramohan     auto loc = caseOp.getLoc();
2812dc48849fSKiran Chandramohan     for (unsigned t = 0; t != conds; ++t) {
2813dc48849fSKiran Chandramohan       mlir::Block *dest = caseOp.getSuccessor(t);
2814dc48849fSKiran Chandramohan       llvm::Optional<mlir::ValueRange> destOps =
2815dc48849fSKiran Chandramohan           caseOp.getSuccessorOperands(adaptor.getOperands(), t);
2816dc48849fSKiran Chandramohan       llvm::Optional<mlir::ValueRange> cmpOps =
2817dc48849fSKiran Chandramohan           *caseOp.getCompareOperands(adaptor.getOperands(), t);
2818dc97886fSKazu Hirata       mlir::Value caseArg = *(cmpOps.value().begin());
2819dc48849fSKiran Chandramohan       mlir::Attribute attr = cases[t];
2820dc48849fSKiran Chandramohan       if (attr.isa<fir::PointIntervalAttr>()) {
2821dc48849fSKiran Chandramohan         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
2822dc48849fSKiran Chandramohan             loc, mlir::LLVM::ICmpPredicate::eq, selector, caseArg);
2823dc48849fSKiran Chandramohan         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
2824dc48849fSKiran Chandramohan         continue;
2825dc48849fSKiran Chandramohan       }
2826dc48849fSKiran Chandramohan       if (attr.isa<fir::LowerBoundAttr>()) {
2827dc48849fSKiran Chandramohan         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
2828dc48849fSKiran Chandramohan             loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector);
2829dc48849fSKiran Chandramohan         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
2830dc48849fSKiran Chandramohan         continue;
2831dc48849fSKiran Chandramohan       }
2832dc48849fSKiran Chandramohan       if (attr.isa<fir::UpperBoundAttr>()) {
2833dc48849fSKiran Chandramohan         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
2834dc48849fSKiran Chandramohan             loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg);
2835dc48849fSKiran Chandramohan         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
2836dc48849fSKiran Chandramohan         continue;
2837dc48849fSKiran Chandramohan       }
2838dc48849fSKiran Chandramohan       if (attr.isa<fir::ClosedIntervalAttr>()) {
2839dc48849fSKiran Chandramohan         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
2840dc48849fSKiran Chandramohan             loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector);
2841dc48849fSKiran Chandramohan         auto *thisBlock = rewriter.getInsertionBlock();
2842dc48849fSKiran Chandramohan         auto *newBlock1 = createBlock(rewriter, dest);
2843dc48849fSKiran Chandramohan         auto *newBlock2 = createBlock(rewriter, dest);
2844dc48849fSKiran Chandramohan         rewriter.setInsertionPointToEnd(thisBlock);
2845dc48849fSKiran Chandramohan         rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, newBlock1, newBlock2);
2846dc48849fSKiran Chandramohan         rewriter.setInsertionPointToEnd(newBlock1);
2847dc97886fSKazu Hirata         mlir::Value caseArg0 = *(cmpOps.value().begin() + 1);
2848dc48849fSKiran Chandramohan         auto cmp0 = rewriter.create<mlir::LLVM::ICmpOp>(
2849dc48849fSKiran Chandramohan             loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg0);
2850dc48849fSKiran Chandramohan         genCondBrOp(loc, cmp0, dest, destOps, rewriter, newBlock2);
2851dc48849fSKiran Chandramohan         rewriter.setInsertionPointToEnd(newBlock2);
2852dc48849fSKiran Chandramohan         continue;
2853dc48849fSKiran Chandramohan       }
2854dc48849fSKiran Chandramohan       assert(attr.isa<mlir::UnitAttr>());
2855dc48849fSKiran Chandramohan       assert((t + 1 == conds) && "unit must be last");
2856dc48849fSKiran Chandramohan       genBrOp(caseOp, dest, destOps, rewriter);
2857dc48849fSKiran Chandramohan     }
285844e58509SEric Schweitz     return mlir::success();
2859dc48849fSKiran Chandramohan   }
2860dc48849fSKiran Chandramohan };
2861dc48849fSKiran Chandramohan 
2862dc48849fSKiran Chandramohan template <typename OP>
2863dc48849fSKiran Chandramohan static void selectMatchAndRewrite(fir::LLVMTypeConverter &lowering, OP select,
2864dc48849fSKiran Chandramohan                                   typename OP::Adaptor adaptor,
2865dc48849fSKiran Chandramohan                                   mlir::ConversionPatternRewriter &rewriter) {
2866dc48849fSKiran Chandramohan   unsigned conds = select.getNumConditions();
2867dc48849fSKiran Chandramohan   auto cases = select.getCases().getValue();
2868dc48849fSKiran Chandramohan   mlir::Value selector = adaptor.getSelector();
2869dc48849fSKiran Chandramohan   auto loc = select.getLoc();
2870dc48849fSKiran Chandramohan   assert(conds > 0 && "select must have cases");
2871dc48849fSKiran Chandramohan 
2872dc48849fSKiran Chandramohan   llvm::SmallVector<mlir::Block *> destinations;
2873dc48849fSKiran Chandramohan   llvm::SmallVector<mlir::ValueRange> destinationsOperands;
2874dc48849fSKiran Chandramohan   mlir::Block *defaultDestination;
2875dc48849fSKiran Chandramohan   mlir::ValueRange defaultOperands;
2876dc48849fSKiran Chandramohan   llvm::SmallVector<int32_t> caseValues;
2877dc48849fSKiran Chandramohan 
2878dc48849fSKiran Chandramohan   for (unsigned t = 0; t != conds; ++t) {
2879dc48849fSKiran Chandramohan     mlir::Block *dest = select.getSuccessor(t);
2880dc48849fSKiran Chandramohan     auto destOps = select.getSuccessorOperands(adaptor.getOperands(), t);
2881dc48849fSKiran Chandramohan     const mlir::Attribute &attr = cases[t];
2882dc48849fSKiran Chandramohan     if (auto intAttr = attr.template dyn_cast<mlir::IntegerAttr>()) {
2883dc48849fSKiran Chandramohan       destinations.push_back(dest);
288486b8c1d9SKazu Hirata       destinationsOperands.push_back(destOps ? *destOps : mlir::ValueRange{});
2885dc48849fSKiran Chandramohan       caseValues.push_back(intAttr.getInt());
2886dc48849fSKiran Chandramohan       continue;
2887dc48849fSKiran Chandramohan     }
2888dc48849fSKiran Chandramohan     assert(attr.template dyn_cast_or_null<mlir::UnitAttr>());
2889dc48849fSKiran Chandramohan     assert((t + 1 == conds) && "unit must be last");
2890dc48849fSKiran Chandramohan     defaultDestination = dest;
289186b8c1d9SKazu Hirata     defaultOperands = destOps ? *destOps : mlir::ValueRange{};
2892dc48849fSKiran Chandramohan   }
2893dc48849fSKiran Chandramohan 
2894dc48849fSKiran Chandramohan   // LLVM::SwitchOp takes a i32 type for the selector.
2895dc48849fSKiran Chandramohan   if (select.getSelector().getType() != rewriter.getI32Type())
289644e58509SEric Schweitz     selector = rewriter.create<mlir::LLVM::TruncOp>(loc, rewriter.getI32Type(),
289744e58509SEric Schweitz                                                     selector);
2898dc48849fSKiran Chandramohan 
2899dc48849fSKiran Chandramohan   rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>(
2900dc48849fSKiran Chandramohan       select, selector,
2901dc48849fSKiran Chandramohan       /*defaultDestination=*/defaultDestination,
2902dc48849fSKiran Chandramohan       /*defaultOperands=*/defaultOperands,
2903dc48849fSKiran Chandramohan       /*caseValues=*/caseValues,
2904dc48849fSKiran Chandramohan       /*caseDestinations=*/destinations,
2905dc48849fSKiran Chandramohan       /*caseOperands=*/destinationsOperands,
290644e58509SEric Schweitz       /*branchWeights=*/llvm::ArrayRef<std::int32_t>());
2907dc48849fSKiran Chandramohan }
2908dc48849fSKiran Chandramohan 
2909dc48849fSKiran Chandramohan /// conversion of fir::SelectOp to an if-then-else ladder
2910dc48849fSKiran Chandramohan struct SelectOpConversion : public FIROpConversion<fir::SelectOp> {
2911dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2912dc48849fSKiran Chandramohan 
2913dc48849fSKiran Chandramohan   mlir::LogicalResult
2914dc48849fSKiran Chandramohan   matchAndRewrite(fir::SelectOp op, OpAdaptor adaptor,
2915dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2916dc48849fSKiran Chandramohan     selectMatchAndRewrite<fir::SelectOp>(lowerTy(), op, adaptor, rewriter);
291744e58509SEric Schweitz     return mlir::success();
2918dc48849fSKiran Chandramohan   }
2919dc48849fSKiran Chandramohan };
2920dc48849fSKiran Chandramohan 
2921dc48849fSKiran Chandramohan /// conversion of fir::SelectRankOp to an if-then-else ladder
2922dc48849fSKiran Chandramohan struct SelectRankOpConversion : public FIROpConversion<fir::SelectRankOp> {
2923dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2924dc48849fSKiran Chandramohan 
2925dc48849fSKiran Chandramohan   mlir::LogicalResult
2926dc48849fSKiran Chandramohan   matchAndRewrite(fir::SelectRankOp op, OpAdaptor adaptor,
2927dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2928dc48849fSKiran Chandramohan     selectMatchAndRewrite<fir::SelectRankOp>(lowerTy(), op, adaptor, rewriter);
292944e58509SEric Schweitz     return mlir::success();
2930dc48849fSKiran Chandramohan   }
2931dc48849fSKiran Chandramohan };
2932dc48849fSKiran Chandramohan 
2933dc48849fSKiran Chandramohan /// Lower `fir.select_type` to LLVM IR dialect.
2934dc48849fSKiran Chandramohan struct SelectTypeOpConversion : public FIROpConversion<fir::SelectTypeOp> {
2935dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2936dc48849fSKiran Chandramohan 
2937dc48849fSKiran Chandramohan   mlir::LogicalResult
2938dc48849fSKiran Chandramohan   matchAndRewrite(fir::SelectTypeOp select, OpAdaptor adaptor,
2939dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2940dc48849fSKiran Chandramohan     mlir::emitError(select.getLoc(),
2941dc48849fSKiran Chandramohan                     "fir.select_type should have already been converted");
294244e58509SEric Schweitz     return mlir::failure();
2943dc48849fSKiran Chandramohan   }
2944dc48849fSKiran Chandramohan };
2945dc48849fSKiran Chandramohan 
2946dc48849fSKiran Chandramohan /// `fir.store` --> `llvm.store`
2947dc48849fSKiran Chandramohan struct StoreOpConversion : public FIROpConversion<fir::StoreOp> {
2948dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2949dc48849fSKiran Chandramohan 
2950dc48849fSKiran Chandramohan   mlir::LogicalResult
2951dc48849fSKiran Chandramohan   matchAndRewrite(fir::StoreOp store, OpAdaptor adaptor,
2952dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2953dc48849fSKiran Chandramohan     if (store.getValue().getType().isa<fir::BoxType>()) {
2954dc48849fSKiran Chandramohan       // fir.box value is actually in memory, load it first before storing it.
2955dc48849fSKiran Chandramohan       mlir::Location loc = store.getLoc();
2956dc48849fSKiran Chandramohan       mlir::Type boxPtrTy = adaptor.getOperands()[0].getType();
2957dc48849fSKiran Chandramohan       auto val = rewriter.create<mlir::LLVM::LoadOp>(
2958dc48849fSKiran Chandramohan           loc, boxPtrTy.cast<mlir::LLVM::LLVMPointerType>().getElementType(),
2959dc48849fSKiran Chandramohan           adaptor.getOperands()[0]);
2960dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
2961dc48849fSKiran Chandramohan           store, val, adaptor.getOperands()[1]);
2962dc48849fSKiran Chandramohan     } else {
2963dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
2964dc48849fSKiran Chandramohan           store, adaptor.getOperands()[0], adaptor.getOperands()[1]);
2965dc48849fSKiran Chandramohan     }
296644e58509SEric Schweitz     return mlir::success();
2967dc48849fSKiran Chandramohan   }
2968dc48849fSKiran Chandramohan };
2969dc48849fSKiran Chandramohan 
2970dc48849fSKiran Chandramohan namespace {
2971dc48849fSKiran Chandramohan 
2972dc48849fSKiran Chandramohan /// Convert `fir.unboxchar` into two `llvm.extractvalue` instructions. One for
2973dc48849fSKiran Chandramohan /// the character buffer and one for the buffer length.
2974dc48849fSKiran Chandramohan struct UnboxCharOpConversion : public FIROpConversion<fir::UnboxCharOp> {
2975dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2976dc48849fSKiran Chandramohan 
2977dc48849fSKiran Chandramohan   mlir::LogicalResult
2978dc48849fSKiran Chandramohan   matchAndRewrite(fir::UnboxCharOp unboxchar, OpAdaptor adaptor,
2979dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
298044e58509SEric Schweitz     auto *ctx = unboxchar.getContext();
2981dc48849fSKiran Chandramohan 
2982dc48849fSKiran Chandramohan     mlir::Type lenTy = convertType(unboxchar.getType(1));
2983dc48849fSKiran Chandramohan     mlir::Value tuple = adaptor.getOperands()[0];
2984dc48849fSKiran Chandramohan     mlir::Type tupleTy = tuple.getType();
2985dc48849fSKiran Chandramohan 
2986dc48849fSKiran Chandramohan     mlir::Location loc = unboxchar.getLoc();
2987dc48849fSKiran Chandramohan     mlir::Value ptrToBuffer =
2988dc48849fSKiran Chandramohan         genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 0);
2989dc48849fSKiran Chandramohan 
2990dc48849fSKiran Chandramohan     mlir::LLVM::ExtractValueOp len =
2991dc48849fSKiran Chandramohan         genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 1);
2992dc48849fSKiran Chandramohan     mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, len);
2993dc48849fSKiran Chandramohan 
2994dc48849fSKiran Chandramohan     rewriter.replaceOp(unboxchar,
299544e58509SEric Schweitz                        llvm::ArrayRef<mlir::Value>{ptrToBuffer, lenAfterCast});
299644e58509SEric Schweitz     return mlir::success();
2997dc48849fSKiran Chandramohan   }
2998dc48849fSKiran Chandramohan };
2999dc48849fSKiran Chandramohan 
3000dc48849fSKiran Chandramohan /// Lower `fir.unboxproc` operation. Unbox a procedure box value, yielding its
3001dc48849fSKiran Chandramohan /// components.
3002dc48849fSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
3003dc48849fSKiran Chandramohan struct UnboxProcOpConversion : public FIROpConversion<fir::UnboxProcOp> {
3004dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3005dc48849fSKiran Chandramohan 
3006dc48849fSKiran Chandramohan   mlir::LogicalResult
3007dc48849fSKiran Chandramohan   matchAndRewrite(fir::UnboxProcOp unboxproc, OpAdaptor adaptor,
3008dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3009dc48849fSKiran Chandramohan     TODO(unboxproc.getLoc(), "fir.unboxproc codegen");
301044e58509SEric Schweitz     return mlir::failure();
3011dc48849fSKiran Chandramohan   }
3012dc48849fSKiran Chandramohan };
3013dc48849fSKiran Chandramohan 
3014dc48849fSKiran Chandramohan /// convert to LLVM IR dialect `undef`
3015dc48849fSKiran Chandramohan struct UndefOpConversion : public FIROpConversion<fir::UndefOp> {
3016dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3017dc48849fSKiran Chandramohan 
3018dc48849fSKiran Chandramohan   mlir::LogicalResult
3019dc48849fSKiran Chandramohan   matchAndRewrite(fir::UndefOp undef, OpAdaptor,
3020dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3021dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::UndefOp>(
3022dc48849fSKiran Chandramohan         undef, convertType(undef.getType()));
302344e58509SEric Schweitz     return mlir::success();
3024dc48849fSKiran Chandramohan   }
3025dc48849fSKiran Chandramohan };
3026dc48849fSKiran Chandramohan 
3027dc48849fSKiran Chandramohan struct ZeroOpConversion : public FIROpConversion<fir::ZeroOp> {
3028dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3029dc48849fSKiran Chandramohan 
3030dc48849fSKiran Chandramohan   mlir::LogicalResult
3031dc48849fSKiran Chandramohan   matchAndRewrite(fir::ZeroOp zero, OpAdaptor,
3032dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3033dc48849fSKiran Chandramohan     mlir::Type ty = convertType(zero.getType());
3034dc48849fSKiran Chandramohan     if (ty.isa<mlir::LLVM::LLVMPointerType>()) {
3035dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(zero, ty);
3036dc48849fSKiran Chandramohan     } else if (ty.isa<mlir::IntegerType>()) {
3037dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
3038dc48849fSKiran Chandramohan           zero, ty, mlir::IntegerAttr::get(zero.getType(), 0));
3039dc48849fSKiran Chandramohan     } else if (mlir::LLVM::isCompatibleFloatingPointType(ty)) {
3040dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
3041dc48849fSKiran Chandramohan           zero, ty, mlir::FloatAttr::get(zero.getType(), 0.0));
3042dc48849fSKiran Chandramohan     } else {
3043dc48849fSKiran Chandramohan       // TODO: create ConstantAggregateZero for FIR aggregate/array types.
3044dc48849fSKiran Chandramohan       return rewriter.notifyMatchFailure(
3045dc48849fSKiran Chandramohan           zero,
3046dc48849fSKiran Chandramohan           "conversion of fir.zero with aggregate type not implemented yet");
3047dc48849fSKiran Chandramohan     }
304844e58509SEric Schweitz     return mlir::success();
3049dc48849fSKiran Chandramohan   }
3050dc48849fSKiran Chandramohan };
3051dc48849fSKiran Chandramohan 
3052dc48849fSKiran Chandramohan /// `fir.unreachable` --> `llvm.unreachable`
3053dc48849fSKiran Chandramohan struct UnreachableOpConversion : public FIROpConversion<fir::UnreachableOp> {
3054dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3055dc48849fSKiran Chandramohan 
3056dc48849fSKiran Chandramohan   mlir::LogicalResult
3057dc48849fSKiran Chandramohan   matchAndRewrite(fir::UnreachableOp unreach, OpAdaptor adaptor,
3058dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3059dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(unreach);
306044e58509SEric Schweitz     return mlir::success();
3061dc48849fSKiran Chandramohan   }
3062dc48849fSKiran Chandramohan };
3063dc48849fSKiran Chandramohan 
3064dc48849fSKiran Chandramohan /// `fir.is_present` -->
3065dc48849fSKiran Chandramohan /// ```
3066dc48849fSKiran Chandramohan ///  %0 = llvm.mlir.constant(0 : i64)
3067dc48849fSKiran Chandramohan ///  %1 = llvm.ptrtoint %0
3068dc48849fSKiran Chandramohan ///  %2 = llvm.icmp "ne" %1, %0 : i64
3069dc48849fSKiran Chandramohan /// ```
3070dc48849fSKiran Chandramohan struct IsPresentOpConversion : public FIROpConversion<fir::IsPresentOp> {
3071dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3072dc48849fSKiran Chandramohan 
3073dc48849fSKiran Chandramohan   mlir::LogicalResult
3074dc48849fSKiran Chandramohan   matchAndRewrite(fir::IsPresentOp isPresent, OpAdaptor adaptor,
3075dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3076dc48849fSKiran Chandramohan     mlir::Type idxTy = lowerTy().indexType();
3077dc48849fSKiran Chandramohan     mlir::Location loc = isPresent.getLoc();
3078dc48849fSKiran Chandramohan     auto ptr = adaptor.getOperands()[0];
3079dc48849fSKiran Chandramohan 
3080dc48849fSKiran Chandramohan     if (isPresent.getVal().getType().isa<fir::BoxCharType>()) {
3081dc48849fSKiran Chandramohan       auto structTy = ptr.getType().cast<mlir::LLVM::LLVMStructType>();
3082dc48849fSKiran Chandramohan       assert(!structTy.isOpaque() && !structTy.getBody().empty());
3083dc48849fSKiran Chandramohan 
3084dc48849fSKiran Chandramohan       mlir::Type ty = structTy.getBody()[0];
3085dc48849fSKiran Chandramohan       mlir::MLIRContext *ctx = isPresent.getContext();
3086dc48849fSKiran Chandramohan       auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
3087dc48849fSKiran Chandramohan       ptr = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, ptr, c0);
3088dc48849fSKiran Chandramohan     }
3089dc48849fSKiran Chandramohan     mlir::LLVM::ConstantOp c0 =
3090dc48849fSKiran Chandramohan         genConstantIndex(isPresent.getLoc(), idxTy, rewriter, 0);
3091dc48849fSKiran Chandramohan     auto addr = rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, ptr);
3092dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
3093dc48849fSKiran Chandramohan         isPresent, mlir::LLVM::ICmpPredicate::ne, addr, c0);
3094dc48849fSKiran Chandramohan 
309544e58509SEric Schweitz     return mlir::success();
3096dc48849fSKiran Chandramohan   }
3097dc48849fSKiran Chandramohan };
3098dc48849fSKiran Chandramohan 
3099dc48849fSKiran Chandramohan /// Create value signaling an absent optional argument in a call, e.g.
3100dc48849fSKiran Chandramohan /// `fir.absent !fir.ref<i64>` -->  `llvm.mlir.null : !llvm.ptr<i64>`
3101dc48849fSKiran Chandramohan struct AbsentOpConversion : public FIROpConversion<fir::AbsentOp> {
3102dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3103dc48849fSKiran Chandramohan 
3104dc48849fSKiran Chandramohan   mlir::LogicalResult
3105dc48849fSKiran Chandramohan   matchAndRewrite(fir::AbsentOp absent, OpAdaptor,
3106dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3107dc48849fSKiran Chandramohan     mlir::Type ty = convertType(absent.getType());
3108dc48849fSKiran Chandramohan     mlir::Location loc = absent.getLoc();
3109dc48849fSKiran Chandramohan 
3110dc48849fSKiran Chandramohan     if (absent.getType().isa<fir::BoxCharType>()) {
3111dc48849fSKiran Chandramohan       auto structTy = ty.cast<mlir::LLVM::LLVMStructType>();
3112dc48849fSKiran Chandramohan       assert(!structTy.isOpaque() && !structTy.getBody().empty());
3113dc48849fSKiran Chandramohan       auto undefStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
3114dc48849fSKiran Chandramohan       auto nullField =
3115dc48849fSKiran Chandramohan           rewriter.create<mlir::LLVM::NullOp>(loc, structTy.getBody()[0]);
3116dc48849fSKiran Chandramohan       mlir::MLIRContext *ctx = absent.getContext();
3117dc48849fSKiran Chandramohan       auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
3118dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
3119dc48849fSKiran Chandramohan           absent, ty, undefStruct, nullField, c0);
3120dc48849fSKiran Chandramohan     } else {
3121dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(absent, ty);
3122dc48849fSKiran Chandramohan     }
312344e58509SEric Schweitz     return mlir::success();
3124dc48849fSKiran Chandramohan   }
3125dc48849fSKiran Chandramohan };
31265d27abe6SValentin Clement 
31277b5132daSValentin Clement //
31287b5132daSValentin Clement // Primitive operations on Complex types
31297b5132daSValentin Clement //
31307b5132daSValentin Clement 
31317b5132daSValentin Clement /// Generate inline code for complex addition/subtraction
31327b5132daSValentin Clement template <typename LLVMOP, typename OPTY>
3133c2acd453SAlexisPerry static mlir::LLVM::InsertValueOp
3134c2acd453SAlexisPerry complexSum(OPTY sumop, mlir::ValueRange opnds,
31357b5132daSValentin Clement            mlir::ConversionPatternRewriter &rewriter,
31367b5132daSValentin Clement            fir::LLVMTypeConverter &lowering) {
31377b5132daSValentin Clement   mlir::Value a = opnds[0];
31387b5132daSValentin Clement   mlir::Value b = opnds[1];
31397b5132daSValentin Clement   auto loc = sumop.getLoc();
31407b5132daSValentin Clement   auto ctx = sumop.getContext();
31417b5132daSValentin Clement   auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
31427b5132daSValentin Clement   auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
31437b5132daSValentin Clement   mlir::Type eleTy = lowering.convertType(getComplexEleTy(sumop.getType()));
31447b5132daSValentin Clement   mlir::Type ty = lowering.convertType(sumop.getType());
31457b5132daSValentin Clement   auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
31467b5132daSValentin Clement   auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
31477b5132daSValentin Clement   auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
31487b5132daSValentin Clement   auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
31497b5132daSValentin Clement   auto rx = rewriter.create<LLVMOP>(loc, eleTy, x0, x1);
31507b5132daSValentin Clement   auto ry = rewriter.create<LLVMOP>(loc, eleTy, y0, y1);
31517b5132daSValentin Clement   auto r0 = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
31527b5132daSValentin Clement   auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r0, rx, c0);
31537b5132daSValentin Clement   return rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ry, c1);
31547b5132daSValentin Clement }
3155dc48849fSKiran Chandramohan } // namespace
31567b5132daSValentin Clement 
3157c2acd453SAlexisPerry namespace {
31587b5132daSValentin Clement struct AddcOpConversion : public FIROpConversion<fir::AddcOp> {
31597b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
31607b5132daSValentin Clement 
31617b5132daSValentin Clement   mlir::LogicalResult
31627b5132daSValentin Clement   matchAndRewrite(fir::AddcOp addc, OpAdaptor adaptor,
31637b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
31647b5132daSValentin Clement     // given: (x + iy) + (x' + iy')
31657b5132daSValentin Clement     // result: (x + x') + i(y + y')
31667b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FAddOp>(addc, adaptor.getOperands(),
31677b5132daSValentin Clement                                             rewriter, lowerTy());
31687b5132daSValentin Clement     rewriter.replaceOp(addc, r.getResult());
316944e58509SEric Schweitz     return mlir::success();
31707b5132daSValentin Clement   }
31717b5132daSValentin Clement };
31727b5132daSValentin Clement 
31737b5132daSValentin Clement struct SubcOpConversion : public FIROpConversion<fir::SubcOp> {
31747b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
31757b5132daSValentin Clement 
31767b5132daSValentin Clement   mlir::LogicalResult
31777b5132daSValentin Clement   matchAndRewrite(fir::SubcOp subc, OpAdaptor adaptor,
31787b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
31797b5132daSValentin Clement     // given: (x + iy) - (x' + iy')
31807b5132daSValentin Clement     // result: (x - x') + i(y - y')
31817b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FSubOp>(subc, adaptor.getOperands(),
31827b5132daSValentin Clement                                             rewriter, lowerTy());
31837b5132daSValentin Clement     rewriter.replaceOp(subc, r.getResult());
318444e58509SEric Schweitz     return mlir::success();
31857b5132daSValentin Clement   }
31867b5132daSValentin Clement };
31877b5132daSValentin Clement 
31887b5132daSValentin Clement /// Inlined complex multiply
31897b5132daSValentin Clement struct MulcOpConversion : public FIROpConversion<fir::MulcOp> {
31907b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
31917b5132daSValentin Clement 
31927b5132daSValentin Clement   mlir::LogicalResult
31937b5132daSValentin Clement   matchAndRewrite(fir::MulcOp mulc, OpAdaptor adaptor,
31947b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
31957b5132daSValentin Clement     // TODO: Can we use a call to __muldc3 ?
31967b5132daSValentin Clement     // given: (x + iy) * (x' + iy')
31977b5132daSValentin Clement     // result: (xx'-yy')+i(xy'+yx')
31987b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
31997b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
32007b5132daSValentin Clement     auto loc = mulc.getLoc();
32017b5132daSValentin Clement     auto *ctx = mulc.getContext();
32027b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
32037b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
32047b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(mulc.getType()));
32057b5132daSValentin Clement     mlir::Type ty = convertType(mulc.getType());
32067b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
32077b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
32087b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
32097b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
32107b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
32117b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
32127b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
32137b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xy, yx);
32147b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
32157b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, xx, yy);
32167b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
32177b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
32187b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
32197b5132daSValentin Clement     rewriter.replaceOp(mulc, r0.getResult());
322044e58509SEric Schweitz     return mlir::success();
32217b5132daSValentin Clement   }
32227b5132daSValentin Clement };
32237b5132daSValentin Clement 
32247b5132daSValentin Clement /// Inlined complex division
32257b5132daSValentin Clement struct DivcOpConversion : public FIROpConversion<fir::DivcOp> {
32267b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
32277b5132daSValentin Clement 
32287b5132daSValentin Clement   mlir::LogicalResult
32297b5132daSValentin Clement   matchAndRewrite(fir::DivcOp divc, OpAdaptor adaptor,
32307b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
32317b5132daSValentin Clement     // TODO: Can we use a call to __divdc3 instead?
32327b5132daSValentin Clement     // Just generate inline code for now.
32337b5132daSValentin Clement     // given: (x + iy) / (x' + iy')
32347b5132daSValentin Clement     // result: ((xx'+yy')/d) + i((yx'-xy')/d) where d = x'x' + y'y'
32357b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
32367b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
32377b5132daSValentin Clement     auto loc = divc.getLoc();
32387b5132daSValentin Clement     auto *ctx = divc.getContext();
32397b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
32407b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
32417b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(divc.getType()));
32427b5132daSValentin Clement     mlir::Type ty = convertType(divc.getType());
32437b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
32447b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
32457b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
32467b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
32477b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
32487b5132daSValentin Clement     auto x1x1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x1, x1);
32497b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
32507b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
32517b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
32527b5132daSValentin Clement     auto y1y1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y1, y1);
32537b5132daSValentin Clement     auto d = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, x1x1, y1y1);
32547b5132daSValentin Clement     auto rrn = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xx, yy);
32557b5132daSValentin Clement     auto rin = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, yx, xy);
32567b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rrn, d);
32577b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rin, d);
32587b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
32597b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
32607b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
32617b5132daSValentin Clement     rewriter.replaceOp(divc, r0.getResult());
326244e58509SEric Schweitz     return mlir::success();
32637b5132daSValentin Clement   }
32647b5132daSValentin Clement };
32657b5132daSValentin Clement 
32667b5132daSValentin Clement /// Inlined complex negation
32677b5132daSValentin Clement struct NegcOpConversion : public FIROpConversion<fir::NegcOp> {
32687b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
32697b5132daSValentin Clement 
32707b5132daSValentin Clement   mlir::LogicalResult
32717b5132daSValentin Clement   matchAndRewrite(fir::NegcOp neg, OpAdaptor adaptor,
32727b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
32737b5132daSValentin Clement     // given: -(x + iy)
32747b5132daSValentin Clement     // result: -x - iy
32757b5132daSValentin Clement     auto *ctxt = neg.getContext();
32767b5132daSValentin Clement     auto eleTy = convertType(getComplexEleTy(neg.getType()));
32777b5132daSValentin Clement     auto ty = convertType(neg.getType());
32787b5132daSValentin Clement     auto loc = neg.getLoc();
32797b5132daSValentin Clement     mlir::Value o0 = adaptor.getOperands()[0];
32807b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0));
32817b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1));
32827b5132daSValentin Clement     auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c0);
32837b5132daSValentin Clement     auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c1);
32847b5132daSValentin Clement     auto nrp = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, rp);
32857b5132daSValentin Clement     auto nip = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, ip);
32867b5132daSValentin Clement     auto r = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, o0, nrp, c0);
32877b5132daSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(neg, ty, r, nip, c1);
328844e58509SEric Schweitz     return mlir::success();
32897b5132daSValentin Clement   }
32907b5132daSValentin Clement };
32917b5132daSValentin Clement 
32921ed5a90fSValentin Clement /// Conversion pattern for operation that must be dead. The information in these
32931ed5a90fSValentin Clement /// operations is used by other operation. At this point they should not have
32941ed5a90fSValentin Clement /// anymore uses.
32951ed5a90fSValentin Clement /// These operations are normally dead after the pre-codegen pass.
32961ed5a90fSValentin Clement template <typename FromOp>
32971ed5a90fSValentin Clement struct MustBeDeadConversion : public FIROpConversion<FromOp> {
3298013160f6SJean Perier   explicit MustBeDeadConversion(fir::LLVMTypeConverter &lowering,
3299013160f6SJean Perier                                 const fir::FIRToLLVMPassOptions &options)
3300013160f6SJean Perier       : FIROpConversion<FromOp>(lowering, options) {}
33011ed5a90fSValentin Clement   using OpAdaptor = typename FromOp::Adaptor;
33021ed5a90fSValentin Clement 
33031ed5a90fSValentin Clement   mlir::LogicalResult
33041ed5a90fSValentin Clement   matchAndRewrite(FromOp op, OpAdaptor adaptor,
33051ed5a90fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const final {
33061ed5a90fSValentin Clement     if (!op->getUses().empty())
33071ed5a90fSValentin Clement       return rewriter.notifyMatchFailure(op, "op must be dead");
33081ed5a90fSValentin Clement     rewriter.eraseOp(op);
330944e58509SEric Schweitz     return mlir::success();
33101ed5a90fSValentin Clement   }
33111ed5a90fSValentin Clement };
33121ed5a90fSValentin Clement 
33131ed5a90fSValentin Clement struct ShapeOpConversion : public MustBeDeadConversion<fir::ShapeOp> {
33141ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
33151ed5a90fSValentin Clement };
33161ed5a90fSValentin Clement 
33171ed5a90fSValentin Clement struct ShapeShiftOpConversion : public MustBeDeadConversion<fir::ShapeShiftOp> {
33181ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
33191ed5a90fSValentin Clement };
33201ed5a90fSValentin Clement 
33211ed5a90fSValentin Clement struct ShiftOpConversion : public MustBeDeadConversion<fir::ShiftOp> {
33221ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
33231ed5a90fSValentin Clement };
33241ed5a90fSValentin Clement 
33251ed5a90fSValentin Clement struct SliceOpConversion : public MustBeDeadConversion<fir::SliceOp> {
33261ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
33271ed5a90fSValentin Clement };
33281ed5a90fSValentin Clement 
3329044d5b5dSValentin Clement } // namespace
3330044d5b5dSValentin Clement 
3331044d5b5dSValentin Clement namespace {
3332044d5b5dSValentin Clement /// Convert FIR dialect to LLVM dialect
3333044d5b5dSValentin Clement ///
3334044d5b5dSValentin Clement /// This pass lowers all FIR dialect operations to LLVM IR dialect. An
3335044d5b5dSValentin Clement /// MLIR pass is used to lower residual Std dialect to LLVM IR dialect.
3336044d5b5dSValentin Clement class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> {
3337044d5b5dSValentin Clement public:
3338013160f6SJean Perier   FIRToLLVMLowering() = default;
3339013160f6SJean Perier   FIRToLLVMLowering(fir::FIRToLLVMPassOptions options) : options{options} {}
3340044d5b5dSValentin Clement   mlir::ModuleOp getModule() { return getOperation(); }
3341044d5b5dSValentin Clement 
3342044d5b5dSValentin Clement   void runOnOperation() override final {
33437b5132daSValentin Clement     auto mod = getModule();
334444e58509SEric Schweitz     if (!forcedTargetTriple.empty())
33457b5132daSValentin Clement       fir::setTargetTriple(mod, forcedTargetTriple);
33467b5132daSValentin Clement 
3347044d5b5dSValentin Clement     auto *context = getModule().getContext();
3348044d5b5dSValentin Clement     fir::LLVMTypeConverter typeConverter{getModule()};
33499f85c198SRiver Riddle     mlir::RewritePatternSet pattern(context);
3350df3b9810SValentin Clement     pattern.insert<
3351420ad7ceSAndrzej Warzynski         AbsentOpConversion, AddcOpConversion, AddrOfOpConversion,
3352c2acd453SAlexisPerry         AllocaOpConversion, AllocMemOpConversion, BoxAddrOpConversion,
3353c2acd453SAlexisPerry         BoxCharLenOpConversion, BoxDimsOpConversion, BoxEleSizeOpConversion,
3354c2acd453SAlexisPerry         BoxIsAllocOpConversion, BoxIsArrayOpConversion, BoxIsPtrOpConversion,
3355c2acd453SAlexisPerry         BoxProcHostOpConversion, BoxRankOpConversion, BoxTypeDescOpConversion,
3356c2acd453SAlexisPerry         CallOpConversion, CmpcOpConversion, ConstcOpConversion,
3357e6e7da55SAndrzej Warzynski         ConvertOpConversion, CoordinateOpConversion, DispatchOpConversion,
3358e6e7da55SAndrzej Warzynski         DispatchTableOpConversion, DTEntryOpConversion, DivcOpConversion,
3359e6e7da55SAndrzej Warzynski         EmboxOpConversion, EmboxCharOpConversion, EmboxProcOpConversion,
3360e6e7da55SAndrzej Warzynski         ExtractValueOpConversion, FieldIndexOpConversion, FirEndOpConversion,
3361dc48849fSKiran Chandramohan         FreeMemOpConversion, GenTypeDescOpConversion, GlobalLenOpConversion,
3362dc48849fSKiran Chandramohan         GlobalOpConversion, HasValueOpConversion, InsertOnRangeOpConversion,
3363e6e7da55SAndrzej Warzynski         InsertValueOpConversion, IsPresentOpConversion,
3364dc48849fSKiran Chandramohan         LenParamIndexOpConversion, LoadOpConversion, MulcOpConversion,
3365dc48849fSKiran Chandramohan         NegcOpConversion, NoReassocOpConversion, SelectCaseOpConversion,
3366e6e7da55SAndrzej Warzynski         SelectOpConversion, SelectRankOpConversion, SelectTypeOpConversion,
3367e6e7da55SAndrzej Warzynski         ShapeOpConversion, ShapeShiftOpConversion, ShiftOpConversion,
3368e6e7da55SAndrzej Warzynski         SliceOpConversion, StoreOpConversion, StringLitOpConversion,
3369e6e7da55SAndrzej Warzynski         SubcOpConversion, UnboxCharOpConversion, UnboxProcOpConversion,
3370e6e7da55SAndrzej Warzynski         UndefOpConversion, UnreachableOpConversion, XArrayCoorOpConversion,
3371013160f6SJean Perier         XEmboxOpConversion, XReboxOpConversion, ZeroOpConversion>(typeConverter,
3372013160f6SJean Perier                                                                   options);
33735a7b9194SRiver Riddle     mlir::populateFuncToLLVMConversionPatterns(typeConverter, pattern);
3374c6ac9370SKiran Chandramohan     mlir::populateOpenMPToLLVMConversionPatterns(typeConverter, pattern);
3375044d5b5dSValentin Clement     mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter,
3376044d5b5dSValentin Clement                                                             pattern);
3377ace01605SRiver Riddle     mlir::cf::populateControlFlowToLLVMConversionPatterns(typeConverter,
3378ace01605SRiver Riddle                                                           pattern);
33799f356579SSlava Zakharin     // Convert math-like dialect operations, which can be produced
33809f356579SSlava Zakharin     // when late math lowering mode is used, into llvm dialect.
33819f356579SSlava Zakharin     mlir::populateMathToLLVMConversionPatterns(typeConverter, pattern);
33829f356579SSlava Zakharin     mlir::populateMathToLibmConversionPatterns(pattern, /*benefit=*/0);
3383044d5b5dSValentin Clement     mlir::ConversionTarget target{*context};
3384044d5b5dSValentin Clement     target.addLegalDialect<mlir::LLVM::LLVMDialect>();
3385c6ac9370SKiran Chandramohan     // The OpenMP dialect is legal for Operations without regions, for those
3386c6ac9370SKiran Chandramohan     // which contains regions it is legal if the region contains only the
338700c511b3SNimish Mishra     // LLVM dialect. Add OpenMP dialect as a legal dialect for conversion and
338800c511b3SNimish Mishra     // legalize conversion of OpenMP operations without regions.
338900c511b3SNimish Mishra     mlir::configureOpenMPToLLVMConversionLegality(target, typeConverter);
3390c6ac9370SKiran Chandramohan     target.addLegalDialect<mlir::omp::OpenMPDialect>();
3391044d5b5dSValentin Clement 
3392044d5b5dSValentin Clement     // required NOPs for applying a full conversion
3393044d5b5dSValentin Clement     target.addLegalOp<mlir::ModuleOp>();
3394044d5b5dSValentin Clement 
3395044d5b5dSValentin Clement     // apply the patterns
3396044d5b5dSValentin Clement     if (mlir::failed(mlir::applyFullConversion(getModule(), target,
3397044d5b5dSValentin Clement                                                std::move(pattern)))) {
3398044d5b5dSValentin Clement       signalPassFailure();
3399044d5b5dSValentin Clement     }
3400044d5b5dSValentin Clement   }
3401013160f6SJean Perier 
3402013160f6SJean Perier private:
3403013160f6SJean Perier   fir::FIRToLLVMPassOptions options;
3404044d5b5dSValentin Clement };
3405853e79d8SValentin Clement 
3406853e79d8SValentin Clement /// Lower from LLVM IR dialect to proper LLVM-IR and dump the module
3407853e79d8SValentin Clement struct LLVMIRLoweringPass
3408853e79d8SValentin Clement     : public mlir::PassWrapper<LLVMIRLoweringPass,
3409853e79d8SValentin Clement                                mlir::OperationPass<mlir::ModuleOp>> {
34105e50dd04SRiver Riddle   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(LLVMIRLoweringPass)
34115e50dd04SRiver Riddle 
341244e58509SEric Schweitz   LLVMIRLoweringPass(llvm::raw_ostream &output, fir::LLVMIRLoweringPrinter p)
3413853e79d8SValentin Clement       : output{output}, printer{p} {}
3414853e79d8SValentin Clement 
3415853e79d8SValentin Clement   mlir::ModuleOp getModule() { return getOperation(); }
3416853e79d8SValentin Clement 
3417853e79d8SValentin Clement   void runOnOperation() override final {
3418853e79d8SValentin Clement     auto *ctx = getModule().getContext();
3419853e79d8SValentin Clement     auto optName = getModule().getName();
3420853e79d8SValentin Clement     llvm::LLVMContext llvmCtx;
3421853e79d8SValentin Clement     if (auto llvmModule = mlir::translateModuleToLLVMIR(
3422853e79d8SValentin Clement             getModule(), llvmCtx, optName ? *optName : "FIRModule")) {
3423853e79d8SValentin Clement       printer(*llvmModule, output);
3424853e79d8SValentin Clement       return;
3425853e79d8SValentin Clement     }
3426853e79d8SValentin Clement 
3427853e79d8SValentin Clement     mlir::emitError(mlir::UnknownLoc::get(ctx), "could not emit LLVM-IR\n");
3428853e79d8SValentin Clement     signalPassFailure();
3429853e79d8SValentin Clement   }
3430853e79d8SValentin Clement 
3431853e79d8SValentin Clement private:
343244e58509SEric Schweitz   llvm::raw_ostream &output;
343344e58509SEric Schweitz   fir::LLVMIRLoweringPrinter printer;
3434853e79d8SValentin Clement };
3435853e79d8SValentin Clement 
3436044d5b5dSValentin Clement } // namespace
3437044d5b5dSValentin Clement 
3438044d5b5dSValentin Clement std::unique_ptr<mlir::Pass> fir::createFIRToLLVMPass() {
3439044d5b5dSValentin Clement   return std::make_unique<FIRToLLVMLowering>();
3440044d5b5dSValentin Clement }
3441853e79d8SValentin Clement 
3442853e79d8SValentin Clement std::unique_ptr<mlir::Pass>
344344e58509SEric Schweitz fir::createFIRToLLVMPass(fir::FIRToLLVMPassOptions options) {
3444013160f6SJean Perier   return std::make_unique<FIRToLLVMLowering>(options);
3445013160f6SJean Perier }
3446013160f6SJean Perier 
3447013160f6SJean Perier std::unique_ptr<mlir::Pass>
344844e58509SEric Schweitz fir::createLLVMDialectToLLVMPass(llvm::raw_ostream &output,
3449853e79d8SValentin Clement                                  fir::LLVMIRLoweringPrinter printer) {
3450853e79d8SValentin Clement   return std::make_unique<LLVMIRLoweringPass>(output, printer);
3451853e79d8SValentin Clement }
3452