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 
getVoidPtrType(mlir::MLIRContext * context)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
genConstantIndex(mlir::Location loc,mlir::Type ity,mlir::ConversionPatternRewriter & rewriter,std::int64_t offset)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 
createBlock(mlir::ConversionPatternRewriter & rewriter,mlir::Block * insertBefore)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 
67af40f99eSJean Perier /// Extract constant from a value that must be the result of one of the
68af40f99eSJean Perier /// ConstantOp operations.
getConstantIntValue(mlir::Value val)69af40f99eSJean Perier static int64_t getConstantIntValue(mlir::Value val) {
70af40f99eSJean Perier   assert(val && val.dyn_cast<mlir::OpResult>() && "must not be null value");
71af40f99eSJean Perier   mlir::Operation *defop = val.getDefiningOp();
72af40f99eSJean Perier 
73af40f99eSJean Perier   if (auto constOp = mlir::dyn_cast<mlir::arith::ConstantIntOp>(defop))
74af40f99eSJean Perier     return constOp.value();
75af40f99eSJean Perier   if (auto llConstOp = mlir::dyn_cast<mlir::LLVM::ConstantOp>(defop))
76af40f99eSJean Perier     if (auto attr = llConstOp.getValue().dyn_cast<mlir::IntegerAttr>())
77af40f99eSJean Perier       return attr.getValue().getSExtValue();
78af40f99eSJean Perier   fir::emitFatalError(val.getLoc(), "must be a constant");
79af40f99eSJean Perier }
80af40f99eSJean Perier 
81044d5b5dSValentin Clement namespace {
82044d5b5dSValentin Clement /// FIR conversion pattern template
83044d5b5dSValentin Clement template <typename FromOp>
84044d5b5dSValentin Clement class FIROpConversion : public mlir::ConvertOpToLLVMPattern<FromOp> {
85044d5b5dSValentin Clement public:
FIROpConversion(fir::LLVMTypeConverter & lowering,const fir::FIRToLLVMPassOptions & options)86013160f6SJean Perier   explicit FIROpConversion(fir::LLVMTypeConverter &lowering,
87013160f6SJean Perier                            const fir::FIRToLLVMPassOptions &options)
88013160f6SJean Perier       : mlir::ConvertOpToLLVMPattern<FromOp>(lowering), options(options) {}
89044d5b5dSValentin Clement 
90044d5b5dSValentin Clement protected:
convertType(mlir::Type ty) const91044d5b5dSValentin Clement   mlir::Type convertType(mlir::Type ty) const {
92044d5b5dSValentin Clement     return lowerTy().convertType(ty);
93044d5b5dSValentin Clement   }
voidPtrTy() const94c2acd453SAlexisPerry   mlir::Type voidPtrTy() const { return getVoidPtrType(); }
95044d5b5dSValentin Clement 
getVoidPtrType() const965d27abe6SValentin Clement   mlir::Type getVoidPtrType() const {
975d27abe6SValentin Clement     return mlir::LLVM::LLVMPointerType::get(
985d27abe6SValentin Clement         mlir::IntegerType::get(&lowerTy().getContext(), 8));
995d27abe6SValentin Clement   }
1005d27abe6SValentin Clement 
101df3b9810SValentin Clement   mlir::LLVM::ConstantOp
genI32Constant(mlir::Location loc,mlir::ConversionPatternRewriter & rewriter,int value) const102af6ee580SValentin Clement   genI32Constant(mlir::Location loc, mlir::ConversionPatternRewriter &rewriter,
103af6ee580SValentin Clement                  int value) const {
104af6ee580SValentin Clement     mlir::Type i32Ty = rewriter.getI32Type();
105af6ee580SValentin Clement     mlir::IntegerAttr attr = rewriter.getI32IntegerAttr(value);
106af6ee580SValentin Clement     return rewriter.create<mlir::LLVM::ConstantOp>(loc, i32Ty, attr);
107af6ee580SValentin Clement   }
108af6ee580SValentin Clement 
109af6ee580SValentin Clement   mlir::LLVM::ConstantOp
genConstantOffset(mlir::Location loc,mlir::ConversionPatternRewriter & rewriter,int offset) const110df3b9810SValentin Clement   genConstantOffset(mlir::Location loc,
111df3b9810SValentin Clement                     mlir::ConversionPatternRewriter &rewriter,
112df3b9810SValentin Clement                     int offset) const {
113af6ee580SValentin Clement     mlir::Type ity = lowerTy().offsetType();
114af6ee580SValentin Clement     mlir::IntegerAttr cattr = rewriter.getI32IntegerAttr(offset);
115df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr);
116df3b9810SValentin Clement   }
117df3b9810SValentin Clement 
118dc48849fSKiran Chandramohan   /// Perform an extension or truncation as needed on an integer value. Lowering
119dc48849fSKiran Chandramohan   /// to the specific target may involve some sign-extending or truncation of
120dc48849fSKiran Chandramohan   /// values, particularly to fit them from abstract box types to the
121dc48849fSKiran Chandramohan   /// appropriate reified structures.
integerCast(mlir::Location loc,mlir::ConversionPatternRewriter & rewriter,mlir::Type ty,mlir::Value val) const122dc48849fSKiran Chandramohan   mlir::Value integerCast(mlir::Location loc,
123dc48849fSKiran Chandramohan                           mlir::ConversionPatternRewriter &rewriter,
124dc48849fSKiran Chandramohan                           mlir::Type ty, mlir::Value val) const {
125dc48849fSKiran Chandramohan     auto valTy = val.getType();
126dc48849fSKiran Chandramohan     // If the value was not yet lowered, lower its type so that it can
127dc48849fSKiran Chandramohan     // be used in getPrimitiveTypeSizeInBits.
128dc48849fSKiran Chandramohan     if (!valTy.isa<mlir::IntegerType>())
129dc48849fSKiran Chandramohan       valTy = convertType(valTy);
130dc48849fSKiran Chandramohan     auto toSize = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
131dc48849fSKiran Chandramohan     auto fromSize = mlir::LLVM::getPrimitiveTypeSizeInBits(valTy);
132dc48849fSKiran Chandramohan     if (toSize < fromSize)
133dc48849fSKiran Chandramohan       return rewriter.create<mlir::LLVM::TruncOp>(loc, ty, val);
134dc48849fSKiran Chandramohan     if (toSize > fromSize)
135dc48849fSKiran Chandramohan       return rewriter.create<mlir::LLVM::SExtOp>(loc, ty, val);
136dc48849fSKiran Chandramohan     return val;
137dc48849fSKiran Chandramohan   }
138dc48849fSKiran Chandramohan 
139b6e44ecdSValentin Clement   /// Construct code sequence to extract the specifc value from a `fir.box`.
getValueFromBox(mlir::Location loc,mlir::Value box,mlir::Type resultTy,mlir::ConversionPatternRewriter & rewriter,unsigned boxValue) const140b6e44ecdSValentin Clement   mlir::Value getValueFromBox(mlir::Location loc, mlir::Value box,
141df3b9810SValentin Clement                               mlir::Type resultTy,
142b6e44ecdSValentin Clement                               mlir::ConversionPatternRewriter &rewriter,
143b6e44ecdSValentin Clement                               unsigned boxValue) const {
144df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
145b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp cValuePos =
146b6e44ecdSValentin Clement         genConstantOffset(loc, rewriter, boxValue);
147df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(resultTy);
148df3b9810SValentin Clement     auto p = rewriter.create<mlir::LLVM::GEPOp>(
14930122656SAlex Zinenko         loc, pty, box, mlir::ValueRange{c0, cValuePos});
150df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, resultTy, p);
151df3b9810SValentin Clement   }
152df3b9810SValentin Clement 
153df3b9810SValentin Clement   /// Method to construct code sequence to get the triple for dimension `dim`
154df3b9810SValentin Clement   /// from a box.
15544e58509SEric Schweitz   llvm::SmallVector<mlir::Value, 3>
getDimsFromBox(mlir::Location loc,llvm::ArrayRef<mlir::Type> retTys,mlir::Value box,mlir::Value dim,mlir::ConversionPatternRewriter & rewriter) const15644e58509SEric Schweitz   getDimsFromBox(mlir::Location loc, llvm::ArrayRef<mlir::Type> retTys,
157df3b9810SValentin Clement                  mlir::Value box, mlir::Value dim,
158df3b9810SValentin Clement                  mlir::ConversionPatternRewriter &rewriter) const {
159df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
160df3b9810SValentin Clement     mlir::LLVM::ConstantOp cDims =
161df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kDimsPosInBox);
162df3b9810SValentin Clement     mlir::LLVM::LoadOp l0 =
163df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 0, retTys[0], rewriter);
164df3b9810SValentin Clement     mlir::LLVM::LoadOp l1 =
165df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 1, retTys[1], rewriter);
166df3b9810SValentin Clement     mlir::LLVM::LoadOp l2 =
167df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 2, retTys[2], rewriter);
168df3b9810SValentin Clement     return {l0.getResult(), l1.getResult(), l2.getResult()};
169df3b9810SValentin Clement   }
170df3b9810SValentin Clement 
171df3b9810SValentin Clement   mlir::LLVM::LoadOp
loadFromOffset(mlir::Location loc,mlir::Value a,mlir::LLVM::ConstantOp c0,mlir::LLVM::ConstantOp cDims,mlir::Value dim,int off,mlir::Type ty,mlir::ConversionPatternRewriter & rewriter) const172df3b9810SValentin Clement   loadFromOffset(mlir::Location loc, mlir::Value a, mlir::LLVM::ConstantOp c0,
173df3b9810SValentin Clement                  mlir::LLVM::ConstantOp cDims, mlir::Value dim, int off,
174df3b9810SValentin Clement                  mlir::Type ty,
175df3b9810SValentin Clement                  mlir::ConversionPatternRewriter &rewriter) const {
176df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
177df3b9810SValentin Clement     mlir::LLVM::ConstantOp c = genConstantOffset(loc, rewriter, off);
178df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, a, c0, cDims, dim, c);
179df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
180df3b9810SValentin Clement   }
181df3b9810SValentin Clement 
1825d27abe6SValentin Clement   mlir::Value
loadStrideFromBox(mlir::Location loc,mlir::Value box,unsigned dim,mlir::ConversionPatternRewriter & rewriter) const1835d27abe6SValentin Clement   loadStrideFromBox(mlir::Location loc, mlir::Value box, unsigned dim,
1845d27abe6SValentin Clement                     mlir::ConversionPatternRewriter &rewriter) const {
1855d27abe6SValentin Clement     auto idxTy = lowerTy().indexType();
1865d27abe6SValentin Clement     auto c0 = genConstantOffset(loc, rewriter, 0);
1875d27abe6SValentin Clement     auto cDims = genConstantOffset(loc, rewriter, kDimsPosInBox);
1885d27abe6SValentin Clement     auto dimValue = genConstantIndex(loc, idxTy, rewriter, dim);
1895d27abe6SValentin Clement     return loadFromOffset(loc, box, c0, cDims, dimValue, kDimStridePos, idxTy,
1905d27abe6SValentin Clement                           rewriter);
1915d27abe6SValentin Clement   }
1925d27abe6SValentin Clement 
193df3b9810SValentin Clement   /// Read base address from a fir.box. Returned address has type ty.
194df3b9810SValentin Clement   mlir::Value
loadBaseAddrFromBox(mlir::Location loc,mlir::Type ty,mlir::Value box,mlir::ConversionPatternRewriter & rewriter) const195df3b9810SValentin Clement   loadBaseAddrFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box,
196df3b9810SValentin Clement                       mlir::ConversionPatternRewriter &rewriter) const {
197df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
198df3b9810SValentin Clement     mlir::LLVM::ConstantOp cAddr =
199df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kAddrPosInBox);
200df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
201df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cAddr);
202df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
203df3b9810SValentin Clement   }
204df3b9810SValentin Clement 
205df3b9810SValentin Clement   mlir::Value
loadElementSizeFromBox(mlir::Location loc,mlir::Type ty,mlir::Value box,mlir::ConversionPatternRewriter & rewriter) const206df3b9810SValentin Clement   loadElementSizeFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box,
207df3b9810SValentin Clement                          mlir::ConversionPatternRewriter &rewriter) const {
208df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
209df3b9810SValentin Clement     mlir::LLVM::ConstantOp cElemLen =
210df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kElemLenPosInBox);
211df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
212df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cElemLen);
213df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
214df3b9810SValentin Clement   }
215df3b9810SValentin Clement 
216af6ee580SValentin Clement   // Get the element type given an LLVM type that is of the form
217af6ee580SValentin Clement   // [llvm.ptr](array|struct|vector)+ and the provided indexes.
getBoxEleTy(mlir::Type type,llvm::ArrayRef<unsigned> indexes)218af6ee580SValentin Clement   static mlir::Type getBoxEleTy(mlir::Type type,
219af6ee580SValentin Clement                                 llvm::ArrayRef<unsigned> indexes) {
220af6ee580SValentin Clement     if (auto t = type.dyn_cast<mlir::LLVM::LLVMPointerType>())
221af6ee580SValentin Clement       type = t.getElementType();
222af6ee580SValentin Clement     for (auto i : indexes) {
223af6ee580SValentin Clement       if (auto t = type.dyn_cast<mlir::LLVM::LLVMStructType>()) {
224af6ee580SValentin Clement         assert(!t.isOpaque() && i < t.getBody().size());
225af6ee580SValentin Clement         type = t.getBody()[i];
226af6ee580SValentin Clement       } else if (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
227af6ee580SValentin Clement         type = t.getElementType();
228af6ee580SValentin Clement       } else if (auto t = type.dyn_cast<mlir::VectorType>()) {
229af6ee580SValentin Clement         type = t.getElementType();
230af6ee580SValentin Clement       } else {
231af6ee580SValentin Clement         fir::emitFatalError(mlir::UnknownLoc::get(type.getContext()),
232af6ee580SValentin Clement                             "request for invalid box element type");
233af6ee580SValentin Clement       }
234af6ee580SValentin Clement     }
235af6ee580SValentin Clement     return type;
236af6ee580SValentin Clement   }
237af6ee580SValentin Clement 
2385d27abe6SValentin Clement   // Return LLVM type of the base address given the LLVM type
2395d27abe6SValentin Clement   // of the related descriptor (lowered fir.box type).
getBaseAddrTypeFromBox(mlir::Type type)2405d27abe6SValentin Clement   static mlir::Type getBaseAddrTypeFromBox(mlir::Type type) {
2415d27abe6SValentin Clement     return getBoxEleTy(type, {kAddrPosInBox});
2425d27abe6SValentin Clement   }
2435d27abe6SValentin Clement 
244dc48849fSKiran Chandramohan   // Load the attribute from the \p box and perform a check against \p maskValue
245dc48849fSKiran Chandramohan   // The final comparison is implemented as `(attribute & maskValue) != 0`.
genBoxAttributeCheck(mlir::Location loc,mlir::Value box,mlir::ConversionPatternRewriter & rewriter,unsigned maskValue) const246dc48849fSKiran Chandramohan   mlir::Value genBoxAttributeCheck(mlir::Location loc, mlir::Value box,
247dc48849fSKiran Chandramohan                                    mlir::ConversionPatternRewriter &rewriter,
248dc48849fSKiran Chandramohan                                    unsigned maskValue) const {
249dc48849fSKiran Chandramohan     mlir::Type attrTy = rewriter.getI32Type();
250dc48849fSKiran Chandramohan     mlir::Value attribute =
251dc48849fSKiran Chandramohan         getValueFromBox(loc, box, attrTy, rewriter, kAttributePosInBox);
252dc48849fSKiran Chandramohan     mlir::LLVM::ConstantOp attrMask =
253dc48849fSKiran Chandramohan         genConstantOffset(loc, rewriter, maskValue);
254dc48849fSKiran Chandramohan     auto maskRes =
255dc48849fSKiran Chandramohan         rewriter.create<mlir::LLVM::AndOp>(loc, attrTy, attribute, attrMask);
256dc48849fSKiran Chandramohan     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
257dc48849fSKiran Chandramohan     return rewriter.create<mlir::LLVM::ICmpOp>(
258dc48849fSKiran Chandramohan         loc, mlir::LLVM::ICmpPredicate::ne, maskRes, c0);
259dc48849fSKiran Chandramohan   }
260dc48849fSKiran Chandramohan 
261df3b9810SValentin Clement   template <typename... ARGS>
genGEP(mlir::Location loc,mlir::Type ty,mlir::ConversionPatternRewriter & rewriter,mlir::Value base,ARGS...args) const262df3b9810SValentin Clement   mlir::LLVM::GEPOp genGEP(mlir::Location loc, mlir::Type ty,
263df3b9810SValentin Clement                            mlir::ConversionPatternRewriter &rewriter,
264df3b9810SValentin Clement                            mlir::Value base, ARGS... args) const {
265575c9d6dSValentin Clement     llvm::SmallVector<mlir::Value> cv = {args...};
266df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::GEPOp>(loc, ty, base, cv);
267df3b9810SValentin Clement   }
268df3b9810SValentin Clement 
lowerTy() const269044d5b5dSValentin Clement   fir::LLVMTypeConverter &lowerTy() const {
270044d5b5dSValentin Clement     return *static_cast<fir::LLVMTypeConverter *>(this->getTypeConverter());
271044d5b5dSValentin Clement   }
272013160f6SJean Perier 
273013160f6SJean Perier   const fir::FIRToLLVMPassOptions &options;
274044d5b5dSValentin Clement };
275044d5b5dSValentin Clement 
2763ae8e442SValentin Clement /// FIR conversion pattern template
2773ae8e442SValentin Clement template <typename FromOp>
2783ae8e442SValentin Clement class FIROpAndTypeConversion : public FIROpConversion<FromOp> {
2793ae8e442SValentin Clement public:
2803ae8e442SValentin Clement   using FIROpConversion<FromOp>::FIROpConversion;
2813ae8e442SValentin Clement   using OpAdaptor = typename FromOp::Adaptor;
2823ae8e442SValentin Clement 
2833ae8e442SValentin Clement   mlir::LogicalResult
matchAndRewrite(FromOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const2843ae8e442SValentin Clement   matchAndRewrite(FromOp op, OpAdaptor adaptor,
2853ae8e442SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const final {
2863ae8e442SValentin Clement     mlir::Type ty = this->convertType(op.getType());
2873ae8e442SValentin Clement     return doRewrite(op, ty, adaptor, rewriter);
2883ae8e442SValentin Clement   }
2893ae8e442SValentin Clement 
2903ae8e442SValentin Clement   virtual mlir::LogicalResult
2913ae8e442SValentin Clement   doRewrite(FromOp addr, mlir::Type ty, OpAdaptor adaptor,
2923ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const = 0;
2933ae8e442SValentin Clement };
294575c9d6dSValentin Clement } // namespace
2953ae8e442SValentin Clement 
296575c9d6dSValentin Clement namespace {
297575c9d6dSValentin Clement /// Lower `fir.address_of` operation to `llvm.address_of` operation.
298044d5b5dSValentin Clement struct AddrOfOpConversion : public FIROpConversion<fir::AddrOfOp> {
299044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
300044d5b5dSValentin Clement 
301044d5b5dSValentin Clement   mlir::LogicalResult
matchAndRewrite__anon447c3e180211::AddrOfOpConversion302044d5b5dSValentin Clement   matchAndRewrite(fir::AddrOfOp addr, OpAdaptor adaptor,
303044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
304044d5b5dSValentin Clement     auto ty = convertType(addr.getType());
305044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::AddressOfOp>(
306149ad3d5SShraiysh Vaishay         addr, ty, addr.getSymbol().getRootReference().getValue());
30744e58509SEric Schweitz     return mlir::success();
308044d5b5dSValentin Clement   }
309044d5b5dSValentin Clement };
3101e6d9c06SDiana Picus } // namespace
3111e6d9c06SDiana Picus 
3121e6d9c06SDiana Picus /// Lookup the function to compute the memory size of this parametric derived
3131e6d9c06SDiana Picus /// type. The size of the object may depend on the LEN type parameters of the
3141e6d9c06SDiana Picus /// derived type.
3151e6d9c06SDiana Picus static mlir::LLVM::LLVMFuncOp
getDependentTypeMemSizeFn(fir::RecordType recTy,fir::AllocaOp op,mlir::ConversionPatternRewriter & rewriter)3161e6d9c06SDiana Picus getDependentTypeMemSizeFn(fir::RecordType recTy, fir::AllocaOp op,
3171e6d9c06SDiana Picus                           mlir::ConversionPatternRewriter &rewriter) {
3181e6d9c06SDiana Picus   auto module = op->getParentOfType<mlir::ModuleOp>();
3191e6d9c06SDiana Picus   std::string name = recTy.getName().str() + "P.mem.size";
320575c9d6dSValentin Clement   if (auto memSizeFunc = module.lookupSymbol<mlir::LLVM::LLVMFuncOp>(name))
321575c9d6dSValentin Clement     return memSizeFunc;
322575c9d6dSValentin Clement   TODO(op.getLoc(), "did not find allocation function");
3231e6d9c06SDiana Picus }
3241e6d9c06SDiana Picus 
325ac0f4c8fSPeixinQiao // Compute the alloc scale size (constant factors encoded in the array type).
326ac0f4c8fSPeixinQiao // We do this for arrays without a constant interior or arrays of character with
327ac0f4c8fSPeixinQiao // dynamic length arrays, since those are the only ones that get decayed to a
328ac0f4c8fSPeixinQiao // pointer to the element type.
329ac0f4c8fSPeixinQiao template <typename OP>
330ac0f4c8fSPeixinQiao static mlir::Value
genAllocationScaleSize(OP op,mlir::Type ity,mlir::ConversionPatternRewriter & rewriter)331ac0f4c8fSPeixinQiao genAllocationScaleSize(OP op, mlir::Type ity,
332ac0f4c8fSPeixinQiao                        mlir::ConversionPatternRewriter &rewriter) {
333ac0f4c8fSPeixinQiao   mlir::Location loc = op.getLoc();
334ac0f4c8fSPeixinQiao   mlir::Type dataTy = op.getInType();
335ac0f4c8fSPeixinQiao   mlir::Type scalarType = fir::unwrapSequenceType(dataTy);
336ac0f4c8fSPeixinQiao   auto seqTy = dataTy.dyn_cast<fir::SequenceType>();
337ac0f4c8fSPeixinQiao   if ((op.hasShapeOperands() && seqTy && !seqTy.hasConstantInterior()) ||
338ac0f4c8fSPeixinQiao       (seqTy && fir::characterWithDynamicLen(scalarType))) {
339ac0f4c8fSPeixinQiao     fir::SequenceType::Extent constSize = 1;
340ac0f4c8fSPeixinQiao     for (auto extent : seqTy.getShape())
341ac0f4c8fSPeixinQiao       if (extent != fir::SequenceType::getUnknownExtent())
342ac0f4c8fSPeixinQiao         constSize *= extent;
343ac0f4c8fSPeixinQiao     if (constSize != 1) {
344ac0f4c8fSPeixinQiao       mlir::Value constVal{
345ac0f4c8fSPeixinQiao           genConstantIndex(loc, ity, rewriter, constSize).getResult()};
346ac0f4c8fSPeixinQiao       return constVal;
347ac0f4c8fSPeixinQiao     }
348ac0f4c8fSPeixinQiao   }
349ac0f4c8fSPeixinQiao   return nullptr;
350ac0f4c8fSPeixinQiao }
351ac0f4c8fSPeixinQiao 
3521e6d9c06SDiana Picus namespace {
3531e6d9c06SDiana Picus /// convert to LLVM IR dialect `alloca`
3541e6d9c06SDiana Picus struct AllocaOpConversion : public FIROpConversion<fir::AllocaOp> {
3551e6d9c06SDiana Picus   using FIROpConversion::FIROpConversion;
3561e6d9c06SDiana Picus 
3571e6d9c06SDiana Picus   mlir::LogicalResult
matchAndRewrite__anon447c3e180311::AllocaOpConversion3581e6d9c06SDiana Picus   matchAndRewrite(fir::AllocaOp alloc, OpAdaptor adaptor,
3591e6d9c06SDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
3601e6d9c06SDiana Picus     mlir::ValueRange operands = adaptor.getOperands();
3611e6d9c06SDiana Picus     auto loc = alloc.getLoc();
3621e6d9c06SDiana Picus     mlir::Type ity = lowerTy().indexType();
3631e6d9c06SDiana Picus     unsigned i = 0;
3641e6d9c06SDiana Picus     mlir::Value size = genConstantIndex(loc, ity, rewriter, 1).getResult();
3651e6d9c06SDiana Picus     mlir::Type ty = convertType(alloc.getType());
3661e6d9c06SDiana Picus     mlir::Type resultTy = ty;
3671e6d9c06SDiana Picus     if (alloc.hasLenParams()) {
3681e6d9c06SDiana Picus       unsigned end = alloc.numLenParams();
3691e6d9c06SDiana Picus       llvm::SmallVector<mlir::Value> lenParams;
3701e6d9c06SDiana Picus       for (; i < end; ++i)
3711e6d9c06SDiana Picus         lenParams.push_back(operands[i]);
3721e6d9c06SDiana Picus       mlir::Type scalarType = fir::unwrapSequenceType(alloc.getInType());
3731e6d9c06SDiana Picus       if (auto chrTy = scalarType.dyn_cast<fir::CharacterType>()) {
3741e6d9c06SDiana Picus         fir::CharacterType rawCharTy = fir::CharacterType::getUnknownLen(
3751e6d9c06SDiana Picus             chrTy.getContext(), chrTy.getFKind());
3761e6d9c06SDiana Picus         ty = mlir::LLVM::LLVMPointerType::get(convertType(rawCharTy));
3771e6d9c06SDiana Picus         assert(end == 1);
3781e6d9c06SDiana Picus         size = integerCast(loc, rewriter, ity, lenParams[0]);
3791e6d9c06SDiana Picus       } else if (auto recTy = scalarType.dyn_cast<fir::RecordType>()) {
3801e6d9c06SDiana Picus         mlir::LLVM::LLVMFuncOp memSizeFn =
3811e6d9c06SDiana Picus             getDependentTypeMemSizeFn(recTy, alloc, rewriter);
3821e6d9c06SDiana Picus         if (!memSizeFn)
3831e6d9c06SDiana Picus           emitError(loc, "did not find allocation function");
3841e6d9c06SDiana Picus         mlir::NamedAttribute attr = rewriter.getNamedAttr(
3851e6d9c06SDiana Picus             "callee", mlir::SymbolRefAttr::get(memSizeFn));
3861e6d9c06SDiana Picus         auto call = rewriter.create<mlir::LLVM::CallOp>(
3871e6d9c06SDiana Picus             loc, ity, lenParams, llvm::ArrayRef<mlir::NamedAttribute>{attr});
3881e6d9c06SDiana Picus         size = call.getResult(0);
389575c9d6dSValentin Clement         ty = ::getVoidPtrType(alloc.getContext());
3901e6d9c06SDiana Picus       } else {
3911e6d9c06SDiana Picus         return emitError(loc, "unexpected type ")
3921e6d9c06SDiana Picus                << scalarType << " with type parameters";
3931e6d9c06SDiana Picus       }
3941e6d9c06SDiana Picus     }
395ac0f4c8fSPeixinQiao     if (auto scaleSize = genAllocationScaleSize(alloc, ity, rewriter))
396ac0f4c8fSPeixinQiao       size = rewriter.create<mlir::LLVM::MulOp>(loc, ity, size, scaleSize);
3971e6d9c06SDiana Picus     if (alloc.hasShapeOperands()) {
3981e6d9c06SDiana Picus       unsigned end = operands.size();
3991e6d9c06SDiana Picus       for (; i < end; ++i)
4001e6d9c06SDiana Picus         size = rewriter.create<mlir::LLVM::MulOp>(
4011e6d9c06SDiana Picus             loc, ity, size, integerCast(loc, rewriter, ity, operands[i]));
4021e6d9c06SDiana Picus     }
4031e6d9c06SDiana Picus     if (ty == resultTy) {
4041e6d9c06SDiana Picus       // Do not emit the bitcast if ty and resultTy are the same.
4051e6d9c06SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::AllocaOp>(alloc, ty, size,
4061e6d9c06SDiana Picus                                                         alloc->getAttrs());
4071e6d9c06SDiana Picus     } else {
4081e6d9c06SDiana Picus       auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, ty, size,
4091e6d9c06SDiana Picus                                                       alloc->getAttrs());
4101e6d9c06SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(alloc, resultTy, al);
4111e6d9c06SDiana Picus     }
41244e58509SEric Schweitz     return mlir::success();
4131e6d9c06SDiana Picus   }
4141e6d9c06SDiana Picus };
415dc48849fSKiran Chandramohan } // namespace
416044d5b5dSValentin Clement 
417dc48849fSKiran Chandramohan /// Construct an `llvm.extractvalue` instruction. It will return value at
418dc48849fSKiran Chandramohan /// element \p x from  \p tuple.
419dc48849fSKiran Chandramohan static mlir::LLVM::ExtractValueOp
genExtractValueWithIndex(mlir::Location loc,mlir::Value tuple,mlir::Type ty,mlir::ConversionPatternRewriter & rewriter,mlir::MLIRContext * ctx,int x)420dc48849fSKiran Chandramohan genExtractValueWithIndex(mlir::Location loc, mlir::Value tuple, mlir::Type ty,
421dc48849fSKiran Chandramohan                          mlir::ConversionPatternRewriter &rewriter,
422dc48849fSKiran Chandramohan                          mlir::MLIRContext *ctx, int x) {
423dc48849fSKiran Chandramohan   auto cx = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(x));
424dc48849fSKiran Chandramohan   auto xty = ty.cast<mlir::LLVM::LLVMStructType>().getBody()[x];
425dc48849fSKiran Chandramohan   return rewriter.create<mlir::LLVM::ExtractValueOp>(loc, xty, tuple, cx);
426dc48849fSKiran Chandramohan }
427dc48849fSKiran Chandramohan 
428dc48849fSKiran Chandramohan namespace {
429df3b9810SValentin Clement /// Lower `fir.box_addr` to the sequence of operations to extract the first
430df3b9810SValentin Clement /// element of the box.
431df3b9810SValentin Clement struct BoxAddrOpConversion : public FIROpConversion<fir::BoxAddrOp> {
432df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
433df3b9810SValentin Clement 
434df3b9810SValentin Clement   mlir::LogicalResult
matchAndRewrite__anon447c3e180411::BoxAddrOpConversion435df3b9810SValentin Clement   matchAndRewrite(fir::BoxAddrOp boxaddr, OpAdaptor adaptor,
436df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
437df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
438df3b9810SValentin Clement     auto loc = boxaddr.getLoc();
439df3b9810SValentin Clement     mlir::Type ty = convertType(boxaddr.getType());
440149ad3d5SShraiysh Vaishay     if (auto argty = boxaddr.getVal().getType().dyn_cast<fir::BoxType>()) {
441df3b9810SValentin Clement       rewriter.replaceOp(boxaddr, loadBaseAddrFromBox(loc, ty, a, rewriter));
442df3b9810SValentin Clement     } else {
443df3b9810SValentin Clement       auto c0attr = rewriter.getI32IntegerAttr(0);
444df3b9810SValentin Clement       auto c0 = mlir::ArrayAttr::get(boxaddr.getContext(), c0attr);
445df3b9810SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(boxaddr, ty, a,
446df3b9810SValentin Clement                                                               c0);
447df3b9810SValentin Clement     }
44844e58509SEric Schweitz     return mlir::success();
449df3b9810SValentin Clement   }
450df3b9810SValentin Clement };
451df3b9810SValentin Clement 
452dc48849fSKiran Chandramohan /// Convert `!fir.boxchar_len` to  `!llvm.extractvalue` for the 2nd part of the
453dc48849fSKiran Chandramohan /// boxchar.
454dc48849fSKiran Chandramohan struct BoxCharLenOpConversion : public FIROpConversion<fir::BoxCharLenOp> {
455dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
456dc48849fSKiran Chandramohan 
457dc48849fSKiran Chandramohan   mlir::LogicalResult
matchAndRewrite__anon447c3e180411::BoxCharLenOpConversion458dc48849fSKiran Chandramohan   matchAndRewrite(fir::BoxCharLenOp boxCharLen, OpAdaptor adaptor,
459dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
460dc48849fSKiran Chandramohan     mlir::Value boxChar = adaptor.getOperands()[0];
461dc48849fSKiran Chandramohan     mlir::Location loc = boxChar.getLoc();
462dc48849fSKiran Chandramohan     mlir::MLIRContext *ctx = boxChar.getContext();
463dc48849fSKiran Chandramohan     mlir::Type returnValTy = boxCharLen.getResult().getType();
464dc48849fSKiran Chandramohan 
465dc48849fSKiran Chandramohan     constexpr int boxcharLenIdx = 1;
466dc48849fSKiran Chandramohan     mlir::LLVM::ExtractValueOp len = genExtractValueWithIndex(
467dc48849fSKiran Chandramohan         loc, boxChar, boxChar.getType(), rewriter, ctx, boxcharLenIdx);
468dc48849fSKiran Chandramohan     mlir::Value lenAfterCast = integerCast(loc, rewriter, returnValTy, len);
469dc48849fSKiran Chandramohan     rewriter.replaceOp(boxCharLen, lenAfterCast);
470dc48849fSKiran Chandramohan 
47144e58509SEric Schweitz     return mlir::success();
472dc48849fSKiran Chandramohan   }
473dc48849fSKiran Chandramohan };
474dc48849fSKiran Chandramohan 
475df3b9810SValentin Clement /// Lower `fir.box_dims` to a sequence of operations to extract the requested
476df3b9810SValentin Clement /// dimension infomartion from the boxed value.
477df3b9810SValentin Clement /// Result in a triple set of GEPs and loads.
478df3b9810SValentin Clement struct BoxDimsOpConversion : public FIROpConversion<fir::BoxDimsOp> {
479df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
480df3b9810SValentin Clement 
481df3b9810SValentin Clement   mlir::LogicalResult
matchAndRewrite__anon447c3e180411::BoxDimsOpConversion482df3b9810SValentin Clement   matchAndRewrite(fir::BoxDimsOp boxdims, OpAdaptor adaptor,
483df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
48444e58509SEric Schweitz     llvm::SmallVector<mlir::Type, 3> resultTypes = {
485df3b9810SValentin Clement         convertType(boxdims.getResult(0).getType()),
486df3b9810SValentin Clement         convertType(boxdims.getResult(1).getType()),
487df3b9810SValentin Clement         convertType(boxdims.getResult(2).getType()),
488df3b9810SValentin Clement     };
489df3b9810SValentin Clement     auto results =
490df3b9810SValentin Clement         getDimsFromBox(boxdims.getLoc(), resultTypes, adaptor.getOperands()[0],
491df3b9810SValentin Clement                        adaptor.getOperands()[1], rewriter);
492df3b9810SValentin Clement     rewriter.replaceOp(boxdims, results);
49344e58509SEric Schweitz     return mlir::success();
494df3b9810SValentin Clement   }
495df3b9810SValentin Clement };
496df3b9810SValentin Clement 
497df3b9810SValentin Clement /// Lower `fir.box_elesize` to a sequence of operations ro extract the size of
498df3b9810SValentin Clement /// an element in the boxed value.
499df3b9810SValentin Clement struct BoxEleSizeOpConversion : public FIROpConversion<fir::BoxEleSizeOp> {
500df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
501df3b9810SValentin Clement 
502df3b9810SValentin Clement   mlir::LogicalResult
matchAndRewrite__anon447c3e180411::BoxEleSizeOpConversion503df3b9810SValentin Clement   matchAndRewrite(fir::BoxEleSizeOp boxelesz, OpAdaptor adaptor,
504df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
505df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
506df3b9810SValentin Clement     auto loc = boxelesz.getLoc();
507df3b9810SValentin Clement     auto ty = convertType(boxelesz.getType());
508b6e44ecdSValentin Clement     auto elemSize = getValueFromBox(loc, a, ty, rewriter, kElemLenPosInBox);
509b6e44ecdSValentin Clement     rewriter.replaceOp(boxelesz, elemSize);
51044e58509SEric Schweitz     return mlir::success();
511b6e44ecdSValentin Clement   }
512b6e44ecdSValentin Clement };
513b6e44ecdSValentin Clement 
514b6e44ecdSValentin Clement /// Lower `fir.box_isalloc` to a sequence of operations to determine if the
515b6e44ecdSValentin Clement /// boxed value was from an ALLOCATABLE entity.
516b6e44ecdSValentin Clement struct BoxIsAllocOpConversion : public FIROpConversion<fir::BoxIsAllocOp> {
517b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
518b6e44ecdSValentin Clement 
519b6e44ecdSValentin Clement   mlir::LogicalResult
matchAndRewrite__anon447c3e180411::BoxIsAllocOpConversion520b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsAllocOp boxisalloc, OpAdaptor adaptor,
521b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
522b6e44ecdSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
523b6e44ecdSValentin Clement     auto loc = boxisalloc.getLoc();
524b6e44ecdSValentin Clement     mlir::Value check =
525b6e44ecdSValentin Clement         genBoxAttributeCheck(loc, box, rewriter, kAttrAllocatable);
526b6e44ecdSValentin Clement     rewriter.replaceOp(boxisalloc, check);
52744e58509SEric Schweitz     return mlir::success();
528b6e44ecdSValentin Clement   }
529b6e44ecdSValentin Clement };
530b6e44ecdSValentin Clement 
531b6e44ecdSValentin Clement /// Lower `fir.box_isarray` to a sequence of operations to determine if the
532b6e44ecdSValentin Clement /// boxed is an array.
533b6e44ecdSValentin Clement struct BoxIsArrayOpConversion : public FIROpConversion<fir::BoxIsArrayOp> {
534b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
535b6e44ecdSValentin Clement 
536b6e44ecdSValentin Clement   mlir::LogicalResult
matchAndRewrite__anon447c3e180411::BoxIsArrayOpConversion537b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsArrayOp boxisarray, OpAdaptor adaptor,
538b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
539b6e44ecdSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
540b6e44ecdSValentin Clement     auto loc = boxisarray.getLoc();
541b6e44ecdSValentin Clement     auto rank =
542b6e44ecdSValentin Clement         getValueFromBox(loc, a, rewriter.getI32Type(), rewriter, kRankPosInBox);
543b6e44ecdSValentin Clement     auto c0 = genConstantOffset(loc, rewriter, 0);
544b6e44ecdSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
545b6e44ecdSValentin Clement         boxisarray, mlir::LLVM::ICmpPredicate::ne, rank, c0);
54644e58509SEric Schweitz     return mlir::success();
547b6e44ecdSValentin Clement   }
548b6e44ecdSValentin Clement };
549b6e44ecdSValentin Clement 
550b6e44ecdSValentin Clement /// Lower `fir.box_isptr` to a sequence of operations to determined if the
551b6e44ecdSValentin Clement /// boxed value was from a POINTER entity.
552b6e44ecdSValentin Clement struct BoxIsPtrOpConversion : public FIROpConversion<fir::BoxIsPtrOp> {
553b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
554b6e44ecdSValentin Clement 
555b6e44ecdSValentin Clement   mlir::LogicalResult
matchAndRewrite__anon447c3e180411::BoxIsPtrOpConversion556b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsPtrOp boxisptr, OpAdaptor adaptor,
557b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
558b6e44ecdSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
559b6e44ecdSValentin Clement     auto loc = boxisptr.getLoc();
560b6e44ecdSValentin Clement     mlir::Value check = genBoxAttributeCheck(loc, box, rewriter, kAttrPointer);
561b6e44ecdSValentin Clement     rewriter.replaceOp(boxisptr, check);
56244e58509SEric Schweitz     return mlir::success();
563df3b9810SValentin Clement   }
564df3b9810SValentin Clement };
565df3b9810SValentin Clement 
566df3b9810SValentin Clement /// Lower `fir.box_rank` to the sequence of operation to extract the rank from
567df3b9810SValentin Clement /// the box.
568df3b9810SValentin Clement struct BoxRankOpConversion : public FIROpConversion<fir::BoxRankOp> {
569df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
570df3b9810SValentin Clement 
571df3b9810SValentin Clement   mlir::LogicalResult
matchAndRewrite__anon447c3e180411::BoxRankOpConversion572df3b9810SValentin Clement   matchAndRewrite(fir::BoxRankOp boxrank, OpAdaptor adaptor,
573df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
574df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
575df3b9810SValentin Clement     auto loc = boxrank.getLoc();
576df3b9810SValentin Clement     mlir::Type ty = convertType(boxrank.getType());
577b6e44ecdSValentin Clement     auto result = getValueFromBox(loc, a, ty, rewriter, kRankPosInBox);
578df3b9810SValentin Clement     rewriter.replaceOp(boxrank, result);
57944e58509SEric Schweitz     return mlir::success();
580df3b9810SValentin Clement   }
581df3b9810SValentin Clement };
582df3b9810SValentin Clement 
583cc505c0bSKiran Chandramohan /// Lower `fir.boxproc_host` operation. Extracts the host pointer from the
584cc505c0bSKiran Chandramohan /// boxproc.
585cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
586cc505c0bSKiran Chandramohan struct BoxProcHostOpConversion : public FIROpConversion<fir::BoxProcHostOp> {
587cc505c0bSKiran Chandramohan   using FIROpConversion::FIROpConversion;
588cc505c0bSKiran Chandramohan 
589cc505c0bSKiran Chandramohan   mlir::LogicalResult
matchAndRewrite__anon447c3e180411::BoxProcHostOpConversion590cc505c0bSKiran Chandramohan   matchAndRewrite(fir::BoxProcHostOp boxprochost, OpAdaptor adaptor,
591cc505c0bSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
5927ce8c6fcSKiran Chandramohan     TODO(boxprochost.getLoc(), "fir.boxproc_host codegen");
59344e58509SEric Schweitz     return mlir::failure();
594cc505c0bSKiran Chandramohan   }
595cc505c0bSKiran Chandramohan };
596cc505c0bSKiran Chandramohan 
597e38ef2ffSValentin Clement /// Lower `fir.box_tdesc` to the sequence of operations to extract the type
598e38ef2ffSValentin Clement /// descriptor from the box.
599e38ef2ffSValentin Clement struct BoxTypeDescOpConversion : public FIROpConversion<fir::BoxTypeDescOp> {
600e38ef2ffSValentin Clement   using FIROpConversion::FIROpConversion;
601e38ef2ffSValentin Clement 
602e38ef2ffSValentin Clement   mlir::LogicalResult
matchAndRewrite__anon447c3e180411::BoxTypeDescOpConversion603e38ef2ffSValentin Clement   matchAndRewrite(fir::BoxTypeDescOp boxtypedesc, OpAdaptor adaptor,
604e38ef2ffSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
605e38ef2ffSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
606e38ef2ffSValentin Clement     auto loc = boxtypedesc.getLoc();
607e38ef2ffSValentin Clement     mlir::Type typeTy =
608e38ef2ffSValentin Clement         fir::getDescFieldTypeModel<kTypePosInBox>()(boxtypedesc.getContext());
609e38ef2ffSValentin Clement     auto result = getValueFromBox(loc, box, typeTy, rewriter, kTypePosInBox);
610e38ef2ffSValentin Clement     auto typePtrTy = mlir::LLVM::LLVMPointerType::get(typeTy);
611e38ef2ffSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(boxtypedesc, typePtrTy,
612e38ef2ffSValentin Clement                                                         result);
61344e58509SEric Schweitz     return mlir::success();
614e38ef2ffSValentin Clement   }
615e38ef2ffSValentin Clement };
616e38ef2ffSValentin Clement 
617dc48849fSKiran Chandramohan /// Lower `fir.string_lit` to LLVM IR dialect operation.
618dc48849fSKiran Chandramohan struct StringLitOpConversion : public FIROpConversion<fir::StringLitOp> {
619dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
620dc48849fSKiran Chandramohan 
621dc48849fSKiran Chandramohan   mlir::LogicalResult
matchAndRewrite__anon447c3e180411::StringLitOpConversion622dc48849fSKiran Chandramohan   matchAndRewrite(fir::StringLitOp constop, OpAdaptor adaptor,
623dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
624dc48849fSKiran Chandramohan     auto ty = convertType(constop.getType());
625dc48849fSKiran Chandramohan     auto attr = constop.getValue();
626dc48849fSKiran Chandramohan     if (attr.isa<mlir::StringAttr>()) {
627dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(constop, ty, attr);
62844e58509SEric Schweitz       return mlir::success();
629dc48849fSKiran Chandramohan     }
630dc48849fSKiran Chandramohan 
631dc48849fSKiran Chandramohan     auto charTy = constop.getType().cast<fir::CharacterType>();
632dc48849fSKiran Chandramohan     unsigned bits = lowerTy().characterBitsize(charTy);
633dc48849fSKiran Chandramohan     mlir::Type intTy = rewriter.getIntegerType(bits);
634e0c782bdSValentin Clement     mlir::Location loc = constop.getLoc();
635e0c782bdSValentin Clement     mlir::Value cst = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
636e0c782bdSValentin Clement     if (auto arr = attr.dyn_cast<mlir::DenseElementsAttr>()) {
637e0c782bdSValentin Clement       cst = rewriter.create<mlir::LLVM::ConstantOp>(loc, ty, arr);
638e0c782bdSValentin Clement     } else if (auto arr = attr.dyn_cast<mlir::ArrayAttr>()) {
639e0c782bdSValentin Clement       for (auto a : llvm::enumerate(arr.getValue())) {
640e0c782bdSValentin Clement         // convert each character to a precise bitsize
641e0c782bdSValentin Clement         auto elemAttr = mlir::IntegerAttr::get(
642dc48849fSKiran Chandramohan             intTy,
643e0c782bdSValentin Clement             a.value().cast<mlir::IntegerAttr>().getValue().zextOrTrunc(bits));
644e0c782bdSValentin Clement         auto elemCst =
645e0c782bdSValentin Clement             rewriter.create<mlir::LLVM::ConstantOp>(loc, intTy, elemAttr);
646e0c782bdSValentin Clement         auto index = mlir::ArrayAttr::get(
647e0c782bdSValentin Clement             constop.getContext(), rewriter.getI32IntegerAttr(a.index()));
648e0c782bdSValentin Clement         cst = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, cst, elemCst,
649e0c782bdSValentin Clement                                                          index);
650e0c782bdSValentin Clement       }
651e0c782bdSValentin Clement     } else {
65244e58509SEric Schweitz       return mlir::failure();
653e0c782bdSValentin Clement     }
654e0c782bdSValentin Clement     rewriter.replaceOp(constop, cst);
65544e58509SEric Schweitz     return mlir::success();
656dc48849fSKiran Chandramohan   }
657dc48849fSKiran Chandramohan };
658dc48849fSKiran Chandramohan 
659575c9d6dSValentin Clement /// `fir.call` -> `llvm.call`
660ddd11b9aSAndrzej Warzynski struct CallOpConversion : public FIROpConversion<fir::CallOp> {
661ddd11b9aSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
662ddd11b9aSAndrzej Warzynski 
663ddd11b9aSAndrzej Warzynski   mlir::LogicalResult
matchAndRewrite__anon447c3e180411::CallOpConversion664ddd11b9aSAndrzej Warzynski   matchAndRewrite(fir::CallOp call, OpAdaptor adaptor,
665ddd11b9aSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
66644e58509SEric Schweitz     llvm::SmallVector<mlir::Type> resultTys;
667ddd11b9aSAndrzej Warzynski     for (auto r : call.getResults())
668ddd11b9aSAndrzej Warzynski       resultTys.push_back(convertType(r.getType()));
669ddd11b9aSAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
670ddd11b9aSAndrzej Warzynski         call, resultTys, adaptor.getOperands(), call->getAttrs());
67144e58509SEric Schweitz     return mlir::success();
672ddd11b9aSAndrzej Warzynski   }
673ddd11b9aSAndrzej Warzynski };
674c2acd453SAlexisPerry } // namespace
675ddd11b9aSAndrzej Warzynski 
getComplexEleTy(mlir::Type complex)676092cee5fSValentin Clement static mlir::Type getComplexEleTy(mlir::Type complex) {
677092cee5fSValentin Clement   if (auto cc = complex.dyn_cast<mlir::ComplexType>())
678092cee5fSValentin Clement     return cc.getElementType();
679092cee5fSValentin Clement   return complex.cast<fir::ComplexType>().getElementType();
680092cee5fSValentin Clement }
681092cee5fSValentin Clement 
682c2acd453SAlexisPerry namespace {
683f1dfc027SDiana Picus /// Compare complex values
684f1dfc027SDiana Picus ///
685f1dfc027SDiana Picus /// Per 10.1, the only comparisons available are .EQ. (oeq) and .NE. (une).
686f1dfc027SDiana Picus ///
687f1dfc027SDiana Picus /// For completeness, all other comparison are done on the real component only.
688f1dfc027SDiana Picus struct CmpcOpConversion : public FIROpConversion<fir::CmpcOp> {
689f1dfc027SDiana Picus   using FIROpConversion::FIROpConversion;
690f1dfc027SDiana Picus 
691f1dfc027SDiana Picus   mlir::LogicalResult
matchAndRewrite__anon447c3e180511::CmpcOpConversion692f1dfc027SDiana Picus   matchAndRewrite(fir::CmpcOp cmp, OpAdaptor adaptor,
693f1dfc027SDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
694f1dfc027SDiana Picus     mlir::ValueRange operands = adaptor.getOperands();
695f1dfc027SDiana Picus     mlir::MLIRContext *ctxt = cmp.getContext();
696149ad3d5SShraiysh Vaishay     mlir::Type eleTy = convertType(getComplexEleTy(cmp.getLhs().getType()));
697f1dfc027SDiana Picus     mlir::Type resTy = convertType(cmp.getType());
698f1dfc027SDiana Picus     mlir::Location loc = cmp.getLoc();
699f1dfc027SDiana Picus     auto pos0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0));
700575c9d6dSValentin Clement     llvm::SmallVector<mlir::Value, 2> rp = {
70144e58509SEric Schweitz         rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, operands[0],
70244e58509SEric Schweitz                                                     pos0),
70344e58509SEric Schweitz         rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, operands[1],
70444e58509SEric Schweitz                                                     pos0)};
705f1dfc027SDiana Picus     auto rcp =
706f1dfc027SDiana Picus         rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, rp, cmp->getAttrs());
707f1dfc027SDiana Picus     auto pos1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1));
708575c9d6dSValentin Clement     llvm::SmallVector<mlir::Value, 2> ip = {
70944e58509SEric Schweitz         rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, operands[0],
71044e58509SEric Schweitz                                                     pos1),
71144e58509SEric Schweitz         rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, operands[1],
71244e58509SEric Schweitz                                                     pos1)};
713f1dfc027SDiana Picus     auto icp =
714f1dfc027SDiana Picus         rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, ip, cmp->getAttrs());
715575c9d6dSValentin Clement     llvm::SmallVector<mlir::Value, 2> cp = {rcp, icp};
716f1dfc027SDiana Picus     switch (cmp.getPredicate()) {
717f1dfc027SDiana Picus     case mlir::arith::CmpFPredicate::OEQ: // .EQ.
718f1dfc027SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(cmp, resTy, cp);
719f1dfc027SDiana Picus       break;
720f1dfc027SDiana Picus     case mlir::arith::CmpFPredicate::UNE: // .NE.
721f1dfc027SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(cmp, resTy, cp);
722f1dfc027SDiana Picus       break;
723f1dfc027SDiana Picus     default:
724f1dfc027SDiana Picus       rewriter.replaceOp(cmp, rcp.getResult());
725f1dfc027SDiana Picus       break;
726f1dfc027SDiana Picus     }
72744e58509SEric Schweitz     return mlir::success();
728f1dfc027SDiana Picus   }
729f1dfc027SDiana Picus };
730f1dfc027SDiana Picus 
731e81d73edSDiana Picus /// Lower complex constants
732e81d73edSDiana Picus struct ConstcOpConversion : public FIROpConversion<fir::ConstcOp> {
733e81d73edSDiana Picus   using FIROpConversion::FIROpConversion;
734e81d73edSDiana Picus 
735e81d73edSDiana Picus   mlir::LogicalResult
matchAndRewrite__anon447c3e180511::ConstcOpConversion736e81d73edSDiana Picus   matchAndRewrite(fir::ConstcOp conc, OpAdaptor,
737e81d73edSDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
738e81d73edSDiana Picus     mlir::Location loc = conc.getLoc();
739e81d73edSDiana Picus     mlir::MLIRContext *ctx = conc.getContext();
740e81d73edSDiana Picus     mlir::Type ty = convertType(conc.getType());
741e81d73edSDiana Picus     mlir::Type ety = convertType(getComplexEleTy(conc.getType()));
742e81d73edSDiana Picus     auto realFloatAttr = mlir::FloatAttr::get(ety, getValue(conc.getReal()));
743e81d73edSDiana Picus     auto realPart =
744e81d73edSDiana Picus         rewriter.create<mlir::LLVM::ConstantOp>(loc, ety, realFloatAttr);
745e81d73edSDiana Picus     auto imFloatAttr = mlir::FloatAttr::get(ety, getValue(conc.getImaginary()));
746e81d73edSDiana Picus     auto imPart =
747e81d73edSDiana Picus         rewriter.create<mlir::LLVM::ConstantOp>(loc, ety, imFloatAttr);
748e81d73edSDiana Picus     auto realIndex = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
749e81d73edSDiana Picus     auto imIndex = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
750e81d73edSDiana Picus     auto undef = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
751e81d73edSDiana Picus     auto setReal = rewriter.create<mlir::LLVM::InsertValueOp>(
752e81d73edSDiana Picus         loc, ty, undef, realPart, realIndex);
753e81d73edSDiana Picus     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(conc, ty, setReal,
754e81d73edSDiana Picus                                                            imPart, imIndex);
75544e58509SEric Schweitz     return mlir::success();
756e81d73edSDiana Picus   }
757e81d73edSDiana Picus 
getValue__anon447c3e180511::ConstcOpConversion75844e58509SEric Schweitz   inline llvm::APFloat getValue(mlir::Attribute attr) const {
759e81d73edSDiana Picus     return attr.cast<fir::RealAttr>().getValue();
760e81d73edSDiana Picus   }
761e81d73edSDiana Picus };
762e81d73edSDiana Picus 
763092cee5fSValentin Clement /// convert value of from-type to value of to-type
764092cee5fSValentin Clement struct ConvertOpConversion : public FIROpConversion<fir::ConvertOp> {
765092cee5fSValentin Clement   using FIROpConversion::FIROpConversion;
766092cee5fSValentin Clement 
isFloatingPointTy__anon447c3e180511::ConvertOpConversion767092cee5fSValentin Clement   static bool isFloatingPointTy(mlir::Type ty) {
768092cee5fSValentin Clement     return ty.isa<mlir::FloatType>();
769092cee5fSValentin Clement   }
770092cee5fSValentin Clement 
771092cee5fSValentin Clement   mlir::LogicalResult
matchAndRewrite__anon447c3e180511::ConvertOpConversion772092cee5fSValentin Clement   matchAndRewrite(fir::ConvertOp convert, OpAdaptor adaptor,
773092cee5fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
7743b7ec85aSJean Perier     auto fromFirTy = convert.getValue().getType();
7753b7ec85aSJean Perier     auto toFirTy = convert.getRes().getType();
7763b7ec85aSJean Perier     auto fromTy = convertType(fromFirTy);
7773b7ec85aSJean Perier     auto toTy = convertType(toFirTy);
778092cee5fSValentin Clement     mlir::Value op0 = adaptor.getOperands()[0];
779092cee5fSValentin Clement     if (fromTy == toTy) {
780092cee5fSValentin Clement       rewriter.replaceOp(convert, op0);
78144e58509SEric Schweitz       return mlir::success();
782092cee5fSValentin Clement     }
783092cee5fSValentin Clement     auto loc = convert.getLoc();
784092cee5fSValentin Clement     auto convertFpToFp = [&](mlir::Value val, unsigned fromBits,
785092cee5fSValentin Clement                              unsigned toBits, mlir::Type toTy) -> mlir::Value {
786092cee5fSValentin Clement       if (fromBits == toBits) {
787092cee5fSValentin Clement         // TODO: Converting between two floating-point representations with the
788092cee5fSValentin Clement         // same bitwidth is not allowed for now.
789092cee5fSValentin Clement         mlir::emitError(loc,
790092cee5fSValentin Clement                         "cannot implicitly convert between two floating-point "
791092cee5fSValentin Clement                         "representations of the same bitwidth");
792092cee5fSValentin Clement         return {};
793092cee5fSValentin Clement       }
794092cee5fSValentin Clement       if (fromBits > toBits)
795092cee5fSValentin Clement         return rewriter.create<mlir::LLVM::FPTruncOp>(loc, toTy, val);
796092cee5fSValentin Clement       return rewriter.create<mlir::LLVM::FPExtOp>(loc, toTy, val);
797092cee5fSValentin Clement     };
798092cee5fSValentin Clement     // Complex to complex conversion.
7993b7ec85aSJean Perier     if (fir::isa_complex(fromFirTy) && fir::isa_complex(toFirTy)) {
800092cee5fSValentin Clement       // Special case: handle the conversion of a complex such that both the
801092cee5fSValentin Clement       // real and imaginary parts are converted together.
802092cee5fSValentin Clement       auto zero = mlir::ArrayAttr::get(convert.getContext(),
803092cee5fSValentin Clement                                        rewriter.getI32IntegerAttr(0));
804092cee5fSValentin Clement       auto one = mlir::ArrayAttr::get(convert.getContext(),
805092cee5fSValentin Clement                                       rewriter.getI32IntegerAttr(1));
806149ad3d5SShraiysh Vaishay       auto ty = convertType(getComplexEleTy(convert.getValue().getType()));
807092cee5fSValentin Clement       auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, zero);
808092cee5fSValentin Clement       auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, one);
809149ad3d5SShraiysh Vaishay       auto nt = convertType(getComplexEleTy(convert.getRes().getType()));
810092cee5fSValentin Clement       auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
811092cee5fSValentin Clement       auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(nt);
812092cee5fSValentin Clement       auto rc = convertFpToFp(rp, fromBits, toBits, nt);
813092cee5fSValentin Clement       auto ic = convertFpToFp(ip, fromBits, toBits, nt);
814092cee5fSValentin Clement       auto un = rewriter.create<mlir::LLVM::UndefOp>(loc, toTy);
815092cee5fSValentin Clement       auto i1 =
816092cee5fSValentin Clement           rewriter.create<mlir::LLVM::InsertValueOp>(loc, toTy, un, rc, zero);
817092cee5fSValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(convert, toTy, i1,
818092cee5fSValentin Clement                                                              ic, one);
819092cee5fSValentin Clement       return mlir::success();
820092cee5fSValentin Clement     }
8213b7ec85aSJean Perier 
8223b7ec85aSJean Perier     // Follow UNIX F77 convention for logicals:
8233b7ec85aSJean Perier     // 1. underlying integer is not zero => logical is .TRUE.
8243b7ec85aSJean Perier     // 2. logical is .TRUE. => set underlying integer to 1.
8253b7ec85aSJean Perier     auto i1Type = mlir::IntegerType::get(convert.getContext(), 1);
8263b7ec85aSJean Perier     if (fromFirTy.isa<fir::LogicalType>() && toFirTy == i1Type) {
8273b7ec85aSJean Perier       mlir::Value zero = genConstantIndex(loc, fromTy, rewriter, 0);
8283b7ec85aSJean Perier       rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
8293b7ec85aSJean Perier           convert, mlir::LLVM::ICmpPredicate::ne, op0, zero);
8303b7ec85aSJean Perier       return mlir::success();
8313b7ec85aSJean Perier     }
8323b7ec85aSJean Perier     if (fromFirTy == i1Type && toFirTy.isa<fir::LogicalType>()) {
8333b7ec85aSJean Perier       rewriter.replaceOpWithNewOp<mlir::LLVM::ZExtOp>(convert, toTy, op0);
8343b7ec85aSJean Perier       return mlir::success();
8353b7ec85aSJean Perier     }
8363b7ec85aSJean Perier 
837092cee5fSValentin Clement     // Floating point to floating point conversion.
838092cee5fSValentin Clement     if (isFloatingPointTy(fromTy)) {
839092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
840092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
841092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
842092cee5fSValentin Clement         auto v = convertFpToFp(op0, fromBits, toBits, toTy);
843092cee5fSValentin Clement         rewriter.replaceOp(convert, v);
844092cee5fSValentin Clement         return mlir::success();
845092cee5fSValentin Clement       }
846092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
847092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::FPToSIOp>(convert, toTy, op0);
848092cee5fSValentin Clement         return mlir::success();
849092cee5fSValentin Clement       }
850092cee5fSValentin Clement     } else if (fromTy.isa<mlir::IntegerType>()) {
851092cee5fSValentin Clement       // Integer to integer conversion.
852092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
853092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
854092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
855092cee5fSValentin Clement         assert(fromBits != toBits);
856092cee5fSValentin Clement         if (fromBits > toBits) {
857092cee5fSValentin Clement           rewriter.replaceOpWithNewOp<mlir::LLVM::TruncOp>(convert, toTy, op0);
858092cee5fSValentin Clement           return mlir::success();
859092cee5fSValentin Clement         }
860092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SExtOp>(convert, toTy, op0);
861092cee5fSValentin Clement         return mlir::success();
862092cee5fSValentin Clement       }
863092cee5fSValentin Clement       // Integer to floating point conversion.
864092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
865092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SIToFPOp>(convert, toTy, op0);
866092cee5fSValentin Clement         return mlir::success();
867092cee5fSValentin Clement       }
868092cee5fSValentin Clement       // Integer to pointer conversion.
869092cee5fSValentin Clement       if (toTy.isa<mlir::LLVM::LLVMPointerType>()) {
870092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(convert, toTy, op0);
871092cee5fSValentin Clement         return mlir::success();
872092cee5fSValentin Clement       }
873092cee5fSValentin Clement     } else if (fromTy.isa<mlir::LLVM::LLVMPointerType>()) {
874092cee5fSValentin Clement       // Pointer to integer conversion.
875092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
876092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::PtrToIntOp>(convert, toTy, op0);
877092cee5fSValentin Clement         return mlir::success();
878092cee5fSValentin Clement       }
879092cee5fSValentin Clement       // Pointer to pointer conversion.
880092cee5fSValentin Clement       if (toTy.isa<mlir::LLVM::LLVMPointerType>()) {
881092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(convert, toTy, op0);
882092cee5fSValentin Clement         return mlir::success();
883092cee5fSValentin Clement       }
884092cee5fSValentin Clement     }
885092cee5fSValentin Clement     return emitError(loc) << "cannot convert " << fromTy << " to " << toTy;
886092cee5fSValentin Clement   }
887092cee5fSValentin Clement };
888092cee5fSValentin Clement 
8899534e361SValentin Clement /// Lower `fir.dispatch` operation. A virtual call to a method in a dispatch
8909534e361SValentin Clement /// table.
8919534e361SValentin Clement struct DispatchOpConversion : public FIROpConversion<fir::DispatchOp> {
8929534e361SValentin Clement   using FIROpConversion::FIROpConversion;
8939534e361SValentin Clement 
8949534e361SValentin Clement   mlir::LogicalResult
matchAndRewrite__anon447c3e180511::DispatchOpConversion8959534e361SValentin Clement   matchAndRewrite(fir::DispatchOp dispatch, OpAdaptor adaptor,
8969534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8977ce8c6fcSKiran Chandramohan     TODO(dispatch.getLoc(), "fir.dispatch codegen");
89844e58509SEric Schweitz     return mlir::failure();
8999534e361SValentin Clement   }
9009534e361SValentin Clement };
9019534e361SValentin Clement 
9029534e361SValentin Clement /// Lower `fir.dispatch_table` operation. The dispatch table for a Fortran
9039534e361SValentin Clement /// derived type.
9049534e361SValentin Clement struct DispatchTableOpConversion
9059534e361SValentin Clement     : public FIROpConversion<fir::DispatchTableOp> {
9069534e361SValentin Clement   using FIROpConversion::FIROpConversion;
9079534e361SValentin Clement 
9089534e361SValentin Clement   mlir::LogicalResult
matchAndRewrite__anon447c3e180511::DispatchTableOpConversion9099534e361SValentin Clement   matchAndRewrite(fir::DispatchTableOp dispTab, OpAdaptor adaptor,
9109534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
9117ce8c6fcSKiran Chandramohan     TODO(dispTab.getLoc(), "fir.dispatch_table codegen");
91244e58509SEric Schweitz     return mlir::failure();
9139534e361SValentin Clement   }
9149534e361SValentin Clement };
9159534e361SValentin Clement 
9169534e361SValentin Clement /// Lower `fir.dt_entry` operation. An entry in a dispatch table; binds a
9179534e361SValentin Clement /// method-name to a function.
9189534e361SValentin Clement struct DTEntryOpConversion : public FIROpConversion<fir::DTEntryOp> {
9199534e361SValentin Clement   using FIROpConversion::FIROpConversion;
9209534e361SValentin Clement 
9219534e361SValentin Clement   mlir::LogicalResult
matchAndRewrite__anon447c3e180511::DTEntryOpConversion9229534e361SValentin Clement   matchAndRewrite(fir::DTEntryOp dtEnt, OpAdaptor adaptor,
9239534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
9247ce8c6fcSKiran Chandramohan     TODO(dtEnt.getLoc(), "fir.dt_entry codegen");
92544e58509SEric Schweitz     return mlir::failure();
9269534e361SValentin Clement   }
9279534e361SValentin Clement };
9289534e361SValentin Clement 
929677df8c7SValentin Clement /// Lower `fir.global_len` operation.
930677df8c7SValentin Clement struct GlobalLenOpConversion : public FIROpConversion<fir::GlobalLenOp> {
931677df8c7SValentin Clement   using FIROpConversion::FIROpConversion;
932677df8c7SValentin Clement 
933677df8c7SValentin Clement   mlir::LogicalResult
matchAndRewrite__anon447c3e180511::GlobalLenOpConversion934677df8c7SValentin Clement   matchAndRewrite(fir::GlobalLenOp globalLen, OpAdaptor adaptor,
935677df8c7SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
9367ce8c6fcSKiran Chandramohan     TODO(globalLen.getLoc(), "fir.global_len codegen");
93744e58509SEric Schweitz     return mlir::failure();
938677df8c7SValentin Clement   }
939677df8c7SValentin Clement };
940677df8c7SValentin Clement 
941cdc476abSDiana Picus /// Lower fir.len_param_index
942cdc476abSDiana Picus struct LenParamIndexOpConversion
943cdc476abSDiana Picus     : public FIROpConversion<fir::LenParamIndexOp> {
944cdc476abSDiana Picus   using FIROpConversion::FIROpConversion;
945cdc476abSDiana Picus 
946cdc476abSDiana Picus   // FIXME: this should be specialized by the runtime target
947cdc476abSDiana Picus   mlir::LogicalResult
matchAndRewrite__anon447c3e180511::LenParamIndexOpConversion948cdc476abSDiana Picus   matchAndRewrite(fir::LenParamIndexOp lenp, OpAdaptor,
949cdc476abSDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
9507ce8c6fcSKiran Chandramohan     TODO(lenp.getLoc(), "fir.len_param_index codegen");
951cdc476abSDiana Picus   }
952cdc476abSDiana Picus };
953cdc476abSDiana Picus 
954dc48849fSKiran Chandramohan /// Convert `!fir.emboxchar<!fir.char<KIND, ?>, #n>` into a sequence of
955dc48849fSKiran Chandramohan /// instructions that generate `!llvm.struct<(ptr<ik>, i64)>`. The 1st element
956dc48849fSKiran Chandramohan /// in this struct is a pointer. Its type is determined from `KIND`. The 2nd
957dc48849fSKiran Chandramohan /// element is the length of the character buffer (`#n`).
958dc48849fSKiran Chandramohan struct EmboxCharOpConversion : public FIROpConversion<fir::EmboxCharOp> {
95931246187SValentin Clement   using FIROpConversion::FIROpConversion;
96031246187SValentin Clement 
96131246187SValentin Clement   mlir::LogicalResult
matchAndRewrite__anon447c3e180511::EmboxCharOpConversion962dc48849fSKiran Chandramohan   matchAndRewrite(fir::EmboxCharOp emboxChar, OpAdaptor adaptor,
96331246187SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
964dc48849fSKiran Chandramohan     mlir::ValueRange operands = adaptor.getOperands();
96544e58509SEric Schweitz     auto *ctx = emboxChar.getContext();
966dc48849fSKiran Chandramohan 
967dc48849fSKiran Chandramohan     mlir::Value charBuffer = operands[0];
968dc48849fSKiran Chandramohan     mlir::Value charBufferLen = operands[1];
969dc48849fSKiran Chandramohan 
970dc48849fSKiran Chandramohan     mlir::Location loc = emboxChar.getLoc();
971dc48849fSKiran Chandramohan     mlir::Type llvmStructTy = convertType(emboxChar.getType());
972dc48849fSKiran Chandramohan     auto llvmStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, llvmStructTy);
973dc48849fSKiran Chandramohan 
974dc48849fSKiran Chandramohan     mlir::Type lenTy =
975dc48849fSKiran Chandramohan         llvmStructTy.cast<mlir::LLVM::LLVMStructType>().getBody()[1];
976dc48849fSKiran Chandramohan     mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, charBufferLen);
977dc48849fSKiran Chandramohan 
978dc48849fSKiran Chandramohan     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
979dc48849fSKiran Chandramohan     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
980dc48849fSKiran Chandramohan     auto insertBufferOp = rewriter.create<mlir::LLVM::InsertValueOp>(
981dc48849fSKiran Chandramohan         loc, llvmStructTy, llvmStruct, charBuffer, c0);
982dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
983dc48849fSKiran Chandramohan         emboxChar, llvmStructTy, insertBufferOp, lenAfterCast, c1);
984dc48849fSKiran Chandramohan 
98544e58509SEric Schweitz     return mlir::success();
98631246187SValentin Clement   }
98731246187SValentin Clement };
988c2acd453SAlexisPerry } // namespace
989c2acd453SAlexisPerry 
990c2acd453SAlexisPerry /// Return the LLVMFuncOp corresponding to the standard malloc call.
991c2acd453SAlexisPerry static mlir::LLVM::LLVMFuncOp
getMalloc(fir::AllocMemOp op,mlir::ConversionPatternRewriter & rewriter)992c2acd453SAlexisPerry getMalloc(fir::AllocMemOp op, mlir::ConversionPatternRewriter &rewriter) {
993c2acd453SAlexisPerry   auto module = op->getParentOfType<mlir::ModuleOp>();
994c2acd453SAlexisPerry   if (mlir::LLVM::LLVMFuncOp mallocFunc =
995c2acd453SAlexisPerry           module.lookupSymbol<mlir::LLVM::LLVMFuncOp>("malloc"))
996c2acd453SAlexisPerry     return mallocFunc;
997c2acd453SAlexisPerry   mlir::OpBuilder moduleBuilder(
998c2acd453SAlexisPerry       op->getParentOfType<mlir::ModuleOp>().getBodyRegion());
999c2acd453SAlexisPerry   auto indexType = mlir::IntegerType::get(op.getContext(), 64);
1000c2acd453SAlexisPerry   return moduleBuilder.create<mlir::LLVM::LLVMFuncOp>(
1001c2acd453SAlexisPerry       rewriter.getUnknownLoc(), "malloc",
1002c2acd453SAlexisPerry       mlir::LLVM::LLVMFunctionType::get(getVoidPtrType(op.getContext()),
1003c2acd453SAlexisPerry                                         indexType,
1004c2acd453SAlexisPerry                                         /*isVarArg=*/false));
1005c2acd453SAlexisPerry }
1006c2acd453SAlexisPerry 
1007c2acd453SAlexisPerry /// Helper function for generating the LLVM IR that computes the size
1008c2acd453SAlexisPerry /// in bytes for a derived type.
1009c2acd453SAlexisPerry static mlir::Value
computeDerivedTypeSize(mlir::Location loc,mlir::Type ptrTy,mlir::Type idxTy,mlir::ConversionPatternRewriter & rewriter)1010c2acd453SAlexisPerry computeDerivedTypeSize(mlir::Location loc, mlir::Type ptrTy, mlir::Type idxTy,
1011c2acd453SAlexisPerry                        mlir::ConversionPatternRewriter &rewriter) {
1012c2acd453SAlexisPerry   auto nullPtr = rewriter.create<mlir::LLVM::NullOp>(loc, ptrTy);
1013c2acd453SAlexisPerry   mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1);
1014575c9d6dSValentin Clement   llvm::SmallVector<mlir::Value> args = {one};
101530122656SAlex Zinenko   auto gep = rewriter.create<mlir::LLVM::GEPOp>(loc, ptrTy, nullPtr, args);
1016c2acd453SAlexisPerry   return rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, gep);
1017c2acd453SAlexisPerry }
1018c2acd453SAlexisPerry 
1019c2acd453SAlexisPerry namespace {
1020c2acd453SAlexisPerry /// Lower a `fir.allocmem` instruction into `llvm.call @malloc`
1021c2acd453SAlexisPerry struct AllocMemOpConversion : public FIROpConversion<fir::AllocMemOp> {
1022c2acd453SAlexisPerry   using FIROpConversion::FIROpConversion;
1023c2acd453SAlexisPerry 
1024c2acd453SAlexisPerry   mlir::LogicalResult
matchAndRewrite__anon447c3e180711::AllocMemOpConversion1025c2acd453SAlexisPerry   matchAndRewrite(fir::AllocMemOp heap, OpAdaptor adaptor,
1026c2acd453SAlexisPerry                   mlir::ConversionPatternRewriter &rewriter) const override {
1027575c9d6dSValentin Clement     mlir::Type heapTy = heap.getType();
1028575c9d6dSValentin Clement     mlir::Type ty = convertType(heapTy);
1029c2acd453SAlexisPerry     mlir::LLVM::LLVMFuncOp mallocFunc = getMalloc(heap, rewriter);
1030c2acd453SAlexisPerry     mlir::Location loc = heap.getLoc();
1031c2acd453SAlexisPerry     auto ity = lowerTy().indexType();
1032575c9d6dSValentin Clement     mlir::Type dataTy = fir::unwrapRefType(heapTy);
1033c45bd4b9SEric Schweitz     if (fir::isRecordWithTypeParameters(fir::unwrapSequenceType(dataTy)))
1034c45bd4b9SEric Schweitz       TODO(loc, "fir.allocmem codegen of derived type with length parameters");
1035c2acd453SAlexisPerry     mlir::Value size = genTypeSizeInBytes(loc, ity, rewriter, ty);
1036ac0f4c8fSPeixinQiao     if (auto scaleSize = genAllocationScaleSize(heap, ity, rewriter))
1037ac0f4c8fSPeixinQiao       size = rewriter.create<mlir::LLVM::MulOp>(loc, ity, size, scaleSize);
1038c2acd453SAlexisPerry     for (mlir::Value opnd : adaptor.getOperands())
1039c2acd453SAlexisPerry       size = rewriter.create<mlir::LLVM::MulOp>(
1040c2acd453SAlexisPerry           loc, ity, size, integerCast(loc, rewriter, ity, opnd));
1041c2acd453SAlexisPerry     heap->setAttr("callee", mlir::SymbolRefAttr::get(mallocFunc));
1042c2acd453SAlexisPerry     auto malloc = rewriter.create<mlir::LLVM::CallOp>(
1043c2acd453SAlexisPerry         loc, ::getVoidPtrType(heap.getContext()), size, heap->getAttrs());
1044c2acd453SAlexisPerry     rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(heap, ty,
1045c2acd453SAlexisPerry                                                        malloc.getResult(0));
104644e58509SEric Schweitz     return mlir::success();
1047c2acd453SAlexisPerry   }
1048c2acd453SAlexisPerry 
1049c2acd453SAlexisPerry   // Compute the (allocation) size of the allocmem type in bytes.
genTypeSizeInBytes__anon447c3e180711::AllocMemOpConversion1050c2acd453SAlexisPerry   mlir::Value genTypeSizeInBytes(mlir::Location loc, mlir::Type idxTy,
1051c2acd453SAlexisPerry                                  mlir::ConversionPatternRewriter &rewriter,
1052c2acd453SAlexisPerry                                  mlir::Type llTy) const {
1053c2acd453SAlexisPerry     // Use the primitive size, if available.
1054c2acd453SAlexisPerry     auto ptrTy = llTy.dyn_cast<mlir::LLVM::LLVMPointerType>();
1055c2acd453SAlexisPerry     if (auto size =
1056c2acd453SAlexisPerry             mlir::LLVM::getPrimitiveTypeSizeInBits(ptrTy.getElementType()))
1057c2acd453SAlexisPerry       return genConstantIndex(loc, idxTy, rewriter, size / 8);
1058c2acd453SAlexisPerry 
1059c2acd453SAlexisPerry     // Otherwise, generate the GEP trick in LLVM IR to compute the size.
1060c2acd453SAlexisPerry     return computeDerivedTypeSize(loc, ptrTy, idxTy, rewriter);
1061c2acd453SAlexisPerry   }
1062c2acd453SAlexisPerry };
1063c2acd453SAlexisPerry } // namespace
1064c2acd453SAlexisPerry 
1065c2acd453SAlexisPerry /// Return the LLVMFuncOp corresponding to the standard free call.
1066c2acd453SAlexisPerry static mlir::LLVM::LLVMFuncOp
getFree(fir::FreeMemOp op,mlir::ConversionPatternRewriter & rewriter)1067c2acd453SAlexisPerry getFree(fir::FreeMemOp op, mlir::ConversionPatternRewriter &rewriter) {
1068c2acd453SAlexisPerry   auto module = op->getParentOfType<mlir::ModuleOp>();
1069c2acd453SAlexisPerry   if (mlir::LLVM::LLVMFuncOp freeFunc =
1070c2acd453SAlexisPerry           module.lookupSymbol<mlir::LLVM::LLVMFuncOp>("free"))
1071c2acd453SAlexisPerry     return freeFunc;
1072c2acd453SAlexisPerry   mlir::OpBuilder moduleBuilder(module.getBodyRegion());
1073c2acd453SAlexisPerry   auto voidType = mlir::LLVM::LLVMVoidType::get(op.getContext());
1074c2acd453SAlexisPerry   return moduleBuilder.create<mlir::LLVM::LLVMFuncOp>(
1075c2acd453SAlexisPerry       rewriter.getUnknownLoc(), "free",
1076c2acd453SAlexisPerry       mlir::LLVM::LLVMFunctionType::get(voidType,
1077c2acd453SAlexisPerry                                         getVoidPtrType(op.getContext()),
1078c2acd453SAlexisPerry                                         /*isVarArg=*/false));
1079c2acd453SAlexisPerry }
1080c2acd453SAlexisPerry 
getDimension(mlir::LLVM::LLVMArrayType ty)1081b094c737SJean Perier static unsigned getDimension(mlir::LLVM::LLVMArrayType ty) {
1082b094c737SJean Perier   unsigned result = 1;
1083b094c737SJean Perier   for (auto eleTy = ty.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>();
1084b094c737SJean Perier        eleTy;
1085b094c737SJean Perier        eleTy = eleTy.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>())
1086b094c737SJean Perier     ++result;
1087b094c737SJean Perier   return result;
1088b094c737SJean Perier }
1089b094c737SJean Perier 
1090c2acd453SAlexisPerry namespace {
1091c2acd453SAlexisPerry /// Lower a `fir.freemem` instruction into `llvm.call @free`
1092c2acd453SAlexisPerry struct FreeMemOpConversion : public FIROpConversion<fir::FreeMemOp> {
1093c2acd453SAlexisPerry   using FIROpConversion::FIROpConversion;
1094c2acd453SAlexisPerry 
1095c2acd453SAlexisPerry   mlir::LogicalResult
matchAndRewrite__anon447c3e180811::FreeMemOpConversion1096c2acd453SAlexisPerry   matchAndRewrite(fir::FreeMemOp freemem, OpAdaptor adaptor,
1097c2acd453SAlexisPerry                   mlir::ConversionPatternRewriter &rewriter) const override {
1098c2acd453SAlexisPerry     mlir::LLVM::LLVMFuncOp freeFunc = getFree(freemem, rewriter);
1099c2acd453SAlexisPerry     mlir::Location loc = freemem.getLoc();
1100c2acd453SAlexisPerry     auto bitcast = rewriter.create<mlir::LLVM::BitcastOp>(
1101c2acd453SAlexisPerry         freemem.getLoc(), voidPtrTy(), adaptor.getOperands()[0]);
1102c2acd453SAlexisPerry     freemem->setAttr("callee", mlir::SymbolRefAttr::get(freeFunc));
1103c2acd453SAlexisPerry     rewriter.create<mlir::LLVM::CallOp>(
1104c2acd453SAlexisPerry         loc, mlir::TypeRange{}, mlir::ValueRange{bitcast}, freemem->getAttrs());
1105c2acd453SAlexisPerry     rewriter.eraseOp(freemem);
110644e58509SEric Schweitz     return mlir::success();
1107c2acd453SAlexisPerry   }
1108c2acd453SAlexisPerry };
1109c2acd453SAlexisPerry } // namespace
1110044d5b5dSValentin Clement 
1111af6ee580SValentin Clement /// Common base class for embox to descriptor conversion.
1112af6ee580SValentin Clement template <typename OP>
1113af6ee580SValentin Clement struct EmboxCommonConversion : public FIROpConversion<OP> {
1114af6ee580SValentin Clement   using FIROpConversion<OP>::FIROpConversion;
1115af6ee580SValentin Clement 
1116af6ee580SValentin Clement   // Find the LLVMFuncOp in whose entry block the alloca should be inserted.
1117af6ee580SValentin Clement   // The order to find the LLVMFuncOp is as follows:
1118af6ee580SValentin Clement   // 1. The parent operation of the current block if it is a LLVMFuncOp.
1119af6ee580SValentin Clement   // 2. The first ancestor that is a LLVMFuncOp.
1120af6ee580SValentin Clement   mlir::LLVM::LLVMFuncOp
getFuncForAllocaInsertEmboxCommonConversion1121af6ee580SValentin Clement   getFuncForAllocaInsert(mlir::ConversionPatternRewriter &rewriter) const {
1122af6ee580SValentin Clement     mlir::Operation *parentOp = rewriter.getInsertionBlock()->getParentOp();
1123af6ee580SValentin Clement     return mlir::isa<mlir::LLVM::LLVMFuncOp>(parentOp)
1124af6ee580SValentin Clement                ? mlir::cast<mlir::LLVM::LLVMFuncOp>(parentOp)
1125af6ee580SValentin Clement                : parentOp->getParentOfType<mlir::LLVM::LLVMFuncOp>();
1126af6ee580SValentin Clement   }
1127af6ee580SValentin Clement 
1128af6ee580SValentin Clement   // Generate an alloca of size 1 and type \p toTy.
1129af6ee580SValentin Clement   mlir::LLVM::AllocaOp
genAllocaWithTypeEmboxCommonConversion1130af6ee580SValentin Clement   genAllocaWithType(mlir::Location loc, mlir::Type toTy, unsigned alignment,
1131af6ee580SValentin Clement                     mlir::ConversionPatternRewriter &rewriter) const {
1132af6ee580SValentin Clement     auto thisPt = rewriter.saveInsertionPoint();
1133af6ee580SValentin Clement     mlir::LLVM::LLVMFuncOp func = getFuncForAllocaInsert(rewriter);
1134af6ee580SValentin Clement     rewriter.setInsertionPointToStart(&func.front());
1135af6ee580SValentin Clement     auto size = this->genI32Constant(loc, rewriter, 1);
1136af6ee580SValentin Clement     auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, toTy, size, alignment);
1137af6ee580SValentin Clement     rewriter.restoreInsertionPoint(thisPt);
1138af6ee580SValentin Clement     return al;
1139af6ee580SValentin Clement   }
1140af6ee580SValentin Clement 
getCFIAttrEmboxCommonConversion1141af6ee580SValentin Clement   static int getCFIAttr(fir::BoxType boxTy) {
1142af6ee580SValentin Clement     auto eleTy = boxTy.getEleTy();
1143af6ee580SValentin Clement     if (eleTy.isa<fir::PointerType>())
1144af6ee580SValentin Clement       return CFI_attribute_pointer;
1145af6ee580SValentin Clement     if (eleTy.isa<fir::HeapType>())
1146af6ee580SValentin Clement       return CFI_attribute_allocatable;
1147af6ee580SValentin Clement     return CFI_attribute_other;
1148af6ee580SValentin Clement   }
1149af6ee580SValentin Clement 
unwrapIfDerivedEmboxCommonConversion1150af6ee580SValentin Clement   static fir::RecordType unwrapIfDerived(fir::BoxType boxTy) {
1151af6ee580SValentin Clement     return fir::unwrapSequenceType(fir::dyn_cast_ptrOrBoxEleTy(boxTy))
1152af6ee580SValentin Clement         .template dyn_cast<fir::RecordType>();
1153af6ee580SValentin Clement   }
isDerivedTypeWithLenParamsEmboxCommonConversion1154af6ee580SValentin Clement   static bool isDerivedTypeWithLenParams(fir::BoxType boxTy) {
1155af6ee580SValentin Clement     auto recTy = unwrapIfDerived(boxTy);
1156af6ee580SValentin Clement     return recTy && recTy.getNumLenParams() > 0;
1157af6ee580SValentin Clement   }
isDerivedTypeEmboxCommonConversion1158af6ee580SValentin Clement   static bool isDerivedType(fir::BoxType boxTy) {
1159575c9d6dSValentin Clement     return static_cast<bool>(unwrapIfDerived(boxTy));
1160af6ee580SValentin Clement   }
1161af6ee580SValentin Clement 
1162af6ee580SValentin Clement   // Get the element size and CFI type code of the boxed value.
getSizeAndTypeCodeEmboxCommonConversion1163af6ee580SValentin Clement   std::tuple<mlir::Value, mlir::Value> getSizeAndTypeCode(
1164af6ee580SValentin Clement       mlir::Location loc, mlir::ConversionPatternRewriter &rewriter,
1165af6ee580SValentin Clement       mlir::Type boxEleTy, mlir::ValueRange lenParams = {}) const {
1166af6ee580SValentin Clement     auto doInteger =
__anon447c3e180902(unsigned width) 1167af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1168af6ee580SValentin Clement       int typeCode = fir::integerBitsToTypeCode(width);
1169af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1170af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1171af6ee580SValentin Clement     };
1172af6ee580SValentin Clement     auto doLogical =
__anon447c3e180a02(unsigned width) 1173af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1174af6ee580SValentin Clement       int typeCode = fir::logicalBitsToTypeCode(width);
1175af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1176af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1177af6ee580SValentin Clement     };
__anon447c3e180b02(unsigned width) 1178af6ee580SValentin Clement     auto doFloat = [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1179af6ee580SValentin Clement       int typeCode = fir::realBitsToTypeCode(width);
1180af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1181af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1182af6ee580SValentin Clement     };
1183af6ee580SValentin Clement     auto doComplex =
__anon447c3e180c02(unsigned width) 1184af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1185af6ee580SValentin Clement       auto typeCode = fir::complexBitsToTypeCode(width);
1186af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8 * 2),
1187af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1188af6ee580SValentin Clement     };
1189af6ee580SValentin Clement     auto doCharacter =
1190af6ee580SValentin Clement         [&](unsigned width,
__anon447c3e180d02(unsigned width, mlir::Value len) 1191af6ee580SValentin Clement             mlir::Value len) -> std::tuple<mlir::Value, mlir::Value> {
1192af6ee580SValentin Clement       auto typeCode = fir::characterBitsToTypeCode(width);
1193af6ee580SValentin Clement       auto typeCodeVal = this->genConstantOffset(loc, rewriter, typeCode);
1194af6ee580SValentin Clement       if (width == 8)
1195af6ee580SValentin Clement         return {len, typeCodeVal};
1196af6ee580SValentin Clement       auto i64Ty = mlir::IntegerType::get(&this->lowerTy().getContext(), 64);
11976c89c531SEric Schweitz       auto byteWidth = genConstantIndex(loc, i64Ty, rewriter, width / 8);
11986c89c531SEric Schweitz       auto len64 = FIROpConversion<OP>::integerCast(loc, rewriter, i64Ty, len);
1199af6ee580SValentin Clement       auto size =
12006c89c531SEric Schweitz           rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, byteWidth, len64);
1201af6ee580SValentin Clement       return {size, typeCodeVal};
1202af6ee580SValentin Clement     };
__anon447c3e180e02() 1203af6ee580SValentin Clement     auto getKindMap = [&]() -> fir::KindMapping & {
1204af6ee580SValentin Clement       return this->lowerTy().getKindMap();
1205af6ee580SValentin Clement     };
1206af6ee580SValentin Clement     // Pointer-like types.
1207af6ee580SValentin Clement     if (auto eleTy = fir::dyn_cast_ptrEleTy(boxEleTy))
1208af6ee580SValentin Clement       boxEleTy = eleTy;
1209af6ee580SValentin Clement     // Integer types.
1210af6ee580SValentin Clement     if (fir::isa_integer(boxEleTy)) {
1211af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::IntegerType>())
1212af6ee580SValentin Clement         return doInteger(ty.getWidth());
1213af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::IntegerType>();
1214af6ee580SValentin Clement       return doInteger(getKindMap().getIntegerBitsize(ty.getFKind()));
1215af6ee580SValentin Clement     }
1216af6ee580SValentin Clement     // Floating point types.
1217af6ee580SValentin Clement     if (fir::isa_real(boxEleTy)) {
1218af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::FloatType>())
1219af6ee580SValentin Clement         return doFloat(ty.getWidth());
1220af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::RealType>();
1221af6ee580SValentin Clement       return doFloat(getKindMap().getRealBitsize(ty.getFKind()));
1222af6ee580SValentin Clement     }
1223af6ee580SValentin Clement     // Complex types.
1224af6ee580SValentin Clement     if (fir::isa_complex(boxEleTy)) {
1225af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::ComplexType>())
1226af6ee580SValentin Clement         return doComplex(
1227af6ee580SValentin Clement             ty.getElementType().cast<mlir::FloatType>().getWidth());
1228af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::ComplexType>();
1229af6ee580SValentin Clement       return doComplex(getKindMap().getRealBitsize(ty.getFKind()));
1230af6ee580SValentin Clement     }
1231af6ee580SValentin Clement     // Character types.
1232af6ee580SValentin Clement     if (auto ty = boxEleTy.dyn_cast<fir::CharacterType>()) {
1233af6ee580SValentin Clement       auto charWidth = getKindMap().getCharacterBitsize(ty.getFKind());
1234af6ee580SValentin Clement       if (ty.getLen() != fir::CharacterType::unknownLen()) {
1235af6ee580SValentin Clement         auto len = this->genConstantOffset(loc, rewriter, ty.getLen());
1236af6ee580SValentin Clement         return doCharacter(charWidth, len);
1237af6ee580SValentin Clement       }
1238af6ee580SValentin Clement       assert(!lenParams.empty());
1239af6ee580SValentin Clement       return doCharacter(charWidth, lenParams.back());
1240af6ee580SValentin Clement     }
1241af6ee580SValentin Clement     // Logical type.
1242af6ee580SValentin Clement     if (auto ty = boxEleTy.dyn_cast<fir::LogicalType>())
1243af6ee580SValentin Clement       return doLogical(getKindMap().getLogicalBitsize(ty.getFKind()));
1244af6ee580SValentin Clement     // Array types.
1245af6ee580SValentin Clement     if (auto seqTy = boxEleTy.dyn_cast<fir::SequenceType>())
1246af6ee580SValentin Clement       return getSizeAndTypeCode(loc, rewriter, seqTy.getEleTy(), lenParams);
1247af6ee580SValentin Clement     // Derived-type types.
1248af6ee580SValentin Clement     if (boxEleTy.isa<fir::RecordType>()) {
1249af6ee580SValentin Clement       auto ptrTy = mlir::LLVM::LLVMPointerType::get(
1250af6ee580SValentin Clement           this->lowerTy().convertType(boxEleTy));
1251af6ee580SValentin Clement       auto nullPtr = rewriter.create<mlir::LLVM::NullOp>(loc, ptrTy);
1252af6ee580SValentin Clement       auto one =
1253af6ee580SValentin Clement           genConstantIndex(loc, this->lowerTy().offsetType(), rewriter, 1);
125430122656SAlex Zinenko       auto gep = rewriter.create<mlir::LLVM::GEPOp>(loc, ptrTy, nullPtr,
125530122656SAlex Zinenko                                                     mlir::ValueRange{one});
1256af6ee580SValentin Clement       auto eleSize = rewriter.create<mlir::LLVM::PtrToIntOp>(
1257af6ee580SValentin Clement           loc, this->lowerTy().indexType(), gep);
1258af6ee580SValentin Clement       return {eleSize,
1259af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, fir::derivedToTypeCode())};
1260af6ee580SValentin Clement     }
1261af6ee580SValentin Clement     // Reference type.
1262af6ee580SValentin Clement     if (fir::isa_ref_type(boxEleTy)) {
1263af6ee580SValentin Clement       // FIXME: use the target pointer size rather than sizeof(void*)
1264af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, sizeof(void *)),
1265af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, CFI_type_cptr)};
1266af6ee580SValentin Clement     }
1267af6ee580SValentin Clement     fir::emitFatalError(loc, "unhandled type in fir.box code generation");
1268af6ee580SValentin Clement   }
1269af6ee580SValentin Clement 
1270af6ee580SValentin Clement   /// Basic pattern to write a field in the descriptor
insertFieldEmboxCommonConversion1271af6ee580SValentin Clement   mlir::Value insertField(mlir::ConversionPatternRewriter &rewriter,
1272af6ee580SValentin Clement                           mlir::Location loc, mlir::Value dest,
127344e58509SEric Schweitz                           llvm::ArrayRef<unsigned> fldIndexes,
127444e58509SEric Schweitz                           mlir::Value value, bool bitcast = false) const {
1275af6ee580SValentin Clement     auto boxTy = dest.getType();
1276af6ee580SValentin Clement     auto fldTy = this->getBoxEleTy(boxTy, fldIndexes);
1277af6ee580SValentin Clement     if (bitcast)
1278af6ee580SValentin Clement       value = rewriter.create<mlir::LLVM::BitcastOp>(loc, fldTy, value);
1279af6ee580SValentin Clement     else
1280af6ee580SValentin Clement       value = this->integerCast(loc, rewriter, fldTy, value);
128144e58509SEric Schweitz     llvm::SmallVector<mlir::Attribute, 2> attrs;
1282af6ee580SValentin Clement     for (auto i : fldIndexes)
1283af6ee580SValentin Clement       attrs.push_back(rewriter.getI32IntegerAttr(i));
1284af6ee580SValentin Clement     auto indexesAttr = mlir::ArrayAttr::get(rewriter.getContext(), attrs);
1285af6ee580SValentin Clement     return rewriter.create<mlir::LLVM::InsertValueOp>(loc, boxTy, dest, value,
1286af6ee580SValentin Clement                                                       indexesAttr);
1287af6ee580SValentin Clement   }
1288af6ee580SValentin Clement 
1289af6ee580SValentin Clement   inline mlir::Value
insertBaseAddressEmboxCommonConversion1290af6ee580SValentin Clement   insertBaseAddress(mlir::ConversionPatternRewriter &rewriter,
1291af6ee580SValentin Clement                     mlir::Location loc, mlir::Value dest,
1292af6ee580SValentin Clement                     mlir::Value base) const {
12931f551032SValentin Clement     return insertField(rewriter, loc, dest, {kAddrPosInBox}, base,
12941f551032SValentin Clement                        /*bitCast=*/true);
12951f551032SValentin Clement   }
12961f551032SValentin Clement 
insertLowerBoundEmboxCommonConversion12971f551032SValentin Clement   inline mlir::Value insertLowerBound(mlir::ConversionPatternRewriter &rewriter,
12981f551032SValentin Clement                                       mlir::Location loc, mlir::Value dest,
12991f551032SValentin Clement                                       unsigned dim, mlir::Value lb) const {
13001f551032SValentin Clement     return insertField(rewriter, loc, dest,
13011f551032SValentin Clement                        {kDimsPosInBox, dim, kDimLowerBoundPos}, lb);
13021f551032SValentin Clement   }
13031f551032SValentin Clement 
insertExtentEmboxCommonConversion13041f551032SValentin Clement   inline mlir::Value insertExtent(mlir::ConversionPatternRewriter &rewriter,
13051f551032SValentin Clement                                   mlir::Location loc, mlir::Value dest,
13061f551032SValentin Clement                                   unsigned dim, mlir::Value extent) const {
13071f551032SValentin Clement     return insertField(rewriter, loc, dest, {kDimsPosInBox, dim, kDimExtentPos},
13081f551032SValentin Clement                        extent);
13091f551032SValentin Clement   }
13101f551032SValentin Clement 
insertStrideEmboxCommonConversion13111f551032SValentin Clement   inline mlir::Value insertStride(mlir::ConversionPatternRewriter &rewriter,
13121f551032SValentin Clement                                   mlir::Location loc, mlir::Value dest,
13131f551032SValentin Clement                                   unsigned dim, mlir::Value stride) const {
13141f551032SValentin Clement     return insertField(rewriter, loc, dest, {kDimsPosInBox, dim, kDimStridePos},
13151f551032SValentin Clement                        stride);
1316af6ee580SValentin Clement   }
1317af6ee580SValentin Clement 
1318af6ee580SValentin Clement   /// Get the address of the type descriptor global variable that was created by
1319af6ee580SValentin Clement   /// lowering for derived type \p recType.
1320af6ee580SValentin Clement   template <typename BOX>
1321af6ee580SValentin Clement   mlir::Value
getTypeDescriptorEmboxCommonConversion1322af6ee580SValentin Clement   getTypeDescriptor(BOX box, mlir::ConversionPatternRewriter &rewriter,
1323af6ee580SValentin Clement                     mlir::Location loc, fir::RecordType recType) const {
1324013160f6SJean Perier     std::string name =
1325013160f6SJean Perier         fir::NameUniquer::getTypeDescriptorName(recType.getName());
1326af6ee580SValentin Clement     auto module = box->template getParentOfType<mlir::ModuleOp>();
1327af6ee580SValentin Clement     if (auto global = module.template lookupSymbol<fir::GlobalOp>(name)) {
1328af6ee580SValentin Clement       auto ty = mlir::LLVM::LLVMPointerType::get(
1329af6ee580SValentin Clement           this->lowerTy().convertType(global.getType()));
1330af6ee580SValentin Clement       return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty,
1331feeee78aSJacques Pienaar                                                       global.getSymName());
1332af6ee580SValentin Clement     }
1333af6ee580SValentin Clement     if (auto global =
1334af6ee580SValentin Clement             module.template lookupSymbol<mlir::LLVM::GlobalOp>(name)) {
1335af6ee580SValentin Clement       // The global may have already been translated to LLVM.
1336af6ee580SValentin Clement       auto ty = mlir::LLVM::LLVMPointerType::get(global.getType());
1337af6ee580SValentin Clement       return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty,
1338feeee78aSJacques Pienaar                                                       global.getSymName());
1339af6ee580SValentin Clement     }
13407dd7ccd2SJean Perier     // Type info derived types do not have type descriptors since they are the
13417dd7ccd2SJean Perier     // types defining type descriptors.
1342013160f6SJean Perier     if (!this->options.ignoreMissingTypeDescriptors &&
1343013160f6SJean Perier         !fir::NameUniquer::belongsToModule(
1344013160f6SJean Perier             name, Fortran::semantics::typeInfoBuiltinModule))
1345013160f6SJean Perier       fir::emitFatalError(
1346013160f6SJean Perier           loc, "runtime derived type info descriptor was not generated");
13475bde97b1SJean Perier     return rewriter.create<mlir::LLVM::NullOp>(
13485bde97b1SJean Perier         loc, ::getVoidPtrType(box.getContext()));
13497dd7ccd2SJean Perier   }
1350af6ee580SValentin Clement 
1351af6ee580SValentin Clement   template <typename BOX>
1352af6ee580SValentin Clement   std::tuple<fir::BoxType, mlir::Value, mlir::Value>
consDescriptorPrefixEmboxCommonConversion1353af6ee580SValentin Clement   consDescriptorPrefix(BOX box, mlir::ConversionPatternRewriter &rewriter,
1354af6ee580SValentin Clement                        unsigned rank, mlir::ValueRange lenParams) const {
1355af6ee580SValentin Clement     auto loc = box.getLoc();
1356af6ee580SValentin Clement     auto boxTy = box.getType().template dyn_cast<fir::BoxType>();
1357af6ee580SValentin Clement     auto convTy = this->lowerTy().convertBoxType(boxTy, rank);
1358af6ee580SValentin Clement     auto llvmBoxPtrTy = convTy.template cast<mlir::LLVM::LLVMPointerType>();
1359af6ee580SValentin Clement     auto llvmBoxTy = llvmBoxPtrTy.getElementType();
1360af6ee580SValentin Clement     mlir::Value descriptor =
1361af6ee580SValentin Clement         rewriter.create<mlir::LLVM::UndefOp>(loc, llvmBoxTy);
1362af6ee580SValentin Clement 
1363af6ee580SValentin Clement     llvm::SmallVector<mlir::Value> typeparams = lenParams;
1364af6ee580SValentin Clement     if constexpr (!std::is_same_v<BOX, fir::EmboxOp>) {
1365af6ee580SValentin Clement       if (!box.substr().empty() && fir::hasDynamicSize(boxTy.getEleTy()))
1366af6ee580SValentin Clement         typeparams.push_back(box.substr()[1]);
1367af6ee580SValentin Clement     }
1368af6ee580SValentin Clement 
1369af6ee580SValentin Clement     // Write each of the fields with the appropriate values
1370af6ee580SValentin Clement     auto [eleSize, cfiTy] =
1371af6ee580SValentin Clement         getSizeAndTypeCode(loc, rewriter, boxTy.getEleTy(), typeparams);
1372af6ee580SValentin Clement     descriptor =
1373af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kElemLenPosInBox}, eleSize);
1374af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kVersionPosInBox},
1375af6ee580SValentin Clement                              this->genI32Constant(loc, rewriter, CFI_VERSION));
1376af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kRankPosInBox},
1377af6ee580SValentin Clement                              this->genI32Constant(loc, rewriter, rank));
1378af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kTypePosInBox}, cfiTy);
1379af6ee580SValentin Clement     descriptor =
1380af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kAttributePosInBox},
1381af6ee580SValentin Clement                     this->genI32Constant(loc, rewriter, getCFIAttr(boxTy)));
1382af6ee580SValentin Clement     const bool hasAddendum = isDerivedType(boxTy);
1383af6ee580SValentin Clement     descriptor =
1384af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kF18AddendumPosInBox},
1385af6ee580SValentin Clement                     this->genI32Constant(loc, rewriter, hasAddendum ? 1 : 0));
1386af6ee580SValentin Clement 
1387af6ee580SValentin Clement     if (hasAddendum) {
1388af6ee580SValentin Clement       auto isArray =
1389af6ee580SValentin Clement           fir::dyn_cast_ptrOrBoxEleTy(boxTy).template isa<fir::SequenceType>();
1390af6ee580SValentin Clement       unsigned typeDescFieldId = isArray ? kOptTypePtrPosInBox : kDimsPosInBox;
1391af6ee580SValentin Clement       auto typeDesc =
1392af6ee580SValentin Clement           getTypeDescriptor(box, rewriter, loc, unwrapIfDerived(boxTy));
1393af6ee580SValentin Clement       descriptor =
1394af6ee580SValentin Clement           insertField(rewriter, loc, descriptor, {typeDescFieldId}, typeDesc,
1395af6ee580SValentin Clement                       /*bitCast=*/true);
1396af6ee580SValentin Clement     }
1397af6ee580SValentin Clement 
1398af6ee580SValentin Clement     return {boxTy, descriptor, eleSize};
1399af6ee580SValentin Clement   }
1400af6ee580SValentin Clement 
1401af40f99eSJean Perier   // Compute the base address of a fir.box given the indices from the slice.
1402af40f99eSJean Perier   // The indices from the "outer" dimensions (every dimension after the first
1403af40f99eSJean Perier   // one (inlcuded) that is not a compile time constant) must have been
1404af40f99eSJean Perier   // multiplied with the related extents and added together into \p outerOffset.
1405af40f99eSJean Perier   mlir::Value
genBoxOffsetGepEmboxCommonConversion1406af40f99eSJean Perier   genBoxOffsetGep(mlir::ConversionPatternRewriter &rewriter, mlir::Location loc,
1407af40f99eSJean Perier                   mlir::Value base, mlir::Value outerOffset,
1408af40f99eSJean Perier                   mlir::ValueRange cstInteriorIndices,
1409af40f99eSJean Perier                   mlir::ValueRange componentIndices,
1410af40f99eSJean Perier                   llvm::Optional<mlir::Value> substringOffset) const {
1411af40f99eSJean Perier     llvm::SmallVector<mlir::Value> gepArgs{outerOffset};
1412af40f99eSJean Perier     mlir::Type resultTy =
14131f551032SValentin Clement         base.getType().cast<mlir::LLVM::LLVMPointerType>().getElementType();
1414af40f99eSJean Perier     // Fortran is column major, llvm GEP is row major: reverse the indices here.
1415af40f99eSJean Perier     for (mlir::Value interiorIndex : llvm::reverse(cstInteriorIndices)) {
1416af40f99eSJean Perier       auto arrayTy = resultTy.dyn_cast<mlir::LLVM::LLVMArrayType>();
1417af40f99eSJean Perier       if (!arrayTy)
1418af40f99eSJean Perier         fir::emitFatalError(
1419af40f99eSJean Perier             loc,
1420af40f99eSJean Perier             "corrupted GEP generated being generated in fir.embox/fir.rebox");
1421af40f99eSJean Perier       resultTy = arrayTy.getElementType();
1422af40f99eSJean Perier       gepArgs.push_back(interiorIndex);
14236c89c531SEric Schweitz     }
1424af40f99eSJean Perier     for (mlir::Value componentIndex : componentIndices) {
1425af40f99eSJean Perier       // Component indices can be field index to select a component, or array
1426af40f99eSJean Perier       // index, to select an element in an array component.
1427af40f99eSJean Perier       if (auto structTy = resultTy.dyn_cast<mlir::LLVM::LLVMStructType>()) {
1428af40f99eSJean Perier         std::int64_t cstIndex = getConstantIntValue(componentIndex);
1429af40f99eSJean Perier         resultTy = structTy.getBody()[cstIndex];
1430af40f99eSJean Perier       } else if (auto arrayTy =
1431af40f99eSJean Perier                      resultTy.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
1432af40f99eSJean Perier         resultTy = arrayTy.getElementType();
1433af40f99eSJean Perier       } else {
1434af40f99eSJean Perier         fir::emitFatalError(loc, "corrupted component GEP generated being "
1435af40f99eSJean Perier                                  "generated in fir.embox/fir.rebox");
1436af40f99eSJean Perier       }
1437af40f99eSJean Perier       gepArgs.push_back(componentIndex);
1438af40f99eSJean Perier     }
1439af40f99eSJean Perier     if (substringOffset) {
1440af40f99eSJean Perier       if (auto arrayTy = resultTy.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
1441af40f99eSJean Perier         gepArgs.push_back(*substringOffset);
1442af40f99eSJean Perier         resultTy = arrayTy.getElementType();
1443af40f99eSJean Perier       } else {
1444af40f99eSJean Perier         // If the CHARACTER length is dynamic, the whole base type should have
1445af40f99eSJean Perier         // degenerated to an llvm.ptr<i[width]>, and there should not be any
1446af40f99eSJean Perier         // cstInteriorIndices/componentIndices. The substring offset can be
1447af40f99eSJean Perier         // added to the outterOffset since it applies on the same LLVM type.
1448af40f99eSJean Perier         if (gepArgs.size() != 1)
1449af40f99eSJean Perier           fir::emitFatalError(loc,
1450af40f99eSJean Perier                               "corrupted substring GEP in fir.embox/fir.rebox");
1451af40f99eSJean Perier         mlir::Type outterOffsetTy = gepArgs[0].getType();
1452af40f99eSJean Perier         mlir::Value cast =
1453af40f99eSJean Perier             this->integerCast(loc, rewriter, outterOffsetTy, *substringOffset);
1454af40f99eSJean Perier 
1455af40f99eSJean Perier         gepArgs[0] = rewriter.create<mlir::LLVM::AddOp>(loc, outterOffsetTy,
1456af40f99eSJean Perier                                                         gepArgs[0], cast);
1457af40f99eSJean Perier       }
1458af40f99eSJean Perier     }
1459af40f99eSJean Perier     resultTy = mlir::LLVM::LLVMPointerType::get(resultTy);
1460af40f99eSJean Perier     return rewriter.create<mlir::LLVM::GEPOp>(loc, resultTy, base, gepArgs);
1461af40f99eSJean Perier   }
1462af40f99eSJean Perier 
1463af40f99eSJean Perier   template <typename BOX>
1464af40f99eSJean Perier   void
getSubcomponentIndicesEmboxCommonConversion1465af40f99eSJean Perier   getSubcomponentIndices(BOX xbox, mlir::Value memref,
1466af40f99eSJean Perier                          mlir::ValueRange operands,
1467af40f99eSJean Perier                          mlir::SmallVectorImpl<mlir::Value> &indices) const {
1468af40f99eSJean Perier     // For each field in the path add the offset to base via the args list.
1469af40f99eSJean Perier     // In the most general case, some offsets must be computed since
1470af40f99eSJean Perier     // they are not be known until runtime.
1471af40f99eSJean Perier     if (fir::hasDynamicSize(fir::unwrapSequenceType(
1472af40f99eSJean Perier             fir::unwrapPassByRefType(memref.getType()))))
1473af40f99eSJean Perier       TODO(xbox.getLoc(),
1474af40f99eSJean Perier            "fir.embox codegen dynamic size component in derived type");
1475af40f99eSJean Perier     indices.append(operands.begin() + xbox.subcomponentOffset(),
1476af40f99eSJean Perier                    operands.begin() + xbox.subcomponentOffset() +
1477af40f99eSJean Perier                        xbox.subcomponent().size());
14781f551032SValentin Clement   }
14791f551032SValentin Clement 
1480af6ee580SValentin Clement   /// If the embox is not in a globalOp body, allocate storage for the box;
1481af6ee580SValentin Clement   /// store the value inside and return the generated alloca. Return the input
1482af6ee580SValentin Clement   /// value otherwise.
1483af6ee580SValentin Clement   mlir::Value
placeInMemoryIfNotGlobalInitEmboxCommonConversion1484af6ee580SValentin Clement   placeInMemoryIfNotGlobalInit(mlir::ConversionPatternRewriter &rewriter,
1485af6ee580SValentin Clement                                mlir::Location loc, mlir::Value boxValue) const {
1486af6ee580SValentin Clement     auto *thisBlock = rewriter.getInsertionBlock();
1487af6ee580SValentin Clement     if (thisBlock && mlir::isa<mlir::LLVM::GlobalOp>(thisBlock->getParentOp()))
1488af6ee580SValentin Clement       return boxValue;
1489af6ee580SValentin Clement     auto boxPtrTy = mlir::LLVM::LLVMPointerType::get(boxValue.getType());
1490af6ee580SValentin Clement     auto alloca = genAllocaWithType(loc, boxPtrTy, defaultAlign, rewriter);
1491af6ee580SValentin Clement     rewriter.create<mlir::LLVM::StoreOp>(loc, boxValue, alloca);
1492af6ee580SValentin Clement     return alloca;
1493af6ee580SValentin Clement   }
1494af6ee580SValentin Clement };
1495af6ee580SValentin Clement 
14961f551032SValentin Clement /// Compute the extent of a triplet slice (lb:ub:step).
14971f551032SValentin Clement static mlir::Value
computeTripletExtent(mlir::ConversionPatternRewriter & rewriter,mlir::Location loc,mlir::Value lb,mlir::Value ub,mlir::Value step,mlir::Value zero,mlir::Type type)14981f551032SValentin Clement computeTripletExtent(mlir::ConversionPatternRewriter &rewriter,
14991f551032SValentin Clement                      mlir::Location loc, mlir::Value lb, mlir::Value ub,
15001f551032SValentin Clement                      mlir::Value step, mlir::Value zero, mlir::Type type) {
15011f551032SValentin Clement   mlir::Value extent = rewriter.create<mlir::LLVM::SubOp>(loc, type, ub, lb);
15021f551032SValentin Clement   extent = rewriter.create<mlir::LLVM::AddOp>(loc, type, extent, step);
15031f551032SValentin Clement   extent = rewriter.create<mlir::LLVM::SDivOp>(loc, type, extent, step);
15041f551032SValentin Clement   // If the resulting extent is negative (`ub-lb` and `step` have different
15051f551032SValentin Clement   // signs), zero must be returned instead.
15061f551032SValentin Clement   auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
15071f551032SValentin Clement       loc, mlir::LLVM::ICmpPredicate::sgt, extent, zero);
15081f551032SValentin Clement   return rewriter.create<mlir::LLVM::SelectOp>(loc, cmp, extent, zero);
15091f551032SValentin Clement }
15101f551032SValentin Clement 
1511af6ee580SValentin Clement /// Create a generic box on a memory reference. This conversions lowers the
1512af6ee580SValentin Clement /// abstract box to the appropriate, initialized descriptor.
1513af6ee580SValentin Clement struct EmboxOpConversion : public EmboxCommonConversion<fir::EmboxOp> {
1514af6ee580SValentin Clement   using EmboxCommonConversion::EmboxCommonConversion;
1515af6ee580SValentin Clement 
1516af6ee580SValentin Clement   mlir::LogicalResult
matchAndRewriteEmboxOpConversion1517af6ee580SValentin Clement   matchAndRewrite(fir::EmboxOp embox, OpAdaptor adaptor,
1518af6ee580SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
151912d26ce9SValentin Clement     mlir::ValueRange operands = adaptor.getOperands();
1520af6ee580SValentin Clement     assert(!embox.getShape() && "There should be no dims on this embox op");
152112d26ce9SValentin Clement     auto [boxTy, dest, eleSize] = consDescriptorPrefix(
152212d26ce9SValentin Clement         embox, rewriter, /*rank=*/0, /*lenParams=*/operands.drop_front(1));
152312d26ce9SValentin Clement     dest = insertBaseAddress(rewriter, embox.getLoc(), dest, operands[0]);
15247ce8c6fcSKiran Chandramohan     if (isDerivedTypeWithLenParams(boxTy)) {
15257ce8c6fcSKiran Chandramohan       TODO(embox.getLoc(),
15267ce8c6fcSKiran Chandramohan            "fir.embox codegen of derived with length parameters");
152744e58509SEric Schweitz       return mlir::failure();
15287ce8c6fcSKiran Chandramohan     }
1529af6ee580SValentin Clement     auto result = placeInMemoryIfNotGlobalInit(rewriter, embox.getLoc(), dest);
1530af6ee580SValentin Clement     rewriter.replaceOp(embox, result);
153144e58509SEric Schweitz     return mlir::success();
1532af6ee580SValentin Clement   }
1533af6ee580SValentin Clement };
1534af6ee580SValentin Clement 
15351f551032SValentin Clement /// Create a generic box on a memory reference.
15361f551032SValentin Clement struct XEmboxOpConversion : public EmboxCommonConversion<fir::cg::XEmboxOp> {
15371f551032SValentin Clement   using EmboxCommonConversion::EmboxCommonConversion;
15381f551032SValentin Clement 
15391f551032SValentin Clement   mlir::LogicalResult
matchAndRewriteXEmboxOpConversion15401f551032SValentin Clement   matchAndRewrite(fir::cg::XEmboxOp xbox, OpAdaptor adaptor,
15411f551032SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
15421f551032SValentin Clement     mlir::ValueRange operands = adaptor.getOperands();
154312d26ce9SValentin Clement     auto [boxTy, dest, eleSize] =
154412d26ce9SValentin Clement         consDescriptorPrefix(xbox, rewriter, xbox.getOutRank(),
154512d26ce9SValentin Clement                              operands.drop_front(xbox.lenParamOffset()));
154612d26ce9SValentin Clement     // Generate the triples in the dims field of the descriptor
15471f551032SValentin Clement     auto i64Ty = mlir::IntegerType::get(xbox.getContext(), 64);
15481f551032SValentin Clement     mlir::Value base = operands[0];
15491f551032SValentin Clement     assert(!xbox.shape().empty() && "must have a shape");
15501f551032SValentin Clement     unsigned shapeOffset = xbox.shapeOffset();
15511f551032SValentin Clement     bool hasShift = !xbox.shift().empty();
15521f551032SValentin Clement     unsigned shiftOffset = xbox.shiftOffset();
15531f551032SValentin Clement     bool hasSlice = !xbox.slice().empty();
15541f551032SValentin Clement     unsigned sliceOffset = xbox.sliceOffset();
15551f551032SValentin Clement     mlir::Location loc = xbox.getLoc();
15561f551032SValentin Clement     mlir::Value zero = genConstantIndex(loc, i64Ty, rewriter, 0);
15571f551032SValentin Clement     mlir::Value one = genConstantIndex(loc, i64Ty, rewriter, 1);
15581f551032SValentin Clement     mlir::Value prevPtrOff = one;
15591f551032SValentin Clement     mlir::Type eleTy = boxTy.getEleTy();
15601f551032SValentin Clement     const unsigned rank = xbox.getRank();
1561af40f99eSJean Perier     llvm::SmallVector<mlir::Value> cstInteriorIndices;
15621f551032SValentin Clement     unsigned constRows = 0;
15631f551032SValentin Clement     mlir::Value ptrOffset = zero;
15646c89c531SEric Schweitz     mlir::Type memEleTy = fir::dyn_cast_ptrEleTy(xbox.memref().getType());
15656c89c531SEric Schweitz     assert(memEleTy.isa<fir::SequenceType>());
15666c89c531SEric Schweitz     auto seqTy = memEleTy.cast<fir::SequenceType>();
15671f551032SValentin Clement     mlir::Type seqEleTy = seqTy.getEleTy();
15681f551032SValentin Clement     // Adjust the element scaling factor if the element is a dependent type.
15691f551032SValentin Clement     if (fir::hasDynamicSize(seqEleTy)) {
15706c89c531SEric Schweitz       if (auto charTy = seqEleTy.dyn_cast<fir::CharacterType>()) {
15711f551032SValentin Clement         assert(xbox.lenParams().size() == 1);
15726c89c531SEric Schweitz         mlir::LLVM::ConstantOp charSize = genConstantIndex(
15736c89c531SEric Schweitz             loc, i64Ty, rewriter, lowerTy().characterBitsize(charTy) / 8);
15746c89c531SEric Schweitz         mlir::Value castedLen =
15756c89c531SEric Schweitz             integerCast(loc, rewriter, i64Ty, operands[xbox.lenParamOffset()]);
15766c89c531SEric Schweitz         auto byteOffset =
15776c89c531SEric Schweitz             rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, charSize, castedLen);
15786c89c531SEric Schweitz         prevPtrOff = integerCast(loc, rewriter, i64Ty, byteOffset);
15791f551032SValentin Clement       } else if (seqEleTy.isa<fir::RecordType>()) {
15806c89c531SEric Schweitz         // prevPtrOff = ;
15811f551032SValentin Clement         TODO(loc, "generate call to calculate size of PDT");
15821f551032SValentin Clement       } else {
15836c89c531SEric Schweitz         fir::emitFatalError(loc, "unexpected dynamic type");
15841f551032SValentin Clement       }
15851f551032SValentin Clement     } else {
15861f551032SValentin Clement       constRows = seqTy.getConstantRows();
15871f551032SValentin Clement     }
15881f551032SValentin Clement 
15896c89c531SEric Schweitz     const auto hasSubcomp = !xbox.subcomponent().empty();
15906c89c531SEric Schweitz     const bool hasSubstr = !xbox.substr().empty();
15916c89c531SEric Schweitz     /// Compute initial element stride that will be use to compute the step in
15926c89c531SEric Schweitz     /// each dimension.
15936c89c531SEric Schweitz     mlir::Value prevDimByteStride = integerCast(loc, rewriter, i64Ty, eleSize);
15941f551032SValentin Clement     if (hasSubcomp) {
15951f551032SValentin Clement       // We have a subcomponent. The step value needs to be the number of
15961f551032SValentin Clement       // bytes per element (which is a derived type).
15971f551032SValentin Clement       auto eleTy = mlir::LLVM::LLVMPointerType::get(convertType(seqEleTy));
15986c89c531SEric Schweitz       prevDimByteStride = computeDerivedTypeSize(loc, eleTy, i64Ty, rewriter);
15996c89c531SEric Schweitz     } else if (hasSubstr) {
16006c89c531SEric Schweitz       // We have a substring. The step value needs to be the number of bytes
16016c89c531SEric Schweitz       // per CHARACTER element.
16026c89c531SEric Schweitz       auto charTy = seqEleTy.cast<fir::CharacterType>();
16036c89c531SEric Schweitz       if (fir::hasDynamicSize(charTy)) {
16046c89c531SEric Schweitz         prevDimByteStride = prevPtrOff;
16056c89c531SEric Schweitz       } else {
16066c89c531SEric Schweitz         prevDimByteStride = genConstantIndex(
16076c89c531SEric Schweitz             loc, i64Ty, rewriter,
16086c89c531SEric Schweitz             charTy.getLen() * lowerTy().characterBitsize(charTy) / 8);
16096c89c531SEric Schweitz       }
16101f551032SValentin Clement     }
16111f551032SValentin Clement 
16121f551032SValentin Clement     // Process the array subspace arguments (shape, shift, etc.), if any,
16131f551032SValentin Clement     // translating everything to values in the descriptor wherever the entity
16141f551032SValentin Clement     // has a dynamic array dimension.
16151f551032SValentin Clement     for (unsigned di = 0, descIdx = 0; di < rank; ++di) {
16161f551032SValentin Clement       mlir::Value extent = operands[shapeOffset];
16171f551032SValentin Clement       mlir::Value outerExtent = extent;
16181f551032SValentin Clement       bool skipNext = false;
16191f551032SValentin Clement       if (hasSlice) {
16201f551032SValentin Clement         mlir::Value off = operands[sliceOffset];
16211f551032SValentin Clement         mlir::Value adj = one;
16221f551032SValentin Clement         if (hasShift)
16231f551032SValentin Clement           adj = operands[shiftOffset];
16241f551032SValentin Clement         auto ao = rewriter.create<mlir::LLVM::SubOp>(loc, i64Ty, off, adj);
16251f551032SValentin Clement         if (constRows > 0) {
1626af40f99eSJean Perier           cstInteriorIndices.push_back(ao);
16271f551032SValentin Clement         } else {
16281f551032SValentin Clement           auto dimOff =
16291f551032SValentin Clement               rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, ao, prevPtrOff);
16301f551032SValentin Clement           ptrOffset =
16311f551032SValentin Clement               rewriter.create<mlir::LLVM::AddOp>(loc, i64Ty, dimOff, ptrOffset);
16321f551032SValentin Clement         }
16331f551032SValentin Clement         if (mlir::isa_and_nonnull<fir::UndefOp>(
16341f551032SValentin Clement                 xbox.slice()[3 * di + 1].getDefiningOp())) {
16351f551032SValentin Clement           // This dimension contains a scalar expression in the array slice op.
16361f551032SValentin Clement           // The dimension is loop invariant, will be dropped, and will not
16371f551032SValentin Clement           // appear in the descriptor.
16381f551032SValentin Clement           skipNext = true;
16391f551032SValentin Clement         }
16401f551032SValentin Clement       }
16411f551032SValentin Clement       if (!skipNext) {
16426c89c531SEric Schweitz         // store extent
16431f551032SValentin Clement         if (hasSlice)
16441f551032SValentin Clement           extent = computeTripletExtent(rewriter, loc, operands[sliceOffset],
16451f551032SValentin Clement                                         operands[sliceOffset + 1],
16461f551032SValentin Clement                                         operands[sliceOffset + 2], zero, i64Ty);
16476c89c531SEric Schweitz         // Lower bound is normalized to 0 for BIND(C) interoperability.
1648d3bc3a04SJean Perier         mlir::Value lb = zero;
1649d3bc3a04SJean Perier         const bool isaPointerOrAllocatable =
1650d3bc3a04SJean Perier             eleTy.isa<fir::PointerType>() || eleTy.isa<fir::HeapType>();
1651d3bc3a04SJean Perier         // Lower bound is defaults to 1 for POINTER, ALLOCATABLE, and
1652d3bc3a04SJean Perier         // denormalized descriptors.
16536c89c531SEric Schweitz         if (isaPointerOrAllocatable || !normalizedLowerBound(xbox))
1654d3bc3a04SJean Perier           lb = one;
1655bb3afae9SJean Perier         // If there is a shifted origin, and no fir.slice, and this is not
1656bb3afae9SJean Perier         // a normalized descriptor then use the value from the shift op as
1657bb3afae9SJean Perier         // the lower bound.
16586c89c531SEric Schweitz         if (hasShift && !(hasSlice || hasSubcomp || hasSubstr) &&
16596c89c531SEric Schweitz             (isaPointerOrAllocatable || !normalizedLowerBound(xbox))) {
1660d3bc3a04SJean Perier           lb = operands[shiftOffset];
1661d3bc3a04SJean Perier           auto extentIsEmpty = rewriter.create<mlir::LLVM::ICmpOp>(
1662d3bc3a04SJean Perier               loc, mlir::LLVM::ICmpPredicate::eq, extent, zero);
1663d3bc3a04SJean Perier           lb = rewriter.create<mlir::LLVM::SelectOp>(loc, extentIsEmpty, one,
1664d3bc3a04SJean Perier                                                      lb);
1665d3bc3a04SJean Perier         }
1666d3bc3a04SJean Perier         dest = insertLowerBound(rewriter, loc, dest, descIdx, lb);
1667d3bc3a04SJean Perier 
16681f551032SValentin Clement         dest = insertExtent(rewriter, loc, dest, descIdx, extent);
16691f551032SValentin Clement 
16701f551032SValentin Clement         // store step (scaled by shaped extent)
16716c89c531SEric Schweitz         mlir::Value step = prevDimByteStride;
16721f551032SValentin Clement         if (hasSlice)
16731f551032SValentin Clement           step = rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, step,
16741f551032SValentin Clement                                                     operands[sliceOffset + 2]);
16751f551032SValentin Clement         dest = insertStride(rewriter, loc, dest, descIdx, step);
16761f551032SValentin Clement         ++descIdx;
16771f551032SValentin Clement       }
16781f551032SValentin Clement 
16791f551032SValentin Clement       // compute the stride and offset for the next natural dimension
16806c89c531SEric Schweitz       prevDimByteStride = rewriter.create<mlir::LLVM::MulOp>(
16816c89c531SEric Schweitz           loc, i64Ty, prevDimByteStride, outerExtent);
16821f551032SValentin Clement       if (constRows == 0)
16831f551032SValentin Clement         prevPtrOff = rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, prevPtrOff,
16841f551032SValentin Clement                                                         outerExtent);
16850601a0dcSJean Perier       else
16860601a0dcSJean Perier         --constRows;
16871f551032SValentin Clement 
16881f551032SValentin Clement       // increment iterators
16891f551032SValentin Clement       ++shapeOffset;
16901f551032SValentin Clement       if (hasShift)
16911f551032SValentin Clement         ++shiftOffset;
16921f551032SValentin Clement       if (hasSlice)
16931f551032SValentin Clement         sliceOffset += 3;
16941f551032SValentin Clement     }
16956c89c531SEric Schweitz     if (hasSlice || hasSubcomp || hasSubstr) {
1696af40f99eSJean Perier       // Shift the base address.
1697af40f99eSJean Perier       llvm::SmallVector<mlir::Value> fieldIndices;
1698af40f99eSJean Perier       llvm::Optional<mlir::Value> substringOffset;
1699af40f99eSJean Perier       if (hasSubcomp)
1700af40f99eSJean Perier         getSubcomponentIndices(xbox, xbox.memref(), operands, fieldIndices);
17016c89c531SEric Schweitz       if (hasSubstr)
1702af40f99eSJean Perier         substringOffset = operands[xbox.substrOffset()];
1703af40f99eSJean Perier       base = genBoxOffsetGep(rewriter, loc, base, ptrOffset, cstInteriorIndices,
1704af40f99eSJean Perier                              fieldIndices, substringOffset);
17051f551032SValentin Clement     }
17061f551032SValentin Clement     dest = insertBaseAddress(rewriter, loc, dest, base);
17071f551032SValentin Clement     if (isDerivedTypeWithLenParams(boxTy))
17081f551032SValentin Clement       TODO(loc, "fir.embox codegen of derived with length parameters");
17091f551032SValentin Clement 
17101f551032SValentin Clement     mlir::Value result = placeInMemoryIfNotGlobalInit(rewriter, loc, dest);
17111f551032SValentin Clement     rewriter.replaceOp(xbox, result);
171244e58509SEric Schweitz     return mlir::success();
17131f551032SValentin Clement   }
1714d3bc3a04SJean Perier 
1715d3bc3a04SJean Perier   /// Return true if `xbox` has a normalized lower bounds attribute. A box value
1716d3bc3a04SJean Perier   /// that is neither a POINTER nor an ALLOCATABLE should be normalized to a
1717d3bc3a04SJean Perier   /// zero origin lower bound for interoperability with BIND(C).
normalizedLowerBoundXEmboxOpConversion1718d3bc3a04SJean Perier   inline static bool normalizedLowerBound(fir::cg::XEmboxOp xbox) {
1719d3bc3a04SJean Perier     return xbox->hasAttr(fir::getNormalizedLowerBoundAttrName());
1720d3bc3a04SJean Perier   }
17211f551032SValentin Clement };
17221f551032SValentin Clement 
1723fa517555SKiran Chandramohan /// Create a new box given a box reference.
1724fa517555SKiran Chandramohan struct XReboxOpConversion : public EmboxCommonConversion<fir::cg::XReboxOp> {
1725fa517555SKiran Chandramohan   using EmboxCommonConversion::EmboxCommonConversion;
1726fa517555SKiran Chandramohan 
1727fa517555SKiran Chandramohan   mlir::LogicalResult
matchAndRewriteXReboxOpConversion1728fa517555SKiran Chandramohan   matchAndRewrite(fir::cg::XReboxOp rebox, OpAdaptor adaptor,
1729fa517555SKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
1730fa517555SKiran Chandramohan     mlir::Location loc = rebox.getLoc();
1731fa517555SKiran Chandramohan     mlir::Type idxTy = lowerTy().indexType();
1732fa517555SKiran Chandramohan     mlir::Value loweredBox = adaptor.getOperands()[0];
1733fa517555SKiran Chandramohan     mlir::ValueRange operands = adaptor.getOperands();
1734fa517555SKiran Chandramohan 
1735fa517555SKiran Chandramohan     // Create new descriptor and fill its non-shape related data.
1736fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value, 2> lenParams;
1737fa517555SKiran Chandramohan     mlir::Type inputEleTy = getInputEleTy(rebox);
1738fa517555SKiran Chandramohan     if (auto charTy = inputEleTy.dyn_cast<fir::CharacterType>()) {
1739fa517555SKiran Chandramohan       mlir::Value len =
1740fa517555SKiran Chandramohan           loadElementSizeFromBox(loc, idxTy, loweredBox, rewriter);
1741fa517555SKiran Chandramohan       if (charTy.getFKind() != 1) {
1742fa517555SKiran Chandramohan         mlir::Value width =
1743fa517555SKiran Chandramohan             genConstantIndex(loc, idxTy, rewriter, charTy.getFKind());
1744fa517555SKiran Chandramohan         len = rewriter.create<mlir::LLVM::SDivOp>(loc, idxTy, len, width);
1745fa517555SKiran Chandramohan       }
1746fa517555SKiran Chandramohan       lenParams.emplace_back(len);
1747fa517555SKiran Chandramohan     } else if (auto recTy = inputEleTy.dyn_cast<fir::RecordType>()) {
1748fa517555SKiran Chandramohan       if (recTy.getNumLenParams() != 0)
1749fa517555SKiran Chandramohan         TODO(loc, "reboxing descriptor of derived type with length parameters");
1750fa517555SKiran Chandramohan     }
1751fa517555SKiran Chandramohan     auto [boxTy, dest, eleSize] =
1752fa517555SKiran Chandramohan         consDescriptorPrefix(rebox, rewriter, rebox.getOutRank(), lenParams);
1753fa517555SKiran Chandramohan 
1754fa517555SKiran Chandramohan     // Read input extents, strides, and base address
1755fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> inputExtents;
1756fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> inputStrides;
1757fa517555SKiran Chandramohan     const unsigned inputRank = rebox.getRank();
1758fa517555SKiran Chandramohan     for (unsigned i = 0; i < inputRank; ++i) {
1759fa517555SKiran Chandramohan       mlir::Value dim = genConstantIndex(loc, idxTy, rewriter, i);
176044e58509SEric Schweitz       llvm::SmallVector<mlir::Value, 3> dimInfo =
1761fa517555SKiran Chandramohan           getDimsFromBox(loc, {idxTy, idxTy, idxTy}, loweredBox, dim, rewriter);
1762fa517555SKiran Chandramohan       inputExtents.emplace_back(dimInfo[1]);
1763fa517555SKiran Chandramohan       inputStrides.emplace_back(dimInfo[2]);
1764fa517555SKiran Chandramohan     }
1765fa517555SKiran Chandramohan 
1766fa517555SKiran Chandramohan     mlir::Type baseTy = getBaseAddrTypeFromBox(loweredBox.getType());
1767fa517555SKiran Chandramohan     mlir::Value baseAddr =
1768fa517555SKiran Chandramohan         loadBaseAddrFromBox(loc, baseTy, loweredBox, rewriter);
1769fa517555SKiran Chandramohan 
1770fa517555SKiran Chandramohan     if (!rebox.slice().empty() || !rebox.subcomponent().empty())
1771fa517555SKiran Chandramohan       return sliceBox(rebox, dest, baseAddr, inputExtents, inputStrides,
1772fa517555SKiran Chandramohan                       operands, rewriter);
1773fa517555SKiran Chandramohan     return reshapeBox(rebox, dest, baseAddr, inputExtents, inputStrides,
1774fa517555SKiran Chandramohan                       operands, rewriter);
1775fa517555SKiran Chandramohan   }
1776fa517555SKiran Chandramohan 
1777fa517555SKiran Chandramohan private:
1778fa517555SKiran Chandramohan   /// Write resulting shape and base address in descriptor, and replace rebox
1779fa517555SKiran Chandramohan   /// op.
1780fa517555SKiran Chandramohan   mlir::LogicalResult
finalizeReboxXReboxOpConversion1781fa517555SKiran Chandramohan   finalizeRebox(fir::cg::XReboxOp rebox, mlir::Value dest, mlir::Value base,
1782fa517555SKiran Chandramohan                 mlir::ValueRange lbounds, mlir::ValueRange extents,
1783fa517555SKiran Chandramohan                 mlir::ValueRange strides,
1784fa517555SKiran Chandramohan                 mlir::ConversionPatternRewriter &rewriter) const {
1785fa517555SKiran Chandramohan     mlir::Location loc = rebox.getLoc();
1786d3bc3a04SJean Perier     mlir::Value zero =
1787d3bc3a04SJean Perier         genConstantIndex(loc, lowerTy().indexType(), rewriter, 0);
1788fa517555SKiran Chandramohan     mlir::Value one = genConstantIndex(loc, lowerTy().indexType(), rewriter, 1);
1789fa517555SKiran Chandramohan     for (auto iter : llvm::enumerate(llvm::zip(extents, strides))) {
1790d3bc3a04SJean Perier       mlir::Value extent = std::get<0>(iter.value());
1791fa517555SKiran Chandramohan       unsigned dim = iter.index();
1792d3bc3a04SJean Perier       mlir::Value lb = one;
1793d3bc3a04SJean Perier       if (!lbounds.empty()) {
1794d3bc3a04SJean Perier         lb = lbounds[dim];
1795d3bc3a04SJean Perier         auto extentIsEmpty = rewriter.create<mlir::LLVM::ICmpOp>(
1796d3bc3a04SJean Perier             loc, mlir::LLVM::ICmpPredicate::eq, extent, zero);
1797d3bc3a04SJean Perier         lb = rewriter.create<mlir::LLVM::SelectOp>(loc, extentIsEmpty, one, lb);
1798d3bc3a04SJean Perier       };
1799fa517555SKiran Chandramohan       dest = insertLowerBound(rewriter, loc, dest, dim, lb);
1800d3bc3a04SJean Perier       dest = insertExtent(rewriter, loc, dest, dim, extent);
1801fa517555SKiran Chandramohan       dest = insertStride(rewriter, loc, dest, dim, std::get<1>(iter.value()));
1802fa517555SKiran Chandramohan     }
1803fa517555SKiran Chandramohan     dest = insertBaseAddress(rewriter, loc, dest, base);
1804fa517555SKiran Chandramohan     mlir::Value result =
1805fa517555SKiran Chandramohan         placeInMemoryIfNotGlobalInit(rewriter, rebox.getLoc(), dest);
1806fa517555SKiran Chandramohan     rewriter.replaceOp(rebox, result);
180744e58509SEric Schweitz     return mlir::success();
1808fa517555SKiran Chandramohan   }
1809fa517555SKiran Chandramohan 
1810fa517555SKiran Chandramohan   // Apply slice given the base address, extents and strides of the input box.
1811fa517555SKiran Chandramohan   mlir::LogicalResult
sliceBoxXReboxOpConversion1812fa517555SKiran Chandramohan   sliceBox(fir::cg::XReboxOp rebox, mlir::Value dest, mlir::Value base,
1813fa517555SKiran Chandramohan            mlir::ValueRange inputExtents, mlir::ValueRange inputStrides,
1814fa517555SKiran Chandramohan            mlir::ValueRange operands,
1815fa517555SKiran Chandramohan            mlir::ConversionPatternRewriter &rewriter) const {
1816fa517555SKiran Chandramohan     mlir::Location loc = rebox.getLoc();
1817fa517555SKiran Chandramohan     mlir::Type voidPtrTy = ::getVoidPtrType(rebox.getContext());
1818fa517555SKiran Chandramohan     mlir::Type idxTy = lowerTy().indexType();
1819fa517555SKiran Chandramohan     mlir::Value zero = genConstantIndex(loc, idxTy, rewriter, 0);
1820fa517555SKiran Chandramohan     // Apply subcomponent and substring shift on base address.
1821fa517555SKiran Chandramohan     if (!rebox.subcomponent().empty() || !rebox.substr().empty()) {
1822fa517555SKiran Chandramohan       // Cast to inputEleTy* so that a GEP can be used.
1823fa517555SKiran Chandramohan       mlir::Type inputEleTy = getInputEleTy(rebox);
1824fa517555SKiran Chandramohan       auto llvmElePtrTy =
1825fa517555SKiran Chandramohan           mlir::LLVM::LLVMPointerType::get(convertType(inputEleTy));
1826fa517555SKiran Chandramohan       base = rewriter.create<mlir::LLVM::BitcastOp>(loc, llvmElePtrTy, base);
1827fa517555SKiran Chandramohan 
1828af40f99eSJean Perier       llvm::SmallVector<mlir::Value> fieldIndices;
1829af40f99eSJean Perier       llvm::Optional<mlir::Value> substringOffset;
1830af40f99eSJean Perier       if (!rebox.subcomponent().empty())
1831af40f99eSJean Perier         getSubcomponentIndices(rebox, rebox.box(), operands, fieldIndices);
1832fa517555SKiran Chandramohan       if (!rebox.substr().empty())
1833af40f99eSJean Perier         substringOffset = operands[rebox.substrOffset()];
1834af40f99eSJean Perier       base = genBoxOffsetGep(rewriter, loc, base, zero,
1835af40f99eSJean Perier                              /*cstInteriorIndices=*/llvm::None, fieldIndices,
1836af40f99eSJean Perier                              substringOffset);
1837fa517555SKiran Chandramohan     }
1838fa517555SKiran Chandramohan 
1839fa517555SKiran Chandramohan     if (rebox.slice().empty())
1840fa517555SKiran Chandramohan       // The array section is of the form array[%component][substring], keep
1841fa517555SKiran Chandramohan       // the input array extents and strides.
1842fa517555SKiran Chandramohan       return finalizeRebox(rebox, dest, base, /*lbounds*/ llvm::None,
1843fa517555SKiran Chandramohan                            inputExtents, inputStrides, rewriter);
1844fa517555SKiran Chandramohan 
1845fa517555SKiran Chandramohan     // Strides from the fir.box are in bytes.
1846fa517555SKiran Chandramohan     base = rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, base);
1847fa517555SKiran Chandramohan 
1848fa517555SKiran Chandramohan     // The slice is of the form array(i:j:k)[%component]. Compute new extents
1849fa517555SKiran Chandramohan     // and strides.
1850fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> slicedExtents;
1851fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> slicedStrides;
1852fa517555SKiran Chandramohan     mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1);
1853fa517555SKiran Chandramohan     const bool sliceHasOrigins = !rebox.shift().empty();
1854fa517555SKiran Chandramohan     unsigned sliceOps = rebox.sliceOffset();
1855fa517555SKiran Chandramohan     unsigned shiftOps = rebox.shiftOffset();
1856fa517555SKiran Chandramohan     auto strideOps = inputStrides.begin();
1857fa517555SKiran Chandramohan     const unsigned inputRank = inputStrides.size();
1858fa517555SKiran Chandramohan     for (unsigned i = 0; i < inputRank;
1859fa517555SKiran Chandramohan          ++i, ++strideOps, ++shiftOps, sliceOps += 3) {
1860fa517555SKiran Chandramohan       mlir::Value sliceLb =
1861fa517555SKiran Chandramohan           integerCast(loc, rewriter, idxTy, operands[sliceOps]);
1862fa517555SKiran Chandramohan       mlir::Value inputStride = *strideOps; // already idxTy
1863fa517555SKiran Chandramohan       // Apply origin shift: base += (lb-shift)*input_stride
1864fa517555SKiran Chandramohan       mlir::Value sliceOrigin =
1865fa517555SKiran Chandramohan           sliceHasOrigins
1866fa517555SKiran Chandramohan               ? integerCast(loc, rewriter, idxTy, operands[shiftOps])
1867fa517555SKiran Chandramohan               : one;
1868fa517555SKiran Chandramohan       mlir::Value diff =
1869fa517555SKiran Chandramohan           rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, sliceLb, sliceOrigin);
1870fa517555SKiran Chandramohan       mlir::Value offset =
1871fa517555SKiran Chandramohan           rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, inputStride);
1872fa517555SKiran Chandramohan       base = genGEP(loc, voidPtrTy, rewriter, base, offset);
1873fa517555SKiran Chandramohan       // Apply upper bound and step if this is a triplet. Otherwise, the
1874fa517555SKiran Chandramohan       // dimension is dropped and no extents/strides are computed.
1875fa517555SKiran Chandramohan       mlir::Value upper = operands[sliceOps + 1];
1876fa517555SKiran Chandramohan       const bool isTripletSlice =
1877fa517555SKiran Chandramohan           !mlir::isa_and_nonnull<mlir::LLVM::UndefOp>(upper.getDefiningOp());
1878fa517555SKiran Chandramohan       if (isTripletSlice) {
1879fa517555SKiran Chandramohan         mlir::Value step =
1880fa517555SKiran Chandramohan             integerCast(loc, rewriter, idxTy, operands[sliceOps + 2]);
1881fa517555SKiran Chandramohan         // extent = ub-lb+step/step
1882fa517555SKiran Chandramohan         mlir::Value sliceUb = integerCast(loc, rewriter, idxTy, upper);
1883fa517555SKiran Chandramohan         mlir::Value extent = computeTripletExtent(rewriter, loc, sliceLb,
1884fa517555SKiran Chandramohan                                                   sliceUb, step, zero, idxTy);
1885fa517555SKiran Chandramohan         slicedExtents.emplace_back(extent);
1886fa517555SKiran Chandramohan         // stride = step*input_stride
1887fa517555SKiran Chandramohan         mlir::Value stride =
1888fa517555SKiran Chandramohan             rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, step, inputStride);
1889fa517555SKiran Chandramohan         slicedStrides.emplace_back(stride);
1890fa517555SKiran Chandramohan       }
1891fa517555SKiran Chandramohan     }
1892fa517555SKiran Chandramohan     return finalizeRebox(rebox, dest, base, /*lbounds*/ llvm::None,
1893fa517555SKiran Chandramohan                          slicedExtents, slicedStrides, rewriter);
1894fa517555SKiran Chandramohan   }
1895fa517555SKiran Chandramohan 
1896fa517555SKiran Chandramohan   /// Apply a new shape to the data described by a box given the base address,
1897fa517555SKiran Chandramohan   /// extents and strides of the box.
1898fa517555SKiran Chandramohan   mlir::LogicalResult
reshapeBoxXReboxOpConversion1899fa517555SKiran Chandramohan   reshapeBox(fir::cg::XReboxOp rebox, mlir::Value dest, mlir::Value base,
1900fa517555SKiran Chandramohan              mlir::ValueRange inputExtents, mlir::ValueRange inputStrides,
1901fa517555SKiran Chandramohan              mlir::ValueRange operands,
1902fa517555SKiran Chandramohan              mlir::ConversionPatternRewriter &rewriter) const {
1903fa517555SKiran Chandramohan     mlir::ValueRange reboxShifts{operands.begin() + rebox.shiftOffset(),
1904fa517555SKiran Chandramohan                                  operands.begin() + rebox.shiftOffset() +
1905fa517555SKiran Chandramohan                                      rebox.shift().size()};
1906fa517555SKiran Chandramohan     if (rebox.shape().empty()) {
1907fa517555SKiran Chandramohan       // Only setting new lower bounds.
1908fa517555SKiran Chandramohan       return finalizeRebox(rebox, dest, base, reboxShifts, inputExtents,
1909fa517555SKiran Chandramohan                            inputStrides, rewriter);
1910fa517555SKiran Chandramohan     }
1911fa517555SKiran Chandramohan 
1912fa517555SKiran Chandramohan     mlir::Location loc = rebox.getLoc();
1913fa517555SKiran Chandramohan     // Strides from the fir.box are in bytes.
1914fa517555SKiran Chandramohan     mlir::Type voidPtrTy = ::getVoidPtrType(rebox.getContext());
1915fa517555SKiran Chandramohan     base = rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, base);
1916fa517555SKiran Chandramohan 
1917fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> newStrides;
1918fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> newExtents;
1919fa517555SKiran Chandramohan     mlir::Type idxTy = lowerTy().indexType();
1920fa517555SKiran Chandramohan     // First stride from input box is kept. The rest is assumed contiguous
1921fa517555SKiran Chandramohan     // (it is not possible to reshape otherwise). If the input is scalar,
1922fa517555SKiran Chandramohan     // which may be OK if all new extents are ones, the stride does not
1923fa517555SKiran Chandramohan     // matter, use one.
1924fa517555SKiran Chandramohan     mlir::Value stride = inputStrides.empty()
1925fa517555SKiran Chandramohan                              ? genConstantIndex(loc, idxTy, rewriter, 1)
1926fa517555SKiran Chandramohan                              : inputStrides[0];
1927fa517555SKiran Chandramohan     for (unsigned i = 0; i < rebox.shape().size(); ++i) {
1928fa517555SKiran Chandramohan       mlir::Value rawExtent = operands[rebox.shapeOffset() + i];
1929fa517555SKiran Chandramohan       mlir::Value extent = integerCast(loc, rewriter, idxTy, rawExtent);
1930fa517555SKiran Chandramohan       newExtents.emplace_back(extent);
1931fa517555SKiran Chandramohan       newStrides.emplace_back(stride);
1932fa517555SKiran Chandramohan       // nextStride = extent * stride;
1933fa517555SKiran Chandramohan       stride = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, extent, stride);
1934fa517555SKiran Chandramohan     }
1935fa517555SKiran Chandramohan     return finalizeRebox(rebox, dest, base, reboxShifts, newExtents, newStrides,
1936fa517555SKiran Chandramohan                          rewriter);
1937fa517555SKiran Chandramohan   }
1938fa517555SKiran Chandramohan 
1939fa517555SKiran Chandramohan   /// Return scalar element type of the input box.
getInputEleTyXReboxOpConversion1940fa517555SKiran Chandramohan   static mlir::Type getInputEleTy(fir::cg::XReboxOp rebox) {
1941fa517555SKiran Chandramohan     auto ty = fir::dyn_cast_ptrOrBoxEleTy(rebox.box().getType());
1942fa517555SKiran Chandramohan     if (auto seqTy = ty.dyn_cast<fir::SequenceType>())
1943fa517555SKiran Chandramohan       return seqTy.getEleTy();
1944fa517555SKiran Chandramohan     return ty;
1945fa517555SKiran Chandramohan   }
1946fa517555SKiran Chandramohan };
1947fa517555SKiran Chandramohan 
1948dc48849fSKiran Chandramohan /// Lower `fir.emboxproc` operation. Creates a procedure box.
1949dc48849fSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
1950dc48849fSKiran Chandramohan struct EmboxProcOpConversion : public FIROpConversion<fir::EmboxProcOp> {
1951dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
1952dc48849fSKiran Chandramohan 
1953dc48849fSKiran Chandramohan   mlir::LogicalResult
matchAndRewriteEmboxProcOpConversion1954dc48849fSKiran Chandramohan   matchAndRewrite(fir::EmboxProcOp emboxproc, OpAdaptor adaptor,
1955dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
1956dc48849fSKiran Chandramohan     TODO(emboxproc.getLoc(), "fir.emboxproc codegen");
195744e58509SEric Schweitz     return mlir::failure();
1958dc48849fSKiran Chandramohan   }
1959dc48849fSKiran Chandramohan };
1960dc48849fSKiran Chandramohan 
196154c56347SValentin Clement // Code shared between insert_value and extract_value Ops.
196254c56347SValentin Clement struct ValueOpCommon {
196354c56347SValentin Clement   // Translate the arguments pertaining to any multidimensional array to
196454c56347SValentin Clement   // row-major order for LLVM-IR.
toRowMajorValueOpCommon196544e58509SEric Schweitz   static void toRowMajor(llvm::SmallVectorImpl<mlir::Attribute> &attrs,
196654c56347SValentin Clement                          mlir::Type ty) {
196754c56347SValentin Clement     assert(ty && "type is null");
196854c56347SValentin Clement     const auto end = attrs.size();
196954c56347SValentin Clement     for (std::remove_const_t<decltype(end)> i = 0; i < end; ++i) {
197054c56347SValentin Clement       if (auto seq = ty.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
197154c56347SValentin Clement         const auto dim = getDimension(seq);
197254c56347SValentin Clement         if (dim > 1) {
197354c56347SValentin Clement           auto ub = std::min(i + dim, end);
197454c56347SValentin Clement           std::reverse(attrs.begin() + i, attrs.begin() + ub);
197554c56347SValentin Clement           i += dim - 1;
197654c56347SValentin Clement         }
197754c56347SValentin Clement         ty = getArrayElementType(seq);
197854c56347SValentin Clement       } else if (auto st = ty.dyn_cast<mlir::LLVM::LLVMStructType>()) {
197954c56347SValentin Clement         ty = st.getBody()[attrs[i].cast<mlir::IntegerAttr>().getInt()];
198054c56347SValentin Clement       } else {
198154c56347SValentin Clement         llvm_unreachable("index into invalid type");
198254c56347SValentin Clement       }
198354c56347SValentin Clement     }
198454c56347SValentin Clement   }
198554c56347SValentin Clement 
198654c56347SValentin Clement   static llvm::SmallVector<mlir::Attribute>
collectIndicesValueOpCommon198754c56347SValentin Clement   collectIndices(mlir::ConversionPatternRewriter &rewriter,
198854c56347SValentin Clement                  mlir::ArrayAttr arrAttr) {
198954c56347SValentin Clement     llvm::SmallVector<mlir::Attribute> attrs;
199054c56347SValentin Clement     for (auto i = arrAttr.begin(), e = arrAttr.end(); i != e; ++i) {
199154c56347SValentin Clement       if (i->isa<mlir::IntegerAttr>()) {
199254c56347SValentin Clement         attrs.push_back(*i);
199354c56347SValentin Clement       } else {
199454c56347SValentin Clement         auto fieldName = i->cast<mlir::StringAttr>().getValue();
199554c56347SValentin Clement         ++i;
199654c56347SValentin Clement         auto ty = i->cast<mlir::TypeAttr>().getValue();
199754c56347SValentin Clement         auto index = ty.cast<fir::RecordType>().getFieldIndex(fieldName);
199854c56347SValentin Clement         attrs.push_back(mlir::IntegerAttr::get(rewriter.getI32Type(), index));
199954c56347SValentin Clement       }
200054c56347SValentin Clement     }
200154c56347SValentin Clement     return attrs;
200254c56347SValentin Clement   }
200354c56347SValentin Clement 
200454c56347SValentin Clement private:
getArrayElementTypeValueOpCommon200554c56347SValentin Clement   static mlir::Type getArrayElementType(mlir::LLVM::LLVMArrayType ty) {
200654c56347SValentin Clement     auto eleTy = ty.getElementType();
200754c56347SValentin Clement     while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>())
200854c56347SValentin Clement       eleTy = arrTy.getElementType();
200954c56347SValentin Clement     return eleTy;
201054c56347SValentin Clement   }
201154c56347SValentin Clement };
201254c56347SValentin Clement 
2013c2acd453SAlexisPerry namespace {
201454c56347SValentin Clement /// Extract a subobject value from an ssa-value of aggregate type
201554c56347SValentin Clement struct ExtractValueOpConversion
201654c56347SValentin Clement     : public FIROpAndTypeConversion<fir::ExtractValueOp>,
201754c56347SValentin Clement       public ValueOpCommon {
201854c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
201954c56347SValentin Clement 
202054c56347SValentin Clement   mlir::LogicalResult
doRewrite__anon447c3e180f11::ExtractValueOpConversion202154c56347SValentin Clement   doRewrite(fir::ExtractValueOp extractVal, mlir::Type ty, OpAdaptor adaptor,
202254c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
202312d26ce9SValentin Clement     mlir::ValueRange operands = adaptor.getOperands();
2024149ad3d5SShraiysh Vaishay     auto attrs = collectIndices(rewriter, extractVal.getCoor());
202512d26ce9SValentin Clement     toRowMajor(attrs, operands[0].getType());
202654c56347SValentin Clement     auto position = mlir::ArrayAttr::get(extractVal.getContext(), attrs);
202754c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(
202812d26ce9SValentin Clement         extractVal, ty, operands[0], position);
202944e58509SEric Schweitz     return mlir::success();
203054c56347SValentin Clement   }
203154c56347SValentin Clement };
203254c56347SValentin Clement 
203354c56347SValentin Clement /// InsertValue is the generalized instruction for the composition of new
203454c56347SValentin Clement /// aggregate type values.
203554c56347SValentin Clement struct InsertValueOpConversion
203654c56347SValentin Clement     : public FIROpAndTypeConversion<fir::InsertValueOp>,
203754c56347SValentin Clement       public ValueOpCommon {
203854c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
203954c56347SValentin Clement 
204054c56347SValentin Clement   mlir::LogicalResult
doRewrite__anon447c3e180f11::InsertValueOpConversion204154c56347SValentin Clement   doRewrite(fir::InsertValueOp insertVal, mlir::Type ty, OpAdaptor adaptor,
204254c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
204312d26ce9SValentin Clement     mlir::ValueRange operands = adaptor.getOperands();
2044149ad3d5SShraiysh Vaishay     auto attrs = collectIndices(rewriter, insertVal.getCoor());
204512d26ce9SValentin Clement     toRowMajor(attrs, operands[0].getType());
204654c56347SValentin Clement     auto position = mlir::ArrayAttr::get(insertVal.getContext(), attrs);
204754c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
204812d26ce9SValentin Clement         insertVal, ty, operands[0], operands[1], position);
204944e58509SEric Schweitz     return mlir::success();
205054c56347SValentin Clement   }
205154c56347SValentin Clement };
205254c56347SValentin Clement 
20533ae8e442SValentin Clement /// InsertOnRange inserts a value into a sequence over a range of offsets.
20543ae8e442SValentin Clement struct InsertOnRangeOpConversion
20553ae8e442SValentin Clement     : public FIROpAndTypeConversion<fir::InsertOnRangeOp> {
20563ae8e442SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
20573ae8e442SValentin Clement 
20583ae8e442SValentin Clement   // Increments an array of subscripts in a row major fasion.
incrementSubscripts__anon447c3e180f11::InsertOnRangeOpConversion205944e58509SEric Schweitz   void incrementSubscripts(const llvm::SmallVector<uint64_t> &dims,
206044e58509SEric Schweitz                            llvm::SmallVector<uint64_t> &subscripts) const {
20613ae8e442SValentin Clement     for (size_t i = dims.size(); i > 0; --i) {
20623ae8e442SValentin Clement       if (++subscripts[i - 1] < dims[i - 1]) {
20633ae8e442SValentin Clement         return;
20643ae8e442SValentin Clement       }
20653ae8e442SValentin Clement       subscripts[i - 1] = 0;
20663ae8e442SValentin Clement     }
20673ae8e442SValentin Clement   }
20683ae8e442SValentin Clement 
20693ae8e442SValentin Clement   mlir::LogicalResult
doRewrite__anon447c3e180f11::InsertOnRangeOpConversion20703ae8e442SValentin Clement   doRewrite(fir::InsertOnRangeOp range, mlir::Type ty, OpAdaptor adaptor,
20713ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
20723ae8e442SValentin Clement 
20733ae8e442SValentin Clement     llvm::SmallVector<uint64_t> dims;
20743ae8e442SValentin Clement     auto type = adaptor.getOperands()[0].getType();
20753ae8e442SValentin Clement 
20763ae8e442SValentin Clement     // Iteratively extract the array dimensions from the type.
20773ae8e442SValentin Clement     while (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
20783ae8e442SValentin Clement       dims.push_back(t.getNumElements());
20793ae8e442SValentin Clement       type = t.getElementType();
20803ae8e442SValentin Clement     }
20813ae8e442SValentin Clement 
2082575c9d6dSValentin Clement     llvm::SmallVector<std::uint64_t> lBounds;
2083575c9d6dSValentin Clement     llvm::SmallVector<std::uint64_t> uBounds;
20843ae8e442SValentin Clement 
20853ae8e442SValentin Clement     // Unzip the upper and lower bound and convert to a row major format.
2086149ad3d5SShraiysh Vaishay     mlir::DenseIntElementsAttr coor = range.getCoor();
20878ec0f221SMehdi Amini     auto reversedCoor = llvm::reverse(coor.getValues<int64_t>());
20888ec0f221SMehdi Amini     for (auto i = reversedCoor.begin(), e = reversedCoor.end(); i != e; ++i) {
20893ae8e442SValentin Clement       uBounds.push_back(*i++);
20903ae8e442SValentin Clement       lBounds.push_back(*i);
20913ae8e442SValentin Clement     }
20923ae8e442SValentin Clement 
20933ae8e442SValentin Clement     auto &subscripts = lBounds;
20943ae8e442SValentin Clement     auto loc = range.getLoc();
20953ae8e442SValentin Clement     mlir::Value lastOp = adaptor.getOperands()[0];
20963ae8e442SValentin Clement     mlir::Value insertVal = adaptor.getOperands()[1];
20973ae8e442SValentin Clement 
20983ae8e442SValentin Clement     auto i64Ty = rewriter.getI64Type();
20993ae8e442SValentin Clement     while (subscripts != uBounds) {
21003ae8e442SValentin Clement       // Convert uint64_t's to Attribute's.
210144e58509SEric Schweitz       llvm::SmallVector<mlir::Attribute> subscriptAttrs;
21023ae8e442SValentin Clement       for (const auto &subscript : subscripts)
210344e58509SEric Schweitz         subscriptAttrs.push_back(mlir::IntegerAttr::get(i64Ty, subscript));
21043ae8e442SValentin Clement       lastOp = rewriter.create<mlir::LLVM::InsertValueOp>(
21053ae8e442SValentin Clement           loc, ty, lastOp, insertVal,
210644e58509SEric Schweitz           mlir::ArrayAttr::get(range.getContext(), subscriptAttrs));
21073ae8e442SValentin Clement 
21083ae8e442SValentin Clement       incrementSubscripts(dims, subscripts);
21093ae8e442SValentin Clement     }
21103ae8e442SValentin Clement 
21113ae8e442SValentin Clement     // Convert uint64_t's to Attribute's.
211244e58509SEric Schweitz     llvm::SmallVector<mlir::Attribute> subscriptAttrs;
21133ae8e442SValentin Clement     for (const auto &subscript : subscripts)
21143ae8e442SValentin Clement       subscriptAttrs.push_back(
211544e58509SEric Schweitz           mlir::IntegerAttr::get(rewriter.getI64Type(), subscript));
21163ae8e442SValentin Clement     mlir::ArrayRef<mlir::Attribute> arrayRef(subscriptAttrs);
21173ae8e442SValentin Clement 
21183ae8e442SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
21193ae8e442SValentin Clement         range, ty, lastOp, insertVal,
212044e58509SEric Schweitz         mlir::ArrayAttr::get(range.getContext(), arrayRef));
21213ae8e442SValentin Clement 
212244e58509SEric Schweitz     return mlir::success();
21233ae8e442SValentin Clement   }
21243ae8e442SValentin Clement };
2125c2acd453SAlexisPerry } // namespace
21267b5132daSValentin Clement 
2127dc48849fSKiran Chandramohan namespace {
21285d27abe6SValentin Clement /// XArrayCoor is the address arithmetic on a dynamically shaped, sliced,
21295d27abe6SValentin Clement /// shifted etc. array.
21305d27abe6SValentin Clement /// (See the static restriction on coordinate_of.) array_coor determines the
21315d27abe6SValentin Clement /// coordinate (location) of a specific element.
21325d27abe6SValentin Clement struct XArrayCoorOpConversion
21335d27abe6SValentin Clement     : public FIROpAndTypeConversion<fir::cg::XArrayCoorOp> {
21345d27abe6SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
21355d27abe6SValentin Clement 
21365d27abe6SValentin Clement   mlir::LogicalResult
doRewrite__anon447c3e181011::XArrayCoorOpConversion21375d27abe6SValentin Clement   doRewrite(fir::cg::XArrayCoorOp coor, mlir::Type ty, OpAdaptor adaptor,
21385d27abe6SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
21395d27abe6SValentin Clement     auto loc = coor.getLoc();
21405d27abe6SValentin Clement     mlir::ValueRange operands = adaptor.getOperands();
21415d27abe6SValentin Clement     unsigned rank = coor.getRank();
21425d27abe6SValentin Clement     assert(coor.indices().size() == rank);
21435d27abe6SValentin Clement     assert(coor.shape().empty() || coor.shape().size() == rank);
21445d27abe6SValentin Clement     assert(coor.shift().empty() || coor.shift().size() == rank);
21455d27abe6SValentin Clement     assert(coor.slice().empty() || coor.slice().size() == 3 * rank);
21465d27abe6SValentin Clement     mlir::Type idxTy = lowerTy().indexType();
2147914b9eecSKiran Chandramohan     unsigned indexOffset = coor.indicesOffset();
2148914b9eecSKiran Chandramohan     unsigned shapeOffset = coor.shapeOffset();
2149914b9eecSKiran Chandramohan     unsigned shiftOffset = coor.shiftOffset();
2150914b9eecSKiran Chandramohan     unsigned sliceOffset = coor.sliceOffset();
2151914b9eecSKiran Chandramohan     auto sliceOps = coor.slice().begin();
21525d27abe6SValentin Clement     mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1);
21535d27abe6SValentin Clement     mlir::Value prevExt = one;
21545d27abe6SValentin Clement     mlir::Value zero = genConstantIndex(loc, idxTy, rewriter, 0);
21555d27abe6SValentin Clement     mlir::Value offset = zero;
21565d27abe6SValentin Clement     const bool isShifted = !coor.shift().empty();
21575d27abe6SValentin Clement     const bool isSliced = !coor.slice().empty();
21585d27abe6SValentin Clement     const bool baseIsBoxed = coor.memref().getType().isa<fir::BoxType>();
21595d27abe6SValentin Clement 
21605d27abe6SValentin Clement     // For each dimension of the array, generate the offset calculation.
2161914b9eecSKiran Chandramohan     for (unsigned i = 0; i < rank; ++i, ++indexOffset, ++shapeOffset,
2162914b9eecSKiran Chandramohan                   ++shiftOffset, sliceOffset += 3, sliceOps += 3) {
21635d27abe6SValentin Clement       mlir::Value index =
2164914b9eecSKiran Chandramohan           integerCast(loc, rewriter, idxTy, operands[indexOffset]);
2165914b9eecSKiran Chandramohan       mlir::Value lb =
2166914b9eecSKiran Chandramohan           isShifted ? integerCast(loc, rewriter, idxTy, operands[shiftOffset])
21675d27abe6SValentin Clement                     : one;
21685d27abe6SValentin Clement       mlir::Value step = one;
21695d27abe6SValentin Clement       bool normalSlice = isSliced;
21705d27abe6SValentin Clement       // Compute zero based index in dimension i of the element, applying
21715d27abe6SValentin Clement       // potential triplets and lower bounds.
21725d27abe6SValentin Clement       if (isSliced) {
2173914b9eecSKiran Chandramohan         mlir::Value originalUb = *(sliceOps + 1);
2174914b9eecSKiran Chandramohan         normalSlice =
2175914b9eecSKiran Chandramohan             !mlir::isa_and_nonnull<fir::UndefOp>(originalUb.getDefiningOp());
21765d27abe6SValentin Clement         if (normalSlice)
2177914b9eecSKiran Chandramohan           step = integerCast(loc, rewriter, idxTy, operands[sliceOffset + 2]);
21785d27abe6SValentin Clement       }
21795d27abe6SValentin Clement       auto idx = rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, index, lb);
21805d27abe6SValentin Clement       mlir::Value diff =
21815d27abe6SValentin Clement           rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, idx, step);
21825d27abe6SValentin Clement       if (normalSlice) {
21835d27abe6SValentin Clement         mlir::Value sliceLb =
2184914b9eecSKiran Chandramohan             integerCast(loc, rewriter, idxTy, operands[sliceOffset]);
21855d27abe6SValentin Clement         auto adj = rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, sliceLb, lb);
21865d27abe6SValentin Clement         diff = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, diff, adj);
21875d27abe6SValentin Clement       }
21885d27abe6SValentin Clement       // Update the offset given the stride and the zero based index `diff`
21895d27abe6SValentin Clement       // that was just computed.
21905d27abe6SValentin Clement       if (baseIsBoxed) {
21915d27abe6SValentin Clement         // Use stride in bytes from the descriptor.
219212d26ce9SValentin Clement         mlir::Value stride = loadStrideFromBox(loc, operands[0], i, rewriter);
21935d27abe6SValentin Clement         auto sc = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, stride);
21945d27abe6SValentin Clement         offset = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, offset);
21955d27abe6SValentin Clement       } else {
21965d27abe6SValentin Clement         // Use stride computed at last iteration.
21975d27abe6SValentin Clement         auto sc = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, prevExt);
21985d27abe6SValentin Clement         offset = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, offset);
21995d27abe6SValentin Clement         // Compute next stride assuming contiguity of the base array
22005d27abe6SValentin Clement         // (in element number).
2201914b9eecSKiran Chandramohan         auto nextExt = integerCast(loc, rewriter, idxTy, operands[shapeOffset]);
22025d27abe6SValentin Clement         prevExt =
22035d27abe6SValentin Clement             rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, prevExt, nextExt);
22045d27abe6SValentin Clement       }
22055d27abe6SValentin Clement     }
22065d27abe6SValentin Clement 
22075d27abe6SValentin Clement     // Add computed offset to the base address.
22085d27abe6SValentin Clement     if (baseIsBoxed) {
22095d27abe6SValentin Clement       // Working with byte offsets. The base address is read from the fir.box.
22105d27abe6SValentin Clement       // and need to be casted to i8* to do the pointer arithmetic.
221112d26ce9SValentin Clement       mlir::Type baseTy = getBaseAddrTypeFromBox(operands[0].getType());
22125d27abe6SValentin Clement       mlir::Value base =
221312d26ce9SValentin Clement           loadBaseAddrFromBox(loc, baseTy, operands[0], rewriter);
22145d27abe6SValentin Clement       mlir::Type voidPtrTy = getVoidPtrType();
22155d27abe6SValentin Clement       base = rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, base);
221630122656SAlex Zinenko       llvm::SmallVector<mlir::Value> args{offset};
221730122656SAlex Zinenko       auto addr =
221830122656SAlex Zinenko           rewriter.create<mlir::LLVM::GEPOp>(loc, voidPtrTy, base, args);
22195d27abe6SValentin Clement       if (coor.subcomponent().empty()) {
222012d26ce9SValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(coor, ty, addr);
222144e58509SEric Schweitz         return mlir::success();
22225d27abe6SValentin Clement       }
22235d27abe6SValentin Clement       auto casted = rewriter.create<mlir::LLVM::BitcastOp>(loc, baseTy, addr);
22245d27abe6SValentin Clement       args.clear();
22255d27abe6SValentin Clement       args.push_back(zero);
22265d27abe6SValentin Clement       if (!coor.lenParams().empty()) {
22275d27abe6SValentin Clement         // If type parameters are present, then we don't want to use a GEPOp
22285d27abe6SValentin Clement         // as below, as the LLVM struct type cannot be statically defined.
22295d27abe6SValentin Clement         TODO(loc, "derived type with type parameters");
22305d27abe6SValentin Clement       }
22315d27abe6SValentin Clement       // TODO: array offset subcomponents must be converted to LLVM's
22325d27abe6SValentin Clement       // row-major layout here.
22335d27abe6SValentin Clement       for (auto i = coor.subcomponentOffset(); i != coor.indicesOffset(); ++i)
22345d27abe6SValentin Clement         args.push_back(operands[i]);
223512d26ce9SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(coor, ty, casted, args);
223644e58509SEric Schweitz       return mlir::success();
22375d27abe6SValentin Clement     }
22385d27abe6SValentin Clement 
22395d27abe6SValentin Clement     // The array was not boxed, so it must be contiguous. offset is therefore an
22405d27abe6SValentin Clement     // element offset and the base type is kept in the GEP unless the element
22415d27abe6SValentin Clement     // type size is itself dynamic.
22425d27abe6SValentin Clement     mlir::Value base;
22435d27abe6SValentin Clement     if (coor.subcomponent().empty()) {
22445d27abe6SValentin Clement       // No subcomponent.
22455d27abe6SValentin Clement       if (!coor.lenParams().empty()) {
22465d27abe6SValentin Clement         // Type parameters. Adjust element size explicitly.
22475d27abe6SValentin Clement         auto eleTy = fir::dyn_cast_ptrEleTy(coor.getType());
22485d27abe6SValentin Clement         assert(eleTy && "result must be a reference-like type");
22495d27abe6SValentin Clement         if (fir::characterWithDynamicLen(eleTy)) {
22505d27abe6SValentin Clement           assert(coor.lenParams().size() == 1);
2251649439e7SValentin Clement           auto length = integerCast(loc, rewriter, idxTy,
2252649439e7SValentin Clement                                     operands[coor.lenParamsOffset()]);
2253649439e7SValentin Clement           offset =
2254649439e7SValentin Clement               rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, offset, length);
22555d27abe6SValentin Clement         } else {
22565d27abe6SValentin Clement           TODO(loc, "compute size of derived type with type parameters");
22575d27abe6SValentin Clement         }
22585d27abe6SValentin Clement       }
22595d27abe6SValentin Clement       // Cast the base address to a pointer to T.
226012d26ce9SValentin Clement       base = rewriter.create<mlir::LLVM::BitcastOp>(loc, ty, operands[0]);
22615d27abe6SValentin Clement     } else {
22625d27abe6SValentin Clement       // Operand #0 must have a pointer type. For subcomponent slicing, we
22635d27abe6SValentin Clement       // want to cast away the array type and have a plain struct type.
226412d26ce9SValentin Clement       mlir::Type ty0 = operands[0].getType();
22655d27abe6SValentin Clement       auto ptrTy = ty0.dyn_cast<mlir::LLVM::LLVMPointerType>();
22665d27abe6SValentin Clement       assert(ptrTy && "expected pointer type");
22675d27abe6SValentin Clement       mlir::Type eleTy = ptrTy.getElementType();
22685d27abe6SValentin Clement       while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>())
22695d27abe6SValentin Clement         eleTy = arrTy.getElementType();
22705d27abe6SValentin Clement       auto newTy = mlir::LLVM::LLVMPointerType::get(eleTy);
227112d26ce9SValentin Clement       base = rewriter.create<mlir::LLVM::BitcastOp>(loc, newTy, operands[0]);
22725d27abe6SValentin Clement     }
227344e58509SEric Schweitz     llvm::SmallVector<mlir::Value> args = {offset};
22745d27abe6SValentin Clement     for (auto i = coor.subcomponentOffset(); i != coor.indicesOffset(); ++i)
22755d27abe6SValentin Clement       args.push_back(operands[i]);
227630122656SAlex Zinenko     rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(coor, ty, base, args);
227744e58509SEric Schweitz     return mlir::success();
22785d27abe6SValentin Clement   }
22795d27abe6SValentin Clement };
2280dc48849fSKiran Chandramohan } // namespace
2281dc48849fSKiran Chandramohan 
2282dc48849fSKiran Chandramohan /// Convert to (memory) reference to a reference to a subobject.
2283dc48849fSKiran Chandramohan /// The coordinate_of op is a Swiss army knife operation that can be used on
2284dc48849fSKiran Chandramohan /// (memory) references to records, arrays, complex, etc. as well as boxes.
2285dc48849fSKiran Chandramohan /// With unboxed arrays, there is the restriction that the array have a static
2286dc48849fSKiran Chandramohan /// shape in all but the last column.
2287dc48849fSKiran Chandramohan struct CoordinateOpConversion
2288dc48849fSKiran Chandramohan     : public FIROpAndTypeConversion<fir::CoordinateOp> {
2289dc48849fSKiran Chandramohan   using FIROpAndTypeConversion::FIROpAndTypeConversion;
2290dc48849fSKiran Chandramohan 
2291dc48849fSKiran Chandramohan   mlir::LogicalResult
doRewriteCoordinateOpConversion2292dc48849fSKiran Chandramohan   doRewrite(fir::CoordinateOp coor, mlir::Type ty, OpAdaptor adaptor,
2293dc48849fSKiran Chandramohan             mlir::ConversionPatternRewriter &rewriter) const override {
2294dc48849fSKiran Chandramohan     mlir::ValueRange operands = adaptor.getOperands();
2295dc48849fSKiran Chandramohan 
2296dc48849fSKiran Chandramohan     mlir::Location loc = coor.getLoc();
2297dc48849fSKiran Chandramohan     mlir::Value base = operands[0];
2298dc48849fSKiran Chandramohan     mlir::Type baseObjectTy = coor.getBaseType();
2299dc48849fSKiran Chandramohan     mlir::Type objectTy = fir::dyn_cast_ptrOrBoxEleTy(baseObjectTy);
2300dc48849fSKiran Chandramohan     assert(objectTy && "fir.coordinate_of expects a reference type");
2301dc48849fSKiran Chandramohan 
2302dc48849fSKiran Chandramohan     // Complex type - basically, extract the real or imaginary part
2303dc48849fSKiran Chandramohan     if (fir::isa_complex(objectTy)) {
2304dc48849fSKiran Chandramohan       mlir::LLVM::ConstantOp c0 =
2305dc48849fSKiran Chandramohan           genConstantIndex(loc, lowerTy().indexType(), rewriter, 0);
230603efa5a3SAndrzej Warzynski       llvm::SmallVector<mlir::Value> offs = {c0, operands[1]};
2307dc48849fSKiran Chandramohan       mlir::Value gep = genGEP(loc, ty, rewriter, base, offs);
2308dc48849fSKiran Chandramohan       rewriter.replaceOp(coor, gep);
230944e58509SEric Schweitz       return mlir::success();
2310dc48849fSKiran Chandramohan     }
2311dc48849fSKiran Chandramohan 
2312dc48849fSKiran Chandramohan     // Boxed type - get the base pointer from the box
2313dc48849fSKiran Chandramohan     if (baseObjectTy.dyn_cast<fir::BoxType>())
2314dc48849fSKiran Chandramohan       return doRewriteBox(coor, ty, operands, loc, rewriter);
2315dc48849fSKiran Chandramohan 
231603efa5a3SAndrzej Warzynski     // Reference, pointer or a heap type
231703efa5a3SAndrzej Warzynski     if (baseObjectTy.isa<fir::ReferenceType, fir::PointerType, fir::HeapType>())
2318dc48849fSKiran Chandramohan       return doRewriteRefOrPtr(coor, ty, operands, loc, rewriter);
2319dc48849fSKiran Chandramohan 
2320dc48849fSKiran Chandramohan     return rewriter.notifyMatchFailure(
2321dc48849fSKiran Chandramohan         coor, "fir.coordinate_of base operand has unsupported type");
2322dc48849fSKiran Chandramohan   }
2323dc48849fSKiran Chandramohan 
getFieldNumberCoordinateOpConversion232403efa5a3SAndrzej Warzynski   static unsigned getFieldNumber(fir::RecordType ty, mlir::Value op) {
2325dc48849fSKiran Chandramohan     return fir::hasDynamicSize(ty)
2326dc48849fSKiran Chandramohan                ? op.getDefiningOp()
2327dc48849fSKiran Chandramohan                      ->getAttrOfType<mlir::IntegerAttr>("field")
2328dc48849fSKiran Chandramohan                      .getInt()
2329af40f99eSJean Perier                : getConstantIntValue(op);
2330dc48849fSKiran Chandramohan   }
2331dc48849fSKiran Chandramohan 
hasSubDimensionsCoordinateOpConversion233203efa5a3SAndrzej Warzynski   static bool hasSubDimensions(mlir::Type type) {
2333dc48849fSKiran Chandramohan     return type.isa<fir::SequenceType, fir::RecordType, mlir::TupleType>();
2334dc48849fSKiran Chandramohan   }
2335dc48849fSKiran Chandramohan 
2336dc48849fSKiran Chandramohan   /// Check whether this form of `!fir.coordinate_of` is supported. These
2337dc48849fSKiran Chandramohan   /// additional checks are required, because we are not yet able to convert
2338dc48849fSKiran Chandramohan   /// all valid forms of `!fir.coordinate_of`.
2339dc48849fSKiran Chandramohan   /// TODO: Either implement the unsupported cases or extend the verifier
2340dc48849fSKiran Chandramohan   /// in FIROps.cpp instead.
supportedCoordinateCoordinateOpConversion234103efa5a3SAndrzej Warzynski   static bool supportedCoordinate(mlir::Type type, mlir::ValueRange coors) {
2342dc48849fSKiran Chandramohan     const std::size_t numOfCoors = coors.size();
2343dc48849fSKiran Chandramohan     std::size_t i = 0;
2344dc48849fSKiran Chandramohan     bool subEle = false;
2345dc48849fSKiran Chandramohan     bool ptrEle = false;
2346dc48849fSKiran Chandramohan     for (; i < numOfCoors; ++i) {
2347dc48849fSKiran Chandramohan       mlir::Value nxtOpnd = coors[i];
2348dc48849fSKiran Chandramohan       if (auto arrTy = type.dyn_cast<fir::SequenceType>()) {
2349dc48849fSKiran Chandramohan         subEle = true;
2350dc48849fSKiran Chandramohan         i += arrTy.getDimension() - 1;
2351dc48849fSKiran Chandramohan         type = arrTy.getEleTy();
2352dc48849fSKiran Chandramohan       } else if (auto recTy = type.dyn_cast<fir::RecordType>()) {
2353dc48849fSKiran Chandramohan         subEle = true;
2354dc48849fSKiran Chandramohan         type = recTy.getType(getFieldNumber(recTy, nxtOpnd));
2355dc48849fSKiran Chandramohan       } else if (auto tupTy = type.dyn_cast<mlir::TupleType>()) {
2356dc48849fSKiran Chandramohan         subEle = true;
2357af40f99eSJean Perier         type = tupTy.getType(getConstantIntValue(nxtOpnd));
2358dc48849fSKiran Chandramohan       } else {
2359dc48849fSKiran Chandramohan         ptrEle = true;
2360dc48849fSKiran Chandramohan       }
2361dc48849fSKiran Chandramohan     }
2362dc48849fSKiran Chandramohan     if (ptrEle)
2363dc48849fSKiran Chandramohan       return (!subEle) && (numOfCoors == 1);
2364dc48849fSKiran Chandramohan     return subEle && (i >= numOfCoors);
2365dc48849fSKiran Chandramohan   }
2366dc48849fSKiran Chandramohan 
2367dc48849fSKiran Chandramohan   /// Walk the abstract memory layout and determine if the path traverses any
2368dc48849fSKiran Chandramohan   /// array types with unknown shape. Return true iff all the array types have a
2369dc48849fSKiran Chandramohan   /// constant shape along the path.
arraysHaveKnownShapeCoordinateOpConversion237003efa5a3SAndrzej Warzynski   static bool arraysHaveKnownShape(mlir::Type type, mlir::ValueRange coors) {
237103efa5a3SAndrzej Warzynski     for (std::size_t i = 0, sz = coors.size(); i < sz; ++i) {
2372dc48849fSKiran Chandramohan       mlir::Value nxtOpnd = coors[i];
2373dc48849fSKiran Chandramohan       if (auto arrTy = type.dyn_cast<fir::SequenceType>()) {
2374dc48849fSKiran Chandramohan         if (fir::sequenceWithNonConstantShape(arrTy))
2375dc48849fSKiran Chandramohan           return false;
2376dc48849fSKiran Chandramohan         i += arrTy.getDimension() - 1;
2377dc48849fSKiran Chandramohan         type = arrTy.getEleTy();
2378dc48849fSKiran Chandramohan       } else if (auto strTy = type.dyn_cast<fir::RecordType>()) {
2379dc48849fSKiran Chandramohan         type = strTy.getType(getFieldNumber(strTy, nxtOpnd));
2380dc48849fSKiran Chandramohan       } else if (auto strTy = type.dyn_cast<mlir::TupleType>()) {
2381af40f99eSJean Perier         type = strTy.getType(getConstantIntValue(nxtOpnd));
2382dc48849fSKiran Chandramohan       } else {
2383dc48849fSKiran Chandramohan         return true;
2384dc48849fSKiran Chandramohan       }
2385dc48849fSKiran Chandramohan     }
2386dc48849fSKiran Chandramohan     return true;
2387dc48849fSKiran Chandramohan   }
2388dc48849fSKiran Chandramohan 
2389dc48849fSKiran Chandramohan private:
2390dc48849fSKiran Chandramohan   mlir::LogicalResult
doRewriteBoxCoordinateOpConversion2391dc48849fSKiran Chandramohan   doRewriteBox(fir::CoordinateOp coor, mlir::Type ty, mlir::ValueRange operands,
2392dc48849fSKiran Chandramohan                mlir::Location loc,
2393dc48849fSKiran Chandramohan                mlir::ConversionPatternRewriter &rewriter) const {
2394dc48849fSKiran Chandramohan     mlir::Type boxObjTy = coor.getBaseType();
2395dc48849fSKiran Chandramohan     assert(boxObjTy.dyn_cast<fir::BoxType>() && "This is not a `fir.box`");
2396dc48849fSKiran Chandramohan 
2397dc48849fSKiran Chandramohan     mlir::Value boxBaseAddr = operands[0];
2398dc48849fSKiran Chandramohan 
2399dc48849fSKiran Chandramohan     // 1. SPECIAL CASE (uses `fir.len_param_index`):
2400dc48849fSKiran Chandramohan     //   %box = ... : !fir.box<!fir.type<derived{len1:i32}>>
2401dc48849fSKiran Chandramohan     //   %lenp = fir.len_param_index len1, !fir.type<derived{len1:i32}>
2402dc48849fSKiran Chandramohan     //   %addr = coordinate_of %box, %lenp
2403dc48849fSKiran Chandramohan     if (coor.getNumOperands() == 2) {
2404dc48849fSKiran Chandramohan       mlir::Operation *coordinateDef =
2405dc48849fSKiran Chandramohan           (*coor.getCoor().begin()).getDefiningOp();
240644e58509SEric Schweitz       if (mlir::isa_and_nonnull<fir::LenParamIndexOp>(coordinateDef))
2407dc48849fSKiran Chandramohan         TODO(loc,
2408dc48849fSKiran Chandramohan              "fir.coordinate_of - fir.len_param_index is not supported yet");
2409dc48849fSKiran Chandramohan     }
2410dc48849fSKiran Chandramohan 
2411dc48849fSKiran Chandramohan     // 2. GENERAL CASE:
2412dc48849fSKiran Chandramohan     // 2.1. (`fir.array`)
2413dc48849fSKiran Chandramohan     //   %box = ... : !fix.box<!fir.array<?xU>>
2414dc48849fSKiran Chandramohan     //   %idx = ... : index
2415dc48849fSKiran Chandramohan     //   %resultAddr = coordinate_of %box, %idx : !fir.ref<U>
2416dc48849fSKiran Chandramohan     // 2.2 (`fir.derived`)
2417dc48849fSKiran Chandramohan     //   %box = ... : !fix.box<!fir.type<derived_type{field_1:i32}>>
2418dc48849fSKiran Chandramohan     //   %idx = ... : i32
2419dc48849fSKiran Chandramohan     //   %resultAddr = coordinate_of %box, %idx : !fir.ref<i32>
2420dc48849fSKiran Chandramohan     // 2.3 (`fir.derived` inside `fir.array`)
2421dc48849fSKiran Chandramohan     //   %box = ... : !fir.box<!fir.array<10 x !fir.type<derived_1{field_1:f32,
2422dc48849fSKiran Chandramohan     //   field_2:f32}>>> %idx1 = ... : index %idx2 = ... : i32 %resultAddr =
2423dc48849fSKiran Chandramohan     //   coordinate_of %box, %idx1, %idx2 : !fir.ref<f32>
2424dc48849fSKiran Chandramohan     // 2.4. TODO: Either document or disable any other case that the following
2425dc48849fSKiran Chandramohan     //  implementation might convert.
2426dc48849fSKiran Chandramohan     mlir::LLVM::ConstantOp c0 =
2427dc48849fSKiran Chandramohan         genConstantIndex(loc, lowerTy().indexType(), rewriter, 0);
2428dc48849fSKiran Chandramohan     mlir::Value resultAddr =
2429dc48849fSKiran Chandramohan         loadBaseAddrFromBox(loc, getBaseAddrTypeFromBox(boxBaseAddr.getType()),
2430dc48849fSKiran Chandramohan                             boxBaseAddr, rewriter);
243103efa5a3SAndrzej Warzynski     // Component Type
243203efa5a3SAndrzej Warzynski     auto cpnTy = fir::dyn_cast_ptrOrBoxEleTy(boxObjTy);
2433dc48849fSKiran Chandramohan     mlir::Type voidPtrTy = ::getVoidPtrType(coor.getContext());
2434dc48849fSKiran Chandramohan 
2435dc48849fSKiran Chandramohan     for (unsigned i = 1, last = operands.size(); i < last; ++i) {
243603efa5a3SAndrzej Warzynski       if (auto arrTy = cpnTy.dyn_cast<fir::SequenceType>()) {
2437dc48849fSKiran Chandramohan         if (i != 1)
2438dc48849fSKiran Chandramohan           TODO(loc, "fir.array nested inside other array and/or derived type");
2439dc48849fSKiran Chandramohan         // Applies byte strides from the box. Ignore lower bound from box
2440dc48849fSKiran Chandramohan         // since fir.coordinate_of indexes are zero based. Lowering takes care
2441dc48849fSKiran Chandramohan         // of lower bound aspects. This both accounts for dynamically sized
2442dc48849fSKiran Chandramohan         // types and non contiguous arrays.
2443dc48849fSKiran Chandramohan         auto idxTy = lowerTy().indexType();
2444dc48849fSKiran Chandramohan         mlir::Value off = genConstantIndex(loc, idxTy, rewriter, 0);
2445dc48849fSKiran Chandramohan         for (unsigned index = i, lastIndex = i + arrTy.getDimension();
2446dc48849fSKiran Chandramohan              index < lastIndex; ++index) {
2447dc48849fSKiran Chandramohan           mlir::Value stride =
2448dc48849fSKiran Chandramohan               loadStrideFromBox(loc, operands[0], index - i, rewriter);
2449dc48849fSKiran Chandramohan           auto sc = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy,
2450dc48849fSKiran Chandramohan                                                        operands[index], stride);
2451dc48849fSKiran Chandramohan           off = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, off);
2452dc48849fSKiran Chandramohan         }
2453dc48849fSKiran Chandramohan         auto voidPtrBase =
2454dc48849fSKiran Chandramohan             rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, resultAddr);
2455575c9d6dSValentin Clement         llvm::SmallVector<mlir::Value> args = {off};
2456dc48849fSKiran Chandramohan         resultAddr = rewriter.create<mlir::LLVM::GEPOp>(loc, voidPtrTy,
2457dc48849fSKiran Chandramohan                                                         voidPtrBase, args);
2458dc48849fSKiran Chandramohan         i += arrTy.getDimension() - 1;
245903efa5a3SAndrzej Warzynski         cpnTy = arrTy.getEleTy();
246003efa5a3SAndrzej Warzynski       } else if (auto recTy = cpnTy.dyn_cast<fir::RecordType>()) {
2461dc48849fSKiran Chandramohan         auto recRefTy =
2462dc48849fSKiran Chandramohan             mlir::LLVM::LLVMPointerType::get(lowerTy().convertType(recTy));
2463dc48849fSKiran Chandramohan         mlir::Value nxtOpnd = operands[i];
2464dc48849fSKiran Chandramohan         auto memObj =
2465dc48849fSKiran Chandramohan             rewriter.create<mlir::LLVM::BitcastOp>(loc, recRefTy, resultAddr);
2466dc48849fSKiran Chandramohan         llvm::SmallVector<mlir::Value> args = {c0, nxtOpnd};
246703efa5a3SAndrzej Warzynski         cpnTy = recTy.getType(getFieldNumber(recTy, nxtOpnd));
246803efa5a3SAndrzej Warzynski         auto llvmCurrentObjTy = lowerTy().convertType(cpnTy);
2469dc48849fSKiran Chandramohan         auto gep = rewriter.create<mlir::LLVM::GEPOp>(
2470dc48849fSKiran Chandramohan             loc, mlir::LLVM::LLVMPointerType::get(llvmCurrentObjTy), memObj,
2471dc48849fSKiran Chandramohan             args);
2472dc48849fSKiran Chandramohan         resultAddr =
2473dc48849fSKiran Chandramohan             rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, gep);
2474dc48849fSKiran Chandramohan       } else {
2475dc48849fSKiran Chandramohan         fir::emitFatalError(loc, "unexpected type in coordinate_of");
2476dc48849fSKiran Chandramohan       }
2477dc48849fSKiran Chandramohan     }
2478dc48849fSKiran Chandramohan 
2479dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(coor, ty, resultAddr);
248044e58509SEric Schweitz     return mlir::success();
2481dc48849fSKiran Chandramohan   }
2482dc48849fSKiran Chandramohan 
2483dc48849fSKiran Chandramohan   mlir::LogicalResult
doRewriteRefOrPtrCoordinateOpConversion2484dc48849fSKiran Chandramohan   doRewriteRefOrPtr(fir::CoordinateOp coor, mlir::Type ty,
2485dc48849fSKiran Chandramohan                     mlir::ValueRange operands, mlir::Location loc,
2486dc48849fSKiran Chandramohan                     mlir::ConversionPatternRewriter &rewriter) const {
2487dc48849fSKiran Chandramohan     mlir::Type baseObjectTy = coor.getBaseType();
2488dc48849fSKiran Chandramohan 
248903efa5a3SAndrzej Warzynski     // Component Type
249003efa5a3SAndrzej Warzynski     mlir::Type cpnTy = fir::dyn_cast_ptrOrBoxEleTy(baseObjectTy);
249103efa5a3SAndrzej Warzynski     bool hasSubdimension = hasSubDimensions(cpnTy);
2492dc48849fSKiran Chandramohan     bool columnIsDeferred = !hasSubdimension;
2493dc48849fSKiran Chandramohan 
249403efa5a3SAndrzej Warzynski     if (!supportedCoordinate(cpnTy, operands.drop_front(1)))
2495dc48849fSKiran Chandramohan       TODO(loc, "unsupported combination of coordinate operands");
2496dc48849fSKiran Chandramohan 
2497dc48849fSKiran Chandramohan     const bool hasKnownShape =
249803efa5a3SAndrzej Warzynski         arraysHaveKnownShape(cpnTy, operands.drop_front(1));
2499dc48849fSKiran Chandramohan 
2500dc48849fSKiran Chandramohan     // If only the column is `?`, then we can simply place the column value in
2501dc48849fSKiran Chandramohan     // the 0-th GEP position.
250203efa5a3SAndrzej Warzynski     if (auto arrTy = cpnTy.dyn_cast<fir::SequenceType>()) {
2503dc48849fSKiran Chandramohan       if (!hasKnownShape) {
2504dc48849fSKiran Chandramohan         const unsigned sz = arrTy.getDimension();
2505dc48849fSKiran Chandramohan         if (arraysHaveKnownShape(arrTy.getEleTy(),
2506dc48849fSKiran Chandramohan                                  operands.drop_front(1 + sz))) {
250703efa5a3SAndrzej Warzynski           fir::SequenceType::ShapeRef shape = arrTy.getShape();
2508dc48849fSKiran Chandramohan           bool allConst = true;
2509dc48849fSKiran Chandramohan           for (unsigned i = 0; i < sz - 1; ++i) {
2510dc48849fSKiran Chandramohan             if (shape[i] < 0) {
2511dc48849fSKiran Chandramohan               allConst = false;
2512dc48849fSKiran Chandramohan               break;
2513dc48849fSKiran Chandramohan             }
2514dc48849fSKiran Chandramohan           }
2515dc48849fSKiran Chandramohan           if (allConst)
2516dc48849fSKiran Chandramohan             columnIsDeferred = true;
2517dc48849fSKiran Chandramohan         }
2518dc48849fSKiran Chandramohan       }
2519dc48849fSKiran Chandramohan     }
2520dc48849fSKiran Chandramohan 
252103efa5a3SAndrzej Warzynski     if (fir::hasDynamicSize(fir::unwrapSequenceType(cpnTy)))
252203efa5a3SAndrzej Warzynski       return mlir::emitError(
2523dc48849fSKiran Chandramohan           loc, "fir.coordinate_of with a dynamic element size is unsupported");
2524dc48849fSKiran Chandramohan 
2525dc48849fSKiran Chandramohan     if (hasKnownShape || columnIsDeferred) {
252644e58509SEric Schweitz       llvm::SmallVector<mlir::Value> offs;
2527dc48849fSKiran Chandramohan       if (hasKnownShape && hasSubdimension) {
2528dc48849fSKiran Chandramohan         mlir::LLVM::ConstantOp c0 =
2529dc48849fSKiran Chandramohan             genConstantIndex(loc, lowerTy().indexType(), rewriter, 0);
2530dc48849fSKiran Chandramohan         offs.push_back(c0);
2531dc48849fSKiran Chandramohan       }
253244e58509SEric Schweitz       llvm::Optional<int> dims;
253344e58509SEric Schweitz       llvm::SmallVector<mlir::Value> arrIdx;
253403efa5a3SAndrzej Warzynski       for (std::size_t i = 1, sz = operands.size(); i < sz; ++i) {
2535dc48849fSKiran Chandramohan         mlir::Value nxtOpnd = operands[i];
2536dc48849fSKiran Chandramohan 
253703efa5a3SAndrzej Warzynski         if (!cpnTy)
253803efa5a3SAndrzej Warzynski           return mlir::emitError(loc, "invalid coordinate/check failed");
2539dc48849fSKiran Chandramohan 
2540dc48849fSKiran Chandramohan         // check if the i-th coordinate relates to an array
25415413bf1bSKazu Hirata         if (dims) {
2542dc48849fSKiran Chandramohan           arrIdx.push_back(nxtOpnd);
2543dc48849fSKiran Chandramohan           int dimsLeft = *dims;
2544dc48849fSKiran Chandramohan           if (dimsLeft > 1) {
2545dc48849fSKiran Chandramohan             dims = dimsLeft - 1;
2546dc48849fSKiran Chandramohan             continue;
2547dc48849fSKiran Chandramohan           }
254803efa5a3SAndrzej Warzynski           cpnTy = cpnTy.cast<fir::SequenceType>().getEleTy();
2549dc48849fSKiran Chandramohan           // append array range in reverse (FIR arrays are column-major)
2550dc48849fSKiran Chandramohan           offs.append(arrIdx.rbegin(), arrIdx.rend());
2551dc48849fSKiran Chandramohan           arrIdx.clear();
2552dc48849fSKiran Chandramohan           dims.reset();
2553dc48849fSKiran Chandramohan           continue;
2554dc48849fSKiran Chandramohan         }
255503efa5a3SAndrzej Warzynski         if (auto arrTy = cpnTy.dyn_cast<fir::SequenceType>()) {
2556dc48849fSKiran Chandramohan           int d = arrTy.getDimension() - 1;
2557dc48849fSKiran Chandramohan           if (d > 0) {
2558dc48849fSKiran Chandramohan             dims = d;
2559dc48849fSKiran Chandramohan             arrIdx.push_back(nxtOpnd);
2560dc48849fSKiran Chandramohan             continue;
2561dc48849fSKiran Chandramohan           }
256203efa5a3SAndrzej Warzynski           cpnTy = cpnTy.cast<fir::SequenceType>().getEleTy();
2563dc48849fSKiran Chandramohan           offs.push_back(nxtOpnd);
2564dc48849fSKiran Chandramohan           continue;
2565dc48849fSKiran Chandramohan         }
2566dc48849fSKiran Chandramohan 
2567dc48849fSKiran Chandramohan         // check if the i-th coordinate relates to a field
256803efa5a3SAndrzej Warzynski         if (auto recTy = cpnTy.dyn_cast<fir::RecordType>())
256903efa5a3SAndrzej Warzynski           cpnTy = recTy.getType(getFieldNumber(recTy, nxtOpnd));
257003efa5a3SAndrzej Warzynski         else if (auto tupTy = cpnTy.dyn_cast<mlir::TupleType>())
2571af40f99eSJean Perier           cpnTy = tupTy.getType(getConstantIntValue(nxtOpnd));
2572dc48849fSKiran Chandramohan         else
257303efa5a3SAndrzej Warzynski           cpnTy = nullptr;
2574dc48849fSKiran Chandramohan 
2575dc48849fSKiran Chandramohan         offs.push_back(nxtOpnd);
2576dc48849fSKiran Chandramohan       }
25775413bf1bSKazu Hirata       if (dims)
2578dc48849fSKiran Chandramohan         offs.append(arrIdx.rbegin(), arrIdx.rend());
2579dc48849fSKiran Chandramohan       mlir::Value base = operands[0];
2580dc48849fSKiran Chandramohan       mlir::Value retval = genGEP(loc, ty, rewriter, base, offs);
2581dc48849fSKiran Chandramohan       rewriter.replaceOp(coor, retval);
258244e58509SEric Schweitz       return mlir::success();
2583dc48849fSKiran Chandramohan     }
2584dc48849fSKiran Chandramohan 
258503efa5a3SAndrzej Warzynski     return mlir::emitError(
258603efa5a3SAndrzej Warzynski         loc, "fir.coordinate_of base operand has unsupported type");
2587dc48849fSKiran Chandramohan   }
2588dc48849fSKiran Chandramohan };
2589dc48849fSKiran Chandramohan 
2590dc48849fSKiran Chandramohan /// Convert `fir.field_index`. The conversion depends on whether the size of
2591dc48849fSKiran Chandramohan /// the record is static or dynamic.
2592dc48849fSKiran Chandramohan struct FieldIndexOpConversion : public FIROpConversion<fir::FieldIndexOp> {
2593dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2594dc48849fSKiran Chandramohan 
2595dc48849fSKiran Chandramohan   // NB: most field references should be resolved by this point
2596dc48849fSKiran Chandramohan   mlir::LogicalResult
matchAndRewriteFieldIndexOpConversion2597dc48849fSKiran Chandramohan   matchAndRewrite(fir::FieldIndexOp field, OpAdaptor adaptor,
2598dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2599dc48849fSKiran Chandramohan     auto recTy = field.getOnType().cast<fir::RecordType>();
2600dc48849fSKiran Chandramohan     unsigned index = recTy.getFieldIndex(field.getFieldId());
2601dc48849fSKiran Chandramohan 
2602dc48849fSKiran Chandramohan     if (!fir::hasDynamicSize(recTy)) {
2603dc48849fSKiran Chandramohan       // Derived type has compile-time constant layout. Return index of the
2604dc48849fSKiran Chandramohan       // component type in the parent type (to be used in GEP).
2605dc48849fSKiran Chandramohan       rewriter.replaceOp(field, mlir::ValueRange{genConstantOffset(
2606dc48849fSKiran Chandramohan                                     field.getLoc(), rewriter, index)});
260744e58509SEric Schweitz       return mlir::success();
2608dc48849fSKiran Chandramohan     }
2609dc48849fSKiran Chandramohan 
2610dc48849fSKiran Chandramohan     // Derived type has compile-time constant layout. Call the compiler
2611dc48849fSKiran Chandramohan     // generated function to determine the byte offset of the field at runtime.
2612dc48849fSKiran Chandramohan     // This returns a non-constant.
261344e58509SEric Schweitz     mlir::FlatSymbolRefAttr symAttr = mlir::SymbolRefAttr::get(
2614dc48849fSKiran Chandramohan         field.getContext(), getOffsetMethodName(recTy, field.getFieldId()));
261544e58509SEric Schweitz     mlir::NamedAttribute callAttr = rewriter.getNamedAttr("callee", symAttr);
261644e58509SEric Schweitz     mlir::NamedAttribute fieldAttr = rewriter.getNamedAttr(
2617dc48849fSKiran Chandramohan         "field", mlir::IntegerAttr::get(lowerTy().indexType(), index));
2618dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
2619dc48849fSKiran Chandramohan         field, lowerTy().offsetType(), adaptor.getOperands(),
2620dc48849fSKiran Chandramohan         llvm::ArrayRef<mlir::NamedAttribute>{callAttr, fieldAttr});
262144e58509SEric Schweitz     return mlir::success();
2622dc48849fSKiran Chandramohan   }
2623dc48849fSKiran Chandramohan 
2624dc48849fSKiran Chandramohan   // Re-Construct the name of the compiler generated method that calculates the
2625dc48849fSKiran Chandramohan   // offset
getOffsetMethodNameFieldIndexOpConversion2626dc48849fSKiran Chandramohan   inline static std::string getOffsetMethodName(fir::RecordType recTy,
2627dc48849fSKiran Chandramohan                                                 llvm::StringRef field) {
2628dc48849fSKiran Chandramohan     return recTy.getName().str() + "P." + field.str() + ".offset";
2629dc48849fSKiran Chandramohan   }
2630dc48849fSKiran Chandramohan };
2631dc48849fSKiran Chandramohan 
2632dc48849fSKiran Chandramohan /// Convert `fir.end`
2633dc48849fSKiran Chandramohan struct FirEndOpConversion : public FIROpConversion<fir::FirEndOp> {
2634dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2635dc48849fSKiran Chandramohan 
2636dc48849fSKiran Chandramohan   mlir::LogicalResult
matchAndRewriteFirEndOpConversion2637dc48849fSKiran Chandramohan   matchAndRewrite(fir::FirEndOp firEnd, OpAdaptor,
2638dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2639dc48849fSKiran Chandramohan     TODO(firEnd.getLoc(), "fir.end codegen");
264044e58509SEric Schweitz     return mlir::failure();
2641dc48849fSKiran Chandramohan   }
2642dc48849fSKiran Chandramohan };
2643dc48849fSKiran Chandramohan 
2644dc48849fSKiran Chandramohan /// Lower `fir.gentypedesc` to a global constant.
2645dc48849fSKiran Chandramohan struct GenTypeDescOpConversion : public FIROpConversion<fir::GenTypeDescOp> {
2646dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2647dc48849fSKiran Chandramohan 
2648dc48849fSKiran Chandramohan   mlir::LogicalResult
matchAndRewriteGenTypeDescOpConversion2649dc48849fSKiran Chandramohan   matchAndRewrite(fir::GenTypeDescOp gentypedesc, OpAdaptor adaptor,
2650dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2651dc48849fSKiran Chandramohan     TODO(gentypedesc.getLoc(), "fir.gentypedesc codegen");
265244e58509SEric Schweitz     return mlir::failure();
2653dc48849fSKiran Chandramohan   }
2654dc48849fSKiran Chandramohan };
2655dc48849fSKiran Chandramohan 
2656dc48849fSKiran Chandramohan /// Lower `fir.has_value` operation to `llvm.return` operation.
2657dc48849fSKiran Chandramohan struct HasValueOpConversion : public FIROpConversion<fir::HasValueOp> {
2658dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2659dc48849fSKiran Chandramohan 
2660dc48849fSKiran Chandramohan   mlir::LogicalResult
matchAndRewriteHasValueOpConversion2661dc48849fSKiran Chandramohan   matchAndRewrite(fir::HasValueOp op, OpAdaptor adaptor,
2662dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
266344e58509SEric Schweitz     rewriter.replaceOpWithNewOp<mlir::LLVM::ReturnOp>(op,
266444e58509SEric Schweitz                                                       adaptor.getOperands());
266544e58509SEric Schweitz     return mlir::success();
2666dc48849fSKiran Chandramohan   }
2667dc48849fSKiran Chandramohan };
2668dc48849fSKiran Chandramohan 
2669dc48849fSKiran Chandramohan /// Lower `fir.global` operation to `llvm.global` operation.
2670dc48849fSKiran Chandramohan /// `fir.insert_on_range` operations are replaced with constant dense attribute
2671dc48849fSKiran Chandramohan /// if they are applied on the full range.
2672dc48849fSKiran Chandramohan struct GlobalOpConversion : public FIROpConversion<fir::GlobalOp> {
2673dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2674dc48849fSKiran Chandramohan 
2675dc48849fSKiran Chandramohan   mlir::LogicalResult
matchAndRewriteGlobalOpConversion2676dc48849fSKiran Chandramohan   matchAndRewrite(fir::GlobalOp global, OpAdaptor adaptor,
2677dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2678dc48849fSKiran Chandramohan     auto tyAttr = convertType(global.getType());
2679dc48849fSKiran Chandramohan     if (global.getType().isa<fir::BoxType>())
2680dc48849fSKiran Chandramohan       tyAttr = tyAttr.cast<mlir::LLVM::LLVMPointerType>().getElementType();
2681dc48849fSKiran Chandramohan     auto loc = global.getLoc();
2682*c715e2ffSKazu Hirata     mlir::Attribute initAttr = global.getInitVal().value_or(mlir::Attribute());
2683dc48849fSKiran Chandramohan     auto linkage = convertLinkage(global.getLinkName());
2684c82fb16fSKazu Hirata     auto isConst = global.getConstant().has_value();
2685dc48849fSKiran Chandramohan     auto g = rewriter.create<mlir::LLVM::GlobalOp>(
2686dc48849fSKiran Chandramohan         loc, tyAttr, isConst, linkage, global.getSymName(), initAttr);
2687dc48849fSKiran Chandramohan     auto &gr = g.getInitializerRegion();
2688dc48849fSKiran Chandramohan     rewriter.inlineRegionBefore(global.getRegion(), gr, gr.end());
2689dc48849fSKiran Chandramohan     if (!gr.empty()) {
2690dc48849fSKiran Chandramohan       // Replace insert_on_range with a constant dense attribute if the
2691dc48849fSKiran Chandramohan       // initialization is on the full range.
2692dc48849fSKiran Chandramohan       auto insertOnRangeOps = gr.front().getOps<fir::InsertOnRangeOp>();
2693dc48849fSKiran Chandramohan       for (auto insertOp : insertOnRangeOps) {
2694dc48849fSKiran Chandramohan         if (isFullRange(insertOp.getCoor(), insertOp.getType())) {
2695dc48849fSKiran Chandramohan           auto seqTyAttr = convertType(insertOp.getType());
2696dc48849fSKiran Chandramohan           auto *op = insertOp.getVal().getDefiningOp();
2697dc48849fSKiran Chandramohan           auto constant = mlir::dyn_cast<mlir::arith::ConstantOp>(op);
2698dc48849fSKiran Chandramohan           if (!constant) {
2699dc48849fSKiran Chandramohan             auto convertOp = mlir::dyn_cast<fir::ConvertOp>(op);
2700dc48849fSKiran Chandramohan             if (!convertOp)
2701dc48849fSKiran Chandramohan               continue;
270244e58509SEric Schweitz             constant = mlir::cast<mlir::arith::ConstantOp>(
2703dc48849fSKiran Chandramohan                 convertOp.getValue().getDefiningOp());
2704dc48849fSKiran Chandramohan           }
2705dc48849fSKiran Chandramohan           mlir::Type vecType = mlir::VectorType::get(
2706dc48849fSKiran Chandramohan               insertOp.getType().getShape(), constant.getType());
2707dc48849fSKiran Chandramohan           auto denseAttr = mlir::DenseElementsAttr::get(
270844e58509SEric Schweitz               vecType.cast<mlir::ShapedType>(), constant.getValue());
2709dc48849fSKiran Chandramohan           rewriter.setInsertionPointAfter(insertOp);
2710dc48849fSKiran Chandramohan           rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(
2711dc48849fSKiran Chandramohan               insertOp, seqTyAttr, denseAttr);
2712dc48849fSKiran Chandramohan         }
2713dc48849fSKiran Chandramohan       }
2714dc48849fSKiran Chandramohan     }
2715dc48849fSKiran Chandramohan     rewriter.eraseOp(global);
271644e58509SEric Schweitz     return mlir::success();
2717dc48849fSKiran Chandramohan   }
2718dc48849fSKiran Chandramohan 
isFullRangeGlobalOpConversion2719dc48849fSKiran Chandramohan   bool isFullRange(mlir::DenseIntElementsAttr indexes,
2720dc48849fSKiran Chandramohan                    fir::SequenceType seqTy) const {
2721dc48849fSKiran Chandramohan     auto extents = seqTy.getShape();
2722dc48849fSKiran Chandramohan     if (indexes.size() / 2 != static_cast<int64_t>(extents.size()))
2723dc48849fSKiran Chandramohan       return false;
2724dc48849fSKiran Chandramohan     auto cur_index = indexes.value_begin<int64_t>();
2725dc48849fSKiran Chandramohan     for (unsigned i = 0; i < indexes.size(); i += 2) {
2726dc48849fSKiran Chandramohan       if (*(cur_index++) != 0)
2727dc48849fSKiran Chandramohan         return false;
2728dc48849fSKiran Chandramohan       if (*(cur_index++) != extents[i / 2] - 1)
2729dc48849fSKiran Chandramohan         return false;
2730dc48849fSKiran Chandramohan     }
2731dc48849fSKiran Chandramohan     return true;
2732dc48849fSKiran Chandramohan   }
2733dc48849fSKiran Chandramohan 
2734dc48849fSKiran Chandramohan   // TODO: String comparaison should be avoided. Replace linkName with an
2735dc48849fSKiran Chandramohan   // enumeration.
273644e58509SEric Schweitz   mlir::LLVM::Linkage
convertLinkageGlobalOpConversion273744e58509SEric Schweitz   convertLinkage(llvm::Optional<llvm::StringRef> optLinkage) const {
273886b8c1d9SKazu Hirata     if (optLinkage) {
2739009ab172SKazu Hirata       auto name = *optLinkage;
2740dc48849fSKiran Chandramohan       if (name == "internal")
2741dc48849fSKiran Chandramohan         return mlir::LLVM::Linkage::Internal;
2742dc48849fSKiran Chandramohan       if (name == "linkonce")
2743dc48849fSKiran Chandramohan         return mlir::LLVM::Linkage::Linkonce;
274430a0fbf5SJean Perier       if (name == "linkonce_odr")
274530a0fbf5SJean Perier         return mlir::LLVM::Linkage::LinkonceODR;
2746dc48849fSKiran Chandramohan       if (name == "common")
2747dc48849fSKiran Chandramohan         return mlir::LLVM::Linkage::Common;
2748dc48849fSKiran Chandramohan       if (name == "weak")
2749dc48849fSKiran Chandramohan         return mlir::LLVM::Linkage::Weak;
2750dc48849fSKiran Chandramohan     }
2751dc48849fSKiran Chandramohan     return mlir::LLVM::Linkage::External;
2752dc48849fSKiran Chandramohan   }
2753dc48849fSKiran Chandramohan };
2754dc48849fSKiran Chandramohan 
2755dc48849fSKiran Chandramohan /// `fir.load` --> `llvm.load`
2756dc48849fSKiran Chandramohan struct LoadOpConversion : public FIROpConversion<fir::LoadOp> {
2757dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2758dc48849fSKiran Chandramohan 
2759dc48849fSKiran Chandramohan   mlir::LogicalResult
matchAndRewriteLoadOpConversion2760dc48849fSKiran Chandramohan   matchAndRewrite(fir::LoadOp load, OpAdaptor adaptor,
2761dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2762dc48849fSKiran Chandramohan     // fir.box is a special case because it is considered as an ssa values in
2763dc48849fSKiran Chandramohan     // fir, but it is lowered as a pointer to a descriptor. So fir.ref<fir.box>
2764dc48849fSKiran Chandramohan     // and fir.box end up being the same llvm types and loading a
2765dc48849fSKiran Chandramohan     // fir.ref<fir.box> is actually a no op in LLVM.
2766dc48849fSKiran Chandramohan     if (load.getType().isa<fir::BoxType>()) {
2767dc48849fSKiran Chandramohan       rewriter.replaceOp(load, adaptor.getOperands()[0]);
2768dc48849fSKiran Chandramohan     } else {
2769dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::LoadOp>(
277044e58509SEric Schweitz           load, convertType(load.getType()), adaptor.getOperands(),
277144e58509SEric Schweitz           load->getAttrs());
2772dc48849fSKiran Chandramohan     }
277344e58509SEric Schweitz     return mlir::success();
2774dc48849fSKiran Chandramohan   }
2775dc48849fSKiran Chandramohan };
2776dc48849fSKiran Chandramohan 
2777dc48849fSKiran Chandramohan /// Lower `fir.no_reassoc` to LLVM IR dialect.
2778dc48849fSKiran Chandramohan /// TODO: how do we want to enforce this in LLVM-IR? Can we manipulate the fast
2779dc48849fSKiran Chandramohan /// math flags?
2780dc48849fSKiran Chandramohan struct NoReassocOpConversion : public FIROpConversion<fir::NoReassocOp> {
2781dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2782dc48849fSKiran Chandramohan 
2783dc48849fSKiran Chandramohan   mlir::LogicalResult
matchAndRewriteNoReassocOpConversion2784dc48849fSKiran Chandramohan   matchAndRewrite(fir::NoReassocOp noreassoc, OpAdaptor adaptor,
2785dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2786dc48849fSKiran Chandramohan     rewriter.replaceOp(noreassoc, adaptor.getOperands()[0]);
278744e58509SEric Schweitz     return mlir::success();
2788dc48849fSKiran Chandramohan   }
2789dc48849fSKiran Chandramohan };
2790dc48849fSKiran Chandramohan 
genCondBrOp(mlir::Location loc,mlir::Value cmp,mlir::Block * dest,llvm::Optional<mlir::ValueRange> destOps,mlir::ConversionPatternRewriter & rewriter,mlir::Block * newBlock)2791dc48849fSKiran Chandramohan static void genCondBrOp(mlir::Location loc, mlir::Value cmp, mlir::Block *dest,
279244e58509SEric Schweitz                         llvm::Optional<mlir::ValueRange> destOps,
2793dc48849fSKiran Chandramohan                         mlir::ConversionPatternRewriter &rewriter,
2794dc48849fSKiran Chandramohan                         mlir::Block *newBlock) {
279586b8c1d9SKazu Hirata   if (destOps)
2796009ab172SKazu Hirata     rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, *destOps, newBlock,
2797009ab172SKazu Hirata                                           mlir::ValueRange());
2798dc48849fSKiran Chandramohan   else
2799dc48849fSKiran Chandramohan     rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, newBlock);
2800dc48849fSKiran Chandramohan }
2801dc48849fSKiran Chandramohan 
2802dc48849fSKiran Chandramohan template <typename A, typename B>
genBrOp(A caseOp,mlir::Block * dest,llvm::Optional<B> destOps,mlir::ConversionPatternRewriter & rewriter)280344e58509SEric Schweitz static void genBrOp(A caseOp, mlir::Block *dest, llvm::Optional<B> destOps,
2804dc48849fSKiran Chandramohan                     mlir::ConversionPatternRewriter &rewriter) {
280586b8c1d9SKazu Hirata   if (destOps)
2806009ab172SKazu Hirata     rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, *destOps, dest);
2807dc48849fSKiran Chandramohan   else
2808dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, llvm::None, dest);
2809dc48849fSKiran Chandramohan }
2810dc48849fSKiran Chandramohan 
genCaseLadderStep(mlir::Location loc,mlir::Value cmp,mlir::Block * dest,llvm::Optional<mlir::ValueRange> destOps,mlir::ConversionPatternRewriter & rewriter)2811dc48849fSKiran Chandramohan static void genCaseLadderStep(mlir::Location loc, mlir::Value cmp,
2812dc48849fSKiran Chandramohan                               mlir::Block *dest,
281344e58509SEric Schweitz                               llvm::Optional<mlir::ValueRange> destOps,
2814dc48849fSKiran Chandramohan                               mlir::ConversionPatternRewriter &rewriter) {
2815dc48849fSKiran Chandramohan   auto *thisBlock = rewriter.getInsertionBlock();
2816dc48849fSKiran Chandramohan   auto *newBlock = createBlock(rewriter, dest);
2817dc48849fSKiran Chandramohan   rewriter.setInsertionPointToEnd(thisBlock);
2818dc48849fSKiran Chandramohan   genCondBrOp(loc, cmp, dest, destOps, rewriter, newBlock);
2819dc48849fSKiran Chandramohan   rewriter.setInsertionPointToEnd(newBlock);
2820dc48849fSKiran Chandramohan }
2821dc48849fSKiran Chandramohan 
2822dc48849fSKiran Chandramohan /// Conversion of `fir.select_case`
2823dc48849fSKiran Chandramohan ///
2824dc48849fSKiran Chandramohan /// The `fir.select_case` operation is converted to a if-then-else ladder.
2825dc48849fSKiran Chandramohan /// Depending on the case condition type, one or several comparison and
2826dc48849fSKiran Chandramohan /// conditional branching can be generated.
2827dc48849fSKiran Chandramohan ///
2828dc48849fSKiran Chandramohan /// A a point value case such as `case(4)`, a lower bound case such as
2829dc48849fSKiran Chandramohan /// `case(5:)` or an upper bound case such as `case(:3)` are converted to a
2830dc48849fSKiran Chandramohan /// simple comparison between the selector value and the constant value in the
2831dc48849fSKiran Chandramohan /// case. The block associated with the case condition is then executed if
2832dc48849fSKiran Chandramohan /// the comparison succeed otherwise it branch to the next block with the
2833dc48849fSKiran Chandramohan /// comparison for the the next case conditon.
2834dc48849fSKiran Chandramohan ///
2835dc48849fSKiran Chandramohan /// A closed interval case condition such as `case(7:10)` is converted with a
2836dc48849fSKiran Chandramohan /// first comparison and conditional branching for the lower bound. If
2837dc48849fSKiran Chandramohan /// successful, it branch to a second block with the comparison for the
2838dc48849fSKiran Chandramohan /// upper bound in the same case condition.
2839dc48849fSKiran Chandramohan ///
2840dc48849fSKiran Chandramohan /// TODO: lowering of CHARACTER type cases is not handled yet.
2841dc48849fSKiran Chandramohan struct SelectCaseOpConversion : public FIROpConversion<fir::SelectCaseOp> {
2842dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2843dc48849fSKiran Chandramohan 
2844dc48849fSKiran Chandramohan   mlir::LogicalResult
matchAndRewriteSelectCaseOpConversion2845dc48849fSKiran Chandramohan   matchAndRewrite(fir::SelectCaseOp caseOp, OpAdaptor adaptor,
2846dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2847dc48849fSKiran Chandramohan     unsigned conds = caseOp.getNumConditions();
2848dc48849fSKiran Chandramohan     llvm::ArrayRef<mlir::Attribute> cases = caseOp.getCases().getValue();
2849dc48849fSKiran Chandramohan     // Type can be CHARACTER, INTEGER, or LOGICAL (C1145)
2850dc48849fSKiran Chandramohan     auto ty = caseOp.getSelector().getType();
2851dc48849fSKiran Chandramohan     if (ty.isa<fir::CharacterType>()) {
2852dc48849fSKiran Chandramohan       TODO(caseOp.getLoc(), "fir.select_case codegen with character type");
285344e58509SEric Schweitz       return mlir::failure();
2854dc48849fSKiran Chandramohan     }
2855dc48849fSKiran Chandramohan     mlir::Value selector = caseOp.getSelector(adaptor.getOperands());
2856dc48849fSKiran Chandramohan     auto loc = caseOp.getLoc();
2857dc48849fSKiran Chandramohan     for (unsigned t = 0; t != conds; ++t) {
2858dc48849fSKiran Chandramohan       mlir::Block *dest = caseOp.getSuccessor(t);
2859dc48849fSKiran Chandramohan       llvm::Optional<mlir::ValueRange> destOps =
2860dc48849fSKiran Chandramohan           caseOp.getSuccessorOperands(adaptor.getOperands(), t);
2861dc48849fSKiran Chandramohan       llvm::Optional<mlir::ValueRange> cmpOps =
2862dc48849fSKiran Chandramohan           *caseOp.getCompareOperands(adaptor.getOperands(), t);
2863dc97886fSKazu Hirata       mlir::Value caseArg = *(cmpOps.value().begin());
2864dc48849fSKiran Chandramohan       mlir::Attribute attr = cases[t];
2865dc48849fSKiran Chandramohan       if (attr.isa<fir::PointIntervalAttr>()) {
2866dc48849fSKiran Chandramohan         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
2867dc48849fSKiran Chandramohan             loc, mlir::LLVM::ICmpPredicate::eq, selector, caseArg);
2868dc48849fSKiran Chandramohan         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
2869dc48849fSKiran Chandramohan         continue;
2870dc48849fSKiran Chandramohan       }
2871dc48849fSKiran Chandramohan       if (attr.isa<fir::LowerBoundAttr>()) {
2872dc48849fSKiran Chandramohan         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
2873dc48849fSKiran Chandramohan             loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector);
2874dc48849fSKiran Chandramohan         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
2875dc48849fSKiran Chandramohan         continue;
2876dc48849fSKiran Chandramohan       }
2877dc48849fSKiran Chandramohan       if (attr.isa<fir::UpperBoundAttr>()) {
2878dc48849fSKiran Chandramohan         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
2879dc48849fSKiran Chandramohan             loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg);
2880dc48849fSKiran Chandramohan         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
2881dc48849fSKiran Chandramohan         continue;
2882dc48849fSKiran Chandramohan       }
2883dc48849fSKiran Chandramohan       if (attr.isa<fir::ClosedIntervalAttr>()) {
2884dc48849fSKiran Chandramohan         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
2885dc48849fSKiran Chandramohan             loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector);
2886dc48849fSKiran Chandramohan         auto *thisBlock = rewriter.getInsertionBlock();
2887dc48849fSKiran Chandramohan         auto *newBlock1 = createBlock(rewriter, dest);
2888dc48849fSKiran Chandramohan         auto *newBlock2 = createBlock(rewriter, dest);
2889dc48849fSKiran Chandramohan         rewriter.setInsertionPointToEnd(thisBlock);
2890dc48849fSKiran Chandramohan         rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, newBlock1, newBlock2);
2891dc48849fSKiran Chandramohan         rewriter.setInsertionPointToEnd(newBlock1);
2892dc97886fSKazu Hirata         mlir::Value caseArg0 = *(cmpOps.value().begin() + 1);
2893dc48849fSKiran Chandramohan         auto cmp0 = rewriter.create<mlir::LLVM::ICmpOp>(
2894dc48849fSKiran Chandramohan             loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg0);
2895dc48849fSKiran Chandramohan         genCondBrOp(loc, cmp0, dest, destOps, rewriter, newBlock2);
2896dc48849fSKiran Chandramohan         rewriter.setInsertionPointToEnd(newBlock2);
2897dc48849fSKiran Chandramohan         continue;
2898dc48849fSKiran Chandramohan       }
2899dc48849fSKiran Chandramohan       assert(attr.isa<mlir::UnitAttr>());
2900dc48849fSKiran Chandramohan       assert((t + 1 == conds) && "unit must be last");
2901dc48849fSKiran Chandramohan       genBrOp(caseOp, dest, destOps, rewriter);
2902dc48849fSKiran Chandramohan     }
290344e58509SEric Schweitz     return mlir::success();
2904dc48849fSKiran Chandramohan   }
2905dc48849fSKiran Chandramohan };
2906dc48849fSKiran Chandramohan 
2907dc48849fSKiran Chandramohan template <typename OP>
selectMatchAndRewrite(fir::LLVMTypeConverter & lowering,OP select,typename OP::Adaptor adaptor,mlir::ConversionPatternRewriter & rewriter)2908dc48849fSKiran Chandramohan static void selectMatchAndRewrite(fir::LLVMTypeConverter &lowering, OP select,
2909dc48849fSKiran Chandramohan                                   typename OP::Adaptor adaptor,
2910dc48849fSKiran Chandramohan                                   mlir::ConversionPatternRewriter &rewriter) {
2911dc48849fSKiran Chandramohan   unsigned conds = select.getNumConditions();
2912dc48849fSKiran Chandramohan   auto cases = select.getCases().getValue();
2913dc48849fSKiran Chandramohan   mlir::Value selector = adaptor.getSelector();
2914dc48849fSKiran Chandramohan   auto loc = select.getLoc();
2915dc48849fSKiran Chandramohan   assert(conds > 0 && "select must have cases");
2916dc48849fSKiran Chandramohan 
2917dc48849fSKiran Chandramohan   llvm::SmallVector<mlir::Block *> destinations;
2918dc48849fSKiran Chandramohan   llvm::SmallVector<mlir::ValueRange> destinationsOperands;
2919dc48849fSKiran Chandramohan   mlir::Block *defaultDestination;
2920dc48849fSKiran Chandramohan   mlir::ValueRange defaultOperands;
2921dc48849fSKiran Chandramohan   llvm::SmallVector<int32_t> caseValues;
2922dc48849fSKiran Chandramohan 
2923dc48849fSKiran Chandramohan   for (unsigned t = 0; t != conds; ++t) {
2924dc48849fSKiran Chandramohan     mlir::Block *dest = select.getSuccessor(t);
2925dc48849fSKiran Chandramohan     auto destOps = select.getSuccessorOperands(adaptor.getOperands(), t);
2926dc48849fSKiran Chandramohan     const mlir::Attribute &attr = cases[t];
2927dc48849fSKiran Chandramohan     if (auto intAttr = attr.template dyn_cast<mlir::IntegerAttr>()) {
2928dc48849fSKiran Chandramohan       destinations.push_back(dest);
292986b8c1d9SKazu Hirata       destinationsOperands.push_back(destOps ? *destOps : mlir::ValueRange{});
2930dc48849fSKiran Chandramohan       caseValues.push_back(intAttr.getInt());
2931dc48849fSKiran Chandramohan       continue;
2932dc48849fSKiran Chandramohan     }
2933dc48849fSKiran Chandramohan     assert(attr.template dyn_cast_or_null<mlir::UnitAttr>());
2934dc48849fSKiran Chandramohan     assert((t + 1 == conds) && "unit must be last");
2935dc48849fSKiran Chandramohan     defaultDestination = dest;
293686b8c1d9SKazu Hirata     defaultOperands = destOps ? *destOps : mlir::ValueRange{};
2937dc48849fSKiran Chandramohan   }
2938dc48849fSKiran Chandramohan 
2939dc48849fSKiran Chandramohan   // LLVM::SwitchOp takes a i32 type for the selector.
2940dc48849fSKiran Chandramohan   if (select.getSelector().getType() != rewriter.getI32Type())
294144e58509SEric Schweitz     selector = rewriter.create<mlir::LLVM::TruncOp>(loc, rewriter.getI32Type(),
294244e58509SEric Schweitz                                                     selector);
2943dc48849fSKiran Chandramohan 
2944dc48849fSKiran Chandramohan   rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>(
2945dc48849fSKiran Chandramohan       select, selector,
2946dc48849fSKiran Chandramohan       /*defaultDestination=*/defaultDestination,
2947dc48849fSKiran Chandramohan       /*defaultOperands=*/defaultOperands,
2948dc48849fSKiran Chandramohan       /*caseValues=*/caseValues,
2949dc48849fSKiran Chandramohan       /*caseDestinations=*/destinations,
2950dc48849fSKiran Chandramohan       /*caseOperands=*/destinationsOperands,
295144e58509SEric Schweitz       /*branchWeights=*/llvm::ArrayRef<std::int32_t>());
2952dc48849fSKiran Chandramohan }
2953dc48849fSKiran Chandramohan 
2954dc48849fSKiran Chandramohan /// conversion of fir::SelectOp to an if-then-else ladder
2955dc48849fSKiran Chandramohan struct SelectOpConversion : public FIROpConversion<fir::SelectOp> {
2956dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2957dc48849fSKiran Chandramohan 
2958dc48849fSKiran Chandramohan   mlir::LogicalResult
matchAndRewriteSelectOpConversion2959dc48849fSKiran Chandramohan   matchAndRewrite(fir::SelectOp op, OpAdaptor adaptor,
2960dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2961dc48849fSKiran Chandramohan     selectMatchAndRewrite<fir::SelectOp>(lowerTy(), op, adaptor, rewriter);
296244e58509SEric Schweitz     return mlir::success();
2963dc48849fSKiran Chandramohan   }
2964dc48849fSKiran Chandramohan };
2965dc48849fSKiran Chandramohan 
2966dc48849fSKiran Chandramohan /// conversion of fir::SelectRankOp to an if-then-else ladder
2967dc48849fSKiran Chandramohan struct SelectRankOpConversion : public FIROpConversion<fir::SelectRankOp> {
2968dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2969dc48849fSKiran Chandramohan 
2970dc48849fSKiran Chandramohan   mlir::LogicalResult
matchAndRewriteSelectRankOpConversion2971dc48849fSKiran Chandramohan   matchAndRewrite(fir::SelectRankOp op, OpAdaptor adaptor,
2972dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2973dc48849fSKiran Chandramohan     selectMatchAndRewrite<fir::SelectRankOp>(lowerTy(), op, adaptor, rewriter);
297444e58509SEric Schweitz     return mlir::success();
2975dc48849fSKiran Chandramohan   }
2976dc48849fSKiran Chandramohan };
2977dc48849fSKiran Chandramohan 
2978dc48849fSKiran Chandramohan /// Lower `fir.select_type` to LLVM IR dialect.
2979dc48849fSKiran Chandramohan struct SelectTypeOpConversion : public FIROpConversion<fir::SelectTypeOp> {
2980dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2981dc48849fSKiran Chandramohan 
2982dc48849fSKiran Chandramohan   mlir::LogicalResult
matchAndRewriteSelectTypeOpConversion2983dc48849fSKiran Chandramohan   matchAndRewrite(fir::SelectTypeOp select, OpAdaptor adaptor,
2984dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2985dc48849fSKiran Chandramohan     mlir::emitError(select.getLoc(),
2986dc48849fSKiran Chandramohan                     "fir.select_type should have already been converted");
298744e58509SEric Schweitz     return mlir::failure();
2988dc48849fSKiran Chandramohan   }
2989dc48849fSKiran Chandramohan };
2990dc48849fSKiran Chandramohan 
2991dc48849fSKiran Chandramohan /// `fir.store` --> `llvm.store`
2992dc48849fSKiran Chandramohan struct StoreOpConversion : public FIROpConversion<fir::StoreOp> {
2993dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2994dc48849fSKiran Chandramohan 
2995dc48849fSKiran Chandramohan   mlir::LogicalResult
matchAndRewriteStoreOpConversion2996dc48849fSKiran Chandramohan   matchAndRewrite(fir::StoreOp store, OpAdaptor adaptor,
2997dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2998dc48849fSKiran Chandramohan     if (store.getValue().getType().isa<fir::BoxType>()) {
2999dc48849fSKiran Chandramohan       // fir.box value is actually in memory, load it first before storing it.
3000dc48849fSKiran Chandramohan       mlir::Location loc = store.getLoc();
3001dc48849fSKiran Chandramohan       mlir::Type boxPtrTy = adaptor.getOperands()[0].getType();
3002dc48849fSKiran Chandramohan       auto val = rewriter.create<mlir::LLVM::LoadOp>(
3003dc48849fSKiran Chandramohan           loc, boxPtrTy.cast<mlir::LLVM::LLVMPointerType>().getElementType(),
3004dc48849fSKiran Chandramohan           adaptor.getOperands()[0]);
3005dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
3006dc48849fSKiran Chandramohan           store, val, adaptor.getOperands()[1]);
3007dc48849fSKiran Chandramohan     } else {
3008dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
3009dc48849fSKiran Chandramohan           store, adaptor.getOperands()[0], adaptor.getOperands()[1]);
3010dc48849fSKiran Chandramohan     }
301144e58509SEric Schweitz     return mlir::success();
3012dc48849fSKiran Chandramohan   }
3013dc48849fSKiran Chandramohan };
3014dc48849fSKiran Chandramohan 
3015dc48849fSKiran Chandramohan namespace {
3016dc48849fSKiran Chandramohan 
3017dc48849fSKiran Chandramohan /// Convert `fir.unboxchar` into two `llvm.extractvalue` instructions. One for
3018dc48849fSKiran Chandramohan /// the character buffer and one for the buffer length.
3019dc48849fSKiran Chandramohan struct UnboxCharOpConversion : public FIROpConversion<fir::UnboxCharOp> {
3020dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3021dc48849fSKiran Chandramohan 
3022dc48849fSKiran Chandramohan   mlir::LogicalResult
matchAndRewrite__anon447c3e181111::UnboxCharOpConversion3023dc48849fSKiran Chandramohan   matchAndRewrite(fir::UnboxCharOp unboxchar, OpAdaptor adaptor,
3024dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
302544e58509SEric Schweitz     auto *ctx = unboxchar.getContext();
3026dc48849fSKiran Chandramohan 
3027dc48849fSKiran Chandramohan     mlir::Type lenTy = convertType(unboxchar.getType(1));
3028dc48849fSKiran Chandramohan     mlir::Value tuple = adaptor.getOperands()[0];
3029dc48849fSKiran Chandramohan     mlir::Type tupleTy = tuple.getType();
3030dc48849fSKiran Chandramohan 
3031dc48849fSKiran Chandramohan     mlir::Location loc = unboxchar.getLoc();
3032dc48849fSKiran Chandramohan     mlir::Value ptrToBuffer =
3033dc48849fSKiran Chandramohan         genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 0);
3034dc48849fSKiran Chandramohan 
3035dc48849fSKiran Chandramohan     mlir::LLVM::ExtractValueOp len =
3036dc48849fSKiran Chandramohan         genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 1);
3037dc48849fSKiran Chandramohan     mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, len);
3038dc48849fSKiran Chandramohan 
3039dc48849fSKiran Chandramohan     rewriter.replaceOp(unboxchar,
304044e58509SEric Schweitz                        llvm::ArrayRef<mlir::Value>{ptrToBuffer, lenAfterCast});
304144e58509SEric Schweitz     return mlir::success();
3042dc48849fSKiran Chandramohan   }
3043dc48849fSKiran Chandramohan };
3044dc48849fSKiran Chandramohan 
3045dc48849fSKiran Chandramohan /// Lower `fir.unboxproc` operation. Unbox a procedure box value, yielding its
3046dc48849fSKiran Chandramohan /// components.
3047dc48849fSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
3048dc48849fSKiran Chandramohan struct UnboxProcOpConversion : public FIROpConversion<fir::UnboxProcOp> {
3049dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3050dc48849fSKiran Chandramohan 
3051dc48849fSKiran Chandramohan   mlir::LogicalResult
matchAndRewrite__anon447c3e181111::UnboxProcOpConversion3052dc48849fSKiran Chandramohan   matchAndRewrite(fir::UnboxProcOp unboxproc, OpAdaptor adaptor,
3053dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3054dc48849fSKiran Chandramohan     TODO(unboxproc.getLoc(), "fir.unboxproc codegen");
305544e58509SEric Schweitz     return mlir::failure();
3056dc48849fSKiran Chandramohan   }
3057dc48849fSKiran Chandramohan };
3058dc48849fSKiran Chandramohan 
3059dc48849fSKiran Chandramohan /// convert to LLVM IR dialect `undef`
3060dc48849fSKiran Chandramohan struct UndefOpConversion : public FIROpConversion<fir::UndefOp> {
3061dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3062dc48849fSKiran Chandramohan 
3063dc48849fSKiran Chandramohan   mlir::LogicalResult
matchAndRewrite__anon447c3e181111::UndefOpConversion3064dc48849fSKiran Chandramohan   matchAndRewrite(fir::UndefOp undef, OpAdaptor,
3065dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3066dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::UndefOp>(
3067dc48849fSKiran Chandramohan         undef, convertType(undef.getType()));
306844e58509SEric Schweitz     return mlir::success();
3069dc48849fSKiran Chandramohan   }
3070dc48849fSKiran Chandramohan };
3071dc48849fSKiran Chandramohan 
3072dc48849fSKiran Chandramohan struct ZeroOpConversion : public FIROpConversion<fir::ZeroOp> {
3073dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3074dc48849fSKiran Chandramohan 
3075dc48849fSKiran Chandramohan   mlir::LogicalResult
matchAndRewrite__anon447c3e181111::ZeroOpConversion3076dc48849fSKiran Chandramohan   matchAndRewrite(fir::ZeroOp zero, OpAdaptor,
3077dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3078dc48849fSKiran Chandramohan     mlir::Type ty = convertType(zero.getType());
3079dc48849fSKiran Chandramohan     if (ty.isa<mlir::LLVM::LLVMPointerType>()) {
3080dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(zero, ty);
3081dc48849fSKiran Chandramohan     } else if (ty.isa<mlir::IntegerType>()) {
3082dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
3083dc48849fSKiran Chandramohan           zero, ty, mlir::IntegerAttr::get(zero.getType(), 0));
3084dc48849fSKiran Chandramohan     } else if (mlir::LLVM::isCompatibleFloatingPointType(ty)) {
3085dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
3086dc48849fSKiran Chandramohan           zero, ty, mlir::FloatAttr::get(zero.getType(), 0.0));
3087dc48849fSKiran Chandramohan     } else {
3088dc48849fSKiran Chandramohan       // TODO: create ConstantAggregateZero for FIR aggregate/array types.
3089dc48849fSKiran Chandramohan       return rewriter.notifyMatchFailure(
3090dc48849fSKiran Chandramohan           zero,
3091dc48849fSKiran Chandramohan           "conversion of fir.zero with aggregate type not implemented yet");
3092dc48849fSKiran Chandramohan     }
309344e58509SEric Schweitz     return mlir::success();
3094dc48849fSKiran Chandramohan   }
3095dc48849fSKiran Chandramohan };
3096dc48849fSKiran Chandramohan 
3097dc48849fSKiran Chandramohan /// `fir.unreachable` --> `llvm.unreachable`
3098dc48849fSKiran Chandramohan struct UnreachableOpConversion : public FIROpConversion<fir::UnreachableOp> {
3099dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3100dc48849fSKiran Chandramohan 
3101dc48849fSKiran Chandramohan   mlir::LogicalResult
matchAndRewrite__anon447c3e181111::UnreachableOpConversion3102dc48849fSKiran Chandramohan   matchAndRewrite(fir::UnreachableOp unreach, OpAdaptor adaptor,
3103dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3104dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(unreach);
310544e58509SEric Schweitz     return mlir::success();
3106dc48849fSKiran Chandramohan   }
3107dc48849fSKiran Chandramohan };
3108dc48849fSKiran Chandramohan 
3109dc48849fSKiran Chandramohan /// `fir.is_present` -->
3110dc48849fSKiran Chandramohan /// ```
3111dc48849fSKiran Chandramohan ///  %0 = llvm.mlir.constant(0 : i64)
3112dc48849fSKiran Chandramohan ///  %1 = llvm.ptrtoint %0
3113dc48849fSKiran Chandramohan ///  %2 = llvm.icmp "ne" %1, %0 : i64
3114dc48849fSKiran Chandramohan /// ```
3115dc48849fSKiran Chandramohan struct IsPresentOpConversion : public FIROpConversion<fir::IsPresentOp> {
3116dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3117dc48849fSKiran Chandramohan 
3118dc48849fSKiran Chandramohan   mlir::LogicalResult
matchAndRewrite__anon447c3e181111::IsPresentOpConversion3119dc48849fSKiran Chandramohan   matchAndRewrite(fir::IsPresentOp isPresent, OpAdaptor adaptor,
3120dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3121dc48849fSKiran Chandramohan     mlir::Type idxTy = lowerTy().indexType();
3122dc48849fSKiran Chandramohan     mlir::Location loc = isPresent.getLoc();
3123dc48849fSKiran Chandramohan     auto ptr = adaptor.getOperands()[0];
3124dc48849fSKiran Chandramohan 
3125dc48849fSKiran Chandramohan     if (isPresent.getVal().getType().isa<fir::BoxCharType>()) {
3126dc48849fSKiran Chandramohan       auto structTy = ptr.getType().cast<mlir::LLVM::LLVMStructType>();
3127dc48849fSKiran Chandramohan       assert(!structTy.isOpaque() && !structTy.getBody().empty());
3128dc48849fSKiran Chandramohan 
3129dc48849fSKiran Chandramohan       mlir::Type ty = structTy.getBody()[0];
3130dc48849fSKiran Chandramohan       mlir::MLIRContext *ctx = isPresent.getContext();
3131dc48849fSKiran Chandramohan       auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
3132dc48849fSKiran Chandramohan       ptr = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, ptr, c0);
3133dc48849fSKiran Chandramohan     }
3134dc48849fSKiran Chandramohan     mlir::LLVM::ConstantOp c0 =
3135dc48849fSKiran Chandramohan         genConstantIndex(isPresent.getLoc(), idxTy, rewriter, 0);
3136dc48849fSKiran Chandramohan     auto addr = rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, ptr);
3137dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
3138dc48849fSKiran Chandramohan         isPresent, mlir::LLVM::ICmpPredicate::ne, addr, c0);
3139dc48849fSKiran Chandramohan 
314044e58509SEric Schweitz     return mlir::success();
3141dc48849fSKiran Chandramohan   }
3142dc48849fSKiran Chandramohan };
3143dc48849fSKiran Chandramohan 
3144dc48849fSKiran Chandramohan /// Create value signaling an absent optional argument in a call, e.g.
3145dc48849fSKiran Chandramohan /// `fir.absent !fir.ref<i64>` -->  `llvm.mlir.null : !llvm.ptr<i64>`
3146dc48849fSKiran Chandramohan struct AbsentOpConversion : public FIROpConversion<fir::AbsentOp> {
3147dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3148dc48849fSKiran Chandramohan 
3149dc48849fSKiran Chandramohan   mlir::LogicalResult
matchAndRewrite__anon447c3e181111::AbsentOpConversion3150dc48849fSKiran Chandramohan   matchAndRewrite(fir::AbsentOp absent, OpAdaptor,
3151dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3152dc48849fSKiran Chandramohan     mlir::Type ty = convertType(absent.getType());
3153dc48849fSKiran Chandramohan     mlir::Location loc = absent.getLoc();
3154dc48849fSKiran Chandramohan 
3155dc48849fSKiran Chandramohan     if (absent.getType().isa<fir::BoxCharType>()) {
3156dc48849fSKiran Chandramohan       auto structTy = ty.cast<mlir::LLVM::LLVMStructType>();
3157dc48849fSKiran Chandramohan       assert(!structTy.isOpaque() && !structTy.getBody().empty());
3158dc48849fSKiran Chandramohan       auto undefStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
3159dc48849fSKiran Chandramohan       auto nullField =
3160dc48849fSKiran Chandramohan           rewriter.create<mlir::LLVM::NullOp>(loc, structTy.getBody()[0]);
3161dc48849fSKiran Chandramohan       mlir::MLIRContext *ctx = absent.getContext();
3162dc48849fSKiran Chandramohan       auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
3163dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
3164dc48849fSKiran Chandramohan           absent, ty, undefStruct, nullField, c0);
3165dc48849fSKiran Chandramohan     } else {
3166dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(absent, ty);
3167dc48849fSKiran Chandramohan     }
316844e58509SEric Schweitz     return mlir::success();
3169dc48849fSKiran Chandramohan   }
3170dc48849fSKiran Chandramohan };
31715d27abe6SValentin Clement 
31727b5132daSValentin Clement //
31737b5132daSValentin Clement // Primitive operations on Complex types
31747b5132daSValentin Clement //
31757b5132daSValentin Clement 
31767b5132daSValentin Clement /// Generate inline code for complex addition/subtraction
31777b5132daSValentin Clement template <typename LLVMOP, typename OPTY>
3178c2acd453SAlexisPerry static mlir::LLVM::InsertValueOp
complexSum(OPTY sumop,mlir::ValueRange opnds,mlir::ConversionPatternRewriter & rewriter,fir::LLVMTypeConverter & lowering)3179c2acd453SAlexisPerry complexSum(OPTY sumop, mlir::ValueRange opnds,
31807b5132daSValentin Clement            mlir::ConversionPatternRewriter &rewriter,
31817b5132daSValentin Clement            fir::LLVMTypeConverter &lowering) {
31827b5132daSValentin Clement   mlir::Value a = opnds[0];
31837b5132daSValentin Clement   mlir::Value b = opnds[1];
31847b5132daSValentin Clement   auto loc = sumop.getLoc();
31857b5132daSValentin Clement   auto ctx = sumop.getContext();
31867b5132daSValentin Clement   auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
31877b5132daSValentin Clement   auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
31887b5132daSValentin Clement   mlir::Type eleTy = lowering.convertType(getComplexEleTy(sumop.getType()));
31897b5132daSValentin Clement   mlir::Type ty = lowering.convertType(sumop.getType());
31907b5132daSValentin Clement   auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
31917b5132daSValentin Clement   auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
31927b5132daSValentin Clement   auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
31937b5132daSValentin Clement   auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
31947b5132daSValentin Clement   auto rx = rewriter.create<LLVMOP>(loc, eleTy, x0, x1);
31957b5132daSValentin Clement   auto ry = rewriter.create<LLVMOP>(loc, eleTy, y0, y1);
31967b5132daSValentin Clement   auto r0 = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
31977b5132daSValentin Clement   auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r0, rx, c0);
31987b5132daSValentin Clement   return rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ry, c1);
31997b5132daSValentin Clement }
3200dc48849fSKiran Chandramohan } // namespace
32017b5132daSValentin Clement 
3202c2acd453SAlexisPerry namespace {
32037b5132daSValentin Clement struct AddcOpConversion : public FIROpConversion<fir::AddcOp> {
32047b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
32057b5132daSValentin Clement 
32067b5132daSValentin Clement   mlir::LogicalResult
matchAndRewrite__anon447c3e181211::AddcOpConversion32077b5132daSValentin Clement   matchAndRewrite(fir::AddcOp addc, OpAdaptor adaptor,
32087b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
32097b5132daSValentin Clement     // given: (x + iy) + (x' + iy')
32107b5132daSValentin Clement     // result: (x + x') + i(y + y')
32117b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FAddOp>(addc, adaptor.getOperands(),
32127b5132daSValentin Clement                                             rewriter, lowerTy());
32137b5132daSValentin Clement     rewriter.replaceOp(addc, r.getResult());
321444e58509SEric Schweitz     return mlir::success();
32157b5132daSValentin Clement   }
32167b5132daSValentin Clement };
32177b5132daSValentin Clement 
32187b5132daSValentin Clement struct SubcOpConversion : public FIROpConversion<fir::SubcOp> {
32197b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
32207b5132daSValentin Clement 
32217b5132daSValentin Clement   mlir::LogicalResult
matchAndRewrite__anon447c3e181211::SubcOpConversion32227b5132daSValentin Clement   matchAndRewrite(fir::SubcOp subc, OpAdaptor adaptor,
32237b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
32247b5132daSValentin Clement     // given: (x + iy) - (x' + iy')
32257b5132daSValentin Clement     // result: (x - x') + i(y - y')
32267b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FSubOp>(subc, adaptor.getOperands(),
32277b5132daSValentin Clement                                             rewriter, lowerTy());
32287b5132daSValentin Clement     rewriter.replaceOp(subc, r.getResult());
322944e58509SEric Schweitz     return mlir::success();
32307b5132daSValentin Clement   }
32317b5132daSValentin Clement };
32327b5132daSValentin Clement 
32337b5132daSValentin Clement /// Inlined complex multiply
32347b5132daSValentin Clement struct MulcOpConversion : public FIROpConversion<fir::MulcOp> {
32357b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
32367b5132daSValentin Clement 
32377b5132daSValentin Clement   mlir::LogicalResult
matchAndRewrite__anon447c3e181211::MulcOpConversion32387b5132daSValentin Clement   matchAndRewrite(fir::MulcOp mulc, OpAdaptor adaptor,
32397b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
32407b5132daSValentin Clement     // TODO: Can we use a call to __muldc3 ?
32417b5132daSValentin Clement     // given: (x + iy) * (x' + iy')
32427b5132daSValentin Clement     // result: (xx'-yy')+i(xy'+yx')
32437b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
32447b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
32457b5132daSValentin Clement     auto loc = mulc.getLoc();
32467b5132daSValentin Clement     auto *ctx = mulc.getContext();
32477b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
32487b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
32497b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(mulc.getType()));
32507b5132daSValentin Clement     mlir::Type ty = convertType(mulc.getType());
32517b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
32527b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
32537b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
32547b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
32557b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
32567b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
32577b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
32587b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xy, yx);
32597b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
32607b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, xx, yy);
32617b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
32627b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
32637b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
32647b5132daSValentin Clement     rewriter.replaceOp(mulc, r0.getResult());
326544e58509SEric Schweitz     return mlir::success();
32667b5132daSValentin Clement   }
32677b5132daSValentin Clement };
32687b5132daSValentin Clement 
32697b5132daSValentin Clement /// Inlined complex division
32707b5132daSValentin Clement struct DivcOpConversion : public FIROpConversion<fir::DivcOp> {
32717b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
32727b5132daSValentin Clement 
32737b5132daSValentin Clement   mlir::LogicalResult
matchAndRewrite__anon447c3e181211::DivcOpConversion32747b5132daSValentin Clement   matchAndRewrite(fir::DivcOp divc, OpAdaptor adaptor,
32757b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
32767b5132daSValentin Clement     // TODO: Can we use a call to __divdc3 instead?
32777b5132daSValentin Clement     // Just generate inline code for now.
32787b5132daSValentin Clement     // given: (x + iy) / (x' + iy')
32797b5132daSValentin Clement     // result: ((xx'+yy')/d) + i((yx'-xy')/d) where d = x'x' + y'y'
32807b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
32817b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
32827b5132daSValentin Clement     auto loc = divc.getLoc();
32837b5132daSValentin Clement     auto *ctx = divc.getContext();
32847b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
32857b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
32867b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(divc.getType()));
32877b5132daSValentin Clement     mlir::Type ty = convertType(divc.getType());
32887b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
32897b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
32907b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
32917b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
32927b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
32937b5132daSValentin Clement     auto x1x1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x1, x1);
32947b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
32957b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
32967b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
32977b5132daSValentin Clement     auto y1y1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y1, y1);
32987b5132daSValentin Clement     auto d = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, x1x1, y1y1);
32997b5132daSValentin Clement     auto rrn = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xx, yy);
33007b5132daSValentin Clement     auto rin = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, yx, xy);
33017b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rrn, d);
33027b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rin, d);
33037b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
33047b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
33057b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
33067b5132daSValentin Clement     rewriter.replaceOp(divc, r0.getResult());
330744e58509SEric Schweitz     return mlir::success();
33087b5132daSValentin Clement   }
33097b5132daSValentin Clement };
33107b5132daSValentin Clement 
33117b5132daSValentin Clement /// Inlined complex negation
33127b5132daSValentin Clement struct NegcOpConversion : public FIROpConversion<fir::NegcOp> {
33137b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
33147b5132daSValentin Clement 
33157b5132daSValentin Clement   mlir::LogicalResult
matchAndRewrite__anon447c3e181211::NegcOpConversion33167b5132daSValentin Clement   matchAndRewrite(fir::NegcOp neg, OpAdaptor adaptor,
33177b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
33187b5132daSValentin Clement     // given: -(x + iy)
33197b5132daSValentin Clement     // result: -x - iy
33207b5132daSValentin Clement     auto *ctxt = neg.getContext();
33217b5132daSValentin Clement     auto eleTy = convertType(getComplexEleTy(neg.getType()));
33227b5132daSValentin Clement     auto ty = convertType(neg.getType());
33237b5132daSValentin Clement     auto loc = neg.getLoc();
33247b5132daSValentin Clement     mlir::Value o0 = adaptor.getOperands()[0];
33257b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0));
33267b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1));
33277b5132daSValentin Clement     auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c0);
33287b5132daSValentin Clement     auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c1);
33297b5132daSValentin Clement     auto nrp = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, rp);
33307b5132daSValentin Clement     auto nip = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, ip);
33317b5132daSValentin Clement     auto r = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, o0, nrp, c0);
33327b5132daSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(neg, ty, r, nip, c1);
333344e58509SEric Schweitz     return mlir::success();
33347b5132daSValentin Clement   }
33357b5132daSValentin Clement };
33367b5132daSValentin Clement 
33371ed5a90fSValentin Clement /// Conversion pattern for operation that must be dead. The information in these
33381ed5a90fSValentin Clement /// operations is used by other operation. At this point they should not have
33391ed5a90fSValentin Clement /// anymore uses.
33401ed5a90fSValentin Clement /// These operations are normally dead after the pre-codegen pass.
33411ed5a90fSValentin Clement template <typename FromOp>
33421ed5a90fSValentin Clement struct MustBeDeadConversion : public FIROpConversion<FromOp> {
MustBeDeadConversion__anon447c3e181211::MustBeDeadConversion3343013160f6SJean Perier   explicit MustBeDeadConversion(fir::LLVMTypeConverter &lowering,
3344013160f6SJean Perier                                 const fir::FIRToLLVMPassOptions &options)
3345013160f6SJean Perier       : FIROpConversion<FromOp>(lowering, options) {}
33461ed5a90fSValentin Clement   using OpAdaptor = typename FromOp::Adaptor;
33471ed5a90fSValentin Clement 
33481ed5a90fSValentin Clement   mlir::LogicalResult
matchAndRewrite__anon447c3e181211::MustBeDeadConversion33491ed5a90fSValentin Clement   matchAndRewrite(FromOp op, OpAdaptor adaptor,
33501ed5a90fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const final {
33511ed5a90fSValentin Clement     if (!op->getUses().empty())
33521ed5a90fSValentin Clement       return rewriter.notifyMatchFailure(op, "op must be dead");
33531ed5a90fSValentin Clement     rewriter.eraseOp(op);
335444e58509SEric Schweitz     return mlir::success();
33551ed5a90fSValentin Clement   }
33561ed5a90fSValentin Clement };
33571ed5a90fSValentin Clement 
33581ed5a90fSValentin Clement struct ShapeOpConversion : public MustBeDeadConversion<fir::ShapeOp> {
33591ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
33601ed5a90fSValentin Clement };
33611ed5a90fSValentin Clement 
33621ed5a90fSValentin Clement struct ShapeShiftOpConversion : public MustBeDeadConversion<fir::ShapeShiftOp> {
33631ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
33641ed5a90fSValentin Clement };
33651ed5a90fSValentin Clement 
33661ed5a90fSValentin Clement struct ShiftOpConversion : public MustBeDeadConversion<fir::ShiftOp> {
33671ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
33681ed5a90fSValentin Clement };
33691ed5a90fSValentin Clement 
33701ed5a90fSValentin Clement struct SliceOpConversion : public MustBeDeadConversion<fir::SliceOp> {
33711ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
33721ed5a90fSValentin Clement };
33731ed5a90fSValentin Clement 
3374044d5b5dSValentin Clement } // namespace
3375044d5b5dSValentin Clement 
3376044d5b5dSValentin Clement namespace {
3377044d5b5dSValentin Clement /// Convert FIR dialect to LLVM dialect
3378044d5b5dSValentin Clement ///
3379044d5b5dSValentin Clement /// This pass lowers all FIR dialect operations to LLVM IR dialect. An
3380044d5b5dSValentin Clement /// MLIR pass is used to lower residual Std dialect to LLVM IR dialect.
3381044d5b5dSValentin Clement class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> {
3382044d5b5dSValentin Clement public:
3383013160f6SJean Perier   FIRToLLVMLowering() = default;
FIRToLLVMLowering(fir::FIRToLLVMPassOptions options)3384013160f6SJean Perier   FIRToLLVMLowering(fir::FIRToLLVMPassOptions options) : options{options} {}
getModule()3385044d5b5dSValentin Clement   mlir::ModuleOp getModule() { return getOperation(); }
3386044d5b5dSValentin Clement 
runOnOperation()3387044d5b5dSValentin Clement   void runOnOperation() override final {
33887b5132daSValentin Clement     auto mod = getModule();
338944e58509SEric Schweitz     if (!forcedTargetTriple.empty())
33907b5132daSValentin Clement       fir::setTargetTriple(mod, forcedTargetTriple);
33917b5132daSValentin Clement 
3392044d5b5dSValentin Clement     auto *context = getModule().getContext();
3393044d5b5dSValentin Clement     fir::LLVMTypeConverter typeConverter{getModule()};
33949f85c198SRiver Riddle     mlir::RewritePatternSet pattern(context);
3395df3b9810SValentin Clement     pattern.insert<
3396420ad7ceSAndrzej Warzynski         AbsentOpConversion, AddcOpConversion, AddrOfOpConversion,
3397c2acd453SAlexisPerry         AllocaOpConversion, AllocMemOpConversion, BoxAddrOpConversion,
3398c2acd453SAlexisPerry         BoxCharLenOpConversion, BoxDimsOpConversion, BoxEleSizeOpConversion,
3399c2acd453SAlexisPerry         BoxIsAllocOpConversion, BoxIsArrayOpConversion, BoxIsPtrOpConversion,
3400c2acd453SAlexisPerry         BoxProcHostOpConversion, BoxRankOpConversion, BoxTypeDescOpConversion,
3401c2acd453SAlexisPerry         CallOpConversion, CmpcOpConversion, ConstcOpConversion,
3402e6e7da55SAndrzej Warzynski         ConvertOpConversion, CoordinateOpConversion, DispatchOpConversion,
3403e6e7da55SAndrzej Warzynski         DispatchTableOpConversion, DTEntryOpConversion, DivcOpConversion,
3404e6e7da55SAndrzej Warzynski         EmboxOpConversion, EmboxCharOpConversion, EmboxProcOpConversion,
3405e6e7da55SAndrzej Warzynski         ExtractValueOpConversion, FieldIndexOpConversion, FirEndOpConversion,
3406dc48849fSKiran Chandramohan         FreeMemOpConversion, GenTypeDescOpConversion, GlobalLenOpConversion,
3407dc48849fSKiran Chandramohan         GlobalOpConversion, HasValueOpConversion, InsertOnRangeOpConversion,
3408e6e7da55SAndrzej Warzynski         InsertValueOpConversion, IsPresentOpConversion,
3409dc48849fSKiran Chandramohan         LenParamIndexOpConversion, LoadOpConversion, MulcOpConversion,
3410dc48849fSKiran Chandramohan         NegcOpConversion, NoReassocOpConversion, SelectCaseOpConversion,
3411e6e7da55SAndrzej Warzynski         SelectOpConversion, SelectRankOpConversion, SelectTypeOpConversion,
3412e6e7da55SAndrzej Warzynski         ShapeOpConversion, ShapeShiftOpConversion, ShiftOpConversion,
3413e6e7da55SAndrzej Warzynski         SliceOpConversion, StoreOpConversion, StringLitOpConversion,
3414e6e7da55SAndrzej Warzynski         SubcOpConversion, UnboxCharOpConversion, UnboxProcOpConversion,
3415e6e7da55SAndrzej Warzynski         UndefOpConversion, UnreachableOpConversion, XArrayCoorOpConversion,
3416013160f6SJean Perier         XEmboxOpConversion, XReboxOpConversion, ZeroOpConversion>(typeConverter,
3417013160f6SJean Perier                                                                   options);
34185a7b9194SRiver Riddle     mlir::populateFuncToLLVMConversionPatterns(typeConverter, pattern);
3419c6ac9370SKiran Chandramohan     mlir::populateOpenMPToLLVMConversionPatterns(typeConverter, pattern);
3420044d5b5dSValentin Clement     mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter,
3421044d5b5dSValentin Clement                                                             pattern);
3422ace01605SRiver Riddle     mlir::cf::populateControlFlowToLLVMConversionPatterns(typeConverter,
3423ace01605SRiver Riddle                                                           pattern);
34249f356579SSlava Zakharin     // Convert math-like dialect operations, which can be produced
34259f356579SSlava Zakharin     // when late math lowering mode is used, into llvm dialect.
34269f356579SSlava Zakharin     mlir::populateMathToLLVMConversionPatterns(typeConverter, pattern);
34279f356579SSlava Zakharin     mlir::populateMathToLibmConversionPatterns(pattern, /*benefit=*/0);
3428044d5b5dSValentin Clement     mlir::ConversionTarget target{*context};
3429044d5b5dSValentin Clement     target.addLegalDialect<mlir::LLVM::LLVMDialect>();
3430c6ac9370SKiran Chandramohan     // The OpenMP dialect is legal for Operations without regions, for those
3431c6ac9370SKiran Chandramohan     // which contains regions it is legal if the region contains only the
343200c511b3SNimish Mishra     // LLVM dialect. Add OpenMP dialect as a legal dialect for conversion and
343300c511b3SNimish Mishra     // legalize conversion of OpenMP operations without regions.
343400c511b3SNimish Mishra     mlir::configureOpenMPToLLVMConversionLegality(target, typeConverter);
3435c6ac9370SKiran Chandramohan     target.addLegalDialect<mlir::omp::OpenMPDialect>();
3436044d5b5dSValentin Clement 
3437044d5b5dSValentin Clement     // required NOPs for applying a full conversion
3438044d5b5dSValentin Clement     target.addLegalOp<mlir::ModuleOp>();
3439044d5b5dSValentin Clement 
3440044d5b5dSValentin Clement     // apply the patterns
3441044d5b5dSValentin Clement     if (mlir::failed(mlir::applyFullConversion(getModule(), target,
3442044d5b5dSValentin Clement                                                std::move(pattern)))) {
3443044d5b5dSValentin Clement       signalPassFailure();
3444044d5b5dSValentin Clement     }
3445044d5b5dSValentin Clement   }
3446013160f6SJean Perier 
3447013160f6SJean Perier private:
3448013160f6SJean Perier   fir::FIRToLLVMPassOptions options;
3449044d5b5dSValentin Clement };
3450853e79d8SValentin Clement 
3451853e79d8SValentin Clement /// Lower from LLVM IR dialect to proper LLVM-IR and dump the module
3452853e79d8SValentin Clement struct LLVMIRLoweringPass
3453853e79d8SValentin Clement     : public mlir::PassWrapper<LLVMIRLoweringPass,
3454853e79d8SValentin Clement                                mlir::OperationPass<mlir::ModuleOp>> {
34555e50dd04SRiver Riddle   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(LLVMIRLoweringPass)
34565e50dd04SRiver Riddle 
LLVMIRLoweringPass__anon447c3e181311::LLVMIRLoweringPass345744e58509SEric Schweitz   LLVMIRLoweringPass(llvm::raw_ostream &output, fir::LLVMIRLoweringPrinter p)
3458853e79d8SValentin Clement       : output{output}, printer{p} {}
3459853e79d8SValentin Clement 
getModule__anon447c3e181311::LLVMIRLoweringPass3460853e79d8SValentin Clement   mlir::ModuleOp getModule() { return getOperation(); }
3461853e79d8SValentin Clement 
runOnOperation__anon447c3e181311::LLVMIRLoweringPass3462853e79d8SValentin Clement   void runOnOperation() override final {
3463853e79d8SValentin Clement     auto *ctx = getModule().getContext();
3464853e79d8SValentin Clement     auto optName = getModule().getName();
3465853e79d8SValentin Clement     llvm::LLVMContext llvmCtx;
3466853e79d8SValentin Clement     if (auto llvmModule = mlir::translateModuleToLLVMIR(
3467853e79d8SValentin Clement             getModule(), llvmCtx, optName ? *optName : "FIRModule")) {
3468853e79d8SValentin Clement       printer(*llvmModule, output);
3469853e79d8SValentin Clement       return;
3470853e79d8SValentin Clement     }
3471853e79d8SValentin Clement 
3472853e79d8SValentin Clement     mlir::emitError(mlir::UnknownLoc::get(ctx), "could not emit LLVM-IR\n");
3473853e79d8SValentin Clement     signalPassFailure();
3474853e79d8SValentin Clement   }
3475853e79d8SValentin Clement 
3476853e79d8SValentin Clement private:
347744e58509SEric Schweitz   llvm::raw_ostream &output;
347844e58509SEric Schweitz   fir::LLVMIRLoweringPrinter printer;
3479853e79d8SValentin Clement };
3480853e79d8SValentin Clement 
3481044d5b5dSValentin Clement } // namespace
3482044d5b5dSValentin Clement 
createFIRToLLVMPass()3483044d5b5dSValentin Clement std::unique_ptr<mlir::Pass> fir::createFIRToLLVMPass() {
3484044d5b5dSValentin Clement   return std::make_unique<FIRToLLVMLowering>();
3485044d5b5dSValentin Clement }
3486853e79d8SValentin Clement 
3487853e79d8SValentin Clement std::unique_ptr<mlir::Pass>
createFIRToLLVMPass(fir::FIRToLLVMPassOptions options)348844e58509SEric Schweitz fir::createFIRToLLVMPass(fir::FIRToLLVMPassOptions options) {
3489013160f6SJean Perier   return std::make_unique<FIRToLLVMLowering>(options);
3490013160f6SJean Perier }
3491013160f6SJean Perier 
3492013160f6SJean Perier std::unique_ptr<mlir::Pass>
createLLVMDialectToLLVMPass(llvm::raw_ostream & output,fir::LLVMIRLoweringPrinter printer)349344e58509SEric Schweitz fir::createLLVMDialectToLLVMPass(llvm::raw_ostream &output,
3494853e79d8SValentin Clement                                  fir::LLVMIRLoweringPrinter printer) {
3495853e79d8SValentin Clement   return std::make_unique<LLVMIRLoweringPass>(output, printer);
3496853e79d8SValentin Clement }
3497