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