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"
19*7dd7ccd2SJean Perier #include "flang/Optimizer/Support/InternalNames.h"
20af6ee580SValentin Clement #include "flang/Optimizer/Support/TypeCode.h"
21*7dd7ccd2SJean Perier #include "flang/Semantics/runtime-type-info.h"
22044d5b5dSValentin Clement #include "mlir/Conversion/ArithmeticToLLVM/ArithmeticToLLVM.h"
23ace01605SRiver Riddle #include "mlir/Conversion/ControlFlowToLLVM/ControlFlowToLLVM.h"
24044d5b5dSValentin Clement #include "mlir/Conversion/LLVMCommon/Pattern.h"
25044d5b5dSValentin Clement #include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h"
26044d5b5dSValentin Clement #include "mlir/IR/BuiltinTypes.h"
273ae8e442SValentin Clement #include "mlir/IR/Matchers.h"
28044d5b5dSValentin Clement #include "mlir/Pass/Pass.h"
29853e79d8SValentin Clement #include "mlir/Target/LLVMIR/ModuleTranslation.h"
30044d5b5dSValentin Clement #include "llvm/ADT/ArrayRef.h"
31044d5b5dSValentin Clement 
32044d5b5dSValentin Clement #define DEBUG_TYPE "flang-codegen"
33044d5b5dSValentin Clement 
34044d5b5dSValentin Clement // fir::LLVMTypeConverter for converting to LLVM IR dialect types.
35044d5b5dSValentin Clement #include "TypeConverter.h"
36044d5b5dSValentin Clement 
37af6ee580SValentin Clement // TODO: This should really be recovered from the specified target.
38af6ee580SValentin Clement static constexpr unsigned defaultAlign = 8;
39af6ee580SValentin Clement 
40b6e44ecdSValentin Clement /// `fir.box` attribute values as defined for CFI_attribute_t in
41b6e44ecdSValentin Clement /// flang/ISO_Fortran_binding.h.
42b6e44ecdSValentin Clement static constexpr unsigned kAttrPointer = CFI_attribute_pointer;
43b6e44ecdSValentin Clement static constexpr unsigned kAttrAllocatable = CFI_attribute_allocatable;
44b6e44ecdSValentin Clement 
45135d5d4aSKiran Chandramohan static inline mlir::Type getVoidPtrType(mlir::MLIRContext *context) {
46fa517555SKiran Chandramohan   return mlir::LLVM::LLVMPointerType::get(mlir::IntegerType::get(context, 8));
47fa517555SKiran Chandramohan }
48fa517555SKiran Chandramohan 
491e6d9c06SDiana Picus static mlir::LLVM::ConstantOp
501e6d9c06SDiana Picus genConstantIndex(mlir::Location loc, mlir::Type ity,
511e6d9c06SDiana Picus                  mlir::ConversionPatternRewriter &rewriter,
521e6d9c06SDiana Picus                  std::int64_t offset) {
531e6d9c06SDiana Picus   auto cattr = rewriter.getI64IntegerAttr(offset);
541e6d9c06SDiana Picus   return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr);
551e6d9c06SDiana Picus }
561e6d9c06SDiana Picus 
5739f4ef81SValentin Clement static Block *createBlock(mlir::ConversionPatternRewriter &rewriter,
5839f4ef81SValentin Clement                           mlir::Block *insertBefore) {
5939f4ef81SValentin Clement   assert(insertBefore && "expected valid insertion block");
6039f4ef81SValentin Clement   return rewriter.createBlock(insertBefore->getParent(),
6139f4ef81SValentin Clement                               mlir::Region::iterator(insertBefore));
6239f4ef81SValentin Clement }
6339f4ef81SValentin Clement 
64044d5b5dSValentin Clement namespace {
65044d5b5dSValentin Clement /// FIR conversion pattern template
66044d5b5dSValentin Clement template <typename FromOp>
67044d5b5dSValentin Clement class FIROpConversion : public mlir::ConvertOpToLLVMPattern<FromOp> {
68044d5b5dSValentin Clement public:
69044d5b5dSValentin Clement   explicit FIROpConversion(fir::LLVMTypeConverter &lowering)
70044d5b5dSValentin Clement       : mlir::ConvertOpToLLVMPattern<FromOp>(lowering) {}
71044d5b5dSValentin Clement 
72044d5b5dSValentin Clement protected:
73044d5b5dSValentin Clement   mlir::Type convertType(mlir::Type ty) const {
74044d5b5dSValentin Clement     return lowerTy().convertType(ty);
75044d5b5dSValentin Clement   }
76c2acd453SAlexisPerry   mlir::Type voidPtrTy() const { return getVoidPtrType(); }
77044d5b5dSValentin Clement 
785d27abe6SValentin Clement   mlir::Type getVoidPtrType() const {
795d27abe6SValentin Clement     return mlir::LLVM::LLVMPointerType::get(
805d27abe6SValentin Clement         mlir::IntegerType::get(&lowerTy().getContext(), 8));
815d27abe6SValentin Clement   }
825d27abe6SValentin Clement 
83df3b9810SValentin Clement   mlir::LLVM::ConstantOp
84af6ee580SValentin Clement   genI32Constant(mlir::Location loc, mlir::ConversionPatternRewriter &rewriter,
85af6ee580SValentin Clement                  int value) const {
86af6ee580SValentin Clement     mlir::Type i32Ty = rewriter.getI32Type();
87af6ee580SValentin Clement     mlir::IntegerAttr attr = rewriter.getI32IntegerAttr(value);
88af6ee580SValentin Clement     return rewriter.create<mlir::LLVM::ConstantOp>(loc, i32Ty, attr);
89af6ee580SValentin Clement   }
90af6ee580SValentin Clement 
91af6ee580SValentin Clement   mlir::LLVM::ConstantOp
92df3b9810SValentin Clement   genConstantOffset(mlir::Location loc,
93df3b9810SValentin Clement                     mlir::ConversionPatternRewriter &rewriter,
94df3b9810SValentin Clement                     int offset) const {
95af6ee580SValentin Clement     mlir::Type ity = lowerTy().offsetType();
96af6ee580SValentin Clement     mlir::IntegerAttr cattr = rewriter.getI32IntegerAttr(offset);
97df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr);
98df3b9810SValentin Clement   }
99df3b9810SValentin Clement 
100b6e44ecdSValentin Clement   /// Construct code sequence to extract the specifc value from a `fir.box`.
101b6e44ecdSValentin Clement   mlir::Value getValueFromBox(mlir::Location loc, mlir::Value box,
102df3b9810SValentin Clement                               mlir::Type resultTy,
103b6e44ecdSValentin Clement                               mlir::ConversionPatternRewriter &rewriter,
104b6e44ecdSValentin Clement                               unsigned boxValue) const {
105df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
106b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp cValuePos =
107b6e44ecdSValentin Clement         genConstantOffset(loc, rewriter, boxValue);
108df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(resultTy);
109df3b9810SValentin Clement     auto p = rewriter.create<mlir::LLVM::GEPOp>(
11030122656SAlex Zinenko         loc, pty, box, mlir::ValueRange{c0, cValuePos});
111df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, resultTy, p);
112df3b9810SValentin Clement   }
113df3b9810SValentin Clement 
114df3b9810SValentin Clement   /// Method to construct code sequence to get the triple for dimension `dim`
115df3b9810SValentin Clement   /// from a box.
116df3b9810SValentin Clement   SmallVector<mlir::Value, 3>
117df3b9810SValentin Clement   getDimsFromBox(mlir::Location loc, ArrayRef<mlir::Type> retTys,
118df3b9810SValentin Clement                  mlir::Value box, mlir::Value dim,
119df3b9810SValentin Clement                  mlir::ConversionPatternRewriter &rewriter) const {
120df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
121df3b9810SValentin Clement     mlir::LLVM::ConstantOp cDims =
122df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kDimsPosInBox);
123df3b9810SValentin Clement     mlir::LLVM::LoadOp l0 =
124df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 0, retTys[0], rewriter);
125df3b9810SValentin Clement     mlir::LLVM::LoadOp l1 =
126df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 1, retTys[1], rewriter);
127df3b9810SValentin Clement     mlir::LLVM::LoadOp l2 =
128df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 2, retTys[2], rewriter);
129df3b9810SValentin Clement     return {l0.getResult(), l1.getResult(), l2.getResult()};
130df3b9810SValentin Clement   }
131df3b9810SValentin Clement 
132df3b9810SValentin Clement   mlir::LLVM::LoadOp
133df3b9810SValentin Clement   loadFromOffset(mlir::Location loc, mlir::Value a, mlir::LLVM::ConstantOp c0,
134df3b9810SValentin Clement                  mlir::LLVM::ConstantOp cDims, mlir::Value dim, int off,
135df3b9810SValentin Clement                  mlir::Type ty,
136df3b9810SValentin Clement                  mlir::ConversionPatternRewriter &rewriter) const {
137df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
138df3b9810SValentin Clement     mlir::LLVM::ConstantOp c = genConstantOffset(loc, rewriter, off);
139df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, a, c0, cDims, dim, c);
140df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
141df3b9810SValentin Clement   }
142df3b9810SValentin Clement 
1435d27abe6SValentin Clement   mlir::Value
1445d27abe6SValentin Clement   loadStrideFromBox(mlir::Location loc, mlir::Value box, unsigned dim,
1455d27abe6SValentin Clement                     mlir::ConversionPatternRewriter &rewriter) const {
1465d27abe6SValentin Clement     auto idxTy = lowerTy().indexType();
1475d27abe6SValentin Clement     auto c0 = genConstantOffset(loc, rewriter, 0);
1485d27abe6SValentin Clement     auto cDims = genConstantOffset(loc, rewriter, kDimsPosInBox);
1495d27abe6SValentin Clement     auto dimValue = genConstantIndex(loc, idxTy, rewriter, dim);
1505d27abe6SValentin Clement     return loadFromOffset(loc, box, c0, cDims, dimValue, kDimStridePos, idxTy,
1515d27abe6SValentin Clement                           rewriter);
1525d27abe6SValentin Clement   }
1535d27abe6SValentin Clement 
154df3b9810SValentin Clement   /// Read base address from a fir.box. Returned address has type ty.
155df3b9810SValentin Clement   mlir::Value
156df3b9810SValentin Clement   loadBaseAddrFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box,
157df3b9810SValentin Clement                       mlir::ConversionPatternRewriter &rewriter) const {
158df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
159df3b9810SValentin Clement     mlir::LLVM::ConstantOp cAddr =
160df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kAddrPosInBox);
161df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
162df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cAddr);
163df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
164df3b9810SValentin Clement   }
165df3b9810SValentin Clement 
166df3b9810SValentin Clement   mlir::Value
167df3b9810SValentin Clement   loadElementSizeFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box,
168df3b9810SValentin Clement                          mlir::ConversionPatternRewriter &rewriter) const {
169df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
170df3b9810SValentin Clement     mlir::LLVM::ConstantOp cElemLen =
171df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kElemLenPosInBox);
172df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
173df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cElemLen);
174df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
175df3b9810SValentin Clement   }
176df3b9810SValentin Clement 
177b6e44ecdSValentin Clement   // Load the attribute from the \p box and perform a check against \p maskValue
178b6e44ecdSValentin Clement   // The final comparison is implemented as `(attribute & maskValue) != 0`.
179b6e44ecdSValentin Clement   mlir::Value genBoxAttributeCheck(mlir::Location loc, mlir::Value box,
180b6e44ecdSValentin Clement                                    mlir::ConversionPatternRewriter &rewriter,
181b6e44ecdSValentin Clement                                    unsigned maskValue) const {
182b6e44ecdSValentin Clement     mlir::Type attrTy = rewriter.getI32Type();
183b6e44ecdSValentin Clement     mlir::Value attribute =
184b6e44ecdSValentin Clement         getValueFromBox(loc, box, attrTy, rewriter, kAttributePosInBox);
185b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp attrMask =
186b6e44ecdSValentin Clement         genConstantOffset(loc, rewriter, maskValue);
187b6e44ecdSValentin Clement     auto maskRes =
188b6e44ecdSValentin Clement         rewriter.create<mlir::LLVM::AndOp>(loc, attrTy, attribute, attrMask);
189b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
190b6e44ecdSValentin Clement     return rewriter.create<mlir::LLVM::ICmpOp>(
191b6e44ecdSValentin Clement         loc, mlir::LLVM::ICmpPredicate::ne, maskRes, c0);
192b6e44ecdSValentin Clement   }
193b6e44ecdSValentin Clement 
194af6ee580SValentin Clement   // Get the element type given an LLVM type that is of the form
195af6ee580SValentin Clement   // [llvm.ptr](array|struct|vector)+ and the provided indexes.
196af6ee580SValentin Clement   static mlir::Type getBoxEleTy(mlir::Type type,
197af6ee580SValentin Clement                                 llvm::ArrayRef<unsigned> indexes) {
198af6ee580SValentin Clement     if (auto t = type.dyn_cast<mlir::LLVM::LLVMPointerType>())
199af6ee580SValentin Clement       type = t.getElementType();
200af6ee580SValentin Clement     for (auto i : indexes) {
201af6ee580SValentin Clement       if (auto t = type.dyn_cast<mlir::LLVM::LLVMStructType>()) {
202af6ee580SValentin Clement         assert(!t.isOpaque() && i < t.getBody().size());
203af6ee580SValentin Clement         type = t.getBody()[i];
204af6ee580SValentin Clement       } else if (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
205af6ee580SValentin Clement         type = t.getElementType();
206af6ee580SValentin Clement       } else if (auto t = type.dyn_cast<mlir::VectorType>()) {
207af6ee580SValentin Clement         type = t.getElementType();
208af6ee580SValentin Clement       } else {
209af6ee580SValentin Clement         fir::emitFatalError(mlir::UnknownLoc::get(type.getContext()),
210af6ee580SValentin Clement                             "request for invalid box element type");
211af6ee580SValentin Clement       }
212af6ee580SValentin Clement     }
213af6ee580SValentin Clement     return type;
214af6ee580SValentin Clement   }
215af6ee580SValentin Clement 
2165d27abe6SValentin Clement   // Return LLVM type of the base address given the LLVM type
2175d27abe6SValentin Clement   // of the related descriptor (lowered fir.box type).
2185d27abe6SValentin Clement   static mlir::Type getBaseAddrTypeFromBox(mlir::Type type) {
2195d27abe6SValentin Clement     return getBoxEleTy(type, {kAddrPosInBox});
2205d27abe6SValentin Clement   }
2215d27abe6SValentin Clement 
222df3b9810SValentin Clement   template <typename... ARGS>
223df3b9810SValentin Clement   mlir::LLVM::GEPOp genGEP(mlir::Location loc, mlir::Type ty,
224df3b9810SValentin Clement                            mlir::ConversionPatternRewriter &rewriter,
225df3b9810SValentin Clement                            mlir::Value base, ARGS... args) const {
226df3b9810SValentin Clement     SmallVector<mlir::Value> cv{args...};
227df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::GEPOp>(loc, ty, base, cv);
228df3b9810SValentin Clement   }
229df3b9810SValentin Clement 
2301e6d9c06SDiana Picus   /// Perform an extension or truncation as needed on an integer value. Lowering
2311e6d9c06SDiana Picus   /// to the specific target may involve some sign-extending or truncation of
2321e6d9c06SDiana Picus   /// values, particularly to fit them from abstract box types to the
2331e6d9c06SDiana Picus   /// appropriate reified structures.
2341e6d9c06SDiana Picus   mlir::Value integerCast(mlir::Location loc,
2351e6d9c06SDiana Picus                           mlir::ConversionPatternRewriter &rewriter,
2361e6d9c06SDiana Picus                           mlir::Type ty, mlir::Value val) const {
2371e6d9c06SDiana Picus     auto valTy = val.getType();
2381e6d9c06SDiana Picus     // If the value was not yet lowered, lower its type so that it can
2391e6d9c06SDiana Picus     // be used in getPrimitiveTypeSizeInBits.
2401e6d9c06SDiana Picus     if (!valTy.isa<mlir::IntegerType>())
2411e6d9c06SDiana Picus       valTy = convertType(valTy);
2421e6d9c06SDiana Picus     auto toSize = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
2431e6d9c06SDiana Picus     auto fromSize = mlir::LLVM::getPrimitiveTypeSizeInBits(valTy);
2441e6d9c06SDiana Picus     if (toSize < fromSize)
2451e6d9c06SDiana Picus       return rewriter.create<mlir::LLVM::TruncOp>(loc, ty, val);
2461e6d9c06SDiana Picus     if (toSize > fromSize)
2471e6d9c06SDiana Picus       return rewriter.create<mlir::LLVM::SExtOp>(loc, ty, val);
2481e6d9c06SDiana Picus     return val;
2491e6d9c06SDiana Picus   }
2501e6d9c06SDiana Picus 
251044d5b5dSValentin Clement   fir::LLVMTypeConverter &lowerTy() const {
252044d5b5dSValentin Clement     return *static_cast<fir::LLVMTypeConverter *>(this->getTypeConverter());
253044d5b5dSValentin Clement   }
254044d5b5dSValentin Clement };
255044d5b5dSValentin Clement 
2563ae8e442SValentin Clement /// FIR conversion pattern template
2573ae8e442SValentin Clement template <typename FromOp>
2583ae8e442SValentin Clement class FIROpAndTypeConversion : public FIROpConversion<FromOp> {
2593ae8e442SValentin Clement public:
2603ae8e442SValentin Clement   using FIROpConversion<FromOp>::FIROpConversion;
2613ae8e442SValentin Clement   using OpAdaptor = typename FromOp::Adaptor;
2623ae8e442SValentin Clement 
2633ae8e442SValentin Clement   mlir::LogicalResult
2643ae8e442SValentin Clement   matchAndRewrite(FromOp op, OpAdaptor adaptor,
2653ae8e442SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const final {
2663ae8e442SValentin Clement     mlir::Type ty = this->convertType(op.getType());
2673ae8e442SValentin Clement     return doRewrite(op, ty, adaptor, rewriter);
2683ae8e442SValentin Clement   }
2693ae8e442SValentin Clement 
2703ae8e442SValentin Clement   virtual mlir::LogicalResult
2713ae8e442SValentin Clement   doRewrite(FromOp addr, mlir::Type ty, OpAdaptor adaptor,
2723ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const = 0;
2733ae8e442SValentin Clement };
2743ae8e442SValentin Clement 
275420ad7ceSAndrzej Warzynski /// Create value signaling an absent optional argument in a call, e.g.
276420ad7ceSAndrzej Warzynski /// `fir.absent !fir.ref<i64>` -->  `llvm.mlir.null : !llvm.ptr<i64>`
277420ad7ceSAndrzej Warzynski struct AbsentOpConversion : public FIROpConversion<fir::AbsentOp> {
278420ad7ceSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
279420ad7ceSAndrzej Warzynski 
280420ad7ceSAndrzej Warzynski   mlir::LogicalResult
281420ad7ceSAndrzej Warzynski   matchAndRewrite(fir::AbsentOp absent, OpAdaptor,
282420ad7ceSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
283420ad7ceSAndrzej Warzynski     mlir::Type ty = convertType(absent.getType());
284420ad7ceSAndrzej Warzynski     mlir::Location loc = absent.getLoc();
285420ad7ceSAndrzej Warzynski 
286420ad7ceSAndrzej Warzynski     if (absent.getType().isa<fir::BoxCharType>()) {
287420ad7ceSAndrzej Warzynski       auto structTy = ty.cast<mlir::LLVM::LLVMStructType>();
288420ad7ceSAndrzej Warzynski       assert(!structTy.isOpaque() && !structTy.getBody().empty());
289420ad7ceSAndrzej Warzynski       auto undefStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
290420ad7ceSAndrzej Warzynski       auto nullField =
291420ad7ceSAndrzej Warzynski           rewriter.create<mlir::LLVM::NullOp>(loc, structTy.getBody()[0]);
292420ad7ceSAndrzej Warzynski       mlir::MLIRContext *ctx = absent.getContext();
293420ad7ceSAndrzej Warzynski       auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
294420ad7ceSAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
295420ad7ceSAndrzej Warzynski           absent, ty, undefStruct, nullField, c0);
296420ad7ceSAndrzej Warzynski     } else {
297420ad7ceSAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(absent, ty);
298420ad7ceSAndrzej Warzynski     }
299420ad7ceSAndrzej Warzynski     return success();
300420ad7ceSAndrzej Warzynski   }
301420ad7ceSAndrzej Warzynski };
302420ad7ceSAndrzej Warzynski 
3030c4a7a52SValentin Clement // Lower `fir.address_of` operation to `llvm.address_of` operation.
304044d5b5dSValentin Clement struct AddrOfOpConversion : public FIROpConversion<fir::AddrOfOp> {
305044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
306044d5b5dSValentin Clement 
307044d5b5dSValentin Clement   mlir::LogicalResult
308044d5b5dSValentin Clement   matchAndRewrite(fir::AddrOfOp addr, OpAdaptor adaptor,
309044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
310044d5b5dSValentin Clement     auto ty = convertType(addr.getType());
311044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::AddressOfOp>(
312044d5b5dSValentin Clement         addr, ty, addr.symbol().getRootReference().getValue());
313044d5b5dSValentin Clement     return success();
314044d5b5dSValentin Clement   }
315044d5b5dSValentin Clement };
3161e6d9c06SDiana Picus } // namespace
3171e6d9c06SDiana Picus 
3181e6d9c06SDiana Picus /// Lookup the function to compute the memory size of this parametric derived
3191e6d9c06SDiana Picus /// type. The size of the object may depend on the LEN type parameters of the
3201e6d9c06SDiana Picus /// derived type.
3211e6d9c06SDiana Picus static mlir::LLVM::LLVMFuncOp
3221e6d9c06SDiana Picus getDependentTypeMemSizeFn(fir::RecordType recTy, fir::AllocaOp op,
3231e6d9c06SDiana Picus                           mlir::ConversionPatternRewriter &rewriter) {
3241e6d9c06SDiana Picus   auto module = op->getParentOfType<mlir::ModuleOp>();
3251e6d9c06SDiana Picus   std::string name = recTy.getName().str() + "P.mem.size";
3261e6d9c06SDiana Picus   return module.lookupSymbol<mlir::LLVM::LLVMFuncOp>(name);
3271e6d9c06SDiana Picus }
3281e6d9c06SDiana Picus 
3291e6d9c06SDiana Picus namespace {
3301e6d9c06SDiana Picus /// convert to LLVM IR dialect `alloca`
3311e6d9c06SDiana Picus struct AllocaOpConversion : public FIROpConversion<fir::AllocaOp> {
3321e6d9c06SDiana Picus   using FIROpConversion::FIROpConversion;
3331e6d9c06SDiana Picus 
3341e6d9c06SDiana Picus   mlir::LogicalResult
3351e6d9c06SDiana Picus   matchAndRewrite(fir::AllocaOp alloc, OpAdaptor adaptor,
3361e6d9c06SDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
3371e6d9c06SDiana Picus     mlir::ValueRange operands = adaptor.getOperands();
3381e6d9c06SDiana Picus     auto loc = alloc.getLoc();
3391e6d9c06SDiana Picus     mlir::Type ity = lowerTy().indexType();
3401e6d9c06SDiana Picus     unsigned i = 0;
3411e6d9c06SDiana Picus     mlir::Value size = genConstantIndex(loc, ity, rewriter, 1).getResult();
3421e6d9c06SDiana Picus     mlir::Type ty = convertType(alloc.getType());
3431e6d9c06SDiana Picus     mlir::Type resultTy = ty;
3441e6d9c06SDiana Picus     if (alloc.hasLenParams()) {
3451e6d9c06SDiana Picus       unsigned end = alloc.numLenParams();
3461e6d9c06SDiana Picus       llvm::SmallVector<mlir::Value> lenParams;
3471e6d9c06SDiana Picus       for (; i < end; ++i)
3481e6d9c06SDiana Picus         lenParams.push_back(operands[i]);
3491e6d9c06SDiana Picus       mlir::Type scalarType = fir::unwrapSequenceType(alloc.getInType());
3501e6d9c06SDiana Picus       if (auto chrTy = scalarType.dyn_cast<fir::CharacterType>()) {
3511e6d9c06SDiana Picus         fir::CharacterType rawCharTy = fir::CharacterType::getUnknownLen(
3521e6d9c06SDiana Picus             chrTy.getContext(), chrTy.getFKind());
3531e6d9c06SDiana Picus         ty = mlir::LLVM::LLVMPointerType::get(convertType(rawCharTy));
3541e6d9c06SDiana Picus         assert(end == 1);
3551e6d9c06SDiana Picus         size = integerCast(loc, rewriter, ity, lenParams[0]);
3561e6d9c06SDiana Picus       } else if (auto recTy = scalarType.dyn_cast<fir::RecordType>()) {
3571e6d9c06SDiana Picus         mlir::LLVM::LLVMFuncOp memSizeFn =
3581e6d9c06SDiana Picus             getDependentTypeMemSizeFn(recTy, alloc, rewriter);
3591e6d9c06SDiana Picus         if (!memSizeFn)
3601e6d9c06SDiana Picus           emitError(loc, "did not find allocation function");
3611e6d9c06SDiana Picus         mlir::NamedAttribute attr = rewriter.getNamedAttr(
3621e6d9c06SDiana Picus             "callee", mlir::SymbolRefAttr::get(memSizeFn));
3631e6d9c06SDiana Picus         auto call = rewriter.create<mlir::LLVM::CallOp>(
3641e6d9c06SDiana Picus             loc, ity, lenParams, llvm::ArrayRef<mlir::NamedAttribute>{attr});
3651e6d9c06SDiana Picus         size = call.getResult(0);
3661e6d9c06SDiana Picus         ty = mlir::LLVM::LLVMPointerType::get(
3671e6d9c06SDiana Picus             mlir::IntegerType::get(alloc.getContext(), 8));
3681e6d9c06SDiana Picus       } else {
3691e6d9c06SDiana Picus         return emitError(loc, "unexpected type ")
3701e6d9c06SDiana Picus                << scalarType << " with type parameters";
3711e6d9c06SDiana Picus       }
3721e6d9c06SDiana Picus     }
3731e6d9c06SDiana Picus     if (alloc.hasShapeOperands()) {
3741e6d9c06SDiana Picus       mlir::Type allocEleTy = fir::unwrapRefType(alloc.getType());
3751e6d9c06SDiana Picus       // Scale the size by constant factors encoded in the array type.
376776d0ed6SDiana Picus       // We only do this for arrays that don't have a constant interior, since
377776d0ed6SDiana Picus       // those are the only ones that get decayed to a pointer to the element
378776d0ed6SDiana Picus       // type.
3791e6d9c06SDiana Picus       if (auto seqTy = allocEleTy.dyn_cast<fir::SequenceType>()) {
380776d0ed6SDiana Picus         if (!seqTy.hasConstantInterior()) {
3811e6d9c06SDiana Picus           fir::SequenceType::Extent constSize = 1;
3821e6d9c06SDiana Picus           for (auto extent : seqTy.getShape())
3831e6d9c06SDiana Picus             if (extent != fir::SequenceType::getUnknownExtent())
3841e6d9c06SDiana Picus               constSize *= extent;
3851e6d9c06SDiana Picus           mlir::Value constVal{
3861e6d9c06SDiana Picus               genConstantIndex(loc, ity, rewriter, constSize).getResult()};
3871e6d9c06SDiana Picus           size = rewriter.create<mlir::LLVM::MulOp>(loc, ity, size, constVal);
3881e6d9c06SDiana Picus         }
389776d0ed6SDiana Picus       }
3901e6d9c06SDiana Picus       unsigned end = operands.size();
3911e6d9c06SDiana Picus       for (; i < end; ++i)
3921e6d9c06SDiana Picus         size = rewriter.create<mlir::LLVM::MulOp>(
3931e6d9c06SDiana Picus             loc, ity, size, integerCast(loc, rewriter, ity, operands[i]));
3941e6d9c06SDiana Picus     }
3951e6d9c06SDiana Picus     if (ty == resultTy) {
3961e6d9c06SDiana Picus       // Do not emit the bitcast if ty and resultTy are the same.
3971e6d9c06SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::AllocaOp>(alloc, ty, size,
3981e6d9c06SDiana Picus                                                         alloc->getAttrs());
3991e6d9c06SDiana Picus     } else {
4001e6d9c06SDiana Picus       auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, ty, size,
4011e6d9c06SDiana Picus                                                       alloc->getAttrs());
4021e6d9c06SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(alloc, resultTy, al);
4031e6d9c06SDiana Picus     }
4041e6d9c06SDiana Picus     return success();
4051e6d9c06SDiana Picus   }
4061e6d9c06SDiana Picus };
407044d5b5dSValentin Clement 
408df3b9810SValentin Clement /// Lower `fir.box_addr` to the sequence of operations to extract the first
409df3b9810SValentin Clement /// element of the box.
410df3b9810SValentin Clement struct BoxAddrOpConversion : public FIROpConversion<fir::BoxAddrOp> {
411df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
412df3b9810SValentin Clement 
413df3b9810SValentin Clement   mlir::LogicalResult
414df3b9810SValentin Clement   matchAndRewrite(fir::BoxAddrOp boxaddr, OpAdaptor adaptor,
415df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
416df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
417df3b9810SValentin Clement     auto loc = boxaddr.getLoc();
418df3b9810SValentin Clement     mlir::Type ty = convertType(boxaddr.getType());
419df3b9810SValentin Clement     if (auto argty = boxaddr.val().getType().dyn_cast<fir::BoxType>()) {
420df3b9810SValentin Clement       rewriter.replaceOp(boxaddr, loadBaseAddrFromBox(loc, ty, a, rewriter));
421df3b9810SValentin Clement     } else {
422df3b9810SValentin Clement       auto c0attr = rewriter.getI32IntegerAttr(0);
423df3b9810SValentin Clement       auto c0 = mlir::ArrayAttr::get(boxaddr.getContext(), c0attr);
424df3b9810SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(boxaddr, ty, a,
425df3b9810SValentin Clement                                                               c0);
426df3b9810SValentin Clement     }
427df3b9810SValentin Clement     return success();
428df3b9810SValentin Clement   }
429df3b9810SValentin Clement };
430df3b9810SValentin Clement 
431df3b9810SValentin Clement /// Lower `fir.box_dims` to a sequence of operations to extract the requested
432df3b9810SValentin Clement /// dimension infomartion from the boxed value.
433df3b9810SValentin Clement /// Result in a triple set of GEPs and loads.
434df3b9810SValentin Clement struct BoxDimsOpConversion : public FIROpConversion<fir::BoxDimsOp> {
435df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
436df3b9810SValentin Clement 
437df3b9810SValentin Clement   mlir::LogicalResult
438df3b9810SValentin Clement   matchAndRewrite(fir::BoxDimsOp boxdims, OpAdaptor adaptor,
439df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
440df3b9810SValentin Clement     SmallVector<mlir::Type, 3> resultTypes = {
441df3b9810SValentin Clement         convertType(boxdims.getResult(0).getType()),
442df3b9810SValentin Clement         convertType(boxdims.getResult(1).getType()),
443df3b9810SValentin Clement         convertType(boxdims.getResult(2).getType()),
444df3b9810SValentin Clement     };
445df3b9810SValentin Clement     auto results =
446df3b9810SValentin Clement         getDimsFromBox(boxdims.getLoc(), resultTypes, adaptor.getOperands()[0],
447df3b9810SValentin Clement                        adaptor.getOperands()[1], rewriter);
448df3b9810SValentin Clement     rewriter.replaceOp(boxdims, results);
449df3b9810SValentin Clement     return success();
450df3b9810SValentin Clement   }
451df3b9810SValentin Clement };
452df3b9810SValentin Clement 
453df3b9810SValentin Clement /// Lower `fir.box_elesize` to a sequence of operations ro extract the size of
454df3b9810SValentin Clement /// an element in the boxed value.
455df3b9810SValentin Clement struct BoxEleSizeOpConversion : public FIROpConversion<fir::BoxEleSizeOp> {
456df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
457df3b9810SValentin Clement 
458df3b9810SValentin Clement   mlir::LogicalResult
459df3b9810SValentin Clement   matchAndRewrite(fir::BoxEleSizeOp boxelesz, OpAdaptor adaptor,
460df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
461df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
462df3b9810SValentin Clement     auto loc = boxelesz.getLoc();
463df3b9810SValentin Clement     auto ty = convertType(boxelesz.getType());
464b6e44ecdSValentin Clement     auto elemSize = getValueFromBox(loc, a, ty, rewriter, kElemLenPosInBox);
465b6e44ecdSValentin Clement     rewriter.replaceOp(boxelesz, elemSize);
466b6e44ecdSValentin Clement     return success();
467b6e44ecdSValentin Clement   }
468b6e44ecdSValentin Clement };
469b6e44ecdSValentin Clement 
470b6e44ecdSValentin Clement /// Lower `fir.box_isalloc` to a sequence of operations to determine if the
471b6e44ecdSValentin Clement /// boxed value was from an ALLOCATABLE entity.
472b6e44ecdSValentin Clement struct BoxIsAllocOpConversion : public FIROpConversion<fir::BoxIsAllocOp> {
473b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
474b6e44ecdSValentin Clement 
475b6e44ecdSValentin Clement   mlir::LogicalResult
476b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsAllocOp boxisalloc, OpAdaptor adaptor,
477b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
478b6e44ecdSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
479b6e44ecdSValentin Clement     auto loc = boxisalloc.getLoc();
480b6e44ecdSValentin Clement     mlir::Value check =
481b6e44ecdSValentin Clement         genBoxAttributeCheck(loc, box, rewriter, kAttrAllocatable);
482b6e44ecdSValentin Clement     rewriter.replaceOp(boxisalloc, check);
483b6e44ecdSValentin Clement     return success();
484b6e44ecdSValentin Clement   }
485b6e44ecdSValentin Clement };
486b6e44ecdSValentin Clement 
487b6e44ecdSValentin Clement /// Lower `fir.box_isarray` to a sequence of operations to determine if the
488b6e44ecdSValentin Clement /// boxed is an array.
489b6e44ecdSValentin Clement struct BoxIsArrayOpConversion : public FIROpConversion<fir::BoxIsArrayOp> {
490b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
491b6e44ecdSValentin Clement 
492b6e44ecdSValentin Clement   mlir::LogicalResult
493b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsArrayOp boxisarray, OpAdaptor adaptor,
494b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
495b6e44ecdSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
496b6e44ecdSValentin Clement     auto loc = boxisarray.getLoc();
497b6e44ecdSValentin Clement     auto rank =
498b6e44ecdSValentin Clement         getValueFromBox(loc, a, rewriter.getI32Type(), rewriter, kRankPosInBox);
499b6e44ecdSValentin Clement     auto c0 = genConstantOffset(loc, rewriter, 0);
500b6e44ecdSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
501b6e44ecdSValentin Clement         boxisarray, mlir::LLVM::ICmpPredicate::ne, rank, c0);
502b6e44ecdSValentin Clement     return success();
503b6e44ecdSValentin Clement   }
504b6e44ecdSValentin Clement };
505b6e44ecdSValentin Clement 
506b6e44ecdSValentin Clement /// Lower `fir.box_isptr` to a sequence of operations to determined if the
507b6e44ecdSValentin Clement /// boxed value was from a POINTER entity.
508b6e44ecdSValentin Clement struct BoxIsPtrOpConversion : public FIROpConversion<fir::BoxIsPtrOp> {
509b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
510b6e44ecdSValentin Clement 
511b6e44ecdSValentin Clement   mlir::LogicalResult
512b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsPtrOp boxisptr, OpAdaptor adaptor,
513b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
514b6e44ecdSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
515b6e44ecdSValentin Clement     auto loc = boxisptr.getLoc();
516b6e44ecdSValentin Clement     mlir::Value check = genBoxAttributeCheck(loc, box, rewriter, kAttrPointer);
517b6e44ecdSValentin Clement     rewriter.replaceOp(boxisptr, check);
518df3b9810SValentin Clement     return success();
519df3b9810SValentin Clement   }
520df3b9810SValentin Clement };
521df3b9810SValentin Clement 
522df3b9810SValentin Clement /// Lower `fir.box_rank` to the sequence of operation to extract the rank from
523df3b9810SValentin Clement /// the box.
524df3b9810SValentin Clement struct BoxRankOpConversion : public FIROpConversion<fir::BoxRankOp> {
525df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
526df3b9810SValentin Clement 
527df3b9810SValentin Clement   mlir::LogicalResult
528df3b9810SValentin Clement   matchAndRewrite(fir::BoxRankOp boxrank, OpAdaptor adaptor,
529df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
530df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
531df3b9810SValentin Clement     auto loc = boxrank.getLoc();
532df3b9810SValentin Clement     mlir::Type ty = convertType(boxrank.getType());
533b6e44ecdSValentin Clement     auto result = getValueFromBox(loc, a, ty, rewriter, kRankPosInBox);
534df3b9810SValentin Clement     rewriter.replaceOp(boxrank, result);
535df3b9810SValentin Clement     return success();
536df3b9810SValentin Clement   }
537df3b9810SValentin Clement };
538df3b9810SValentin Clement 
5391a2ec667SValentin Clement /// Lower `fir.string_lit` to LLVM IR dialect operation.
5401a2ec667SValentin Clement struct StringLitOpConversion : public FIROpConversion<fir::StringLitOp> {
5411a2ec667SValentin Clement   using FIROpConversion::FIROpConversion;
5421a2ec667SValentin Clement 
5431a2ec667SValentin Clement   mlir::LogicalResult
5441a2ec667SValentin Clement   matchAndRewrite(fir::StringLitOp constop, OpAdaptor adaptor,
5451a2ec667SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
5461a2ec667SValentin Clement     auto ty = convertType(constop.getType());
5471a2ec667SValentin Clement     auto attr = constop.getValue();
5481a2ec667SValentin Clement     if (attr.isa<mlir::StringAttr>()) {
5491a2ec667SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(constop, ty, attr);
5501a2ec667SValentin Clement       return success();
5511a2ec667SValentin Clement     }
5521a2ec667SValentin Clement 
5531a2ec667SValentin Clement     auto arr = attr.cast<mlir::ArrayAttr>();
5541a2ec667SValentin Clement     auto charTy = constop.getType().cast<fir::CharacterType>();
5551a2ec667SValentin Clement     unsigned bits = lowerTy().characterBitsize(charTy);
5561a2ec667SValentin Clement     mlir::Type intTy = rewriter.getIntegerType(bits);
5571a2ec667SValentin Clement     auto attrs = llvm::map_range(
5581a2ec667SValentin Clement         arr.getValue(), [intTy, bits](mlir::Attribute attr) -> Attribute {
5591a2ec667SValentin Clement           return mlir::IntegerAttr::get(
5601a2ec667SValentin Clement               intTy,
5611a2ec667SValentin Clement               attr.cast<mlir::IntegerAttr>().getValue().sextOrTrunc(bits));
5621a2ec667SValentin Clement         });
5631a2ec667SValentin Clement     mlir::Type vecType = mlir::VectorType::get(arr.size(), intTy);
5641a2ec667SValentin Clement     auto denseAttr = mlir::DenseElementsAttr::get(
5651a2ec667SValentin Clement         vecType.cast<mlir::ShapedType>(), llvm::to_vector<8>(attrs));
5661a2ec667SValentin Clement     rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(constop, ty,
5671a2ec667SValentin Clement                                                          denseAttr);
5681a2ec667SValentin Clement     return success();
5691a2ec667SValentin Clement   }
5701a2ec667SValentin Clement };
5711a2ec667SValentin Clement 
572cc505c0bSKiran Chandramohan /// Lower `fir.boxproc_host` operation. Extracts the host pointer from the
573cc505c0bSKiran Chandramohan /// boxproc.
574cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
575cc505c0bSKiran Chandramohan struct BoxProcHostOpConversion : public FIROpConversion<fir::BoxProcHostOp> {
576cc505c0bSKiran Chandramohan   using FIROpConversion::FIROpConversion;
577cc505c0bSKiran Chandramohan 
578cc505c0bSKiran Chandramohan   mlir::LogicalResult
579cc505c0bSKiran Chandramohan   matchAndRewrite(fir::BoxProcHostOp boxprochost, OpAdaptor adaptor,
580cc505c0bSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
5817ce8c6fcSKiran Chandramohan     TODO(boxprochost.getLoc(), "fir.boxproc_host codegen");
5827ce8c6fcSKiran Chandramohan     return failure();
583cc505c0bSKiran Chandramohan   }
584cc505c0bSKiran Chandramohan };
585cc505c0bSKiran Chandramohan 
586e38ef2ffSValentin Clement /// Lower `fir.box_tdesc` to the sequence of operations to extract the type
587e38ef2ffSValentin Clement /// descriptor from the box.
588e38ef2ffSValentin Clement struct BoxTypeDescOpConversion : public FIROpConversion<fir::BoxTypeDescOp> {
589e38ef2ffSValentin Clement   using FIROpConversion::FIROpConversion;
590e38ef2ffSValentin Clement 
591e38ef2ffSValentin Clement   mlir::LogicalResult
592e38ef2ffSValentin Clement   matchAndRewrite(fir::BoxTypeDescOp boxtypedesc, OpAdaptor adaptor,
593e38ef2ffSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
594e38ef2ffSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
595e38ef2ffSValentin Clement     auto loc = boxtypedesc.getLoc();
596e38ef2ffSValentin Clement     mlir::Type typeTy =
597e38ef2ffSValentin Clement         fir::getDescFieldTypeModel<kTypePosInBox>()(boxtypedesc.getContext());
598e38ef2ffSValentin Clement     auto result = getValueFromBox(loc, box, typeTy, rewriter, kTypePosInBox);
599e38ef2ffSValentin Clement     auto typePtrTy = mlir::LLVM::LLVMPointerType::get(typeTy);
600e38ef2ffSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(boxtypedesc, typePtrTy,
601e38ef2ffSValentin Clement                                                         result);
602e38ef2ffSValentin Clement     return success();
603e38ef2ffSValentin Clement   }
604e38ef2ffSValentin Clement };
605e38ef2ffSValentin Clement 
606ddd11b9aSAndrzej Warzynski // `fir.call` -> `llvm.call`
607ddd11b9aSAndrzej Warzynski struct CallOpConversion : public FIROpConversion<fir::CallOp> {
608ddd11b9aSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
609ddd11b9aSAndrzej Warzynski 
610ddd11b9aSAndrzej Warzynski   mlir::LogicalResult
611ddd11b9aSAndrzej Warzynski   matchAndRewrite(fir::CallOp call, OpAdaptor adaptor,
612ddd11b9aSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
613ddd11b9aSAndrzej Warzynski     SmallVector<mlir::Type> resultTys;
614ddd11b9aSAndrzej Warzynski     for (auto r : call.getResults())
615ddd11b9aSAndrzej Warzynski       resultTys.push_back(convertType(r.getType()));
616ddd11b9aSAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
617ddd11b9aSAndrzej Warzynski         call, resultTys, adaptor.getOperands(), call->getAttrs());
618ddd11b9aSAndrzej Warzynski     return success();
619ddd11b9aSAndrzej Warzynski   }
620ddd11b9aSAndrzej Warzynski };
621c2acd453SAlexisPerry } // namespace
622ddd11b9aSAndrzej Warzynski 
623092cee5fSValentin Clement static mlir::Type getComplexEleTy(mlir::Type complex) {
624092cee5fSValentin Clement   if (auto cc = complex.dyn_cast<mlir::ComplexType>())
625092cee5fSValentin Clement     return cc.getElementType();
626092cee5fSValentin Clement   return complex.cast<fir::ComplexType>().getElementType();
627092cee5fSValentin Clement }
628092cee5fSValentin Clement 
629c2acd453SAlexisPerry namespace {
630f1dfc027SDiana Picus /// Compare complex values
631f1dfc027SDiana Picus ///
632f1dfc027SDiana Picus /// Per 10.1, the only comparisons available are .EQ. (oeq) and .NE. (une).
633f1dfc027SDiana Picus ///
634f1dfc027SDiana Picus /// For completeness, all other comparison are done on the real component only.
635f1dfc027SDiana Picus struct CmpcOpConversion : public FIROpConversion<fir::CmpcOp> {
636f1dfc027SDiana Picus   using FIROpConversion::FIROpConversion;
637f1dfc027SDiana Picus 
638f1dfc027SDiana Picus   mlir::LogicalResult
639f1dfc027SDiana Picus   matchAndRewrite(fir::CmpcOp cmp, OpAdaptor adaptor,
640f1dfc027SDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
641f1dfc027SDiana Picus     mlir::ValueRange operands = adaptor.getOperands();
642f1dfc027SDiana Picus     mlir::MLIRContext *ctxt = cmp.getContext();
643f1dfc027SDiana Picus     mlir::Type eleTy = convertType(getComplexEleTy(cmp.lhs().getType()));
644f1dfc027SDiana Picus     mlir::Type resTy = convertType(cmp.getType());
645f1dfc027SDiana Picus     mlir::Location loc = cmp.getLoc();
646f1dfc027SDiana Picus     auto pos0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0));
647f1dfc027SDiana Picus     SmallVector<mlir::Value, 2> rp{rewriter.create<mlir::LLVM::ExtractValueOp>(
648f1dfc027SDiana Picus                                        loc, eleTy, operands[0], pos0),
649f1dfc027SDiana Picus                                    rewriter.create<mlir::LLVM::ExtractValueOp>(
650f1dfc027SDiana Picus                                        loc, eleTy, operands[1], pos0)};
651f1dfc027SDiana Picus     auto rcp =
652f1dfc027SDiana Picus         rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, rp, cmp->getAttrs());
653f1dfc027SDiana Picus     auto pos1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1));
654f1dfc027SDiana Picus     SmallVector<mlir::Value, 2> ip{rewriter.create<mlir::LLVM::ExtractValueOp>(
655f1dfc027SDiana Picus                                        loc, eleTy, operands[0], pos1),
656f1dfc027SDiana Picus                                    rewriter.create<mlir::LLVM::ExtractValueOp>(
657f1dfc027SDiana Picus                                        loc, eleTy, operands[1], pos1)};
658f1dfc027SDiana Picus     auto icp =
659f1dfc027SDiana Picus         rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, ip, cmp->getAttrs());
660f1dfc027SDiana Picus     SmallVector<mlir::Value, 2> cp{rcp, icp};
661f1dfc027SDiana Picus     switch (cmp.getPredicate()) {
662f1dfc027SDiana Picus     case mlir::arith::CmpFPredicate::OEQ: // .EQ.
663f1dfc027SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(cmp, resTy, cp);
664f1dfc027SDiana Picus       break;
665f1dfc027SDiana Picus     case mlir::arith::CmpFPredicate::UNE: // .NE.
666f1dfc027SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(cmp, resTy, cp);
667f1dfc027SDiana Picus       break;
668f1dfc027SDiana Picus     default:
669f1dfc027SDiana Picus       rewriter.replaceOp(cmp, rcp.getResult());
670f1dfc027SDiana Picus       break;
671f1dfc027SDiana Picus     }
672f1dfc027SDiana Picus     return success();
673f1dfc027SDiana Picus   }
674f1dfc027SDiana Picus };
675f1dfc027SDiana Picus 
676e81d73edSDiana Picus /// Lower complex constants
677e81d73edSDiana Picus struct ConstcOpConversion : public FIROpConversion<fir::ConstcOp> {
678e81d73edSDiana Picus   using FIROpConversion::FIROpConversion;
679e81d73edSDiana Picus 
680e81d73edSDiana Picus   mlir::LogicalResult
681e81d73edSDiana Picus   matchAndRewrite(fir::ConstcOp conc, OpAdaptor,
682e81d73edSDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
683e81d73edSDiana Picus     mlir::Location loc = conc.getLoc();
684e81d73edSDiana Picus     mlir::MLIRContext *ctx = conc.getContext();
685e81d73edSDiana Picus     mlir::Type ty = convertType(conc.getType());
686e81d73edSDiana Picus     mlir::Type ety = convertType(getComplexEleTy(conc.getType()));
687e81d73edSDiana Picus     auto realFloatAttr = mlir::FloatAttr::get(ety, getValue(conc.getReal()));
688e81d73edSDiana Picus     auto realPart =
689e81d73edSDiana Picus         rewriter.create<mlir::LLVM::ConstantOp>(loc, ety, realFloatAttr);
690e81d73edSDiana Picus     auto imFloatAttr = mlir::FloatAttr::get(ety, getValue(conc.getImaginary()));
691e81d73edSDiana Picus     auto imPart =
692e81d73edSDiana Picus         rewriter.create<mlir::LLVM::ConstantOp>(loc, ety, imFloatAttr);
693e81d73edSDiana Picus     auto realIndex = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
694e81d73edSDiana Picus     auto imIndex = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
695e81d73edSDiana Picus     auto undef = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
696e81d73edSDiana Picus     auto setReal = rewriter.create<mlir::LLVM::InsertValueOp>(
697e81d73edSDiana Picus         loc, ty, undef, realPart, realIndex);
698e81d73edSDiana Picus     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(conc, ty, setReal,
699e81d73edSDiana Picus                                                            imPart, imIndex);
700e81d73edSDiana Picus     return success();
701e81d73edSDiana Picus   }
702e81d73edSDiana Picus 
703e81d73edSDiana Picus   inline APFloat getValue(mlir::Attribute attr) const {
704e81d73edSDiana Picus     return attr.cast<fir::RealAttr>().getValue();
705e81d73edSDiana Picus   }
706e81d73edSDiana Picus };
707e81d73edSDiana Picus 
708092cee5fSValentin Clement /// convert value of from-type to value of to-type
709092cee5fSValentin Clement struct ConvertOpConversion : public FIROpConversion<fir::ConvertOp> {
710092cee5fSValentin Clement   using FIROpConversion::FIROpConversion;
711092cee5fSValentin Clement 
712092cee5fSValentin Clement   static bool isFloatingPointTy(mlir::Type ty) {
713092cee5fSValentin Clement     return ty.isa<mlir::FloatType>();
714092cee5fSValentin Clement   }
715092cee5fSValentin Clement 
716092cee5fSValentin Clement   mlir::LogicalResult
717092cee5fSValentin Clement   matchAndRewrite(fir::ConvertOp convert, OpAdaptor adaptor,
718092cee5fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
719092cee5fSValentin Clement     auto fromTy = convertType(convert.value().getType());
720092cee5fSValentin Clement     auto toTy = convertType(convert.res().getType());
721092cee5fSValentin Clement     mlir::Value op0 = adaptor.getOperands()[0];
722092cee5fSValentin Clement     if (fromTy == toTy) {
723092cee5fSValentin Clement       rewriter.replaceOp(convert, op0);
724092cee5fSValentin Clement       return success();
725092cee5fSValentin Clement     }
726092cee5fSValentin Clement     auto loc = convert.getLoc();
727092cee5fSValentin Clement     auto convertFpToFp = [&](mlir::Value val, unsigned fromBits,
728092cee5fSValentin Clement                              unsigned toBits, mlir::Type toTy) -> mlir::Value {
729092cee5fSValentin Clement       if (fromBits == toBits) {
730092cee5fSValentin Clement         // TODO: Converting between two floating-point representations with the
731092cee5fSValentin Clement         // same bitwidth is not allowed for now.
732092cee5fSValentin Clement         mlir::emitError(loc,
733092cee5fSValentin Clement                         "cannot implicitly convert between two floating-point "
734092cee5fSValentin Clement                         "representations of the same bitwidth");
735092cee5fSValentin Clement         return {};
736092cee5fSValentin Clement       }
737092cee5fSValentin Clement       if (fromBits > toBits)
738092cee5fSValentin Clement         return rewriter.create<mlir::LLVM::FPTruncOp>(loc, toTy, val);
739092cee5fSValentin Clement       return rewriter.create<mlir::LLVM::FPExtOp>(loc, toTy, val);
740092cee5fSValentin Clement     };
741092cee5fSValentin Clement     // Complex to complex conversion.
742092cee5fSValentin Clement     if (fir::isa_complex(convert.value().getType()) &&
743092cee5fSValentin Clement         fir::isa_complex(convert.res().getType())) {
744092cee5fSValentin Clement       // Special case: handle the conversion of a complex such that both the
745092cee5fSValentin Clement       // real and imaginary parts are converted together.
746092cee5fSValentin Clement       auto zero = mlir::ArrayAttr::get(convert.getContext(),
747092cee5fSValentin Clement                                        rewriter.getI32IntegerAttr(0));
748092cee5fSValentin Clement       auto one = mlir::ArrayAttr::get(convert.getContext(),
749092cee5fSValentin Clement                                       rewriter.getI32IntegerAttr(1));
750092cee5fSValentin Clement       auto ty = convertType(getComplexEleTy(convert.value().getType()));
751092cee5fSValentin Clement       auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, zero);
752092cee5fSValentin Clement       auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, one);
753092cee5fSValentin Clement       auto nt = convertType(getComplexEleTy(convert.res().getType()));
754092cee5fSValentin Clement       auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
755092cee5fSValentin Clement       auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(nt);
756092cee5fSValentin Clement       auto rc = convertFpToFp(rp, fromBits, toBits, nt);
757092cee5fSValentin Clement       auto ic = convertFpToFp(ip, fromBits, toBits, nt);
758092cee5fSValentin Clement       auto un = rewriter.create<mlir::LLVM::UndefOp>(loc, toTy);
759092cee5fSValentin Clement       auto i1 =
760092cee5fSValentin Clement           rewriter.create<mlir::LLVM::InsertValueOp>(loc, toTy, un, rc, zero);
761092cee5fSValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(convert, toTy, i1,
762092cee5fSValentin Clement                                                              ic, one);
763092cee5fSValentin Clement       return mlir::success();
764092cee5fSValentin Clement     }
765092cee5fSValentin Clement     // Floating point to floating point conversion.
766092cee5fSValentin Clement     if (isFloatingPointTy(fromTy)) {
767092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
768092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
769092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
770092cee5fSValentin Clement         auto v = convertFpToFp(op0, fromBits, toBits, toTy);
771092cee5fSValentin Clement         rewriter.replaceOp(convert, v);
772092cee5fSValentin Clement         return mlir::success();
773092cee5fSValentin Clement       }
774092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
775092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::FPToSIOp>(convert, toTy, op0);
776092cee5fSValentin Clement         return mlir::success();
777092cee5fSValentin Clement       }
778092cee5fSValentin Clement     } else if (fromTy.isa<mlir::IntegerType>()) {
779092cee5fSValentin Clement       // Integer to integer conversion.
780092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
781092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
782092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
783092cee5fSValentin Clement         assert(fromBits != toBits);
784092cee5fSValentin Clement         if (fromBits > toBits) {
785092cee5fSValentin Clement           rewriter.replaceOpWithNewOp<mlir::LLVM::TruncOp>(convert, toTy, op0);
786092cee5fSValentin Clement           return mlir::success();
787092cee5fSValentin Clement         }
788092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SExtOp>(convert, toTy, op0);
789092cee5fSValentin Clement         return mlir::success();
790092cee5fSValentin Clement       }
791092cee5fSValentin Clement       // Integer to floating point conversion.
792092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
793092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SIToFPOp>(convert, toTy, op0);
794092cee5fSValentin Clement         return mlir::success();
795092cee5fSValentin Clement       }
796092cee5fSValentin Clement       // Integer to pointer conversion.
797092cee5fSValentin Clement       if (toTy.isa<mlir::LLVM::LLVMPointerType>()) {
798092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(convert, toTy, op0);
799092cee5fSValentin Clement         return mlir::success();
800092cee5fSValentin Clement       }
801092cee5fSValentin Clement     } else if (fromTy.isa<mlir::LLVM::LLVMPointerType>()) {
802092cee5fSValentin Clement       // Pointer to integer conversion.
803092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
804092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::PtrToIntOp>(convert, toTy, op0);
805092cee5fSValentin Clement         return mlir::success();
806092cee5fSValentin Clement       }
807092cee5fSValentin Clement       // Pointer to pointer conversion.
808092cee5fSValentin Clement       if (toTy.isa<mlir::LLVM::LLVMPointerType>()) {
809092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(convert, toTy, op0);
810092cee5fSValentin Clement         return mlir::success();
811092cee5fSValentin Clement       }
812092cee5fSValentin Clement     }
813092cee5fSValentin Clement     return emitError(loc) << "cannot convert " << fromTy << " to " << toTy;
814092cee5fSValentin Clement   }
815092cee5fSValentin Clement };
816092cee5fSValentin Clement 
8179534e361SValentin Clement /// Lower `fir.dispatch` operation. A virtual call to a method in a dispatch
8189534e361SValentin Clement /// table.
8199534e361SValentin Clement struct DispatchOpConversion : public FIROpConversion<fir::DispatchOp> {
8209534e361SValentin Clement   using FIROpConversion::FIROpConversion;
8219534e361SValentin Clement 
8229534e361SValentin Clement   mlir::LogicalResult
8239534e361SValentin Clement   matchAndRewrite(fir::DispatchOp dispatch, OpAdaptor adaptor,
8249534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8257ce8c6fcSKiran Chandramohan     TODO(dispatch.getLoc(), "fir.dispatch codegen");
8267ce8c6fcSKiran Chandramohan     return failure();
8279534e361SValentin Clement   }
8289534e361SValentin Clement };
8299534e361SValentin Clement 
8309534e361SValentin Clement /// Lower `fir.dispatch_table` operation. The dispatch table for a Fortran
8319534e361SValentin Clement /// derived type.
8329534e361SValentin Clement struct DispatchTableOpConversion
8339534e361SValentin Clement     : public FIROpConversion<fir::DispatchTableOp> {
8349534e361SValentin Clement   using FIROpConversion::FIROpConversion;
8359534e361SValentin Clement 
8369534e361SValentin Clement   mlir::LogicalResult
8379534e361SValentin Clement   matchAndRewrite(fir::DispatchTableOp dispTab, OpAdaptor adaptor,
8389534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8397ce8c6fcSKiran Chandramohan     TODO(dispTab.getLoc(), "fir.dispatch_table codegen");
8407ce8c6fcSKiran Chandramohan     return failure();
8419534e361SValentin Clement   }
8429534e361SValentin Clement };
8439534e361SValentin Clement 
8449534e361SValentin Clement /// Lower `fir.dt_entry` operation. An entry in a dispatch table; binds a
8459534e361SValentin Clement /// method-name to a function.
8469534e361SValentin Clement struct DTEntryOpConversion : public FIROpConversion<fir::DTEntryOp> {
8479534e361SValentin Clement   using FIROpConversion::FIROpConversion;
8489534e361SValentin Clement 
8499534e361SValentin Clement   mlir::LogicalResult
8509534e361SValentin Clement   matchAndRewrite(fir::DTEntryOp dtEnt, OpAdaptor adaptor,
8519534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8527ce8c6fcSKiran Chandramohan     TODO(dtEnt.getLoc(), "fir.dt_entry codegen");
8537ce8c6fcSKiran Chandramohan     return failure();
8549534e361SValentin Clement   }
8559534e361SValentin Clement };
8569534e361SValentin Clement 
857677df8c7SValentin Clement /// Lower `fir.global_len` operation.
858677df8c7SValentin Clement struct GlobalLenOpConversion : public FIROpConversion<fir::GlobalLenOp> {
859677df8c7SValentin Clement   using FIROpConversion::FIROpConversion;
860677df8c7SValentin Clement 
861677df8c7SValentin Clement   mlir::LogicalResult
862677df8c7SValentin Clement   matchAndRewrite(fir::GlobalLenOp globalLen, OpAdaptor adaptor,
863677df8c7SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8647ce8c6fcSKiran Chandramohan     TODO(globalLen.getLoc(), "fir.global_len codegen");
8657ce8c6fcSKiran Chandramohan     return failure();
866677df8c7SValentin Clement   }
867677df8c7SValentin Clement };
868677df8c7SValentin Clement 
869cdc476abSDiana Picus /// Lower fir.len_param_index
870cdc476abSDiana Picus struct LenParamIndexOpConversion
871cdc476abSDiana Picus     : public FIROpConversion<fir::LenParamIndexOp> {
872cdc476abSDiana Picus   using FIROpConversion::FIROpConversion;
873cdc476abSDiana Picus 
874cdc476abSDiana Picus   // FIXME: this should be specialized by the runtime target
875cdc476abSDiana Picus   mlir::LogicalResult
876cdc476abSDiana Picus   matchAndRewrite(fir::LenParamIndexOp lenp, OpAdaptor,
877cdc476abSDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
8787ce8c6fcSKiran Chandramohan     TODO(lenp.getLoc(), "fir.len_param_index codegen");
879cdc476abSDiana Picus   }
880cdc476abSDiana Picus };
881cdc476abSDiana Picus 
88231246187SValentin Clement /// Lower `fir.gentypedesc` to a global constant.
88331246187SValentin Clement struct GenTypeDescOpConversion : public FIROpConversion<fir::GenTypeDescOp> {
88431246187SValentin Clement   using FIROpConversion::FIROpConversion;
88531246187SValentin Clement 
88631246187SValentin Clement   mlir::LogicalResult
88731246187SValentin Clement   matchAndRewrite(fir::GenTypeDescOp gentypedesc, OpAdaptor adaptor,
88831246187SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8897ce8c6fcSKiran Chandramohan     TODO(gentypedesc.getLoc(), "fir.gentypedesc codegen");
8907ce8c6fcSKiran Chandramohan     return failure();
89131246187SValentin Clement   }
89231246187SValentin Clement };
893c2acd453SAlexisPerry } // namespace
894c2acd453SAlexisPerry 
895c2acd453SAlexisPerry /// Return the LLVMFuncOp corresponding to the standard malloc call.
896c2acd453SAlexisPerry static mlir::LLVM::LLVMFuncOp
897c2acd453SAlexisPerry getMalloc(fir::AllocMemOp op, mlir::ConversionPatternRewriter &rewriter) {
898c2acd453SAlexisPerry   auto module = op->getParentOfType<mlir::ModuleOp>();
899c2acd453SAlexisPerry   if (mlir::LLVM::LLVMFuncOp mallocFunc =
900c2acd453SAlexisPerry           module.lookupSymbol<mlir::LLVM::LLVMFuncOp>("malloc"))
901c2acd453SAlexisPerry     return mallocFunc;
902c2acd453SAlexisPerry   mlir::OpBuilder moduleBuilder(
903c2acd453SAlexisPerry       op->getParentOfType<mlir::ModuleOp>().getBodyRegion());
904c2acd453SAlexisPerry   auto indexType = mlir::IntegerType::get(op.getContext(), 64);
905c2acd453SAlexisPerry   return moduleBuilder.create<mlir::LLVM::LLVMFuncOp>(
906c2acd453SAlexisPerry       rewriter.getUnknownLoc(), "malloc",
907c2acd453SAlexisPerry       mlir::LLVM::LLVMFunctionType::get(getVoidPtrType(op.getContext()),
908c2acd453SAlexisPerry                                         indexType,
909c2acd453SAlexisPerry                                         /*isVarArg=*/false));
910c2acd453SAlexisPerry }
911c2acd453SAlexisPerry 
912c2acd453SAlexisPerry /// Helper function for generating the LLVM IR that computes the size
913c2acd453SAlexisPerry /// in bytes for a derived type.
914c2acd453SAlexisPerry static mlir::Value
915c2acd453SAlexisPerry computeDerivedTypeSize(mlir::Location loc, mlir::Type ptrTy, mlir::Type idxTy,
916c2acd453SAlexisPerry                        mlir::ConversionPatternRewriter &rewriter) {
917c2acd453SAlexisPerry   auto nullPtr = rewriter.create<mlir::LLVM::NullOp>(loc, ptrTy);
918c2acd453SAlexisPerry   mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1);
91930122656SAlex Zinenko   llvm::SmallVector<mlir::Value> args{one};
92030122656SAlex Zinenko   auto gep = rewriter.create<mlir::LLVM::GEPOp>(loc, ptrTy, nullPtr, args);
921c2acd453SAlexisPerry   return rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, gep);
922c2acd453SAlexisPerry }
923c2acd453SAlexisPerry 
924c2acd453SAlexisPerry namespace {
925c2acd453SAlexisPerry /// Lower a `fir.allocmem` instruction into `llvm.call @malloc`
926c2acd453SAlexisPerry struct AllocMemOpConversion : public FIROpConversion<fir::AllocMemOp> {
927c2acd453SAlexisPerry   using FIROpConversion::FIROpConversion;
928c2acd453SAlexisPerry 
929c2acd453SAlexisPerry   mlir::LogicalResult
930c2acd453SAlexisPerry   matchAndRewrite(fir::AllocMemOp heap, OpAdaptor adaptor,
931c2acd453SAlexisPerry                   mlir::ConversionPatternRewriter &rewriter) const override {
932c45bd4b9SEric Schweitz     auto heapTy = heap.getType();
933c45bd4b9SEric Schweitz     auto ty = convertType(heapTy);
934c2acd453SAlexisPerry     mlir::LLVM::LLVMFuncOp mallocFunc = getMalloc(heap, rewriter);
935c2acd453SAlexisPerry     mlir::Location loc = heap.getLoc();
936c2acd453SAlexisPerry     auto ity = lowerTy().indexType();
937c45bd4b9SEric Schweitz     auto dataTy = fir::unwrapRefType(heapTy);
938c45bd4b9SEric Schweitz     if (fir::isRecordWithTypeParameters(fir::unwrapSequenceType(dataTy)))
939c45bd4b9SEric Schweitz       TODO(loc, "fir.allocmem codegen of derived type with length parameters");
940c2acd453SAlexisPerry     mlir::Value size = genTypeSizeInBytes(loc, ity, rewriter, ty);
941c45bd4b9SEric Schweitz     // !fir.array<NxMx!fir.char<K,?>> sets `size` to the width of !fir.char<K>.
942c45bd4b9SEric Schweitz     // So multiply the constant dimensions here.
943c45bd4b9SEric Schweitz     if (fir::hasDynamicSize(dataTy))
944c45bd4b9SEric Schweitz       if (auto seqTy = dataTy.dyn_cast<fir::SequenceType>())
945c45bd4b9SEric Schweitz         if (fir::characterWithDynamicLen(seqTy.getEleTy())) {
946c45bd4b9SEric Schweitz           fir::SequenceType::Extent arrSize = 1;
947c45bd4b9SEric Schweitz           for (auto d : seqTy.getShape())
948c45bd4b9SEric Schweitz             if (d != fir::SequenceType::getUnknownExtent())
949c45bd4b9SEric Schweitz               arrSize *= d;
950c45bd4b9SEric Schweitz           size = rewriter.create<mlir::LLVM::MulOp>(
951c45bd4b9SEric Schweitz               loc, ity, size, genConstantIndex(loc, ity, rewriter, arrSize));
952c45bd4b9SEric Schweitz         }
953c2acd453SAlexisPerry     for (mlir::Value opnd : adaptor.getOperands())
954c2acd453SAlexisPerry       size = rewriter.create<mlir::LLVM::MulOp>(
955c2acd453SAlexisPerry           loc, ity, size, integerCast(loc, rewriter, ity, opnd));
956c2acd453SAlexisPerry     heap->setAttr("callee", mlir::SymbolRefAttr::get(mallocFunc));
957c2acd453SAlexisPerry     auto malloc = rewriter.create<mlir::LLVM::CallOp>(
958c2acd453SAlexisPerry         loc, ::getVoidPtrType(heap.getContext()), size, heap->getAttrs());
959c2acd453SAlexisPerry     rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(heap, ty,
960c2acd453SAlexisPerry                                                        malloc.getResult(0));
961c2acd453SAlexisPerry     return success();
962c2acd453SAlexisPerry   }
963c2acd453SAlexisPerry 
964c2acd453SAlexisPerry   // Compute the (allocation) size of the allocmem type in bytes.
965c2acd453SAlexisPerry   mlir::Value genTypeSizeInBytes(mlir::Location loc, mlir::Type idxTy,
966c2acd453SAlexisPerry                                  mlir::ConversionPatternRewriter &rewriter,
967c2acd453SAlexisPerry                                  mlir::Type llTy) const {
968c2acd453SAlexisPerry     // Use the primitive size, if available.
969c2acd453SAlexisPerry     auto ptrTy = llTy.dyn_cast<mlir::LLVM::LLVMPointerType>();
970c2acd453SAlexisPerry     if (auto size =
971c2acd453SAlexisPerry             mlir::LLVM::getPrimitiveTypeSizeInBits(ptrTy.getElementType()))
972c2acd453SAlexisPerry       return genConstantIndex(loc, idxTy, rewriter, size / 8);
973c2acd453SAlexisPerry 
974c2acd453SAlexisPerry     // Otherwise, generate the GEP trick in LLVM IR to compute the size.
975c2acd453SAlexisPerry     return computeDerivedTypeSize(loc, ptrTy, idxTy, rewriter);
976c2acd453SAlexisPerry   }
977c2acd453SAlexisPerry };
978c2acd453SAlexisPerry } // namespace
979c2acd453SAlexisPerry 
980c2acd453SAlexisPerry /// Return the LLVMFuncOp corresponding to the standard free call.
981c2acd453SAlexisPerry static mlir::LLVM::LLVMFuncOp
982c2acd453SAlexisPerry getFree(fir::FreeMemOp op, mlir::ConversionPatternRewriter &rewriter) {
983c2acd453SAlexisPerry   auto module = op->getParentOfType<mlir::ModuleOp>();
984c2acd453SAlexisPerry   if (mlir::LLVM::LLVMFuncOp freeFunc =
985c2acd453SAlexisPerry           module.lookupSymbol<mlir::LLVM::LLVMFuncOp>("free"))
986c2acd453SAlexisPerry     return freeFunc;
987c2acd453SAlexisPerry   mlir::OpBuilder moduleBuilder(module.getBodyRegion());
988c2acd453SAlexisPerry   auto voidType = mlir::LLVM::LLVMVoidType::get(op.getContext());
989c2acd453SAlexisPerry   return moduleBuilder.create<mlir::LLVM::LLVMFuncOp>(
990c2acd453SAlexisPerry       rewriter.getUnknownLoc(), "free",
991c2acd453SAlexisPerry       mlir::LLVM::LLVMFunctionType::get(voidType,
992c2acd453SAlexisPerry                                         getVoidPtrType(op.getContext()),
993c2acd453SAlexisPerry                                         /*isVarArg=*/false));
994c2acd453SAlexisPerry }
995c2acd453SAlexisPerry 
996c2acd453SAlexisPerry namespace {
997c2acd453SAlexisPerry /// Lower a `fir.freemem` instruction into `llvm.call @free`
998c2acd453SAlexisPerry struct FreeMemOpConversion : public FIROpConversion<fir::FreeMemOp> {
999c2acd453SAlexisPerry   using FIROpConversion::FIROpConversion;
1000c2acd453SAlexisPerry 
1001c2acd453SAlexisPerry   mlir::LogicalResult
1002c2acd453SAlexisPerry   matchAndRewrite(fir::FreeMemOp freemem, OpAdaptor adaptor,
1003c2acd453SAlexisPerry                   mlir::ConversionPatternRewriter &rewriter) const override {
1004c2acd453SAlexisPerry     mlir::LLVM::LLVMFuncOp freeFunc = getFree(freemem, rewriter);
1005c2acd453SAlexisPerry     mlir::Location loc = freemem.getLoc();
1006c2acd453SAlexisPerry     auto bitcast = rewriter.create<mlir::LLVM::BitcastOp>(
1007c2acd453SAlexisPerry         freemem.getLoc(), voidPtrTy(), adaptor.getOperands()[0]);
1008c2acd453SAlexisPerry     freemem->setAttr("callee", mlir::SymbolRefAttr::get(freeFunc));
1009c2acd453SAlexisPerry     rewriter.create<mlir::LLVM::CallOp>(
1010c2acd453SAlexisPerry         loc, mlir::TypeRange{}, mlir::ValueRange{bitcast}, freemem->getAttrs());
1011c2acd453SAlexisPerry     rewriter.eraseOp(freemem);
1012c2acd453SAlexisPerry     return success();
1013c2acd453SAlexisPerry   }
1014c2acd453SAlexisPerry };
101531246187SValentin Clement 
101622d332a0SAndrzej Warzynski /// Convert `fir.end`
101722d332a0SAndrzej Warzynski struct FirEndOpConversion : public FIROpConversion<fir::FirEndOp> {
101822d332a0SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
101922d332a0SAndrzej Warzynski 
102022d332a0SAndrzej Warzynski   mlir::LogicalResult
102122d332a0SAndrzej Warzynski   matchAndRewrite(fir::FirEndOp firEnd, OpAdaptor,
102222d332a0SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
10237ce8c6fcSKiran Chandramohan     TODO(firEnd.getLoc(), "fir.end codegen");
10247ce8c6fcSKiran Chandramohan     return failure();
102522d332a0SAndrzej Warzynski   }
102622d332a0SAndrzej Warzynski };
102722d332a0SAndrzej Warzynski 
10280c4a7a52SValentin Clement /// Lower `fir.has_value` operation to `llvm.return` operation.
1029044d5b5dSValentin Clement struct HasValueOpConversion : public FIROpConversion<fir::HasValueOp> {
1030044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
1031044d5b5dSValentin Clement 
1032044d5b5dSValentin Clement   mlir::LogicalResult
1033044d5b5dSValentin Clement   matchAndRewrite(fir::HasValueOp op, OpAdaptor adaptor,
1034044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1035044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, adaptor.getOperands());
1036044d5b5dSValentin Clement     return success();
1037044d5b5dSValentin Clement   }
1038044d5b5dSValentin Clement };
1039044d5b5dSValentin Clement 
10400c4a7a52SValentin Clement /// Lower `fir.global` operation to `llvm.global` operation.
10410c4a7a52SValentin Clement /// `fir.insert_on_range` operations are replaced with constant dense attribute
10420c4a7a52SValentin Clement /// if they are applied on the full range.
1043044d5b5dSValentin Clement struct GlobalOpConversion : public FIROpConversion<fir::GlobalOp> {
1044044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
1045044d5b5dSValentin Clement 
1046044d5b5dSValentin Clement   mlir::LogicalResult
1047044d5b5dSValentin Clement   matchAndRewrite(fir::GlobalOp global, OpAdaptor adaptor,
1048044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1049044d5b5dSValentin Clement     auto tyAttr = convertType(global.getType());
1050044d5b5dSValentin Clement     if (global.getType().isa<fir::BoxType>())
1051044d5b5dSValentin Clement       tyAttr = tyAttr.cast<mlir::LLVM::LLVMPointerType>().getElementType();
1052044d5b5dSValentin Clement     auto loc = global.getLoc();
1053044d5b5dSValentin Clement     mlir::Attribute initAttr{};
1054044d5b5dSValentin Clement     if (global.initVal())
1055044d5b5dSValentin Clement       initAttr = global.initVal().getValue();
1056044d5b5dSValentin Clement     auto linkage = convertLinkage(global.linkName());
1057044d5b5dSValentin Clement     auto isConst = global.constant().hasValue();
1058044d5b5dSValentin Clement     auto g = rewriter.create<mlir::LLVM::GlobalOp>(
1059feeee78aSJacques Pienaar         loc, tyAttr, isConst, linkage, global.getSymName(), initAttr);
1060044d5b5dSValentin Clement     auto &gr = g.getInitializerRegion();
1061044d5b5dSValentin Clement     rewriter.inlineRegionBefore(global.region(), gr, gr.end());
1062044d5b5dSValentin Clement     if (!gr.empty()) {
1063044d5b5dSValentin Clement       // Replace insert_on_range with a constant dense attribute if the
1064044d5b5dSValentin Clement       // initialization is on the full range.
1065044d5b5dSValentin Clement       auto insertOnRangeOps = gr.front().getOps<fir::InsertOnRangeOp>();
1066044d5b5dSValentin Clement       for (auto insertOp : insertOnRangeOps) {
1067044d5b5dSValentin Clement         if (isFullRange(insertOp.coor(), insertOp.getType())) {
1068044d5b5dSValentin Clement           auto seqTyAttr = convertType(insertOp.getType());
1069044d5b5dSValentin Clement           auto *op = insertOp.val().getDefiningOp();
1070044d5b5dSValentin Clement           auto constant = mlir::dyn_cast<mlir::arith::ConstantOp>(op);
1071044d5b5dSValentin Clement           if (!constant) {
1072044d5b5dSValentin Clement             auto convertOp = mlir::dyn_cast<fir::ConvertOp>(op);
1073044d5b5dSValentin Clement             if (!convertOp)
1074044d5b5dSValentin Clement               continue;
1075044d5b5dSValentin Clement             constant = cast<mlir::arith::ConstantOp>(
1076044d5b5dSValentin Clement                 convertOp.value().getDefiningOp());
1077044d5b5dSValentin Clement           }
1078044d5b5dSValentin Clement           mlir::Type vecType = mlir::VectorType::get(
1079044d5b5dSValentin Clement               insertOp.getType().getShape(), constant.getType());
1080044d5b5dSValentin Clement           auto denseAttr = mlir::DenseElementsAttr::get(
10813012f35fSJacques Pienaar               vecType.cast<ShapedType>(), constant.getValue());
1082044d5b5dSValentin Clement           rewriter.setInsertionPointAfter(insertOp);
1083044d5b5dSValentin Clement           rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(
1084044d5b5dSValentin Clement               insertOp, seqTyAttr, denseAttr);
1085044d5b5dSValentin Clement         }
1086044d5b5dSValentin Clement       }
1087044d5b5dSValentin Clement     }
1088044d5b5dSValentin Clement     rewriter.eraseOp(global);
1089044d5b5dSValentin Clement     return success();
1090044d5b5dSValentin Clement   }
1091044d5b5dSValentin Clement 
10928ec0f221SMehdi Amini   bool isFullRange(mlir::DenseIntElementsAttr indexes,
10938ec0f221SMehdi Amini                    fir::SequenceType seqTy) const {
1094044d5b5dSValentin Clement     auto extents = seqTy.getShape();
10958ec0f221SMehdi Amini     if (indexes.size() / 2 != static_cast<int64_t>(extents.size()))
1096044d5b5dSValentin Clement       return false;
10978ec0f221SMehdi Amini     auto cur_index = indexes.value_begin<int64_t>();
1098044d5b5dSValentin Clement     for (unsigned i = 0; i < indexes.size(); i += 2) {
10998ec0f221SMehdi Amini       if (*(cur_index++) != 0)
1100044d5b5dSValentin Clement         return false;
11018ec0f221SMehdi Amini       if (*(cur_index++) != extents[i / 2] - 1)
1102044d5b5dSValentin Clement         return false;
1103044d5b5dSValentin Clement     }
1104044d5b5dSValentin Clement     return true;
1105044d5b5dSValentin Clement   }
1106044d5b5dSValentin Clement 
11070c4a7a52SValentin Clement   // TODO: String comparaison should be avoided. Replace linkName with an
11080c4a7a52SValentin Clement   // enumeration.
1109044d5b5dSValentin Clement   mlir::LLVM::Linkage convertLinkage(Optional<StringRef> optLinkage) const {
1110044d5b5dSValentin Clement     if (optLinkage.hasValue()) {
1111044d5b5dSValentin Clement       auto name = optLinkage.getValue();
1112044d5b5dSValentin Clement       if (name == "internal")
1113044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Internal;
1114044d5b5dSValentin Clement       if (name == "linkonce")
1115044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Linkonce;
1116044d5b5dSValentin Clement       if (name == "common")
1117044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Common;
1118044d5b5dSValentin Clement       if (name == "weak")
1119044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Weak;
1120044d5b5dSValentin Clement     }
1121044d5b5dSValentin Clement     return mlir::LLVM::Linkage::External;
1122044d5b5dSValentin Clement   }
1123044d5b5dSValentin Clement };
1124c2acd453SAlexisPerry } // namespace
1125044d5b5dSValentin Clement 
1126c2acd453SAlexisPerry static void genCondBrOp(mlir::Location loc, mlir::Value cmp, mlir::Block *dest,
112739f4ef81SValentin Clement                         Optional<mlir::ValueRange> destOps,
112839f4ef81SValentin Clement                         mlir::ConversionPatternRewriter &rewriter,
112939f4ef81SValentin Clement                         mlir::Block *newBlock) {
113039f4ef81SValentin Clement   if (destOps.hasValue())
113139f4ef81SValentin Clement     rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, destOps.getValue(),
113239f4ef81SValentin Clement                                           newBlock, mlir::ValueRange());
113339f4ef81SValentin Clement   else
113439f4ef81SValentin Clement     rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, newBlock);
113539f4ef81SValentin Clement }
113639f4ef81SValentin Clement 
113739f4ef81SValentin Clement template <typename A, typename B>
1138c2acd453SAlexisPerry static void genBrOp(A caseOp, mlir::Block *dest, Optional<B> destOps,
113939f4ef81SValentin Clement                     mlir::ConversionPatternRewriter &rewriter) {
114039f4ef81SValentin Clement   if (destOps.hasValue())
114139f4ef81SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, destOps.getValue(),
114239f4ef81SValentin Clement                                                   dest);
114339f4ef81SValentin Clement   else
114439f4ef81SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, llvm::None, dest);
114539f4ef81SValentin Clement }
114639f4ef81SValentin Clement 
1147c2acd453SAlexisPerry static void genCaseLadderStep(mlir::Location loc, mlir::Value cmp,
1148c2acd453SAlexisPerry                               mlir::Block *dest,
114939f4ef81SValentin Clement                               Optional<mlir::ValueRange> destOps,
115039f4ef81SValentin Clement                               mlir::ConversionPatternRewriter &rewriter) {
115139f4ef81SValentin Clement   auto *thisBlock = rewriter.getInsertionBlock();
115239f4ef81SValentin Clement   auto *newBlock = createBlock(rewriter, dest);
115339f4ef81SValentin Clement   rewriter.setInsertionPointToEnd(thisBlock);
115439f4ef81SValentin Clement   genCondBrOp(loc, cmp, dest, destOps, rewriter, newBlock);
115539f4ef81SValentin Clement   rewriter.setInsertionPointToEnd(newBlock);
115639f4ef81SValentin Clement }
115739f4ef81SValentin Clement 
1158c2acd453SAlexisPerry namespace {
115939f4ef81SValentin Clement /// Conversion of `fir.select_case`
116039f4ef81SValentin Clement ///
116139f4ef81SValentin Clement /// The `fir.select_case` operation is converted to a if-then-else ladder.
116239f4ef81SValentin Clement /// Depending on the case condition type, one or several comparison and
116339f4ef81SValentin Clement /// conditional branching can be generated.
116439f4ef81SValentin Clement ///
116539f4ef81SValentin Clement /// A a point value case such as `case(4)`, a lower bound case such as
116639f4ef81SValentin Clement /// `case(5:)` or an upper bound case such as `case(:3)` are converted to a
116739f4ef81SValentin Clement /// simple comparison between the selector value and the constant value in the
116839f4ef81SValentin Clement /// case. The block associated with the case condition is then executed if
116939f4ef81SValentin Clement /// the comparison succeed otherwise it branch to the next block with the
117039f4ef81SValentin Clement /// comparison for the the next case conditon.
117139f4ef81SValentin Clement ///
117239f4ef81SValentin Clement /// A closed interval case condition such as `case(7:10)` is converted with a
117339f4ef81SValentin Clement /// first comparison and conditional branching for the lower bound. If
117439f4ef81SValentin Clement /// successful, it branch to a second block with the comparison for the
117539f4ef81SValentin Clement /// upper bound in the same case condition.
117639f4ef81SValentin Clement ///
117739f4ef81SValentin Clement /// TODO: lowering of CHARACTER type cases is not handled yet.
117839f4ef81SValentin Clement struct SelectCaseOpConversion : public FIROpConversion<fir::SelectCaseOp> {
117939f4ef81SValentin Clement   using FIROpConversion::FIROpConversion;
118039f4ef81SValentin Clement 
118139f4ef81SValentin Clement   mlir::LogicalResult
118239f4ef81SValentin Clement   matchAndRewrite(fir::SelectCaseOp caseOp, OpAdaptor adaptor,
118339f4ef81SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
118439f4ef81SValentin Clement     unsigned conds = caseOp.getNumConditions();
118539f4ef81SValentin Clement     llvm::ArrayRef<mlir::Attribute> cases = caseOp.getCases().getValue();
118639f4ef81SValentin Clement     // Type can be CHARACTER, INTEGER, or LOGICAL (C1145)
11877ce8c6fcSKiran Chandramohan     auto ty = caseOp.getSelector().getType();
11887ce8c6fcSKiran Chandramohan     if (ty.isa<fir::CharacterType>()) {
11897ce8c6fcSKiran Chandramohan       TODO(caseOp.getLoc(), "fir.select_case codegen with character type");
11907ce8c6fcSKiran Chandramohan       return failure();
11917ce8c6fcSKiran Chandramohan     }
119239f4ef81SValentin Clement     mlir::Value selector = caseOp.getSelector(adaptor.getOperands());
119339f4ef81SValentin Clement     auto loc = caseOp.getLoc();
119439f4ef81SValentin Clement     for (unsigned t = 0; t != conds; ++t) {
119539f4ef81SValentin Clement       mlir::Block *dest = caseOp.getSuccessor(t);
119639f4ef81SValentin Clement       llvm::Optional<mlir::ValueRange> destOps =
119739f4ef81SValentin Clement           caseOp.getSuccessorOperands(adaptor.getOperands(), t);
119839f4ef81SValentin Clement       llvm::Optional<mlir::ValueRange> cmpOps =
119939f4ef81SValentin Clement           *caseOp.getCompareOperands(adaptor.getOperands(), t);
120039f4ef81SValentin Clement       mlir::Value caseArg = *(cmpOps.getValue().begin());
120139f4ef81SValentin Clement       mlir::Attribute attr = cases[t];
120239f4ef81SValentin Clement       if (attr.isa<fir::PointIntervalAttr>()) {
120339f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
120439f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::eq, selector, caseArg);
120539f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
120639f4ef81SValentin Clement         continue;
120739f4ef81SValentin Clement       }
120839f4ef81SValentin Clement       if (attr.isa<fir::LowerBoundAttr>()) {
120939f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
121039f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector);
121139f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
121239f4ef81SValentin Clement         continue;
121339f4ef81SValentin Clement       }
121439f4ef81SValentin Clement       if (attr.isa<fir::UpperBoundAttr>()) {
121539f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
121639f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg);
121739f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
121839f4ef81SValentin Clement         continue;
121939f4ef81SValentin Clement       }
122039f4ef81SValentin Clement       if (attr.isa<fir::ClosedIntervalAttr>()) {
122139f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
122239f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector);
122339f4ef81SValentin Clement         auto *thisBlock = rewriter.getInsertionBlock();
122439f4ef81SValentin Clement         auto *newBlock1 = createBlock(rewriter, dest);
122539f4ef81SValentin Clement         auto *newBlock2 = createBlock(rewriter, dest);
122639f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(thisBlock);
122739f4ef81SValentin Clement         rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, newBlock1, newBlock2);
122839f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(newBlock1);
122939f4ef81SValentin Clement         mlir::Value caseArg0 = *(cmpOps.getValue().begin() + 1);
123039f4ef81SValentin Clement         auto cmp0 = rewriter.create<mlir::LLVM::ICmpOp>(
123139f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg0);
123239f4ef81SValentin Clement         genCondBrOp(loc, cmp0, dest, destOps, rewriter, newBlock2);
123339f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(newBlock2);
123439f4ef81SValentin Clement         continue;
123539f4ef81SValentin Clement       }
123639f4ef81SValentin Clement       assert(attr.isa<mlir::UnitAttr>());
123739f4ef81SValentin Clement       assert((t + 1 == conds) && "unit must be last");
123839f4ef81SValentin Clement       genBrOp(caseOp, dest, destOps, rewriter);
123939f4ef81SValentin Clement     }
124039f4ef81SValentin Clement     return success();
124139f4ef81SValentin Clement   }
124239f4ef81SValentin Clement };
1243c2acd453SAlexisPerry } // namespace
124439f4ef81SValentin Clement 
12458c239909SValentin Clement template <typename OP>
1246c2acd453SAlexisPerry static void selectMatchAndRewrite(fir::LLVMTypeConverter &lowering, OP select,
12478c239909SValentin Clement                                   typename OP::Adaptor adaptor,
12488c239909SValentin Clement                                   mlir::ConversionPatternRewriter &rewriter) {
12498c239909SValentin Clement   unsigned conds = select.getNumConditions();
12508c239909SValentin Clement   auto cases = select.getCases().getValue();
12518c239909SValentin Clement   mlir::Value selector = adaptor.selector();
12528c239909SValentin Clement   auto loc = select.getLoc();
12538c239909SValentin Clement   assert(conds > 0 && "select must have cases");
12548c239909SValentin Clement 
12558c239909SValentin Clement   llvm::SmallVector<mlir::Block *> destinations;
12568c239909SValentin Clement   llvm::SmallVector<mlir::ValueRange> destinationsOperands;
12578c239909SValentin Clement   mlir::Block *defaultDestination;
12588c239909SValentin Clement   mlir::ValueRange defaultOperands;
12598c239909SValentin Clement   llvm::SmallVector<int32_t> caseValues;
12608c239909SValentin Clement 
12618c239909SValentin Clement   for (unsigned t = 0; t != conds; ++t) {
12628c239909SValentin Clement     mlir::Block *dest = select.getSuccessor(t);
12638c239909SValentin Clement     auto destOps = select.getSuccessorOperands(adaptor.getOperands(), t);
12648c239909SValentin Clement     const mlir::Attribute &attr = cases[t];
12658c239909SValentin Clement     if (auto intAttr = attr.template dyn_cast<mlir::IntegerAttr>()) {
12668c239909SValentin Clement       destinations.push_back(dest);
12678c239909SValentin Clement       destinationsOperands.push_back(destOps.hasValue() ? *destOps
12688c239909SValentin Clement                                                         : ValueRange());
12698c239909SValentin Clement       caseValues.push_back(intAttr.getInt());
12708c239909SValentin Clement       continue;
12718c239909SValentin Clement     }
12728c239909SValentin Clement     assert(attr.template dyn_cast_or_null<mlir::UnitAttr>());
12738c239909SValentin Clement     assert((t + 1 == conds) && "unit must be last");
12748c239909SValentin Clement     defaultDestination = dest;
12758c239909SValentin Clement     defaultOperands = destOps.hasValue() ? *destOps : ValueRange();
12768c239909SValentin Clement   }
12778c239909SValentin Clement 
12788c239909SValentin Clement   // LLVM::SwitchOp takes a i32 type for the selector.
12798c239909SValentin Clement   if (select.getSelector().getType() != rewriter.getI32Type())
12808c239909SValentin Clement     selector =
12818c239909SValentin Clement         rewriter.create<LLVM::TruncOp>(loc, rewriter.getI32Type(), selector);
12828c239909SValentin Clement 
12838c239909SValentin Clement   rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>(
12848c239909SValentin Clement       select, selector,
12858c239909SValentin Clement       /*defaultDestination=*/defaultDestination,
12868c239909SValentin Clement       /*defaultOperands=*/defaultOperands,
12878c239909SValentin Clement       /*caseValues=*/caseValues,
12888c239909SValentin Clement       /*caseDestinations=*/destinations,
12898c239909SValentin Clement       /*caseOperands=*/destinationsOperands,
12908c239909SValentin Clement       /*branchWeights=*/ArrayRef<int32_t>());
12918c239909SValentin Clement }
12928c239909SValentin Clement 
1293c2acd453SAlexisPerry namespace {
12948c239909SValentin Clement /// conversion of fir::SelectOp to an if-then-else ladder
12958c239909SValentin Clement struct SelectOpConversion : public FIROpConversion<fir::SelectOp> {
12968c239909SValentin Clement   using FIROpConversion::FIROpConversion;
12978c239909SValentin Clement 
12988c239909SValentin Clement   mlir::LogicalResult
12998c239909SValentin Clement   matchAndRewrite(fir::SelectOp op, OpAdaptor adaptor,
13008c239909SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
13018c239909SValentin Clement     selectMatchAndRewrite<fir::SelectOp>(lowerTy(), op, adaptor, rewriter);
13028c239909SValentin Clement     return success();
13038c239909SValentin Clement   }
13048c239909SValentin Clement };
13058c239909SValentin Clement 
1306e3349fa1SAndrzej Warzynski /// `fir.load` --> `llvm.load`
1307e3349fa1SAndrzej Warzynski struct LoadOpConversion : public FIROpConversion<fir::LoadOp> {
1308e3349fa1SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
1309e3349fa1SAndrzej Warzynski 
1310e3349fa1SAndrzej Warzynski   mlir::LogicalResult
1311e3349fa1SAndrzej Warzynski   matchAndRewrite(fir::LoadOp load, OpAdaptor adaptor,
1312e3349fa1SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
1313e3349fa1SAndrzej Warzynski     // fir.box is a special case because it is considered as an ssa values in
1314e3349fa1SAndrzej Warzynski     // fir, but it is lowered as a pointer to a descriptor. So fir.ref<fir.box>
1315e3349fa1SAndrzej Warzynski     // and fir.box end up being the same llvm types and loading a
1316e3349fa1SAndrzej Warzynski     // fir.ref<fir.box> is actually a no op in LLVM.
1317e3349fa1SAndrzej Warzynski     if (load.getType().isa<fir::BoxType>()) {
1318e3349fa1SAndrzej Warzynski       rewriter.replaceOp(load, adaptor.getOperands()[0]);
1319e3349fa1SAndrzej Warzynski     } else {
1320e3349fa1SAndrzej Warzynski       mlir::Type ty = convertType(load.getType());
1321e3349fa1SAndrzej Warzynski       ArrayRef<NamedAttribute> at = load->getAttrs();
1322e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::LoadOp>(
1323e3349fa1SAndrzej Warzynski           load, ty, adaptor.getOperands(), at);
1324e3349fa1SAndrzej Warzynski     }
1325e3349fa1SAndrzej Warzynski     return success();
1326e3349fa1SAndrzej Warzynski   }
1327e3349fa1SAndrzej Warzynski };
1328e3349fa1SAndrzej Warzynski 
1329b8207db7SValentin Clement /// Lower `fir.no_reassoc` to LLVM IR dialect.
1330b8207db7SValentin Clement /// TODO: how do we want to enforce this in LLVM-IR? Can we manipulate the fast
1331b8207db7SValentin Clement /// math flags?
1332b8207db7SValentin Clement struct NoReassocOpConversion : public FIROpConversion<fir::NoReassocOp> {
1333b8207db7SValentin Clement   using FIROpConversion::FIROpConversion;
1334b8207db7SValentin Clement 
1335b8207db7SValentin Clement   mlir::LogicalResult
1336b8207db7SValentin Clement   matchAndRewrite(fir::NoReassocOp noreassoc, OpAdaptor adaptor,
1337b8207db7SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1338b8207db7SValentin Clement     rewriter.replaceOp(noreassoc, adaptor.getOperands()[0]);
1339b8207db7SValentin Clement     return success();
1340b8207db7SValentin Clement   }
1341b8207db7SValentin Clement };
1342b8207db7SValentin Clement 
13432a299e4fSValentin Clement /// Lower `fir.select_type` to LLVM IR dialect.
13442a299e4fSValentin Clement struct SelectTypeOpConversion : public FIROpConversion<fir::SelectTypeOp> {
13452a299e4fSValentin Clement   using FIROpConversion::FIROpConversion;
13462a299e4fSValentin Clement 
13472a299e4fSValentin Clement   mlir::LogicalResult
13482a299e4fSValentin Clement   matchAndRewrite(fir::SelectTypeOp select, OpAdaptor adaptor,
13492a299e4fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
13507ce8c6fcSKiran Chandramohan     mlir::emitError(select.getLoc(),
13517ce8c6fcSKiran Chandramohan                     "fir.select_type should have already been converted");
13527ce8c6fcSKiran Chandramohan     return failure();
13532a299e4fSValentin Clement   }
13542a299e4fSValentin Clement };
13552a299e4fSValentin Clement 
13568c239909SValentin Clement /// conversion of fir::SelectRankOp to an if-then-else ladder
13578c239909SValentin Clement struct SelectRankOpConversion : public FIROpConversion<fir::SelectRankOp> {
13588c239909SValentin Clement   using FIROpConversion::FIROpConversion;
13598c239909SValentin Clement 
13608c239909SValentin Clement   mlir::LogicalResult
13618c239909SValentin Clement   matchAndRewrite(fir::SelectRankOp op, OpAdaptor adaptor,
13628c239909SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
13638c239909SValentin Clement     selectMatchAndRewrite<fir::SelectRankOp>(lowerTy(), op, adaptor, rewriter);
13648c239909SValentin Clement     return success();
13658c239909SValentin Clement   }
13668c239909SValentin Clement };
13678c239909SValentin Clement 
1368e3349fa1SAndrzej Warzynski /// `fir.store` --> `llvm.store`
1369e3349fa1SAndrzej Warzynski struct StoreOpConversion : public FIROpConversion<fir::StoreOp> {
1370e3349fa1SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
1371e3349fa1SAndrzej Warzynski 
1372e3349fa1SAndrzej Warzynski   mlir::LogicalResult
1373e3349fa1SAndrzej Warzynski   matchAndRewrite(fir::StoreOp store, OpAdaptor adaptor,
1374e3349fa1SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
1375e3349fa1SAndrzej Warzynski     if (store.value().getType().isa<fir::BoxType>()) {
1376e3349fa1SAndrzej Warzynski       // fir.box value is actually in memory, load it first before storing it.
1377e3349fa1SAndrzej Warzynski       mlir::Location loc = store.getLoc();
1378e3349fa1SAndrzej Warzynski       mlir::Type boxPtrTy = adaptor.getOperands()[0].getType();
1379e3349fa1SAndrzej Warzynski       auto val = rewriter.create<mlir::LLVM::LoadOp>(
1380e3349fa1SAndrzej Warzynski           loc, boxPtrTy.cast<mlir::LLVM::LLVMPointerType>().getElementType(),
1381e3349fa1SAndrzej Warzynski           adaptor.getOperands()[0]);
1382e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
1383e3349fa1SAndrzej Warzynski           store, val, adaptor.getOperands()[1]);
1384e3349fa1SAndrzej Warzynski     } else {
1385e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
1386e3349fa1SAndrzej Warzynski           store, adaptor.getOperands()[0], adaptor.getOperands()[1]);
1387e3349fa1SAndrzej Warzynski     }
1388e3349fa1SAndrzej Warzynski     return success();
1389e3349fa1SAndrzej Warzynski   }
1390e3349fa1SAndrzej Warzynski };
1391e3349fa1SAndrzej Warzynski 
1392e3349fa1SAndrzej Warzynski /// convert to LLVM IR dialect `undef`
1393044d5b5dSValentin Clement struct UndefOpConversion : public FIROpConversion<fir::UndefOp> {
1394044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
1395044d5b5dSValentin Clement 
1396044d5b5dSValentin Clement   mlir::LogicalResult
1397044d5b5dSValentin Clement   matchAndRewrite(fir::UndefOp undef, OpAdaptor,
1398044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1399044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::UndefOp>(
1400044d5b5dSValentin Clement         undef, convertType(undef.getType()));
1401044d5b5dSValentin Clement     return success();
1402044d5b5dSValentin Clement   }
1403044d5b5dSValentin Clement };
1404a7a61359SValentin Clement 
1405e3349fa1SAndrzej Warzynski /// `fir.unreachable` --> `llvm.unreachable`
140632e08248SAndrzej Warzynski struct UnreachableOpConversion : public FIROpConversion<fir::UnreachableOp> {
140732e08248SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
140832e08248SAndrzej Warzynski 
140932e08248SAndrzej Warzynski   mlir::LogicalResult
141032e08248SAndrzej Warzynski   matchAndRewrite(fir::UnreachableOp unreach, OpAdaptor adaptor,
141132e08248SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
141232e08248SAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(unreach);
141332e08248SAndrzej Warzynski     return success();
141432e08248SAndrzej Warzynski   }
141532e08248SAndrzej Warzynski };
141632e08248SAndrzej Warzynski 
1417a7a61359SValentin Clement struct ZeroOpConversion : public FIROpConversion<fir::ZeroOp> {
1418a7a61359SValentin Clement   using FIROpConversion::FIROpConversion;
1419a7a61359SValentin Clement 
1420a7a61359SValentin Clement   mlir::LogicalResult
1421a7a61359SValentin Clement   matchAndRewrite(fir::ZeroOp zero, OpAdaptor,
1422a7a61359SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
14237ce8c6fcSKiran Chandramohan     mlir::Type ty = convertType(zero.getType());
1424a7a61359SValentin Clement     if (ty.isa<mlir::LLVM::LLVMPointerType>()) {
1425a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(zero, ty);
1426a7a61359SValentin Clement     } else if (ty.isa<mlir::IntegerType>()) {
1427a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
1428a7a61359SValentin Clement           zero, ty, mlir::IntegerAttr::get(zero.getType(), 0));
1429a7a61359SValentin Clement     } else if (mlir::LLVM::isCompatibleFloatingPointType(ty)) {
1430a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
1431a7a61359SValentin Clement           zero, ty, mlir::FloatAttr::get(zero.getType(), 0.0));
1432a7a61359SValentin Clement     } else {
1433a7a61359SValentin Clement       // TODO: create ConstantAggregateZero for FIR aggregate/array types.
143452d813edSValentin Clement       return rewriter.notifyMatchFailure(
143552d813edSValentin Clement           zero,
1436a7a61359SValentin Clement           "conversion of fir.zero with aggregate type not implemented yet");
1437a7a61359SValentin Clement     }
1438a7a61359SValentin Clement     return success();
1439a7a61359SValentin Clement   }
1440a7a61359SValentin Clement };
1441c2acd453SAlexisPerry } // namespace
144232e08248SAndrzej Warzynski 
1443af6ee580SValentin Clement /// Common base class for embox to descriptor conversion.
1444af6ee580SValentin Clement template <typename OP>
1445af6ee580SValentin Clement struct EmboxCommonConversion : public FIROpConversion<OP> {
1446af6ee580SValentin Clement   using FIROpConversion<OP>::FIROpConversion;
1447af6ee580SValentin Clement 
1448af6ee580SValentin Clement   // Find the LLVMFuncOp in whose entry block the alloca should be inserted.
1449af6ee580SValentin Clement   // The order to find the LLVMFuncOp is as follows:
1450af6ee580SValentin Clement   // 1. The parent operation of the current block if it is a LLVMFuncOp.
1451af6ee580SValentin Clement   // 2. The first ancestor that is a LLVMFuncOp.
1452af6ee580SValentin Clement   mlir::LLVM::LLVMFuncOp
1453af6ee580SValentin Clement   getFuncForAllocaInsert(mlir::ConversionPatternRewriter &rewriter) const {
1454af6ee580SValentin Clement     mlir::Operation *parentOp = rewriter.getInsertionBlock()->getParentOp();
1455af6ee580SValentin Clement     return mlir::isa<mlir::LLVM::LLVMFuncOp>(parentOp)
1456af6ee580SValentin Clement                ? mlir::cast<mlir::LLVM::LLVMFuncOp>(parentOp)
1457af6ee580SValentin Clement                : parentOp->getParentOfType<mlir::LLVM::LLVMFuncOp>();
1458af6ee580SValentin Clement   }
1459af6ee580SValentin Clement 
1460af6ee580SValentin Clement   // Generate an alloca of size 1 and type \p toTy.
1461af6ee580SValentin Clement   mlir::LLVM::AllocaOp
1462af6ee580SValentin Clement   genAllocaWithType(mlir::Location loc, mlir::Type toTy, unsigned alignment,
1463af6ee580SValentin Clement                     mlir::ConversionPatternRewriter &rewriter) const {
1464af6ee580SValentin Clement     auto thisPt = rewriter.saveInsertionPoint();
1465af6ee580SValentin Clement     mlir::LLVM::LLVMFuncOp func = getFuncForAllocaInsert(rewriter);
1466af6ee580SValentin Clement     rewriter.setInsertionPointToStart(&func.front());
1467af6ee580SValentin Clement     auto size = this->genI32Constant(loc, rewriter, 1);
1468af6ee580SValentin Clement     auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, toTy, size, alignment);
1469af6ee580SValentin Clement     rewriter.restoreInsertionPoint(thisPt);
1470af6ee580SValentin Clement     return al;
1471af6ee580SValentin Clement   }
1472af6ee580SValentin Clement 
1473af6ee580SValentin Clement   static int getCFIAttr(fir::BoxType boxTy) {
1474af6ee580SValentin Clement     auto eleTy = boxTy.getEleTy();
1475af6ee580SValentin Clement     if (eleTy.isa<fir::PointerType>())
1476af6ee580SValentin Clement       return CFI_attribute_pointer;
1477af6ee580SValentin Clement     if (eleTy.isa<fir::HeapType>())
1478af6ee580SValentin Clement       return CFI_attribute_allocatable;
1479af6ee580SValentin Clement     return CFI_attribute_other;
1480af6ee580SValentin Clement   }
1481af6ee580SValentin Clement 
1482af6ee580SValentin Clement   static fir::RecordType unwrapIfDerived(fir::BoxType boxTy) {
1483af6ee580SValentin Clement     return fir::unwrapSequenceType(fir::dyn_cast_ptrOrBoxEleTy(boxTy))
1484af6ee580SValentin Clement         .template dyn_cast<fir::RecordType>();
1485af6ee580SValentin Clement   }
1486af6ee580SValentin Clement   static bool isDerivedTypeWithLenParams(fir::BoxType boxTy) {
1487af6ee580SValentin Clement     auto recTy = unwrapIfDerived(boxTy);
1488af6ee580SValentin Clement     return recTy && recTy.getNumLenParams() > 0;
1489af6ee580SValentin Clement   }
1490af6ee580SValentin Clement   static bool isDerivedType(fir::BoxType boxTy) {
1491af6ee580SValentin Clement     return unwrapIfDerived(boxTy) != nullptr;
1492af6ee580SValentin Clement   }
1493af6ee580SValentin Clement 
1494af6ee580SValentin Clement   // Get the element size and CFI type code of the boxed value.
1495af6ee580SValentin Clement   std::tuple<mlir::Value, mlir::Value> getSizeAndTypeCode(
1496af6ee580SValentin Clement       mlir::Location loc, mlir::ConversionPatternRewriter &rewriter,
1497af6ee580SValentin Clement       mlir::Type boxEleTy, mlir::ValueRange lenParams = {}) const {
1498af6ee580SValentin Clement     auto doInteger =
1499af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1500af6ee580SValentin Clement       int typeCode = fir::integerBitsToTypeCode(width);
1501af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1502af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1503af6ee580SValentin Clement     };
1504af6ee580SValentin Clement     auto doLogical =
1505af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1506af6ee580SValentin Clement       int typeCode = fir::logicalBitsToTypeCode(width);
1507af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1508af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1509af6ee580SValentin Clement     };
1510af6ee580SValentin Clement     auto doFloat = [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1511af6ee580SValentin Clement       int typeCode = fir::realBitsToTypeCode(width);
1512af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8),
1513af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1514af6ee580SValentin Clement     };
1515af6ee580SValentin Clement     auto doComplex =
1516af6ee580SValentin Clement         [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> {
1517af6ee580SValentin Clement       auto typeCode = fir::complexBitsToTypeCode(width);
1518af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, width / 8 * 2),
1519af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, typeCode)};
1520af6ee580SValentin Clement     };
1521af6ee580SValentin Clement     auto doCharacter =
1522af6ee580SValentin Clement         [&](unsigned width,
1523af6ee580SValentin Clement             mlir::Value len) -> std::tuple<mlir::Value, mlir::Value> {
1524af6ee580SValentin Clement       auto typeCode = fir::characterBitsToTypeCode(width);
1525af6ee580SValentin Clement       auto typeCodeVal = this->genConstantOffset(loc, rewriter, typeCode);
1526af6ee580SValentin Clement       if (width == 8)
1527af6ee580SValentin Clement         return {len, typeCodeVal};
1528af6ee580SValentin Clement       auto byteWidth = this->genConstantOffset(loc, rewriter, width / 8);
1529af6ee580SValentin Clement       auto i64Ty = mlir::IntegerType::get(&this->lowerTy().getContext(), 64);
1530af6ee580SValentin Clement       auto size =
1531af6ee580SValentin Clement           rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, byteWidth, len);
1532af6ee580SValentin Clement       return {size, typeCodeVal};
1533af6ee580SValentin Clement     };
1534af6ee580SValentin Clement     auto getKindMap = [&]() -> fir::KindMapping & {
1535af6ee580SValentin Clement       return this->lowerTy().getKindMap();
1536af6ee580SValentin Clement     };
1537af6ee580SValentin Clement     // Pointer-like types.
1538af6ee580SValentin Clement     if (auto eleTy = fir::dyn_cast_ptrEleTy(boxEleTy))
1539af6ee580SValentin Clement       boxEleTy = eleTy;
1540af6ee580SValentin Clement     // Integer types.
1541af6ee580SValentin Clement     if (fir::isa_integer(boxEleTy)) {
1542af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::IntegerType>())
1543af6ee580SValentin Clement         return doInteger(ty.getWidth());
1544af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::IntegerType>();
1545af6ee580SValentin Clement       return doInteger(getKindMap().getIntegerBitsize(ty.getFKind()));
1546af6ee580SValentin Clement     }
1547af6ee580SValentin Clement     // Floating point types.
1548af6ee580SValentin Clement     if (fir::isa_real(boxEleTy)) {
1549af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::FloatType>())
1550af6ee580SValentin Clement         return doFloat(ty.getWidth());
1551af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::RealType>();
1552af6ee580SValentin Clement       return doFloat(getKindMap().getRealBitsize(ty.getFKind()));
1553af6ee580SValentin Clement     }
1554af6ee580SValentin Clement     // Complex types.
1555af6ee580SValentin Clement     if (fir::isa_complex(boxEleTy)) {
1556af6ee580SValentin Clement       if (auto ty = boxEleTy.dyn_cast<mlir::ComplexType>())
1557af6ee580SValentin Clement         return doComplex(
1558af6ee580SValentin Clement             ty.getElementType().cast<mlir::FloatType>().getWidth());
1559af6ee580SValentin Clement       auto ty = boxEleTy.cast<fir::ComplexType>();
1560af6ee580SValentin Clement       return doComplex(getKindMap().getRealBitsize(ty.getFKind()));
1561af6ee580SValentin Clement     }
1562af6ee580SValentin Clement     // Character types.
1563af6ee580SValentin Clement     if (auto ty = boxEleTy.dyn_cast<fir::CharacterType>()) {
1564af6ee580SValentin Clement       auto charWidth = getKindMap().getCharacterBitsize(ty.getFKind());
1565af6ee580SValentin Clement       if (ty.getLen() != fir::CharacterType::unknownLen()) {
1566af6ee580SValentin Clement         auto len = this->genConstantOffset(loc, rewriter, ty.getLen());
1567af6ee580SValentin Clement         return doCharacter(charWidth, len);
1568af6ee580SValentin Clement       }
1569af6ee580SValentin Clement       assert(!lenParams.empty());
1570af6ee580SValentin Clement       return doCharacter(charWidth, lenParams.back());
1571af6ee580SValentin Clement     }
1572af6ee580SValentin Clement     // Logical type.
1573af6ee580SValentin Clement     if (auto ty = boxEleTy.dyn_cast<fir::LogicalType>())
1574af6ee580SValentin Clement       return doLogical(getKindMap().getLogicalBitsize(ty.getFKind()));
1575af6ee580SValentin Clement     // Array types.
1576af6ee580SValentin Clement     if (auto seqTy = boxEleTy.dyn_cast<fir::SequenceType>())
1577af6ee580SValentin Clement       return getSizeAndTypeCode(loc, rewriter, seqTy.getEleTy(), lenParams);
1578af6ee580SValentin Clement     // Derived-type types.
1579af6ee580SValentin Clement     if (boxEleTy.isa<fir::RecordType>()) {
1580af6ee580SValentin Clement       auto ptrTy = mlir::LLVM::LLVMPointerType::get(
1581af6ee580SValentin Clement           this->lowerTy().convertType(boxEleTy));
1582af6ee580SValentin Clement       auto nullPtr = rewriter.create<mlir::LLVM::NullOp>(loc, ptrTy);
1583af6ee580SValentin Clement       auto one =
1584af6ee580SValentin Clement           genConstantIndex(loc, this->lowerTy().offsetType(), rewriter, 1);
158530122656SAlex Zinenko       auto gep = rewriter.create<mlir::LLVM::GEPOp>(loc, ptrTy, nullPtr,
158630122656SAlex Zinenko                                                     mlir::ValueRange{one});
1587af6ee580SValentin Clement       auto eleSize = rewriter.create<mlir::LLVM::PtrToIntOp>(
1588af6ee580SValentin Clement           loc, this->lowerTy().indexType(), gep);
1589af6ee580SValentin Clement       return {eleSize,
1590af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, fir::derivedToTypeCode())};
1591af6ee580SValentin Clement     }
1592af6ee580SValentin Clement     // Reference type.
1593af6ee580SValentin Clement     if (fir::isa_ref_type(boxEleTy)) {
1594af6ee580SValentin Clement       // FIXME: use the target pointer size rather than sizeof(void*)
1595af6ee580SValentin Clement       return {this->genConstantOffset(loc, rewriter, sizeof(void *)),
1596af6ee580SValentin Clement               this->genConstantOffset(loc, rewriter, CFI_type_cptr)};
1597af6ee580SValentin Clement     }
1598af6ee580SValentin Clement     fir::emitFatalError(loc, "unhandled type in fir.box code generation");
1599af6ee580SValentin Clement   }
1600af6ee580SValentin Clement 
1601af6ee580SValentin Clement   /// Basic pattern to write a field in the descriptor
1602af6ee580SValentin Clement   mlir::Value insertField(mlir::ConversionPatternRewriter &rewriter,
1603af6ee580SValentin Clement                           mlir::Location loc, mlir::Value dest,
1604af6ee580SValentin Clement                           ArrayRef<unsigned> fldIndexes, mlir::Value value,
1605af6ee580SValentin Clement                           bool bitcast = false) const {
1606af6ee580SValentin Clement     auto boxTy = dest.getType();
1607af6ee580SValentin Clement     auto fldTy = this->getBoxEleTy(boxTy, fldIndexes);
1608af6ee580SValentin Clement     if (bitcast)
1609af6ee580SValentin Clement       value = rewriter.create<mlir::LLVM::BitcastOp>(loc, fldTy, value);
1610af6ee580SValentin Clement     else
1611af6ee580SValentin Clement       value = this->integerCast(loc, rewriter, fldTy, value);
1612af6ee580SValentin Clement     SmallVector<mlir::Attribute, 2> attrs;
1613af6ee580SValentin Clement     for (auto i : fldIndexes)
1614af6ee580SValentin Clement       attrs.push_back(rewriter.getI32IntegerAttr(i));
1615af6ee580SValentin Clement     auto indexesAttr = mlir::ArrayAttr::get(rewriter.getContext(), attrs);
1616af6ee580SValentin Clement     return rewriter.create<mlir::LLVM::InsertValueOp>(loc, boxTy, dest, value,
1617af6ee580SValentin Clement                                                       indexesAttr);
1618af6ee580SValentin Clement   }
1619af6ee580SValentin Clement 
1620af6ee580SValentin Clement   inline mlir::Value
1621af6ee580SValentin Clement   insertBaseAddress(mlir::ConversionPatternRewriter &rewriter,
1622af6ee580SValentin Clement                     mlir::Location loc, mlir::Value dest,
1623af6ee580SValentin Clement                     mlir::Value base) const {
16241f551032SValentin Clement     return insertField(rewriter, loc, dest, {kAddrPosInBox}, base,
16251f551032SValentin Clement                        /*bitCast=*/true);
16261f551032SValentin Clement   }
16271f551032SValentin Clement 
16281f551032SValentin Clement   inline mlir::Value insertLowerBound(mlir::ConversionPatternRewriter &rewriter,
16291f551032SValentin Clement                                       mlir::Location loc, mlir::Value dest,
16301f551032SValentin Clement                                       unsigned dim, mlir::Value lb) const {
16311f551032SValentin Clement     return insertField(rewriter, loc, dest,
16321f551032SValentin Clement                        {kDimsPosInBox, dim, kDimLowerBoundPos}, lb);
16331f551032SValentin Clement   }
16341f551032SValentin Clement 
16351f551032SValentin Clement   inline mlir::Value insertExtent(mlir::ConversionPatternRewriter &rewriter,
16361f551032SValentin Clement                                   mlir::Location loc, mlir::Value dest,
16371f551032SValentin Clement                                   unsigned dim, mlir::Value extent) const {
16381f551032SValentin Clement     return insertField(rewriter, loc, dest, {kDimsPosInBox, dim, kDimExtentPos},
16391f551032SValentin Clement                        extent);
16401f551032SValentin Clement   }
16411f551032SValentin Clement 
16421f551032SValentin Clement   inline mlir::Value insertStride(mlir::ConversionPatternRewriter &rewriter,
16431f551032SValentin Clement                                   mlir::Location loc, mlir::Value dest,
16441f551032SValentin Clement                                   unsigned dim, mlir::Value stride) const {
16451f551032SValentin Clement     return insertField(rewriter, loc, dest, {kDimsPosInBox, dim, kDimStridePos},
16461f551032SValentin Clement                        stride);
1647af6ee580SValentin Clement   }
1648af6ee580SValentin Clement 
1649af6ee580SValentin Clement   /// Get the address of the type descriptor global variable that was created by
1650af6ee580SValentin Clement   /// lowering for derived type \p recType.
1651af6ee580SValentin Clement   template <typename BOX>
1652af6ee580SValentin Clement   mlir::Value
1653af6ee580SValentin Clement   getTypeDescriptor(BOX box, mlir::ConversionPatternRewriter &rewriter,
1654af6ee580SValentin Clement                     mlir::Location loc, fir::RecordType recType) const {
165574acd744SValentin Clement     std::string name = recType.translateNameToFrontendMangledName();
1656af6ee580SValentin Clement     auto module = box->template getParentOfType<mlir::ModuleOp>();
1657af6ee580SValentin Clement     if (auto global = module.template lookupSymbol<fir::GlobalOp>(name)) {
1658af6ee580SValentin Clement       auto ty = mlir::LLVM::LLVMPointerType::get(
1659af6ee580SValentin Clement           this->lowerTy().convertType(global.getType()));
1660af6ee580SValentin Clement       return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty,
1661feeee78aSJacques Pienaar                                                       global.getSymName());
1662af6ee580SValentin Clement     }
1663af6ee580SValentin Clement     if (auto global =
1664af6ee580SValentin Clement             module.template lookupSymbol<mlir::LLVM::GlobalOp>(name)) {
1665af6ee580SValentin Clement       // The global may have already been translated to LLVM.
1666af6ee580SValentin Clement       auto ty = mlir::LLVM::LLVMPointerType::get(global.getType());
1667af6ee580SValentin Clement       return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty,
1668feeee78aSJacques Pienaar                                                       global.getSymName());
1669af6ee580SValentin Clement     }
1670*7dd7ccd2SJean Perier     auto i8Ty = rewriter.getIntegerType(8);
1671*7dd7ccd2SJean Perier     if (fir::NameUniquer::belongsToModule(
1672*7dd7ccd2SJean Perier             name, Fortran::semantics::typeInfoBuiltinModule)) {
1673*7dd7ccd2SJean Perier       // Type info derived types do not have type descriptors since they are the
1674*7dd7ccd2SJean Perier       // types defining type descriptors.
1675*7dd7ccd2SJean Perier       auto i8PtrTy = mlir::LLVM::LLVMPointerType::get(i8Ty);
1676*7dd7ccd2SJean Perier       return rewriter.create<mlir::LLVM::NullOp>(loc, i8PtrTy);
1677*7dd7ccd2SJean Perier     }
1678af6ee580SValentin Clement     // The global does not exist in the current translation unit, but may be
1679af6ee580SValentin Clement     // defined elsewhere (e.g., type defined in a module).
1680*7dd7ccd2SJean Perier     // Create an available_externally global to require the symbols to be
1681af6ee580SValentin Clement     // defined elsewhere and to cause link-time failure otherwise.
1682af6ee580SValentin Clement     mlir::OpBuilder modBuilder(module.getBodyRegion());
1683*7dd7ccd2SJean Perier     modBuilder.create<mlir::LLVM::GlobalOp>(
1684*7dd7ccd2SJean Perier         loc, i8Ty, /*isConstant=*/true,
1685*7dd7ccd2SJean Perier         mlir::LLVM::Linkage::AvailableExternally, name, mlir::Attribute{});
1686af6ee580SValentin Clement     auto ty = mlir::LLVM::LLVMPointerType::get(i8Ty);
1687af6ee580SValentin Clement     return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty, name);
1688af6ee580SValentin Clement   }
1689af6ee580SValentin Clement 
1690af6ee580SValentin Clement   template <typename BOX>
1691af6ee580SValentin Clement   std::tuple<fir::BoxType, mlir::Value, mlir::Value>
1692af6ee580SValentin Clement   consDescriptorPrefix(BOX box, mlir::ConversionPatternRewriter &rewriter,
1693af6ee580SValentin Clement                        unsigned rank, mlir::ValueRange lenParams) const {
1694af6ee580SValentin Clement     auto loc = box.getLoc();
1695af6ee580SValentin Clement     auto boxTy = box.getType().template dyn_cast<fir::BoxType>();
1696af6ee580SValentin Clement     auto convTy = this->lowerTy().convertBoxType(boxTy, rank);
1697af6ee580SValentin Clement     auto llvmBoxPtrTy = convTy.template cast<mlir::LLVM::LLVMPointerType>();
1698af6ee580SValentin Clement     auto llvmBoxTy = llvmBoxPtrTy.getElementType();
1699af6ee580SValentin Clement     mlir::Value descriptor =
1700af6ee580SValentin Clement         rewriter.create<mlir::LLVM::UndefOp>(loc, llvmBoxTy);
1701af6ee580SValentin Clement 
1702af6ee580SValentin Clement     llvm::SmallVector<mlir::Value> typeparams = lenParams;
1703af6ee580SValentin Clement     if constexpr (!std::is_same_v<BOX, fir::EmboxOp>) {
1704af6ee580SValentin Clement       if (!box.substr().empty() && fir::hasDynamicSize(boxTy.getEleTy()))
1705af6ee580SValentin Clement         typeparams.push_back(box.substr()[1]);
1706af6ee580SValentin Clement     }
1707af6ee580SValentin Clement 
1708af6ee580SValentin Clement     // Write each of the fields with the appropriate values
1709af6ee580SValentin Clement     auto [eleSize, cfiTy] =
1710af6ee580SValentin Clement         getSizeAndTypeCode(loc, rewriter, boxTy.getEleTy(), typeparams);
1711af6ee580SValentin Clement     descriptor =
1712af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kElemLenPosInBox}, eleSize);
1713af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kVersionPosInBox},
1714af6ee580SValentin Clement                              this->genI32Constant(loc, rewriter, CFI_VERSION));
1715af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kRankPosInBox},
1716af6ee580SValentin Clement                              this->genI32Constant(loc, rewriter, rank));
1717af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kTypePosInBox}, cfiTy);
1718af6ee580SValentin Clement     descriptor =
1719af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kAttributePosInBox},
1720af6ee580SValentin Clement                     this->genI32Constant(loc, rewriter, getCFIAttr(boxTy)));
1721af6ee580SValentin Clement     const bool hasAddendum = isDerivedType(boxTy);
1722af6ee580SValentin Clement     descriptor =
1723af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kF18AddendumPosInBox},
1724af6ee580SValentin Clement                     this->genI32Constant(loc, rewriter, hasAddendum ? 1 : 0));
1725af6ee580SValentin Clement 
1726af6ee580SValentin Clement     if (hasAddendum) {
1727af6ee580SValentin Clement       auto isArray =
1728af6ee580SValentin Clement           fir::dyn_cast_ptrOrBoxEleTy(boxTy).template isa<fir::SequenceType>();
1729af6ee580SValentin Clement       unsigned typeDescFieldId = isArray ? kOptTypePtrPosInBox : kDimsPosInBox;
1730af6ee580SValentin Clement       auto typeDesc =
1731af6ee580SValentin Clement           getTypeDescriptor(box, rewriter, loc, unwrapIfDerived(boxTy));
1732af6ee580SValentin Clement       descriptor =
1733af6ee580SValentin Clement           insertField(rewriter, loc, descriptor, {typeDescFieldId}, typeDesc,
1734af6ee580SValentin Clement                       /*bitCast=*/true);
1735af6ee580SValentin Clement     }
1736af6ee580SValentin Clement 
1737af6ee580SValentin Clement     return {boxTy, descriptor, eleSize};
1738af6ee580SValentin Clement   }
1739af6ee580SValentin Clement 
17401f551032SValentin Clement   /// Compute the base address of a substring given the base address of a scalar
17411f551032SValentin Clement   /// string and the zero based string lower bound.
17421f551032SValentin Clement   mlir::Value shiftSubstringBase(mlir::ConversionPatternRewriter &rewriter,
17431f551032SValentin Clement                                  mlir::Location loc, mlir::Value base,
17441f551032SValentin Clement                                  mlir::Value lowerBound) const {
17451f551032SValentin Clement     llvm::SmallVector<mlir::Value> gepOperands;
17461f551032SValentin Clement     auto baseType =
17471f551032SValentin Clement         base.getType().cast<mlir::LLVM::LLVMPointerType>().getElementType();
17481f551032SValentin Clement     if (baseType.isa<mlir::LLVM::LLVMArrayType>()) {
17491f551032SValentin Clement       auto idxTy = this->lowerTy().indexType();
17501f551032SValentin Clement       mlir::Value zero = genConstantIndex(loc, idxTy, rewriter, 0);
17511f551032SValentin Clement       gepOperands.push_back(zero);
17521f551032SValentin Clement     }
17531f551032SValentin Clement     gepOperands.push_back(lowerBound);
17541f551032SValentin Clement     return this->genGEP(loc, base.getType(), rewriter, base, gepOperands);
17551f551032SValentin Clement   }
17561f551032SValentin Clement 
1757af6ee580SValentin Clement   /// If the embox is not in a globalOp body, allocate storage for the box;
1758af6ee580SValentin Clement   /// store the value inside and return the generated alloca. Return the input
1759af6ee580SValentin Clement   /// value otherwise.
1760af6ee580SValentin Clement   mlir::Value
1761af6ee580SValentin Clement   placeInMemoryIfNotGlobalInit(mlir::ConversionPatternRewriter &rewriter,
1762af6ee580SValentin Clement                                mlir::Location loc, mlir::Value boxValue) const {
1763af6ee580SValentin Clement     auto *thisBlock = rewriter.getInsertionBlock();
1764af6ee580SValentin Clement     if (thisBlock && mlir::isa<mlir::LLVM::GlobalOp>(thisBlock->getParentOp()))
1765af6ee580SValentin Clement       return boxValue;
1766af6ee580SValentin Clement     auto boxPtrTy = mlir::LLVM::LLVMPointerType::get(boxValue.getType());
1767af6ee580SValentin Clement     auto alloca = genAllocaWithType(loc, boxPtrTy, defaultAlign, rewriter);
1768af6ee580SValentin Clement     rewriter.create<mlir::LLVM::StoreOp>(loc, boxValue, alloca);
1769af6ee580SValentin Clement     return alloca;
1770af6ee580SValentin Clement   }
1771af6ee580SValentin Clement };
1772af6ee580SValentin Clement 
17731f551032SValentin Clement /// Compute the extent of a triplet slice (lb:ub:step).
17741f551032SValentin Clement static mlir::Value
17751f551032SValentin Clement computeTripletExtent(mlir::ConversionPatternRewriter &rewriter,
17761f551032SValentin Clement                      mlir::Location loc, mlir::Value lb, mlir::Value ub,
17771f551032SValentin Clement                      mlir::Value step, mlir::Value zero, mlir::Type type) {
17781f551032SValentin Clement   mlir::Value extent = rewriter.create<mlir::LLVM::SubOp>(loc, type, ub, lb);
17791f551032SValentin Clement   extent = rewriter.create<mlir::LLVM::AddOp>(loc, type, extent, step);
17801f551032SValentin Clement   extent = rewriter.create<mlir::LLVM::SDivOp>(loc, type, extent, step);
17811f551032SValentin Clement   // If the resulting extent is negative (`ub-lb` and `step` have different
17821f551032SValentin Clement   // signs), zero must be returned instead.
17831f551032SValentin Clement   auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
17841f551032SValentin Clement       loc, mlir::LLVM::ICmpPredicate::sgt, extent, zero);
17851f551032SValentin Clement   return rewriter.create<mlir::LLVM::SelectOp>(loc, cmp, extent, zero);
17861f551032SValentin Clement }
17871f551032SValentin Clement 
1788af6ee580SValentin Clement /// Create a generic box on a memory reference. This conversions lowers the
1789af6ee580SValentin Clement /// abstract box to the appropriate, initialized descriptor.
1790af6ee580SValentin Clement struct EmboxOpConversion : public EmboxCommonConversion<fir::EmboxOp> {
1791af6ee580SValentin Clement   using EmboxCommonConversion::EmboxCommonConversion;
1792af6ee580SValentin Clement 
1793af6ee580SValentin Clement   mlir::LogicalResult
1794af6ee580SValentin Clement   matchAndRewrite(fir::EmboxOp embox, OpAdaptor adaptor,
1795af6ee580SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
1796af6ee580SValentin Clement     assert(!embox.getShape() && "There should be no dims on this embox op");
1797af6ee580SValentin Clement     auto [boxTy, dest, eleSize] =
1798af6ee580SValentin Clement         consDescriptorPrefix(embox, rewriter, /*rank=*/0,
1799af6ee580SValentin Clement                              /*lenParams=*/adaptor.getOperands().drop_front(1));
1800af6ee580SValentin Clement     dest = insertBaseAddress(rewriter, embox.getLoc(), dest,
1801af6ee580SValentin Clement                              adaptor.getOperands()[0]);
18027ce8c6fcSKiran Chandramohan     if (isDerivedTypeWithLenParams(boxTy)) {
18037ce8c6fcSKiran Chandramohan       TODO(embox.getLoc(),
18047ce8c6fcSKiran Chandramohan            "fir.embox codegen of derived with length parameters");
18057ce8c6fcSKiran Chandramohan       return failure();
18067ce8c6fcSKiran Chandramohan     }
1807af6ee580SValentin Clement     auto result = placeInMemoryIfNotGlobalInit(rewriter, embox.getLoc(), dest);
1808af6ee580SValentin Clement     rewriter.replaceOp(embox, result);
1809af6ee580SValentin Clement     return success();
1810af6ee580SValentin Clement   }
1811af6ee580SValentin Clement };
1812af6ee580SValentin Clement 
1813cc505c0bSKiran Chandramohan /// Lower `fir.emboxproc` operation. Creates a procedure box.
1814cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
1815cc505c0bSKiran Chandramohan struct EmboxProcOpConversion : public FIROpConversion<fir::EmboxProcOp> {
1816cc505c0bSKiran Chandramohan   using FIROpConversion::FIROpConversion;
1817cc505c0bSKiran Chandramohan 
1818cc505c0bSKiran Chandramohan   mlir::LogicalResult
1819cc505c0bSKiran Chandramohan   matchAndRewrite(fir::EmboxProcOp emboxproc, OpAdaptor adaptor,
1820cc505c0bSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
18217ce8c6fcSKiran Chandramohan     TODO(emboxproc.getLoc(), "fir.emboxproc codegen");
18227ce8c6fcSKiran Chandramohan     return failure();
1823cc505c0bSKiran Chandramohan   }
1824cc505c0bSKiran Chandramohan };
1825cc505c0bSKiran Chandramohan 
18261f551032SValentin Clement /// Create a generic box on a memory reference.
18271f551032SValentin Clement struct XEmboxOpConversion : public EmboxCommonConversion<fir::cg::XEmboxOp> {
18281f551032SValentin Clement   using EmboxCommonConversion::EmboxCommonConversion;
18291f551032SValentin Clement 
18301f551032SValentin Clement   mlir::LogicalResult
18311f551032SValentin Clement   matchAndRewrite(fir::cg::XEmboxOp xbox, OpAdaptor adaptor,
18321f551032SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
18331f551032SValentin Clement     auto [boxTy, dest, eleSize] = consDescriptorPrefix(
18341f551032SValentin Clement         xbox, rewriter, xbox.getOutRank(),
18351f551032SValentin Clement         adaptor.getOperands().drop_front(xbox.lenParamOffset()));
18361f551032SValentin Clement     // Generate the triples in the dims field of the descriptor
18371f551032SValentin Clement     mlir::ValueRange operands = adaptor.getOperands();
18381f551032SValentin Clement     auto i64Ty = mlir::IntegerType::get(xbox.getContext(), 64);
18391f551032SValentin Clement     mlir::Value base = operands[0];
18401f551032SValentin Clement     assert(!xbox.shape().empty() && "must have a shape");
18411f551032SValentin Clement     unsigned shapeOffset = xbox.shapeOffset();
18421f551032SValentin Clement     bool hasShift = !xbox.shift().empty();
18431f551032SValentin Clement     unsigned shiftOffset = xbox.shiftOffset();
18441f551032SValentin Clement     bool hasSlice = !xbox.slice().empty();
18451f551032SValentin Clement     unsigned sliceOffset = xbox.sliceOffset();
18461f551032SValentin Clement     mlir::Location loc = xbox.getLoc();
18471f551032SValentin Clement     mlir::Value zero = genConstantIndex(loc, i64Ty, rewriter, 0);
18481f551032SValentin Clement     mlir::Value one = genConstantIndex(loc, i64Ty, rewriter, 1);
18491f551032SValentin Clement     mlir::Value prevDim = integerCast(loc, rewriter, i64Ty, eleSize);
18501f551032SValentin Clement     mlir::Value prevPtrOff = one;
18511f551032SValentin Clement     mlir::Type eleTy = boxTy.getEleTy();
18521f551032SValentin Clement     const unsigned rank = xbox.getRank();
18531f551032SValentin Clement     llvm::SmallVector<mlir::Value> gepArgs;
18541f551032SValentin Clement     unsigned constRows = 0;
18551f551032SValentin Clement     mlir::Value ptrOffset = zero;
18561f551032SValentin Clement     if (auto memEleTy = fir::dyn_cast_ptrEleTy(xbox.memref().getType()))
18571f551032SValentin Clement       if (auto seqTy = memEleTy.dyn_cast<fir::SequenceType>()) {
18581f551032SValentin Clement         mlir::Type seqEleTy = seqTy.getEleTy();
18591f551032SValentin Clement         // Adjust the element scaling factor if the element is a dependent type.
18601f551032SValentin Clement         if (fir::hasDynamicSize(seqEleTy)) {
18611f551032SValentin Clement           if (fir::isa_char(seqEleTy)) {
18621f551032SValentin Clement             assert(xbox.lenParams().size() == 1);
18631f551032SValentin Clement             prevPtrOff = integerCast(loc, rewriter, i64Ty,
18641f551032SValentin Clement                                      operands[xbox.lenParamOffset()]);
18651f551032SValentin Clement           } else if (seqEleTy.isa<fir::RecordType>()) {
18661f551032SValentin Clement             TODO(loc, "generate call to calculate size of PDT");
18671f551032SValentin Clement           } else {
18681f551032SValentin Clement             return rewriter.notifyMatchFailure(xbox, "unexpected dynamic type");
18691f551032SValentin Clement           }
18701f551032SValentin Clement         } else {
18711f551032SValentin Clement           constRows = seqTy.getConstantRows();
18721f551032SValentin Clement         }
18731f551032SValentin Clement       }
18741f551032SValentin Clement 
18751f551032SValentin Clement     bool hasSubcomp = !xbox.subcomponent().empty();
18761f551032SValentin Clement     mlir::Value stepExpr;
18771f551032SValentin Clement     if (hasSubcomp) {
18781f551032SValentin Clement       // We have a subcomponent. The step value needs to be the number of
18791f551032SValentin Clement       // bytes per element (which is a derived type).
18801f551032SValentin Clement       mlir::Type ty0 = base.getType();
18811f551032SValentin Clement       [[maybe_unused]] auto ptrTy = ty0.dyn_cast<mlir::LLVM::LLVMPointerType>();
18821f551032SValentin Clement       assert(ptrTy && "expected pointer type");
18831f551032SValentin Clement       mlir::Type memEleTy = fir::dyn_cast_ptrEleTy(xbox.memref().getType());
18841f551032SValentin Clement       assert(memEleTy && "expected fir pointer type");
18851f551032SValentin Clement       auto seqTy = memEleTy.dyn_cast<fir::SequenceType>();
18861f551032SValentin Clement       assert(seqTy && "expected sequence type");
18871f551032SValentin Clement       mlir::Type seqEleTy = seqTy.getEleTy();
18881f551032SValentin Clement       auto eleTy = mlir::LLVM::LLVMPointerType::get(convertType(seqEleTy));
18891f551032SValentin Clement       stepExpr = computeDerivedTypeSize(loc, eleTy, i64Ty, rewriter);
18901f551032SValentin Clement     }
18911f551032SValentin Clement 
18921f551032SValentin Clement     // Process the array subspace arguments (shape, shift, etc.), if any,
18931f551032SValentin Clement     // translating everything to values in the descriptor wherever the entity
18941f551032SValentin Clement     // has a dynamic array dimension.
18951f551032SValentin Clement     for (unsigned di = 0, descIdx = 0; di < rank; ++di) {
18961f551032SValentin Clement       mlir::Value extent = operands[shapeOffset];
18971f551032SValentin Clement       mlir::Value outerExtent = extent;
18981f551032SValentin Clement       bool skipNext = false;
18991f551032SValentin Clement       if (hasSlice) {
19001f551032SValentin Clement         mlir::Value off = operands[sliceOffset];
19011f551032SValentin Clement         mlir::Value adj = one;
19021f551032SValentin Clement         if (hasShift)
19031f551032SValentin Clement           adj = operands[shiftOffset];
19041f551032SValentin Clement         auto ao = rewriter.create<mlir::LLVM::SubOp>(loc, i64Ty, off, adj);
19051f551032SValentin Clement         if (constRows > 0) {
19061f551032SValentin Clement           gepArgs.push_back(ao);
19071f551032SValentin Clement           --constRows;
19081f551032SValentin Clement         } else {
19091f551032SValentin Clement           auto dimOff =
19101f551032SValentin Clement               rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, ao, prevPtrOff);
19111f551032SValentin Clement           ptrOffset =
19121f551032SValentin Clement               rewriter.create<mlir::LLVM::AddOp>(loc, i64Ty, dimOff, ptrOffset);
19131f551032SValentin Clement         }
19141f551032SValentin Clement         if (mlir::isa_and_nonnull<fir::UndefOp>(
19151f551032SValentin Clement                 xbox.slice()[3 * di + 1].getDefiningOp())) {
19161f551032SValentin Clement           // This dimension contains a scalar expression in the array slice op.
19171f551032SValentin Clement           // The dimension is loop invariant, will be dropped, and will not
19181f551032SValentin Clement           // appear in the descriptor.
19191f551032SValentin Clement           skipNext = true;
19201f551032SValentin Clement         }
19211f551032SValentin Clement       }
19221f551032SValentin Clement       if (!skipNext) {
19231f551032SValentin Clement         // store lower bound (normally 0)
19241f551032SValentin Clement         mlir::Value lb = zero;
19251f551032SValentin Clement         if (eleTy.isa<fir::PointerType>() || eleTy.isa<fir::HeapType>()) {
19261f551032SValentin Clement           lb = one;
19271f551032SValentin Clement           if (hasShift)
19281f551032SValentin Clement             lb = operands[shiftOffset];
19291f551032SValentin Clement         }
19301f551032SValentin Clement         dest = insertLowerBound(rewriter, loc, dest, descIdx, lb);
19311f551032SValentin Clement 
19321f551032SValentin Clement         // store extent
19331f551032SValentin Clement         if (hasSlice)
19341f551032SValentin Clement           extent = computeTripletExtent(rewriter, loc, operands[sliceOffset],
19351f551032SValentin Clement                                         operands[sliceOffset + 1],
19361f551032SValentin Clement                                         operands[sliceOffset + 2], zero, i64Ty);
19371f551032SValentin Clement         dest = insertExtent(rewriter, loc, dest, descIdx, extent);
19381f551032SValentin Clement 
19391f551032SValentin Clement         // store step (scaled by shaped extent)
19401f551032SValentin Clement 
19411f551032SValentin Clement         mlir::Value step = hasSubcomp ? stepExpr : prevDim;
19421f551032SValentin Clement         if (hasSlice)
19431f551032SValentin Clement           step = rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, step,
19441f551032SValentin Clement                                                     operands[sliceOffset + 2]);
19451f551032SValentin Clement         dest = insertStride(rewriter, loc, dest, descIdx, step);
19461f551032SValentin Clement         ++descIdx;
19471f551032SValentin Clement       }
19481f551032SValentin Clement 
19491f551032SValentin Clement       // compute the stride and offset for the next natural dimension
19501f551032SValentin Clement       prevDim =
19511f551032SValentin Clement           rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, prevDim, outerExtent);
19521f551032SValentin Clement       if (constRows == 0)
19531f551032SValentin Clement         prevPtrOff = rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, prevPtrOff,
19541f551032SValentin Clement                                                         outerExtent);
19551f551032SValentin Clement 
19561f551032SValentin Clement       // increment iterators
19571f551032SValentin Clement       ++shapeOffset;
19581f551032SValentin Clement       if (hasShift)
19591f551032SValentin Clement         ++shiftOffset;
19601f551032SValentin Clement       if (hasSlice)
19611f551032SValentin Clement         sliceOffset += 3;
19621f551032SValentin Clement     }
19631f551032SValentin Clement     if (hasSlice || hasSubcomp || !xbox.substr().empty()) {
196430122656SAlex Zinenko       llvm::SmallVector<mlir::Value> args = {ptrOffset};
19651f551032SValentin Clement       args.append(gepArgs.rbegin(), gepArgs.rend());
19661f551032SValentin Clement       if (hasSubcomp) {
19671f551032SValentin Clement         // For each field in the path add the offset to base via the args list.
19681f551032SValentin Clement         // In the most general case, some offsets must be computed since
19691f551032SValentin Clement         // they are not be known until runtime.
19701f551032SValentin Clement         if (fir::hasDynamicSize(fir::unwrapSequenceType(
19711f551032SValentin Clement                 fir::unwrapPassByRefType(xbox.memref().getType()))))
19721f551032SValentin Clement           TODO(loc, "fir.embox codegen dynamic size component in derived type");
19731f551032SValentin Clement         args.append(operands.begin() + xbox.subcomponentOffset(),
19741f551032SValentin Clement                     operands.begin() + xbox.subcomponentOffset() +
19751f551032SValentin Clement                         xbox.subcomponent().size());
19761f551032SValentin Clement       }
197730122656SAlex Zinenko       base =
197830122656SAlex Zinenko           rewriter.create<mlir::LLVM::GEPOp>(loc, base.getType(), base, args);
19791f551032SValentin Clement       if (!xbox.substr().empty())
19801f551032SValentin Clement         base = shiftSubstringBase(rewriter, loc, base,
19811f551032SValentin Clement                                   operands[xbox.substrOffset()]);
19821f551032SValentin Clement     }
19831f551032SValentin Clement     dest = insertBaseAddress(rewriter, loc, dest, base);
19841f551032SValentin Clement     if (isDerivedTypeWithLenParams(boxTy))
19851f551032SValentin Clement       TODO(loc, "fir.embox codegen of derived with length parameters");
19861f551032SValentin Clement 
19871f551032SValentin Clement     mlir::Value result = placeInMemoryIfNotGlobalInit(rewriter, loc, dest);
19881f551032SValentin Clement     rewriter.replaceOp(xbox, result);
19891f551032SValentin Clement     return success();
19901f551032SValentin Clement   }
19911f551032SValentin Clement };
19921f551032SValentin Clement 
1993fa517555SKiran Chandramohan /// Create a new box given a box reference.
1994fa517555SKiran Chandramohan struct XReboxOpConversion : public EmboxCommonConversion<fir::cg::XReboxOp> {
1995fa517555SKiran Chandramohan   using EmboxCommonConversion::EmboxCommonConversion;
1996fa517555SKiran Chandramohan 
1997fa517555SKiran Chandramohan   mlir::LogicalResult
1998fa517555SKiran Chandramohan   matchAndRewrite(fir::cg::XReboxOp rebox, OpAdaptor adaptor,
1999fa517555SKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2000fa517555SKiran Chandramohan     mlir::Location loc = rebox.getLoc();
2001fa517555SKiran Chandramohan     mlir::Type idxTy = lowerTy().indexType();
2002fa517555SKiran Chandramohan     mlir::Value loweredBox = adaptor.getOperands()[0];
2003fa517555SKiran Chandramohan     mlir::ValueRange operands = adaptor.getOperands();
2004fa517555SKiran Chandramohan 
2005fa517555SKiran Chandramohan     // Create new descriptor and fill its non-shape related data.
2006fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value, 2> lenParams;
2007fa517555SKiran Chandramohan     mlir::Type inputEleTy = getInputEleTy(rebox);
2008fa517555SKiran Chandramohan     if (auto charTy = inputEleTy.dyn_cast<fir::CharacterType>()) {
2009fa517555SKiran Chandramohan       mlir::Value len =
2010fa517555SKiran Chandramohan           loadElementSizeFromBox(loc, idxTy, loweredBox, rewriter);
2011fa517555SKiran Chandramohan       if (charTy.getFKind() != 1) {
2012fa517555SKiran Chandramohan         mlir::Value width =
2013fa517555SKiran Chandramohan             genConstantIndex(loc, idxTy, rewriter, charTy.getFKind());
2014fa517555SKiran Chandramohan         len = rewriter.create<mlir::LLVM::SDivOp>(loc, idxTy, len, width);
2015fa517555SKiran Chandramohan       }
2016fa517555SKiran Chandramohan       lenParams.emplace_back(len);
2017fa517555SKiran Chandramohan     } else if (auto recTy = inputEleTy.dyn_cast<fir::RecordType>()) {
2018fa517555SKiran Chandramohan       if (recTy.getNumLenParams() != 0)
2019fa517555SKiran Chandramohan         TODO(loc, "reboxing descriptor of derived type with length parameters");
2020fa517555SKiran Chandramohan     }
2021fa517555SKiran Chandramohan     auto [boxTy, dest, eleSize] =
2022fa517555SKiran Chandramohan         consDescriptorPrefix(rebox, rewriter, rebox.getOutRank(), lenParams);
2023fa517555SKiran Chandramohan 
2024fa517555SKiran Chandramohan     // Read input extents, strides, and base address
2025fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> inputExtents;
2026fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> inputStrides;
2027fa517555SKiran Chandramohan     const unsigned inputRank = rebox.getRank();
2028fa517555SKiran Chandramohan     for (unsigned i = 0; i < inputRank; ++i) {
2029fa517555SKiran Chandramohan       mlir::Value dim = genConstantIndex(loc, idxTy, rewriter, i);
2030fa517555SKiran Chandramohan       SmallVector<mlir::Value, 3> dimInfo =
2031fa517555SKiran Chandramohan           getDimsFromBox(loc, {idxTy, idxTy, idxTy}, loweredBox, dim, rewriter);
2032fa517555SKiran Chandramohan       inputExtents.emplace_back(dimInfo[1]);
2033fa517555SKiran Chandramohan       inputStrides.emplace_back(dimInfo[2]);
2034fa517555SKiran Chandramohan     }
2035fa517555SKiran Chandramohan 
2036fa517555SKiran Chandramohan     mlir::Type baseTy = getBaseAddrTypeFromBox(loweredBox.getType());
2037fa517555SKiran Chandramohan     mlir::Value baseAddr =
2038fa517555SKiran Chandramohan         loadBaseAddrFromBox(loc, baseTy, loweredBox, rewriter);
2039fa517555SKiran Chandramohan 
2040fa517555SKiran Chandramohan     if (!rebox.slice().empty() || !rebox.subcomponent().empty())
2041fa517555SKiran Chandramohan       return sliceBox(rebox, dest, baseAddr, inputExtents, inputStrides,
2042fa517555SKiran Chandramohan                       operands, rewriter);
2043fa517555SKiran Chandramohan     return reshapeBox(rebox, dest, baseAddr, inputExtents, inputStrides,
2044fa517555SKiran Chandramohan                       operands, rewriter);
2045fa517555SKiran Chandramohan   }
2046fa517555SKiran Chandramohan 
2047fa517555SKiran Chandramohan private:
2048fa517555SKiran Chandramohan   /// Write resulting shape and base address in descriptor, and replace rebox
2049fa517555SKiran Chandramohan   /// op.
2050fa517555SKiran Chandramohan   mlir::LogicalResult
2051fa517555SKiran Chandramohan   finalizeRebox(fir::cg::XReboxOp rebox, mlir::Value dest, mlir::Value base,
2052fa517555SKiran Chandramohan                 mlir::ValueRange lbounds, mlir::ValueRange extents,
2053fa517555SKiran Chandramohan                 mlir::ValueRange strides,
2054fa517555SKiran Chandramohan                 mlir::ConversionPatternRewriter &rewriter) const {
2055fa517555SKiran Chandramohan     mlir::Location loc = rebox.getLoc();
2056fa517555SKiran Chandramohan     mlir::Value one = genConstantIndex(loc, lowerTy().indexType(), rewriter, 1);
2057fa517555SKiran Chandramohan     for (auto iter : llvm::enumerate(llvm::zip(extents, strides))) {
2058fa517555SKiran Chandramohan       unsigned dim = iter.index();
2059fa517555SKiran Chandramohan       mlir::Value lb = lbounds.empty() ? one : lbounds[dim];
2060fa517555SKiran Chandramohan       dest = insertLowerBound(rewriter, loc, dest, dim, lb);
2061fa517555SKiran Chandramohan       dest = insertExtent(rewriter, loc, dest, dim, std::get<0>(iter.value()));
2062fa517555SKiran Chandramohan       dest = insertStride(rewriter, loc, dest, dim, std::get<1>(iter.value()));
2063fa517555SKiran Chandramohan     }
2064fa517555SKiran Chandramohan     dest = insertBaseAddress(rewriter, loc, dest, base);
2065fa517555SKiran Chandramohan     mlir::Value result =
2066fa517555SKiran Chandramohan         placeInMemoryIfNotGlobalInit(rewriter, rebox.getLoc(), dest);
2067fa517555SKiran Chandramohan     rewriter.replaceOp(rebox, result);
2068fa517555SKiran Chandramohan     return success();
2069fa517555SKiran Chandramohan   }
2070fa517555SKiran Chandramohan 
2071fa517555SKiran Chandramohan   // Apply slice given the base address, extents and strides of the input box.
2072fa517555SKiran Chandramohan   mlir::LogicalResult
2073fa517555SKiran Chandramohan   sliceBox(fir::cg::XReboxOp rebox, mlir::Value dest, mlir::Value base,
2074fa517555SKiran Chandramohan            mlir::ValueRange inputExtents, mlir::ValueRange inputStrides,
2075fa517555SKiran Chandramohan            mlir::ValueRange operands,
2076fa517555SKiran Chandramohan            mlir::ConversionPatternRewriter &rewriter) const {
2077fa517555SKiran Chandramohan     mlir::Location loc = rebox.getLoc();
2078fa517555SKiran Chandramohan     mlir::Type voidPtrTy = ::getVoidPtrType(rebox.getContext());
2079fa517555SKiran Chandramohan     mlir::Type idxTy = lowerTy().indexType();
2080fa517555SKiran Chandramohan     mlir::Value zero = genConstantIndex(loc, idxTy, rewriter, 0);
2081fa517555SKiran Chandramohan     // Apply subcomponent and substring shift on base address.
2082fa517555SKiran Chandramohan     if (!rebox.subcomponent().empty() || !rebox.substr().empty()) {
2083fa517555SKiran Chandramohan       // Cast to inputEleTy* so that a GEP can be used.
2084fa517555SKiran Chandramohan       mlir::Type inputEleTy = getInputEleTy(rebox);
2085fa517555SKiran Chandramohan       auto llvmElePtrTy =
2086fa517555SKiran Chandramohan           mlir::LLVM::LLVMPointerType::get(convertType(inputEleTy));
2087fa517555SKiran Chandramohan       base = rewriter.create<mlir::LLVM::BitcastOp>(loc, llvmElePtrTy, base);
2088fa517555SKiran Chandramohan 
2089fa517555SKiran Chandramohan       if (!rebox.subcomponent().empty()) {
2090fa517555SKiran Chandramohan         llvm::SmallVector<mlir::Value> gepOperands = {zero};
2091fa517555SKiran Chandramohan         for (unsigned i = 0; i < rebox.subcomponent().size(); ++i)
2092fa517555SKiran Chandramohan           gepOperands.push_back(operands[rebox.subcomponentOffset() + i]);
2093fa517555SKiran Chandramohan         base = genGEP(loc, llvmElePtrTy, rewriter, base, gepOperands);
2094fa517555SKiran Chandramohan       }
2095fa517555SKiran Chandramohan       if (!rebox.substr().empty())
2096fa517555SKiran Chandramohan         base = shiftSubstringBase(rewriter, loc, base,
2097fa517555SKiran Chandramohan                                   operands[rebox.substrOffset()]);
2098fa517555SKiran Chandramohan     }
2099fa517555SKiran Chandramohan 
2100fa517555SKiran Chandramohan     if (rebox.slice().empty())
2101fa517555SKiran Chandramohan       // The array section is of the form array[%component][substring], keep
2102fa517555SKiran Chandramohan       // the input array extents and strides.
2103fa517555SKiran Chandramohan       return finalizeRebox(rebox, dest, base, /*lbounds*/ llvm::None,
2104fa517555SKiran Chandramohan                            inputExtents, inputStrides, rewriter);
2105fa517555SKiran Chandramohan 
2106fa517555SKiran Chandramohan     // Strides from the fir.box are in bytes.
2107fa517555SKiran Chandramohan     base = rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, base);
2108fa517555SKiran Chandramohan 
2109fa517555SKiran Chandramohan     // The slice is of the form array(i:j:k)[%component]. Compute new extents
2110fa517555SKiran Chandramohan     // and strides.
2111fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> slicedExtents;
2112fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> slicedStrides;
2113fa517555SKiran Chandramohan     mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1);
2114fa517555SKiran Chandramohan     const bool sliceHasOrigins = !rebox.shift().empty();
2115fa517555SKiran Chandramohan     unsigned sliceOps = rebox.sliceOffset();
2116fa517555SKiran Chandramohan     unsigned shiftOps = rebox.shiftOffset();
2117fa517555SKiran Chandramohan     auto strideOps = inputStrides.begin();
2118fa517555SKiran Chandramohan     const unsigned inputRank = inputStrides.size();
2119fa517555SKiran Chandramohan     for (unsigned i = 0; i < inputRank;
2120fa517555SKiran Chandramohan          ++i, ++strideOps, ++shiftOps, sliceOps += 3) {
2121fa517555SKiran Chandramohan       mlir::Value sliceLb =
2122fa517555SKiran Chandramohan           integerCast(loc, rewriter, idxTy, operands[sliceOps]);
2123fa517555SKiran Chandramohan       mlir::Value inputStride = *strideOps; // already idxTy
2124fa517555SKiran Chandramohan       // Apply origin shift: base += (lb-shift)*input_stride
2125fa517555SKiran Chandramohan       mlir::Value sliceOrigin =
2126fa517555SKiran Chandramohan           sliceHasOrigins
2127fa517555SKiran Chandramohan               ? integerCast(loc, rewriter, idxTy, operands[shiftOps])
2128fa517555SKiran Chandramohan               : one;
2129fa517555SKiran Chandramohan       mlir::Value diff =
2130fa517555SKiran Chandramohan           rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, sliceLb, sliceOrigin);
2131fa517555SKiran Chandramohan       mlir::Value offset =
2132fa517555SKiran Chandramohan           rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, inputStride);
2133fa517555SKiran Chandramohan       base = genGEP(loc, voidPtrTy, rewriter, base, offset);
2134fa517555SKiran Chandramohan       // Apply upper bound and step if this is a triplet. Otherwise, the
2135fa517555SKiran Chandramohan       // dimension is dropped and no extents/strides are computed.
2136fa517555SKiran Chandramohan       mlir::Value upper = operands[sliceOps + 1];
2137fa517555SKiran Chandramohan       const bool isTripletSlice =
2138fa517555SKiran Chandramohan           !mlir::isa_and_nonnull<mlir::LLVM::UndefOp>(upper.getDefiningOp());
2139fa517555SKiran Chandramohan       if (isTripletSlice) {
2140fa517555SKiran Chandramohan         mlir::Value step =
2141fa517555SKiran Chandramohan             integerCast(loc, rewriter, idxTy, operands[sliceOps + 2]);
2142fa517555SKiran Chandramohan         // extent = ub-lb+step/step
2143fa517555SKiran Chandramohan         mlir::Value sliceUb = integerCast(loc, rewriter, idxTy, upper);
2144fa517555SKiran Chandramohan         mlir::Value extent = computeTripletExtent(rewriter, loc, sliceLb,
2145fa517555SKiran Chandramohan                                                   sliceUb, step, zero, idxTy);
2146fa517555SKiran Chandramohan         slicedExtents.emplace_back(extent);
2147fa517555SKiran Chandramohan         // stride = step*input_stride
2148fa517555SKiran Chandramohan         mlir::Value stride =
2149fa517555SKiran Chandramohan             rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, step, inputStride);
2150fa517555SKiran Chandramohan         slicedStrides.emplace_back(stride);
2151fa517555SKiran Chandramohan       }
2152fa517555SKiran Chandramohan     }
2153fa517555SKiran Chandramohan     return finalizeRebox(rebox, dest, base, /*lbounds*/ llvm::None,
2154fa517555SKiran Chandramohan                          slicedExtents, slicedStrides, rewriter);
2155fa517555SKiran Chandramohan   }
2156fa517555SKiran Chandramohan 
2157fa517555SKiran Chandramohan   /// Apply a new shape to the data described by a box given the base address,
2158fa517555SKiran Chandramohan   /// extents and strides of the box.
2159fa517555SKiran Chandramohan   mlir::LogicalResult
2160fa517555SKiran Chandramohan   reshapeBox(fir::cg::XReboxOp rebox, mlir::Value dest, mlir::Value base,
2161fa517555SKiran Chandramohan              mlir::ValueRange inputExtents, mlir::ValueRange inputStrides,
2162fa517555SKiran Chandramohan              mlir::ValueRange operands,
2163fa517555SKiran Chandramohan              mlir::ConversionPatternRewriter &rewriter) const {
2164fa517555SKiran Chandramohan     mlir::ValueRange reboxShifts{operands.begin() + rebox.shiftOffset(),
2165fa517555SKiran Chandramohan                                  operands.begin() + rebox.shiftOffset() +
2166fa517555SKiran Chandramohan                                      rebox.shift().size()};
2167fa517555SKiran Chandramohan     if (rebox.shape().empty()) {
2168fa517555SKiran Chandramohan       // Only setting new lower bounds.
2169fa517555SKiran Chandramohan       return finalizeRebox(rebox, dest, base, reboxShifts, inputExtents,
2170fa517555SKiran Chandramohan                            inputStrides, rewriter);
2171fa517555SKiran Chandramohan     }
2172fa517555SKiran Chandramohan 
2173fa517555SKiran Chandramohan     mlir::Location loc = rebox.getLoc();
2174fa517555SKiran Chandramohan     // Strides from the fir.box are in bytes.
2175fa517555SKiran Chandramohan     mlir::Type voidPtrTy = ::getVoidPtrType(rebox.getContext());
2176fa517555SKiran Chandramohan     base = rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, base);
2177fa517555SKiran Chandramohan 
2178fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> newStrides;
2179fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> newExtents;
2180fa517555SKiran Chandramohan     mlir::Type idxTy = lowerTy().indexType();
2181fa517555SKiran Chandramohan     // First stride from input box is kept. The rest is assumed contiguous
2182fa517555SKiran Chandramohan     // (it is not possible to reshape otherwise). If the input is scalar,
2183fa517555SKiran Chandramohan     // which may be OK if all new extents are ones, the stride does not
2184fa517555SKiran Chandramohan     // matter, use one.
2185fa517555SKiran Chandramohan     mlir::Value stride = inputStrides.empty()
2186fa517555SKiran Chandramohan                              ? genConstantIndex(loc, idxTy, rewriter, 1)
2187fa517555SKiran Chandramohan                              : inputStrides[0];
2188fa517555SKiran Chandramohan     for (unsigned i = 0; i < rebox.shape().size(); ++i) {
2189fa517555SKiran Chandramohan       mlir::Value rawExtent = operands[rebox.shapeOffset() + i];
2190fa517555SKiran Chandramohan       mlir::Value extent = integerCast(loc, rewriter, idxTy, rawExtent);
2191fa517555SKiran Chandramohan       newExtents.emplace_back(extent);
2192fa517555SKiran Chandramohan       newStrides.emplace_back(stride);
2193fa517555SKiran Chandramohan       // nextStride = extent * stride;
2194fa517555SKiran Chandramohan       stride = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, extent, stride);
2195fa517555SKiran Chandramohan     }
2196fa517555SKiran Chandramohan     return finalizeRebox(rebox, dest, base, reboxShifts, newExtents, newStrides,
2197fa517555SKiran Chandramohan                          rewriter);
2198fa517555SKiran Chandramohan   }
2199fa517555SKiran Chandramohan 
2200fa517555SKiran Chandramohan   /// Return scalar element type of the input box.
2201fa517555SKiran Chandramohan   static mlir::Type getInputEleTy(fir::cg::XReboxOp rebox) {
2202fa517555SKiran Chandramohan     auto ty = fir::dyn_cast_ptrOrBoxEleTy(rebox.box().getType());
2203fa517555SKiran Chandramohan     if (auto seqTy = ty.dyn_cast<fir::SequenceType>())
2204fa517555SKiran Chandramohan       return seqTy.getEleTy();
2205fa517555SKiran Chandramohan     return ty;
2206fa517555SKiran Chandramohan   }
2207fa517555SKiran Chandramohan };
2208fa517555SKiran Chandramohan 
220954c56347SValentin Clement // Code shared between insert_value and extract_value Ops.
221054c56347SValentin Clement struct ValueOpCommon {
221154c56347SValentin Clement   // Translate the arguments pertaining to any multidimensional array to
221254c56347SValentin Clement   // row-major order for LLVM-IR.
221354c56347SValentin Clement   static void toRowMajor(SmallVectorImpl<mlir::Attribute> &attrs,
221454c56347SValentin Clement                          mlir::Type ty) {
221554c56347SValentin Clement     assert(ty && "type is null");
221654c56347SValentin Clement     const auto end = attrs.size();
221754c56347SValentin Clement     for (std::remove_const_t<decltype(end)> i = 0; i < end; ++i) {
221854c56347SValentin Clement       if (auto seq = ty.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
221954c56347SValentin Clement         const auto dim = getDimension(seq);
222054c56347SValentin Clement         if (dim > 1) {
222154c56347SValentin Clement           auto ub = std::min(i + dim, end);
222254c56347SValentin Clement           std::reverse(attrs.begin() + i, attrs.begin() + ub);
222354c56347SValentin Clement           i += dim - 1;
222454c56347SValentin Clement         }
222554c56347SValentin Clement         ty = getArrayElementType(seq);
222654c56347SValentin Clement       } else if (auto st = ty.dyn_cast<mlir::LLVM::LLVMStructType>()) {
222754c56347SValentin Clement         ty = st.getBody()[attrs[i].cast<mlir::IntegerAttr>().getInt()];
222854c56347SValentin Clement       } else {
222954c56347SValentin Clement         llvm_unreachable("index into invalid type");
223054c56347SValentin Clement       }
223154c56347SValentin Clement     }
223254c56347SValentin Clement   }
223354c56347SValentin Clement 
223454c56347SValentin Clement   static llvm::SmallVector<mlir::Attribute>
223554c56347SValentin Clement   collectIndices(mlir::ConversionPatternRewriter &rewriter,
223654c56347SValentin Clement                  mlir::ArrayAttr arrAttr) {
223754c56347SValentin Clement     llvm::SmallVector<mlir::Attribute> attrs;
223854c56347SValentin Clement     for (auto i = arrAttr.begin(), e = arrAttr.end(); i != e; ++i) {
223954c56347SValentin Clement       if (i->isa<mlir::IntegerAttr>()) {
224054c56347SValentin Clement         attrs.push_back(*i);
224154c56347SValentin Clement       } else {
224254c56347SValentin Clement         auto fieldName = i->cast<mlir::StringAttr>().getValue();
224354c56347SValentin Clement         ++i;
224454c56347SValentin Clement         auto ty = i->cast<mlir::TypeAttr>().getValue();
224554c56347SValentin Clement         auto index = ty.cast<fir::RecordType>().getFieldIndex(fieldName);
224654c56347SValentin Clement         attrs.push_back(mlir::IntegerAttr::get(rewriter.getI32Type(), index));
224754c56347SValentin Clement       }
224854c56347SValentin Clement     }
224954c56347SValentin Clement     return attrs;
225054c56347SValentin Clement   }
225154c56347SValentin Clement 
225254c56347SValentin Clement private:
225354c56347SValentin Clement   static unsigned getDimension(mlir::LLVM::LLVMArrayType ty) {
225454c56347SValentin Clement     unsigned result = 1;
225554c56347SValentin Clement     for (auto eleTy = ty.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>();
225654c56347SValentin Clement          eleTy;
225754c56347SValentin Clement          eleTy = eleTy.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>())
225854c56347SValentin Clement       ++result;
225954c56347SValentin Clement     return result;
226054c56347SValentin Clement   }
226154c56347SValentin Clement 
226254c56347SValentin Clement   static mlir::Type getArrayElementType(mlir::LLVM::LLVMArrayType ty) {
226354c56347SValentin Clement     auto eleTy = ty.getElementType();
226454c56347SValentin Clement     while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>())
226554c56347SValentin Clement       eleTy = arrTy.getElementType();
226654c56347SValentin Clement     return eleTy;
226754c56347SValentin Clement   }
226854c56347SValentin Clement };
226954c56347SValentin Clement 
2270c2acd453SAlexisPerry namespace {
227154c56347SValentin Clement /// Extract a subobject value from an ssa-value of aggregate type
227254c56347SValentin Clement struct ExtractValueOpConversion
227354c56347SValentin Clement     : public FIROpAndTypeConversion<fir::ExtractValueOp>,
227454c56347SValentin Clement       public ValueOpCommon {
227554c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
227654c56347SValentin Clement 
227754c56347SValentin Clement   mlir::LogicalResult
227854c56347SValentin Clement   doRewrite(fir::ExtractValueOp extractVal, mlir::Type ty, OpAdaptor adaptor,
227954c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
228054c56347SValentin Clement     auto attrs = collectIndices(rewriter, extractVal.coor());
228154c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
228254c56347SValentin Clement     auto position = mlir::ArrayAttr::get(extractVal.getContext(), attrs);
228354c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(
228454c56347SValentin Clement         extractVal, ty, adaptor.getOperands()[0], position);
228554c56347SValentin Clement     return success();
228654c56347SValentin Clement   }
228754c56347SValentin Clement };
228854c56347SValentin Clement 
228954c56347SValentin Clement /// InsertValue is the generalized instruction for the composition of new
229054c56347SValentin Clement /// aggregate type values.
229154c56347SValentin Clement struct InsertValueOpConversion
229254c56347SValentin Clement     : public FIROpAndTypeConversion<fir::InsertValueOp>,
229354c56347SValentin Clement       public ValueOpCommon {
229454c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
229554c56347SValentin Clement 
229654c56347SValentin Clement   mlir::LogicalResult
229754c56347SValentin Clement   doRewrite(fir::InsertValueOp insertVal, mlir::Type ty, OpAdaptor adaptor,
229854c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
229954c56347SValentin Clement     auto attrs = collectIndices(rewriter, insertVal.coor());
230054c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
230154c56347SValentin Clement     auto position = mlir::ArrayAttr::get(insertVal.getContext(), attrs);
230254c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
230354c56347SValentin Clement         insertVal, ty, adaptor.getOperands()[0], adaptor.getOperands()[1],
230454c56347SValentin Clement         position);
230554c56347SValentin Clement     return success();
230654c56347SValentin Clement   }
230754c56347SValentin Clement };
230854c56347SValentin Clement 
23093ae8e442SValentin Clement /// InsertOnRange inserts a value into a sequence over a range of offsets.
23103ae8e442SValentin Clement struct InsertOnRangeOpConversion
23113ae8e442SValentin Clement     : public FIROpAndTypeConversion<fir::InsertOnRangeOp> {
23123ae8e442SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
23133ae8e442SValentin Clement 
23143ae8e442SValentin Clement   // Increments an array of subscripts in a row major fasion.
23153ae8e442SValentin Clement   void incrementSubscripts(const SmallVector<uint64_t> &dims,
23163ae8e442SValentin Clement                            SmallVector<uint64_t> &subscripts) const {
23173ae8e442SValentin Clement     for (size_t i = dims.size(); i > 0; --i) {
23183ae8e442SValentin Clement       if (++subscripts[i - 1] < dims[i - 1]) {
23193ae8e442SValentin Clement         return;
23203ae8e442SValentin Clement       }
23213ae8e442SValentin Clement       subscripts[i - 1] = 0;
23223ae8e442SValentin Clement     }
23233ae8e442SValentin Clement   }
23243ae8e442SValentin Clement 
23253ae8e442SValentin Clement   mlir::LogicalResult
23263ae8e442SValentin Clement   doRewrite(fir::InsertOnRangeOp range, mlir::Type ty, OpAdaptor adaptor,
23273ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
23283ae8e442SValentin Clement 
23293ae8e442SValentin Clement     llvm::SmallVector<uint64_t> dims;
23303ae8e442SValentin Clement     auto type = adaptor.getOperands()[0].getType();
23313ae8e442SValentin Clement 
23323ae8e442SValentin Clement     // Iteratively extract the array dimensions from the type.
23333ae8e442SValentin Clement     while (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
23343ae8e442SValentin Clement       dims.push_back(t.getNumElements());
23353ae8e442SValentin Clement       type = t.getElementType();
23363ae8e442SValentin Clement     }
23373ae8e442SValentin Clement 
23383ae8e442SValentin Clement     SmallVector<uint64_t> lBounds;
23393ae8e442SValentin Clement     SmallVector<uint64_t> uBounds;
23403ae8e442SValentin Clement 
23413ae8e442SValentin Clement     // Unzip the upper and lower bound and convert to a row major format.
23428ec0f221SMehdi Amini     mlir::DenseIntElementsAttr coor = range.coor();
23438ec0f221SMehdi Amini     auto reversedCoor = llvm::reverse(coor.getValues<int64_t>());
23448ec0f221SMehdi Amini     for (auto i = reversedCoor.begin(), e = reversedCoor.end(); i != e; ++i) {
23453ae8e442SValentin Clement       uBounds.push_back(*i++);
23463ae8e442SValentin Clement       lBounds.push_back(*i);
23473ae8e442SValentin Clement     }
23483ae8e442SValentin Clement 
23493ae8e442SValentin Clement     auto &subscripts = lBounds;
23503ae8e442SValentin Clement     auto loc = range.getLoc();
23513ae8e442SValentin Clement     mlir::Value lastOp = adaptor.getOperands()[0];
23523ae8e442SValentin Clement     mlir::Value insertVal = adaptor.getOperands()[1];
23533ae8e442SValentin Clement 
23543ae8e442SValentin Clement     auto i64Ty = rewriter.getI64Type();
23553ae8e442SValentin Clement     while (subscripts != uBounds) {
23563ae8e442SValentin Clement       // Convert uint64_t's to Attribute's.
23573ae8e442SValentin Clement       SmallVector<mlir::Attribute> subscriptAttrs;
23583ae8e442SValentin Clement       for (const auto &subscript : subscripts)
23593ae8e442SValentin Clement         subscriptAttrs.push_back(IntegerAttr::get(i64Ty, subscript));
23603ae8e442SValentin Clement       lastOp = rewriter.create<mlir::LLVM::InsertValueOp>(
23613ae8e442SValentin Clement           loc, ty, lastOp, insertVal,
23623ae8e442SValentin Clement           ArrayAttr::get(range.getContext(), subscriptAttrs));
23633ae8e442SValentin Clement 
23643ae8e442SValentin Clement       incrementSubscripts(dims, subscripts);
23653ae8e442SValentin Clement     }
23663ae8e442SValentin Clement 
23673ae8e442SValentin Clement     // Convert uint64_t's to Attribute's.
23683ae8e442SValentin Clement     SmallVector<mlir::Attribute> subscriptAttrs;
23693ae8e442SValentin Clement     for (const auto &subscript : subscripts)
23703ae8e442SValentin Clement       subscriptAttrs.push_back(
23713ae8e442SValentin Clement           IntegerAttr::get(rewriter.getI64Type(), subscript));
23723ae8e442SValentin Clement     mlir::ArrayRef<mlir::Attribute> arrayRef(subscriptAttrs);
23733ae8e442SValentin Clement 
23743ae8e442SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
23753ae8e442SValentin Clement         range, ty, lastOp, insertVal,
23763ae8e442SValentin Clement         ArrayAttr::get(range.getContext(), arrayRef));
23773ae8e442SValentin Clement 
23783ae8e442SValentin Clement     return success();
23793ae8e442SValentin Clement   }
23803ae8e442SValentin Clement };
2381c2acd453SAlexisPerry } // namespace
23827b5132daSValentin Clement 
23835d27abe6SValentin Clement /// XArrayCoor is the address arithmetic on a dynamically shaped, sliced,
23845d27abe6SValentin Clement /// shifted etc. array.
23855d27abe6SValentin Clement /// (See the static restriction on coordinate_of.) array_coor determines the
23865d27abe6SValentin Clement /// coordinate (location) of a specific element.
23875d27abe6SValentin Clement struct XArrayCoorOpConversion
23885d27abe6SValentin Clement     : public FIROpAndTypeConversion<fir::cg::XArrayCoorOp> {
23895d27abe6SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
23905d27abe6SValentin Clement 
23915d27abe6SValentin Clement   mlir::LogicalResult
23925d27abe6SValentin Clement   doRewrite(fir::cg::XArrayCoorOp coor, mlir::Type ty, OpAdaptor adaptor,
23935d27abe6SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
23945d27abe6SValentin Clement     auto loc = coor.getLoc();
23955d27abe6SValentin Clement     mlir::ValueRange operands = adaptor.getOperands();
23965d27abe6SValentin Clement     unsigned rank = coor.getRank();
23975d27abe6SValentin Clement     assert(coor.indices().size() == rank);
23985d27abe6SValentin Clement     assert(coor.shape().empty() || coor.shape().size() == rank);
23995d27abe6SValentin Clement     assert(coor.shift().empty() || coor.shift().size() == rank);
24005d27abe6SValentin Clement     assert(coor.slice().empty() || coor.slice().size() == 3 * rank);
24015d27abe6SValentin Clement     mlir::Type idxTy = lowerTy().indexType();
24025d27abe6SValentin Clement     mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1);
24035d27abe6SValentin Clement     mlir::Value prevExt = one;
24045d27abe6SValentin Clement     mlir::Value zero = genConstantIndex(loc, idxTy, rewriter, 0);
24055d27abe6SValentin Clement     mlir::Value offset = zero;
24065d27abe6SValentin Clement     const bool isShifted = !coor.shift().empty();
24075d27abe6SValentin Clement     const bool isSliced = !coor.slice().empty();
24085d27abe6SValentin Clement     const bool baseIsBoxed = coor.memref().getType().isa<fir::BoxType>();
24095d27abe6SValentin Clement 
24105d27abe6SValentin Clement     auto indexOps = coor.indices().begin();
24115d27abe6SValentin Clement     auto shapeOps = coor.shape().begin();
24125d27abe6SValentin Clement     auto shiftOps = coor.shift().begin();
24135d27abe6SValentin Clement     auto sliceOps = coor.slice().begin();
24145d27abe6SValentin Clement     // For each dimension of the array, generate the offset calculation.
24155d27abe6SValentin Clement     for (unsigned i = 0; i < rank;
24165d27abe6SValentin Clement          ++i, ++indexOps, ++shapeOps, ++shiftOps, sliceOps += 3) {
24175d27abe6SValentin Clement       mlir::Value index =
24185d27abe6SValentin Clement           integerCast(loc, rewriter, idxTy, operands[coor.indicesOffset() + i]);
24195d27abe6SValentin Clement       mlir::Value lb = isShifted ? integerCast(loc, rewriter, idxTy,
24205d27abe6SValentin Clement                                                operands[coor.shiftOffset() + i])
24215d27abe6SValentin Clement                                  : one;
24225d27abe6SValentin Clement       mlir::Value step = one;
24235d27abe6SValentin Clement       bool normalSlice = isSliced;
24245d27abe6SValentin Clement       // Compute zero based index in dimension i of the element, applying
24255d27abe6SValentin Clement       // potential triplets and lower bounds.
24265d27abe6SValentin Clement       if (isSliced) {
24275d27abe6SValentin Clement         mlir::Value ub = *(sliceOps + 1);
24285d27abe6SValentin Clement         normalSlice = !mlir::isa_and_nonnull<fir::UndefOp>(ub.getDefiningOp());
24295d27abe6SValentin Clement         if (normalSlice)
24305d27abe6SValentin Clement           step = integerCast(loc, rewriter, idxTy, *(sliceOps + 2));
24315d27abe6SValentin Clement       }
24325d27abe6SValentin Clement       auto idx = rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, index, lb);
24335d27abe6SValentin Clement       mlir::Value diff =
24345d27abe6SValentin Clement           rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, idx, step);
24355d27abe6SValentin Clement       if (normalSlice) {
24365d27abe6SValentin Clement         mlir::Value sliceLb =
24375d27abe6SValentin Clement             integerCast(loc, rewriter, idxTy, operands[coor.sliceOffset() + i]);
24385d27abe6SValentin Clement         auto adj = rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, sliceLb, lb);
24395d27abe6SValentin Clement         diff = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, diff, adj);
24405d27abe6SValentin Clement       }
24415d27abe6SValentin Clement       // Update the offset given the stride and the zero based index `diff`
24425d27abe6SValentin Clement       // that was just computed.
24435d27abe6SValentin Clement       if (baseIsBoxed) {
24445d27abe6SValentin Clement         // Use stride in bytes from the descriptor.
24455d27abe6SValentin Clement         mlir::Value stride =
24465d27abe6SValentin Clement             loadStrideFromBox(loc, adaptor.getOperands()[0], i, rewriter);
24475d27abe6SValentin Clement         auto sc = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, stride);
24485d27abe6SValentin Clement         offset = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, offset);
24495d27abe6SValentin Clement       } else {
24505d27abe6SValentin Clement         // Use stride computed at last iteration.
24515d27abe6SValentin Clement         auto sc = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, prevExt);
24525d27abe6SValentin Clement         offset = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, offset);
24535d27abe6SValentin Clement         // Compute next stride assuming contiguity of the base array
24545d27abe6SValentin Clement         // (in element number).
24555d27abe6SValentin Clement         auto nextExt =
24565d27abe6SValentin Clement             integerCast(loc, rewriter, idxTy, operands[coor.shapeOffset() + i]);
24575d27abe6SValentin Clement         prevExt =
24585d27abe6SValentin Clement             rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, prevExt, nextExt);
24595d27abe6SValentin Clement       }
24605d27abe6SValentin Clement     }
24615d27abe6SValentin Clement 
24625d27abe6SValentin Clement     // Add computed offset to the base address.
24635d27abe6SValentin Clement     if (baseIsBoxed) {
24645d27abe6SValentin Clement       // Working with byte offsets. The base address is read from the fir.box.
24655d27abe6SValentin Clement       // and need to be casted to i8* to do the pointer arithmetic.
24665d27abe6SValentin Clement       mlir::Type baseTy =
24675d27abe6SValentin Clement           getBaseAddrTypeFromBox(adaptor.getOperands()[0].getType());
24685d27abe6SValentin Clement       mlir::Value base =
24695d27abe6SValentin Clement           loadBaseAddrFromBox(loc, baseTy, adaptor.getOperands()[0], rewriter);
24705d27abe6SValentin Clement       mlir::Type voidPtrTy = getVoidPtrType();
24715d27abe6SValentin Clement       base = rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, base);
247230122656SAlex Zinenko       llvm::SmallVector<mlir::Value> args{offset};
247330122656SAlex Zinenko       auto addr =
247430122656SAlex Zinenko           rewriter.create<mlir::LLVM::GEPOp>(loc, voidPtrTy, base, args);
24755d27abe6SValentin Clement       if (coor.subcomponent().empty()) {
24765d27abe6SValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(coor, baseTy, addr);
24775d27abe6SValentin Clement         return success();
24785d27abe6SValentin Clement       }
24795d27abe6SValentin Clement       auto casted = rewriter.create<mlir::LLVM::BitcastOp>(loc, baseTy, addr);
24805d27abe6SValentin Clement       args.clear();
24815d27abe6SValentin Clement       args.push_back(zero);
24825d27abe6SValentin Clement       if (!coor.lenParams().empty()) {
24835d27abe6SValentin Clement         // If type parameters are present, then we don't want to use a GEPOp
24845d27abe6SValentin Clement         // as below, as the LLVM struct type cannot be statically defined.
24855d27abe6SValentin Clement         TODO(loc, "derived type with type parameters");
24865d27abe6SValentin Clement       }
24875d27abe6SValentin Clement       // TODO: array offset subcomponents must be converted to LLVM's
24885d27abe6SValentin Clement       // row-major layout here.
24895d27abe6SValentin Clement       for (auto i = coor.subcomponentOffset(); i != coor.indicesOffset(); ++i)
24905d27abe6SValentin Clement         args.push_back(operands[i]);
249130122656SAlex Zinenko       rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(coor, baseTy, casted,
249230122656SAlex Zinenko                                                      args);
24935d27abe6SValentin Clement       return success();
24945d27abe6SValentin Clement     }
24955d27abe6SValentin Clement 
24965d27abe6SValentin Clement     // The array was not boxed, so it must be contiguous. offset is therefore an
24975d27abe6SValentin Clement     // element offset and the base type is kept in the GEP unless the element
24985d27abe6SValentin Clement     // type size is itself dynamic.
24995d27abe6SValentin Clement     mlir::Value base;
25005d27abe6SValentin Clement     if (coor.subcomponent().empty()) {
25015d27abe6SValentin Clement       // No subcomponent.
25025d27abe6SValentin Clement       if (!coor.lenParams().empty()) {
25035d27abe6SValentin Clement         // Type parameters. Adjust element size explicitly.
25045d27abe6SValentin Clement         auto eleTy = fir::dyn_cast_ptrEleTy(coor.getType());
25055d27abe6SValentin Clement         assert(eleTy && "result must be a reference-like type");
25065d27abe6SValentin Clement         if (fir::characterWithDynamicLen(eleTy)) {
25075d27abe6SValentin Clement           assert(coor.lenParams().size() == 1);
25085d27abe6SValentin Clement           auto bitsInChar = lowerTy().getKindMap().getCharacterBitsize(
25095d27abe6SValentin Clement               eleTy.cast<fir::CharacterType>().getFKind());
25105d27abe6SValentin Clement           auto scaling = genConstantIndex(loc, idxTy, rewriter, bitsInChar / 8);
25115d27abe6SValentin Clement           auto scaledBySize =
25125d27abe6SValentin Clement               rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, offset, scaling);
25135d27abe6SValentin Clement           auto length =
25145d27abe6SValentin Clement               integerCast(loc, rewriter, idxTy,
25155d27abe6SValentin Clement                           adaptor.getOperands()[coor.lenParamsOffset()]);
25165d27abe6SValentin Clement           offset = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, scaledBySize,
25175d27abe6SValentin Clement                                                       length);
25185d27abe6SValentin Clement         } else {
25195d27abe6SValentin Clement           TODO(loc, "compute size of derived type with type parameters");
25205d27abe6SValentin Clement         }
25215d27abe6SValentin Clement       }
25225d27abe6SValentin Clement       // Cast the base address to a pointer to T.
25235d27abe6SValentin Clement       base = rewriter.create<mlir::LLVM::BitcastOp>(loc, ty,
25245d27abe6SValentin Clement                                                     adaptor.getOperands()[0]);
25255d27abe6SValentin Clement     } else {
25265d27abe6SValentin Clement       // Operand #0 must have a pointer type. For subcomponent slicing, we
25275d27abe6SValentin Clement       // want to cast away the array type and have a plain struct type.
25285d27abe6SValentin Clement       mlir::Type ty0 = adaptor.getOperands()[0].getType();
25295d27abe6SValentin Clement       auto ptrTy = ty0.dyn_cast<mlir::LLVM::LLVMPointerType>();
25305d27abe6SValentin Clement       assert(ptrTy && "expected pointer type");
25315d27abe6SValentin Clement       mlir::Type eleTy = ptrTy.getElementType();
25325d27abe6SValentin Clement       while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>())
25335d27abe6SValentin Clement         eleTy = arrTy.getElementType();
25345d27abe6SValentin Clement       auto newTy = mlir::LLVM::LLVMPointerType::get(eleTy);
25355d27abe6SValentin Clement       base = rewriter.create<mlir::LLVM::BitcastOp>(loc, newTy,
25365d27abe6SValentin Clement                                                     adaptor.getOperands()[0]);
25375d27abe6SValentin Clement     }
253830122656SAlex Zinenko     SmallVector<mlir::Value> args = {offset};
25395d27abe6SValentin Clement     for (auto i = coor.subcomponentOffset(); i != coor.indicesOffset(); ++i)
25405d27abe6SValentin Clement       args.push_back(operands[i]);
254130122656SAlex Zinenko     rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(coor, ty, base, args);
25425d27abe6SValentin Clement     return success();
25435d27abe6SValentin Clement   }
25445d27abe6SValentin Clement };
25455d27abe6SValentin Clement 
25467b5132daSValentin Clement //
25477b5132daSValentin Clement // Primitive operations on Complex types
25487b5132daSValentin Clement //
25497b5132daSValentin Clement 
25507b5132daSValentin Clement /// Generate inline code for complex addition/subtraction
25517b5132daSValentin Clement template <typename LLVMOP, typename OPTY>
2552c2acd453SAlexisPerry static mlir::LLVM::InsertValueOp
2553c2acd453SAlexisPerry complexSum(OPTY sumop, mlir::ValueRange opnds,
25547b5132daSValentin Clement            mlir::ConversionPatternRewriter &rewriter,
25557b5132daSValentin Clement            fir::LLVMTypeConverter &lowering) {
25567b5132daSValentin Clement   mlir::Value a = opnds[0];
25577b5132daSValentin Clement   mlir::Value b = opnds[1];
25587b5132daSValentin Clement   auto loc = sumop.getLoc();
25597b5132daSValentin Clement   auto ctx = sumop.getContext();
25607b5132daSValentin Clement   auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
25617b5132daSValentin Clement   auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
25627b5132daSValentin Clement   mlir::Type eleTy = lowering.convertType(getComplexEleTy(sumop.getType()));
25637b5132daSValentin Clement   mlir::Type ty = lowering.convertType(sumop.getType());
25647b5132daSValentin Clement   auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
25657b5132daSValentin Clement   auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
25667b5132daSValentin Clement   auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
25677b5132daSValentin Clement   auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
25687b5132daSValentin Clement   auto rx = rewriter.create<LLVMOP>(loc, eleTy, x0, x1);
25697b5132daSValentin Clement   auto ry = rewriter.create<LLVMOP>(loc, eleTy, y0, y1);
25707b5132daSValentin Clement   auto r0 = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
25717b5132daSValentin Clement   auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r0, rx, c0);
25727b5132daSValentin Clement   return rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ry, c1);
25737b5132daSValentin Clement }
25747b5132daSValentin Clement 
2575c2acd453SAlexisPerry namespace {
25767b5132daSValentin Clement struct AddcOpConversion : public FIROpConversion<fir::AddcOp> {
25777b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
25787b5132daSValentin Clement 
25797b5132daSValentin Clement   mlir::LogicalResult
25807b5132daSValentin Clement   matchAndRewrite(fir::AddcOp addc, OpAdaptor adaptor,
25817b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
25827b5132daSValentin Clement     // given: (x + iy) + (x' + iy')
25837b5132daSValentin Clement     // result: (x + x') + i(y + y')
25847b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FAddOp>(addc, adaptor.getOperands(),
25857b5132daSValentin Clement                                             rewriter, lowerTy());
25867b5132daSValentin Clement     rewriter.replaceOp(addc, r.getResult());
25877b5132daSValentin Clement     return success();
25887b5132daSValentin Clement   }
25897b5132daSValentin Clement };
25907b5132daSValentin Clement 
25917b5132daSValentin Clement struct SubcOpConversion : public FIROpConversion<fir::SubcOp> {
25927b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
25937b5132daSValentin Clement 
25947b5132daSValentin Clement   mlir::LogicalResult
25957b5132daSValentin Clement   matchAndRewrite(fir::SubcOp subc, OpAdaptor adaptor,
25967b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
25977b5132daSValentin Clement     // given: (x + iy) - (x' + iy')
25987b5132daSValentin Clement     // result: (x - x') + i(y - y')
25997b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FSubOp>(subc, adaptor.getOperands(),
26007b5132daSValentin Clement                                             rewriter, lowerTy());
26017b5132daSValentin Clement     rewriter.replaceOp(subc, r.getResult());
26027b5132daSValentin Clement     return success();
26037b5132daSValentin Clement   }
26047b5132daSValentin Clement };
26057b5132daSValentin Clement 
26067b5132daSValentin Clement /// Inlined complex multiply
26077b5132daSValentin Clement struct MulcOpConversion : public FIROpConversion<fir::MulcOp> {
26087b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
26097b5132daSValentin Clement 
26107b5132daSValentin Clement   mlir::LogicalResult
26117b5132daSValentin Clement   matchAndRewrite(fir::MulcOp mulc, OpAdaptor adaptor,
26127b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
26137b5132daSValentin Clement     // TODO: Can we use a call to __muldc3 ?
26147b5132daSValentin Clement     // given: (x + iy) * (x' + iy')
26157b5132daSValentin Clement     // result: (xx'-yy')+i(xy'+yx')
26167b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
26177b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
26187b5132daSValentin Clement     auto loc = mulc.getLoc();
26197b5132daSValentin Clement     auto *ctx = mulc.getContext();
26207b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
26217b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
26227b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(mulc.getType()));
26237b5132daSValentin Clement     mlir::Type ty = convertType(mulc.getType());
26247b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
26257b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
26267b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
26277b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
26287b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
26297b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
26307b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
26317b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xy, yx);
26327b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
26337b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, xx, yy);
26347b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
26357b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
26367b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
26377b5132daSValentin Clement     rewriter.replaceOp(mulc, r0.getResult());
26387b5132daSValentin Clement     return success();
26397b5132daSValentin Clement   }
26407b5132daSValentin Clement };
26417b5132daSValentin Clement 
26427b5132daSValentin Clement /// Inlined complex division
26437b5132daSValentin Clement struct DivcOpConversion : public FIROpConversion<fir::DivcOp> {
26447b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
26457b5132daSValentin Clement 
26467b5132daSValentin Clement   mlir::LogicalResult
26477b5132daSValentin Clement   matchAndRewrite(fir::DivcOp divc, OpAdaptor adaptor,
26487b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
26497b5132daSValentin Clement     // TODO: Can we use a call to __divdc3 instead?
26507b5132daSValentin Clement     // Just generate inline code for now.
26517b5132daSValentin Clement     // given: (x + iy) / (x' + iy')
26527b5132daSValentin Clement     // result: ((xx'+yy')/d) + i((yx'-xy')/d) where d = x'x' + y'y'
26537b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
26547b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
26557b5132daSValentin Clement     auto loc = divc.getLoc();
26567b5132daSValentin Clement     auto *ctx = divc.getContext();
26577b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
26587b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
26597b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(divc.getType()));
26607b5132daSValentin Clement     mlir::Type ty = convertType(divc.getType());
26617b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
26627b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
26637b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
26647b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
26657b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
26667b5132daSValentin Clement     auto x1x1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x1, x1);
26677b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
26687b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
26697b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
26707b5132daSValentin Clement     auto y1y1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y1, y1);
26717b5132daSValentin Clement     auto d = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, x1x1, y1y1);
26727b5132daSValentin Clement     auto rrn = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xx, yy);
26737b5132daSValentin Clement     auto rin = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, yx, xy);
26747b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rrn, d);
26757b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rin, d);
26767b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
26777b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
26787b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
26797b5132daSValentin Clement     rewriter.replaceOp(divc, r0.getResult());
26807b5132daSValentin Clement     return success();
26817b5132daSValentin Clement   }
26827b5132daSValentin Clement };
26837b5132daSValentin Clement 
26847b5132daSValentin Clement /// Inlined complex negation
26857b5132daSValentin Clement struct NegcOpConversion : public FIROpConversion<fir::NegcOp> {
26867b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
26877b5132daSValentin Clement 
26887b5132daSValentin Clement   mlir::LogicalResult
26897b5132daSValentin Clement   matchAndRewrite(fir::NegcOp neg, OpAdaptor adaptor,
26907b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
26917b5132daSValentin Clement     // given: -(x + iy)
26927b5132daSValentin Clement     // result: -x - iy
26937b5132daSValentin Clement     auto *ctxt = neg.getContext();
26947b5132daSValentin Clement     auto eleTy = convertType(getComplexEleTy(neg.getType()));
26957b5132daSValentin Clement     auto ty = convertType(neg.getType());
26967b5132daSValentin Clement     auto loc = neg.getLoc();
26977b5132daSValentin Clement     mlir::Value o0 = adaptor.getOperands()[0];
26987b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0));
26997b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1));
27007b5132daSValentin Clement     auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c0);
27017b5132daSValentin Clement     auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c1);
27027b5132daSValentin Clement     auto nrp = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, rp);
27037b5132daSValentin Clement     auto nip = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, ip);
27047b5132daSValentin Clement     auto r = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, o0, nrp, c0);
27057b5132daSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(neg, ty, r, nip, c1);
27067b5132daSValentin Clement     return success();
27077b5132daSValentin Clement   }
27087b5132daSValentin Clement };
27097b5132daSValentin Clement 
27101ed5a90fSValentin Clement /// Conversion pattern for operation that must be dead. The information in these
27111ed5a90fSValentin Clement /// operations is used by other operation. At this point they should not have
27121ed5a90fSValentin Clement /// anymore uses.
27131ed5a90fSValentin Clement /// These operations are normally dead after the pre-codegen pass.
27141ed5a90fSValentin Clement template <typename FromOp>
27151ed5a90fSValentin Clement struct MustBeDeadConversion : public FIROpConversion<FromOp> {
27161ed5a90fSValentin Clement   explicit MustBeDeadConversion(fir::LLVMTypeConverter &lowering)
27171ed5a90fSValentin Clement       : FIROpConversion<FromOp>(lowering) {}
27181ed5a90fSValentin Clement   using OpAdaptor = typename FromOp::Adaptor;
27191ed5a90fSValentin Clement 
27201ed5a90fSValentin Clement   mlir::LogicalResult
27211ed5a90fSValentin Clement   matchAndRewrite(FromOp op, OpAdaptor adaptor,
27221ed5a90fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const final {
27231ed5a90fSValentin Clement     if (!op->getUses().empty())
27241ed5a90fSValentin Clement       return rewriter.notifyMatchFailure(op, "op must be dead");
27251ed5a90fSValentin Clement     rewriter.eraseOp(op);
27261ed5a90fSValentin Clement     return success();
27271ed5a90fSValentin Clement   }
27281ed5a90fSValentin Clement };
27291ed5a90fSValentin Clement 
27301ed5a90fSValentin Clement struct ShapeOpConversion : public MustBeDeadConversion<fir::ShapeOp> {
27311ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
27321ed5a90fSValentin Clement };
27331ed5a90fSValentin Clement 
27341ed5a90fSValentin Clement struct ShapeShiftOpConversion : public MustBeDeadConversion<fir::ShapeShiftOp> {
27351ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
27361ed5a90fSValentin Clement };
27371ed5a90fSValentin Clement 
27381ed5a90fSValentin Clement struct ShiftOpConversion : public MustBeDeadConversion<fir::ShiftOp> {
27391ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
27401ed5a90fSValentin Clement };
27411ed5a90fSValentin Clement 
27421ed5a90fSValentin Clement struct SliceOpConversion : public MustBeDeadConversion<fir::SliceOp> {
27431ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
27441ed5a90fSValentin Clement };
27451ed5a90fSValentin Clement 
2746420ad7ceSAndrzej Warzynski /// `fir.is_present` -->
2747420ad7ceSAndrzej Warzynski /// ```
2748420ad7ceSAndrzej Warzynski ///  %0 = llvm.mlir.constant(0 : i64)
2749420ad7ceSAndrzej Warzynski ///  %1 = llvm.ptrtoint %0
2750420ad7ceSAndrzej Warzynski ///  %2 = llvm.icmp "ne" %1, %0 : i64
2751420ad7ceSAndrzej Warzynski /// ```
2752420ad7ceSAndrzej Warzynski struct IsPresentOpConversion : public FIROpConversion<fir::IsPresentOp> {
2753420ad7ceSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
2754420ad7ceSAndrzej Warzynski 
2755420ad7ceSAndrzej Warzynski   mlir::LogicalResult
2756420ad7ceSAndrzej Warzynski   matchAndRewrite(fir::IsPresentOp isPresent, OpAdaptor adaptor,
2757420ad7ceSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
2758420ad7ceSAndrzej Warzynski     mlir::Type idxTy = lowerTy().indexType();
2759420ad7ceSAndrzej Warzynski     mlir::Location loc = isPresent.getLoc();
2760420ad7ceSAndrzej Warzynski     auto ptr = adaptor.getOperands()[0];
2761420ad7ceSAndrzej Warzynski 
2762420ad7ceSAndrzej Warzynski     if (isPresent.val().getType().isa<fir::BoxCharType>()) {
2763420ad7ceSAndrzej Warzynski       auto structTy = ptr.getType().cast<mlir::LLVM::LLVMStructType>();
2764420ad7ceSAndrzej Warzynski       assert(!structTy.isOpaque() && !structTy.getBody().empty());
2765420ad7ceSAndrzej Warzynski 
2766420ad7ceSAndrzej Warzynski       mlir::Type ty = structTy.getBody()[0];
2767420ad7ceSAndrzej Warzynski       mlir::MLIRContext *ctx = isPresent.getContext();
2768420ad7ceSAndrzej Warzynski       auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
2769420ad7ceSAndrzej Warzynski       ptr = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, ptr, c0);
2770420ad7ceSAndrzej Warzynski     }
2771420ad7ceSAndrzej Warzynski     mlir::LLVM::ConstantOp c0 =
2772420ad7ceSAndrzej Warzynski         genConstantIndex(isPresent.getLoc(), idxTy, rewriter, 0);
2773420ad7ceSAndrzej Warzynski     auto addr = rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, ptr);
2774420ad7ceSAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
2775420ad7ceSAndrzej Warzynski         isPresent, mlir::LLVM::ICmpPredicate::ne, addr, c0);
2776420ad7ceSAndrzej Warzynski 
2777420ad7ceSAndrzej Warzynski     return success();
2778420ad7ceSAndrzej Warzynski   }
2779420ad7ceSAndrzej Warzynski };
27801e77b095SAndrzej Warzynski 
27811e77b095SAndrzej Warzynski /// Convert `!fir.emboxchar<!fir.char<KIND, ?>, #n>` into a sequence of
27821e77b095SAndrzej Warzynski /// instructions that generate `!llvm.struct<(ptr<ik>, i64)>`. The 1st element
27831e77b095SAndrzej Warzynski /// in this struct is a pointer. Its type is determined from `KIND`. The 2nd
27841e77b095SAndrzej Warzynski /// element is the length of the character buffer (`#n`).
27851e77b095SAndrzej Warzynski struct EmboxCharOpConversion : public FIROpConversion<fir::EmboxCharOp> {
27861e77b095SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
27871e77b095SAndrzej Warzynski 
27881e77b095SAndrzej Warzynski   mlir::LogicalResult
27891e77b095SAndrzej Warzynski   matchAndRewrite(fir::EmboxCharOp emboxChar, OpAdaptor adaptor,
27901e77b095SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
27911e77b095SAndrzej Warzynski     mlir::ValueRange operands = adaptor.getOperands();
27921e77b095SAndrzej Warzynski     MLIRContext *ctx = emboxChar.getContext();
27931e77b095SAndrzej Warzynski 
27941e77b095SAndrzej Warzynski     mlir::Value charBuffer = operands[0];
27951e77b095SAndrzej Warzynski     mlir::Value charBufferLen = operands[1];
27961e77b095SAndrzej Warzynski 
27971e77b095SAndrzej Warzynski     mlir::Location loc = emboxChar.getLoc();
27981e77b095SAndrzej Warzynski     mlir::Type llvmStructTy = convertType(emboxChar.getType());
27991e77b095SAndrzej Warzynski     auto llvmStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, llvmStructTy);
28001e77b095SAndrzej Warzynski 
28011e77b095SAndrzej Warzynski     mlir::Type lenTy =
28021e77b095SAndrzej Warzynski         llvmStructTy.cast<mlir::LLVM::LLVMStructType>().getBody()[1];
28031e77b095SAndrzej Warzynski     mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, charBufferLen);
28041e77b095SAndrzej Warzynski 
28051e77b095SAndrzej Warzynski     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
28061e77b095SAndrzej Warzynski     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
28071e77b095SAndrzej Warzynski     auto insertBufferOp = rewriter.create<mlir::LLVM::InsertValueOp>(
28081e77b095SAndrzej Warzynski         loc, llvmStructTy, llvmStruct, charBuffer, c0);
28091e77b095SAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
28101e77b095SAndrzej Warzynski         emboxChar, llvmStructTy, insertBufferOp, lenAfterCast, c1);
28111e77b095SAndrzej Warzynski 
28121e77b095SAndrzej Warzynski     return success();
28131e77b095SAndrzej Warzynski   }
28141e77b095SAndrzej Warzynski };
2815c2acd453SAlexisPerry } // namespace
281614867ffcSAndrzej Warzynski 
281714867ffcSAndrzej Warzynski /// Construct an `llvm.extractvalue` instruction. It will return value at
281814867ffcSAndrzej Warzynski /// element \p x from  \p tuple.
2819c2acd453SAlexisPerry static mlir::LLVM::ExtractValueOp
282014867ffcSAndrzej Warzynski genExtractValueWithIndex(mlir::Location loc, mlir::Value tuple, mlir::Type ty,
282114867ffcSAndrzej Warzynski                          mlir::ConversionPatternRewriter &rewriter,
282214867ffcSAndrzej Warzynski                          mlir::MLIRContext *ctx, int x) {
282314867ffcSAndrzej Warzynski   auto cx = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(x));
282414867ffcSAndrzej Warzynski   auto xty = ty.cast<mlir::LLVM::LLVMStructType>().getBody()[x];
282514867ffcSAndrzej Warzynski   return rewriter.create<mlir::LLVM::ExtractValueOp>(loc, xty, tuple, cx);
282614867ffcSAndrzej Warzynski }
282714867ffcSAndrzej Warzynski 
2828c2acd453SAlexisPerry namespace {
28296c3d7fd4SAndrzej Warzynski /// Convert `!fir.boxchar_len` to  `!llvm.extractvalue` for the 2nd part of the
28306c3d7fd4SAndrzej Warzynski /// boxchar.
28316c3d7fd4SAndrzej Warzynski struct BoxCharLenOpConversion : public FIROpConversion<fir::BoxCharLenOp> {
28326c3d7fd4SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
28336c3d7fd4SAndrzej Warzynski 
28346c3d7fd4SAndrzej Warzynski   mlir::LogicalResult
28356c3d7fd4SAndrzej Warzynski   matchAndRewrite(fir::BoxCharLenOp boxCharLen, OpAdaptor adaptor,
28366c3d7fd4SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
28376c3d7fd4SAndrzej Warzynski     mlir::Value boxChar = adaptor.getOperands()[0];
28386c3d7fd4SAndrzej Warzynski     mlir::Location loc = boxChar.getLoc();
28396c3d7fd4SAndrzej Warzynski     mlir::MLIRContext *ctx = boxChar.getContext();
28406c3d7fd4SAndrzej Warzynski     mlir::Type returnValTy = boxCharLen.getResult().getType();
28416c3d7fd4SAndrzej Warzynski 
28426c3d7fd4SAndrzej Warzynski     constexpr int boxcharLenIdx = 1;
28436c3d7fd4SAndrzej Warzynski     mlir::LLVM::ExtractValueOp len = genExtractValueWithIndex(
28446c3d7fd4SAndrzej Warzynski         loc, boxChar, boxChar.getType(), rewriter, ctx, boxcharLenIdx);
28456c3d7fd4SAndrzej Warzynski     mlir::Value lenAfterCast = integerCast(loc, rewriter, returnValTy, len);
28466c3d7fd4SAndrzej Warzynski     rewriter.replaceOp(boxCharLen, lenAfterCast);
28476c3d7fd4SAndrzej Warzynski 
28486c3d7fd4SAndrzej Warzynski     return success();
28496c3d7fd4SAndrzej Warzynski   }
28506c3d7fd4SAndrzej Warzynski };
28516c3d7fd4SAndrzej Warzynski 
285214867ffcSAndrzej Warzynski /// Convert `fir.unboxchar` into two `llvm.extractvalue` instructions. One for
285314867ffcSAndrzej Warzynski /// the character buffer and one for the buffer length.
285414867ffcSAndrzej Warzynski struct UnboxCharOpConversion : public FIROpConversion<fir::UnboxCharOp> {
285514867ffcSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
285614867ffcSAndrzej Warzynski 
285714867ffcSAndrzej Warzynski   mlir::LogicalResult
285814867ffcSAndrzej Warzynski   matchAndRewrite(fir::UnboxCharOp unboxchar, OpAdaptor adaptor,
285914867ffcSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
286014867ffcSAndrzej Warzynski     MLIRContext *ctx = unboxchar.getContext();
286114867ffcSAndrzej Warzynski 
286214867ffcSAndrzej Warzynski     mlir::Type lenTy = convertType(unboxchar.getType(1));
286314867ffcSAndrzej Warzynski     mlir::Value tuple = adaptor.getOperands()[0];
286414867ffcSAndrzej Warzynski     mlir::Type tupleTy = tuple.getType();
286514867ffcSAndrzej Warzynski 
286614867ffcSAndrzej Warzynski     mlir::Location loc = unboxchar.getLoc();
286714867ffcSAndrzej Warzynski     mlir::Value ptrToBuffer =
286814867ffcSAndrzej Warzynski         genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 0);
286914867ffcSAndrzej Warzynski 
287014867ffcSAndrzej Warzynski     mlir::LLVM::ExtractValueOp len =
287114867ffcSAndrzej Warzynski         genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 1);
287214867ffcSAndrzej Warzynski     mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, len);
287314867ffcSAndrzej Warzynski 
287414867ffcSAndrzej Warzynski     rewriter.replaceOp(unboxchar,
287514867ffcSAndrzej Warzynski                        ArrayRef<mlir::Value>{ptrToBuffer, lenAfterCast});
287614867ffcSAndrzej Warzynski     return success();
287714867ffcSAndrzej Warzynski   }
287814867ffcSAndrzej Warzynski };
287914867ffcSAndrzej Warzynski 
2880cc505c0bSKiran Chandramohan /// Lower `fir.unboxproc` operation. Unbox a procedure box value, yielding its
2881cc505c0bSKiran Chandramohan /// components.
2882cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
2883cc505c0bSKiran Chandramohan struct UnboxProcOpConversion : public FIROpConversion<fir::UnboxProcOp> {
2884cc505c0bSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2885cc505c0bSKiran Chandramohan 
2886cc505c0bSKiran Chandramohan   mlir::LogicalResult
2887cc505c0bSKiran Chandramohan   matchAndRewrite(fir::UnboxProcOp unboxproc, OpAdaptor adaptor,
2888cc505c0bSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
28897ce8c6fcSKiran Chandramohan     TODO(unboxproc.getLoc(), "fir.unboxproc codegen");
28907ce8c6fcSKiran Chandramohan     return failure();
2891cc505c0bSKiran Chandramohan   }
2892cc505c0bSKiran Chandramohan };
2893cc505c0bSKiran Chandramohan 
2894e6c66ef5SAndrzej Warzynski /// Convert `fir.field_index`. The conversion depends on whether the size of
2895e6c66ef5SAndrzej Warzynski /// the record is static or dynamic.
2896e6c66ef5SAndrzej Warzynski struct FieldIndexOpConversion : public FIROpConversion<fir::FieldIndexOp> {
2897e6c66ef5SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
2898e6c66ef5SAndrzej Warzynski 
2899e6c66ef5SAndrzej Warzynski   // NB: most field references should be resolved by this point
2900e6c66ef5SAndrzej Warzynski   mlir::LogicalResult
2901e6c66ef5SAndrzej Warzynski   matchAndRewrite(fir::FieldIndexOp field, OpAdaptor adaptor,
2902e6c66ef5SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
2903e6c66ef5SAndrzej Warzynski     auto recTy = field.on_type().cast<fir::RecordType>();
2904e6c66ef5SAndrzej Warzynski     unsigned index = recTy.getFieldIndex(field.field_id());
2905e6c66ef5SAndrzej Warzynski 
2906e6c66ef5SAndrzej Warzynski     if (!fir::hasDynamicSize(recTy)) {
2907e6c66ef5SAndrzej Warzynski       // Derived type has compile-time constant layout. Return index of the
2908e6c66ef5SAndrzej Warzynski       // component type in the parent type (to be used in GEP).
2909e6c66ef5SAndrzej Warzynski       rewriter.replaceOp(field, mlir::ValueRange{genConstantOffset(
2910e6c66ef5SAndrzej Warzynski                                     field.getLoc(), rewriter, index)});
2911e6c66ef5SAndrzej Warzynski       return success();
2912e6c66ef5SAndrzej Warzynski     }
2913e6c66ef5SAndrzej Warzynski 
2914e6c66ef5SAndrzej Warzynski     // Derived type has compile-time constant layout. Call the compiler
2915e6c66ef5SAndrzej Warzynski     // generated function to determine the byte offset of the field at runtime.
2916e6c66ef5SAndrzej Warzynski     // This returns a non-constant.
2917e6c66ef5SAndrzej Warzynski     FlatSymbolRefAttr symAttr = mlir::SymbolRefAttr::get(
2918e6c66ef5SAndrzej Warzynski         field.getContext(), getOffsetMethodName(recTy, field.field_id()));
2919e6c66ef5SAndrzej Warzynski     NamedAttribute callAttr = rewriter.getNamedAttr("callee", symAttr);
2920e6c66ef5SAndrzej Warzynski     NamedAttribute fieldAttr = rewriter.getNamedAttr(
2921e6c66ef5SAndrzej Warzynski         "field", mlir::IntegerAttr::get(lowerTy().indexType(), index));
2922e6c66ef5SAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
2923e6c66ef5SAndrzej Warzynski         field, lowerTy().offsetType(), adaptor.getOperands(),
2924e6c66ef5SAndrzej Warzynski         llvm::ArrayRef<mlir::NamedAttribute>{callAttr, fieldAttr});
2925e6c66ef5SAndrzej Warzynski     return success();
2926e6c66ef5SAndrzej Warzynski   }
2927e6c66ef5SAndrzej Warzynski 
2928e6c66ef5SAndrzej Warzynski   // Re-Construct the name of the compiler generated method that calculates the
2929e6c66ef5SAndrzej Warzynski   // offset
2930e6c66ef5SAndrzej Warzynski   inline static std::string getOffsetMethodName(fir::RecordType recTy,
2931e6c66ef5SAndrzej Warzynski                                                 llvm::StringRef field) {
2932e6c66ef5SAndrzej Warzynski     return recTy.getName().str() + "P." + field.str() + ".offset";
2933e6c66ef5SAndrzej Warzynski   }
2934e6c66ef5SAndrzej Warzynski };
2935e6c66ef5SAndrzej Warzynski 
293675db341dSAndrzej Warzynski /// Convert to (memory) reference to a reference to a subobject.
293775db341dSAndrzej Warzynski /// The coordinate_of op is a Swiss army knife operation that can be used on
293875db341dSAndrzej Warzynski /// (memory) references to records, arrays, complex, etc. as well as boxes.
293975db341dSAndrzej Warzynski /// With unboxed arrays, there is the restriction that the array have a static
294075db341dSAndrzej Warzynski /// shape in all but the last column.
294175db341dSAndrzej Warzynski struct CoordinateOpConversion
294275db341dSAndrzej Warzynski     : public FIROpAndTypeConversion<fir::CoordinateOp> {
294375db341dSAndrzej Warzynski   using FIROpAndTypeConversion::FIROpAndTypeConversion;
294475db341dSAndrzej Warzynski 
294575db341dSAndrzej Warzynski   mlir::LogicalResult
294675db341dSAndrzej Warzynski   doRewrite(fir::CoordinateOp coor, mlir::Type ty, OpAdaptor adaptor,
294775db341dSAndrzej Warzynski             mlir::ConversionPatternRewriter &rewriter) const override {
294875db341dSAndrzej Warzynski     mlir::ValueRange operands = adaptor.getOperands();
294975db341dSAndrzej Warzynski 
295075db341dSAndrzej Warzynski     mlir::Location loc = coor.getLoc();
295175db341dSAndrzej Warzynski     mlir::Value base = operands[0];
295275db341dSAndrzej Warzynski     mlir::Type baseObjectTy = coor.getBaseType();
295375db341dSAndrzej Warzynski     mlir::Type objectTy = fir::dyn_cast_ptrOrBoxEleTy(baseObjectTy);
295475db341dSAndrzej Warzynski     assert(objectTy && "fir.coordinate_of expects a reference type");
295575db341dSAndrzej Warzynski 
295675db341dSAndrzej Warzynski     // Complex type - basically, extract the real or imaginary part
295775db341dSAndrzej Warzynski     if (fir::isa_complex(objectTy)) {
295875db341dSAndrzej Warzynski       mlir::LLVM::ConstantOp c0 =
295975db341dSAndrzej Warzynski           genConstantIndex(loc, lowerTy().indexType(), rewriter, 0);
296075db341dSAndrzej Warzynski       SmallVector<mlir::Value> offs = {c0, operands[1]};
296175db341dSAndrzej Warzynski       mlir::Value gep = genGEP(loc, ty, rewriter, base, offs);
296275db341dSAndrzej Warzynski       rewriter.replaceOp(coor, gep);
296375db341dSAndrzej Warzynski       return success();
296475db341dSAndrzej Warzynski     }
296575db341dSAndrzej Warzynski 
29666d655ad0SAndrzej Warzynski     // Boxed type - get the base pointer from the box
29676d655ad0SAndrzej Warzynski     if (baseObjectTy.dyn_cast<fir::BoxType>())
29686d655ad0SAndrzej Warzynski       return doRewriteBox(coor, ty, operands, loc, rewriter);
296975db341dSAndrzej Warzynski 
29706d655ad0SAndrzej Warzynski     // Reference or pointer type
29716d655ad0SAndrzej Warzynski     if (baseObjectTy.isa<fir::ReferenceType, fir::PointerType>())
29726d655ad0SAndrzej Warzynski       return doRewriteRefOrPtr(coor, ty, operands, loc, rewriter);
297375db341dSAndrzej Warzynski 
297475db341dSAndrzej Warzynski     return rewriter.notifyMatchFailure(
297575db341dSAndrzej Warzynski         coor, "fir.coordinate_of base operand has unsupported type");
297675db341dSAndrzej Warzynski   }
297775db341dSAndrzej Warzynski 
297875db341dSAndrzej Warzynski   unsigned getFieldNumber(fir::RecordType ty, mlir::Value op) const {
297975db341dSAndrzej Warzynski     return fir::hasDynamicSize(ty)
298075db341dSAndrzej Warzynski                ? op.getDefiningOp()
298175db341dSAndrzej Warzynski                      ->getAttrOfType<mlir::IntegerAttr>("field")
298275db341dSAndrzej Warzynski                      .getInt()
298375db341dSAndrzej Warzynski                : getIntValue(op);
298475db341dSAndrzej Warzynski   }
298575db341dSAndrzej Warzynski 
298675db341dSAndrzej Warzynski   int64_t getIntValue(mlir::Value val) const {
298775db341dSAndrzej Warzynski     assert(val && val.dyn_cast<mlir::OpResult>() && "must not be null value");
298875db341dSAndrzej Warzynski     mlir::Operation *defop = val.getDefiningOp();
298975db341dSAndrzej Warzynski 
299075db341dSAndrzej Warzynski     if (auto constOp = dyn_cast<mlir::arith::ConstantIntOp>(defop))
299175db341dSAndrzej Warzynski       return constOp.value();
299275db341dSAndrzej Warzynski     if (auto llConstOp = dyn_cast<mlir::LLVM::ConstantOp>(defop))
2993feeee78aSJacques Pienaar       if (auto attr = llConstOp.getValue().dyn_cast<mlir::IntegerAttr>())
299475db341dSAndrzej Warzynski         return attr.getValue().getSExtValue();
299575db341dSAndrzej Warzynski     fir::emitFatalError(val.getLoc(), "must be a constant");
299675db341dSAndrzej Warzynski   }
299775db341dSAndrzej Warzynski 
29986d655ad0SAndrzej Warzynski   bool hasSubDimensions(mlir::Type type) const {
29996d655ad0SAndrzej Warzynski     return type.isa<fir::SequenceType, fir::RecordType, mlir::TupleType>();
30006d655ad0SAndrzej Warzynski   }
30016d655ad0SAndrzej Warzynski 
30026d655ad0SAndrzej Warzynski   /// Check whether this form of `!fir.coordinate_of` is supported. These
30036d655ad0SAndrzej Warzynski   /// additional checks are required, because we are not yet able to convert
30046d655ad0SAndrzej Warzynski   /// all valid forms of `!fir.coordinate_of`.
30056d655ad0SAndrzej Warzynski   /// TODO: Either implement the unsupported cases or extend the verifier
30066d655ad0SAndrzej Warzynski   /// in FIROps.cpp instead.
30076d655ad0SAndrzej Warzynski   bool supportedCoordinate(mlir::Type type, mlir::ValueRange coors) const {
30086d655ad0SAndrzej Warzynski     const std::size_t numOfCoors = coors.size();
30096d655ad0SAndrzej Warzynski     std::size_t i = 0;
30106d655ad0SAndrzej Warzynski     bool subEle = false;
30116d655ad0SAndrzej Warzynski     bool ptrEle = false;
30126d655ad0SAndrzej Warzynski     for (; i < numOfCoors; ++i) {
30136d655ad0SAndrzej Warzynski       mlir::Value nxtOpnd = coors[i];
30146d655ad0SAndrzej Warzynski       if (auto arrTy = type.dyn_cast<fir::SequenceType>()) {
30156d655ad0SAndrzej Warzynski         subEle = true;
30166d655ad0SAndrzej Warzynski         i += arrTy.getDimension() - 1;
30176d655ad0SAndrzej Warzynski         type = arrTy.getEleTy();
30186d655ad0SAndrzej Warzynski       } else if (auto recTy = type.dyn_cast<fir::RecordType>()) {
30196d655ad0SAndrzej Warzynski         subEle = true;
30206d655ad0SAndrzej Warzynski         type = recTy.getType(getFieldNumber(recTy, nxtOpnd));
30216d655ad0SAndrzej Warzynski       } else if (auto tupTy = type.dyn_cast<mlir::TupleType>()) {
30226d655ad0SAndrzej Warzynski         subEle = true;
30236d655ad0SAndrzej Warzynski         type = tupTy.getType(getIntValue(nxtOpnd));
30246d655ad0SAndrzej Warzynski       } else {
30256d655ad0SAndrzej Warzynski         ptrEle = true;
30266d655ad0SAndrzej Warzynski       }
30276d655ad0SAndrzej Warzynski     }
30286d655ad0SAndrzej Warzynski     if (ptrEle)
30296d655ad0SAndrzej Warzynski       return (!subEle) && (numOfCoors == 1);
30306d655ad0SAndrzej Warzynski     return subEle && (i >= numOfCoors);
30316d655ad0SAndrzej Warzynski   }
30326d655ad0SAndrzej Warzynski 
30336d655ad0SAndrzej Warzynski   /// Walk the abstract memory layout and determine if the path traverses any
30346d655ad0SAndrzej Warzynski   /// array types with unknown shape. Return true iff all the array types have a
30356d655ad0SAndrzej Warzynski   /// constant shape along the path.
30366d655ad0SAndrzej Warzynski   bool arraysHaveKnownShape(mlir::Type type, mlir::ValueRange coors) const {
30376d655ad0SAndrzej Warzynski     const std::size_t sz = coors.size();
30386d655ad0SAndrzej Warzynski     std::size_t i = 0;
30396d655ad0SAndrzej Warzynski     for (; i < sz; ++i) {
30406d655ad0SAndrzej Warzynski       mlir::Value nxtOpnd = coors[i];
30416d655ad0SAndrzej Warzynski       if (auto arrTy = type.dyn_cast<fir::SequenceType>()) {
30426d655ad0SAndrzej Warzynski         if (fir::sequenceWithNonConstantShape(arrTy))
30436d655ad0SAndrzej Warzynski           return false;
30446d655ad0SAndrzej Warzynski         i += arrTy.getDimension() - 1;
30456d655ad0SAndrzej Warzynski         type = arrTy.getEleTy();
30466d655ad0SAndrzej Warzynski       } else if (auto strTy = type.dyn_cast<fir::RecordType>()) {
30476d655ad0SAndrzej Warzynski         type = strTy.getType(getFieldNumber(strTy, nxtOpnd));
30486d655ad0SAndrzej Warzynski       } else if (auto strTy = type.dyn_cast<mlir::TupleType>()) {
30496d655ad0SAndrzej Warzynski         type = strTy.getType(getIntValue(nxtOpnd));
30506d655ad0SAndrzej Warzynski       } else {
30516d655ad0SAndrzej Warzynski         return true;
30526d655ad0SAndrzej Warzynski       }
30536d655ad0SAndrzej Warzynski     }
30546d655ad0SAndrzej Warzynski     return true;
30556d655ad0SAndrzej Warzynski   }
30566d655ad0SAndrzej Warzynski 
305775db341dSAndrzej Warzynski private:
30586d655ad0SAndrzej Warzynski   mlir::LogicalResult
30596d655ad0SAndrzej Warzynski   doRewriteBox(fir::CoordinateOp coor, mlir::Type ty, mlir::ValueRange operands,
30606d655ad0SAndrzej Warzynski                mlir::Location loc,
306175db341dSAndrzej Warzynski                mlir::ConversionPatternRewriter &rewriter) const {
306275db341dSAndrzej Warzynski     mlir::Type boxObjTy = coor.getBaseType();
306375db341dSAndrzej Warzynski     assert(boxObjTy.dyn_cast<fir::BoxType>() && "This is not a `fir.box`");
306475db341dSAndrzej Warzynski 
306575db341dSAndrzej Warzynski     mlir::Value boxBaseAddr = operands[0];
306675db341dSAndrzej Warzynski 
306775db341dSAndrzej Warzynski     // 1. SPECIAL CASE (uses `fir.len_param_index`):
306875db341dSAndrzej Warzynski     //   %box = ... : !fir.box<!fir.type<derived{len1:i32}>>
306975db341dSAndrzej Warzynski     //   %lenp = fir.len_param_index len1, !fir.type<derived{len1:i32}>
307075db341dSAndrzej Warzynski     //   %addr = coordinate_of %box, %lenp
307175db341dSAndrzej Warzynski     if (coor.getNumOperands() == 2) {
307275db341dSAndrzej Warzynski       mlir::Operation *coordinateDef = (*coor.coor().begin()).getDefiningOp();
307375db341dSAndrzej Warzynski       if (isa_and_nonnull<fir::LenParamIndexOp>(coordinateDef)) {
307475db341dSAndrzej Warzynski         TODO(loc,
307575db341dSAndrzej Warzynski              "fir.coordinate_of - fir.len_param_index is not supported yet");
307675db341dSAndrzej Warzynski       }
307775db341dSAndrzej Warzynski     }
307875db341dSAndrzej Warzynski 
307975db341dSAndrzej Warzynski     // 2. GENERAL CASE:
308075db341dSAndrzej Warzynski     // 2.1. (`fir.array`)
308175db341dSAndrzej Warzynski     //   %box = ... : !fix.box<!fir.array<?xU>>
308275db341dSAndrzej Warzynski     //   %idx = ... : index
308375db341dSAndrzej Warzynski     //   %resultAddr = coordinate_of %box, %idx : !fir.ref<U>
308475db341dSAndrzej Warzynski     // 2.2 (`fir.derived`)
308575db341dSAndrzej Warzynski     //   %box = ... : !fix.box<!fir.type<derived_type{field_1:i32}>>
308675db341dSAndrzej Warzynski     //   %idx = ... : i32
308775db341dSAndrzej Warzynski     //   %resultAddr = coordinate_of %box, %idx : !fir.ref<i32>
308875db341dSAndrzej Warzynski     // 2.3 (`fir.derived` inside `fir.array`)
308975db341dSAndrzej Warzynski     //   %box = ... : !fir.box<!fir.array<10 x !fir.type<derived_1{field_1:f32, field_2:f32}>>>
309075db341dSAndrzej Warzynski     //   %idx1 = ... : index
309175db341dSAndrzej Warzynski     //   %idx2 = ... : i32
309275db341dSAndrzej Warzynski     //   %resultAddr = coordinate_of %box, %idx1, %idx2 : !fir.ref<f32>
309375db341dSAndrzej Warzynski     // 2.4. TODO: Either document or disable any other case that the following
309475db341dSAndrzej Warzynski     //  implementation might convert.
309575db341dSAndrzej Warzynski     mlir::LLVM::ConstantOp c0 =
309675db341dSAndrzej Warzynski         genConstantIndex(loc, lowerTy().indexType(), rewriter, 0);
309775db341dSAndrzej Warzynski     mlir::Value resultAddr =
309875db341dSAndrzej Warzynski         loadBaseAddrFromBox(loc, getBaseAddrTypeFromBox(boxBaseAddr.getType()),
309975db341dSAndrzej Warzynski                             boxBaseAddr, rewriter);
310075db341dSAndrzej Warzynski     auto currentObjTy = fir::dyn_cast_ptrOrBoxEleTy(boxObjTy);
310175db341dSAndrzej Warzynski     mlir::Type voidPtrTy = ::getVoidPtrType(coor.getContext());
310275db341dSAndrzej Warzynski 
310375db341dSAndrzej Warzynski     for (unsigned i = 1, last = operands.size(); i < last; ++i) {
310475db341dSAndrzej Warzynski       if (auto arrTy = currentObjTy.dyn_cast<fir::SequenceType>()) {
310575db341dSAndrzej Warzynski         if (i != 1)
310675db341dSAndrzej Warzynski           TODO(loc, "fir.array nested inside other array and/or derived type");
310775db341dSAndrzej Warzynski         // Applies byte strides from the box. Ignore lower bound from box
310875db341dSAndrzej Warzynski         // since fir.coordinate_of indexes are zero based. Lowering takes care
310975db341dSAndrzej Warzynski         // of lower bound aspects. This both accounts for dynamically sized
311075db341dSAndrzej Warzynski         // types and non contiguous arrays.
311175db341dSAndrzej Warzynski         auto idxTy = lowerTy().indexType();
311275db341dSAndrzej Warzynski         mlir::Value off = genConstantIndex(loc, idxTy, rewriter, 0);
311375db341dSAndrzej Warzynski         for (unsigned index = i, lastIndex = i + arrTy.getDimension();
311475db341dSAndrzej Warzynski              index < lastIndex; ++index) {
311575db341dSAndrzej Warzynski           mlir::Value stride =
311675db341dSAndrzej Warzynski               loadStrideFromBox(loc, operands[0], index - i, rewriter);
311775db341dSAndrzej Warzynski           auto sc = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy,
311875db341dSAndrzej Warzynski                                                        operands[index], stride);
311975db341dSAndrzej Warzynski           off = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, off);
312075db341dSAndrzej Warzynski         }
312175db341dSAndrzej Warzynski         auto voidPtrBase =
312275db341dSAndrzej Warzynski             rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, resultAddr);
312330122656SAlex Zinenko         SmallVector<mlir::Value> args{off};
312430122656SAlex Zinenko         resultAddr = rewriter.create<mlir::LLVM::GEPOp>(loc, voidPtrTy,
312530122656SAlex Zinenko                                                         voidPtrBase, args);
312675db341dSAndrzej Warzynski         i += arrTy.getDimension() - 1;
312775db341dSAndrzej Warzynski         currentObjTy = arrTy.getEleTy();
312875db341dSAndrzej Warzynski       } else if (auto recTy = currentObjTy.dyn_cast<fir::RecordType>()) {
312975db341dSAndrzej Warzynski         auto recRefTy =
313075db341dSAndrzej Warzynski             mlir::LLVM::LLVMPointerType::get(lowerTy().convertType(recTy));
313175db341dSAndrzej Warzynski         mlir::Value nxtOpnd = operands[i];
313275db341dSAndrzej Warzynski         auto memObj =
313375db341dSAndrzej Warzynski             rewriter.create<mlir::LLVM::BitcastOp>(loc, recRefTy, resultAddr);
313430122656SAlex Zinenko         llvm::SmallVector<mlir::Value> args = {c0, nxtOpnd};
313575db341dSAndrzej Warzynski         currentObjTy = recTy.getType(getFieldNumber(recTy, nxtOpnd));
313675db341dSAndrzej Warzynski         auto llvmCurrentObjTy = lowerTy().convertType(currentObjTy);
313775db341dSAndrzej Warzynski         auto gep = rewriter.create<mlir::LLVM::GEPOp>(
313830122656SAlex Zinenko             loc, mlir::LLVM::LLVMPointerType::get(llvmCurrentObjTy), memObj,
313930122656SAlex Zinenko             args);
314075db341dSAndrzej Warzynski         resultAddr =
314175db341dSAndrzej Warzynski             rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, gep);
314275db341dSAndrzej Warzynski       } else {
314375db341dSAndrzej Warzynski         fir::emitFatalError(loc, "unexpected type in coordinate_of");
314475db341dSAndrzej Warzynski       }
314575db341dSAndrzej Warzynski     }
314675db341dSAndrzej Warzynski 
314775db341dSAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(coor, ty, resultAddr);
31486d655ad0SAndrzej Warzynski     return success();
314975db341dSAndrzej Warzynski   }
315075db341dSAndrzej Warzynski 
31516d655ad0SAndrzej Warzynski   mlir::LogicalResult
31526d655ad0SAndrzej Warzynski   doRewriteRefOrPtr(fir::CoordinateOp coor, mlir::Type ty,
31536d655ad0SAndrzej Warzynski                     mlir::ValueRange operands, mlir::Location loc,
31546d655ad0SAndrzej Warzynski                     mlir::ConversionPatternRewriter &rewriter) const {
31556d655ad0SAndrzej Warzynski     mlir::Type baseObjectTy = coor.getBaseType();
31566d655ad0SAndrzej Warzynski 
31576d655ad0SAndrzej Warzynski     mlir::Type currentObjTy = fir::dyn_cast_ptrOrBoxEleTy(baseObjectTy);
31586d655ad0SAndrzej Warzynski     bool hasSubdimension = hasSubDimensions(currentObjTy);
31596d655ad0SAndrzej Warzynski     bool columnIsDeferred = !hasSubdimension;
31606d655ad0SAndrzej Warzynski 
31616d655ad0SAndrzej Warzynski     if (!supportedCoordinate(currentObjTy, operands.drop_front(1))) {
31626d655ad0SAndrzej Warzynski       TODO(loc, "unsupported combination of coordinate operands");
31636d655ad0SAndrzej Warzynski     }
31646d655ad0SAndrzej Warzynski 
31656d655ad0SAndrzej Warzynski     const bool hasKnownShape =
31666d655ad0SAndrzej Warzynski         arraysHaveKnownShape(currentObjTy, operands.drop_front(1));
31676d655ad0SAndrzej Warzynski 
31686d655ad0SAndrzej Warzynski     // If only the column is `?`, then we can simply place the column value in
31696d655ad0SAndrzej Warzynski     // the 0-th GEP position.
31706d655ad0SAndrzej Warzynski     if (auto arrTy = currentObjTy.dyn_cast<fir::SequenceType>()) {
31716d655ad0SAndrzej Warzynski       if (!hasKnownShape) {
31726d655ad0SAndrzej Warzynski         const unsigned sz = arrTy.getDimension();
31736d655ad0SAndrzej Warzynski         if (arraysHaveKnownShape(arrTy.getEleTy(),
31746d655ad0SAndrzej Warzynski                                  operands.drop_front(1 + sz))) {
31756d655ad0SAndrzej Warzynski           llvm::ArrayRef<int64_t> shape = arrTy.getShape();
31766d655ad0SAndrzej Warzynski           bool allConst = true;
31776d655ad0SAndrzej Warzynski           for (unsigned i = 0; i < sz - 1; ++i) {
31786d655ad0SAndrzej Warzynski             if (shape[i] < 0) {
31796d655ad0SAndrzej Warzynski               allConst = false;
31806d655ad0SAndrzej Warzynski               break;
31816d655ad0SAndrzej Warzynski             }
31826d655ad0SAndrzej Warzynski           }
31836d655ad0SAndrzej Warzynski           if (allConst)
31846d655ad0SAndrzej Warzynski             columnIsDeferred = true;
31856d655ad0SAndrzej Warzynski         }
31866d655ad0SAndrzej Warzynski       }
31876d655ad0SAndrzej Warzynski     }
31886d655ad0SAndrzej Warzynski 
31896d655ad0SAndrzej Warzynski     if (fir::hasDynamicSize(fir::unwrapSequenceType(currentObjTy))) {
31906d655ad0SAndrzej Warzynski       mlir::emitError(
31916d655ad0SAndrzej Warzynski           loc, "fir.coordinate_of with a dynamic element size is unsupported");
31926d655ad0SAndrzej Warzynski       return failure();
31936d655ad0SAndrzej Warzynski     }
31946d655ad0SAndrzej Warzynski 
31956d655ad0SAndrzej Warzynski     if (hasKnownShape || columnIsDeferred) {
31966d655ad0SAndrzej Warzynski       SmallVector<mlir::Value> offs;
31976d655ad0SAndrzej Warzynski       if (hasKnownShape && hasSubdimension) {
31986d655ad0SAndrzej Warzynski         mlir::LLVM::ConstantOp c0 =
31996d655ad0SAndrzej Warzynski             genConstantIndex(loc, lowerTy().indexType(), rewriter, 0);
32006d655ad0SAndrzej Warzynski         offs.push_back(c0);
32016d655ad0SAndrzej Warzynski       }
32026d655ad0SAndrzej Warzynski       const std::size_t sz = operands.size();
32036d655ad0SAndrzej Warzynski       Optional<int> dims;
32046d655ad0SAndrzej Warzynski       SmallVector<mlir::Value> arrIdx;
32056d655ad0SAndrzej Warzynski       for (std::size_t i = 1; i < sz; ++i) {
32066d655ad0SAndrzej Warzynski         mlir::Value nxtOpnd = operands[i];
32076d655ad0SAndrzej Warzynski 
32086d655ad0SAndrzej Warzynski         if (!currentObjTy) {
32096d655ad0SAndrzej Warzynski           mlir::emitError(loc, "invalid coordinate/check failed");
32106d655ad0SAndrzej Warzynski           return failure();
32116d655ad0SAndrzej Warzynski         }
32126d655ad0SAndrzej Warzynski 
32136d655ad0SAndrzej Warzynski         // check if the i-th coordinate relates to an array
32146d655ad0SAndrzej Warzynski         if (dims.hasValue()) {
32156d655ad0SAndrzej Warzynski           arrIdx.push_back(nxtOpnd);
32166d655ad0SAndrzej Warzynski           int dimsLeft = *dims;
32176d655ad0SAndrzej Warzynski           if (dimsLeft > 1) {
32186d655ad0SAndrzej Warzynski             dims = dimsLeft - 1;
32196d655ad0SAndrzej Warzynski             continue;
32206d655ad0SAndrzej Warzynski           }
32216d655ad0SAndrzej Warzynski           currentObjTy = currentObjTy.cast<fir::SequenceType>().getEleTy();
32226d655ad0SAndrzej Warzynski           // append array range in reverse (FIR arrays are column-major)
32236d655ad0SAndrzej Warzynski           offs.append(arrIdx.rbegin(), arrIdx.rend());
32246d655ad0SAndrzej Warzynski           arrIdx.clear();
32256d655ad0SAndrzej Warzynski           dims.reset();
32266d655ad0SAndrzej Warzynski           continue;
32276d655ad0SAndrzej Warzynski         }
32286d655ad0SAndrzej Warzynski         if (auto arrTy = currentObjTy.dyn_cast<fir::SequenceType>()) {
32296d655ad0SAndrzej Warzynski           int d = arrTy.getDimension() - 1;
32306d655ad0SAndrzej Warzynski           if (d > 0) {
32316d655ad0SAndrzej Warzynski             dims = d;
32326d655ad0SAndrzej Warzynski             arrIdx.push_back(nxtOpnd);
32336d655ad0SAndrzej Warzynski             continue;
32346d655ad0SAndrzej Warzynski           }
32356d655ad0SAndrzej Warzynski           currentObjTy = currentObjTy.cast<fir::SequenceType>().getEleTy();
32366d655ad0SAndrzej Warzynski           offs.push_back(nxtOpnd);
32376d655ad0SAndrzej Warzynski           continue;
32386d655ad0SAndrzej Warzynski         }
32396d655ad0SAndrzej Warzynski 
32406d655ad0SAndrzej Warzynski         // check if the i-th coordinate relates to a field
32416d655ad0SAndrzej Warzynski         if (auto recTy = currentObjTy.dyn_cast<fir::RecordType>())
32426d655ad0SAndrzej Warzynski           currentObjTy = recTy.getType(getFieldNumber(recTy, nxtOpnd));
32436d655ad0SAndrzej Warzynski         else if (auto tupTy = currentObjTy.dyn_cast<mlir::TupleType>())
32446d655ad0SAndrzej Warzynski           currentObjTy = tupTy.getType(getIntValue(nxtOpnd));
32456d655ad0SAndrzej Warzynski         else
32466d655ad0SAndrzej Warzynski           currentObjTy = nullptr;
32476d655ad0SAndrzej Warzynski 
32486d655ad0SAndrzej Warzynski         offs.push_back(nxtOpnd);
32496d655ad0SAndrzej Warzynski       }
32506d655ad0SAndrzej Warzynski       if (dims.hasValue())
32516d655ad0SAndrzej Warzynski         offs.append(arrIdx.rbegin(), arrIdx.rend());
32526d655ad0SAndrzej Warzynski       mlir::Value base = operands[0];
32536d655ad0SAndrzej Warzynski       mlir::Value retval = genGEP(loc, ty, rewriter, base, offs);
32546d655ad0SAndrzej Warzynski       rewriter.replaceOp(coor, retval);
32556d655ad0SAndrzej Warzynski       return success();
32566d655ad0SAndrzej Warzynski     }
32576d655ad0SAndrzej Warzynski 
32586d655ad0SAndrzej Warzynski     mlir::emitError(loc, "fir.coordinate_of base operand has unsupported type");
32596d655ad0SAndrzej Warzynski     return failure();
326075db341dSAndrzej Warzynski   }
326175db341dSAndrzej Warzynski };
326275db341dSAndrzej Warzynski 
3263044d5b5dSValentin Clement } // namespace
3264044d5b5dSValentin Clement 
3265044d5b5dSValentin Clement namespace {
3266044d5b5dSValentin Clement /// Convert FIR dialect to LLVM dialect
3267044d5b5dSValentin Clement ///
3268044d5b5dSValentin Clement /// This pass lowers all FIR dialect operations to LLVM IR dialect. An
3269044d5b5dSValentin Clement /// MLIR pass is used to lower residual Std dialect to LLVM IR dialect.
3270044d5b5dSValentin Clement ///
3271044d5b5dSValentin Clement /// This pass is not complete yet. We are upstreaming it in small patches.
3272044d5b5dSValentin Clement class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> {
3273044d5b5dSValentin Clement public:
3274044d5b5dSValentin Clement   mlir::ModuleOp getModule() { return getOperation(); }
3275044d5b5dSValentin Clement 
3276044d5b5dSValentin Clement   void runOnOperation() override final {
32777b5132daSValentin Clement     auto mod = getModule();
32787b5132daSValentin Clement     if (!forcedTargetTriple.empty()) {
32797b5132daSValentin Clement       fir::setTargetTriple(mod, forcedTargetTriple);
32807b5132daSValentin Clement     }
32817b5132daSValentin Clement 
3282044d5b5dSValentin Clement     auto *context = getModule().getContext();
3283044d5b5dSValentin Clement     fir::LLVMTypeConverter typeConverter{getModule()};
32849f85c198SRiver Riddle     mlir::RewritePatternSet pattern(context);
3285df3b9810SValentin Clement     pattern.insert<
3286420ad7ceSAndrzej Warzynski         AbsentOpConversion, AddcOpConversion, AddrOfOpConversion,
3287c2acd453SAlexisPerry         AllocaOpConversion, AllocMemOpConversion, BoxAddrOpConversion,
3288c2acd453SAlexisPerry         BoxCharLenOpConversion, BoxDimsOpConversion, BoxEleSizeOpConversion,
3289c2acd453SAlexisPerry         BoxIsAllocOpConversion, BoxIsArrayOpConversion, BoxIsPtrOpConversion,
3290c2acd453SAlexisPerry         BoxProcHostOpConversion, BoxRankOpConversion, BoxTypeDescOpConversion,
3291c2acd453SAlexisPerry         CallOpConversion, CmpcOpConversion, ConstcOpConversion,
3292e6e7da55SAndrzej Warzynski         ConvertOpConversion, CoordinateOpConversion, DispatchOpConversion,
3293e6e7da55SAndrzej Warzynski         DispatchTableOpConversion, DTEntryOpConversion, DivcOpConversion,
3294e6e7da55SAndrzej Warzynski         EmboxOpConversion, EmboxCharOpConversion, EmboxProcOpConversion,
3295e6e7da55SAndrzej Warzynski         ExtractValueOpConversion, FieldIndexOpConversion, FirEndOpConversion,
3296e6e7da55SAndrzej Warzynski         FreeMemOpConversion, HasValueOpConversion, GenTypeDescOpConversion,
3297e6e7da55SAndrzej Warzynski         GlobalLenOpConversion, GlobalOpConversion, InsertOnRangeOpConversion,
3298e6e7da55SAndrzej Warzynski         InsertValueOpConversion, IsPresentOpConversion,
3299e6e7da55SAndrzej Warzynski         LenParamIndexOpConversion, LoadOpConversion, NegcOpConversion,
3300e6e7da55SAndrzej Warzynski         NoReassocOpConversion, MulcOpConversion, SelectCaseOpConversion,
3301e6e7da55SAndrzej Warzynski         SelectOpConversion, SelectRankOpConversion, SelectTypeOpConversion,
3302e6e7da55SAndrzej Warzynski         ShapeOpConversion, ShapeShiftOpConversion, ShiftOpConversion,
3303e6e7da55SAndrzej Warzynski         SliceOpConversion, StoreOpConversion, StringLitOpConversion,
3304e6e7da55SAndrzej Warzynski         SubcOpConversion, UnboxCharOpConversion, UnboxProcOpConversion,
3305e6e7da55SAndrzej Warzynski         UndefOpConversion, UnreachableOpConversion, XArrayCoorOpConversion,
3306e6e7da55SAndrzej Warzynski         XEmboxOpConversion, XReboxOpConversion, ZeroOpConversion>(
3307e6e7da55SAndrzej Warzynski         typeConverter);
3308044d5b5dSValentin Clement     mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern);
3309044d5b5dSValentin Clement     mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter,
3310044d5b5dSValentin Clement                                                             pattern);
3311ace01605SRiver Riddle     mlir::cf::populateControlFlowToLLVMConversionPatterns(typeConverter,
3312ace01605SRiver Riddle                                                           pattern);
3313044d5b5dSValentin Clement     mlir::ConversionTarget target{*context};
3314044d5b5dSValentin Clement     target.addLegalDialect<mlir::LLVM::LLVMDialect>();
3315044d5b5dSValentin Clement 
3316044d5b5dSValentin Clement     // required NOPs for applying a full conversion
3317044d5b5dSValentin Clement     target.addLegalOp<mlir::ModuleOp>();
3318044d5b5dSValentin Clement 
3319044d5b5dSValentin Clement     // apply the patterns
3320044d5b5dSValentin Clement     if (mlir::failed(mlir::applyFullConversion(getModule(), target,
3321044d5b5dSValentin Clement                                                std::move(pattern)))) {
3322044d5b5dSValentin Clement       signalPassFailure();
3323044d5b5dSValentin Clement     }
3324044d5b5dSValentin Clement   }
3325044d5b5dSValentin Clement };
3326853e79d8SValentin Clement 
3327853e79d8SValentin Clement /// Lower from LLVM IR dialect to proper LLVM-IR and dump the module
3328853e79d8SValentin Clement struct LLVMIRLoweringPass
3329853e79d8SValentin Clement     : public mlir::PassWrapper<LLVMIRLoweringPass,
3330853e79d8SValentin Clement                                mlir::OperationPass<mlir::ModuleOp>> {
3331853e79d8SValentin Clement   using Printer = fir::LLVMIRLoweringPrinter;
3332853e79d8SValentin Clement   LLVMIRLoweringPass(raw_ostream &output, Printer p)
3333853e79d8SValentin Clement       : output{output}, printer{p} {}
3334853e79d8SValentin Clement 
3335853e79d8SValentin Clement   mlir::ModuleOp getModule() { return getOperation(); }
3336853e79d8SValentin Clement 
3337853e79d8SValentin Clement   void runOnOperation() override final {
3338853e79d8SValentin Clement     auto *ctx = getModule().getContext();
3339853e79d8SValentin Clement     auto optName = getModule().getName();
3340853e79d8SValentin Clement     llvm::LLVMContext llvmCtx;
3341853e79d8SValentin Clement     if (auto llvmModule = mlir::translateModuleToLLVMIR(
3342853e79d8SValentin Clement             getModule(), llvmCtx, optName ? *optName : "FIRModule")) {
3343853e79d8SValentin Clement       printer(*llvmModule, output);
3344853e79d8SValentin Clement       return;
3345853e79d8SValentin Clement     }
3346853e79d8SValentin Clement 
3347853e79d8SValentin Clement     mlir::emitError(mlir::UnknownLoc::get(ctx), "could not emit LLVM-IR\n");
3348853e79d8SValentin Clement     signalPassFailure();
3349853e79d8SValentin Clement   }
3350853e79d8SValentin Clement 
3351853e79d8SValentin Clement private:
3352853e79d8SValentin Clement   raw_ostream &output;
3353853e79d8SValentin Clement   Printer printer;
3354853e79d8SValentin Clement };
3355853e79d8SValentin Clement 
3356044d5b5dSValentin Clement } // namespace
3357044d5b5dSValentin Clement 
3358044d5b5dSValentin Clement std::unique_ptr<mlir::Pass> fir::createFIRToLLVMPass() {
3359044d5b5dSValentin Clement   return std::make_unique<FIRToLLVMLowering>();
3360044d5b5dSValentin Clement }
3361853e79d8SValentin Clement 
3362853e79d8SValentin Clement std::unique_ptr<mlir::Pass>
3363853e79d8SValentin Clement fir::createLLVMDialectToLLVMPass(raw_ostream &output,
3364853e79d8SValentin Clement                                  fir::LLVMIRLoweringPrinter printer) {
3365853e79d8SValentin Clement   return std::make_unique<LLVMIRLoweringPass>(output, printer);
3366853e79d8SValentin Clement }
3367