xref: /llvm-project/flang/lib/Optimizer/CodeGen/CodeGen.cpp (revision 0b80491cd5e7dcb6d5432727d0a2c746a9a9438e)
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"
1467d0d7acSMichele Scuttari 
15cd5ee271SAbid Qadeer #include "flang/Optimizer/CodeGen/CGOps.h"
1695fe47caSagozillon #include "flang/Optimizer/CodeGen/CodeGenOpenMP.h"
17e9639e9cSValentin Clement (バレンタイン クレメン) #include "flang/Optimizer/CodeGen/FIROpPatterns.h"
18e9639e9cSValentin Clement (バレンタイン クレメン) #include "flang/Optimizer/CodeGen/TypeConverter.h"
1939f4ef81SValentin Clement #include "flang/Optimizer/Dialect/FIRAttr.h"
20044d5b5dSValentin Clement #include "flang/Optimizer/Dialect/FIROps.h"
210538bfe7SRenaud-K #include "flang/Optimizer/Dialect/FIRType.h"
2227d9a479SjeanPerier #include "flang/Optimizer/Support/DataLayout.h"
237dd7ccd2SJean Perier #include "flang/Optimizer/Support/InternalNames.h"
24af6ee580SValentin Clement #include "flang/Optimizer/Support/TypeCode.h"
250538bfe7SRenaud-K #include "flang/Optimizer/Support/Utils.h"
265e1f87e8SValentin Clement (バレンタイン クレメン) #include "flang/Runtime/CUDA/descriptor.h"
274530273dSValentin Clement (バレンタイン クレメン) #include "flang/Runtime/CUDA/memory.h"
28c91ba043SMichael Kruse #include "flang/Runtime/allocator-registry-consts.h"
29c91ba043SMichael Kruse #include "flang/Runtime/descriptor-consts.h"
307dd7ccd2SJean Perier #include "flang/Semantics/runtime-type-info.h"
31bc955caeSSlava Zakharin #include "mlir/Conversion/ArithCommon/AttrToLLVMConverter.h"
326c8d8d10SJakub Kuderski #include "mlir/Conversion/ArithToLLVM/ArithToLLVM.h"
33000de666SDavid Truby #include "mlir/Conversion/ComplexToLLVM/ComplexToLLVM.h"
34000de666SDavid Truby #include "mlir/Conversion/ComplexToStandard/ComplexToStandard.h"
35ace01605SRiver Riddle #include "mlir/Conversion/ControlFlowToLLVM/ControlFlowToLLVM.h"
365a7b9194SRiver Riddle #include "mlir/Conversion/FuncToLLVM/ConvertFuncToLLVM.h"
37044d5b5dSValentin Clement #include "mlir/Conversion/LLVMCommon/Pattern.h"
38bac3aedaSSlava Zakharin #include "mlir/Conversion/MathToFuncs/MathToFuncs.h"
399f356579SSlava Zakharin #include "mlir/Conversion/MathToLLVM/MathToLLVM.h"
409f356579SSlava Zakharin #include "mlir/Conversion/MathToLibm/MathToLibm.h"
414290e34eSJan Leyonberg #include "mlir/Conversion/MathToROCDL/MathToROCDL.h"
42c6ac9370SKiran Chandramohan #include "mlir/Conversion/OpenMPToLLVM/ConvertOpenMPToLLVM.h"
43a9e1d2e7SKelvin Li #include "mlir/Conversion/VectorToLLVM/ConvertVectorToLLVM.h"
446be0e979STom Eccles #include "mlir/Dialect/Arith/IR/Arith.h"
4527d9a479SjeanPerier #include "mlir/Dialect/DLTI/DLTI.h"
46e5092c30SValentin Clement (バレンタイン クレメン) #include "mlir/Dialect/GPU/IR/GPUDialect.h"
4785d7fef6SValentin Clement (バレンタイン クレメン) #include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
4867d0d7acSMichele Scuttari #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
495f476b80SDavid Truby #include "mlir/Dialect/LLVMIR/Transforms/AddComdats.h"
50cd9cdc68SValentin Clement #include "mlir/Dialect/OpenACC/OpenACC.h"
5167d0d7acSMichele Scuttari #include "mlir/Dialect/OpenMP/OpenMPDialect.h"
52044d5b5dSValentin Clement #include "mlir/IR/BuiltinTypes.h"
533ae8e442SValentin Clement #include "mlir/IR/Matchers.h"
54044d5b5dSValentin Clement #include "mlir/Pass/Pass.h"
55bac3aedaSSlava Zakharin #include "mlir/Pass/PassManager.h"
56abeb6c9fSagozillon #include "mlir/Target/LLVMIR/Import.h"
57853e79d8SValentin Clement #include "mlir/Target/LLVMIR/ModuleTranslation.h"
58044d5b5dSValentin Clement #include "llvm/ADT/ArrayRef.h"
59dfcc0a70SValentin Clement #include "llvm/ADT/TypeSwitch.h"
60044d5b5dSValentin Clement 
6167d0d7acSMichele Scuttari namespace fir {
6267d0d7acSMichele Scuttari #define GEN_PASS_DEF_FIRTOLLVMLOWERING
6367d0d7acSMichele Scuttari #include "flang/Optimizer/CodeGen/CGPasses.h.inc"
6467d0d7acSMichele Scuttari } // namespace fir
6567d0d7acSMichele Scuttari 
66044d5b5dSValentin Clement #define DEBUG_TYPE "flang-codegen"
67044d5b5dSValentin Clement 
68af6ee580SValentin Clement // TODO: This should really be recovered from the specified target.
69af6ee580SValentin Clement static constexpr unsigned defaultAlign = 8;
70af6ee580SValentin Clement 
71b6e44ecdSValentin Clement /// `fir.box` attribute values as defined for CFI_attribute_t in
72b6e44ecdSValentin Clement /// flang/ISO_Fortran_binding.h.
73b6e44ecdSValentin Clement static constexpr unsigned kAttrPointer = CFI_attribute_pointer;
74b6e44ecdSValentin Clement static constexpr unsigned kAttrAllocatable = CFI_attribute_allocatable;
75b6e44ecdSValentin Clement 
76abeb6c9fSagozillon static inline mlir::Type getLlvmPtrType(mlir::MLIRContext *context,
77abeb6c9fSagozillon                                         unsigned addressSpace = 0) {
78abeb6c9fSagozillon   return mlir::LLVM::LLVMPointerType::get(context, addressSpace);
798a1ce2d6SjeanPerier }
808a1ce2d6SjeanPerier 
818a1ce2d6SjeanPerier static inline mlir::Type getI8Type(mlir::MLIRContext *context) {
828a1ce2d6SjeanPerier   return mlir::IntegerType::get(context, 8);
83fa517555SKiran Chandramohan }
84fa517555SKiran Chandramohan 
851e6d9c06SDiana Picus static mlir::LLVM::ConstantOp
861e6d9c06SDiana Picus genConstantIndex(mlir::Location loc, mlir::Type ity,
871e6d9c06SDiana Picus                  mlir::ConversionPatternRewriter &rewriter,
881e6d9c06SDiana Picus                  std::int64_t offset) {
8965923012SJeff Niu   auto cattr = rewriter.getI64IntegerAttr(offset);
9065923012SJeff Niu   return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr);
911e6d9c06SDiana Picus }
921e6d9c06SDiana Picus 
9344e58509SEric Schweitz static mlir::Block *createBlock(mlir::ConversionPatternRewriter &rewriter,
9439f4ef81SValentin Clement                                 mlir::Block *insertBefore) {
9539f4ef81SValentin Clement   assert(insertBefore && "expected valid insertion block");
9639f4ef81SValentin Clement   return rewriter.createBlock(insertBefore->getParent(),
9739f4ef81SValentin Clement                               mlir::Region::iterator(insertBefore));
9839f4ef81SValentin Clement }
9939f4ef81SValentin Clement 
100f9e995b4SSlava Zakharin /// Extract constant from a value that must be the result of one of the
101f9e995b4SSlava Zakharin /// ConstantOp operations.
102f9e995b4SSlava Zakharin static int64_t getConstantIntValue(mlir::Value val) {
103a5ae54abSTom Eccles   if (auto constVal = fir::getIntIfConstant(val))
104f9e995b4SSlava Zakharin     return *constVal;
105af40f99eSJean Perier   fir::emitFatalError(val.getLoc(), "must be a constant");
106af40f99eSJean Perier }
107af40f99eSJean Perier 
108016fbc40SValentin Clement static unsigned getTypeDescFieldId(mlir::Type ty) {
109fac349a1SChristian Sigg   auto isArray = mlir::isa<fir::SequenceType>(fir::dyn_cast_ptrOrBoxEleTy(ty));
110016fbc40SValentin Clement   return isArray ? kOptTypePtrPosInBox : kDimsPosInBox;
111016fbc40SValentin Clement }
112d26a6464SjeanPerier static unsigned getLenParamFieldId(mlir::Type ty) {
113d26a6464SjeanPerier   return getTypeDescFieldId(ty) + 1;
114d26a6464SjeanPerier }
115016fbc40SValentin Clement 
116fde3c16aSSirui Mu static llvm::SmallVector<mlir::NamedAttribute>
117fde3c16aSSirui Mu addLLVMOpBundleAttrs(mlir::ConversionPatternRewriter &rewriter,
118fde3c16aSSirui Mu                      llvm::ArrayRef<mlir::NamedAttribute> attrs,
119fde3c16aSSirui Mu                      int32_t numCallOperands) {
120fde3c16aSSirui Mu   llvm::SmallVector<mlir::NamedAttribute> newAttrs;
121fde3c16aSSirui Mu   newAttrs.reserve(attrs.size() + 2);
122fde3c16aSSirui Mu 
123fde3c16aSSirui Mu   for (mlir::NamedAttribute attr : attrs) {
124fde3c16aSSirui Mu     if (attr.getName() != "operandSegmentSizes")
125fde3c16aSSirui Mu       newAttrs.push_back(attr);
126fde3c16aSSirui Mu   }
127fde3c16aSSirui Mu 
128fde3c16aSSirui Mu   newAttrs.push_back(rewriter.getNamedAttr(
129fde3c16aSSirui Mu       "operandSegmentSizes",
130fde3c16aSSirui Mu       rewriter.getDenseI32ArrayAttr({numCallOperands, 0})));
131fde3c16aSSirui Mu   newAttrs.push_back(rewriter.getNamedAttr("op_bundle_sizes",
132fde3c16aSSirui Mu                                            rewriter.getDenseI32ArrayAttr({})));
133fde3c16aSSirui Mu   return newAttrs;
134fde3c16aSSirui Mu }
135fde3c16aSSirui Mu 
136044d5b5dSValentin Clement namespace {
137575c9d6dSValentin Clement /// Lower `fir.address_of` operation to `llvm.address_of` operation.
138e9639e9cSValentin Clement (バレンタイン クレメン) struct AddrOfOpConversion : public fir::FIROpConversion<fir::AddrOfOp> {
139044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
140044d5b5dSValentin Clement 
141db791b27SRamkumar Ramachandra   llvm::LogicalResult
142044d5b5dSValentin Clement   matchAndRewrite(fir::AddrOfOp addr, OpAdaptor adaptor,
143044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
144044d5b5dSValentin Clement     auto ty = convertType(addr.getType());
145044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::AddressOfOp>(
146149ad3d5SShraiysh Vaishay         addr, ty, addr.getSymbol().getRootReference().getValue());
14744e58509SEric Schweitz     return mlir::success();
148044d5b5dSValentin Clement   }
149044d5b5dSValentin Clement };
1501e6d9c06SDiana Picus } // namespace
1511e6d9c06SDiana Picus 
1521e6d9c06SDiana Picus /// Lookup the function to compute the memory size of this parametric derived
1531e6d9c06SDiana Picus /// type. The size of the object may depend on the LEN type parameters of the
1541e6d9c06SDiana Picus /// derived type.
1551e6d9c06SDiana Picus static mlir::LLVM::LLVMFuncOp
1561e6d9c06SDiana Picus getDependentTypeMemSizeFn(fir::RecordType recTy, fir::AllocaOp op,
1571e6d9c06SDiana Picus                           mlir::ConversionPatternRewriter &rewriter) {
1581e6d9c06SDiana Picus   auto module = op->getParentOfType<mlir::ModuleOp>();
1591e6d9c06SDiana Picus   std::string name = recTy.getName().str() + "P.mem.size";
160575c9d6dSValentin Clement   if (auto memSizeFunc = module.lookupSymbol<mlir::LLVM::LLVMFuncOp>(name))
161575c9d6dSValentin Clement     return memSizeFunc;
162575c9d6dSValentin Clement   TODO(op.getLoc(), "did not find allocation function");
1631e6d9c06SDiana Picus }
1641e6d9c06SDiana Picus 
165ac0f4c8fSPeixinQiao // Compute the alloc scale size (constant factors encoded in the array type).
166ac0f4c8fSPeixinQiao // We do this for arrays without a constant interior or arrays of character with
167ac0f4c8fSPeixinQiao // dynamic length arrays, since those are the only ones that get decayed to a
168ac0f4c8fSPeixinQiao // pointer to the element type.
169ac0f4c8fSPeixinQiao template <typename OP>
170ac0f4c8fSPeixinQiao static mlir::Value
171ac0f4c8fSPeixinQiao genAllocationScaleSize(OP op, mlir::Type ity,
172ac0f4c8fSPeixinQiao                        mlir::ConversionPatternRewriter &rewriter) {
173ac0f4c8fSPeixinQiao   mlir::Location loc = op.getLoc();
174ac0f4c8fSPeixinQiao   mlir::Type dataTy = op.getInType();
175fac349a1SChristian Sigg   auto seqTy = mlir::dyn_cast<fir::SequenceType>(dataTy);
176ac0f4c8fSPeixinQiao   fir::SequenceType::Extent constSize = 1;
1777ae39114SMats Petersson   if (seqTy) {
1787ae39114SMats Petersson     int constRows = seqTy.getConstantRows();
1797ae39114SMats Petersson     const fir::SequenceType::ShapeRef &shape = seqTy.getShape();
1807ae39114SMats Petersson     if (constRows != static_cast<int>(shape.size())) {
1817ae39114SMats Petersson       for (auto extent : shape) {
1827ae39114SMats Petersson         if (constRows-- > 0)
1837ae39114SMats Petersson           continue;
184ac0f4c8fSPeixinQiao         if (extent != fir::SequenceType::getUnknownExtent())
185ac0f4c8fSPeixinQiao           constSize *= extent;
1867ae39114SMats Petersson       }
1877ae39114SMats Petersson     }
1887ae39114SMats Petersson   }
1897ae39114SMats Petersson 
190ac0f4c8fSPeixinQiao   if (constSize != 1) {
191ac0f4c8fSPeixinQiao     mlir::Value constVal{
192ac0f4c8fSPeixinQiao         genConstantIndex(loc, ity, rewriter, constSize).getResult()};
193ac0f4c8fSPeixinQiao     return constVal;
194ac0f4c8fSPeixinQiao   }
195ac0f4c8fSPeixinQiao   return nullptr;
196ac0f4c8fSPeixinQiao }
197ac0f4c8fSPeixinQiao 
1981e6d9c06SDiana Picus namespace {
199cd5ee271SAbid Qadeer struct DeclareOpConversion : public fir::FIROpConversion<fir::cg::XDeclareOp> {
200cd5ee271SAbid Qadeer public:
201cd5ee271SAbid Qadeer   using FIROpConversion::FIROpConversion;
202db791b27SRamkumar Ramachandra   llvm::LogicalResult
203cd5ee271SAbid Qadeer   matchAndRewrite(fir::cg::XDeclareOp declareOp, OpAdaptor adaptor,
204cd5ee271SAbid Qadeer                   mlir::ConversionPatternRewriter &rewriter) const override {
205cd5ee271SAbid Qadeer     auto memRef = adaptor.getOperands()[0];
206cd5ee271SAbid Qadeer     if (auto fusedLoc = mlir::dyn_cast<mlir::FusedLoc>(declareOp.getLoc())) {
207cd5ee271SAbid Qadeer       if (auto varAttr =
208cd5ee271SAbid Qadeer               mlir::dyn_cast_or_null<mlir::LLVM::DILocalVariableAttr>(
209cd5ee271SAbid Qadeer                   fusedLoc.getMetadata())) {
210cd5ee271SAbid Qadeer         rewriter.create<mlir::LLVM::DbgDeclareOp>(memRef.getLoc(), memRef,
211cd5ee271SAbid Qadeer                                                   varAttr, nullptr);
212cd5ee271SAbid Qadeer       }
213cd5ee271SAbid Qadeer     }
214cd5ee271SAbid Qadeer     rewriter.replaceOp(declareOp, memRef);
215cd5ee271SAbid Qadeer     return mlir::success();
216cd5ee271SAbid Qadeer   }
217cd5ee271SAbid Qadeer };
218cd5ee271SAbid Qadeer } // namespace
219cd5ee271SAbid Qadeer 
220cd5ee271SAbid Qadeer namespace {
2211e6d9c06SDiana Picus /// convert to LLVM IR dialect `alloca`
222e9639e9cSValentin Clement (バレンタイン クレメン) struct AllocaOpConversion : public fir::FIROpConversion<fir::AllocaOp> {
2231e6d9c06SDiana Picus   using FIROpConversion::FIROpConversion;
2241e6d9c06SDiana Picus 
225db791b27SRamkumar Ramachandra   llvm::LogicalResult
2261e6d9c06SDiana Picus   matchAndRewrite(fir::AllocaOp alloc, OpAdaptor adaptor,
2271e6d9c06SDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
2281e6d9c06SDiana Picus     mlir::ValueRange operands = adaptor.getOperands();
2291e6d9c06SDiana Picus     auto loc = alloc.getLoc();
2301e6d9c06SDiana Picus     mlir::Type ity = lowerTy().indexType();
2311e6d9c06SDiana Picus     unsigned i = 0;
2321e6d9c06SDiana Picus     mlir::Value size = genConstantIndex(loc, ity, rewriter, 1).getResult();
2338a1ce2d6SjeanPerier     mlir::Type firObjType = fir::unwrapRefType(alloc.getType());
2348a1ce2d6SjeanPerier     mlir::Type llvmObjectType = convertObjectType(firObjType);
2351e6d9c06SDiana Picus     if (alloc.hasLenParams()) {
2361e6d9c06SDiana Picus       unsigned end = alloc.numLenParams();
2371e6d9c06SDiana Picus       llvm::SmallVector<mlir::Value> lenParams;
2381e6d9c06SDiana Picus       for (; i < end; ++i)
2391e6d9c06SDiana Picus         lenParams.push_back(operands[i]);
2401e6d9c06SDiana Picus       mlir::Type scalarType = fir::unwrapSequenceType(alloc.getInType());
241fac349a1SChristian Sigg       if (auto chrTy = mlir::dyn_cast<fir::CharacterType>(scalarType)) {
2421e6d9c06SDiana Picus         fir::CharacterType rawCharTy = fir::CharacterType::getUnknownLen(
2431e6d9c06SDiana Picus             chrTy.getContext(), chrTy.getFKind());
2448a1ce2d6SjeanPerier         llvmObjectType = convertType(rawCharTy);
2451e6d9c06SDiana Picus         assert(end == 1);
246c0cba519SVijay Kandiah         size = integerCast(loc, rewriter, ity, lenParams[0], /*fold=*/true);
247fac349a1SChristian Sigg       } else if (auto recTy = mlir::dyn_cast<fir::RecordType>(scalarType)) {
2481e6d9c06SDiana Picus         mlir::LLVM::LLVMFuncOp memSizeFn =
2491e6d9c06SDiana Picus             getDependentTypeMemSizeFn(recTy, alloc, rewriter);
2501e6d9c06SDiana Picus         if (!memSizeFn)
2511e6d9c06SDiana Picus           emitError(loc, "did not find allocation function");
2521e6d9c06SDiana Picus         mlir::NamedAttribute attr = rewriter.getNamedAttr(
2531e6d9c06SDiana Picus             "callee", mlir::SymbolRefAttr::get(memSizeFn));
2541e6d9c06SDiana Picus         auto call = rewriter.create<mlir::LLVM::CallOp>(
255fde3c16aSSirui Mu             loc, ity, lenParams,
256fde3c16aSSirui Mu             addLLVMOpBundleAttrs(rewriter, {attr}, lenParams.size()));
2574e0a2bd6SJeff Niu         size = call.getResult();
2588a1ce2d6SjeanPerier         llvmObjectType = ::getI8Type(alloc.getContext());
2591e6d9c06SDiana Picus       } else {
2601e6d9c06SDiana Picus         return emitError(loc, "unexpected type ")
2611e6d9c06SDiana Picus                << scalarType << " with type parameters";
2621e6d9c06SDiana Picus       }
2631e6d9c06SDiana Picus     }
264ac0f4c8fSPeixinQiao     if (auto scaleSize = genAllocationScaleSize(alloc, ity, rewriter))
265c0cba519SVijay Kandiah       size =
266c0cba519SVijay Kandiah           rewriter.createOrFold<mlir::LLVM::MulOp>(loc, ity, size, scaleSize);
2671e6d9c06SDiana Picus     if (alloc.hasShapeOperands()) {
2681e6d9c06SDiana Picus       unsigned end = operands.size();
2691e6d9c06SDiana Picus       for (; i < end; ++i)
270c0cba519SVijay Kandiah         size = rewriter.createOrFold<mlir::LLVM::MulOp>(
271c0cba519SVijay Kandiah             loc, ity, size,
272c0cba519SVijay Kandiah             integerCast(loc, rewriter, ity, operands[i], /*fold=*/true));
2731e6d9c06SDiana Picus     }
274abeb6c9fSagozillon 
275abeb6c9fSagozillon     unsigned allocaAs = getAllocaAddressSpace(rewriter);
276abeb6c9fSagozillon     unsigned programAs = getProgramAddressSpace(rewriter);
277abeb6c9fSagozillon 
278c0cba519SVijay Kandiah     if (mlir::isa<mlir::LLVM::ConstantOp>(size.getDefiningOp())) {
279c0cba519SVijay Kandiah       // Set the Block in which the llvm alloca should be inserted.
280c0cba519SVijay Kandiah       mlir::Operation *parentOp = rewriter.getInsertionBlock()->getParentOp();
281c0cba519SVijay Kandiah       mlir::Region *parentRegion = rewriter.getInsertionBlock()->getParent();
282c0cba519SVijay Kandiah       mlir::Block *insertBlock =
283c0cba519SVijay Kandiah           getBlockForAllocaInsert(parentOp, parentRegion);
284e9fc2fafSTom Eccles 
285e9fc2fafSTom Eccles       // The old size might have had multiple users, some at a broader scope
286e9fc2fafSTom Eccles       // than we can safely outline the alloca to. As it is only an
287e9fc2fafSTom Eccles       // llvm.constant operation, it is faster to clone it than to calculate the
288e9fc2fafSTom Eccles       // dominance to see if it really should be moved.
289e9fc2fafSTom Eccles       mlir::Operation *clonedSize = rewriter.clone(*size.getDefiningOp());
290e9fc2fafSTom Eccles       size = clonedSize->getResult(0);
291e9fc2fafSTom Eccles       clonedSize->moveBefore(&insertBlock->front());
292c0cba519SVijay Kandiah       rewriter.setInsertionPointAfter(size.getDefiningOp());
293c0cba519SVijay Kandiah     }
294c0cba519SVijay Kandiah 
2958a1ce2d6SjeanPerier     // NOTE: we used to pass alloc->getAttrs() in the builder for non opaque
2968a1ce2d6SjeanPerier     // pointers! Only propagate pinned and bindc_name to help debugging, but
2978a1ce2d6SjeanPerier     // this should have no functional purpose (and passing the operand segment
2988a1ce2d6SjeanPerier     // attribute like before is certainly bad).
2998a1ce2d6SjeanPerier     auto llvmAlloc = rewriter.create<mlir::LLVM::AllocaOp>(
300abeb6c9fSagozillon         loc, ::getLlvmPtrType(alloc.getContext(), allocaAs), llvmObjectType,
301abeb6c9fSagozillon         size);
3028a1ce2d6SjeanPerier     if (alloc.getPinned())
3038a1ce2d6SjeanPerier       llvmAlloc->setDiscardableAttr(alloc.getPinnedAttrName(),
3048a1ce2d6SjeanPerier                                     alloc.getPinnedAttr());
3058a1ce2d6SjeanPerier     if (alloc.getBindcName())
3068a1ce2d6SjeanPerier       llvmAlloc->setDiscardableAttr(alloc.getBindcNameAttrName(),
3078a1ce2d6SjeanPerier                                     alloc.getBindcNameAttr());
308abeb6c9fSagozillon     if (allocaAs == programAs) {
3098a1ce2d6SjeanPerier       rewriter.replaceOp(alloc, llvmAlloc);
310abeb6c9fSagozillon     } else {
311abeb6c9fSagozillon       // if our allocation address space, is not the same as the program address
312abeb6c9fSagozillon       // space, then we must emit a cast to the program address space before
313abeb6c9fSagozillon       // use. An example case would be on AMDGPU, where the allocation address
314abeb6c9fSagozillon       // space is the numeric value 5 (private), and the program address space
315abeb6c9fSagozillon       // is 0 (generic).
316abeb6c9fSagozillon       rewriter.replaceOpWithNewOp<mlir::LLVM::AddrSpaceCastOp>(
317abeb6c9fSagozillon           alloc, ::getLlvmPtrType(alloc.getContext(), programAs), llvmAlloc);
318abeb6c9fSagozillon     }
31944e58509SEric Schweitz     return mlir::success();
3201e6d9c06SDiana Picus   }
3211e6d9c06SDiana Picus };
322dc48849fSKiran Chandramohan } // namespace
323044d5b5dSValentin Clement 
324dc48849fSKiran Chandramohan namespace {
325df3b9810SValentin Clement /// Lower `fir.box_addr` to the sequence of operations to extract the first
326df3b9810SValentin Clement /// element of the box.
327e9639e9cSValentin Clement (バレンタイン クレメン) struct BoxAddrOpConversion : public fir::FIROpConversion<fir::BoxAddrOp> {
328df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
329df3b9810SValentin Clement 
330db791b27SRamkumar Ramachandra   llvm::LogicalResult
331df3b9810SValentin Clement   matchAndRewrite(fir::BoxAddrOp boxaddr, OpAdaptor adaptor,
332df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
333df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
334df3b9810SValentin Clement     auto loc = boxaddr.getLoc();
335fac349a1SChristian Sigg     if (auto argty =
336fac349a1SChristian Sigg             mlir::dyn_cast<fir::BaseBoxType>(boxaddr.getVal().getType())) {
3378a1ce2d6SjeanPerier       TypePair boxTyPair = getBoxTypePair(argty);
3389c84d20fSSlava Zakharin       rewriter.replaceOp(boxaddr,
3398a1ce2d6SjeanPerier                          getBaseAddrFromBox(loc, boxTyPair, a, rewriter));
340df3b9810SValentin Clement     } else {
3415c5af910SJeff Niu       rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(boxaddr, a, 0);
342df3b9810SValentin Clement     }
34344e58509SEric Schweitz     return mlir::success();
344df3b9810SValentin Clement   }
345df3b9810SValentin Clement };
346df3b9810SValentin Clement 
347dc48849fSKiran Chandramohan /// Convert `!fir.boxchar_len` to  `!llvm.extractvalue` for the 2nd part of the
348dc48849fSKiran Chandramohan /// boxchar.
349e9639e9cSValentin Clement (バレンタイン クレメン) struct BoxCharLenOpConversion : public fir::FIROpConversion<fir::BoxCharLenOp> {
350dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
351dc48849fSKiran Chandramohan 
352db791b27SRamkumar Ramachandra   llvm::LogicalResult
353dc48849fSKiran Chandramohan   matchAndRewrite(fir::BoxCharLenOp boxCharLen, OpAdaptor adaptor,
354dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
355dc48849fSKiran Chandramohan     mlir::Value boxChar = adaptor.getOperands()[0];
356dc48849fSKiran Chandramohan     mlir::Location loc = boxChar.getLoc();
357dc48849fSKiran Chandramohan     mlir::Type returnValTy = boxCharLen.getResult().getType();
358dc48849fSKiran Chandramohan 
359dc48849fSKiran Chandramohan     constexpr int boxcharLenIdx = 1;
3605c5af910SJeff Niu     auto len = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, boxChar,
3615c5af910SJeff Niu                                                            boxcharLenIdx);
362dc48849fSKiran Chandramohan     mlir::Value lenAfterCast = integerCast(loc, rewriter, returnValTy, len);
363dc48849fSKiran Chandramohan     rewriter.replaceOp(boxCharLen, lenAfterCast);
364dc48849fSKiran Chandramohan 
36544e58509SEric Schweitz     return mlir::success();
366dc48849fSKiran Chandramohan   }
367dc48849fSKiran Chandramohan };
368dc48849fSKiran Chandramohan 
369df3b9810SValentin Clement /// Lower `fir.box_dims` to a sequence of operations to extract the requested
3709c84d20fSSlava Zakharin /// dimension information from the boxed value.
371df3b9810SValentin Clement /// Result in a triple set of GEPs and loads.
372e9639e9cSValentin Clement (バレンタイン クレメン) struct BoxDimsOpConversion : public fir::FIROpConversion<fir::BoxDimsOp> {
373df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
374df3b9810SValentin Clement 
375db791b27SRamkumar Ramachandra   llvm::LogicalResult
376df3b9810SValentin Clement   matchAndRewrite(fir::BoxDimsOp boxdims, OpAdaptor adaptor,
377df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
37844e58509SEric Schweitz     llvm::SmallVector<mlir::Type, 3> resultTypes = {
379df3b9810SValentin Clement         convertType(boxdims.getResult(0).getType()),
380df3b9810SValentin Clement         convertType(boxdims.getResult(1).getType()),
381df3b9810SValentin Clement         convertType(boxdims.getResult(2).getType()),
382df3b9810SValentin Clement     };
3838a1ce2d6SjeanPerier     TypePair boxTyPair = getBoxTypePair(boxdims.getVal().getType());
3848a1ce2d6SjeanPerier     auto results = getDimsFromBox(boxdims.getLoc(), resultTypes, boxTyPair,
3858a1ce2d6SjeanPerier                                   adaptor.getOperands()[0],
3868a1ce2d6SjeanPerier                                   adaptor.getOperands()[1], rewriter);
387df3b9810SValentin Clement     rewriter.replaceOp(boxdims, results);
38844e58509SEric Schweitz     return mlir::success();
389df3b9810SValentin Clement   }
390df3b9810SValentin Clement };
391df3b9810SValentin Clement 
392df3b9810SValentin Clement /// Lower `fir.box_elesize` to a sequence of operations ro extract the size of
393df3b9810SValentin Clement /// an element in the boxed value.
394e9639e9cSValentin Clement (バレンタイン クレメン) struct BoxEleSizeOpConversion : public fir::FIROpConversion<fir::BoxEleSizeOp> {
395df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
396df3b9810SValentin Clement 
397db791b27SRamkumar Ramachandra   llvm::LogicalResult
398df3b9810SValentin Clement   matchAndRewrite(fir::BoxEleSizeOp boxelesz, OpAdaptor adaptor,
399df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
4009c84d20fSSlava Zakharin     mlir::Value box = adaptor.getOperands()[0];
401df3b9810SValentin Clement     auto loc = boxelesz.getLoc();
402df3b9810SValentin Clement     auto ty = convertType(boxelesz.getType());
4038a1ce2d6SjeanPerier     TypePair boxTyPair = getBoxTypePair(boxelesz.getVal().getType());
4048a1ce2d6SjeanPerier     auto elemSize = getElementSizeFromBox(loc, ty, boxTyPair, box, rewriter);
405b6e44ecdSValentin Clement     rewriter.replaceOp(boxelesz, elemSize);
40644e58509SEric Schweitz     return mlir::success();
407b6e44ecdSValentin Clement   }
408b6e44ecdSValentin Clement };
409b6e44ecdSValentin Clement 
410b6e44ecdSValentin Clement /// Lower `fir.box_isalloc` to a sequence of operations to determine if the
411b6e44ecdSValentin Clement /// boxed value was from an ALLOCATABLE entity.
412e9639e9cSValentin Clement (バレンタイン クレメン) struct BoxIsAllocOpConversion : public fir::FIROpConversion<fir::BoxIsAllocOp> {
413b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
414b6e44ecdSValentin Clement 
415db791b27SRamkumar Ramachandra   llvm::LogicalResult
416b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsAllocOp boxisalloc, OpAdaptor adaptor,
417b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
418b6e44ecdSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
419b6e44ecdSValentin Clement     auto loc = boxisalloc.getLoc();
4208a1ce2d6SjeanPerier     TypePair boxTyPair = getBoxTypePair(boxisalloc.getVal().getType());
4218a1ce2d6SjeanPerier     mlir::Value check =
4228a1ce2d6SjeanPerier         genBoxAttributeCheck(loc, boxTyPair, box, rewriter, kAttrAllocatable);
423b6e44ecdSValentin Clement     rewriter.replaceOp(boxisalloc, check);
42444e58509SEric Schweitz     return mlir::success();
425b6e44ecdSValentin Clement   }
426b6e44ecdSValentin Clement };
427b6e44ecdSValentin Clement 
428b6e44ecdSValentin Clement /// Lower `fir.box_isarray` to a sequence of operations to determine if the
429b6e44ecdSValentin Clement /// boxed is an array.
430e9639e9cSValentin Clement (バレンタイン クレメン) struct BoxIsArrayOpConversion : public fir::FIROpConversion<fir::BoxIsArrayOp> {
431b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
432b6e44ecdSValentin Clement 
433db791b27SRamkumar Ramachandra   llvm::LogicalResult
434b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsArrayOp boxisarray, OpAdaptor adaptor,
435b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
436b6e44ecdSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
437b6e44ecdSValentin Clement     auto loc = boxisarray.getLoc();
4388a1ce2d6SjeanPerier     TypePair boxTyPair = getBoxTypePair(boxisarray.getVal().getType());
43926e0ce0bSjeanPerier     mlir::Value rank = getRankFromBox(loc, boxTyPair, a, rewriter);
44026e0ce0bSjeanPerier     mlir::Value c0 = genConstantIndex(loc, rank.getType(), rewriter, 0);
441b6e44ecdSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
442b6e44ecdSValentin Clement         boxisarray, mlir::LLVM::ICmpPredicate::ne, rank, c0);
44344e58509SEric Schweitz     return mlir::success();
444b6e44ecdSValentin Clement   }
445b6e44ecdSValentin Clement };
446b6e44ecdSValentin Clement 
447b6e44ecdSValentin Clement /// Lower `fir.box_isptr` to a sequence of operations to determined if the
448b6e44ecdSValentin Clement /// boxed value was from a POINTER entity.
449e9639e9cSValentin Clement (バレンタイン クレメン) struct BoxIsPtrOpConversion : public fir::FIROpConversion<fir::BoxIsPtrOp> {
450b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
451b6e44ecdSValentin Clement 
452db791b27SRamkumar Ramachandra   llvm::LogicalResult
453b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsPtrOp boxisptr, OpAdaptor adaptor,
454b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
455b6e44ecdSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
456b6e44ecdSValentin Clement     auto loc = boxisptr.getLoc();
4578a1ce2d6SjeanPerier     TypePair boxTyPair = getBoxTypePair(boxisptr.getVal().getType());
4588a1ce2d6SjeanPerier     mlir::Value check =
4598a1ce2d6SjeanPerier         genBoxAttributeCheck(loc, boxTyPair, box, rewriter, kAttrPointer);
460b6e44ecdSValentin Clement     rewriter.replaceOp(boxisptr, check);
46144e58509SEric Schweitz     return mlir::success();
462df3b9810SValentin Clement   }
463df3b9810SValentin Clement };
464df3b9810SValentin Clement 
465df3b9810SValentin Clement /// Lower `fir.box_rank` to the sequence of operation to extract the rank from
466df3b9810SValentin Clement /// the box.
467e9639e9cSValentin Clement (バレンタイン クレメン) struct BoxRankOpConversion : public fir::FIROpConversion<fir::BoxRankOp> {
468df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
469df3b9810SValentin Clement 
470db791b27SRamkumar Ramachandra   llvm::LogicalResult
471df3b9810SValentin Clement   matchAndRewrite(fir::BoxRankOp boxrank, OpAdaptor adaptor,
472df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
473df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
474df3b9810SValentin Clement     auto loc = boxrank.getLoc();
475df3b9810SValentin Clement     mlir::Type ty = convertType(boxrank.getType());
476fd8b2d20SjeanPerier     TypePair boxTyPair =
477fd8b2d20SjeanPerier         getBoxTypePair(fir::unwrapRefType(boxrank.getBox().getType()));
47826e0ce0bSjeanPerier     mlir::Value rank = getRankFromBox(loc, boxTyPair, a, rewriter);
47926e0ce0bSjeanPerier     mlir::Value result = integerCast(loc, rewriter, ty, rank);
480df3b9810SValentin Clement     rewriter.replaceOp(boxrank, result);
48144e58509SEric Schweitz     return mlir::success();
482df3b9810SValentin Clement   }
483df3b9810SValentin Clement };
484df3b9810SValentin Clement 
485cc505c0bSKiran Chandramohan /// Lower `fir.boxproc_host` operation. Extracts the host pointer from the
486cc505c0bSKiran Chandramohan /// boxproc.
487cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
488e9639e9cSValentin Clement (バレンタイン クレメン) struct BoxProcHostOpConversion
489e9639e9cSValentin Clement (バレンタイン クレメン)     : public fir::FIROpConversion<fir::BoxProcHostOp> {
490cc505c0bSKiran Chandramohan   using FIROpConversion::FIROpConversion;
491cc505c0bSKiran Chandramohan 
492db791b27SRamkumar Ramachandra   llvm::LogicalResult
493cc505c0bSKiran Chandramohan   matchAndRewrite(fir::BoxProcHostOp boxprochost, OpAdaptor adaptor,
494cc505c0bSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
4957ce8c6fcSKiran Chandramohan     TODO(boxprochost.getLoc(), "fir.boxproc_host codegen");
49644e58509SEric Schweitz     return mlir::failure();
497cc505c0bSKiran Chandramohan   }
498cc505c0bSKiran Chandramohan };
499cc505c0bSKiran Chandramohan 
500e38ef2ffSValentin Clement /// Lower `fir.box_tdesc` to the sequence of operations to extract the type
501e38ef2ffSValentin Clement /// descriptor from the box.
502e9639e9cSValentin Clement (バレンタイン クレメン) struct BoxTypeDescOpConversion
503e9639e9cSValentin Clement (バレンタイン クレメン)     : public fir::FIROpConversion<fir::BoxTypeDescOp> {
504e38ef2ffSValentin Clement   using FIROpConversion::FIROpConversion;
505e38ef2ffSValentin Clement 
506db791b27SRamkumar Ramachandra   llvm::LogicalResult
507e38ef2ffSValentin Clement   matchAndRewrite(fir::BoxTypeDescOp boxtypedesc, OpAdaptor adaptor,
508e38ef2ffSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
509e38ef2ffSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
5108a1ce2d6SjeanPerier     TypePair boxTyPair = getBoxTypePair(boxtypedesc.getBox().getType());
5118a1ce2d6SjeanPerier     auto typeDescAddr =
5128a1ce2d6SjeanPerier         loadTypeDescAddress(boxtypedesc.getLoc(), boxTyPair, box, rewriter);
5132e978986SValentin Clement     rewriter.replaceOp(boxtypedesc, typeDescAddr);
51444e58509SEric Schweitz     return mlir::success();
515e38ef2ffSValentin Clement   }
516e38ef2ffSValentin Clement };
517e38ef2ffSValentin Clement 
51849ee5634SValentin Clement /// Lower `fir.box_typecode` to a sequence of operations to extract the type
51949ee5634SValentin Clement /// code in the boxed value.
520e9639e9cSValentin Clement (バレンタイン クレメン) struct BoxTypeCodeOpConversion
521e9639e9cSValentin Clement (バレンタイン クレメン)     : public fir::FIROpConversion<fir::BoxTypeCodeOp> {
52249ee5634SValentin Clement   using FIROpConversion::FIROpConversion;
52349ee5634SValentin Clement 
524db791b27SRamkumar Ramachandra   llvm::LogicalResult
52549ee5634SValentin Clement   matchAndRewrite(fir::BoxTypeCodeOp op, OpAdaptor adaptor,
52649ee5634SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
52749ee5634SValentin Clement     mlir::Value box = adaptor.getOperands()[0];
52849ee5634SValentin Clement     auto loc = box.getLoc();
52949ee5634SValentin Clement     auto ty = convertType(op.getType());
5308a1ce2d6SjeanPerier     TypePair boxTyPair = getBoxTypePair(op.getBox().getType());
5318a1ce2d6SjeanPerier     auto typeCode =
5328a1ce2d6SjeanPerier         getValueFromBox(loc, boxTyPair, box, ty, rewriter, kTypePosInBox);
53349ee5634SValentin Clement     rewriter.replaceOp(op, typeCode);
53449ee5634SValentin Clement     return mlir::success();
53549ee5634SValentin Clement   }
53649ee5634SValentin Clement };
53749ee5634SValentin Clement 
538dc48849fSKiran Chandramohan /// Lower `fir.string_lit` to LLVM IR dialect operation.
539e9639e9cSValentin Clement (バレンタイン クレメン) struct StringLitOpConversion : public fir::FIROpConversion<fir::StringLitOp> {
540dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
541dc48849fSKiran Chandramohan 
542db791b27SRamkumar Ramachandra   llvm::LogicalResult
543dc48849fSKiran Chandramohan   matchAndRewrite(fir::StringLitOp constop, OpAdaptor adaptor,
544dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
545dc48849fSKiran Chandramohan     auto ty = convertType(constop.getType());
546dc48849fSKiran Chandramohan     auto attr = constop.getValue();
547fac349a1SChristian Sigg     if (mlir::isa<mlir::StringAttr>(attr)) {
548dc48849fSKiran Chandramohan       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(constop, ty, attr);
54944e58509SEric Schweitz       return mlir::success();
550dc48849fSKiran Chandramohan     }
551dc48849fSKiran Chandramohan 
552fac349a1SChristian Sigg     auto charTy = mlir::cast<fir::CharacterType>(constop.getType());
553dc48849fSKiran Chandramohan     unsigned bits = lowerTy().characterBitsize(charTy);
554dc48849fSKiran Chandramohan     mlir::Type intTy = rewriter.getIntegerType(bits);
555e0c782bdSValentin Clement     mlir::Location loc = constop.getLoc();
556e0c782bdSValentin Clement     mlir::Value cst = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
557fac349a1SChristian Sigg     if (auto arr = mlir::dyn_cast<mlir::DenseElementsAttr>(attr)) {
558e0c782bdSValentin Clement       cst = rewriter.create<mlir::LLVM::ConstantOp>(loc, ty, arr);
559fac349a1SChristian Sigg     } else if (auto arr = mlir::dyn_cast<mlir::ArrayAttr>(attr)) {
56065923012SJeff Niu       for (auto a : llvm::enumerate(arr.getValue())) {
561e0c782bdSValentin Clement         // convert each character to a precise bitsize
56265923012SJeff Niu         auto elemAttr = mlir::IntegerAttr::get(
56365923012SJeff Niu             intTy,
564fac349a1SChristian Sigg             mlir::cast<mlir::IntegerAttr>(a.value()).getValue().zextOrTrunc(
565fac349a1SChristian Sigg                 bits));
56665923012SJeff Niu         auto elemCst =
56765923012SJeff Niu             rewriter.create<mlir::LLVM::ConstantOp>(loc, intTy, elemAttr);
5685c5af910SJeff Niu         cst = rewriter.create<mlir::LLVM::InsertValueOp>(loc, cst, elemCst,
5695c5af910SJeff Niu                                                          a.index());
570e0c782bdSValentin Clement       }
571e0c782bdSValentin Clement     } else {
57244e58509SEric Schweitz       return mlir::failure();
573e0c782bdSValentin Clement     }
574e0c782bdSValentin Clement     rewriter.replaceOp(constop, cst);
57544e58509SEric Schweitz     return mlir::success();
576dc48849fSKiran Chandramohan   }
577dc48849fSKiran Chandramohan };
578dc48849fSKiran Chandramohan 
579575c9d6dSValentin Clement /// `fir.call` -> `llvm.call`
580e9639e9cSValentin Clement (バレンタイン クレメン) struct CallOpConversion : public fir::FIROpConversion<fir::CallOp> {
581ddd11b9aSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
582ddd11b9aSAndrzej Warzynski 
583db791b27SRamkumar Ramachandra   llvm::LogicalResult
584ddd11b9aSAndrzej Warzynski   matchAndRewrite(fir::CallOp call, OpAdaptor adaptor,
585ddd11b9aSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
58644e58509SEric Schweitz     llvm::SmallVector<mlir::Type> resultTys;
587ddd11b9aSAndrzej Warzynski     for (auto r : call.getResults())
588ddd11b9aSAndrzej Warzynski       resultTys.push_back(convertType(r.getType()));
589bc955caeSSlava Zakharin     // Convert arith::FastMathFlagsAttr to LLVM::FastMathFlagsAttr.
590bc955caeSSlava Zakharin     mlir::arith::AttrConvertFastMathToLLVM<fir::CallOp, mlir::LLVM::CallOp>
591bc955caeSSlava Zakharin         attrConvert(call);
592ddd11b9aSAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
593fde3c16aSSirui Mu         call, resultTys, adaptor.getOperands(),
594fde3c16aSSirui Mu         addLLVMOpBundleAttrs(rewriter, attrConvert.getAttrs(),
595fde3c16aSSirui Mu                              adaptor.getOperands().size()));
59644e58509SEric Schweitz     return mlir::success();
597ddd11b9aSAndrzej Warzynski   }
598ddd11b9aSAndrzej Warzynski };
599c2acd453SAlexisPerry } // namespace
600ddd11b9aSAndrzej Warzynski 
601092cee5fSValentin Clement static mlir::Type getComplexEleTy(mlir::Type complex) {
6021753de2dSjeanPerier   return mlir::cast<mlir::ComplexType>(complex).getElementType();
603092cee5fSValentin Clement }
604092cee5fSValentin Clement 
605c2acd453SAlexisPerry namespace {
606f1dfc027SDiana Picus /// Compare complex values
607f1dfc027SDiana Picus ///
608f1dfc027SDiana Picus /// Per 10.1, the only comparisons available are .EQ. (oeq) and .NE. (une).
609f1dfc027SDiana Picus ///
610f1dfc027SDiana Picus /// For completeness, all other comparison are done on the real component only.
611e9639e9cSValentin Clement (バレンタイン クレメン) struct CmpcOpConversion : public fir::FIROpConversion<fir::CmpcOp> {
612f1dfc027SDiana Picus   using FIROpConversion::FIROpConversion;
613f1dfc027SDiana Picus 
614db791b27SRamkumar Ramachandra   llvm::LogicalResult
615f1dfc027SDiana Picus   matchAndRewrite(fir::CmpcOp cmp, OpAdaptor adaptor,
616f1dfc027SDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
617f1dfc027SDiana Picus     mlir::ValueRange operands = adaptor.getOperands();
618f1dfc027SDiana Picus     mlir::Type resTy = convertType(cmp.getType());
619f1dfc027SDiana Picus     mlir::Location loc = cmp.getLoc();
620fcd06d77STom Eccles     mlir::LLVM::FastmathFlags fmf =
621fcd06d77STom Eccles         mlir::arith::convertArithFastMathFlagsToLLVM(cmp.getFastmath());
622fcd06d77STom Eccles     mlir::LLVM::FCmpPredicate pred =
623fcd06d77STom Eccles         static_cast<mlir::LLVM::FCmpPredicate>(cmp.getPredicate());
624fcd06d77STom Eccles     auto rcp = rewriter.create<mlir::LLVM::FCmpOp>(
625fcd06d77STom Eccles         loc, resTy, pred,
6265c5af910SJeff Niu         rewriter.create<mlir::LLVM::ExtractValueOp>(loc, operands[0], 0),
627fcd06d77STom Eccles         rewriter.create<mlir::LLVM::ExtractValueOp>(loc, operands[1], 0), fmf);
628fcd06d77STom Eccles     auto icp = rewriter.create<mlir::LLVM::FCmpOp>(
629fcd06d77STom Eccles         loc, resTy, pred,
6305c5af910SJeff Niu         rewriter.create<mlir::LLVM::ExtractValueOp>(loc, operands[0], 1),
631fcd06d77STom Eccles         rewriter.create<mlir::LLVM::ExtractValueOp>(loc, operands[1], 1), fmf);
632575c9d6dSValentin Clement     llvm::SmallVector<mlir::Value, 2> cp = {rcp, icp};
633f1dfc027SDiana Picus     switch (cmp.getPredicate()) {
634f1dfc027SDiana Picus     case mlir::arith::CmpFPredicate::OEQ: // .EQ.
635f1dfc027SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(cmp, resTy, cp);
636f1dfc027SDiana Picus       break;
637f1dfc027SDiana Picus     case mlir::arith::CmpFPredicate::UNE: // .NE.
638f1dfc027SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(cmp, resTy, cp);
639f1dfc027SDiana Picus       break;
640f1dfc027SDiana Picus     default:
641f1dfc027SDiana Picus       rewriter.replaceOp(cmp, rcp.getResult());
642f1dfc027SDiana Picus       break;
643f1dfc027SDiana Picus     }
64444e58509SEric Schweitz     return mlir::success();
645f1dfc027SDiana Picus   }
646f1dfc027SDiana Picus };
647f1dfc027SDiana Picus 
648092cee5fSValentin Clement /// convert value of from-type to value of to-type
649e9639e9cSValentin Clement (バレンタイン クレメン) struct ConvertOpConversion : public fir::FIROpConversion<fir::ConvertOp> {
650092cee5fSValentin Clement   using FIROpConversion::FIROpConversion;
651092cee5fSValentin Clement 
652092cee5fSValentin Clement   static bool isFloatingPointTy(mlir::Type ty) {
653fac349a1SChristian Sigg     return mlir::isa<mlir::FloatType>(ty);
654092cee5fSValentin Clement   }
655092cee5fSValentin Clement 
656db791b27SRamkumar Ramachandra   llvm::LogicalResult
657092cee5fSValentin Clement   matchAndRewrite(fir::ConvertOp convert, OpAdaptor adaptor,
658092cee5fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
6593b7ec85aSJean Perier     auto fromFirTy = convert.getValue().getType();
6603b7ec85aSJean Perier     auto toFirTy = convert.getRes().getType();
6613b7ec85aSJean Perier     auto fromTy = convertType(fromFirTy);
6623b7ec85aSJean Perier     auto toTy = convertType(toFirTy);
663092cee5fSValentin Clement     mlir::Value op0 = adaptor.getOperands()[0];
664f9e995b4SSlava Zakharin 
665f9e995b4SSlava Zakharin     if (fromFirTy == toFirTy) {
666f9e995b4SSlava Zakharin       rewriter.replaceOp(convert, op0);
667f9e995b4SSlava Zakharin       return mlir::success();
668f9e995b4SSlava Zakharin     }
669f9e995b4SSlava Zakharin 
670f9e995b4SSlava Zakharin     auto loc = convert.getLoc();
671f9e995b4SSlava Zakharin     auto i1Type = mlir::IntegerType::get(convert.getContext(), 1);
672f9e995b4SSlava Zakharin 
673390943f2SLeandro Lupori     if (mlir::isa<fir::RecordType>(toFirTy)) {
674390943f2SLeandro Lupori       // Convert to compatible BIND(C) record type.
675390943f2SLeandro Lupori       // Double check that the record types are compatible (it should have
676390943f2SLeandro Lupori       // already been checked by the verifier).
677390943f2SLeandro Lupori       assert(mlir::cast<fir::RecordType>(fromFirTy).getTypeList() ==
678390943f2SLeandro Lupori                  mlir::cast<fir::RecordType>(toFirTy).getTypeList() &&
679390943f2SLeandro Lupori              "incompatible record types");
680390943f2SLeandro Lupori 
681390943f2SLeandro Lupori       auto toStTy = mlir::cast<mlir::LLVM::LLVMStructType>(toTy);
682390943f2SLeandro Lupori       mlir::Value val = rewriter.create<mlir::LLVM::UndefOp>(loc, toStTy);
683390943f2SLeandro Lupori       auto indexTypeMap = toStTy.getSubelementIndexMap();
684390943f2SLeandro Lupori       assert(indexTypeMap.has_value() && "invalid record type");
685390943f2SLeandro Lupori 
686390943f2SLeandro Lupori       for (auto [attr, type] : indexTypeMap.value()) {
687390943f2SLeandro Lupori         int64_t index = mlir::cast<mlir::IntegerAttr>(attr).getInt();
688390943f2SLeandro Lupori         auto extVal =
689390943f2SLeandro Lupori             rewriter.create<mlir::LLVM::ExtractValueOp>(loc, op0, index);
690390943f2SLeandro Lupori         val =
691390943f2SLeandro Lupori             rewriter.create<mlir::LLVM::InsertValueOp>(loc, val, extVal, index);
692390943f2SLeandro Lupori       }
693390943f2SLeandro Lupori 
694390943f2SLeandro Lupori       rewriter.replaceOp(convert, val);
695390943f2SLeandro Lupori       return mlir::success();
696390943f2SLeandro Lupori     }
697390943f2SLeandro Lupori 
698fac349a1SChristian Sigg     if (mlir::isa<fir::LogicalType>(fromFirTy) ||
699fac349a1SChristian Sigg         mlir::isa<fir::LogicalType>(toFirTy)) {
700f9e995b4SSlava Zakharin       // By specification fir::LogicalType value may be any number,
701f9e995b4SSlava Zakharin       // where non-zero value represents .true. and zero value represents
702f9e995b4SSlava Zakharin       // .false.
703f9e995b4SSlava Zakharin       //
704f9e995b4SSlava Zakharin       // integer<->logical conversion requires value normalization.
705f9e995b4SSlava Zakharin       // Conversion from wide logical to narrow logical must set the result
706f9e995b4SSlava Zakharin       // to non-zero iff the input is non-zero - the easiest way to implement
707f9e995b4SSlava Zakharin       // it is to compare the input agains zero and set the result to
708f9e995b4SSlava Zakharin       // the canonical 0/1.
709f9e995b4SSlava Zakharin       // Conversion from narrow logical to wide logical may be implemented
710f9e995b4SSlava Zakharin       // as a zero or sign extension of the input, but it may use value
711f9e995b4SSlava Zakharin       // normalization as well.
712fac349a1SChristian Sigg       if (!mlir::isa<mlir::IntegerType>(fromTy) ||
713fac349a1SChristian Sigg           !mlir::isa<mlir::IntegerType>(toTy))
714f9e995b4SSlava Zakharin         return mlir::emitError(loc)
715f9e995b4SSlava Zakharin                << "unsupported types for logical conversion: " << fromTy
716f9e995b4SSlava Zakharin                << " -> " << toTy;
717f9e995b4SSlava Zakharin 
718f9e995b4SSlava Zakharin       // Do folding for constant inputs.
719a5ae54abSTom Eccles       if (auto constVal = fir::getIntIfConstant(op0)) {
720f9e995b4SSlava Zakharin         mlir::Value normVal =
721f9e995b4SSlava Zakharin             genConstantIndex(loc, toTy, rewriter, *constVal ? 1 : 0);
722f9e995b4SSlava Zakharin         rewriter.replaceOp(convert, normVal);
723f9e995b4SSlava Zakharin         return mlir::success();
724f9e995b4SSlava Zakharin       }
725f9e995b4SSlava Zakharin 
726f9e995b4SSlava Zakharin       // If the input is i1, then we can just zero extend it, and
727f9e995b4SSlava Zakharin       // the result will be normalized.
728f9e995b4SSlava Zakharin       if (fromTy == i1Type) {
729f9e995b4SSlava Zakharin         rewriter.replaceOpWithNewOp<mlir::LLVM::ZExtOp>(convert, toTy, op0);
730f9e995b4SSlava Zakharin         return mlir::success();
731f9e995b4SSlava Zakharin       }
732f9e995b4SSlava Zakharin 
733f9e995b4SSlava Zakharin       // Compare the input with zero.
734f9e995b4SSlava Zakharin       mlir::Value zero = genConstantIndex(loc, fromTy, rewriter, 0);
735f9e995b4SSlava Zakharin       auto isTrue = rewriter.create<mlir::LLVM::ICmpOp>(
736f9e995b4SSlava Zakharin           loc, mlir::LLVM::ICmpPredicate::ne, op0, zero);
737f9e995b4SSlava Zakharin 
738f9e995b4SSlava Zakharin       // Zero extend the i1 isTrue result to the required type (unless it is i1
739f9e995b4SSlava Zakharin       // itself).
740f9e995b4SSlava Zakharin       if (toTy != i1Type)
741f9e995b4SSlava Zakharin         rewriter.replaceOpWithNewOp<mlir::LLVM::ZExtOp>(convert, toTy, isTrue);
742f9e995b4SSlava Zakharin       else
743f9e995b4SSlava Zakharin         rewriter.replaceOp(convert, isTrue.getResult());
744f9e995b4SSlava Zakharin 
745f9e995b4SSlava Zakharin       return mlir::success();
746f9e995b4SSlava Zakharin     }
747f9e995b4SSlava Zakharin 
748092cee5fSValentin Clement     if (fromTy == toTy) {
749092cee5fSValentin Clement       rewriter.replaceOp(convert, op0);
75044e58509SEric Schweitz       return mlir::success();
751092cee5fSValentin Clement     }
752092cee5fSValentin Clement     auto convertFpToFp = [&](mlir::Value val, unsigned fromBits,
753092cee5fSValentin Clement                              unsigned toBits, mlir::Type toTy) -> mlir::Value {
754092cee5fSValentin Clement       if (fromBits == toBits) {
755092cee5fSValentin Clement         // TODO: Converting between two floating-point representations with the
756092cee5fSValentin Clement         // same bitwidth is not allowed for now.
757092cee5fSValentin Clement         mlir::emitError(loc,
758092cee5fSValentin Clement                         "cannot implicitly convert between two floating-point "
759092cee5fSValentin Clement                         "representations of the same bitwidth");
760092cee5fSValentin Clement         return {};
761092cee5fSValentin Clement       }
762092cee5fSValentin Clement       if (fromBits > toBits)
763092cee5fSValentin Clement         return rewriter.create<mlir::LLVM::FPTruncOp>(loc, toTy, val);
764092cee5fSValentin Clement       return rewriter.create<mlir::LLVM::FPExtOp>(loc, toTy, val);
765092cee5fSValentin Clement     };
766092cee5fSValentin Clement     // Complex to complex conversion.
7673b7ec85aSJean Perier     if (fir::isa_complex(fromFirTy) && fir::isa_complex(toFirTy)) {
768092cee5fSValentin Clement       // Special case: handle the conversion of a complex such that both the
769092cee5fSValentin Clement       // real and imaginary parts are converted together.
770149ad3d5SShraiysh Vaishay       auto ty = convertType(getComplexEleTy(convert.getValue().getType()));
7715c5af910SJeff Niu       auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, op0, 0);
7725c5af910SJeff Niu       auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, op0, 1);
773149ad3d5SShraiysh Vaishay       auto nt = convertType(getComplexEleTy(convert.getRes().getType()));
774092cee5fSValentin Clement       auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
775092cee5fSValentin Clement       auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(nt);
776092cee5fSValentin Clement       auto rc = convertFpToFp(rp, fromBits, toBits, nt);
777092cee5fSValentin Clement       auto ic = convertFpToFp(ip, fromBits, toBits, nt);
778092cee5fSValentin Clement       auto un = rewriter.create<mlir::LLVM::UndefOp>(loc, toTy);
7795c5af910SJeff Niu       auto i1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, un, rc, 0);
7805c5af910SJeff Niu       rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(convert, i1, ic,
7815c5af910SJeff Niu                                                              1);
782092cee5fSValentin Clement       return mlir::success();
783092cee5fSValentin Clement     }
7843b7ec85aSJean Perier 
785092cee5fSValentin Clement     // Floating point to floating point conversion.
786092cee5fSValentin Clement     if (isFloatingPointTy(fromTy)) {
787092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
788092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
789092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
790092cee5fSValentin Clement         auto v = convertFpToFp(op0, fromBits, toBits, toTy);
791092cee5fSValentin Clement         rewriter.replaceOp(convert, v);
792092cee5fSValentin Clement         return mlir::success();
793092cee5fSValentin Clement       }
794fac349a1SChristian Sigg       if (mlir::isa<mlir::IntegerType>(toTy)) {
795fc97d2e6SPeter Klausler         if (toTy.isUnsignedInteger())
796fc97d2e6SPeter Klausler           rewriter.replaceOpWithNewOp<mlir::LLVM::FPToUIOp>(convert, toTy, op0);
797fc97d2e6SPeter Klausler         else
798092cee5fSValentin Clement           rewriter.replaceOpWithNewOp<mlir::LLVM::FPToSIOp>(convert, toTy, op0);
799092cee5fSValentin Clement         return mlir::success();
800092cee5fSValentin Clement       }
801fac349a1SChristian Sigg     } else if (mlir::isa<mlir::IntegerType>(fromTy)) {
802092cee5fSValentin Clement       // Integer to integer conversion.
803fac349a1SChristian Sigg       if (mlir::isa<mlir::IntegerType>(toTy)) {
804092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
805092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
806092cee5fSValentin Clement         assert(fromBits != toBits);
807092cee5fSValentin Clement         if (fromBits > toBits) {
808092cee5fSValentin Clement           rewriter.replaceOpWithNewOp<mlir::LLVM::TruncOp>(convert, toTy, op0);
809092cee5fSValentin Clement           return mlir::success();
810092cee5fSValentin Clement         }
811fc97d2e6SPeter Klausler         if (fromFirTy == i1Type || fromFirTy.isUnsignedInteger()) {
812c024fa4bSValentin Clement           rewriter.replaceOpWithNewOp<mlir::LLVM::ZExtOp>(convert, toTy, op0);
813c024fa4bSValentin Clement           return mlir::success();
814c024fa4bSValentin Clement         }
815092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SExtOp>(convert, toTy, op0);
816092cee5fSValentin Clement         return mlir::success();
817092cee5fSValentin Clement       }
818092cee5fSValentin Clement       // Integer to floating point conversion.
819092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
820fc97d2e6SPeter Klausler         if (fromTy.isUnsignedInteger())
821fc97d2e6SPeter Klausler           rewriter.replaceOpWithNewOp<mlir::LLVM::UIToFPOp>(convert, toTy, op0);
822fc97d2e6SPeter Klausler         else
823092cee5fSValentin Clement           rewriter.replaceOpWithNewOp<mlir::LLVM::SIToFPOp>(convert, toTy, op0);
824092cee5fSValentin Clement         return mlir::success();
825092cee5fSValentin Clement       }
826092cee5fSValentin Clement       // Integer to pointer conversion.
827fac349a1SChristian Sigg       if (mlir::isa<mlir::LLVM::LLVMPointerType>(toTy)) {
828092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(convert, toTy, op0);
829092cee5fSValentin Clement         return mlir::success();
830092cee5fSValentin Clement       }
831fac349a1SChristian Sigg     } else if (mlir::isa<mlir::LLVM::LLVMPointerType>(fromTy)) {
832092cee5fSValentin Clement       // Pointer to integer conversion.
833fac349a1SChristian Sigg       if (mlir::isa<mlir::IntegerType>(toTy)) {
834092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::PtrToIntOp>(convert, toTy, op0);
835092cee5fSValentin Clement         return mlir::success();
836092cee5fSValentin Clement       }
837092cee5fSValentin Clement       // Pointer to pointer conversion.
838fac349a1SChristian Sigg       if (mlir::isa<mlir::LLVM::LLVMPointerType>(toTy)) {
839092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(convert, toTy, op0);
840092cee5fSValentin Clement         return mlir::success();
841092cee5fSValentin Clement       }
842092cee5fSValentin Clement     }
843092cee5fSValentin Clement     return emitError(loc) << "cannot convert " << fromTy << " to " << toTy;
844092cee5fSValentin Clement   }
845092cee5fSValentin Clement };
846092cee5fSValentin Clement 
8474ccd57ddSjeanPerier /// `fir.type_info` operation has no specific CodeGen. The operation is
8484ccd57ddSjeanPerier /// only used to carry information during FIR to FIR passes. It may be used
8494ccd57ddSjeanPerier /// in the future to generate the runtime type info data structures instead
8504ccd57ddSjeanPerier /// of generating them in lowering.
851e9639e9cSValentin Clement (バレンタイン クレメン) struct TypeInfoOpConversion : public fir::FIROpConversion<fir::TypeInfoOp> {
8529534e361SValentin Clement   using FIROpConversion::FIROpConversion;
8539534e361SValentin Clement 
854db791b27SRamkumar Ramachandra   llvm::LogicalResult
8554ccd57ddSjeanPerier   matchAndRewrite(fir::TypeInfoOp op, OpAdaptor,
8569534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8576393d2eaSValentin Clement     rewriter.eraseOp(op);
8586393d2eaSValentin Clement     return mlir::success();
8599534e361SValentin Clement   }
8609534e361SValentin Clement };
8619534e361SValentin Clement 
8626393d2eaSValentin Clement /// `fir.dt_entry` operation has no specific CodeGen. The operation is only used
8636393d2eaSValentin Clement /// to carry information during FIR to FIR passes.
864e9639e9cSValentin Clement (バレンタイン クレメン) struct DTEntryOpConversion : public fir::FIROpConversion<fir::DTEntryOp> {
8659534e361SValentin Clement   using FIROpConversion::FIROpConversion;
8669534e361SValentin Clement 
867db791b27SRamkumar Ramachandra   llvm::LogicalResult
8686393d2eaSValentin Clement   matchAndRewrite(fir::DTEntryOp op, OpAdaptor,
8699534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8706393d2eaSValentin Clement     rewriter.eraseOp(op);
8716393d2eaSValentin Clement     return mlir::success();
8729534e361SValentin Clement   }
8739534e361SValentin Clement };
8749534e361SValentin Clement 
875677df8c7SValentin Clement /// Lower `fir.global_len` operation.
876e9639e9cSValentin Clement (バレンタイン クレメン) struct GlobalLenOpConversion : public fir::FIROpConversion<fir::GlobalLenOp> {
877677df8c7SValentin Clement   using FIROpConversion::FIROpConversion;
878677df8c7SValentin Clement 
879db791b27SRamkumar Ramachandra   llvm::LogicalResult
880677df8c7SValentin Clement   matchAndRewrite(fir::GlobalLenOp globalLen, OpAdaptor adaptor,
881677df8c7SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8827ce8c6fcSKiran Chandramohan     TODO(globalLen.getLoc(), "fir.global_len codegen");
88344e58509SEric Schweitz     return mlir::failure();
884677df8c7SValentin Clement   }
885677df8c7SValentin Clement };
886677df8c7SValentin Clement 
887cdc476abSDiana Picus /// Lower fir.len_param_index
888cdc476abSDiana Picus struct LenParamIndexOpConversion
889e9639e9cSValentin Clement (バレンタイン クレメン)     : public fir::FIROpConversion<fir::LenParamIndexOp> {
890cdc476abSDiana Picus   using FIROpConversion::FIROpConversion;
891cdc476abSDiana Picus 
892cdc476abSDiana Picus   // FIXME: this should be specialized by the runtime target
893db791b27SRamkumar Ramachandra   llvm::LogicalResult
894cdc476abSDiana Picus   matchAndRewrite(fir::LenParamIndexOp lenp, OpAdaptor,
895cdc476abSDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
8967ce8c6fcSKiran Chandramohan     TODO(lenp.getLoc(), "fir.len_param_index codegen");
897cdc476abSDiana Picus   }
898cdc476abSDiana Picus };
899cdc476abSDiana Picus 
900dc48849fSKiran Chandramohan /// Convert `!fir.emboxchar<!fir.char<KIND, ?>, #n>` into a sequence of
901dc48849fSKiran Chandramohan /// instructions that generate `!llvm.struct<(ptr<ik>, i64)>`. The 1st element
902dc48849fSKiran Chandramohan /// in this struct is a pointer. Its type is determined from `KIND`. The 2nd
903dc48849fSKiran Chandramohan /// element is the length of the character buffer (`#n`).
904e9639e9cSValentin Clement (バレンタイン クレメン) struct EmboxCharOpConversion : public fir::FIROpConversion<fir::EmboxCharOp> {
90531246187SValentin Clement   using FIROpConversion::FIROpConversion;
90631246187SValentin Clement 
907db791b27SRamkumar Ramachandra   llvm::LogicalResult
908dc48849fSKiran Chandramohan   matchAndRewrite(fir::EmboxCharOp emboxChar, OpAdaptor adaptor,
90931246187SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
910dc48849fSKiran Chandramohan     mlir::ValueRange operands = adaptor.getOperands();
911dc48849fSKiran Chandramohan 
912dc48849fSKiran Chandramohan     mlir::Value charBuffer = operands[0];
913dc48849fSKiran Chandramohan     mlir::Value charBufferLen = operands[1];
914dc48849fSKiran Chandramohan 
915dc48849fSKiran Chandramohan     mlir::Location loc = emboxChar.getLoc();
916dc48849fSKiran Chandramohan     mlir::Type llvmStructTy = convertType(emboxChar.getType());
917dc48849fSKiran Chandramohan     auto llvmStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, llvmStructTy);
918dc48849fSKiran Chandramohan 
919dc48849fSKiran Chandramohan     mlir::Type lenTy =
920fac349a1SChristian Sigg         mlir::cast<mlir::LLVM::LLVMStructType>(llvmStructTy).getBody()[1];
921dc48849fSKiran Chandramohan     mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, charBufferLen);
922dc48849fSKiran Chandramohan 
923959de150SJean Perier     mlir::Type addrTy =
924fac349a1SChristian Sigg         mlir::cast<mlir::LLVM::LLVMStructType>(llvmStructTy).getBody()[0];
925959de150SJean Perier     if (addrTy != charBuffer.getType())
926959de150SJean Perier       charBuffer =
927959de150SJean Perier           rewriter.create<mlir::LLVM::BitcastOp>(loc, addrTy, charBuffer);
928959de150SJean Perier 
929dc48849fSKiran Chandramohan     auto insertBufferOp = rewriter.create<mlir::LLVM::InsertValueOp>(
9305c5af910SJeff Niu         loc, llvmStruct, charBuffer, 0);
931dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
9325c5af910SJeff Niu         emboxChar, insertBufferOp, lenAfterCast, 1);
933dc48849fSKiran Chandramohan 
93444e58509SEric Schweitz     return mlir::success();
93531246187SValentin Clement   }
93631246187SValentin Clement };
937c2acd453SAlexisPerry } // namespace
938c2acd453SAlexisPerry 
939e5092c30SValentin Clement (バレンタイン クレメン) template <typename ModuleOp>
9404f62a183SjeanPerier static mlir::SymbolRefAttr
941e5092c30SValentin Clement (バレンタイン クレメン) getMallocInModule(ModuleOp mod, fir::AllocMemOp op,
942e5092c30SValentin Clement (バレンタイン クレメン)                   mlir::ConversionPatternRewriter &rewriter) {
9434f62a183SjeanPerier   static constexpr char mallocName[] = "malloc";
944e5092c30SValentin Clement (バレンタイン クレメン)   if (auto mallocFunc =
945e5092c30SValentin Clement (バレンタイン クレメン)           mod.template lookupSymbol<mlir::LLVM::LLVMFuncOp>(mallocName))
9464f62a183SjeanPerier     return mlir::SymbolRefAttr::get(mallocFunc);
947e5092c30SValentin Clement (バレンタイン クレメン)   if (auto userMalloc =
948e5092c30SValentin Clement (バレンタイン クレメン)           mod.template lookupSymbol<mlir::func::FuncOp>(mallocName))
9494f62a183SjeanPerier     return mlir::SymbolRefAttr::get(userMalloc);
950e5092c30SValentin Clement (バレンタイン クレメン) 
951e5092c30SValentin Clement (バレンタイン クレメン)   mlir::OpBuilder moduleBuilder(mod.getBodyRegion());
952c2acd453SAlexisPerry   auto indexType = mlir::IntegerType::get(op.getContext(), 64);
9534f62a183SjeanPerier   auto mallocDecl = moduleBuilder.create<mlir::LLVM::LLVMFuncOp>(
9544f62a183SjeanPerier       op.getLoc(), mallocName,
9558a1ce2d6SjeanPerier       mlir::LLVM::LLVMFunctionType::get(getLlvmPtrType(op.getContext()),
956c2acd453SAlexisPerry                                         indexType,
957c2acd453SAlexisPerry                                         /*isVarArg=*/false));
9584f62a183SjeanPerier   return mlir::SymbolRefAttr::get(mallocDecl);
959c2acd453SAlexisPerry }
960c2acd453SAlexisPerry 
961e5092c30SValentin Clement (バレンタイン クレメン) /// Return the LLVMFuncOp corresponding to the standard malloc call.
962e5092c30SValentin Clement (バレンタイン クレメン) static mlir::SymbolRefAttr
963e5092c30SValentin Clement (バレンタイン クレメン) getMalloc(fir::AllocMemOp op, mlir::ConversionPatternRewriter &rewriter) {
964e5092c30SValentin Clement (バレンタイン クレメン)   if (auto mod = op->getParentOfType<mlir::gpu::GPUModuleOp>())
965e5092c30SValentin Clement (バレンタイン クレメン)     return getMallocInModule(mod, op, rewriter);
966e5092c30SValentin Clement (バレンタイン クレメン)   auto mod = op->getParentOfType<mlir::ModuleOp>();
967e5092c30SValentin Clement (バレンタイン クレメン)   return getMallocInModule(mod, op, rewriter);
968e5092c30SValentin Clement (バレンタイン クレメン) }
969e5092c30SValentin Clement (バレンタイン クレメン) 
97002f3fec3SSlava Zakharin /// Helper function for generating the LLVM IR that computes the distance
97102f3fec3SSlava Zakharin /// in bytes between adjacent elements pointed to by a pointer
97202f3fec3SSlava Zakharin /// of type \p ptrTy. The result is returned as a value of \p idxTy integer
97302f3fec3SSlava Zakharin /// type.
974c2acd453SAlexisPerry static mlir::Value
9758a1ce2d6SjeanPerier computeElementDistance(mlir::Location loc, mlir::Type llvmObjectType,
9768a1ce2d6SjeanPerier                        mlir::Type idxTy,
977c2acd453SAlexisPerry                        mlir::ConversionPatternRewriter &rewriter) {
97802f3fec3SSlava Zakharin   // Note that we cannot use something like
97902f3fec3SSlava Zakharin   // mlir::LLVM::getPrimitiveTypeSizeInBits() for the element type here. For
98002f3fec3SSlava Zakharin   // example, it returns 10 bytes for mlir::Float80Type for targets where it
98102f3fec3SSlava Zakharin   // occupies 16 bytes. Proper solution is probably to use
98202f3fec3SSlava Zakharin   // mlir::DataLayout::getTypeABIAlignment(), but DataLayout is not being set
98302f3fec3SSlava Zakharin   // yet (see llvm-project#57230). For the time being use the '(intptr_t)((type
98402f3fec3SSlava Zakharin   // *)0 + 1)' trick for all types. The generated instructions are optimized
98502f3fec3SSlava Zakharin   // into constant by the first pass of InstCombine, so it should not be a
98602f3fec3SSlava Zakharin   // performance issue.
9878a1ce2d6SjeanPerier   auto llvmPtrTy = ::getLlvmPtrType(llvmObjectType.getContext());
9888a1ce2d6SjeanPerier   auto nullPtr = rewriter.create<mlir::LLVM::ZeroOp>(loc, llvmPtrTy);
989bd7eff1fSMarkus Böck   auto gep = rewriter.create<mlir::LLVM::GEPOp>(
9908a1ce2d6SjeanPerier       loc, llvmPtrTy, llvmObjectType, nullPtr,
9918a1ce2d6SjeanPerier       llvm::ArrayRef<mlir::LLVM::GEPArg>{1});
992c2acd453SAlexisPerry   return rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, gep);
993c2acd453SAlexisPerry }
994c2acd453SAlexisPerry 
99502f3fec3SSlava Zakharin /// Return value of the stride in bytes between adjacent elements
99602f3fec3SSlava Zakharin /// of LLVM type \p llTy. The result is returned as a value of
99702f3fec3SSlava Zakharin /// \p idxTy integer type.
99802f3fec3SSlava Zakharin static mlir::Value
99902f3fec3SSlava Zakharin genTypeStrideInBytes(mlir::Location loc, mlir::Type idxTy,
100002f3fec3SSlava Zakharin                      mlir::ConversionPatternRewriter &rewriter,
100102f3fec3SSlava Zakharin                      mlir::Type llTy) {
100202f3fec3SSlava Zakharin   // Create a pointer type and use computeElementDistance().
10038a1ce2d6SjeanPerier   return computeElementDistance(loc, llTy, idxTy, rewriter);
100402f3fec3SSlava Zakharin }
100502f3fec3SSlava Zakharin 
1006c2acd453SAlexisPerry namespace {
1007c2acd453SAlexisPerry /// Lower a `fir.allocmem` instruction into `llvm.call @malloc`
1008e9639e9cSValentin Clement (バレンタイン クレメン) struct AllocMemOpConversion : public fir::FIROpConversion<fir::AllocMemOp> {
1009c2acd453SAlexisPerry   using FIROpConversion::FIROpConversion;
1010c2acd453SAlexisPerry 
1011db791b27SRamkumar Ramachandra   llvm::LogicalResult
1012c2acd453SAlexisPerry   matchAndRewrite(fir::AllocMemOp heap, OpAdaptor adaptor,
1013c2acd453SAlexisPerry                   mlir::ConversionPatternRewriter &rewriter) const override {
1014575c9d6dSValentin Clement     mlir::Type heapTy = heap.getType();
1015c2acd453SAlexisPerry     mlir::Location loc = heap.getLoc();
1016c2acd453SAlexisPerry     auto ity = lowerTy().indexType();
1017575c9d6dSValentin Clement     mlir::Type dataTy = fir::unwrapRefType(heapTy);
10188a1ce2d6SjeanPerier     mlir::Type llvmObjectTy = convertObjectType(dataTy);
1019c45bd4b9SEric Schweitz     if (fir::isRecordWithTypeParameters(fir::unwrapSequenceType(dataTy)))
1020c45bd4b9SEric Schweitz       TODO(loc, "fir.allocmem codegen of derived type with length parameters");
10218a1ce2d6SjeanPerier     mlir::Value size = genTypeSizeInBytes(loc, ity, rewriter, llvmObjectTy);
1022ac0f4c8fSPeixinQiao     if (auto scaleSize = genAllocationScaleSize(heap, ity, rewriter))
1023ac0f4c8fSPeixinQiao       size = rewriter.create<mlir::LLVM::MulOp>(loc, ity, size, scaleSize);
1024c2acd453SAlexisPerry     for (mlir::Value opnd : adaptor.getOperands())
1025c2acd453SAlexisPerry       size = rewriter.create<mlir::LLVM::MulOp>(
1026c2acd453SAlexisPerry           loc, ity, size, integerCast(loc, rewriter, ity, opnd));
10274f62a183SjeanPerier     heap->setAttr("callee", getMalloc(heap, rewriter));
10288a1ce2d6SjeanPerier     rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
1029fde3c16aSSirui Mu         heap, ::getLlvmPtrType(heap.getContext()), size,
1030fde3c16aSSirui Mu         addLLVMOpBundleAttrs(rewriter, heap->getAttrs(), 1));
103144e58509SEric Schweitz     return mlir::success();
1032c2acd453SAlexisPerry   }
1033c2acd453SAlexisPerry 
103402f3fec3SSlava Zakharin   /// Compute the allocation size in bytes of the element type of
103502f3fec3SSlava Zakharin   /// \p llTy pointer type. The result is returned as a value of \p idxTy
103602f3fec3SSlava Zakharin   /// integer type.
1037c2acd453SAlexisPerry   mlir::Value genTypeSizeInBytes(mlir::Location loc, mlir::Type idxTy,
1038c2acd453SAlexisPerry                                  mlir::ConversionPatternRewriter &rewriter,
1039c2acd453SAlexisPerry                                  mlir::Type llTy) const {
10408a1ce2d6SjeanPerier     return computeElementDistance(loc, llTy, idxTy, rewriter);
1041c2acd453SAlexisPerry   }
1042c2acd453SAlexisPerry };
1043c2acd453SAlexisPerry } // namespace
1044c2acd453SAlexisPerry 
1045c2acd453SAlexisPerry /// Return the LLVMFuncOp corresponding to the standard free call.
1046e5092c30SValentin Clement (バレンタイン クレメン) template <typename ModuleOp>
1047e5092c30SValentin Clement (バレンタイン クレメン) static mlir::SymbolRefAttr
1048e5092c30SValentin Clement (バレンタイン クレメン) getFreeInModule(ModuleOp mod, fir::FreeMemOp op,
10494f62a183SjeanPerier                 mlir::ConversionPatternRewriter &rewriter) {
10504f62a183SjeanPerier   static constexpr char freeName[] = "free";
10514f62a183SjeanPerier   // Check if free already defined in the module.
1052e5092c30SValentin Clement (バレンタイン クレメン)   if (auto freeFunc =
1053e5092c30SValentin Clement (バレンタイン クレメン)           mod.template lookupSymbol<mlir::LLVM::LLVMFuncOp>(freeName))
10544f62a183SjeanPerier     return mlir::SymbolRefAttr::get(freeFunc);
10554f62a183SjeanPerier   if (auto freeDefinedByUser =
1056e5092c30SValentin Clement (バレンタイン クレメン)           mod.template lookupSymbol<mlir::func::FuncOp>(freeName))
10574f62a183SjeanPerier     return mlir::SymbolRefAttr::get(freeDefinedByUser);
10584f62a183SjeanPerier   // Create llvm declaration for free.
1059e5092c30SValentin Clement (バレンタイン クレメン)   mlir::OpBuilder moduleBuilder(mod.getBodyRegion());
1060c2acd453SAlexisPerry   auto voidType = mlir::LLVM::LLVMVoidType::get(op.getContext());
10614f62a183SjeanPerier   auto freeDecl = moduleBuilder.create<mlir::LLVM::LLVMFuncOp>(
10624f62a183SjeanPerier       rewriter.getUnknownLoc(), freeName,
1063c2acd453SAlexisPerry       mlir::LLVM::LLVMFunctionType::get(voidType,
10648a1ce2d6SjeanPerier                                         getLlvmPtrType(op.getContext()),
1065c2acd453SAlexisPerry                                         /*isVarArg=*/false));
10664f62a183SjeanPerier   return mlir::SymbolRefAttr::get(freeDecl);
1067c2acd453SAlexisPerry }
1068c2acd453SAlexisPerry 
1069e5092c30SValentin Clement (バレンタイン クレメン) static mlir::SymbolRefAttr getFree(fir::FreeMemOp op,
1070e5092c30SValentin Clement (バレンタイン クレメン)                                    mlir::ConversionPatternRewriter &rewriter) {
1071e5092c30SValentin Clement (バレンタイン クレメン)   if (auto mod = op->getParentOfType<mlir::gpu::GPUModuleOp>())
1072e5092c30SValentin Clement (バレンタイン クレメン)     return getFreeInModule(mod, op, rewriter);
1073e5092c30SValentin Clement (バレンタイン クレメン)   auto mod = op->getParentOfType<mlir::ModuleOp>();
1074e5092c30SValentin Clement (バレンタイン クレメン)   return getFreeInModule(mod, op, rewriter);
1075e5092c30SValentin Clement (バレンタイン クレメン) }
1076e5092c30SValentin Clement (バレンタイン クレメン) 
1077b094c737SJean Perier static unsigned getDimension(mlir::LLVM::LLVMArrayType ty) {
1078b094c737SJean Perier   unsigned result = 1;
1079fac349a1SChristian Sigg   for (auto eleTy =
1080fac349a1SChristian Sigg            mlir::dyn_cast<mlir::LLVM::LLVMArrayType>(ty.getElementType());
1081fac349a1SChristian Sigg        eleTy; eleTy = mlir::dyn_cast<mlir::LLVM::LLVMArrayType>(
1082fac349a1SChristian Sigg                   eleTy.getElementType()))
1083b094c737SJean Perier     ++result;
1084b094c737SJean Perier   return result;
1085b094c737SJean Perier }
1086b094c737SJean Perier 
1087c2acd453SAlexisPerry namespace {
1088c2acd453SAlexisPerry /// Lower a `fir.freemem` instruction into `llvm.call @free`
1089e9639e9cSValentin Clement (バレンタイン クレメン) struct FreeMemOpConversion : public fir::FIROpConversion<fir::FreeMemOp> {
1090c2acd453SAlexisPerry   using FIROpConversion::FIROpConversion;
1091c2acd453SAlexisPerry 
1092db791b27SRamkumar Ramachandra   llvm::LogicalResult
1093c2acd453SAlexisPerry   matchAndRewrite(fir::FreeMemOp freemem, OpAdaptor adaptor,
1094c2acd453SAlexisPerry                   mlir::ConversionPatternRewriter &rewriter) const override {
1095c2acd453SAlexisPerry     mlir::Location loc = freemem.getLoc();
10964f62a183SjeanPerier     freemem->setAttr("callee", getFree(freemem, rewriter));
1097fde3c16aSSirui Mu     rewriter.create<mlir::LLVM::CallOp>(
1098fde3c16aSSirui Mu         loc, mlir::TypeRange{}, mlir::ValueRange{adaptor.getHeapref()},
1099fde3c16aSSirui Mu         addLLVMOpBundleAttrs(rewriter, freemem->getAttrs(), 1));
1100c2acd453SAlexisPerry     rewriter.eraseOp(freemem);
110144e58509SEric Schweitz     return mlir::success();
1102c2acd453SAlexisPerry   }
1103c2acd453SAlexisPerry };
1104c2acd453SAlexisPerry } // namespace
1105044d5b5dSValentin Clement 
1106783222efSLeandro Lupori // Convert subcomponent array indices from column-major to row-major ordering.
1107783222efSLeandro Lupori static llvm::SmallVector<mlir::Value>
1108783222efSLeandro Lupori convertSubcomponentIndices(mlir::Location loc, mlir::Type eleTy,
1109783222efSLeandro Lupori                            mlir::ValueRange indices,
1110783222efSLeandro Lupori                            mlir::Type *retTy = nullptr) {
1111783222efSLeandro Lupori   llvm::SmallVector<mlir::Value> result;
1112783222efSLeandro Lupori   llvm::SmallVector<mlir::Value> arrayIndices;
1113783222efSLeandro Lupori 
1114783222efSLeandro Lupori   auto appendArrayIndices = [&] {
1115783222efSLeandro Lupori     if (arrayIndices.empty())
1116783222efSLeandro Lupori       return;
1117783222efSLeandro Lupori     std::reverse(arrayIndices.begin(), arrayIndices.end());
1118783222efSLeandro Lupori     result.append(arrayIndices.begin(), arrayIndices.end());
1119783222efSLeandro Lupori     arrayIndices.clear();
1120783222efSLeandro Lupori   };
1121783222efSLeandro Lupori 
1122783222efSLeandro Lupori   for (mlir::Value index : indices) {
1123783222efSLeandro Lupori     // Component indices can be field index to select a component, or array
1124783222efSLeandro Lupori     // index, to select an element in an array component.
1125783222efSLeandro Lupori     if (auto structTy = mlir::dyn_cast<mlir::LLVM::LLVMStructType>(eleTy)) {
1126783222efSLeandro Lupori       std::int64_t cstIndex = getConstantIntValue(index);
1127783222efSLeandro Lupori       assert(cstIndex < (int64_t)structTy.getBody().size() &&
1128783222efSLeandro Lupori              "out-of-bounds struct field index");
1129783222efSLeandro Lupori       eleTy = structTy.getBody()[cstIndex];
1130783222efSLeandro Lupori       appendArrayIndices();
1131783222efSLeandro Lupori       result.push_back(index);
1132783222efSLeandro Lupori     } else if (auto arrayTy =
1133783222efSLeandro Lupori                    mlir::dyn_cast<mlir::LLVM::LLVMArrayType>(eleTy)) {
1134783222efSLeandro Lupori       eleTy = arrayTy.getElementType();
1135783222efSLeandro Lupori       arrayIndices.push_back(index);
1136783222efSLeandro Lupori     } else
1137783222efSLeandro Lupori       fir::emitFatalError(loc, "Unexpected subcomponent type");
1138783222efSLeandro Lupori   }
1139783222efSLeandro Lupori   appendArrayIndices();
1140783222efSLeandro Lupori   if (retTy)
1141783222efSLeandro Lupori     *retTy = eleTy;
1142783222efSLeandro Lupori   return result;
1143783222efSLeandro Lupori }
1144783222efSLeandro Lupori 
11454530273dSValentin Clement (バレンタイン クレメン) static mlir::Value genSourceFile(mlir::Location loc, mlir::ModuleOp mod,
11464530273dSValentin Clement (バレンタイン クレメン)                                  mlir::ConversionPatternRewriter &rewriter) {
11474530273dSValentin Clement (バレンタイン クレメン)   auto ptrTy = mlir::LLVM::LLVMPointerType::get(rewriter.getContext());
11484530273dSValentin Clement (バレンタイン クレメン)   if (auto flc = mlir::dyn_cast<mlir::FileLineColLoc>(loc)) {
11494530273dSValentin Clement (バレンタイン クレメン)     auto fn = flc.getFilename().str() + '\0';
11504530273dSValentin Clement (バレンタイン クレメン)     std::string globalName = fir::factory::uniqueCGIdent("cl", fn);
11514530273dSValentin Clement (バレンタイン クレメン) 
11524530273dSValentin Clement (バレンタイン クレメン)     if (auto g = mod.lookupSymbol<fir::GlobalOp>(globalName)) {
11534530273dSValentin Clement (バレンタイン クレメン)       return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ptrTy, g.getName());
11544530273dSValentin Clement (バレンタイン クレメン)     } else if (auto g = mod.lookupSymbol<mlir::LLVM::GlobalOp>(globalName)) {
11554530273dSValentin Clement (バレンタイン クレメン)       return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ptrTy, g.getName());
11564530273dSValentin Clement (バレンタイン クレメン)     }
11574530273dSValentin Clement (バレンタイン クレメン) 
11584530273dSValentin Clement (バレンタイン クレメン)     auto crtInsPt = rewriter.saveInsertionPoint();
11594530273dSValentin Clement (バレンタイン クレメン)     rewriter.setInsertionPoint(mod.getBody(), mod.getBody()->end());
11604530273dSValentin Clement (バレンタイン クレメン)     auto arrayTy = mlir::LLVM::LLVMArrayType::get(
11614530273dSValentin Clement (バレンタイン クレメン)         mlir::IntegerType::get(rewriter.getContext(), 8), fn.size());
11624530273dSValentin Clement (バレンタイン クレメン)     mlir::LLVM::GlobalOp globalOp = rewriter.create<mlir::LLVM::GlobalOp>(
11634530273dSValentin Clement (バレンタイン クレメン)         loc, arrayTy, /*constant=*/true, mlir::LLVM::Linkage::Linkonce,
11644530273dSValentin Clement (バレンタイン クレメン)         globalName, mlir::Attribute());
11654530273dSValentin Clement (バレンタイン クレメン) 
11664530273dSValentin Clement (バレンタイン クレメン)     mlir::Region &region = globalOp.getInitializerRegion();
11674530273dSValentin Clement (バレンタイン クレメン)     mlir::Block *block = rewriter.createBlock(&region);
11684530273dSValentin Clement (バレンタイン クレメン)     rewriter.setInsertionPoint(block, block->begin());
11694530273dSValentin Clement (バレンタイン クレメン)     mlir::Value constValue = rewriter.create<mlir::LLVM::ConstantOp>(
11704530273dSValentin Clement (バレンタイン クレメン)         loc, arrayTy, rewriter.getStringAttr(fn));
11714530273dSValentin Clement (バレンタイン クレメン)     rewriter.create<mlir::LLVM::ReturnOp>(loc, constValue);
11724530273dSValentin Clement (バレンタイン クレメン)     rewriter.restoreInsertionPoint(crtInsPt);
11734530273dSValentin Clement (バレンタイン クレメン)     return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ptrTy,
11744530273dSValentin Clement (バレンタイン クレメン)                                                     globalOp.getName());
11754530273dSValentin Clement (バレンタイン クレメン)   }
11764530273dSValentin Clement (バレンタイン クレメン)   return rewriter.create<mlir::LLVM::ZeroOp>(loc, ptrTy);
11774530273dSValentin Clement (バレンタイン クレメン) }
11784530273dSValentin Clement (バレンタイン クレメン) 
11794530273dSValentin Clement (バレンタイン クレメン) static mlir::Value genSourceLine(mlir::Location loc,
11804530273dSValentin Clement (バレンタイン クレメン)                                  mlir::ConversionPatternRewriter &rewriter) {
11814530273dSValentin Clement (バレンタイン クレメン)   if (auto flc = mlir::dyn_cast<mlir::FileLineColLoc>(loc))
11824530273dSValentin Clement (バレンタイン クレメン)     return rewriter.create<mlir::LLVM::ConstantOp>(loc, rewriter.getI32Type(),
11834530273dSValentin Clement (バレンタイン クレメン)                                                    flc.getLine());
11844530273dSValentin Clement (バレンタイン クレメン)   return rewriter.create<mlir::LLVM::ConstantOp>(loc, rewriter.getI32Type(), 0);
11854530273dSValentin Clement (バレンタイン クレメン) }
11864530273dSValentin Clement (バレンタイン クレメン) 
11874530273dSValentin Clement (バレンタイン クレメン) static mlir::Value
11884530273dSValentin Clement (バレンタイン クレメン) genCUFAllocDescriptor(mlir::Location loc,
11894530273dSValentin Clement (バレンタイン クレメン)                       mlir::ConversionPatternRewriter &rewriter,
11904530273dSValentin Clement (バレンタイン クレメン)                       mlir::ModuleOp mod, fir::BaseBoxType boxTy,
11914530273dSValentin Clement (バレンタイン クレメン)                       const fir::LLVMTypeConverter &typeConverter) {
11924530273dSValentin Clement (バレンタイン クレメン)   std::optional<mlir::DataLayout> dl =
11934530273dSValentin Clement (バレンタイン クレメン)       fir::support::getOrSetDataLayout(mod, /*allowDefaultLayout=*/true);
11944530273dSValentin Clement (バレンタイン クレメン)   if (!dl)
11954530273dSValentin Clement (バレンタイン クレメン)     mlir::emitError(mod.getLoc(),
11964530273dSValentin Clement (バレンタイン クレメン)                     "module operation must carry a data layout attribute "
11974530273dSValentin Clement (バレンタイン クレメン)                     "to generate llvm IR from FIR");
11984530273dSValentin Clement (バレンタイン クレメン) 
11994530273dSValentin Clement (バレンタイン クレメン)   mlir::Value sourceFile = genSourceFile(loc, mod, rewriter);
12004530273dSValentin Clement (バレンタイン クレメン)   mlir::Value sourceLine = genSourceLine(loc, rewriter);
12014530273dSValentin Clement (バレンタイン クレメン) 
12024530273dSValentin Clement (バレンタイン クレメン)   mlir::MLIRContext *ctx = mod.getContext();
12034530273dSValentin Clement (バレンタイン クレメン) 
12044530273dSValentin Clement (バレンタイン クレメン)   mlir::LLVM::LLVMPointerType llvmPointerType =
12054530273dSValentin Clement (バレンタイン クレメン)       mlir::LLVM::LLVMPointerType::get(ctx);
12064530273dSValentin Clement (バレンタイン クレメン)   mlir::Type llvmInt32Type = mlir::IntegerType::get(ctx, 32);
12074530273dSValentin Clement (バレンタイン クレメン)   mlir::Type llvmIntPtrType =
12084530273dSValentin Clement (バレンタイン クレメン)       mlir::IntegerType::get(ctx, typeConverter.getPointerBitwidth(0));
12094530273dSValentin Clement (バレンタイン クレメン)   auto fctTy = mlir::LLVM::LLVMFunctionType::get(
12104530273dSValentin Clement (バレンタイン クレメン)       llvmPointerType, {llvmIntPtrType, llvmPointerType, llvmInt32Type});
12114530273dSValentin Clement (バレンタイン クレメン) 
12124530273dSValentin Clement (バレンタイン クレメン)   auto llvmFunc = mod.lookupSymbol<mlir::LLVM::LLVMFuncOp>(
1213e650ac16SValentin Clement (バレンタイン クレメン)       RTNAME_STRING(CUFAllocDescriptor));
12144530273dSValentin Clement (バレンタイン クレメン)   auto funcFunc =
1215e650ac16SValentin Clement (バレンタイン クレメン)       mod.lookupSymbol<mlir::func::FuncOp>(RTNAME_STRING(CUFAllocDescriptor));
12164530273dSValentin Clement (バレンタイン クレメン)   if (!llvmFunc && !funcFunc)
12174530273dSValentin Clement (バレンタイン クレメン)     mlir::OpBuilder::atBlockEnd(mod.getBody())
1218e650ac16SValentin Clement (バレンタイン クレメン)         .create<mlir::LLVM::LLVMFuncOp>(loc, RTNAME_STRING(CUFAllocDescriptor),
12194530273dSValentin Clement (バレンタイン クレメン)                                         fctTy);
12204530273dSValentin Clement (バレンタイン クレメン) 
12214530273dSValentin Clement (バレンタイン クレメン)   mlir::Type structTy = typeConverter.convertBoxTypeAsStruct(boxTy);
12224530273dSValentin Clement (バレンタイン クレメン)   std::size_t boxSize = dl->getTypeSizeInBits(structTy) / 8;
12234530273dSValentin Clement (バレンタイン クレメン)   mlir::Value sizeInBytes =
12244530273dSValentin Clement (バレンタイン クレメン)       genConstantIndex(loc, llvmIntPtrType, rewriter, boxSize);
12254530273dSValentin Clement (バレンタイン クレメン)   llvm::SmallVector args = {sizeInBytes, sourceFile, sourceLine};
12264530273dSValentin Clement (バレンタイン クレメン)   return rewriter
1227e650ac16SValentin Clement (バレンタイン クレメン)       .create<mlir::LLVM::CallOp>(loc, fctTy, RTNAME_STRING(CUFAllocDescriptor),
12284530273dSValentin Clement (バレンタイン クレメン)                                   args)
12294530273dSValentin Clement (バレンタイン クレメン)       .getResult();
12304530273dSValentin Clement (バレンタイン クレメン) }
12314530273dSValentin Clement (バレンタイン クレメン) 
1232af6ee580SValentin Clement /// Common base class for embox to descriptor conversion.
1233af6ee580SValentin Clement template <typename OP>
1234e9639e9cSValentin Clement (バレンタイン クレメン) struct EmboxCommonConversion : public fir::FIROpConversion<OP> {
1235e9639e9cSValentin Clement (バレンタイン クレメン)   using fir::FIROpConversion<OP>::FIROpConversion;
1236e9639e9cSValentin Clement (バレンタイン クレメン)   using TypePair = typename fir::FIROpConversion<OP>::TypePair;
1237af6ee580SValentin Clement 
12386e85b880SValentin Clement   static int getCFIAttr(fir::BaseBoxType boxTy) {
1239af6ee580SValentin Clement     auto eleTy = boxTy.getEleTy();
1240fac349a1SChristian Sigg     if (mlir::isa<fir::PointerType>(eleTy))
1241af6ee580SValentin Clement       return CFI_attribute_pointer;
1242fac349a1SChristian Sigg     if (mlir::isa<fir::HeapType>(eleTy))
1243af6ee580SValentin Clement       return CFI_attribute_allocatable;
1244af6ee580SValentin Clement     return CFI_attribute_other;
1245af6ee580SValentin Clement   }
1246af6ee580SValentin Clement 
1247b881fc27SJean Perier   mlir::Value getCharacterByteSize(mlir::Location loc,
1248b881fc27SJean Perier                                    mlir::ConversionPatternRewriter &rewriter,
1249b881fc27SJean Perier                                    fir::CharacterType charTy,
1250b881fc27SJean Perier                                    mlir::ValueRange lenParams) const {
1251b881fc27SJean Perier     auto i64Ty = mlir::IntegerType::get(rewriter.getContext(), 64);
1252b881fc27SJean Perier     mlir::Value size =
1253b881fc27SJean Perier         genTypeStrideInBytes(loc, i64Ty, rewriter, this->convertType(charTy));
1254b881fc27SJean Perier     if (charTy.hasConstantLen())
1255b881fc27SJean Perier       return size; // Length accounted for in the genTypeStrideInBytes GEP.
1256b881fc27SJean Perier     // Otherwise,  multiply the single character size by the length.
1257b881fc27SJean Perier     assert(!lenParams.empty());
1258e9639e9cSValentin Clement (バレンタイン クレメン)     auto len64 = fir::FIROpConversion<OP>::integerCast(loc, rewriter, i64Ty,
1259b881fc27SJean Perier                                                        lenParams.back());
1260b881fc27SJean Perier     return rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, size, len64);
1261b881fc27SJean Perier   }
1262b881fc27SJean Perier 
1263af6ee580SValentin Clement   // Get the element size and CFI type code of the boxed value.
1264af6ee580SValentin Clement   std::tuple<mlir::Value, mlir::Value> getSizeAndTypeCode(
1265af6ee580SValentin Clement       mlir::Location loc, mlir::ConversionPatternRewriter &rewriter,
1266af6ee580SValentin Clement       mlir::Type boxEleTy, mlir::ValueRange lenParams = {}) const {
126702f3fec3SSlava Zakharin     auto i64Ty = mlir::IntegerType::get(rewriter.getContext(), 64);
1268bddd7a64SV Donaldson     if (auto eleTy = fir::dyn_cast_ptrEleTy(boxEleTy))
1269bddd7a64SV Donaldson       boxEleTy = eleTy;
1270fac349a1SChristian Sigg     if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(boxEleTy))
1271bddd7a64SV Donaldson       return getSizeAndTypeCode(loc, rewriter, seqTy.getEleTy(), lenParams);
1272fac349a1SChristian Sigg     if (mlir::isa<mlir::NoneType>(
1273fac349a1SChristian Sigg             boxEleTy)) // unlimited polymorphic or assumed type
1274bddd7a64SV Donaldson       return {rewriter.create<mlir::LLVM::ConstantOp>(loc, i64Ty, 0),
1275bddd7a64SV Donaldson               this->genConstantOffset(loc, rewriter, CFI_type_other)};
1276bddd7a64SV Donaldson     mlir::Value typeCodeVal = this->genConstantOffset(
1277bddd7a64SV Donaldson         loc, rewriter,
1278bddd7a64SV Donaldson         fir::getTypeCode(boxEleTy, this->lowerTy().getKindMap()));
1279fac349a1SChristian Sigg     if (fir::isa_integer(boxEleTy) ||
1280fac349a1SChristian Sigg         mlir::dyn_cast<fir::LogicalType>(boxEleTy) || fir::isa_real(boxEleTy) ||
1281fac349a1SChristian Sigg         fir::isa_complex(boxEleTy))
1282bddd7a64SV Donaldson       return {genTypeStrideInBytes(loc, i64Ty, rewriter,
1283bddd7a64SV Donaldson                                    this->convertType(boxEleTy)),
1284bddd7a64SV Donaldson               typeCodeVal};
1285fac349a1SChristian Sigg     if (auto charTy = mlir::dyn_cast<fir::CharacterType>(boxEleTy))
1286b881fc27SJean Perier       return {getCharacterByteSize(loc, rewriter, charTy, lenParams),
1287b881fc27SJean Perier               typeCodeVal};
1288af6ee580SValentin Clement     if (fir::isa_ref_type(boxEleTy)) {
12898a1ce2d6SjeanPerier       auto ptrTy = ::getLlvmPtrType(rewriter.getContext());
1290bddd7a64SV Donaldson       return {genTypeStrideInBytes(loc, i64Ty, rewriter, ptrTy), typeCodeVal};
1291af6ee580SValentin Clement     }
1292fac349a1SChristian Sigg     if (mlir::isa<fir::RecordType>(boxEleTy))
1293bddd7a64SV Donaldson       return {genTypeStrideInBytes(loc, i64Ty, rewriter,
1294bddd7a64SV Donaldson                                    this->convertType(boxEleTy)),
1295bddd7a64SV Donaldson               typeCodeVal};
1296af6ee580SValentin Clement     fir::emitFatalError(loc, "unhandled type in fir.box code generation");
1297af6ee580SValentin Clement   }
1298af6ee580SValentin Clement 
1299af6ee580SValentin Clement   /// Basic pattern to write a field in the descriptor
1300af6ee580SValentin Clement   mlir::Value insertField(mlir::ConversionPatternRewriter &rewriter,
1301af6ee580SValentin Clement                           mlir::Location loc, mlir::Value dest,
13025c5af910SJeff Niu                           llvm::ArrayRef<std::int64_t> fldIndexes,
130344e58509SEric Schweitz                           mlir::Value value, bool bitcast = false) const {
1304af6ee580SValentin Clement     auto boxTy = dest.getType();
1305af6ee580SValentin Clement     auto fldTy = this->getBoxEleTy(boxTy, fldIndexes);
13068a1ce2d6SjeanPerier     if (!bitcast)
1307af6ee580SValentin Clement       value = this->integerCast(loc, rewriter, fldTy, value);
13088a1ce2d6SjeanPerier     // bitcast are no-ops with LLVM opaque pointers.
13095c5af910SJeff Niu     return rewriter.create<mlir::LLVM::InsertValueOp>(loc, dest, value,
13105c5af910SJeff Niu                                                       fldIndexes);
1311af6ee580SValentin Clement   }
1312af6ee580SValentin Clement 
1313af6ee580SValentin Clement   inline mlir::Value
1314af6ee580SValentin Clement   insertBaseAddress(mlir::ConversionPatternRewriter &rewriter,
1315af6ee580SValentin Clement                     mlir::Location loc, mlir::Value dest,
1316af6ee580SValentin Clement                     mlir::Value base) const {
13171f551032SValentin Clement     return insertField(rewriter, loc, dest, {kAddrPosInBox}, base,
13181f551032SValentin Clement                        /*bitCast=*/true);
13191f551032SValentin Clement   }
13201f551032SValentin Clement 
13211f551032SValentin Clement   inline mlir::Value insertLowerBound(mlir::ConversionPatternRewriter &rewriter,
13221f551032SValentin Clement                                       mlir::Location loc, mlir::Value dest,
13231f551032SValentin Clement                                       unsigned dim, mlir::Value lb) const {
13241f551032SValentin Clement     return insertField(rewriter, loc, dest,
13251f551032SValentin Clement                        {kDimsPosInBox, dim, kDimLowerBoundPos}, lb);
13261f551032SValentin Clement   }
13271f551032SValentin Clement 
13281f551032SValentin Clement   inline mlir::Value insertExtent(mlir::ConversionPatternRewriter &rewriter,
13291f551032SValentin Clement                                   mlir::Location loc, mlir::Value dest,
13301f551032SValentin Clement                                   unsigned dim, mlir::Value extent) const {
13311f551032SValentin Clement     return insertField(rewriter, loc, dest, {kDimsPosInBox, dim, kDimExtentPos},
13321f551032SValentin Clement                        extent);
13331f551032SValentin Clement   }
13341f551032SValentin Clement 
13351f551032SValentin Clement   inline mlir::Value insertStride(mlir::ConversionPatternRewriter &rewriter,
13361f551032SValentin Clement                                   mlir::Location loc, mlir::Value dest,
13371f551032SValentin Clement                                   unsigned dim, mlir::Value stride) const {
13381f551032SValentin Clement     return insertField(rewriter, loc, dest, {kDimsPosInBox, dim, kDimStridePos},
13391f551032SValentin Clement                        stride);
1340af6ee580SValentin Clement   }
1341af6ee580SValentin Clement 
1342af6ee580SValentin Clement   /// Get the address of the type descriptor global variable that was created by
1343af6ee580SValentin Clement   /// lowering for derived type \p recType.
1344e93d2266SValentin Clement (バレンタイン クレメン)   template <typename ModOpTy>
1345e93d2266SValentin Clement (バレンタイン クレメン)   mlir::Value
1346e93d2266SValentin Clement (バレンタイン クレメン)   getTypeDescriptor(ModOpTy mod, mlir::ConversionPatternRewriter &rewriter,
1347e93d2266SValentin Clement (バレンタイン クレメン)                     mlir::Location loc, fir::RecordType recType) const {
1348013160f6SJean Perier     std::string name =
1349cfd4c180SSlava Zakharin         this->options.typeDescriptorsRenamedForAssembly
1350cfd4c180SSlava Zakharin             ? fir::NameUniquer::getTypeDescriptorAssemblyName(recType.getName())
1351cfd4c180SSlava Zakharin             : fir::NameUniquer::getTypeDescriptorName(recType.getName());
13528a1ce2d6SjeanPerier     mlir::Type llvmPtrTy = ::getLlvmPtrType(mod.getContext());
1353c1b7e9c9SValentin Clement     if (auto global = mod.template lookupSymbol<fir::GlobalOp>(name)) {
13548a1ce2d6SjeanPerier       return rewriter.create<mlir::LLVM::AddressOfOp>(loc, llvmPtrTy,
1355feeee78aSJacques Pienaar                                                       global.getSymName());
1356af6ee580SValentin Clement     }
1357c1b7e9c9SValentin Clement     if (auto global = mod.template lookupSymbol<mlir::LLVM::GlobalOp>(name)) {
1358af6ee580SValentin Clement       // The global may have already been translated to LLVM.
13598a1ce2d6SjeanPerier       return rewriter.create<mlir::LLVM::AddressOfOp>(loc, llvmPtrTy,
1360feeee78aSJacques Pienaar                                                       global.getSymName());
1361af6ee580SValentin Clement     }
13627dd7ccd2SJean Perier     // Type info derived types do not have type descriptors since they are the
13637dd7ccd2SJean Perier     // types defining type descriptors.
1364013160f6SJean Perier     if (!this->options.ignoreMissingTypeDescriptors &&
1365013160f6SJean Perier         !fir::NameUniquer::belongsToModule(
1366013160f6SJean Perier             name, Fortran::semantics::typeInfoBuiltinModule))
1367013160f6SJean Perier       fir::emitFatalError(
1368013160f6SJean Perier           loc, "runtime derived type info descriptor was not generated");
13698a1ce2d6SjeanPerier     return rewriter.create<mlir::LLVM::ZeroOp>(loc, llvmPtrTy);
13707dd7ccd2SJean Perier   }
1371af6ee580SValentin Clement 
1372e93d2266SValentin Clement (バレンタイン クレメン)   template <typename ModOpTy>
1373e93d2266SValentin Clement (バレンタイン クレメン)   mlir::Value populateDescriptor(mlir::Location loc, ModOpTy mod,
1374c1b7e9c9SValentin Clement                                  fir::BaseBoxType boxTy, mlir::Type inputType,
1375c1b7e9c9SValentin Clement                                  mlir::ConversionPatternRewriter &rewriter,
1376c1b7e9c9SValentin Clement                                  unsigned rank, mlir::Value eleSize,
13770def9a92SValentin Clement (バレンタイン クレメン)                                  mlir::Value cfiTy, mlir::Value typeDesc,
137815e1e3b2SValentin Clement (バレンタイン クレメン)                                  int allocatorIdx = kDefaultAllocator,
137915e1e3b2SValentin Clement (バレンタイン クレメン)                                  mlir::Value extraField = {}) const {
13808a1ce2d6SjeanPerier     auto llvmBoxTy = this->lowerTy().convertBoxTypeAsStruct(boxTy, rank);
1381c1b7e9c9SValentin Clement     bool isUnlimitedPolymorphic = fir::isUnlimitedPolymorphicType(boxTy);
1382c97d3e5fSValentin Clement     bool useInputType = fir::isPolymorphicType(boxTy) || isUnlimitedPolymorphic;
1383af6ee580SValentin Clement     mlir::Value descriptor =
1384af6ee580SValentin Clement         rewriter.create<mlir::LLVM::UndefOp>(loc, llvmBoxTy);
1385af6ee580SValentin Clement     descriptor =
1386af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kElemLenPosInBox}, eleSize);
1387af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kVersionPosInBox},
1388af6ee580SValentin Clement                              this->genI32Constant(loc, rewriter, CFI_VERSION));
1389af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kRankPosInBox},
1390af6ee580SValentin Clement                              this->genI32Constant(loc, rewriter, rank));
1391af6ee580SValentin Clement     descriptor = insertField(rewriter, loc, descriptor, {kTypePosInBox}, cfiTy);
1392af6ee580SValentin Clement     descriptor =
1393af6ee580SValentin Clement         insertField(rewriter, loc, descriptor, {kAttributePosInBox},
1394af6ee580SValentin Clement                     this->genI32Constant(loc, rewriter, getCFIAttr(boxTy)));
13956df4e7c2SValentin Clement (バレンタイン クレメン) 
13960538bfe7SRenaud-K     const bool hasAddendum = fir::boxHasAddendum(boxTy);
13970def9a92SValentin Clement (バレンタイン クレメン) 
139815e1e3b2SValentin Clement (バレンタイン クレメン)     if (extraField) {
139915e1e3b2SValentin Clement (バレンタイン クレメン)       // Make sure to set the addendum presence flag according to the
140015e1e3b2SValentin Clement (バレンタイン クレメン)       // destination box.
140115e1e3b2SValentin Clement (バレンタイン クレメン)       if (hasAddendum) {
140215e1e3b2SValentin Clement (バレンタイン クレメン)         auto maskAttr = mlir::IntegerAttr::get(
140315e1e3b2SValentin Clement (バレンタイン クレメン)             rewriter.getIntegerType(8, /*isSigned=*/false),
140415e1e3b2SValentin Clement (バレンタイン クレメン)             llvm::APInt(8, (uint64_t)_CFI_ADDENDUM_FLAG, /*isSigned=*/false));
140515e1e3b2SValentin Clement (バレンタイン クレメン)         mlir::LLVM::ConstantOp mask = rewriter.create<mlir::LLVM::ConstantOp>(
140615e1e3b2SValentin Clement (バレンタイン クレメン)             loc, rewriter.getI8Type(), maskAttr);
140715e1e3b2SValentin Clement (バレンタイン クレメン)         extraField = rewriter.create<mlir::LLVM::OrOp>(loc, extraField, mask);
140815e1e3b2SValentin Clement (バレンタイン クレメン)       } else {
140915e1e3b2SValentin Clement (バレンタイン クレメン)         auto maskAttr = mlir::IntegerAttr::get(
141015e1e3b2SValentin Clement (バレンタイン クレメン)             rewriter.getIntegerType(8, /*isSigned=*/false),
141167e19e5bSNikita Popov             llvm::APInt(8, (uint64_t)~_CFI_ADDENDUM_FLAG, /*isSigned=*/true));
141215e1e3b2SValentin Clement (バレンタイン クレメン)         mlir::LLVM::ConstantOp mask = rewriter.create<mlir::LLVM::ConstantOp>(
141315e1e3b2SValentin Clement (バレンタイン クレメン)             loc, rewriter.getI8Type(), maskAttr);
141415e1e3b2SValentin Clement (バレンタイン クレメン)         extraField = rewriter.create<mlir::LLVM::AndOp>(loc, extraField, mask);
141515e1e3b2SValentin Clement (バレンタイン クレメン)       }
141615e1e3b2SValentin Clement (バレンタイン クレメン)       // Extra field value is provided so just use it.
141715e1e3b2SValentin Clement (バレンタイン クレメン)       descriptor =
141815e1e3b2SValentin Clement (バレンタイン クレメン)           insertField(rewriter, loc, descriptor, {kExtraPosInBox}, extraField);
141915e1e3b2SValentin Clement (バレンタイン クレメン)     } else {
142015e1e3b2SValentin Clement (バレンタイン クレメン)       // Compute the value of the extra field based on allocator_idx and
1421c91ba043SMichael Kruse       // addendum present.
1422c91ba043SMichael Kruse       unsigned extra = allocatorIdx << _CFI_ALLOCATOR_IDX_SHIFT;
14230def9a92SValentin Clement (バレンタイン クレメン)       if (hasAddendum)
1424c91ba043SMichael Kruse         extra |= _CFI_ADDENDUM_FLAG;
1425c91ba043SMichael Kruse       descriptor = insertField(rewriter, loc, descriptor, {kExtraPosInBox},
1426c91ba043SMichael Kruse                                this->genI32Constant(loc, rewriter, extra));
142715e1e3b2SValentin Clement (バレンタイン クレメン)     }
1428af6ee580SValentin Clement 
1429af6ee580SValentin Clement     if (hasAddendum) {
1430016fbc40SValentin Clement       unsigned typeDescFieldId = getTypeDescFieldId(boxTy);
1431c1b7e9c9SValentin Clement       if (!typeDesc) {
1432c97d3e5fSValentin Clement         if (useInputType) {
1433c1b7e9c9SValentin Clement           mlir::Type innerType = fir::unwrapInnerType(inputType);
1434fac349a1SChristian Sigg           if (innerType && mlir::isa<fir::RecordType>(innerType)) {
1435fac349a1SChristian Sigg             auto recTy = mlir::dyn_cast<fir::RecordType>(innerType);
1436c1b7e9c9SValentin Clement             typeDesc = getTypeDescriptor(mod, rewriter, loc, recTy);
1437c1b7e9c9SValentin Clement           } else {
1438c1b7e9c9SValentin Clement             // Unlimited polymorphic type descriptor with no record type. Set
1439c1b7e9c9SValentin Clement             // type descriptor address to a clean state.
144085175eddSTobias Gysi             typeDesc = rewriter.create<mlir::LLVM::ZeroOp>(
14418a1ce2d6SjeanPerier                 loc, ::getLlvmPtrType(mod.getContext()));
1442c1b7e9c9SValentin Clement           }
1443c1b7e9c9SValentin Clement         } else {
14440538bfe7SRenaud-K           typeDesc = getTypeDescriptor(mod, rewriter, loc,
14450538bfe7SRenaud-K                                        fir::unwrapIfDerived(boxTy));
1446c1b7e9c9SValentin Clement         }
1447c1b7e9c9SValentin Clement       }
1448c1b7e9c9SValentin Clement       if (typeDesc)
1449af6ee580SValentin Clement         descriptor =
1450af6ee580SValentin Clement             insertField(rewriter, loc, descriptor, {typeDescFieldId}, typeDesc,
1451af6ee580SValentin Clement                         /*bitCast=*/true);
1452d26a6464SjeanPerier       // Always initialize the length parameter field to zero to avoid issues
1453d26a6464SjeanPerier       // with uninitialized values in Fortran code trying to compare physical
1454d26a6464SjeanPerier       // representation of derived types with pointer/allocatable components.
1455d26a6464SjeanPerier       // This has been seen in hashing algorithms using TRANSFER.
1456d26a6464SjeanPerier       mlir::Value zero =
1457d26a6464SjeanPerier           genConstantIndex(loc, rewriter.getI64Type(), rewriter, 0);
1458d26a6464SjeanPerier       descriptor = insertField(rewriter, loc, descriptor,
1459d26a6464SjeanPerier                                {getLenParamFieldId(boxTy), 0}, zero);
1460af6ee580SValentin Clement     }
1461c1b7e9c9SValentin Clement     return descriptor;
1462c1b7e9c9SValentin Clement   }
1463c1b7e9c9SValentin Clement 
1464c1b7e9c9SValentin Clement   // Template used for fir::EmboxOp and fir::cg::XEmboxOp
1465c1b7e9c9SValentin Clement   template <typename BOX>
1466c1b7e9c9SValentin Clement   std::tuple<fir::BaseBoxType, mlir::Value, mlir::Value>
1467c1b7e9c9SValentin Clement   consDescriptorPrefix(BOX box, mlir::Type inputType,
1468c1b7e9c9SValentin Clement                        mlir::ConversionPatternRewriter &rewriter, unsigned rank,
1469a45ca5d9SSlava Zakharin                        [[maybe_unused]] mlir::ValueRange substrParams,
14709f1bb307SValentin Clement                        mlir::ValueRange lenParams, mlir::Value sourceBox = {},
14719f1bb307SValentin Clement                        mlir::Type sourceBoxType = {}) const {
1472c1b7e9c9SValentin Clement     auto loc = box.getLoc();
1473fac349a1SChristian Sigg     auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(box.getType());
1474a6924c6dSValentin Clement     bool useInputType = fir::isPolymorphicType(boxTy) &&
1475a6924c6dSValentin Clement                         !fir::isUnlimitedPolymorphicType(inputType);
1476c1b7e9c9SValentin Clement     llvm::SmallVector<mlir::Value> typeparams = lenParams;
1477c1b7e9c9SValentin Clement     if constexpr (!std::is_same_v<BOX, fir::EmboxOp>) {
1478c1b7e9c9SValentin Clement       if (!box.getSubstr().empty() && fir::hasDynamicSize(boxTy.getEleTy()))
1479a45ca5d9SSlava Zakharin         typeparams.push_back(substrParams[1]);
1480c1b7e9c9SValentin Clement     }
1481c1b7e9c9SValentin Clement 
14820def9a92SValentin Clement (バレンタイン クレメン)     int allocatorIdx = 0;
14830def9a92SValentin Clement (バレンタイン クレメン)     if constexpr (std::is_same_v<BOX, fir::EmboxOp> ||
14840def9a92SValentin Clement (バレンタイン クレメン)                   std::is_same_v<BOX, fir::cg::XEmboxOp>) {
14850def9a92SValentin Clement (バレンタイン クレメン)       if (box.getAllocatorIdx())
14860def9a92SValentin Clement (バレンタイン クレメン)         allocatorIdx = *box.getAllocatorIdx();
14870def9a92SValentin Clement (バレンタイン クレメン)     }
14880def9a92SValentin Clement (バレンタイン クレメン) 
1489c1b7e9c9SValentin Clement     // Write each of the fields with the appropriate values.
1490a6924c6dSValentin Clement     // When emboxing an element to a polymorphic descriptor, use the
1491a6924c6dSValentin Clement     // input type since the destination descriptor type has not the exact
1492a6924c6dSValentin Clement     // information.
1493c1b7e9c9SValentin Clement     auto [eleSize, cfiTy] = getSizeAndTypeCode(
1494c1b7e9c9SValentin Clement         loc, rewriter, useInputType ? inputType : boxTy.getEleTy(), typeparams);
1495747211b7SValentin Clement 
14969f1bb307SValentin Clement     mlir::Value typeDesc;
149715e1e3b2SValentin Clement (バレンタイン クレメン)     mlir::Value extraField;
14980b19ac83SValentin Clement     // When emboxing to a polymorphic box, get the type descriptor, type code
14990b19ac83SValentin Clement     // and element size from the source box if any.
15000b19ac83SValentin Clement     if (fir::isPolymorphicType(boxTy) && sourceBox) {
15018a1ce2d6SjeanPerier       TypePair sourceBoxTyPair = this->getBoxTypePair(sourceBoxType);
15029f1bb307SValentin Clement       typeDesc =
15038a1ce2d6SjeanPerier           this->loadTypeDescAddress(loc, sourceBoxTyPair, sourceBox, rewriter);
1504747211b7SValentin Clement       mlir::Type idxTy = this->lowerTy().indexType();
15058a1ce2d6SjeanPerier       eleSize = this->getElementSizeFromBox(loc, idxTy, sourceBoxTyPair,
15069c84d20fSSlava Zakharin                                             sourceBox, rewriter);
15078a1ce2d6SjeanPerier       cfiTy = this->getValueFromBox(loc, sourceBoxTyPair, sourceBox,
15089c84d20fSSlava Zakharin                                     cfiTy.getType(), rewriter, kTypePosInBox);
150915e1e3b2SValentin Clement (バレンタイン クレメン)       extraField =
151015e1e3b2SValentin Clement (バレンタイン クレメン)           this->getExtraFromBox(loc, sourceBoxTyPair, sourceBox, rewriter);
1511747211b7SValentin Clement     }
1512e93d2266SValentin Clement (バレンタイン クレメン) 
1513e93d2266SValentin Clement (バレンタイン クレメン)     mlir::Value descriptor;
1514e93d2266SValentin Clement (バレンタイン クレメン)     if (auto gpuMod = box->template getParentOfType<mlir::gpu::GPUModuleOp>())
1515e93d2266SValentin Clement (バレンタイン クレメン)       descriptor = populateDescriptor(loc, gpuMod, boxTy, inputType, rewriter,
1516e93d2266SValentin Clement (バレンタイン クレメン)                                       rank, eleSize, cfiTy, typeDesc,
1517e93d2266SValentin Clement (バレンタイン クレメン)                                       allocatorIdx, extraField);
1518e93d2266SValentin Clement (バレンタイン クレメン)     else if (auto mod = box->template getParentOfType<mlir::ModuleOp>())
1519e93d2266SValentin Clement (バレンタイン クレメン)       descriptor = populateDescriptor(loc, mod, boxTy, inputType, rewriter,
1520e93d2266SValentin Clement (バレンタイン クレメン)                                       rank, eleSize, cfiTy, typeDesc,
1521e93d2266SValentin Clement (バレンタイン クレメン)                                       allocatorIdx, extraField);
1522c1b7e9c9SValentin Clement 
1523c1b7e9c9SValentin Clement     return {boxTy, descriptor, eleSize};
1524c1b7e9c9SValentin Clement   }
1525c1b7e9c9SValentin Clement 
1526c1b7e9c9SValentin Clement   std::tuple<fir::BaseBoxType, mlir::Value, mlir::Value>
1527c1b7e9c9SValentin Clement   consDescriptorPrefix(fir::cg::XReboxOp box, mlir::Value loweredBox,
1528c1b7e9c9SValentin Clement                        mlir::ConversionPatternRewriter &rewriter, unsigned rank,
1529a45ca5d9SSlava Zakharin                        mlir::ValueRange substrParams,
1530c1b7e9c9SValentin Clement                        mlir::ValueRange lenParams,
1531c1b7e9c9SValentin Clement                        mlir::Value typeDesc = {}) const {
1532c1b7e9c9SValentin Clement     auto loc = box.getLoc();
1533fac349a1SChristian Sigg     auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(box.getType());
1534fac349a1SChristian Sigg     auto inputBoxTy = mlir::dyn_cast<fir::BaseBoxType>(box.getBox().getType());
15358a1ce2d6SjeanPerier     auto inputBoxTyPair = this->getBoxTypePair(inputBoxTy);
1536c1b7e9c9SValentin Clement     llvm::SmallVector<mlir::Value> typeparams = lenParams;
1537c1b7e9c9SValentin Clement     if (!box.getSubstr().empty() && fir::hasDynamicSize(boxTy.getEleTy()))
1538a45ca5d9SSlava Zakharin       typeparams.push_back(substrParams[1]);
1539c1b7e9c9SValentin Clement 
1540c1b7e9c9SValentin Clement     auto [eleSize, cfiTy] =
1541c1b7e9c9SValentin Clement         getSizeAndTypeCode(loc, rewriter, boxTy.getEleTy(), typeparams);
1542c1b7e9c9SValentin Clement 
1543959caaaaSValentin Clement     // Reboxing to a polymorphic entity. eleSize and type code need to
1544f3a94ff0SValentin Clement     // be retrieved from the initial box and propagated to the new box.
1545959caaaaSValentin Clement     // If the initial box has an addendum, the type desc must be propagated as
1546959caaaaSValentin Clement     // well.
1547959caaaaSValentin Clement     if (fir::isPolymorphicType(boxTy)) {
1548c1b7e9c9SValentin Clement       mlir::Type idxTy = this->lowerTy().indexType();
15498a1ce2d6SjeanPerier       eleSize = this->getElementSizeFromBox(loc, idxTy, inputBoxTyPair,
15508a1ce2d6SjeanPerier                                             loweredBox, rewriter);
15518a1ce2d6SjeanPerier       cfiTy = this->getValueFromBox(loc, inputBoxTyPair, loweredBox,
15528a1ce2d6SjeanPerier                                     cfiTy.getType(), rewriter, kTypePosInBox);
1553959caaaaSValentin Clement       // TODO: For initial box that are unlimited polymorphic entities, this
1554959caaaaSValentin Clement       // code must be made conditional because unlimited polymorphic entities
1555959caaaaSValentin Clement       // with intrinsic type spec does not have addendum.
15560538bfe7SRenaud-K       if (fir::boxHasAddendum(inputBoxTy))
15578a1ce2d6SjeanPerier         typeDesc = this->loadTypeDescAddress(loc, inputBoxTyPair, loweredBox,
15588a1ce2d6SjeanPerier                                              rewriter);
1559c1b7e9c9SValentin Clement     }
1560c1b7e9c9SValentin Clement 
156115e1e3b2SValentin Clement (バレンタイン クレメン)     mlir::Value extraField =
156215e1e3b2SValentin Clement (バレンタイン クレメン)         this->getExtraFromBox(loc, inputBoxTyPair, loweredBox, rewriter);
156315e1e3b2SValentin Clement (バレンタイン クレメン) 
1564e93d2266SValentin Clement (バレンタイン クレメン)     mlir::Value descriptor;
1565e93d2266SValentin Clement (バレンタイン クレメン)     if (auto gpuMod = box->template getParentOfType<mlir::gpu::GPUModuleOp>())
1566e93d2266SValentin Clement (バレンタイン クレメン)       descriptor =
1567e93d2266SValentin Clement (バレンタイン クレメン)           populateDescriptor(loc, gpuMod, boxTy, box.getBox().getType(),
1568e93d2266SValentin Clement (バレンタイン クレメン)                              rewriter, rank, eleSize, cfiTy, typeDesc,
1569e93d2266SValentin Clement (バレンタイン クレメン)                              /*allocatorIdx=*/kDefaultAllocator, extraField);
1570e93d2266SValentin Clement (バレンタイン クレメン)     else if (auto mod = box->template getParentOfType<mlir::ModuleOp>())
1571e93d2266SValentin Clement (バレンタイン クレメン)       descriptor =
1572c1b7e9c9SValentin Clement           populateDescriptor(loc, mod, boxTy, box.getBox().getType(), rewriter,
157315e1e3b2SValentin Clement (バレンタイン クレメン)                              rank, eleSize, cfiTy, typeDesc,
157415e1e3b2SValentin Clement (バレンタイン クレメン)                              /*allocatorIdx=*/kDefaultAllocator, extraField);
1575af6ee580SValentin Clement 
1576af6ee580SValentin Clement     return {boxTy, descriptor, eleSize};
1577af6ee580SValentin Clement   }
1578af6ee580SValentin Clement 
1579af40f99eSJean Perier   // Compute the base address of a fir.box given the indices from the slice.
1580af40f99eSJean Perier   // The indices from the "outer" dimensions (every dimension after the first
15818a1ce2d6SjeanPerier   // one (included) that is not a compile time constant) must have been
1582af40f99eSJean Perier   // multiplied with the related extents and added together into \p outerOffset.
1583af40f99eSJean Perier   mlir::Value
1584af40f99eSJean Perier   genBoxOffsetGep(mlir::ConversionPatternRewriter &rewriter, mlir::Location loc,
15858a1ce2d6SjeanPerier                   mlir::Value base, mlir::Type llvmBaseObjectType,
15868a1ce2d6SjeanPerier                   mlir::Value outerOffset, mlir::ValueRange cstInteriorIndices,
1587af40f99eSJean Perier                   mlir::ValueRange componentIndices,
158822426110SRamkumar Ramachandra                   std::optional<mlir::Value> substringOffset) const {
1589bd7eff1fSMarkus Böck     llvm::SmallVector<mlir::LLVM::GEPArg> gepArgs{outerOffset};
15908a1ce2d6SjeanPerier     mlir::Type resultTy = llvmBaseObjectType;
1591af40f99eSJean Perier     // Fortran is column major, llvm GEP is row major: reverse the indices here.
1592af40f99eSJean Perier     for (mlir::Value interiorIndex : llvm::reverse(cstInteriorIndices)) {
1593fac349a1SChristian Sigg       auto arrayTy = mlir::dyn_cast<mlir::LLVM::LLVMArrayType>(resultTy);
1594af40f99eSJean Perier       if (!arrayTy)
1595af40f99eSJean Perier         fir::emitFatalError(
1596af40f99eSJean Perier             loc,
1597af40f99eSJean Perier             "corrupted GEP generated being generated in fir.embox/fir.rebox");
1598af40f99eSJean Perier       resultTy = arrayTy.getElementType();
1599af40f99eSJean Perier       gepArgs.push_back(interiorIndex);
16006c89c531SEric Schweitz     }
1601783222efSLeandro Lupori     llvm::SmallVector<mlir::Value> gepIndices =
1602783222efSLeandro Lupori         convertSubcomponentIndices(loc, resultTy, componentIndices, &resultTy);
1603783222efSLeandro Lupori     gepArgs.append(gepIndices.begin(), gepIndices.end());
1604af40f99eSJean Perier     if (substringOffset) {
1605fac349a1SChristian Sigg       if (auto arrayTy = mlir::dyn_cast<mlir::LLVM::LLVMArrayType>(resultTy)) {
1606af40f99eSJean Perier         gepArgs.push_back(*substringOffset);
1607af40f99eSJean Perier         resultTy = arrayTy.getElementType();
1608af40f99eSJean Perier       } else {
1609af40f99eSJean Perier         // If the CHARACTER length is dynamic, the whole base type should have
1610af40f99eSJean Perier         // degenerated to an llvm.ptr<i[width]>, and there should not be any
1611af40f99eSJean Perier         // cstInteriorIndices/componentIndices. The substring offset can be
1612af40f99eSJean Perier         // added to the outterOffset since it applies on the same LLVM type.
1613af40f99eSJean Perier         if (gepArgs.size() != 1)
1614af40f99eSJean Perier           fir::emitFatalError(loc,
1615af40f99eSJean Perier                               "corrupted substring GEP in fir.embox/fir.rebox");
1616392651a7SKazu Hirata         mlir::Type outterOffsetTy =
1617392651a7SKazu Hirata             llvm::cast<mlir::Value>(gepArgs[0]).getType();
1618af40f99eSJean Perier         mlir::Value cast =
1619af40f99eSJean Perier             this->integerCast(loc, rewriter, outterOffsetTy, *substringOffset);
1620af40f99eSJean Perier 
1621bd7eff1fSMarkus Böck         gepArgs[0] = rewriter.create<mlir::LLVM::AddOp>(
1622392651a7SKazu Hirata             loc, outterOffsetTy, llvm::cast<mlir::Value>(gepArgs[0]), cast);
1623af40f99eSJean Perier       }
1624af40f99eSJean Perier     }
16258a1ce2d6SjeanPerier     mlir::Type llvmPtrTy = ::getLlvmPtrType(resultTy.getContext());
16268a1ce2d6SjeanPerier     return rewriter.create<mlir::LLVM::GEPOp>(
16278a1ce2d6SjeanPerier         loc, llvmPtrTy, llvmBaseObjectType, base, gepArgs);
1628af40f99eSJean Perier   }
1629af40f99eSJean Perier 
1630af40f99eSJean Perier   template <typename BOX>
1631af40f99eSJean Perier   void
1632af40f99eSJean Perier   getSubcomponentIndices(BOX xbox, mlir::Value memref,
1633af40f99eSJean Perier                          mlir::ValueRange operands,
1634af40f99eSJean Perier                          mlir::SmallVectorImpl<mlir::Value> &indices) const {
1635af40f99eSJean Perier     // For each field in the path add the offset to base via the args list.
1636af40f99eSJean Perier     // In the most general case, some offsets must be computed since
1637af40f99eSJean Perier     // they are not be known until runtime.
1638af40f99eSJean Perier     if (fir::hasDynamicSize(fir::unwrapSequenceType(
1639af40f99eSJean Perier             fir::unwrapPassByRefType(memref.getType()))))
1640af40f99eSJean Perier       TODO(xbox.getLoc(),
1641af40f99eSJean Perier            "fir.embox codegen dynamic size component in derived type");
1642d8b672daSjeanPerier     indices.append(operands.begin() + xbox.getSubcomponentOperandIndex(),
1643d8b672daSjeanPerier                    operands.begin() + xbox.getSubcomponentOperandIndex() +
1644a89b0480SValentin Clement                        xbox.getSubcomponent().size());
16451f551032SValentin Clement   }
16461f551032SValentin Clement 
1647de2811eeSJean Perier   static bool isInGlobalOp(mlir::ConversionPatternRewriter &rewriter) {
1648de2811eeSJean Perier     auto *thisBlock = rewriter.getInsertionBlock();
1649de2811eeSJean Perier     return thisBlock &&
1650de2811eeSJean Perier            mlir::isa<mlir::LLVM::GlobalOp>(thisBlock->getParentOp());
1651de2811eeSJean Perier   }
1652de2811eeSJean Perier 
1653af6ee580SValentin Clement   /// If the embox is not in a globalOp body, allocate storage for the box;
1654af6ee580SValentin Clement   /// store the value inside and return the generated alloca. Return the input
1655af6ee580SValentin Clement   /// value otherwise.
1656af6ee580SValentin Clement   mlir::Value
1657af6ee580SValentin Clement   placeInMemoryIfNotGlobalInit(mlir::ConversionPatternRewriter &rewriter,
16589c84d20fSSlava Zakharin                                mlir::Location loc, mlir::Type boxTy,
16594530273dSValentin Clement (バレンタイン クレメン)                                mlir::Value boxValue,
16604530273dSValentin Clement (バレンタイン クレメン)                                bool needDeviceAllocation = false) const {
1661de2811eeSJean Perier     if (isInGlobalOp(rewriter))
1662af6ee580SValentin Clement       return boxValue;
16638a1ce2d6SjeanPerier     mlir::Type llvmBoxTy = boxValue.getType();
16644530273dSValentin Clement (バレンタイン クレメン)     mlir::Value storage;
16654530273dSValentin Clement (バレンタイン クレメン)     if (needDeviceAllocation) {
16664530273dSValentin Clement (バレンタイン クレメン)       auto mod = boxValue.getDefiningOp()->getParentOfType<mlir::ModuleOp>();
16674530273dSValentin Clement (バレンタイン クレメン)       auto baseBoxTy = mlir::dyn_cast<fir::BaseBoxType>(boxTy);
16684530273dSValentin Clement (バレンタイン クレメン)       storage =
16694530273dSValentin Clement (バレンタイン クレメン)           genCUFAllocDescriptor(loc, rewriter, mod, baseBoxTy, this->lowerTy());
16704530273dSValentin Clement (バレンタイン クレメン)     } else {
16714530273dSValentin Clement (バレンタイン クレメン)       storage = this->genAllocaAndAddrCastWithType(loc, llvmBoxTy, defaultAlign,
16724530273dSValentin Clement (バレンタイン クレメン)                                                    rewriter);
16734530273dSValentin Clement (バレンタイン クレメン)     }
16744530273dSValentin Clement (バレンタイン クレメン)     auto storeOp = rewriter.create<mlir::LLVM::StoreOp>(loc, boxValue, storage);
16759c84d20fSSlava Zakharin     this->attachTBAATag(storeOp, boxTy, boxTy, nullptr);
16764530273dSValentin Clement (バレンタイン クレメン)     return storage;
1677af6ee580SValentin Clement   }
1678af6ee580SValentin Clement 
16791f551032SValentin Clement   /// Compute the extent of a triplet slice (lb:ub:step).
1680*0b80491cSSlava Zakharin   mlir::Value computeTripletExtent(mlir::ConversionPatternRewriter &rewriter,
1681*0b80491cSSlava Zakharin                                    mlir::Location loc, mlir::Value lb,
1682*0b80491cSSlava Zakharin                                    mlir::Value ub, mlir::Value step,
1683*0b80491cSSlava Zakharin                                    mlir::Value zero, mlir::Type type) const {
1684*0b80491cSSlava Zakharin     lb = this->integerCast(loc, rewriter, type, lb);
1685*0b80491cSSlava Zakharin     ub = this->integerCast(loc, rewriter, type, ub);
1686*0b80491cSSlava Zakharin     step = this->integerCast(loc, rewriter, type, step);
1687*0b80491cSSlava Zakharin     zero = this->integerCast(loc, rewriter, type, zero);
16881f551032SValentin Clement     mlir::Value extent = rewriter.create<mlir::LLVM::SubOp>(loc, type, ub, lb);
16891f551032SValentin Clement     extent = rewriter.create<mlir::LLVM::AddOp>(loc, type, extent, step);
16901f551032SValentin Clement     extent = rewriter.create<mlir::LLVM::SDivOp>(loc, type, extent, step);
16911f551032SValentin Clement     // If the resulting extent is negative (`ub-lb` and `step` have different
16921f551032SValentin Clement     // signs), zero must be returned instead.
16931f551032SValentin Clement     auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
16941f551032SValentin Clement         loc, mlir::LLVM::ICmpPredicate::sgt, extent, zero);
16951f551032SValentin Clement     return rewriter.create<mlir::LLVM::SelectOp>(loc, cmp, extent, zero);
16961f551032SValentin Clement   }
1697*0b80491cSSlava Zakharin };
16981f551032SValentin Clement 
1699af6ee580SValentin Clement /// Create a generic box on a memory reference. This conversions lowers the
1700af6ee580SValentin Clement /// abstract box to the appropriate, initialized descriptor.
1701af6ee580SValentin Clement struct EmboxOpConversion : public EmboxCommonConversion<fir::EmboxOp> {
1702af6ee580SValentin Clement   using EmboxCommonConversion::EmboxCommonConversion;
1703af6ee580SValentin Clement 
1704db791b27SRamkumar Ramachandra   llvm::LogicalResult
1705af6ee580SValentin Clement   matchAndRewrite(fir::EmboxOp embox, OpAdaptor adaptor,
1706af6ee580SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
170712d26ce9SValentin Clement     mlir::ValueRange operands = adaptor.getOperands();
17089f1bb307SValentin Clement     mlir::Value sourceBox;
17099f1bb307SValentin Clement     mlir::Type sourceBoxType;
17109f1bb307SValentin Clement     if (embox.getSourceBox()) {
1711d8b672daSjeanPerier       sourceBox = operands[embox.getSourceBoxOperandIndex()];
17129f1bb307SValentin Clement       sourceBoxType = embox.getSourceBox().getType();
17139f1bb307SValentin Clement     }
1714af6ee580SValentin Clement     assert(!embox.getShape() && "There should be no dims on this embox op");
171512d26ce9SValentin Clement     auto [boxTy, dest, eleSize] = consDescriptorPrefix(
1716c1b7e9c9SValentin Clement         embox, fir::unwrapRefType(embox.getMemref().getType()), rewriter,
1717a45ca5d9SSlava Zakharin         /*rank=*/0, /*substrParams=*/mlir::ValueRange{},
1718a45ca5d9SSlava Zakharin         adaptor.getTypeparams(), sourceBox, sourceBoxType);
171912d26ce9SValentin Clement     dest = insertBaseAddress(rewriter, embox.getLoc(), dest, operands[0]);
17200538bfe7SRenaud-K     if (fir::isDerivedTypeWithLenParams(boxTy)) {
17217ce8c6fcSKiran Chandramohan       TODO(embox.getLoc(),
17227ce8c6fcSKiran Chandramohan            "fir.embox codegen of derived with length parameters");
172344e58509SEric Schweitz       return mlir::failure();
17247ce8c6fcSKiran Chandramohan     }
17259c84d20fSSlava Zakharin     auto result =
17269c84d20fSSlava Zakharin         placeInMemoryIfNotGlobalInit(rewriter, embox.getLoc(), boxTy, dest);
1727af6ee580SValentin Clement     rewriter.replaceOp(embox, result);
172844e58509SEric Schweitz     return mlir::success();
1729af6ee580SValentin Clement   }
1730af6ee580SValentin Clement };
1731af6ee580SValentin Clement 
1732c26e1a22SValentin Clement (バレンタイン クレメン) static bool isDeviceAllocation(mlir::Value val, mlir::Value adaptorVal) {
173381831ef3SValentin Clement (バレンタイン クレメン)   if (auto loadOp = mlir::dyn_cast_or_null<fir::LoadOp>(val.getDefiningOp()))
1734c26e1a22SValentin Clement (バレンタイン クレメン)     return isDeviceAllocation(loadOp.getMemref(), {});
1735d36836deSValentin Clement (バレンタイン クレメン)   if (auto boxAddrOp =
1736d36836deSValentin Clement (バレンタイン クレメン)           mlir::dyn_cast_or_null<fir::BoxAddrOp>(val.getDefiningOp()))
1737c26e1a22SValentin Clement (バレンタイン クレメン)     return isDeviceAllocation(boxAddrOp.getVal(), {});
17384530273dSValentin Clement (バレンタイン クレメン)   if (auto convertOp =
17394530273dSValentin Clement (バレンタイン クレメン)           mlir::dyn_cast_or_null<fir::ConvertOp>(val.getDefiningOp()))
1740c26e1a22SValentin Clement (バレンタイン クレメン)     return isDeviceAllocation(convertOp.getValue(), {});
1741c26e1a22SValentin Clement (バレンタイン クレメン)   if (!val.getDefiningOp() && adaptorVal) {
1742c26e1a22SValentin Clement (バレンタイン クレメン)     if (auto blockArg = llvm::cast<mlir::BlockArgument>(adaptorVal)) {
1743c26e1a22SValentin Clement (バレンタイン クレメン)       if (blockArg.getOwner() && blockArg.getOwner()->getParentOp() &&
1744c26e1a22SValentin Clement (バレンタイン クレメン)           blockArg.getOwner()->isEntryBlock()) {
1745c26e1a22SValentin Clement (バレンタイン クレメン)         if (auto func = mlir::dyn_cast_or_null<mlir::FunctionOpInterface>(
1746c26e1a22SValentin Clement (バレンタイン クレメン)                 *blockArg.getOwner()->getParentOp())) {
1747c26e1a22SValentin Clement (バレンタイン クレメン)           auto argAttrs = func.getArgAttrs(blockArg.getArgNumber());
1748c26e1a22SValentin Clement (バレンタイン クレメン)           for (auto attr : argAttrs) {
1749c26e1a22SValentin Clement (バレンタイン クレメン)             if (attr.getName().getValue().ends_with(cuf::getDataAttrName())) {
1750c26e1a22SValentin Clement (バレンタイン クレメン)               auto dataAttr =
1751c26e1a22SValentin Clement (バレンタイン クレメン)                   mlir::dyn_cast<cuf::DataAttributeAttr>(attr.getValue());
1752c26e1a22SValentin Clement (バレンタイン クレメン)               if (dataAttr.getValue() != cuf::DataAttribute::Pinned &&
1753c26e1a22SValentin Clement (バレンタイン クレメン)                   dataAttr.getValue() != cuf::DataAttribute::Unified)
1754c26e1a22SValentin Clement (バレンタイン クレメン)                 return true;
1755c26e1a22SValentin Clement (バレンタイン クレメン)             }
1756c26e1a22SValentin Clement (バレンタイン クレメン)           }
1757c26e1a22SValentin Clement (バレンタイン クレメン)         }
1758c26e1a22SValentin Clement (バレンタイン クレメン)       }
1759c26e1a22SValentin Clement (バレンタイン クレメン)     }
1760c26e1a22SValentin Clement (バレンタイン クレメン)   }
17614530273dSValentin Clement (バレンタイン クレメン)   if (auto callOp = mlir::dyn_cast_or_null<fir::CallOp>(val.getDefiningOp()))
17624530273dSValentin Clement (バレンタイン クレメン)     if (callOp.getCallee() &&
176381831ef3SValentin Clement (バレンタイン クレメン)         (callOp.getCallee().value().getRootReference().getValue().starts_with(
176481831ef3SValentin Clement (バレンタイン クレメン)              RTNAME_STRING(CUFMemAlloc)) ||
17654530273dSValentin Clement (バレンタイン クレメン)          callOp.getCallee().value().getRootReference().getValue().starts_with(
1766e650ac16SValentin Clement (バレンタイン クレメン)              RTNAME_STRING(CUFAllocDescriptor))))
17674530273dSValentin Clement (バレンタイン クレメン)       return true;
17684530273dSValentin Clement (バレンタイン クレメン)   return false;
17694530273dSValentin Clement (バレンタイン クレメン) }
17704530273dSValentin Clement (バレンタイン クレメン) 
17711f551032SValentin Clement /// Create a generic box on a memory reference.
17721f551032SValentin Clement struct XEmboxOpConversion : public EmboxCommonConversion<fir::cg::XEmboxOp> {
17731f551032SValentin Clement   using EmboxCommonConversion::EmboxCommonConversion;
17741f551032SValentin Clement 
1775db791b27SRamkumar Ramachandra   llvm::LogicalResult
17761f551032SValentin Clement   matchAndRewrite(fir::cg::XEmboxOp xbox, OpAdaptor adaptor,
17771f551032SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
17781f551032SValentin Clement     mlir::ValueRange operands = adaptor.getOperands();
17799f1bb307SValentin Clement     mlir::Value sourceBox;
17809f1bb307SValentin Clement     mlir::Type sourceBoxType;
17819f1bb307SValentin Clement     if (xbox.getSourceBox()) {
1782d8b672daSjeanPerier       sourceBox = operands[xbox.getSourceBoxOperandIndex()];
17839f1bb307SValentin Clement       sourceBoxType = xbox.getSourceBox().getType();
17849f1bb307SValentin Clement     }
1785b881fc27SJean Perier     auto [boxTy, dest, resultEleSize] = consDescriptorPrefix(
1786c1b7e9c9SValentin Clement         xbox, fir::unwrapRefType(xbox.getMemref().getType()), rewriter,
1787a45ca5d9SSlava Zakharin         xbox.getOutRank(), adaptor.getSubstr(), adaptor.getLenParams(),
17889f1bb307SValentin Clement         sourceBox, sourceBoxType);
178912d26ce9SValentin Clement     // Generate the triples in the dims field of the descriptor
17901f551032SValentin Clement     auto i64Ty = mlir::IntegerType::get(xbox.getContext(), 64);
1791a89b0480SValentin Clement     assert(!xbox.getShape().empty() && "must have a shape");
1792d8b672daSjeanPerier     unsigned shapeOffset = xbox.getShapeOperandIndex();
1793a89b0480SValentin Clement     bool hasShift = !xbox.getShift().empty();
1794d8b672daSjeanPerier     unsigned shiftOffset = xbox.getShiftOperandIndex();
1795a89b0480SValentin Clement     bool hasSlice = !xbox.getSlice().empty();
1796d8b672daSjeanPerier     unsigned sliceOffset = xbox.getSliceOperandIndex();
17971f551032SValentin Clement     mlir::Location loc = xbox.getLoc();
17981f551032SValentin Clement     mlir::Value zero = genConstantIndex(loc, i64Ty, rewriter, 0);
17991f551032SValentin Clement     mlir::Value one = genConstantIndex(loc, i64Ty, rewriter, 1);
18001f551032SValentin Clement     mlir::Value prevPtrOff = one;
18011f551032SValentin Clement     mlir::Type eleTy = boxTy.getEleTy();
18021f551032SValentin Clement     const unsigned rank = xbox.getRank();
1803af40f99eSJean Perier     llvm::SmallVector<mlir::Value> cstInteriorIndices;
18041f551032SValentin Clement     unsigned constRows = 0;
18051f551032SValentin Clement     mlir::Value ptrOffset = zero;
1806a89b0480SValentin Clement     mlir::Type memEleTy = fir::dyn_cast_ptrEleTy(xbox.getMemref().getType());
1807fac349a1SChristian Sigg     assert(mlir::isa<fir::SequenceType>(memEleTy));
1808fac349a1SChristian Sigg     auto seqTy = mlir::cast<fir::SequenceType>(memEleTy);
18091f551032SValentin Clement     mlir::Type seqEleTy = seqTy.getEleTy();
18101f551032SValentin Clement     // Adjust the element scaling factor if the element is a dependent type.
18111f551032SValentin Clement     if (fir::hasDynamicSize(seqEleTy)) {
1812fac349a1SChristian Sigg       if (auto charTy = mlir::dyn_cast<fir::CharacterType>(seqEleTy)) {
1813315939fdSSlava Zakharin         // The GEP pointer type decays to llvm.ptr<i[width]>.
1814315939fdSSlava Zakharin         // The scaling factor is the runtime value of the length.
1815315939fdSSlava Zakharin         assert(!adaptor.getLenParams().empty());
1816315939fdSSlava Zakharin         prevPtrOff = FIROpConversion::integerCast(
1817315939fdSSlava Zakharin             loc, rewriter, i64Ty, adaptor.getLenParams().back());
1818fac349a1SChristian Sigg       } else if (mlir::isa<fir::RecordType>(seqEleTy)) {
18196c89c531SEric Schweitz         // prevPtrOff = ;
18201f551032SValentin Clement         TODO(loc, "generate call to calculate size of PDT");
18211f551032SValentin Clement       } else {
18226c89c531SEric Schweitz         fir::emitFatalError(loc, "unexpected dynamic type");
18231f551032SValentin Clement       }
18241f551032SValentin Clement     } else {
18251f551032SValentin Clement       constRows = seqTy.getConstantRows();
18261f551032SValentin Clement     }
18271f551032SValentin Clement 
1828a89b0480SValentin Clement     const auto hasSubcomp = !xbox.getSubcomponent().empty();
1829a89b0480SValentin Clement     const bool hasSubstr = !xbox.getSubstr().empty();
183002f3fec3SSlava Zakharin     // Initial element stride that will be use to compute the step in
1831b881fc27SJean Perier     // each dimension. Initially, this is the size of the input element.
1832b881fc27SJean Perier     // Note that when there are no components/substring, the resultEleSize
1833b881fc27SJean Perier     // that was previously computed matches the input element size.
1834b881fc27SJean Perier     mlir::Value prevDimByteStride = resultEleSize;
18351f551032SValentin Clement     if (hasSubcomp) {
18361f551032SValentin Clement       // We have a subcomponent. The step value needs to be the number of
18371f551032SValentin Clement       // bytes per element (which is a derived type).
183802f3fec3SSlava Zakharin       prevDimByteStride =
183902f3fec3SSlava Zakharin           genTypeStrideInBytes(loc, i64Ty, rewriter, convertType(seqEleTy));
18406c89c531SEric Schweitz     } else if (hasSubstr) {
18416c89c531SEric Schweitz       // We have a substring. The step value needs to be the number of bytes
18426c89c531SEric Schweitz       // per CHARACTER element.
1843fac349a1SChristian Sigg       auto charTy = mlir::cast<fir::CharacterType>(seqEleTy);
18446c89c531SEric Schweitz       if (fir::hasDynamicSize(charTy)) {
1845315939fdSSlava Zakharin         prevDimByteStride =
1846315939fdSSlava Zakharin             getCharacterByteSize(loc, rewriter, charTy, adaptor.getLenParams());
18476c89c531SEric Schweitz       } else {
18486c89c531SEric Schweitz         prevDimByteStride = genConstantIndex(
18496c89c531SEric Schweitz             loc, i64Ty, rewriter,
18506c89c531SEric Schweitz             charTy.getLen() * lowerTy().characterBitsize(charTy) / 8);
18516c89c531SEric Schweitz       }
18521f551032SValentin Clement     }
18531f551032SValentin Clement 
18541f551032SValentin Clement     // Process the array subspace arguments (shape, shift, etc.), if any,
18551f551032SValentin Clement     // translating everything to values in the descriptor wherever the entity
18561f551032SValentin Clement     // has a dynamic array dimension.
18571f551032SValentin Clement     for (unsigned di = 0, descIdx = 0; di < rank; ++di) {
1858*0b80491cSSlava Zakharin       mlir::Value extent =
1859*0b80491cSSlava Zakharin           integerCast(loc, rewriter, i64Ty, operands[shapeOffset]);
18601f551032SValentin Clement       mlir::Value outerExtent = extent;
18611f551032SValentin Clement       bool skipNext = false;
18621f551032SValentin Clement       if (hasSlice) {
1863*0b80491cSSlava Zakharin         mlir::Value off =
1864*0b80491cSSlava Zakharin             integerCast(loc, rewriter, i64Ty, operands[sliceOffset]);
18651f551032SValentin Clement         mlir::Value adj = one;
18661f551032SValentin Clement         if (hasShift)
1867*0b80491cSSlava Zakharin           adj = integerCast(loc, rewriter, i64Ty, operands[shiftOffset]);
18681f551032SValentin Clement         auto ao = rewriter.create<mlir::LLVM::SubOp>(loc, i64Ty, off, adj);
18691f551032SValentin Clement         if (constRows > 0) {
1870af40f99eSJean Perier           cstInteriorIndices.push_back(ao);
18711f551032SValentin Clement         } else {
18721f551032SValentin Clement           auto dimOff =
18731f551032SValentin Clement               rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, ao, prevPtrOff);
18741f551032SValentin Clement           ptrOffset =
18751f551032SValentin Clement               rewriter.create<mlir::LLVM::AddOp>(loc, i64Ty, dimOff, ptrOffset);
18761f551032SValentin Clement         }
18771f551032SValentin Clement         if (mlir::isa_and_nonnull<fir::UndefOp>(
1878a89b0480SValentin Clement                 xbox.getSlice()[3 * di + 1].getDefiningOp())) {
18791f551032SValentin Clement           // This dimension contains a scalar expression in the array slice op.
18801f551032SValentin Clement           // The dimension is loop invariant, will be dropped, and will not
18811f551032SValentin Clement           // appear in the descriptor.
18821f551032SValentin Clement           skipNext = true;
18831f551032SValentin Clement         }
18841f551032SValentin Clement       }
18851f551032SValentin Clement       if (!skipNext) {
18866c89c531SEric Schweitz         // store extent
18871f551032SValentin Clement         if (hasSlice)
18881f551032SValentin Clement           extent = computeTripletExtent(rewriter, loc, operands[sliceOffset],
18891f551032SValentin Clement                                         operands[sliceOffset + 1],
18901f551032SValentin Clement                                         operands[sliceOffset + 2], zero, i64Ty);
18916c89c531SEric Schweitz         // Lower bound is normalized to 0 for BIND(C) interoperability.
1892d3bc3a04SJean Perier         mlir::Value lb = zero;
1893d3bc3a04SJean Perier         const bool isaPointerOrAllocatable =
1894fac349a1SChristian Sigg             mlir::isa<fir::PointerType, fir::HeapType>(eleTy);
1895d3bc3a04SJean Perier         // Lower bound is defaults to 1 for POINTER, ALLOCATABLE, and
1896d3bc3a04SJean Perier         // denormalized descriptors.
18976c89c531SEric Schweitz         if (isaPointerOrAllocatable || !normalizedLowerBound(xbox))
1898d3bc3a04SJean Perier           lb = one;
1899bb3afae9SJean Perier         // If there is a shifted origin, and no fir.slice, and this is not
1900bb3afae9SJean Perier         // a normalized descriptor then use the value from the shift op as
1901bb3afae9SJean Perier         // the lower bound.
19026c89c531SEric Schweitz         if (hasShift && !(hasSlice || hasSubcomp || hasSubstr) &&
19036c89c531SEric Schweitz             (isaPointerOrAllocatable || !normalizedLowerBound(xbox))) {
1904*0b80491cSSlava Zakharin           lb = integerCast(loc, rewriter, i64Ty, operands[shiftOffset]);
1905d3bc3a04SJean Perier           auto extentIsEmpty = rewriter.create<mlir::LLVM::ICmpOp>(
1906d3bc3a04SJean Perier               loc, mlir::LLVM::ICmpPredicate::eq, extent, zero);
1907d3bc3a04SJean Perier           lb = rewriter.create<mlir::LLVM::SelectOp>(loc, extentIsEmpty, one,
1908d3bc3a04SJean Perier                                                      lb);
1909d3bc3a04SJean Perier         }
1910d3bc3a04SJean Perier         dest = insertLowerBound(rewriter, loc, dest, descIdx, lb);
1911d3bc3a04SJean Perier 
19121f551032SValentin Clement         dest = insertExtent(rewriter, loc, dest, descIdx, extent);
19131f551032SValentin Clement 
19141f551032SValentin Clement         // store step (scaled by shaped extent)
19156c89c531SEric Schweitz         mlir::Value step = prevDimByteStride;
1916*0b80491cSSlava Zakharin         if (hasSlice) {
1917*0b80491cSSlava Zakharin           mlir::Value sliceStep =
1918*0b80491cSSlava Zakharin               integerCast(loc, rewriter, i64Ty, operands[sliceOffset + 2]);
1919*0b80491cSSlava Zakharin           step =
1920*0b80491cSSlava Zakharin               rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, step, sliceStep);
1921*0b80491cSSlava Zakharin         }
19221f551032SValentin Clement         dest = insertStride(rewriter, loc, dest, descIdx, step);
19231f551032SValentin Clement         ++descIdx;
19241f551032SValentin Clement       }
19251f551032SValentin Clement 
19261f551032SValentin Clement       // compute the stride and offset for the next natural dimension
19276c89c531SEric Schweitz       prevDimByteStride = rewriter.create<mlir::LLVM::MulOp>(
19286c89c531SEric Schweitz           loc, i64Ty, prevDimByteStride, outerExtent);
19291f551032SValentin Clement       if (constRows == 0)
19301f551032SValentin Clement         prevPtrOff = rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, prevPtrOff,
19311f551032SValentin Clement                                                         outerExtent);
19320601a0dcSJean Perier       else
19330601a0dcSJean Perier         --constRows;
19341f551032SValentin Clement 
19351f551032SValentin Clement       // increment iterators
19361f551032SValentin Clement       ++shapeOffset;
19371f551032SValentin Clement       if (hasShift)
19381f551032SValentin Clement         ++shiftOffset;
19391f551032SValentin Clement       if (hasSlice)
19401f551032SValentin Clement         sliceOffset += 3;
19411f551032SValentin Clement     }
19428a1ce2d6SjeanPerier     mlir::Value base = adaptor.getMemref();
19436c89c531SEric Schweitz     if (hasSlice || hasSubcomp || hasSubstr) {
1944af40f99eSJean Perier       // Shift the base address.
1945af40f99eSJean Perier       llvm::SmallVector<mlir::Value> fieldIndices;
194622426110SRamkumar Ramachandra       std::optional<mlir::Value> substringOffset;
1947af40f99eSJean Perier       if (hasSubcomp)
1948a89b0480SValentin Clement         getSubcomponentIndices(xbox, xbox.getMemref(), operands, fieldIndices);
19496c89c531SEric Schweitz       if (hasSubstr)
1950d8b672daSjeanPerier         substringOffset = operands[xbox.getSubstrOperandIndex()];
19518a1ce2d6SjeanPerier       mlir::Type llvmBaseType =
19528a1ce2d6SjeanPerier           convertType(fir::unwrapRefType(xbox.getMemref().getType()));
19538a1ce2d6SjeanPerier       base = genBoxOffsetGep(rewriter, loc, base, llvmBaseType, ptrOffset,
19548a1ce2d6SjeanPerier                              cstInteriorIndices, fieldIndices, substringOffset);
19551f551032SValentin Clement     }
19561f551032SValentin Clement     dest = insertBaseAddress(rewriter, loc, dest, base);
19570538bfe7SRenaud-K     if (fir::isDerivedTypeWithLenParams(boxTy))
19581f551032SValentin Clement       TODO(loc, "fir.embox codegen of derived with length parameters");
19594530273dSValentin Clement (バレンタイン クレメン)     mlir::Value result = placeInMemoryIfNotGlobalInit(
1960c26e1a22SValentin Clement (バレンタイン クレメン)         rewriter, loc, boxTy, dest,
1961c26e1a22SValentin Clement (バレンタイン クレメン)         isDeviceAllocation(xbox.getMemref(), adaptor.getMemref()));
19621f551032SValentin Clement     rewriter.replaceOp(xbox, result);
196344e58509SEric Schweitz     return mlir::success();
19641f551032SValentin Clement   }
1965d3bc3a04SJean Perier 
1966d3bc3a04SJean Perier   /// Return true if `xbox` has a normalized lower bounds attribute. A box value
1967d3bc3a04SJean Perier   /// that is neither a POINTER nor an ALLOCATABLE should be normalized to a
1968d3bc3a04SJean Perier   /// zero origin lower bound for interoperability with BIND(C).
1969d3bc3a04SJean Perier   inline static bool normalizedLowerBound(fir::cg::XEmboxOp xbox) {
1970d3bc3a04SJean Perier     return xbox->hasAttr(fir::getNormalizedLowerBoundAttrName());
1971d3bc3a04SJean Perier   }
19721f551032SValentin Clement };
19731f551032SValentin Clement 
1974fa517555SKiran Chandramohan /// Create a new box given a box reference.
1975fa517555SKiran Chandramohan struct XReboxOpConversion : public EmboxCommonConversion<fir::cg::XReboxOp> {
1976fa517555SKiran Chandramohan   using EmboxCommonConversion::EmboxCommonConversion;
1977fa517555SKiran Chandramohan 
1978db791b27SRamkumar Ramachandra   llvm::LogicalResult
1979fa517555SKiran Chandramohan   matchAndRewrite(fir::cg::XReboxOp rebox, OpAdaptor adaptor,
1980fa517555SKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
1981fa517555SKiran Chandramohan     mlir::Location loc = rebox.getLoc();
1982fa517555SKiran Chandramohan     mlir::Type idxTy = lowerTy().indexType();
1983fa517555SKiran Chandramohan     mlir::Value loweredBox = adaptor.getOperands()[0];
1984fa517555SKiran Chandramohan     mlir::ValueRange operands = adaptor.getOperands();
1985fa517555SKiran Chandramohan 
1986de2811eeSJean Perier     // Inside a fir.global, the input box was produced as an llvm.struct<>
1987de2811eeSJean Perier     // because objects cannot be handled in memory inside a fir.global body that
1988de2811eeSJean Perier     // must be constant foldable. However, the type translation are not
1989de2811eeSJean Perier     // contextual, so the fir.box<T> type of the operation that produced the
1990de2811eeSJean Perier     // fir.box was translated to an llvm.ptr<llvm.struct<>> and the MLIR pass
1991de2811eeSJean Perier     // manager inserted a builtin.unrealized_conversion_cast that was inserted
1992de2811eeSJean Perier     // and needs to be removed here.
1993de2811eeSJean Perier     if (isInGlobalOp(rewriter))
1994de2811eeSJean Perier       if (auto unrealizedCast =
1995de2811eeSJean Perier               loweredBox.getDefiningOp<mlir::UnrealizedConversionCastOp>())
1996de2811eeSJean Perier         loweredBox = unrealizedCast.getInputs()[0];
1997de2811eeSJean Perier 
19988a1ce2d6SjeanPerier     TypePair inputBoxTyPair = getBoxTypePair(rebox.getBox().getType());
19998a1ce2d6SjeanPerier 
2000fa517555SKiran Chandramohan     // Create new descriptor and fill its non-shape related data.
2001fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value, 2> lenParams;
2002fa517555SKiran Chandramohan     mlir::Type inputEleTy = getInputEleTy(rebox);
2003fac349a1SChristian Sigg     if (auto charTy = mlir::dyn_cast<fir::CharacterType>(inputEleTy)) {
200451a34681SJean Perier       if (charTy.hasConstantLen()) {
200551a34681SJean Perier         mlir::Value len =
200651a34681SJean Perier             genConstantIndex(loc, idxTy, rewriter, charTy.getLen());
200751a34681SJean Perier         lenParams.emplace_back(len);
200851a34681SJean Perier       } else {
20098a1ce2d6SjeanPerier         mlir::Value len = getElementSizeFromBox(loc, idxTy, inputBoxTyPair,
20108a1ce2d6SjeanPerier                                                 loweredBox, rewriter);
2011fa517555SKiran Chandramohan         if (charTy.getFKind() != 1) {
201251a34681SJean Perier           assert(!isInGlobalOp(rewriter) &&
201351a34681SJean Perier                  "character target in global op must have constant length");
2014fa517555SKiran Chandramohan           mlir::Value width =
2015fa517555SKiran Chandramohan               genConstantIndex(loc, idxTy, rewriter, charTy.getFKind());
2016fa517555SKiran Chandramohan           len = rewriter.create<mlir::LLVM::SDivOp>(loc, idxTy, len, width);
2017fa517555SKiran Chandramohan         }
2018fa517555SKiran Chandramohan         lenParams.emplace_back(len);
201951a34681SJean Perier       }
2020fac349a1SChristian Sigg     } else if (auto recTy = mlir::dyn_cast<fir::RecordType>(inputEleTy)) {
2021fa517555SKiran Chandramohan       if (recTy.getNumLenParams() != 0)
2022fa517555SKiran Chandramohan         TODO(loc, "reboxing descriptor of derived type with length parameters");
2023fa517555SKiran Chandramohan     }
2024016fbc40SValentin Clement 
2025016fbc40SValentin Clement     // Rebox on polymorphic entities needs to carry over the dynamic type.
2026016fbc40SValentin Clement     mlir::Value typeDescAddr;
2027fac349a1SChristian Sigg     if (mlir::isa<fir::ClassType>(inputBoxTyPair.fir) &&
2028fac349a1SChristian Sigg         mlir::isa<fir::ClassType>(rebox.getType()))
20298a1ce2d6SjeanPerier       typeDescAddr =
20308a1ce2d6SjeanPerier           loadTypeDescAddress(loc, inputBoxTyPair, loweredBox, rewriter);
2031016fbc40SValentin Clement 
2032c1b7e9c9SValentin Clement     auto [boxTy, dest, eleSize] =
2033c1b7e9c9SValentin Clement         consDescriptorPrefix(rebox, loweredBox, rewriter, rebox.getOutRank(),
2034a45ca5d9SSlava Zakharin                              adaptor.getSubstr(), lenParams, typeDescAddr);
2035fa517555SKiran Chandramohan 
2036fa517555SKiran Chandramohan     // Read input extents, strides, and base address
2037fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> inputExtents;
2038fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> inputStrides;
2039fa517555SKiran Chandramohan     const unsigned inputRank = rebox.getRank();
2040de2811eeSJean Perier     for (unsigned dim = 0; dim < inputRank; ++dim) {
204144e58509SEric Schweitz       llvm::SmallVector<mlir::Value, 3> dimInfo =
20428a1ce2d6SjeanPerier           getDimsFromBox(loc, {idxTy, idxTy, idxTy}, inputBoxTyPair, loweredBox,
20438a1ce2d6SjeanPerier                          dim, rewriter);
2044fa517555SKiran Chandramohan       inputExtents.emplace_back(dimInfo[1]);
2045fa517555SKiran Chandramohan       inputStrides.emplace_back(dimInfo[2]);
2046fa517555SKiran Chandramohan     }
2047fa517555SKiran Chandramohan 
20488a1ce2d6SjeanPerier     mlir::Value baseAddr =
20498a1ce2d6SjeanPerier         getBaseAddrFromBox(loc, inputBoxTyPair, loweredBox, rewriter);
2050fa517555SKiran Chandramohan 
2051a89b0480SValentin Clement     if (!rebox.getSlice().empty() || !rebox.getSubcomponent().empty())
20529f83c4edSValentin Clement (バレンタイン クレメン)       return sliceBox(rebox, adaptor, boxTy, dest, baseAddr, inputExtents,
20539f83c4edSValentin Clement (バレンタイン クレメン)                       inputStrides, operands, rewriter);
20549f83c4edSValentin Clement (バレンタイン クレメン)     return reshapeBox(rebox, adaptor, boxTy, dest, baseAddr, inputExtents,
20559f83c4edSValentin Clement (バレンタイン クレメン)                       inputStrides, operands, rewriter);
2056fa517555SKiran Chandramohan   }
2057fa517555SKiran Chandramohan 
2058fa517555SKiran Chandramohan private:
2059fa517555SKiran Chandramohan   /// Write resulting shape and base address in descriptor, and replace rebox
2060fa517555SKiran Chandramohan   /// op.
2061db791b27SRamkumar Ramachandra   llvm::LogicalResult
20629f83c4edSValentin Clement (バレンタイン クレメン)   finalizeRebox(fir::cg::XReboxOp rebox, OpAdaptor adaptor,
20639f83c4edSValentin Clement (バレンタイン クレメン)                 mlir::Type destBoxTy, mlir::Value dest, mlir::Value base,
20649f83c4edSValentin Clement (バレンタイン クレメン)                 mlir::ValueRange lbounds, mlir::ValueRange extents,
20659f83c4edSValentin Clement (バレンタイン クレメン)                 mlir::ValueRange strides,
2066fa517555SKiran Chandramohan                 mlir::ConversionPatternRewriter &rewriter) const {
2067fa517555SKiran Chandramohan     mlir::Location loc = rebox.getLoc();
2068d3bc3a04SJean Perier     mlir::Value zero =
2069d3bc3a04SJean Perier         genConstantIndex(loc, lowerTy().indexType(), rewriter, 0);
2070fa517555SKiran Chandramohan     mlir::Value one = genConstantIndex(loc, lowerTy().indexType(), rewriter, 1);
2071fa517555SKiran Chandramohan     for (auto iter : llvm::enumerate(llvm::zip(extents, strides))) {
2072d3bc3a04SJean Perier       mlir::Value extent = std::get<0>(iter.value());
2073fa517555SKiran Chandramohan       unsigned dim = iter.index();
2074d3bc3a04SJean Perier       mlir::Value lb = one;
2075d3bc3a04SJean Perier       if (!lbounds.empty()) {
2076d3bc3a04SJean Perier         lb = lbounds[dim];
2077d3bc3a04SJean Perier         auto extentIsEmpty = rewriter.create<mlir::LLVM::ICmpOp>(
2078d3bc3a04SJean Perier             loc, mlir::LLVM::ICmpPredicate::eq, extent, zero);
2079d3bc3a04SJean Perier         lb = rewriter.create<mlir::LLVM::SelectOp>(loc, extentIsEmpty, one, lb);
2080d3bc3a04SJean Perier       };
2081fa517555SKiran Chandramohan       dest = insertLowerBound(rewriter, loc, dest, dim, lb);
2082d3bc3a04SJean Perier       dest = insertExtent(rewriter, loc, dest, dim, extent);
2083fa517555SKiran Chandramohan       dest = insertStride(rewriter, loc, dest, dim, std::get<1>(iter.value()));
2084fa517555SKiran Chandramohan     }
2085fa517555SKiran Chandramohan     dest = insertBaseAddress(rewriter, loc, dest, base);
2086c26e1a22SValentin Clement (バレンタイン クレメン)     mlir::Value result = placeInMemoryIfNotGlobalInit(
2087c26e1a22SValentin Clement (バレンタイン クレメン)         rewriter, rebox.getLoc(), destBoxTy, dest,
20889f83c4edSValentin Clement (バレンタイン クレメン)         isDeviceAllocation(rebox.getBox(), adaptor.getBox()));
2089fa517555SKiran Chandramohan     rewriter.replaceOp(rebox, result);
209044e58509SEric Schweitz     return mlir::success();
2091fa517555SKiran Chandramohan   }
2092fa517555SKiran Chandramohan 
2093fa517555SKiran Chandramohan   // Apply slice given the base address, extents and strides of the input box.
2094db791b27SRamkumar Ramachandra   llvm::LogicalResult
20959f83c4edSValentin Clement (バレンタイン クレメン)   sliceBox(fir::cg::XReboxOp rebox, OpAdaptor adaptor, mlir::Type destBoxTy,
20969f83c4edSValentin Clement (バレンタイン クレメン)            mlir::Value dest, mlir::Value base, mlir::ValueRange inputExtents,
20979c84d20fSSlava Zakharin            mlir::ValueRange inputStrides, mlir::ValueRange operands,
2098fa517555SKiran Chandramohan            mlir::ConversionPatternRewriter &rewriter) const {
2099fa517555SKiran Chandramohan     mlir::Location loc = rebox.getLoc();
21008a1ce2d6SjeanPerier     mlir::Type byteTy = ::getI8Type(rebox.getContext());
2101fa517555SKiran Chandramohan     mlir::Type idxTy = lowerTy().indexType();
2102fa517555SKiran Chandramohan     mlir::Value zero = genConstantIndex(loc, idxTy, rewriter, 0);
2103fa517555SKiran Chandramohan     // Apply subcomponent and substring shift on base address.
2104a89b0480SValentin Clement     if (!rebox.getSubcomponent().empty() || !rebox.getSubstr().empty()) {
2105fa517555SKiran Chandramohan       // Cast to inputEleTy* so that a GEP can be used.
2106fa517555SKiran Chandramohan       mlir::Type inputEleTy = getInputEleTy(rebox);
21078a1ce2d6SjeanPerier       mlir::Type llvmBaseObjectType = convertType(inputEleTy);
2108af40f99eSJean Perier       llvm::SmallVector<mlir::Value> fieldIndices;
210922426110SRamkumar Ramachandra       std::optional<mlir::Value> substringOffset;
2110a89b0480SValentin Clement       if (!rebox.getSubcomponent().empty())
2111a89b0480SValentin Clement         getSubcomponentIndices(rebox, rebox.getBox(), operands, fieldIndices);
2112a89b0480SValentin Clement       if (!rebox.getSubstr().empty())
2113d8b672daSjeanPerier         substringOffset = operands[rebox.getSubstrOperandIndex()];
21148a1ce2d6SjeanPerier       base = genBoxOffsetGep(rewriter, loc, base, llvmBaseObjectType, zero,
21159a417395SKazu Hirata                              /*cstInteriorIndices=*/std::nullopt, fieldIndices,
2116af40f99eSJean Perier                              substringOffset);
2117fa517555SKiran Chandramohan     }
2118fa517555SKiran Chandramohan 
2119a89b0480SValentin Clement     if (rebox.getSlice().empty())
2120fa517555SKiran Chandramohan       // The array section is of the form array[%component][substring], keep
2121fa517555SKiran Chandramohan       // the input array extents and strides.
21229f83c4edSValentin Clement (バレンタイン クレメン)       return finalizeRebox(rebox, adaptor, destBoxTy, dest, base,
21239c84d20fSSlava Zakharin                            /*lbounds*/ std::nullopt, inputExtents, inputStrides,
21249c84d20fSSlava Zakharin                            rewriter);
2125fa517555SKiran Chandramohan 
2126fa517555SKiran Chandramohan     // The slice is of the form array(i:j:k)[%component]. Compute new extents
2127fa517555SKiran Chandramohan     // and strides.
2128fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> slicedExtents;
2129fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> slicedStrides;
2130fa517555SKiran Chandramohan     mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1);
2131a89b0480SValentin Clement     const bool sliceHasOrigins = !rebox.getShift().empty();
2132d8b672daSjeanPerier     unsigned sliceOps = rebox.getSliceOperandIndex();
2133d8b672daSjeanPerier     unsigned shiftOps = rebox.getShiftOperandIndex();
2134fa517555SKiran Chandramohan     auto strideOps = inputStrides.begin();
2135fa517555SKiran Chandramohan     const unsigned inputRank = inputStrides.size();
2136fa517555SKiran Chandramohan     for (unsigned i = 0; i < inputRank;
2137fa517555SKiran Chandramohan          ++i, ++strideOps, ++shiftOps, sliceOps += 3) {
2138fa517555SKiran Chandramohan       mlir::Value sliceLb =
2139fa517555SKiran Chandramohan           integerCast(loc, rewriter, idxTy, operands[sliceOps]);
2140fa517555SKiran Chandramohan       mlir::Value inputStride = *strideOps; // already idxTy
2141fa517555SKiran Chandramohan       // Apply origin shift: base += (lb-shift)*input_stride
2142fa517555SKiran Chandramohan       mlir::Value sliceOrigin =
2143fa517555SKiran Chandramohan           sliceHasOrigins
2144fa517555SKiran Chandramohan               ? integerCast(loc, rewriter, idxTy, operands[shiftOps])
2145fa517555SKiran Chandramohan               : one;
2146fa517555SKiran Chandramohan       mlir::Value diff =
2147fa517555SKiran Chandramohan           rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, sliceLb, sliceOrigin);
2148fa517555SKiran Chandramohan       mlir::Value offset =
2149fa517555SKiran Chandramohan           rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, inputStride);
21508a1ce2d6SjeanPerier       // Strides from the fir.box are in bytes.
21518a1ce2d6SjeanPerier       base = genGEP(loc, byteTy, rewriter, base, offset);
2152fa517555SKiran Chandramohan       // Apply upper bound and step if this is a triplet. Otherwise, the
2153fa517555SKiran Chandramohan       // dimension is dropped and no extents/strides are computed.
2154fa517555SKiran Chandramohan       mlir::Value upper = operands[sliceOps + 1];
2155fa517555SKiran Chandramohan       const bool isTripletSlice =
2156fa517555SKiran Chandramohan           !mlir::isa_and_nonnull<mlir::LLVM::UndefOp>(upper.getDefiningOp());
2157fa517555SKiran Chandramohan       if (isTripletSlice) {
2158fa517555SKiran Chandramohan         mlir::Value step =
2159fa517555SKiran Chandramohan             integerCast(loc, rewriter, idxTy, operands[sliceOps + 2]);
2160fa517555SKiran Chandramohan         // extent = ub-lb+step/step
2161fa517555SKiran Chandramohan         mlir::Value sliceUb = integerCast(loc, rewriter, idxTy, upper);
2162fa517555SKiran Chandramohan         mlir::Value extent = computeTripletExtent(rewriter, loc, sliceLb,
2163fa517555SKiran Chandramohan                                                   sliceUb, step, zero, idxTy);
2164fa517555SKiran Chandramohan         slicedExtents.emplace_back(extent);
2165fa517555SKiran Chandramohan         // stride = step*input_stride
2166fa517555SKiran Chandramohan         mlir::Value stride =
2167fa517555SKiran Chandramohan             rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, step, inputStride);
2168fa517555SKiran Chandramohan         slicedStrides.emplace_back(stride);
2169fa517555SKiran Chandramohan       }
2170fa517555SKiran Chandramohan     }
21719f83c4edSValentin Clement (バレンタイン クレメン)     return finalizeRebox(rebox, adaptor, destBoxTy, dest, base,
21729f83c4edSValentin Clement (バレンタイン クレメン)                          /*lbounds*/ std::nullopt, slicedExtents, slicedStrides,
21739f83c4edSValentin Clement (バレンタイン クレメン)                          rewriter);
2174fa517555SKiran Chandramohan   }
2175fa517555SKiran Chandramohan 
2176fa517555SKiran Chandramohan   /// Apply a new shape to the data described by a box given the base address,
2177fa517555SKiran Chandramohan   /// extents and strides of the box.
2178db791b27SRamkumar Ramachandra   llvm::LogicalResult
21799f83c4edSValentin Clement (バレンタイン クレメン)   reshapeBox(fir::cg::XReboxOp rebox, OpAdaptor adaptor, mlir::Type destBoxTy,
21809f83c4edSValentin Clement (バレンタイン クレメン)              mlir::Value dest, mlir::Value base, mlir::ValueRange inputExtents,
21819c84d20fSSlava Zakharin              mlir::ValueRange inputStrides, mlir::ValueRange operands,
2182fa517555SKiran Chandramohan              mlir::ConversionPatternRewriter &rewriter) const {
2183d8b672daSjeanPerier     mlir::ValueRange reboxShifts{
2184d8b672daSjeanPerier         operands.begin() + rebox.getShiftOperandIndex(),
2185d8b672daSjeanPerier         operands.begin() + rebox.getShiftOperandIndex() +
2186a89b0480SValentin Clement             rebox.getShift().size()};
2187a89b0480SValentin Clement     if (rebox.getShape().empty()) {
2188fa517555SKiran Chandramohan       // Only setting new lower bounds.
21899f83c4edSValentin Clement (バレンタイン クレメン)       return finalizeRebox(rebox, adaptor, destBoxTy, dest, base, reboxShifts,
21909c84d20fSSlava Zakharin                            inputExtents, inputStrides, rewriter);
2191fa517555SKiran Chandramohan     }
2192fa517555SKiran Chandramohan 
2193fa517555SKiran Chandramohan     mlir::Location loc = rebox.getLoc();
2194fa517555SKiran Chandramohan 
2195fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> newStrides;
2196fa517555SKiran Chandramohan     llvm::SmallVector<mlir::Value> newExtents;
2197fa517555SKiran Chandramohan     mlir::Type idxTy = lowerTy().indexType();
2198fa517555SKiran Chandramohan     // First stride from input box is kept. The rest is assumed contiguous
2199fa517555SKiran Chandramohan     // (it is not possible to reshape otherwise). If the input is scalar,
2200fa517555SKiran Chandramohan     // which may be OK if all new extents are ones, the stride does not
2201fa517555SKiran Chandramohan     // matter, use one.
2202fa517555SKiran Chandramohan     mlir::Value stride = inputStrides.empty()
2203fa517555SKiran Chandramohan                              ? genConstantIndex(loc, idxTy, rewriter, 1)
2204fa517555SKiran Chandramohan                              : inputStrides[0];
2205a89b0480SValentin Clement     for (unsigned i = 0; i < rebox.getShape().size(); ++i) {
2206d8b672daSjeanPerier       mlir::Value rawExtent = operands[rebox.getShapeOperandIndex() + i];
2207fa517555SKiran Chandramohan       mlir::Value extent = integerCast(loc, rewriter, idxTy, rawExtent);
2208fa517555SKiran Chandramohan       newExtents.emplace_back(extent);
2209fa517555SKiran Chandramohan       newStrides.emplace_back(stride);
2210fa517555SKiran Chandramohan       // nextStride = extent * stride;
2211fa517555SKiran Chandramohan       stride = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, extent, stride);
2212fa517555SKiran Chandramohan     }
22139f83c4edSValentin Clement (バレンタイン クレメン)     return finalizeRebox(rebox, adaptor, destBoxTy, dest, base, reboxShifts,
22149f83c4edSValentin Clement (バレンタイン クレメン)                          newExtents, newStrides, rewriter);
2215fa517555SKiran Chandramohan   }
2216fa517555SKiran Chandramohan 
2217fa517555SKiran Chandramohan   /// Return scalar element type of the input box.
2218fa517555SKiran Chandramohan   static mlir::Type getInputEleTy(fir::cg::XReboxOp rebox) {
2219a89b0480SValentin Clement     auto ty = fir::dyn_cast_ptrOrBoxEleTy(rebox.getBox().getType());
2220fac349a1SChristian Sigg     if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(ty))
2221fa517555SKiran Chandramohan       return seqTy.getEleTy();
2222fa517555SKiran Chandramohan     return ty;
2223fa517555SKiran Chandramohan   }
2224fa517555SKiran Chandramohan };
2225fa517555SKiran Chandramohan 
2226dc48849fSKiran Chandramohan /// Lower `fir.emboxproc` operation. Creates a procedure box.
2227dc48849fSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
2228e9639e9cSValentin Clement (バレンタイン クレメン) struct EmboxProcOpConversion : public fir::FIROpConversion<fir::EmboxProcOp> {
2229dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2230dc48849fSKiran Chandramohan 
2231db791b27SRamkumar Ramachandra   llvm::LogicalResult
2232dc48849fSKiran Chandramohan   matchAndRewrite(fir::EmboxProcOp emboxproc, OpAdaptor adaptor,
2233dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2234dc48849fSKiran Chandramohan     TODO(emboxproc.getLoc(), "fir.emboxproc codegen");
223544e58509SEric Schweitz     return mlir::failure();
2236dc48849fSKiran Chandramohan   }
2237dc48849fSKiran Chandramohan };
2238dc48849fSKiran Chandramohan 
223954c56347SValentin Clement // Code shared between insert_value and extract_value Ops.
224054c56347SValentin Clement struct ValueOpCommon {
224154c56347SValentin Clement   // Translate the arguments pertaining to any multidimensional array to
224254c56347SValentin Clement   // row-major order for LLVM-IR.
22435c5af910SJeff Niu   static void toRowMajor(llvm::SmallVectorImpl<int64_t> &indices,
224454c56347SValentin Clement                          mlir::Type ty) {
224554c56347SValentin Clement     assert(ty && "type is null");
22465c5af910SJeff Niu     const auto end = indices.size();
224754c56347SValentin Clement     for (std::remove_const_t<decltype(end)> i = 0; i < end; ++i) {
2248fac349a1SChristian Sigg       if (auto seq = mlir::dyn_cast<mlir::LLVM::LLVMArrayType>(ty)) {
224954c56347SValentin Clement         const auto dim = getDimension(seq);
225054c56347SValentin Clement         if (dim > 1) {
225154c56347SValentin Clement           auto ub = std::min(i + dim, end);
22525c5af910SJeff Niu           std::reverse(indices.begin() + i, indices.begin() + ub);
225354c56347SValentin Clement           i += dim - 1;
225454c56347SValentin Clement         }
225554c56347SValentin Clement         ty = getArrayElementType(seq);
2256fac349a1SChristian Sigg       } else if (auto st = mlir::dyn_cast<mlir::LLVM::LLVMStructType>(ty)) {
22575c5af910SJeff Niu         ty = st.getBody()[indices[i]];
225854c56347SValentin Clement       } else {
225954c56347SValentin Clement         llvm_unreachable("index into invalid type");
226054c56347SValentin Clement       }
226154c56347SValentin Clement     }
226254c56347SValentin Clement   }
226354c56347SValentin Clement 
22645c5af910SJeff Niu   static llvm::SmallVector<int64_t>
226554c56347SValentin Clement   collectIndices(mlir::ConversionPatternRewriter &rewriter,
226654c56347SValentin Clement                  mlir::ArrayAttr arrAttr) {
22675c5af910SJeff Niu     llvm::SmallVector<int64_t> indices;
226854c56347SValentin Clement     for (auto i = arrAttr.begin(), e = arrAttr.end(); i != e; ++i) {
2269bd9fdce6SChristian Sigg       if (auto intAttr = mlir::dyn_cast<mlir::IntegerAttr>(*i)) {
22705c5af910SJeff Niu         indices.push_back(intAttr.getInt());
227154c56347SValentin Clement       } else {
2272bd9fdce6SChristian Sigg         auto fieldName = mlir::cast<mlir::StringAttr>(*i).getValue();
227354c56347SValentin Clement         ++i;
2274bd9fdce6SChristian Sigg         auto ty = mlir::cast<mlir::TypeAttr>(*i).getValue();
2275fac349a1SChristian Sigg         auto index = mlir::cast<fir::RecordType>(ty).getFieldIndex(fieldName);
22765c5af910SJeff Niu         indices.push_back(index);
227754c56347SValentin Clement       }
227854c56347SValentin Clement     }
22795c5af910SJeff Niu     return indices;
228054c56347SValentin Clement   }
228154c56347SValentin Clement 
228254c56347SValentin Clement private:
228354c56347SValentin Clement   static mlir::Type getArrayElementType(mlir::LLVM::LLVMArrayType ty) {
228454c56347SValentin Clement     auto eleTy = ty.getElementType();
2285fac349a1SChristian Sigg     while (auto arrTy = mlir::dyn_cast<mlir::LLVM::LLVMArrayType>(eleTy))
228654c56347SValentin Clement       eleTy = arrTy.getElementType();
228754c56347SValentin Clement     return eleTy;
228854c56347SValentin Clement   }
228954c56347SValentin Clement };
229054c56347SValentin Clement 
2291c2acd453SAlexisPerry namespace {
229254c56347SValentin Clement /// Extract a subobject value from an ssa-value of aggregate type
229354c56347SValentin Clement struct ExtractValueOpConversion
2294e9639e9cSValentin Clement (バレンタイン クレメン)     : public fir::FIROpAndTypeConversion<fir::ExtractValueOp>,
229554c56347SValentin Clement       public ValueOpCommon {
229654c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
229754c56347SValentin Clement 
2298db791b27SRamkumar Ramachandra   llvm::LogicalResult
229954c56347SValentin Clement   doRewrite(fir::ExtractValueOp extractVal, mlir::Type ty, OpAdaptor adaptor,
230054c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
230112d26ce9SValentin Clement     mlir::ValueRange operands = adaptor.getOperands();
23025c5af910SJeff Niu     auto indices = collectIndices(rewriter, extractVal.getCoor());
23035c5af910SJeff Niu     toRowMajor(indices, operands[0].getType());
230454c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(
23055c5af910SJeff Niu         extractVal, operands[0], indices);
230644e58509SEric Schweitz     return mlir::success();
230754c56347SValentin Clement   }
230854c56347SValentin Clement };
230954c56347SValentin Clement 
231054c56347SValentin Clement /// InsertValue is the generalized instruction for the composition of new
231154c56347SValentin Clement /// aggregate type values.
231254c56347SValentin Clement struct InsertValueOpConversion
2313e73cf2f0SMatthias Springer     : public mlir::OpConversionPattern<fir::InsertValueOp>,
231454c56347SValentin Clement       public ValueOpCommon {
2315e73cf2f0SMatthias Springer   using OpConversionPattern::OpConversionPattern;
231654c56347SValentin Clement 
2317db791b27SRamkumar Ramachandra   llvm::LogicalResult
2318e73cf2f0SMatthias Springer   matchAndRewrite(fir::InsertValueOp insertVal, OpAdaptor adaptor,
231954c56347SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
232012d26ce9SValentin Clement     mlir::ValueRange operands = adaptor.getOperands();
23215c5af910SJeff Niu     auto indices = collectIndices(rewriter, insertVal.getCoor());
23225c5af910SJeff Niu     toRowMajor(indices, operands[0].getType());
232354c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
23245c5af910SJeff Niu         insertVal, operands[0], operands[1], indices);
232544e58509SEric Schweitz     return mlir::success();
232654c56347SValentin Clement   }
232754c56347SValentin Clement };
232854c56347SValentin Clement 
23293ae8e442SValentin Clement /// InsertOnRange inserts a value into a sequence over a range of offsets.
23303ae8e442SValentin Clement struct InsertOnRangeOpConversion
2331e9639e9cSValentin Clement (バレンタイン クレメン)     : public fir::FIROpAndTypeConversion<fir::InsertOnRangeOp> {
23323ae8e442SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
23333ae8e442SValentin Clement 
23343ae8e442SValentin Clement   // Increments an array of subscripts in a row major fasion.
23355c5af910SJeff Niu   void incrementSubscripts(llvm::ArrayRef<int64_t> dims,
23365c5af910SJeff Niu                            llvm::SmallVectorImpl<int64_t> &subscripts) const {
23373ae8e442SValentin Clement     for (size_t i = dims.size(); i > 0; --i) {
23383ae8e442SValentin Clement       if (++subscripts[i - 1] < dims[i - 1]) {
23393ae8e442SValentin Clement         return;
23403ae8e442SValentin Clement       }
23413ae8e442SValentin Clement       subscripts[i - 1] = 0;
23423ae8e442SValentin Clement     }
23433ae8e442SValentin Clement   }
23443ae8e442SValentin Clement 
2345db791b27SRamkumar Ramachandra   llvm::LogicalResult
23463ae8e442SValentin Clement   doRewrite(fir::InsertOnRangeOp range, mlir::Type ty, OpAdaptor adaptor,
23473ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
23483ae8e442SValentin Clement 
23495c5af910SJeff Niu     llvm::SmallVector<std::int64_t> dims;
23503ae8e442SValentin Clement     auto type = adaptor.getOperands()[0].getType();
23513ae8e442SValentin Clement 
23523ae8e442SValentin Clement     // Iteratively extract the array dimensions from the type.
2353fac349a1SChristian Sigg     while (auto t = mlir::dyn_cast<mlir::LLVM::LLVMArrayType>(type)) {
23543ae8e442SValentin Clement       dims.push_back(t.getNumElements());
23553ae8e442SValentin Clement       type = t.getElementType();
23563ae8e442SValentin Clement     }
23573ae8e442SValentin Clement 
23585c5af910SJeff Niu     llvm::SmallVector<std::int64_t> lBounds;
23595c5af910SJeff Niu     llvm::SmallVector<std::int64_t> uBounds;
23603ae8e442SValentin Clement 
23613ae8e442SValentin Clement     // Unzip the upper and lower bound and convert to a row major format.
2362149ad3d5SShraiysh Vaishay     mlir::DenseIntElementsAttr coor = range.getCoor();
23638ec0f221SMehdi Amini     auto reversedCoor = llvm::reverse(coor.getValues<int64_t>());
23648ec0f221SMehdi Amini     for (auto i = reversedCoor.begin(), e = reversedCoor.end(); i != e; ++i) {
23653ae8e442SValentin Clement       uBounds.push_back(*i++);
23663ae8e442SValentin Clement       lBounds.push_back(*i);
23673ae8e442SValentin Clement     }
23683ae8e442SValentin Clement 
23693ae8e442SValentin Clement     auto &subscripts = lBounds;
23703ae8e442SValentin Clement     auto loc = range.getLoc();
23713ae8e442SValentin Clement     mlir::Value lastOp = adaptor.getOperands()[0];
23723ae8e442SValentin Clement     mlir::Value insertVal = adaptor.getOperands()[1];
23733ae8e442SValentin Clement 
23743ae8e442SValentin Clement     while (subscripts != uBounds) {
23753ae8e442SValentin Clement       lastOp = rewriter.create<mlir::LLVM::InsertValueOp>(
23765c5af910SJeff Niu           loc, lastOp, insertVal, subscripts);
23773ae8e442SValentin Clement 
23783ae8e442SValentin Clement       incrementSubscripts(dims, subscripts);
23793ae8e442SValentin Clement     }
23803ae8e442SValentin Clement 
23813ae8e442SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
23825c5af910SJeff Niu         range, lastOp, insertVal, subscripts);
23833ae8e442SValentin Clement 
238444e58509SEric Schweitz     return mlir::success();
23853ae8e442SValentin Clement   }
23863ae8e442SValentin Clement };
2387c2acd453SAlexisPerry } // namespace
23887b5132daSValentin Clement 
2389dc48849fSKiran Chandramohan namespace {
23905d27abe6SValentin Clement /// XArrayCoor is the address arithmetic on a dynamically shaped, sliced,
23915d27abe6SValentin Clement /// shifted etc. array.
23925d27abe6SValentin Clement /// (See the static restriction on coordinate_of.) array_coor determines the
23935d27abe6SValentin Clement /// coordinate (location) of a specific element.
23945d27abe6SValentin Clement struct XArrayCoorOpConversion
2395e9639e9cSValentin Clement (バレンタイン クレメン)     : public fir::FIROpAndTypeConversion<fir::cg::XArrayCoorOp> {
23965d27abe6SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
23975d27abe6SValentin Clement 
2398db791b27SRamkumar Ramachandra   llvm::LogicalResult
23998a1ce2d6SjeanPerier   doRewrite(fir::cg::XArrayCoorOp coor, mlir::Type llvmPtrTy, OpAdaptor adaptor,
24005d27abe6SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
24015d27abe6SValentin Clement     auto loc = coor.getLoc();
24025d27abe6SValentin Clement     mlir::ValueRange operands = adaptor.getOperands();
24035d27abe6SValentin Clement     unsigned rank = coor.getRank();
2404a89b0480SValentin Clement     assert(coor.getIndices().size() == rank);
2405a89b0480SValentin Clement     assert(coor.getShape().empty() || coor.getShape().size() == rank);
2406a89b0480SValentin Clement     assert(coor.getShift().empty() || coor.getShift().size() == rank);
2407a89b0480SValentin Clement     assert(coor.getSlice().empty() || coor.getSlice().size() == 3 * rank);
24085d27abe6SValentin Clement     mlir::Type idxTy = lowerTy().indexType();
2409d8b672daSjeanPerier     unsigned indexOffset = coor.getIndicesOperandIndex();
2410d8b672daSjeanPerier     unsigned shapeOffset = coor.getShapeOperandIndex();
2411d8b672daSjeanPerier     unsigned shiftOffset = coor.getShiftOperandIndex();
2412d8b672daSjeanPerier     unsigned sliceOffset = coor.getSliceOperandIndex();
2413a89b0480SValentin Clement     auto sliceOps = coor.getSlice().begin();
24145d27abe6SValentin Clement     mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1);
24155d27abe6SValentin Clement     mlir::Value prevExt = one;
2416bd7eff1fSMarkus Böck     mlir::Value offset = genConstantIndex(loc, idxTy, rewriter, 0);
2417a89b0480SValentin Clement     const bool isShifted = !coor.getShift().empty();
2418a89b0480SValentin Clement     const bool isSliced = !coor.getSlice().empty();
2419fac349a1SChristian Sigg     const bool baseIsBoxed =
2420fac349a1SChristian Sigg         mlir::isa<fir::BaseBoxType>(coor.getMemref().getType());
24218a1ce2d6SjeanPerier     TypePair baseBoxTyPair =
24228a1ce2d6SjeanPerier         baseIsBoxed ? getBoxTypePair(coor.getMemref().getType()) : TypePair{};
2423e553ac4dSJeff Niu     mlir::LLVM::IntegerOverflowFlags nsw =
2424e553ac4dSJeff Niu         mlir::LLVM::IntegerOverflowFlags::nsw;
24255d27abe6SValentin Clement 
24265d27abe6SValentin Clement     // For each dimension of the array, generate the offset calculation.
2427914b9eecSKiran Chandramohan     for (unsigned i = 0; i < rank; ++i, ++indexOffset, ++shapeOffset,
2428914b9eecSKiran Chandramohan                   ++shiftOffset, sliceOffset += 3, sliceOps += 3) {
24295d27abe6SValentin Clement       mlir::Value index =
2430914b9eecSKiran Chandramohan           integerCast(loc, rewriter, idxTy, operands[indexOffset]);
2431914b9eecSKiran Chandramohan       mlir::Value lb =
2432914b9eecSKiran Chandramohan           isShifted ? integerCast(loc, rewriter, idxTy, operands[shiftOffset])
24335d27abe6SValentin Clement                     : one;
24345d27abe6SValentin Clement       mlir::Value step = one;
24355d27abe6SValentin Clement       bool normalSlice = isSliced;
24365d27abe6SValentin Clement       // Compute zero based index in dimension i of the element, applying
24375d27abe6SValentin Clement       // potential triplets and lower bounds.
24385d27abe6SValentin Clement       if (isSliced) {
2439914b9eecSKiran Chandramohan         mlir::Value originalUb = *(sliceOps + 1);
2440914b9eecSKiran Chandramohan         normalSlice =
2441914b9eecSKiran Chandramohan             !mlir::isa_and_nonnull<fir::UndefOp>(originalUb.getDefiningOp());
24425d27abe6SValentin Clement         if (normalSlice)
2443914b9eecSKiran Chandramohan           step = integerCast(loc, rewriter, idxTy, operands[sliceOffset + 2]);
24445d27abe6SValentin Clement       }
2445bdacd56fSTom Eccles       auto idx = rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, index, lb, nsw);
24465d27abe6SValentin Clement       mlir::Value diff =
2447bdacd56fSTom Eccles           rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, idx, step, nsw);
24485d27abe6SValentin Clement       if (normalSlice) {
24495d27abe6SValentin Clement         mlir::Value sliceLb =
2450914b9eecSKiran Chandramohan             integerCast(loc, rewriter, idxTy, operands[sliceOffset]);
2451bdacd56fSTom Eccles         auto adj =
2452bdacd56fSTom Eccles             rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, sliceLb, lb, nsw);
2453bdacd56fSTom Eccles         diff = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, diff, adj, nsw);
24545d27abe6SValentin Clement       }
24555d27abe6SValentin Clement       // Update the offset given the stride and the zero based index `diff`
24565d27abe6SValentin Clement       // that was just computed.
24575d27abe6SValentin Clement       if (baseIsBoxed) {
24585d27abe6SValentin Clement         // Use stride in bytes from the descriptor.
24598a1ce2d6SjeanPerier         mlir::Value stride =
24608a1ce2d6SjeanPerier             getStrideFromBox(loc, baseBoxTyPair, operands[0], i, rewriter);
2461bdacd56fSTom Eccles         auto sc =
2462bdacd56fSTom Eccles             rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, stride, nsw);
2463bdacd56fSTom Eccles         offset =
2464bdacd56fSTom Eccles             rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, offset, nsw);
24655d27abe6SValentin Clement       } else {
24665d27abe6SValentin Clement         // Use stride computed at last iteration.
2467bdacd56fSTom Eccles         auto sc =
2468bdacd56fSTom Eccles             rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, prevExt, nsw);
2469bdacd56fSTom Eccles         offset =
2470bdacd56fSTom Eccles             rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, offset, nsw);
24715d27abe6SValentin Clement         // Compute next stride assuming contiguity of the base array
24725d27abe6SValentin Clement         // (in element number).
2473914b9eecSKiran Chandramohan         auto nextExt = integerCast(loc, rewriter, idxTy, operands[shapeOffset]);
2474bdacd56fSTom Eccles         prevExt = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, prevExt,
2475bdacd56fSTom Eccles                                                      nextExt, nsw);
24765d27abe6SValentin Clement       }
24775d27abe6SValentin Clement     }
24785d27abe6SValentin Clement 
24795d27abe6SValentin Clement     // Add computed offset to the base address.
24805d27abe6SValentin Clement     if (baseIsBoxed) {
24815d27abe6SValentin Clement       // Working with byte offsets. The base address is read from the fir.box.
24828a1ce2d6SjeanPerier       // and used in i8* GEP to do the pointer arithmetic.
24838a1ce2d6SjeanPerier       mlir::Type byteTy = ::getI8Type(coor.getContext());
24848a1ce2d6SjeanPerier       mlir::Value base =
24858a1ce2d6SjeanPerier           getBaseAddrFromBox(loc, baseBoxTyPair, operands[0], rewriter);
2486bd7eff1fSMarkus Böck       llvm::SmallVector<mlir::LLVM::GEPArg> args{offset};
24878a1ce2d6SjeanPerier       auto addr = rewriter.create<mlir::LLVM::GEPOp>(loc, llvmPtrTy, byteTy,
24888a1ce2d6SjeanPerier                                                      base, args);
2489a89b0480SValentin Clement       if (coor.getSubcomponent().empty()) {
24908a1ce2d6SjeanPerier         rewriter.replaceOp(coor, addr);
249144e58509SEric Schweitz         return mlir::success();
24925d27abe6SValentin Clement       }
24933ce7e4b2SJean Perier       // Cast the element address from void* to the derived type so that the
24943ce7e4b2SJean Perier       // derived type members can be addresses via a GEP using the index of
24953ce7e4b2SJean Perier       // components.
24963ce7e4b2SJean Perier       mlir::Type elementType =
24978a1ce2d6SjeanPerier           getLlvmObjectTypeFromBoxType(coor.getMemref().getType());
2498fac349a1SChristian Sigg       while (auto arrayTy =
2499fac349a1SChristian Sigg                  mlir::dyn_cast<mlir::LLVM::LLVMArrayType>(elementType))
25003ce7e4b2SJean Perier         elementType = arrayTy.getElementType();
25015d27abe6SValentin Clement       args.clear();
2502bd7eff1fSMarkus Böck       args.push_back(0);
2503a89b0480SValentin Clement       if (!coor.getLenParams().empty()) {
25045d27abe6SValentin Clement         // If type parameters are present, then we don't want to use a GEPOp
25055d27abe6SValentin Clement         // as below, as the LLVM struct type cannot be statically defined.
25065d27abe6SValentin Clement         TODO(loc, "derived type with type parameters");
25075d27abe6SValentin Clement       }
2508783222efSLeandro Lupori       llvm::SmallVector<mlir::Value> indices = convertSubcomponentIndices(
2509783222efSLeandro Lupori           loc, elementType,
2510d8b672daSjeanPerier           operands.slice(coor.getSubcomponentOperandIndex(),
2511783222efSLeandro Lupori                          coor.getSubcomponent().size()));
2512783222efSLeandro Lupori       args.append(indices.begin(), indices.end());
25138a1ce2d6SjeanPerier       rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(coor, llvmPtrTy,
25148a1ce2d6SjeanPerier                                                      elementType, addr, args);
251544e58509SEric Schweitz       return mlir::success();
25165d27abe6SValentin Clement     }
25175d27abe6SValentin Clement 
25185d27abe6SValentin Clement     // The array was not boxed, so it must be contiguous. offset is therefore an
25195d27abe6SValentin Clement     // element offset and the base type is kept in the GEP unless the element
25205d27abe6SValentin Clement     // type size is itself dynamic.
25218a1ce2d6SjeanPerier     mlir::Type objectTy = fir::unwrapRefType(coor.getMemref().getType());
25228a1ce2d6SjeanPerier     mlir::Type eleType = fir::unwrapSequenceType(objectTy);
25238a1ce2d6SjeanPerier     mlir::Type gepObjectType = convertType(eleType);
25248a1ce2d6SjeanPerier     llvm::SmallVector<mlir::LLVM::GEPArg> args;
2525a89b0480SValentin Clement     if (coor.getSubcomponent().empty()) {
25265d27abe6SValentin Clement       // No subcomponent.
2527a89b0480SValentin Clement       if (!coor.getLenParams().empty()) {
25285d27abe6SValentin Clement         // Type parameters. Adjust element size explicitly.
25295d27abe6SValentin Clement         auto eleTy = fir::dyn_cast_ptrEleTy(coor.getType());
25305d27abe6SValentin Clement         assert(eleTy && "result must be a reference-like type");
25315d27abe6SValentin Clement         if (fir::characterWithDynamicLen(eleTy)) {
2532a89b0480SValentin Clement           assert(coor.getLenParams().size() == 1);
2533649439e7SValentin Clement           auto length = integerCast(loc, rewriter, idxTy,
2534d8b672daSjeanPerier                                     operands[coor.getLenParamsOperandIndex()]);
2535bdacd56fSTom Eccles           offset = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, offset,
2536bdacd56fSTom Eccles                                                       length, nsw);
25375d27abe6SValentin Clement         } else {
25385d27abe6SValentin Clement           TODO(loc, "compute size of derived type with type parameters");
25395d27abe6SValentin Clement         }
25405d27abe6SValentin Clement       }
25418a1ce2d6SjeanPerier       args.push_back(offset);
25428a1ce2d6SjeanPerier     } else {
25438a1ce2d6SjeanPerier       // There are subcomponents.
25448a1ce2d6SjeanPerier       args.push_back(offset);
2545783222efSLeandro Lupori       llvm::SmallVector<mlir::Value> indices = convertSubcomponentIndices(
25468a1ce2d6SjeanPerier           loc, gepObjectType,
2547d8b672daSjeanPerier           operands.slice(coor.getSubcomponentOperandIndex(),
2548783222efSLeandro Lupori                          coor.getSubcomponent().size()));
2549783222efSLeandro Lupori       args.append(indices.begin(), indices.end());
25505d27abe6SValentin Clement     }
25518a1ce2d6SjeanPerier     rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(
25528a1ce2d6SjeanPerier         coor, llvmPtrTy, gepObjectType, adaptor.getMemref(), args);
255344e58509SEric Schweitz     return mlir::success();
25545d27abe6SValentin Clement   }
25555d27abe6SValentin Clement };
2556dc48849fSKiran Chandramohan } // namespace
2557dc48849fSKiran Chandramohan 
2558dc48849fSKiran Chandramohan /// Convert to (memory) reference to a reference to a subobject.
2559dc48849fSKiran Chandramohan /// The coordinate_of op is a Swiss army knife operation that can be used on
2560dc48849fSKiran Chandramohan /// (memory) references to records, arrays, complex, etc. as well as boxes.
2561dc48849fSKiran Chandramohan /// With unboxed arrays, there is the restriction that the array have a static
2562dc48849fSKiran Chandramohan /// shape in all but the last column.
2563dc48849fSKiran Chandramohan struct CoordinateOpConversion
2564e9639e9cSValentin Clement (バレンタイン クレメン)     : public fir::FIROpAndTypeConversion<fir::CoordinateOp> {
2565dc48849fSKiran Chandramohan   using FIROpAndTypeConversion::FIROpAndTypeConversion;
2566dc48849fSKiran Chandramohan 
2567db791b27SRamkumar Ramachandra   llvm::LogicalResult
2568dc48849fSKiran Chandramohan   doRewrite(fir::CoordinateOp coor, mlir::Type ty, OpAdaptor adaptor,
2569dc48849fSKiran Chandramohan             mlir::ConversionPatternRewriter &rewriter) const override {
2570dc48849fSKiran Chandramohan     mlir::ValueRange operands = adaptor.getOperands();
2571dc48849fSKiran Chandramohan 
2572dc48849fSKiran Chandramohan     mlir::Location loc = coor.getLoc();
2573dc48849fSKiran Chandramohan     mlir::Value base = operands[0];
2574dc48849fSKiran Chandramohan     mlir::Type baseObjectTy = coor.getBaseType();
2575dc48849fSKiran Chandramohan     mlir::Type objectTy = fir::dyn_cast_ptrOrBoxEleTy(baseObjectTy);
2576dc48849fSKiran Chandramohan     assert(objectTy && "fir.coordinate_of expects a reference type");
25778a1ce2d6SjeanPerier     mlir::Type llvmObjectTy = convertType(objectTy);
2578dc48849fSKiran Chandramohan 
2579dc48849fSKiran Chandramohan     // Complex type - basically, extract the real or imaginary part
25808a1ce2d6SjeanPerier     // FIXME: double check why this is done before the fir.box case below.
2581dc48849fSKiran Chandramohan     if (fir::isa_complex(objectTy)) {
25828a1ce2d6SjeanPerier       mlir::Value gep =
25838a1ce2d6SjeanPerier           genGEP(loc, llvmObjectTy, rewriter, base, 0, operands[1]);
2584dc48849fSKiran Chandramohan       rewriter.replaceOp(coor, gep);
258544e58509SEric Schweitz       return mlir::success();
2586dc48849fSKiran Chandramohan     }
2587dc48849fSKiran Chandramohan 
2588dc48849fSKiran Chandramohan     // Boxed type - get the base pointer from the box
2589fac349a1SChristian Sigg     if (mlir::dyn_cast<fir::BaseBoxType>(baseObjectTy))
25908a1ce2d6SjeanPerier       return doRewriteBox(coor, operands, loc, rewriter);
2591dc48849fSKiran Chandramohan 
259203efa5a3SAndrzej Warzynski     // Reference, pointer or a heap type
2593fac349a1SChristian Sigg     if (mlir::isa<fir::ReferenceType, fir::PointerType, fir::HeapType>(
2594fac349a1SChristian Sigg             baseObjectTy))
25958a1ce2d6SjeanPerier       return doRewriteRefOrPtr(coor, llvmObjectTy, operands, loc, rewriter);
2596dc48849fSKiran Chandramohan 
2597dc48849fSKiran Chandramohan     return rewriter.notifyMatchFailure(
2598dc48849fSKiran Chandramohan         coor, "fir.coordinate_of base operand has unsupported type");
2599dc48849fSKiran Chandramohan   }
2600dc48849fSKiran Chandramohan 
260103efa5a3SAndrzej Warzynski   static unsigned getFieldNumber(fir::RecordType ty, mlir::Value op) {
2602dc48849fSKiran Chandramohan     return fir::hasDynamicSize(ty)
2603dc48849fSKiran Chandramohan                ? op.getDefiningOp()
2604dc48849fSKiran Chandramohan                      ->getAttrOfType<mlir::IntegerAttr>("field")
2605dc48849fSKiran Chandramohan                      .getInt()
2606af40f99eSJean Perier                : getConstantIntValue(op);
2607dc48849fSKiran Chandramohan   }
2608dc48849fSKiran Chandramohan 
260903efa5a3SAndrzej Warzynski   static bool hasSubDimensions(mlir::Type type) {
2610fac349a1SChristian Sigg     return mlir::isa<fir::SequenceType, fir::RecordType, mlir::TupleType>(type);
2611dc48849fSKiran Chandramohan   }
2612dc48849fSKiran Chandramohan 
2613dc48849fSKiran Chandramohan   /// Check whether this form of `!fir.coordinate_of` is supported. These
2614dc48849fSKiran Chandramohan   /// additional checks are required, because we are not yet able to convert
2615dc48849fSKiran Chandramohan   /// all valid forms of `!fir.coordinate_of`.
2616dc48849fSKiran Chandramohan   /// TODO: Either implement the unsupported cases or extend the verifier
2617dc48849fSKiran Chandramohan   /// in FIROps.cpp instead.
261803efa5a3SAndrzej Warzynski   static bool supportedCoordinate(mlir::Type type, mlir::ValueRange coors) {
2619dc48849fSKiran Chandramohan     const std::size_t numOfCoors = coors.size();
2620dc48849fSKiran Chandramohan     std::size_t i = 0;
2621dc48849fSKiran Chandramohan     bool subEle = false;
2622dc48849fSKiran Chandramohan     bool ptrEle = false;
2623dc48849fSKiran Chandramohan     for (; i < numOfCoors; ++i) {
2624dc48849fSKiran Chandramohan       mlir::Value nxtOpnd = coors[i];
2625fac349a1SChristian Sigg       if (auto arrTy = mlir::dyn_cast<fir::SequenceType>(type)) {
2626dc48849fSKiran Chandramohan         subEle = true;
2627dc48849fSKiran Chandramohan         i += arrTy.getDimension() - 1;
2628dc48849fSKiran Chandramohan         type = arrTy.getEleTy();
2629fac349a1SChristian Sigg       } else if (auto recTy = mlir::dyn_cast<fir::RecordType>(type)) {
2630dc48849fSKiran Chandramohan         subEle = true;
2631dc48849fSKiran Chandramohan         type = recTy.getType(getFieldNumber(recTy, nxtOpnd));
2632fac349a1SChristian Sigg       } else if (auto tupTy = mlir::dyn_cast<mlir::TupleType>(type)) {
2633dc48849fSKiran Chandramohan         subEle = true;
2634af40f99eSJean Perier         type = tupTy.getType(getConstantIntValue(nxtOpnd));
2635dc48849fSKiran Chandramohan       } else {
2636dc48849fSKiran Chandramohan         ptrEle = true;
2637dc48849fSKiran Chandramohan       }
2638dc48849fSKiran Chandramohan     }
2639dc48849fSKiran Chandramohan     if (ptrEle)
2640dc48849fSKiran Chandramohan       return (!subEle) && (numOfCoors == 1);
2641dc48849fSKiran Chandramohan     return subEle && (i >= numOfCoors);
2642dc48849fSKiran Chandramohan   }
2643dc48849fSKiran Chandramohan 
2644dc48849fSKiran Chandramohan   /// Walk the abstract memory layout and determine if the path traverses any
2645dc48849fSKiran Chandramohan   /// array types with unknown shape. Return true iff all the array types have a
2646dc48849fSKiran Chandramohan   /// constant shape along the path.
264703efa5a3SAndrzej Warzynski   static bool arraysHaveKnownShape(mlir::Type type, mlir::ValueRange coors) {
264803efa5a3SAndrzej Warzynski     for (std::size_t i = 0, sz = coors.size(); i < sz; ++i) {
2649dc48849fSKiran Chandramohan       mlir::Value nxtOpnd = coors[i];
2650fac349a1SChristian Sigg       if (auto arrTy = mlir::dyn_cast<fir::SequenceType>(type)) {
2651dc48849fSKiran Chandramohan         if (fir::sequenceWithNonConstantShape(arrTy))
2652dc48849fSKiran Chandramohan           return false;
2653dc48849fSKiran Chandramohan         i += arrTy.getDimension() - 1;
2654dc48849fSKiran Chandramohan         type = arrTy.getEleTy();
2655fac349a1SChristian Sigg       } else if (auto strTy = mlir::dyn_cast<fir::RecordType>(type)) {
2656dc48849fSKiran Chandramohan         type = strTy.getType(getFieldNumber(strTy, nxtOpnd));
2657fac349a1SChristian Sigg       } else if (auto strTy = mlir::dyn_cast<mlir::TupleType>(type)) {
2658af40f99eSJean Perier         type = strTy.getType(getConstantIntValue(nxtOpnd));
2659dc48849fSKiran Chandramohan       } else {
2660dc48849fSKiran Chandramohan         return true;
2661dc48849fSKiran Chandramohan       }
2662dc48849fSKiran Chandramohan     }
2663dc48849fSKiran Chandramohan     return true;
2664dc48849fSKiran Chandramohan   }
2665dc48849fSKiran Chandramohan 
2666dc48849fSKiran Chandramohan private:
2667db791b27SRamkumar Ramachandra   llvm::LogicalResult
26688a1ce2d6SjeanPerier   doRewriteBox(fir::CoordinateOp coor, mlir::ValueRange operands,
2669dc48849fSKiran Chandramohan                mlir::Location loc,
2670dc48849fSKiran Chandramohan                mlir::ConversionPatternRewriter &rewriter) const {
2671dc48849fSKiran Chandramohan     mlir::Type boxObjTy = coor.getBaseType();
2672fac349a1SChristian Sigg     assert(mlir::dyn_cast<fir::BaseBoxType>(boxObjTy) &&
2673fac349a1SChristian Sigg            "This is not a `fir.box`");
26748a1ce2d6SjeanPerier     TypePair boxTyPair = getBoxTypePair(boxObjTy);
2675dc48849fSKiran Chandramohan 
2676dc48849fSKiran Chandramohan     mlir::Value boxBaseAddr = operands[0];
2677dc48849fSKiran Chandramohan 
2678dc48849fSKiran Chandramohan     // 1. SPECIAL CASE (uses `fir.len_param_index`):
2679dc48849fSKiran Chandramohan     //   %box = ... : !fir.box<!fir.type<derived{len1:i32}>>
2680dc48849fSKiran Chandramohan     //   %lenp = fir.len_param_index len1, !fir.type<derived{len1:i32}>
2681dc48849fSKiran Chandramohan     //   %addr = coordinate_of %box, %lenp
2682dc48849fSKiran Chandramohan     if (coor.getNumOperands() == 2) {
2683dc48849fSKiran Chandramohan       mlir::Operation *coordinateDef =
2684dc48849fSKiran Chandramohan           (*coor.getCoor().begin()).getDefiningOp();
268544e58509SEric Schweitz       if (mlir::isa_and_nonnull<fir::LenParamIndexOp>(coordinateDef))
2686dc48849fSKiran Chandramohan         TODO(loc,
2687dc48849fSKiran Chandramohan              "fir.coordinate_of - fir.len_param_index is not supported yet");
2688dc48849fSKiran Chandramohan     }
2689dc48849fSKiran Chandramohan 
2690dc48849fSKiran Chandramohan     // 2. GENERAL CASE:
2691dc48849fSKiran Chandramohan     // 2.1. (`fir.array`)
2692dc48849fSKiran Chandramohan     //   %box = ... : !fix.box<!fir.array<?xU>>
2693dc48849fSKiran Chandramohan     //   %idx = ... : index
2694dc48849fSKiran Chandramohan     //   %resultAddr = coordinate_of %box, %idx : !fir.ref<U>
2695dc48849fSKiran Chandramohan     // 2.2 (`fir.derived`)
2696dc48849fSKiran Chandramohan     //   %box = ... : !fix.box<!fir.type<derived_type{field_1:i32}>>
2697dc48849fSKiran Chandramohan     //   %idx = ... : i32
2698dc48849fSKiran Chandramohan     //   %resultAddr = coordinate_of %box, %idx : !fir.ref<i32>
2699dc48849fSKiran Chandramohan     // 2.3 (`fir.derived` inside `fir.array`)
2700dc48849fSKiran Chandramohan     //   %box = ... : !fir.box<!fir.array<10 x !fir.type<derived_1{field_1:f32,
2701dc48849fSKiran Chandramohan     //   field_2:f32}>>> %idx1 = ... : index %idx2 = ... : i32 %resultAddr =
2702dc48849fSKiran Chandramohan     //   coordinate_of %box, %idx1, %idx2 : !fir.ref<f32>
2703dc48849fSKiran Chandramohan     // 2.4. TODO: Either document or disable any other case that the following
2704dc48849fSKiran Chandramohan     //  implementation might convert.
2705dc48849fSKiran Chandramohan     mlir::Value resultAddr =
27068a1ce2d6SjeanPerier         getBaseAddrFromBox(loc, boxTyPair, boxBaseAddr, rewriter);
270703efa5a3SAndrzej Warzynski     // Component Type
270803efa5a3SAndrzej Warzynski     auto cpnTy = fir::dyn_cast_ptrOrBoxEleTy(boxObjTy);
27098a1ce2d6SjeanPerier     mlir::Type llvmPtrTy = ::getLlvmPtrType(coor.getContext());
27108a1ce2d6SjeanPerier     mlir::Type byteTy = ::getI8Type(coor.getContext());
2711e553ac4dSJeff Niu     mlir::LLVM::IntegerOverflowFlags nsw =
2712e553ac4dSJeff Niu         mlir::LLVM::IntegerOverflowFlags::nsw;
2713dc48849fSKiran Chandramohan 
2714dc48849fSKiran Chandramohan     for (unsigned i = 1, last = operands.size(); i < last; ++i) {
2715fac349a1SChristian Sigg       if (auto arrTy = mlir::dyn_cast<fir::SequenceType>(cpnTy)) {
2716dc48849fSKiran Chandramohan         if (i != 1)
2717dc48849fSKiran Chandramohan           TODO(loc, "fir.array nested inside other array and/or derived type");
2718dc48849fSKiran Chandramohan         // Applies byte strides from the box. Ignore lower bound from box
2719dc48849fSKiran Chandramohan         // since fir.coordinate_of indexes are zero based. Lowering takes care
2720dc48849fSKiran Chandramohan         // of lower bound aspects. This both accounts for dynamically sized
2721dc48849fSKiran Chandramohan         // types and non contiguous arrays.
2722dc48849fSKiran Chandramohan         auto idxTy = lowerTy().indexType();
2723dc48849fSKiran Chandramohan         mlir::Value off = genConstantIndex(loc, idxTy, rewriter, 0);
2724dc48849fSKiran Chandramohan         for (unsigned index = i, lastIndex = i + arrTy.getDimension();
2725dc48849fSKiran Chandramohan              index < lastIndex; ++index) {
27268a1ce2d6SjeanPerier           mlir::Value stride = getStrideFromBox(loc, boxTyPair, operands[0],
27278a1ce2d6SjeanPerier                                                 index - i, rewriter);
2728bdacd56fSTom Eccles           auto sc = rewriter.create<mlir::LLVM::MulOp>(
2729bdacd56fSTom Eccles               loc, idxTy, operands[index], stride, nsw);
2730bdacd56fSTom Eccles           off = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, off, nsw);
2731dc48849fSKiran Chandramohan         }
2732bd7eff1fSMarkus Böck         resultAddr = rewriter.create<mlir::LLVM::GEPOp>(
27338a1ce2d6SjeanPerier             loc, llvmPtrTy, byteTy, resultAddr,
2734bd7eff1fSMarkus Böck             llvm::ArrayRef<mlir::LLVM::GEPArg>{off});
2735dc48849fSKiran Chandramohan         i += arrTy.getDimension() - 1;
273603efa5a3SAndrzej Warzynski         cpnTy = arrTy.getEleTy();
2737fac349a1SChristian Sigg       } else if (auto recTy = mlir::dyn_cast<fir::RecordType>(cpnTy)) {
2738dc48849fSKiran Chandramohan         mlir::Value nxtOpnd = operands[i];
273903efa5a3SAndrzej Warzynski         cpnTy = recTy.getType(getFieldNumber(recTy, nxtOpnd));
27408a1ce2d6SjeanPerier         auto llvmRecTy = lowerTy().convertType(recTy);
27418a1ce2d6SjeanPerier         resultAddr = rewriter.create<mlir::LLVM::GEPOp>(
27428a1ce2d6SjeanPerier             loc, llvmPtrTy, llvmRecTy, resultAddr,
2743bd7eff1fSMarkus Böck             llvm::ArrayRef<mlir::LLVM::GEPArg>{0, nxtOpnd});
2744dc48849fSKiran Chandramohan       } else {
2745dc48849fSKiran Chandramohan         fir::emitFatalError(loc, "unexpected type in coordinate_of");
2746dc48849fSKiran Chandramohan       }
2747dc48849fSKiran Chandramohan     }
2748dc48849fSKiran Chandramohan 
27498a1ce2d6SjeanPerier     rewriter.replaceOp(coor, resultAddr);
275044e58509SEric Schweitz     return mlir::success();
2751dc48849fSKiran Chandramohan   }
2752dc48849fSKiran Chandramohan 
2753db791b27SRamkumar Ramachandra   llvm::LogicalResult
27548a1ce2d6SjeanPerier   doRewriteRefOrPtr(fir::CoordinateOp coor, mlir::Type llvmObjectTy,
2755dc48849fSKiran Chandramohan                     mlir::ValueRange operands, mlir::Location loc,
2756dc48849fSKiran Chandramohan                     mlir::ConversionPatternRewriter &rewriter) const {
2757dc48849fSKiran Chandramohan     mlir::Type baseObjectTy = coor.getBaseType();
2758dc48849fSKiran Chandramohan 
275903efa5a3SAndrzej Warzynski     // Component Type
276003efa5a3SAndrzej Warzynski     mlir::Type cpnTy = fir::dyn_cast_ptrOrBoxEleTy(baseObjectTy);
276103efa5a3SAndrzej Warzynski     bool hasSubdimension = hasSubDimensions(cpnTy);
2762dc48849fSKiran Chandramohan     bool columnIsDeferred = !hasSubdimension;
2763dc48849fSKiran Chandramohan 
276403efa5a3SAndrzej Warzynski     if (!supportedCoordinate(cpnTy, operands.drop_front(1)))
2765dc48849fSKiran Chandramohan       TODO(loc, "unsupported combination of coordinate operands");
2766dc48849fSKiran Chandramohan 
2767dc48849fSKiran Chandramohan     const bool hasKnownShape =
276803efa5a3SAndrzej Warzynski         arraysHaveKnownShape(cpnTy, operands.drop_front(1));
2769dc48849fSKiran Chandramohan 
2770dc48849fSKiran Chandramohan     // If only the column is `?`, then we can simply place the column value in
2771dc48849fSKiran Chandramohan     // the 0-th GEP position.
2772fac349a1SChristian Sigg     if (auto arrTy = mlir::dyn_cast<fir::SequenceType>(cpnTy)) {
2773dc48849fSKiran Chandramohan       if (!hasKnownShape) {
2774dc48849fSKiran Chandramohan         const unsigned sz = arrTy.getDimension();
2775dc48849fSKiran Chandramohan         if (arraysHaveKnownShape(arrTy.getEleTy(),
2776dc48849fSKiran Chandramohan                                  operands.drop_front(1 + sz))) {
277703efa5a3SAndrzej Warzynski           fir::SequenceType::ShapeRef shape = arrTy.getShape();
2778dc48849fSKiran Chandramohan           bool allConst = true;
2779dc48849fSKiran Chandramohan           for (unsigned i = 0; i < sz - 1; ++i) {
2780dc48849fSKiran Chandramohan             if (shape[i] < 0) {
2781dc48849fSKiran Chandramohan               allConst = false;
2782dc48849fSKiran Chandramohan               break;
2783dc48849fSKiran Chandramohan             }
2784dc48849fSKiran Chandramohan           }
2785dc48849fSKiran Chandramohan           if (allConst)
2786dc48849fSKiran Chandramohan             columnIsDeferred = true;
2787dc48849fSKiran Chandramohan         }
2788dc48849fSKiran Chandramohan       }
2789dc48849fSKiran Chandramohan     }
2790dc48849fSKiran Chandramohan 
279103efa5a3SAndrzej Warzynski     if (fir::hasDynamicSize(fir::unwrapSequenceType(cpnTy)))
279203efa5a3SAndrzej Warzynski       return mlir::emitError(
2793dc48849fSKiran Chandramohan           loc, "fir.coordinate_of with a dynamic element size is unsupported");
2794dc48849fSKiran Chandramohan 
2795dc48849fSKiran Chandramohan     if (hasKnownShape || columnIsDeferred) {
2796bd7eff1fSMarkus Böck       llvm::SmallVector<mlir::LLVM::GEPArg> offs;
2797dc48849fSKiran Chandramohan       if (hasKnownShape && hasSubdimension) {
2798bd7eff1fSMarkus Böck         offs.push_back(0);
2799dc48849fSKiran Chandramohan       }
280022426110SRamkumar Ramachandra       std::optional<int> dims;
280144e58509SEric Schweitz       llvm::SmallVector<mlir::Value> arrIdx;
280203efa5a3SAndrzej Warzynski       for (std::size_t i = 1, sz = operands.size(); i < sz; ++i) {
2803dc48849fSKiran Chandramohan         mlir::Value nxtOpnd = operands[i];
2804dc48849fSKiran Chandramohan 
280503efa5a3SAndrzej Warzynski         if (!cpnTy)
280603efa5a3SAndrzej Warzynski           return mlir::emitError(loc, "invalid coordinate/check failed");
2807dc48849fSKiran Chandramohan 
2808dc48849fSKiran Chandramohan         // check if the i-th coordinate relates to an array
28095413bf1bSKazu Hirata         if (dims) {
2810dc48849fSKiran Chandramohan           arrIdx.push_back(nxtOpnd);
2811dc48849fSKiran Chandramohan           int dimsLeft = *dims;
2812dc48849fSKiran Chandramohan           if (dimsLeft > 1) {
2813dc48849fSKiran Chandramohan             dims = dimsLeft - 1;
2814dc48849fSKiran Chandramohan             continue;
2815dc48849fSKiran Chandramohan           }
2816e6a4346bSScott Manley           cpnTy = mlir::cast<fir::SequenceType>(cpnTy).getElementType();
2817dc48849fSKiran Chandramohan           // append array range in reverse (FIR arrays are column-major)
2818dc48849fSKiran Chandramohan           offs.append(arrIdx.rbegin(), arrIdx.rend());
2819dc48849fSKiran Chandramohan           arrIdx.clear();
2820dc48849fSKiran Chandramohan           dims.reset();
2821dc48849fSKiran Chandramohan           continue;
2822dc48849fSKiran Chandramohan         }
2823fac349a1SChristian Sigg         if (auto arrTy = mlir::dyn_cast<fir::SequenceType>(cpnTy)) {
2824dc48849fSKiran Chandramohan           int d = arrTy.getDimension() - 1;
2825dc48849fSKiran Chandramohan           if (d > 0) {
2826dc48849fSKiran Chandramohan             dims = d;
2827dc48849fSKiran Chandramohan             arrIdx.push_back(nxtOpnd);
2828dc48849fSKiran Chandramohan             continue;
2829dc48849fSKiran Chandramohan           }
2830e6a4346bSScott Manley           cpnTy = mlir::cast<fir::SequenceType>(cpnTy).getElementType();
2831dc48849fSKiran Chandramohan           offs.push_back(nxtOpnd);
2832dc48849fSKiran Chandramohan           continue;
2833dc48849fSKiran Chandramohan         }
2834dc48849fSKiran Chandramohan 
2835dc48849fSKiran Chandramohan         // check if the i-th coordinate relates to a field
2836fac349a1SChristian Sigg         if (auto recTy = mlir::dyn_cast<fir::RecordType>(cpnTy))
283703efa5a3SAndrzej Warzynski           cpnTy = recTy.getType(getFieldNumber(recTy, nxtOpnd));
2838fac349a1SChristian Sigg         else if (auto tupTy = mlir::dyn_cast<mlir::TupleType>(cpnTy))
2839af40f99eSJean Perier           cpnTy = tupTy.getType(getConstantIntValue(nxtOpnd));
2840dc48849fSKiran Chandramohan         else
284103efa5a3SAndrzej Warzynski           cpnTy = nullptr;
2842dc48849fSKiran Chandramohan 
2843dc48849fSKiran Chandramohan         offs.push_back(nxtOpnd);
2844dc48849fSKiran Chandramohan       }
28455413bf1bSKazu Hirata       if (dims)
2846dc48849fSKiran Chandramohan         offs.append(arrIdx.rbegin(), arrIdx.rend());
2847dc48849fSKiran Chandramohan       mlir::Value base = operands[0];
28488a1ce2d6SjeanPerier       mlir::Value retval = genGEP(loc, llvmObjectTy, rewriter, base, offs);
2849dc48849fSKiran Chandramohan       rewriter.replaceOp(coor, retval);
285044e58509SEric Schweitz       return mlir::success();
2851dc48849fSKiran Chandramohan     }
2852dc48849fSKiran Chandramohan 
285303efa5a3SAndrzej Warzynski     return mlir::emitError(
285403efa5a3SAndrzej Warzynski         loc, "fir.coordinate_of base operand has unsupported type");
2855dc48849fSKiran Chandramohan   }
2856dc48849fSKiran Chandramohan };
2857dc48849fSKiran Chandramohan 
2858dc48849fSKiran Chandramohan /// Convert `fir.field_index`. The conversion depends on whether the size of
2859dc48849fSKiran Chandramohan /// the record is static or dynamic.
2860e9639e9cSValentin Clement (バレンタイン クレメン) struct FieldIndexOpConversion : public fir::FIROpConversion<fir::FieldIndexOp> {
2861dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2862dc48849fSKiran Chandramohan 
2863dc48849fSKiran Chandramohan   // NB: most field references should be resolved by this point
2864db791b27SRamkumar Ramachandra   llvm::LogicalResult
2865dc48849fSKiran Chandramohan   matchAndRewrite(fir::FieldIndexOp field, OpAdaptor adaptor,
2866dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2867fac349a1SChristian Sigg     auto recTy = mlir::cast<fir::RecordType>(field.getOnType());
2868dc48849fSKiran Chandramohan     unsigned index = recTy.getFieldIndex(field.getFieldId());
2869dc48849fSKiran Chandramohan 
2870dc48849fSKiran Chandramohan     if (!fir::hasDynamicSize(recTy)) {
2871dc48849fSKiran Chandramohan       // Derived type has compile-time constant layout. Return index of the
2872dc48849fSKiran Chandramohan       // component type in the parent type (to be used in GEP).
2873dc48849fSKiran Chandramohan       rewriter.replaceOp(field, mlir::ValueRange{genConstantOffset(
2874dc48849fSKiran Chandramohan                                     field.getLoc(), rewriter, index)});
287544e58509SEric Schweitz       return mlir::success();
2876dc48849fSKiran Chandramohan     }
2877dc48849fSKiran Chandramohan 
2878dc48849fSKiran Chandramohan     // Derived type has compile-time constant layout. Call the compiler
2879dc48849fSKiran Chandramohan     // generated function to determine the byte offset of the field at runtime.
2880dc48849fSKiran Chandramohan     // This returns a non-constant.
288144e58509SEric Schweitz     mlir::FlatSymbolRefAttr symAttr = mlir::SymbolRefAttr::get(
2882dc48849fSKiran Chandramohan         field.getContext(), getOffsetMethodName(recTy, field.getFieldId()));
288344e58509SEric Schweitz     mlir::NamedAttribute callAttr = rewriter.getNamedAttr("callee", symAttr);
288444e58509SEric Schweitz     mlir::NamedAttribute fieldAttr = rewriter.getNamedAttr(
2885dc48849fSKiran Chandramohan         "field", mlir::IntegerAttr::get(lowerTy().indexType(), index));
2886dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
2887dc48849fSKiran Chandramohan         field, lowerTy().offsetType(), adaptor.getOperands(),
2888fde3c16aSSirui Mu         addLLVMOpBundleAttrs(rewriter, {callAttr, fieldAttr},
2889fde3c16aSSirui Mu                              adaptor.getOperands().size()));
289044e58509SEric Schweitz     return mlir::success();
2891dc48849fSKiran Chandramohan   }
2892dc48849fSKiran Chandramohan 
2893dc48849fSKiran Chandramohan   // Re-Construct the name of the compiler generated method that calculates the
2894dc48849fSKiran Chandramohan   // offset
2895dc48849fSKiran Chandramohan   inline static std::string getOffsetMethodName(fir::RecordType recTy,
2896dc48849fSKiran Chandramohan                                                 llvm::StringRef field) {
2897dc48849fSKiran Chandramohan     return recTy.getName().str() + "P." + field.str() + ".offset";
2898dc48849fSKiran Chandramohan   }
2899dc48849fSKiran Chandramohan };
2900dc48849fSKiran Chandramohan 
2901dc48849fSKiran Chandramohan /// Convert `fir.end`
2902e9639e9cSValentin Clement (バレンタイン クレメン) struct FirEndOpConversion : public fir::FIROpConversion<fir::FirEndOp> {
2903dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2904dc48849fSKiran Chandramohan 
2905db791b27SRamkumar Ramachandra   llvm::LogicalResult
2906dc48849fSKiran Chandramohan   matchAndRewrite(fir::FirEndOp firEnd, OpAdaptor,
2907dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
2908dc48849fSKiran Chandramohan     TODO(firEnd.getLoc(), "fir.end codegen");
290944e58509SEric Schweitz     return mlir::failure();
2910dc48849fSKiran Chandramohan   }
2911dc48849fSKiran Chandramohan };
2912dc48849fSKiran Chandramohan 
291316bd0fe5SValentin Clement /// Lower `fir.type_desc` to a global addr.
2914e9639e9cSValentin Clement (バレンタイン クレメン) struct TypeDescOpConversion : public fir::FIROpConversion<fir::TypeDescOp> {
2915dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
2916dc48849fSKiran Chandramohan 
2917db791b27SRamkumar Ramachandra   llvm::LogicalResult
291816bd0fe5SValentin Clement   matchAndRewrite(fir::TypeDescOp typeDescOp, OpAdaptor adaptor,
2919dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
292016bd0fe5SValentin Clement     mlir::Type inTy = typeDescOp.getInType();
2921fac349a1SChristian Sigg     assert(mlir::isa<fir::RecordType>(inTy) && "expecting fir.type");
2922fac349a1SChristian Sigg     auto recordType = mlir::dyn_cast<fir::RecordType>(inTy);
292316bd0fe5SValentin Clement     auto module = typeDescOp.getOperation()->getParentOfType<mlir::ModuleOp>();
292416bd0fe5SValentin Clement     std::string typeDescName =
2925cfd4c180SSlava Zakharin         this->options.typeDescriptorsRenamedForAssembly
2926cfd4c180SSlava Zakharin             ? fir::NameUniquer::getTypeDescriptorAssemblyName(
2927cfd4c180SSlava Zakharin                   recordType.getName())
2928cfd4c180SSlava Zakharin             : fir::NameUniquer::getTypeDescriptorName(recordType.getName());
29298a1ce2d6SjeanPerier     auto llvmPtrTy = ::getLlvmPtrType(typeDescOp.getContext());
293016bd0fe5SValentin Clement     if (auto global = module.lookupSymbol<mlir::LLVM::GlobalOp>(typeDescName)) {
29318a1ce2d6SjeanPerier       rewriter.replaceOpWithNewOp<mlir::LLVM::AddressOfOp>(
29328a1ce2d6SjeanPerier           typeDescOp, llvmPtrTy, global.getSymName());
293316bd0fe5SValentin Clement       return mlir::success();
293416bd0fe5SValentin Clement     } else if (auto global = module.lookupSymbol<fir::GlobalOp>(typeDescName)) {
29358a1ce2d6SjeanPerier       rewriter.replaceOpWithNewOp<mlir::LLVM::AddressOfOp>(
29368a1ce2d6SjeanPerier           typeDescOp, llvmPtrTy, global.getSymName());
293716bd0fe5SValentin Clement       return mlir::success();
293816bd0fe5SValentin Clement     }
293944e58509SEric Schweitz     return mlir::failure();
2940dc48849fSKiran Chandramohan   }
2941dc48849fSKiran Chandramohan };
2942dc48849fSKiran Chandramohan 
2943dc48849fSKiran Chandramohan /// Lower `fir.has_value` operation to `llvm.return` operation.
2944e73cf2f0SMatthias Springer struct HasValueOpConversion
2945e73cf2f0SMatthias Springer     : public mlir::OpConversionPattern<fir::HasValueOp> {
2946e73cf2f0SMatthias Springer   using OpConversionPattern::OpConversionPattern;
2947dc48849fSKiran Chandramohan 
2948db791b27SRamkumar Ramachandra   llvm::LogicalResult
2949dc48849fSKiran Chandramohan   matchAndRewrite(fir::HasValueOp op, OpAdaptor adaptor,
2950dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
295144e58509SEric Schweitz     rewriter.replaceOpWithNewOp<mlir::LLVM::ReturnOp>(op,
295244e58509SEric Schweitz                                                       adaptor.getOperands());
295344e58509SEric Schweitz     return mlir::success();
2954dc48849fSKiran Chandramohan   }
2955dc48849fSKiran Chandramohan };
2956dc48849fSKiran Chandramohan 
2957910b9372SJie Fu #ifndef NDEBUG
2958c8517f17SLeandro Lupori // Check if attr's type is compatible with ty.
2959c8517f17SLeandro Lupori //
2960c8517f17SLeandro Lupori // This is done by comparing attr's element type, converted to LLVM type,
2961c8517f17SLeandro Lupori // with ty's element type.
2962c8517f17SLeandro Lupori //
2963c8517f17SLeandro Lupori // Only integer and floating point (including complex) attributes are
2964c8517f17SLeandro Lupori // supported. Also, attr is expected to have a TensorType and ty is expected
2965c8517f17SLeandro Lupori // to be of LLVMArrayType. If any of the previous conditions is false, then
2966c8517f17SLeandro Lupori // the specified attr and ty are not supported by this function and are
2967c8517f17SLeandro Lupori // assumed to be compatible.
2968c8517f17SLeandro Lupori static inline bool attributeTypeIsCompatible(mlir::MLIRContext *ctx,
2969c8517f17SLeandro Lupori                                              mlir::Attribute attr,
2970c8517f17SLeandro Lupori                                              mlir::Type ty) {
2971c8517f17SLeandro Lupori   // Get attr's LLVM element type.
2972c8517f17SLeandro Lupori   if (!attr)
2973c8517f17SLeandro Lupori     return true;
2974c8517f17SLeandro Lupori   auto intOrFpEleAttr = mlir::dyn_cast<mlir::DenseIntOrFPElementsAttr>(attr);
2975c8517f17SLeandro Lupori   if (!intOrFpEleAttr)
2976c8517f17SLeandro Lupori     return true;
2977c8517f17SLeandro Lupori   auto tensorTy = mlir::dyn_cast<mlir::TensorType>(intOrFpEleAttr.getType());
2978c8517f17SLeandro Lupori   if (!tensorTy)
2979c8517f17SLeandro Lupori     return true;
2980c8517f17SLeandro Lupori   mlir::Type attrEleTy =
2981c8517f17SLeandro Lupori       mlir::LLVMTypeConverter(ctx).convertType(tensorTy.getElementType());
2982c8517f17SLeandro Lupori 
2983c8517f17SLeandro Lupori   // Get ty's element type.
2984c8517f17SLeandro Lupori   auto arrTy = mlir::dyn_cast<mlir::LLVM::LLVMArrayType>(ty);
2985c8517f17SLeandro Lupori   if (!arrTy)
2986c8517f17SLeandro Lupori     return true;
2987c8517f17SLeandro Lupori   mlir::Type eleTy = arrTy.getElementType();
2988c8517f17SLeandro Lupori   while ((arrTy = mlir::dyn_cast<mlir::LLVM::LLVMArrayType>(eleTy)))
2989c8517f17SLeandro Lupori     eleTy = arrTy.getElementType();
2990c8517f17SLeandro Lupori 
2991c8517f17SLeandro Lupori   return attrEleTy == eleTy;
2992c8517f17SLeandro Lupori }
2993910b9372SJie Fu #endif
2994c8517f17SLeandro Lupori 
2995dc48849fSKiran Chandramohan /// Lower `fir.global` operation to `llvm.global` operation.
2996dc48849fSKiran Chandramohan /// `fir.insert_on_range` operations are replaced with constant dense attribute
2997dc48849fSKiran Chandramohan /// if they are applied on the full range.
2998e9639e9cSValentin Clement (バレンタイン クレメン) struct GlobalOpConversion : public fir::FIROpConversion<fir::GlobalOp> {
2999dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3000dc48849fSKiran Chandramohan 
3001db791b27SRamkumar Ramachandra   llvm::LogicalResult
3002dc48849fSKiran Chandramohan   matchAndRewrite(fir::GlobalOp global, OpAdaptor adaptor,
3003dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3004f156b9ceSAbid Qadeer 
3005cd12ffb6SAbid Qadeer     llvm::SmallVector<mlir::Attribute> dbgExprs;
3006f156b9ceSAbid Qadeer 
3007f156b9ceSAbid Qadeer     if (auto fusedLoc = mlir::dyn_cast<mlir::FusedLoc>(global.getLoc())) {
3008afa4681cSAbid Qadeer       if (auto gvExprAttr = mlir::dyn_cast_if_present<mlir::ArrayAttr>(
3009f156b9ceSAbid Qadeer               fusedLoc.getMetadata())) {
3010afa4681cSAbid Qadeer         for (auto attr : gvExprAttr.getAsRange<mlir::Attribute>())
3011afa4681cSAbid Qadeer           if (auto dbgAttr =
3012afa4681cSAbid Qadeer                   mlir::dyn_cast<mlir::LLVM::DIGlobalVariableExpressionAttr>(
3013afa4681cSAbid Qadeer                       attr))
3014afa4681cSAbid Qadeer             dbgExprs.push_back(dbgAttr);
3015f156b9ceSAbid Qadeer       }
3016f156b9ceSAbid Qadeer     }
3017f156b9ceSAbid Qadeer 
3018dc48849fSKiran Chandramohan     auto tyAttr = convertType(global.getType());
30198a1ce2d6SjeanPerier     if (auto boxType = mlir::dyn_cast<fir::BaseBoxType>(global.getType()))
30208a1ce2d6SjeanPerier       tyAttr = this->lowerTy().convertBoxTypeAsStruct(boxType);
3021dc48849fSKiran Chandramohan     auto loc = global.getLoc();
3022c715e2ffSKazu Hirata     mlir::Attribute initAttr = global.getInitVal().value_or(mlir::Attribute());
3023c8517f17SLeandro Lupori     assert(attributeTypeIsCompatible(global.getContext(), initAttr, tyAttr));
3024dc48849fSKiran Chandramohan     auto linkage = convertLinkage(global.getLinkName());
3025c82fb16fSKazu Hirata     auto isConst = global.getConstant().has_value();
3026f156b9ceSAbid Qadeer     mlir::SymbolRefAttr comdat;
3027f156b9ceSAbid Qadeer     llvm::ArrayRef<mlir::NamedAttribute> attrs;
3028dc48849fSKiran Chandramohan     auto g = rewriter.create<mlir::LLVM::GlobalOp>(
3029f156b9ceSAbid Qadeer         loc, tyAttr, isConst, linkage, global.getSymName(), initAttr, 0, 0,
3030cd12ffb6SAbid Qadeer         false, false, comdat, attrs, dbgExprs);
30316b44274dSAndrew Gozillon 
3032c1654c38SValentin Clement (バレンタイン クレメン)     if (global.getAlignment() && *global.getAlignment() > 0)
3033c1654c38SValentin Clement (バレンタイン クレメン)       g.setAlignment(*global.getAlignment());
3034c1654c38SValentin Clement (バレンタイン クレメン) 
30358cb0c3bbSDavid Truby     auto module = global->getParentOfType<mlir::ModuleOp>();
30363e13acfbSValentin Clement (バレンタイン クレメン)     auto gpuMod = global->getParentOfType<mlir::gpu::GPUModuleOp>();
30378cb0c3bbSDavid Truby     // Add comdat if necessary
30388cb0c3bbSDavid Truby     if (fir::getTargetTriple(module).supportsCOMDAT() &&
30398cb0c3bbSDavid Truby         (linkage == mlir::LLVM::Linkage::Linkonce ||
30403e13acfbSValentin Clement (バレンタイン クレメン)          linkage == mlir::LLVM::Linkage::LinkonceODR) &&
30413e13acfbSValentin Clement (バレンタイン クレメン)         !gpuMod) {
30428cb0c3bbSDavid Truby       addComdat(g, rewriter, module);
30438cb0c3bbSDavid Truby     }
30448cb0c3bbSDavid Truby 
30456b44274dSAndrew Gozillon     // Apply all non-Fir::GlobalOp attributes to the LLVM::GlobalOp, preserving
30466b44274dSAndrew Gozillon     // them; whilst taking care not to apply attributes that are lowered in
30476b44274dSAndrew Gozillon     // other ways.
30486b44274dSAndrew Gozillon     llvm::SmallDenseSet<llvm::StringRef> elidedAttrsSet(
30496b44274dSAndrew Gozillon         global.getAttributeNames().begin(), global.getAttributeNames().end());
30506b44274dSAndrew Gozillon     for (auto &attr : global->getAttrs())
30516b44274dSAndrew Gozillon       if (!elidedAttrsSet.contains(attr.getName().strref()))
30526b44274dSAndrew Gozillon         g->setAttr(attr.getName(), attr.getValue());
30536b44274dSAndrew Gozillon 
3054dc48849fSKiran Chandramohan     auto &gr = g.getInitializerRegion();
3055dc48849fSKiran Chandramohan     rewriter.inlineRegionBefore(global.getRegion(), gr, gr.end());
3056dc48849fSKiran Chandramohan     if (!gr.empty()) {
3057dc48849fSKiran Chandramohan       // Replace insert_on_range with a constant dense attribute if the
3058dc48849fSKiran Chandramohan       // initialization is on the full range.
3059dc48849fSKiran Chandramohan       auto insertOnRangeOps = gr.front().getOps<fir::InsertOnRangeOp>();
3060dc48849fSKiran Chandramohan       for (auto insertOp : insertOnRangeOps) {
3061dc48849fSKiran Chandramohan         if (isFullRange(insertOp.getCoor(), insertOp.getType())) {
3062dc48849fSKiran Chandramohan           auto seqTyAttr = convertType(insertOp.getType());
3063dc48849fSKiran Chandramohan           auto *op = insertOp.getVal().getDefiningOp();
3064dc48849fSKiran Chandramohan           auto constant = mlir::dyn_cast<mlir::arith::ConstantOp>(op);
3065dc48849fSKiran Chandramohan           if (!constant) {
3066dc48849fSKiran Chandramohan             auto convertOp = mlir::dyn_cast<fir::ConvertOp>(op);
3067dc48849fSKiran Chandramohan             if (!convertOp)
3068dc48849fSKiran Chandramohan               continue;
306944e58509SEric Schweitz             constant = mlir::cast<mlir::arith::ConstantOp>(
3070dc48849fSKiran Chandramohan                 convertOp.getValue().getDefiningOp());
3071dc48849fSKiran Chandramohan           }
3072dc48849fSKiran Chandramohan           mlir::Type vecType = mlir::VectorType::get(
3073dc48849fSKiran Chandramohan               insertOp.getType().getShape(), constant.getType());
3074dc48849fSKiran Chandramohan           auto denseAttr = mlir::DenseElementsAttr::get(
3075fac349a1SChristian Sigg               mlir::cast<mlir::ShapedType>(vecType), constant.getValue());
3076dc48849fSKiran Chandramohan           rewriter.setInsertionPointAfter(insertOp);
3077dc48849fSKiran Chandramohan           rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(
3078dc48849fSKiran Chandramohan               insertOp, seqTyAttr, denseAttr);
3079dc48849fSKiran Chandramohan         }
3080dc48849fSKiran Chandramohan       }
3081dc48849fSKiran Chandramohan     }
3082dc48849fSKiran Chandramohan     rewriter.eraseOp(global);
308344e58509SEric Schweitz     return mlir::success();
3084dc48849fSKiran Chandramohan   }
3085dc48849fSKiran Chandramohan 
3086dc48849fSKiran Chandramohan   bool isFullRange(mlir::DenseIntElementsAttr indexes,
3087dc48849fSKiran Chandramohan                    fir::SequenceType seqTy) const {
3088dc48849fSKiran Chandramohan     auto extents = seqTy.getShape();
3089dc48849fSKiran Chandramohan     if (indexes.size() / 2 != static_cast<int64_t>(extents.size()))
3090dc48849fSKiran Chandramohan       return false;
3091dc48849fSKiran Chandramohan     auto cur_index = indexes.value_begin<int64_t>();
3092dc48849fSKiran Chandramohan     for (unsigned i = 0; i < indexes.size(); i += 2) {
3093dc48849fSKiran Chandramohan       if (*(cur_index++) != 0)
3094dc48849fSKiran Chandramohan         return false;
3095dc48849fSKiran Chandramohan       if (*(cur_index++) != extents[i / 2] - 1)
3096dc48849fSKiran Chandramohan         return false;
3097dc48849fSKiran Chandramohan     }
3098dc48849fSKiran Chandramohan     return true;
3099dc48849fSKiran Chandramohan   }
3100dc48849fSKiran Chandramohan 
3101dc48849fSKiran Chandramohan   // TODO: String comparaison should be avoided. Replace linkName with an
3102dc48849fSKiran Chandramohan   // enumeration.
310344e58509SEric Schweitz   mlir::LLVM::Linkage
310422426110SRamkumar Ramachandra   convertLinkage(std::optional<llvm::StringRef> optLinkage) const {
310586b8c1d9SKazu Hirata     if (optLinkage) {
3106009ab172SKazu Hirata       auto name = *optLinkage;
3107dc48849fSKiran Chandramohan       if (name == "internal")
3108dc48849fSKiran Chandramohan         return mlir::LLVM::Linkage::Internal;
3109dc48849fSKiran Chandramohan       if (name == "linkonce")
3110dc48849fSKiran Chandramohan         return mlir::LLVM::Linkage::Linkonce;
311130a0fbf5SJean Perier       if (name == "linkonce_odr")
311230a0fbf5SJean Perier         return mlir::LLVM::Linkage::LinkonceODR;
3113dc48849fSKiran Chandramohan       if (name == "common")
3114dc48849fSKiran Chandramohan         return mlir::LLVM::Linkage::Common;
3115dc48849fSKiran Chandramohan       if (name == "weak")
3116dc48849fSKiran Chandramohan         return mlir::LLVM::Linkage::Weak;
3117dc48849fSKiran Chandramohan     }
3118dc48849fSKiran Chandramohan     return mlir::LLVM::Linkage::External;
3119dc48849fSKiran Chandramohan   }
31208cb0c3bbSDavid Truby 
31218cb0c3bbSDavid Truby private:
31228cb0c3bbSDavid Truby   static void addComdat(mlir::LLVM::GlobalOp &global,
31238cb0c3bbSDavid Truby                         mlir::ConversionPatternRewriter &rewriter,
3124c870632eSMatthias Springer                         mlir::ModuleOp module) {
31258cb0c3bbSDavid Truby     const char *comdatName = "__llvm_comdat";
31268cb0c3bbSDavid Truby     mlir::LLVM::ComdatOp comdatOp =
31278cb0c3bbSDavid Truby         module.lookupSymbol<mlir::LLVM::ComdatOp>(comdatName);
31288cb0c3bbSDavid Truby     if (!comdatOp) {
31298cb0c3bbSDavid Truby       comdatOp =
31308cb0c3bbSDavid Truby           rewriter.create<mlir::LLVM::ComdatOp>(module.getLoc(), comdatName);
31318cb0c3bbSDavid Truby     }
3132466b58baSValentin Clement (バレンタイン クレメン)     if (auto select = comdatOp.lookupSymbol<mlir::LLVM::ComdatSelectorOp>(
3133466b58baSValentin Clement (バレンタイン クレメン)             global.getSymName()))
3134466b58baSValentin Clement (バレンタイン クレメン)       return;
31358cb0c3bbSDavid Truby     mlir::OpBuilder::InsertionGuard guard(rewriter);
31368cb0c3bbSDavid Truby     rewriter.setInsertionPointToEnd(&comdatOp.getBody().back());
31378cb0c3bbSDavid Truby     auto selectorOp = rewriter.create<mlir::LLVM::ComdatSelectorOp>(
31388cb0c3bbSDavid Truby         comdatOp.getLoc(), global.getSymName(),
31398cb0c3bbSDavid Truby         mlir::LLVM::comdat::Comdat::Any);
31408cb0c3bbSDavid Truby     global.setComdatAttr(mlir::SymbolRefAttr::get(
31418cb0c3bbSDavid Truby         rewriter.getContext(), comdatName,
31428cb0c3bbSDavid Truby         mlir::FlatSymbolRefAttr::get(selectorOp.getSymNameAttr())));
31438cb0c3bbSDavid Truby   }
3144dc48849fSKiran Chandramohan };
3145dc48849fSKiran Chandramohan 
3146dc48849fSKiran Chandramohan /// `fir.load` --> `llvm.load`
3147e9639e9cSValentin Clement (バレンタイン クレメン) struct LoadOpConversion : public fir::FIROpConversion<fir::LoadOp> {
3148dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3149dc48849fSKiran Chandramohan 
3150db791b27SRamkumar Ramachandra   llvm::LogicalResult
3151dc48849fSKiran Chandramohan   matchAndRewrite(fir::LoadOp load, OpAdaptor adaptor,
3152dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
31530c9a0235SAsher Mancinelli 
31548a1ce2d6SjeanPerier     mlir::Type llvmLoadTy = convertObjectType(load.getType());
3155fac349a1SChristian Sigg     if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(load.getType())) {
31560c9a0235SAsher Mancinelli       // fir.box is a special case because it is considered an ssa value in
31579e1395efSJean Perier       // fir, but it is lowered as a pointer to a descriptor. So
31589e1395efSJean Perier       // fir.ref<fir.box> and fir.box end up being the same llvm types and
31599e1395efSJean Perier       // loading a fir.ref<fir.box> is implemented as taking a snapshot of the
31609e1395efSJean Perier       // descriptor value into a new descriptor temp.
31619e1395efSJean Perier       auto inputBoxStorage = adaptor.getOperands()[0];
31625e1f87e8SValentin Clement (バレンタイン クレメン)       mlir::Value newBoxStorage;
31639e1395efSJean Perier       mlir::Location loc = load.getLoc();
31645e1f87e8SValentin Clement (バレンタイン クレメン)       if (auto callOp = mlir::dyn_cast_or_null<mlir::LLVM::CallOp>(
31655e1f87e8SValentin Clement (バレンタイン クレメン)               inputBoxStorage.getDefiningOp())) {
31665e1f87e8SValentin Clement (バレンタイン クレメン)         if (callOp.getCallee() &&
31675e1f87e8SValentin Clement (バレンタイン クレメン)             (*callOp.getCallee())
3168e650ac16SValentin Clement (バレンタイン クレメン)                 .starts_with(RTNAME_STRING(CUFAllocDescriptor))) {
31695e1f87e8SValentin Clement (バレンタイン クレメン)           // CUDA Fortran local descriptor are allocated in managed memory. So
31705e1f87e8SValentin Clement (バレンタイン クレメン)           // new storage must be allocated the same way.
31715e1f87e8SValentin Clement (バレンタイン クレメン)           auto mod = load->getParentOfType<mlir::ModuleOp>();
31725e1f87e8SValentin Clement (バレンタイン クレメン)           newBoxStorage =
31735e1f87e8SValentin Clement (バレンタイン クレメン)               genCUFAllocDescriptor(loc, rewriter, mod, boxTy, lowerTy());
31745e1f87e8SValentin Clement (バレンタイン クレメン)         }
31755e1f87e8SValentin Clement (バレンタイン クレメン)       }
31765e1f87e8SValentin Clement (バレンタイン クレメン)       if (!newBoxStorage)
31775e1f87e8SValentin Clement (バレンタイン クレメン)         newBoxStorage = genAllocaAndAddrCastWithType(loc, llvmLoadTy,
31785e1f87e8SValentin Clement (バレンタイン クレメン)                                                      defaultAlign, rewriter);
3179e398383fSjeanPerier 
3180e398383fSjeanPerier       TypePair boxTypePair{boxTy, llvmLoadTy};
3181e398383fSjeanPerier       mlir::Value boxSize =
3182e398383fSjeanPerier           computeBoxSize(loc, boxTypePair, inputBoxStorage, rewriter);
3183e398383fSjeanPerier       auto memcpy = rewriter.create<mlir::LLVM::MemcpyOp>(
3184e398383fSjeanPerier           loc, newBoxStorage, inputBoxStorage, boxSize, /*isVolatile=*/false);
31850c9a0235SAsher Mancinelli 
3186e398383fSjeanPerier       if (std::optional<mlir::ArrayAttr> optionalTag = load.getTbaa())
3187e398383fSjeanPerier         memcpy.setTBAATags(*optionalTag);
3188e398383fSjeanPerier       else
3189e398383fSjeanPerier         attachTBAATag(memcpy, boxTy, boxTy, nullptr);
3190abeb6c9fSagozillon       rewriter.replaceOp(load, newBoxStorage);
3191dc48849fSKiran Chandramohan     } else {
31929c84d20fSSlava Zakharin       auto loadOp = rewriter.create<mlir::LLVM::LoadOp>(
31938a1ce2d6SjeanPerier           load.getLoc(), llvmLoadTy, adaptor.getOperands(), load->getAttrs());
31948301e485STom Eccles       if (std::optional<mlir::ArrayAttr> optionalTag = load.getTbaa())
31958301e485STom Eccles         loadOp.setTBAATags(*optionalTag);
31968301e485STom Eccles       else
31979c84d20fSSlava Zakharin         attachTBAATag(loadOp, load.getType(), load.getType(), nullptr);
31989c84d20fSSlava Zakharin       rewriter.replaceOp(load, loadOp.getResult());
3199dc48849fSKiran Chandramohan     }
320044e58509SEric Schweitz     return mlir::success();
3201dc48849fSKiran Chandramohan   }
3202dc48849fSKiran Chandramohan };
3203dc48849fSKiran Chandramohan 
3204dc48849fSKiran Chandramohan /// Lower `fir.no_reassoc` to LLVM IR dialect.
3205dc48849fSKiran Chandramohan /// TODO: how do we want to enforce this in LLVM-IR? Can we manipulate the fast
3206dc48849fSKiran Chandramohan /// math flags?
3207e9639e9cSValentin Clement (バレンタイン クレメン) struct NoReassocOpConversion : public fir::FIROpConversion<fir::NoReassocOp> {
3208dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3209dc48849fSKiran Chandramohan 
3210db791b27SRamkumar Ramachandra   llvm::LogicalResult
3211dc48849fSKiran Chandramohan   matchAndRewrite(fir::NoReassocOp noreassoc, OpAdaptor adaptor,
3212dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3213dc48849fSKiran Chandramohan     rewriter.replaceOp(noreassoc, adaptor.getOperands()[0]);
321444e58509SEric Schweitz     return mlir::success();
3215dc48849fSKiran Chandramohan   }
3216dc48849fSKiran Chandramohan };
3217dc48849fSKiran Chandramohan 
3218dc48849fSKiran Chandramohan static void genCondBrOp(mlir::Location loc, mlir::Value cmp, mlir::Block *dest,
321922426110SRamkumar Ramachandra                         std::optional<mlir::ValueRange> destOps,
3220dc48849fSKiran Chandramohan                         mlir::ConversionPatternRewriter &rewriter,
3221dc48849fSKiran Chandramohan                         mlir::Block *newBlock) {
322286b8c1d9SKazu Hirata   if (destOps)
3223009ab172SKazu Hirata     rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, *destOps, newBlock,
3224009ab172SKazu Hirata                                           mlir::ValueRange());
3225dc48849fSKiran Chandramohan   else
3226dc48849fSKiran Chandramohan     rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, newBlock);
3227dc48849fSKiran Chandramohan }
3228dc48849fSKiran Chandramohan 
3229dc48849fSKiran Chandramohan template <typename A, typename B>
323022426110SRamkumar Ramachandra static void genBrOp(A caseOp, mlir::Block *dest, std::optional<B> destOps,
3231dc48849fSKiran Chandramohan                     mlir::ConversionPatternRewriter &rewriter) {
323286b8c1d9SKazu Hirata   if (destOps)
3233009ab172SKazu Hirata     rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, *destOps, dest);
3234dc48849fSKiran Chandramohan   else
32359a417395SKazu Hirata     rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, std::nullopt, dest);
3236dc48849fSKiran Chandramohan }
3237dc48849fSKiran Chandramohan 
3238dc48849fSKiran Chandramohan static void genCaseLadderStep(mlir::Location loc, mlir::Value cmp,
3239dc48849fSKiran Chandramohan                               mlir::Block *dest,
324022426110SRamkumar Ramachandra                               std::optional<mlir::ValueRange> destOps,
3241dc48849fSKiran Chandramohan                               mlir::ConversionPatternRewriter &rewriter) {
3242dc48849fSKiran Chandramohan   auto *thisBlock = rewriter.getInsertionBlock();
3243dc48849fSKiran Chandramohan   auto *newBlock = createBlock(rewriter, dest);
3244dc48849fSKiran Chandramohan   rewriter.setInsertionPointToEnd(thisBlock);
3245dc48849fSKiran Chandramohan   genCondBrOp(loc, cmp, dest, destOps, rewriter, newBlock);
3246dc48849fSKiran Chandramohan   rewriter.setInsertionPointToEnd(newBlock);
3247dc48849fSKiran Chandramohan }
3248dc48849fSKiran Chandramohan 
3249dc48849fSKiran Chandramohan /// Conversion of `fir.select_case`
3250dc48849fSKiran Chandramohan ///
3251dc48849fSKiran Chandramohan /// The `fir.select_case` operation is converted to a if-then-else ladder.
3252dc48849fSKiran Chandramohan /// Depending on the case condition type, one or several comparison and
3253dc48849fSKiran Chandramohan /// conditional branching can be generated.
3254dc48849fSKiran Chandramohan ///
3255fc04472aSFangrui Song /// A point value case such as `case(4)`, a lower bound case such as
3256dc48849fSKiran Chandramohan /// `case(5:)` or an upper bound case such as `case(:3)` are converted to a
3257dc48849fSKiran Chandramohan /// simple comparison between the selector value and the constant value in the
3258dc48849fSKiran Chandramohan /// case. The block associated with the case condition is then executed if
3259dc48849fSKiran Chandramohan /// the comparison succeed otherwise it branch to the next block with the
3260fc04472aSFangrui Song /// comparison for the next case conditon.
3261dc48849fSKiran Chandramohan ///
3262dc48849fSKiran Chandramohan /// A closed interval case condition such as `case(7:10)` is converted with a
3263dc48849fSKiran Chandramohan /// first comparison and conditional branching for the lower bound. If
3264dc48849fSKiran Chandramohan /// successful, it branch to a second block with the comparison for the
3265dc48849fSKiran Chandramohan /// upper bound in the same case condition.
3266dc48849fSKiran Chandramohan ///
3267dc48849fSKiran Chandramohan /// TODO: lowering of CHARACTER type cases is not handled yet.
3268e9639e9cSValentin Clement (バレンタイン クレメン) struct SelectCaseOpConversion : public fir::FIROpConversion<fir::SelectCaseOp> {
3269dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3270dc48849fSKiran Chandramohan 
3271db791b27SRamkumar Ramachandra   llvm::LogicalResult
3272dc48849fSKiran Chandramohan   matchAndRewrite(fir::SelectCaseOp caseOp, OpAdaptor adaptor,
3273dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3274dc48849fSKiran Chandramohan     unsigned conds = caseOp.getNumConditions();
3275dc48849fSKiran Chandramohan     llvm::ArrayRef<mlir::Attribute> cases = caseOp.getCases().getValue();
3276dc48849fSKiran Chandramohan     // Type can be CHARACTER, INTEGER, or LOGICAL (C1145)
3277dc48849fSKiran Chandramohan     auto ty = caseOp.getSelector().getType();
3278fac349a1SChristian Sigg     if (mlir::isa<fir::CharacterType>(ty)) {
3279dc48849fSKiran Chandramohan       TODO(caseOp.getLoc(), "fir.select_case codegen with character type");
328044e58509SEric Schweitz       return mlir::failure();
3281dc48849fSKiran Chandramohan     }
3282dc48849fSKiran Chandramohan     mlir::Value selector = caseOp.getSelector(adaptor.getOperands());
3283dc48849fSKiran Chandramohan     auto loc = caseOp.getLoc();
3284dc48849fSKiran Chandramohan     for (unsigned t = 0; t != conds; ++t) {
3285dc48849fSKiran Chandramohan       mlir::Block *dest = caseOp.getSuccessor(t);
328622426110SRamkumar Ramachandra       std::optional<mlir::ValueRange> destOps =
3287dc48849fSKiran Chandramohan           caseOp.getSuccessorOperands(adaptor.getOperands(), t);
328822426110SRamkumar Ramachandra       std::optional<mlir::ValueRange> cmpOps =
3289dc48849fSKiran Chandramohan           *caseOp.getCompareOperands(adaptor.getOperands(), t);
3290dc48849fSKiran Chandramohan       mlir::Attribute attr = cases[t];
3291101f977fSKrzysztof Parzyszek       assert(mlir::isa<mlir::UnitAttr>(attr) || cmpOps.has_value());
3292fac349a1SChristian Sigg       if (mlir::isa<fir::PointIntervalAttr>(attr)) {
3293dc48849fSKiran Chandramohan         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
3294101f977fSKrzysztof Parzyszek             loc, mlir::LLVM::ICmpPredicate::eq, selector, cmpOps->front());
3295dc48849fSKiran Chandramohan         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
3296dc48849fSKiran Chandramohan         continue;
3297dc48849fSKiran Chandramohan       }
3298fac349a1SChristian Sigg       if (mlir::isa<fir::LowerBoundAttr>(attr)) {
3299dc48849fSKiran Chandramohan         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
3300101f977fSKrzysztof Parzyszek             loc, mlir::LLVM::ICmpPredicate::sle, cmpOps->front(), selector);
3301dc48849fSKiran Chandramohan         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
3302dc48849fSKiran Chandramohan         continue;
3303dc48849fSKiran Chandramohan       }
3304fac349a1SChristian Sigg       if (mlir::isa<fir::UpperBoundAttr>(attr)) {
3305dc48849fSKiran Chandramohan         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
3306101f977fSKrzysztof Parzyszek             loc, mlir::LLVM::ICmpPredicate::sle, selector, cmpOps->front());
3307dc48849fSKiran Chandramohan         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
3308dc48849fSKiran Chandramohan         continue;
3309dc48849fSKiran Chandramohan       }
3310fac349a1SChristian Sigg       if (mlir::isa<fir::ClosedIntervalAttr>(attr)) {
3311101f977fSKrzysztof Parzyszek         mlir::Value caseArg0 = *cmpOps->begin();
3312101f977fSKrzysztof Parzyszek         auto cmp0 = rewriter.create<mlir::LLVM::ICmpOp>(
3313101f977fSKrzysztof Parzyszek             loc, mlir::LLVM::ICmpPredicate::sle, caseArg0, selector);
3314dc48849fSKiran Chandramohan         auto *thisBlock = rewriter.getInsertionBlock();
3315dc48849fSKiran Chandramohan         auto *newBlock1 = createBlock(rewriter, dest);
3316dc48849fSKiran Chandramohan         auto *newBlock2 = createBlock(rewriter, dest);
3317dc48849fSKiran Chandramohan         rewriter.setInsertionPointToEnd(thisBlock);
3318101f977fSKrzysztof Parzyszek         rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp0, newBlock1, newBlock2);
3319dc48849fSKiran Chandramohan         rewriter.setInsertionPointToEnd(newBlock1);
3320101f977fSKrzysztof Parzyszek         mlir::Value caseArg1 = *(cmpOps->begin() + 1);
3321101f977fSKrzysztof Parzyszek         auto cmp1 = rewriter.create<mlir::LLVM::ICmpOp>(
3322101f977fSKrzysztof Parzyszek             loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg1);
3323101f977fSKrzysztof Parzyszek         genCondBrOp(loc, cmp1, dest, destOps, rewriter, newBlock2);
3324dc48849fSKiran Chandramohan         rewriter.setInsertionPointToEnd(newBlock2);
3325dc48849fSKiran Chandramohan         continue;
3326dc48849fSKiran Chandramohan       }
3327fac349a1SChristian Sigg       assert(mlir::isa<mlir::UnitAttr>(attr));
3328dc48849fSKiran Chandramohan       assert((t + 1 == conds) && "unit must be last");
3329dc48849fSKiran Chandramohan       genBrOp(caseOp, dest, destOps, rewriter);
3330dc48849fSKiran Chandramohan     }
333144e58509SEric Schweitz     return mlir::success();
3332dc48849fSKiran Chandramohan   }
3333dc48849fSKiran Chandramohan };
3334dc48849fSKiran Chandramohan 
3335eb6c4197SMatthias Springer /// Helper function for converting select ops. This function converts the
3336eb6c4197SMatthias Springer /// signature of the given block. If the new block signature is different from
3337eb6c4197SMatthias Springer /// `expectedTypes`, returns "failure".
3338eb6c4197SMatthias Springer static llvm::FailureOr<mlir::Block *>
3339eb6c4197SMatthias Springer getConvertedBlock(mlir::ConversionPatternRewriter &rewriter,
3340eb6c4197SMatthias Springer                   const mlir::TypeConverter *converter,
3341eb6c4197SMatthias Springer                   mlir::Operation *branchOp, mlir::Block *block,
3342eb6c4197SMatthias Springer                   mlir::TypeRange expectedTypes) {
3343eb6c4197SMatthias Springer   assert(converter && "expected non-null type converter");
3344eb6c4197SMatthias Springer   assert(!block->isEntryBlock() && "entry blocks have no predecessors");
3345eb6c4197SMatthias Springer 
3346eb6c4197SMatthias Springer   // There is nothing to do if the types already match.
3347eb6c4197SMatthias Springer   if (block->getArgumentTypes() == expectedTypes)
3348eb6c4197SMatthias Springer     return block;
3349eb6c4197SMatthias Springer 
3350eb6c4197SMatthias Springer   // Compute the new block argument types and convert the block.
3351eb6c4197SMatthias Springer   std::optional<mlir::TypeConverter::SignatureConversion> conversion =
3352eb6c4197SMatthias Springer       converter->convertBlockSignature(block);
3353eb6c4197SMatthias Springer   if (!conversion)
3354eb6c4197SMatthias Springer     return rewriter.notifyMatchFailure(branchOp,
3355eb6c4197SMatthias Springer                                        "could not compute block signature");
3356eb6c4197SMatthias Springer   if (expectedTypes != conversion->getConvertedTypes())
3357eb6c4197SMatthias Springer     return rewriter.notifyMatchFailure(
3358eb6c4197SMatthias Springer         branchOp,
3359eb6c4197SMatthias Springer         "mismatch between adaptor operand types and computed block signature");
3360eb6c4197SMatthias Springer   return rewriter.applySignatureConversion(block, *conversion, converter);
3361eb6c4197SMatthias Springer }
3362eb6c4197SMatthias Springer 
3363dc48849fSKiran Chandramohan template <typename OP>
3364eb6c4197SMatthias Springer static llvm::LogicalResult
3365eb6c4197SMatthias Springer selectMatchAndRewrite(const fir::LLVMTypeConverter &lowering, OP select,
3366eb6c4197SMatthias Springer                       typename OP::Adaptor adaptor,
3367eb6c4197SMatthias Springer                       mlir::ConversionPatternRewriter &rewriter,
3368eb6c4197SMatthias Springer                       const mlir::TypeConverter *converter) {
3369dc48849fSKiran Chandramohan   unsigned conds = select.getNumConditions();
3370dc48849fSKiran Chandramohan   auto cases = select.getCases().getValue();
3371dc48849fSKiran Chandramohan   mlir::Value selector = adaptor.getSelector();
3372dc48849fSKiran Chandramohan   auto loc = select.getLoc();
3373dc48849fSKiran Chandramohan   assert(conds > 0 && "select must have cases");
3374dc48849fSKiran Chandramohan 
3375dc48849fSKiran Chandramohan   llvm::SmallVector<mlir::Block *> destinations;
3376dc48849fSKiran Chandramohan   llvm::SmallVector<mlir::ValueRange> destinationsOperands;
3377dc48849fSKiran Chandramohan   mlir::Block *defaultDestination;
3378dc48849fSKiran Chandramohan   mlir::ValueRange defaultOperands;
3379dc48849fSKiran Chandramohan   llvm::SmallVector<int32_t> caseValues;
3380dc48849fSKiran Chandramohan 
3381dc48849fSKiran Chandramohan   for (unsigned t = 0; t != conds; ++t) {
3382dc48849fSKiran Chandramohan     mlir::Block *dest = select.getSuccessor(t);
3383dc48849fSKiran Chandramohan     auto destOps = select.getSuccessorOperands(adaptor.getOperands(), t);
3384dc48849fSKiran Chandramohan     const mlir::Attribute &attr = cases[t];
3385fac349a1SChristian Sigg     if (auto intAttr = mlir::dyn_cast<mlir::IntegerAttr>(attr)) {
338686b8c1d9SKazu Hirata       destinationsOperands.push_back(destOps ? *destOps : mlir::ValueRange{});
3387eb6c4197SMatthias Springer       auto convertedBlock =
3388eb6c4197SMatthias Springer           getConvertedBlock(rewriter, converter, select, dest,
3389eb6c4197SMatthias Springer                             mlir::TypeRange(destinationsOperands.back()));
3390eb6c4197SMatthias Springer       if (mlir::failed(convertedBlock))
3391eb6c4197SMatthias Springer         return mlir::failure();
3392eb6c4197SMatthias Springer       destinations.push_back(*convertedBlock);
3393dc48849fSKiran Chandramohan       caseValues.push_back(intAttr.getInt());
3394dc48849fSKiran Chandramohan       continue;
3395dc48849fSKiran Chandramohan     }
3396bd9fdce6SChristian Sigg     assert(mlir::dyn_cast_or_null<mlir::UnitAttr>(attr));
3397dc48849fSKiran Chandramohan     assert((t + 1 == conds) && "unit must be last");
339886b8c1d9SKazu Hirata     defaultOperands = destOps ? *destOps : mlir::ValueRange{};
3399eb6c4197SMatthias Springer     auto convertedBlock = getConvertedBlock(rewriter, converter, select, dest,
3400eb6c4197SMatthias Springer                                             mlir::TypeRange(defaultOperands));
3401eb6c4197SMatthias Springer     if (mlir::failed(convertedBlock))
3402eb6c4197SMatthias Springer       return mlir::failure();
3403eb6c4197SMatthias Springer     defaultDestination = *convertedBlock;
3404dc48849fSKiran Chandramohan   }
3405dc48849fSKiran Chandramohan 
3406dc48849fSKiran Chandramohan   // LLVM::SwitchOp takes a i32 type for the selector.
3407dc48849fSKiran Chandramohan   if (select.getSelector().getType() != rewriter.getI32Type())
340844e58509SEric Schweitz     selector = rewriter.create<mlir::LLVM::TruncOp>(loc, rewriter.getI32Type(),
340944e58509SEric Schweitz                                                     selector);
3410dc48849fSKiran Chandramohan 
3411dc48849fSKiran Chandramohan   rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>(
3412dc48849fSKiran Chandramohan       select, selector,
3413dc48849fSKiran Chandramohan       /*defaultDestination=*/defaultDestination,
3414dc48849fSKiran Chandramohan       /*defaultOperands=*/defaultOperands,
3415dc48849fSKiran Chandramohan       /*caseValues=*/caseValues,
3416dc48849fSKiran Chandramohan       /*caseDestinations=*/destinations,
3417dc48849fSKiran Chandramohan       /*caseOperands=*/destinationsOperands,
341844e58509SEric Schweitz       /*branchWeights=*/llvm::ArrayRef<std::int32_t>());
3419eb6c4197SMatthias Springer   return mlir::success();
3420dc48849fSKiran Chandramohan }
3421dc48849fSKiran Chandramohan 
3422dc48849fSKiran Chandramohan /// conversion of fir::SelectOp to an if-then-else ladder
3423e9639e9cSValentin Clement (バレンタイン クレメン) struct SelectOpConversion : public fir::FIROpConversion<fir::SelectOp> {
3424dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3425dc48849fSKiran Chandramohan 
3426db791b27SRamkumar Ramachandra   llvm::LogicalResult
3427dc48849fSKiran Chandramohan   matchAndRewrite(fir::SelectOp op, OpAdaptor adaptor,
3428dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3429eb6c4197SMatthias Springer     return selectMatchAndRewrite<fir::SelectOp>(lowerTy(), op, adaptor,
3430eb6c4197SMatthias Springer                                                 rewriter, getTypeConverter());
3431dc48849fSKiran Chandramohan   }
3432dc48849fSKiran Chandramohan };
3433dc48849fSKiran Chandramohan 
3434dc48849fSKiran Chandramohan /// conversion of fir::SelectRankOp to an if-then-else ladder
3435e9639e9cSValentin Clement (バレンタイン クレメン) struct SelectRankOpConversion : public fir::FIROpConversion<fir::SelectRankOp> {
3436dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3437dc48849fSKiran Chandramohan 
3438db791b27SRamkumar Ramachandra   llvm::LogicalResult
3439dc48849fSKiran Chandramohan   matchAndRewrite(fir::SelectRankOp op, OpAdaptor adaptor,
3440dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3441eb6c4197SMatthias Springer     return selectMatchAndRewrite<fir::SelectRankOp>(
3442eb6c4197SMatthias Springer         lowerTy(), op, adaptor, rewriter, getTypeConverter());
3443dc48849fSKiran Chandramohan   }
3444dc48849fSKiran Chandramohan };
3445dc48849fSKiran Chandramohan 
3446dc48849fSKiran Chandramohan /// Lower `fir.select_type` to LLVM IR dialect.
3447e9639e9cSValentin Clement (バレンタイン クレメン) struct SelectTypeOpConversion : public fir::FIROpConversion<fir::SelectTypeOp> {
3448dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3449dc48849fSKiran Chandramohan 
3450db791b27SRamkumar Ramachandra   llvm::LogicalResult
3451dc48849fSKiran Chandramohan   matchAndRewrite(fir::SelectTypeOp select, OpAdaptor adaptor,
3452dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3453dc48849fSKiran Chandramohan     mlir::emitError(select.getLoc(),
3454dc48849fSKiran Chandramohan                     "fir.select_type should have already been converted");
345544e58509SEric Schweitz     return mlir::failure();
3456dc48849fSKiran Chandramohan   }
3457dc48849fSKiran Chandramohan };
3458dc48849fSKiran Chandramohan 
3459dc48849fSKiran Chandramohan /// `fir.store` --> `llvm.store`
3460e9639e9cSValentin Clement (バレンタイン クレメン) struct StoreOpConversion : public fir::FIROpConversion<fir::StoreOp> {
3461dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3462dc48849fSKiran Chandramohan 
3463db791b27SRamkumar Ramachandra   llvm::LogicalResult
3464dc48849fSKiran Chandramohan   matchAndRewrite(fir::StoreOp store, OpAdaptor adaptor,
3465dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3466dc48849fSKiran Chandramohan     mlir::Location loc = store.getLoc();
34679c84d20fSSlava Zakharin     mlir::Type storeTy = store.getValue().getType();
3468a7869192SjeanPerier     mlir::Value llvmValue = adaptor.getValue();
3469a7869192SjeanPerier     mlir::Value llvmMemref = adaptor.getMemref();
3470a7869192SjeanPerier     mlir::LLVM::AliasAnalysisOpInterface newOp;
3471fac349a1SChristian Sigg     if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(storeTy)) {
34728a1ce2d6SjeanPerier       mlir::Type llvmBoxTy = lowerTy().convertBoxTypeAsStruct(boxTy);
34730c9a0235SAsher Mancinelli       // Always use memcpy because LLVM is not as effective at optimizing
34740c9a0235SAsher Mancinelli       // aggregate loads/stores as it is optimizing memcpy.
3475a7869192SjeanPerier       TypePair boxTypePair{boxTy, llvmBoxTy};
3476a7869192SjeanPerier       mlir::Value boxSize =
3477a7869192SjeanPerier           computeBoxSize(loc, boxTypePair, llvmValue, rewriter);
3478a7869192SjeanPerier       newOp = rewriter.create<mlir::LLVM::MemcpyOp>(
3479a7869192SjeanPerier           loc, llvmMemref, llvmValue, boxSize, /*isVolatile=*/false);
3480dc48849fSKiran Chandramohan     } else {
3481a7869192SjeanPerier       newOp = rewriter.create<mlir::LLVM::StoreOp>(loc, llvmValue, llvmMemref);
3482dc48849fSKiran Chandramohan     }
34838301e485STom Eccles     if (std::optional<mlir::ArrayAttr> optionalTag = store.getTbaa())
3484a7869192SjeanPerier       newOp.setTBAATags(*optionalTag);
34858301e485STom Eccles     else
3486a7869192SjeanPerier       attachTBAATag(newOp, storeTy, storeTy, nullptr);
34879c84d20fSSlava Zakharin     rewriter.eraseOp(store);
348844e58509SEric Schweitz     return mlir::success();
3489dc48849fSKiran Chandramohan   }
3490dc48849fSKiran Chandramohan };
3491dc48849fSKiran Chandramohan 
3492dc48849fSKiran Chandramohan namespace {
3493dc48849fSKiran Chandramohan 
3494dc48849fSKiran Chandramohan /// Convert `fir.unboxchar` into two `llvm.extractvalue` instructions. One for
3495dc48849fSKiran Chandramohan /// the character buffer and one for the buffer length.
3496e9639e9cSValentin Clement (バレンタイン クレメン) struct UnboxCharOpConversion : public fir::FIROpConversion<fir::UnboxCharOp> {
3497dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3498dc48849fSKiran Chandramohan 
3499db791b27SRamkumar Ramachandra   llvm::LogicalResult
3500dc48849fSKiran Chandramohan   matchAndRewrite(fir::UnboxCharOp unboxchar, OpAdaptor adaptor,
3501dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3502dc48849fSKiran Chandramohan     mlir::Type lenTy = convertType(unboxchar.getType(1));
3503dc48849fSKiran Chandramohan     mlir::Value tuple = adaptor.getOperands()[0];
3504dc48849fSKiran Chandramohan 
3505dc48849fSKiran Chandramohan     mlir::Location loc = unboxchar.getLoc();
3506dc48849fSKiran Chandramohan     mlir::Value ptrToBuffer =
35075c5af910SJeff Niu         rewriter.create<mlir::LLVM::ExtractValueOp>(loc, tuple, 0);
3508dc48849fSKiran Chandramohan 
35095c5af910SJeff Niu     auto len = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, tuple, 1);
3510dc48849fSKiran Chandramohan     mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, len);
3511dc48849fSKiran Chandramohan 
3512dc48849fSKiran Chandramohan     rewriter.replaceOp(unboxchar,
351344e58509SEric Schweitz                        llvm::ArrayRef<mlir::Value>{ptrToBuffer, lenAfterCast});
351444e58509SEric Schweitz     return mlir::success();
3515dc48849fSKiran Chandramohan   }
3516dc48849fSKiran Chandramohan };
3517dc48849fSKiran Chandramohan 
3518dc48849fSKiran Chandramohan /// Lower `fir.unboxproc` operation. Unbox a procedure box value, yielding its
3519dc48849fSKiran Chandramohan /// components.
3520dc48849fSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers.
3521e9639e9cSValentin Clement (バレンタイン クレメン) struct UnboxProcOpConversion : public fir::FIROpConversion<fir::UnboxProcOp> {
3522dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3523dc48849fSKiran Chandramohan 
3524db791b27SRamkumar Ramachandra   llvm::LogicalResult
3525dc48849fSKiran Chandramohan   matchAndRewrite(fir::UnboxProcOp unboxproc, OpAdaptor adaptor,
3526dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3527dc48849fSKiran Chandramohan     TODO(unboxproc.getLoc(), "fir.unboxproc codegen");
352844e58509SEric Schweitz     return mlir::failure();
3529dc48849fSKiran Chandramohan   }
3530dc48849fSKiran Chandramohan };
3531dc48849fSKiran Chandramohan 
3532dc48849fSKiran Chandramohan /// convert to LLVM IR dialect `undef`
3533e9639e9cSValentin Clement (バレンタイン クレメン) struct UndefOpConversion : public fir::FIROpConversion<fir::UndefOp> {
3534dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3535dc48849fSKiran Chandramohan 
3536db791b27SRamkumar Ramachandra   llvm::LogicalResult
3537dc48849fSKiran Chandramohan   matchAndRewrite(fir::UndefOp undef, OpAdaptor,
3538dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3539dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::UndefOp>(
3540dc48849fSKiran Chandramohan         undef, convertType(undef.getType()));
354144e58509SEric Schweitz     return mlir::success();
3542dc48849fSKiran Chandramohan   }
3543dc48849fSKiran Chandramohan };
3544dc48849fSKiran Chandramohan 
3545e9639e9cSValentin Clement (バレンタイン クレメン) struct ZeroOpConversion : public fir::FIROpConversion<fir::ZeroOp> {
3546dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3547dc48849fSKiran Chandramohan 
3548db791b27SRamkumar Ramachandra   llvm::LogicalResult
3549dc48849fSKiran Chandramohan   matchAndRewrite(fir::ZeroOp zero, OpAdaptor,
3550dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3551dc48849fSKiran Chandramohan     mlir::Type ty = convertType(zero.getType());
355285175eddSTobias Gysi     rewriter.replaceOpWithNewOp<mlir::LLVM::ZeroOp>(zero, ty);
355344e58509SEric Schweitz     return mlir::success();
3554dc48849fSKiran Chandramohan   }
3555dc48849fSKiran Chandramohan };
3556dc48849fSKiran Chandramohan 
3557dc48849fSKiran Chandramohan /// `fir.unreachable` --> `llvm.unreachable`
3558e9639e9cSValentin Clement (バレンタイン クレメン) struct UnreachableOpConversion
3559e9639e9cSValentin Clement (バレンタイン クレメン)     : public fir::FIROpConversion<fir::UnreachableOp> {
3560dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3561dc48849fSKiran Chandramohan 
3562db791b27SRamkumar Ramachandra   llvm::LogicalResult
3563dc48849fSKiran Chandramohan   matchAndRewrite(fir::UnreachableOp unreach, OpAdaptor adaptor,
3564dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3565dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(unreach);
356644e58509SEric Schweitz     return mlir::success();
3567dc48849fSKiran Chandramohan   }
3568dc48849fSKiran Chandramohan };
3569dc48849fSKiran Chandramohan 
3570dc48849fSKiran Chandramohan /// `fir.is_present` -->
3571dc48849fSKiran Chandramohan /// ```
3572dc48849fSKiran Chandramohan ///  %0 = llvm.mlir.constant(0 : i64)
3573dc48849fSKiran Chandramohan ///  %1 = llvm.ptrtoint %0
3574dc48849fSKiran Chandramohan ///  %2 = llvm.icmp "ne" %1, %0 : i64
3575dc48849fSKiran Chandramohan /// ```
3576e9639e9cSValentin Clement (バレンタイン クレメン) struct IsPresentOpConversion : public fir::FIROpConversion<fir::IsPresentOp> {
3577dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3578dc48849fSKiran Chandramohan 
3579db791b27SRamkumar Ramachandra   llvm::LogicalResult
3580dc48849fSKiran Chandramohan   matchAndRewrite(fir::IsPresentOp isPresent, OpAdaptor adaptor,
3581dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3582dc48849fSKiran Chandramohan     mlir::Type idxTy = lowerTy().indexType();
3583dc48849fSKiran Chandramohan     mlir::Location loc = isPresent.getLoc();
3584dc48849fSKiran Chandramohan     auto ptr = adaptor.getOperands()[0];
3585dc48849fSKiran Chandramohan 
3586fac349a1SChristian Sigg     if (mlir::isa<fir::BoxCharType>(isPresent.getVal().getType())) {
358767d0d7acSMichele Scuttari       [[maybe_unused]] auto structTy =
3588fac349a1SChristian Sigg           mlir::cast<mlir::LLVM::LLVMStructType>(ptr.getType());
3589dc48849fSKiran Chandramohan       assert(!structTy.isOpaque() && !structTy.getBody().empty());
3590dc48849fSKiran Chandramohan 
35915c5af910SJeff Niu       ptr = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ptr, 0);
3592dc48849fSKiran Chandramohan     }
3593dc48849fSKiran Chandramohan     mlir::LLVM::ConstantOp c0 =
3594dc48849fSKiran Chandramohan         genConstantIndex(isPresent.getLoc(), idxTy, rewriter, 0);
3595dc48849fSKiran Chandramohan     auto addr = rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, ptr);
3596dc48849fSKiran Chandramohan     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
3597dc48849fSKiran Chandramohan         isPresent, mlir::LLVM::ICmpPredicate::ne, addr, c0);
3598dc48849fSKiran Chandramohan 
359944e58509SEric Schweitz     return mlir::success();
3600dc48849fSKiran Chandramohan   }
3601dc48849fSKiran Chandramohan };
3602dc48849fSKiran Chandramohan 
3603dc48849fSKiran Chandramohan /// Create value signaling an absent optional argument in a call, e.g.
360485175eddSTobias Gysi /// `fir.absent !fir.ref<i64>` -->  `llvm.mlir.zero : !llvm.ptr<i64>`
3605e9639e9cSValentin Clement (バレンタイン クレメン) struct AbsentOpConversion : public fir::FIROpConversion<fir::AbsentOp> {
3606dc48849fSKiran Chandramohan   using FIROpConversion::FIROpConversion;
3607dc48849fSKiran Chandramohan 
3608db791b27SRamkumar Ramachandra   llvm::LogicalResult
3609dc48849fSKiran Chandramohan   matchAndRewrite(fir::AbsentOp absent, OpAdaptor,
3610dc48849fSKiran Chandramohan                   mlir::ConversionPatternRewriter &rewriter) const override {
3611dc48849fSKiran Chandramohan     mlir::Type ty = convertType(absent.getType());
361285175eddSTobias Gysi     rewriter.replaceOpWithNewOp<mlir::LLVM::ZeroOp>(absent, ty);
361344e58509SEric Schweitz     return mlir::success();
3614dc48849fSKiran Chandramohan   }
3615dc48849fSKiran Chandramohan };
36165d27abe6SValentin Clement 
36177b5132daSValentin Clement //
36187b5132daSValentin Clement // Primitive operations on Complex types
36197b5132daSValentin Clement //
36207b5132daSValentin Clement 
36216be0e979STom Eccles template <typename OPTY>
36226be0e979STom Eccles static inline mlir::LLVM::FastmathFlagsAttr getLLVMFMFAttr(OPTY op) {
36236be0e979STom Eccles   return mlir::LLVM::FastmathFlagsAttr::get(
36246be0e979STom Eccles       op.getContext(),
36256be0e979STom Eccles       mlir::arith::convertArithFastMathFlagsToLLVM(op.getFastmath()));
36266be0e979STom Eccles }
36276be0e979STom Eccles 
36287b5132daSValentin Clement /// Generate inline code for complex addition/subtraction
36297b5132daSValentin Clement template <typename LLVMOP, typename OPTY>
3630c2acd453SAlexisPerry static mlir::LLVM::InsertValueOp
3631c2acd453SAlexisPerry complexSum(OPTY sumop, mlir::ValueRange opnds,
36327b5132daSValentin Clement            mlir::ConversionPatternRewriter &rewriter,
3633ce254598SMatthias Springer            const fir::LLVMTypeConverter &lowering) {
36346be0e979STom Eccles   mlir::LLVM::FastmathFlagsAttr fmf = getLLVMFMFAttr(sumop);
36357b5132daSValentin Clement   mlir::Value a = opnds[0];
36367b5132daSValentin Clement   mlir::Value b = opnds[1];
36377b5132daSValentin Clement   auto loc = sumop.getLoc();
36387b5132daSValentin Clement   mlir::Type eleTy = lowering.convertType(getComplexEleTy(sumop.getType()));
36397b5132daSValentin Clement   mlir::Type ty = lowering.convertType(sumop.getType());
36405c5af910SJeff Niu   auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, a, 0);
36415c5af910SJeff Niu   auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, a, 1);
36425c5af910SJeff Niu   auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, b, 0);
36435c5af910SJeff Niu   auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, b, 1);
36446be0e979STom Eccles   auto rx = rewriter.create<LLVMOP>(loc, eleTy, x0, x1, fmf);
36456be0e979STom Eccles   auto ry = rewriter.create<LLVMOP>(loc, eleTy, y0, y1, fmf);
36467b5132daSValentin Clement   auto r0 = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
36475c5af910SJeff Niu   auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, r0, rx, 0);
36485c5af910SJeff Niu   return rewriter.create<mlir::LLVM::InsertValueOp>(loc, r1, ry, 1);
36497b5132daSValentin Clement }
3650dc48849fSKiran Chandramohan } // namespace
36517b5132daSValentin Clement 
3652c2acd453SAlexisPerry namespace {
3653e9639e9cSValentin Clement (バレンタイン クレメン) struct AddcOpConversion : public fir::FIROpConversion<fir::AddcOp> {
36547b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
36557b5132daSValentin Clement 
3656db791b27SRamkumar Ramachandra   llvm::LogicalResult
36577b5132daSValentin Clement   matchAndRewrite(fir::AddcOp addc, OpAdaptor adaptor,
36587b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
36597b5132daSValentin Clement     // given: (x + iy) + (x' + iy')
36607b5132daSValentin Clement     // result: (x + x') + i(y + y')
36617b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FAddOp>(addc, adaptor.getOperands(),
36627b5132daSValentin Clement                                             rewriter, lowerTy());
36637b5132daSValentin Clement     rewriter.replaceOp(addc, r.getResult());
366444e58509SEric Schweitz     return mlir::success();
36657b5132daSValentin Clement   }
36667b5132daSValentin Clement };
36677b5132daSValentin Clement 
3668e9639e9cSValentin Clement (バレンタイン クレメン) struct SubcOpConversion : public fir::FIROpConversion<fir::SubcOp> {
36697b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
36707b5132daSValentin Clement 
3671db791b27SRamkumar Ramachandra   llvm::LogicalResult
36727b5132daSValentin Clement   matchAndRewrite(fir::SubcOp subc, OpAdaptor adaptor,
36737b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
36747b5132daSValentin Clement     // given: (x + iy) - (x' + iy')
36757b5132daSValentin Clement     // result: (x - x') + i(y - y')
36767b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FSubOp>(subc, adaptor.getOperands(),
36777b5132daSValentin Clement                                             rewriter, lowerTy());
36787b5132daSValentin Clement     rewriter.replaceOp(subc, r.getResult());
367944e58509SEric Schweitz     return mlir::success();
36807b5132daSValentin Clement   }
36817b5132daSValentin Clement };
36827b5132daSValentin Clement 
36837b5132daSValentin Clement /// Inlined complex multiply
3684e9639e9cSValentin Clement (バレンタイン クレメン) struct MulcOpConversion : public fir::FIROpConversion<fir::MulcOp> {
36857b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
36867b5132daSValentin Clement 
3687db791b27SRamkumar Ramachandra   llvm::LogicalResult
36887b5132daSValentin Clement   matchAndRewrite(fir::MulcOp mulc, OpAdaptor adaptor,
36897b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
36907b5132daSValentin Clement     // TODO: Can we use a call to __muldc3 ?
36917b5132daSValentin Clement     // given: (x + iy) * (x' + iy')
36927b5132daSValentin Clement     // result: (xx'-yy')+i(xy'+yx')
36936be0e979STom Eccles     mlir::LLVM::FastmathFlagsAttr fmf = getLLVMFMFAttr(mulc);
36947b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
36957b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
36967b5132daSValentin Clement     auto loc = mulc.getLoc();
36977b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(mulc.getType()));
36987b5132daSValentin Clement     mlir::Type ty = convertType(mulc.getType());
36995c5af910SJeff Niu     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, a, 0);
37005c5af910SJeff Niu     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, a, 1);
37015c5af910SJeff Niu     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, b, 0);
37025c5af910SJeff Niu     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, b, 1);
37036be0e979STom Eccles     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1, fmf);
37046be0e979STom Eccles     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1, fmf);
37056be0e979STom Eccles     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1, fmf);
37066be0e979STom Eccles     auto ri = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xy, yx, fmf);
37076be0e979STom Eccles     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1, fmf);
37086be0e979STom Eccles     auto rr = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, xx, yy, fmf);
37097b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
37105c5af910SJeff Niu     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ra, rr, 0);
37115c5af910SJeff Niu     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, r1, ri, 1);
37127b5132daSValentin Clement     rewriter.replaceOp(mulc, r0.getResult());
371344e58509SEric Schweitz     return mlir::success();
37147b5132daSValentin Clement   }
37157b5132daSValentin Clement };
37167b5132daSValentin Clement 
371796e1d2b5SKiran Chandramohan /// Inlined complex division
3718e9639e9cSValentin Clement (バレンタイン クレメン) struct DivcOpConversion : public fir::FIROpConversion<fir::DivcOp> {
37197b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
37207b5132daSValentin Clement 
3721db791b27SRamkumar Ramachandra   llvm::LogicalResult
37227b5132daSValentin Clement   matchAndRewrite(fir::DivcOp divc, OpAdaptor adaptor,
37237b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
372496e1d2b5SKiran Chandramohan     // TODO: Can we use a call to __divdc3 instead?
372596e1d2b5SKiran Chandramohan     // Just generate inline code for now.
37267b5132daSValentin Clement     // given: (x + iy) / (x' + iy')
37277b5132daSValentin Clement     // result: ((xx'+yy')/d) + i((yx'-xy')/d) where d = x'x' + y'y'
37286be0e979STom Eccles     mlir::LLVM::FastmathFlagsAttr fmf = getLLVMFMFAttr(divc);
37297b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
37307b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
37317b5132daSValentin Clement     auto loc = divc.getLoc();
37327b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(divc.getType()));
373396e1d2b5SKiran Chandramohan     mlir::Type ty = convertType(divc.getType());
37345c5af910SJeff Niu     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, a, 0);
37355c5af910SJeff Niu     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, a, 1);
37365c5af910SJeff Niu     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, b, 0);
37375c5af910SJeff Niu     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, b, 1);
37386be0e979STom Eccles     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1, fmf);
37396be0e979STom Eccles     auto x1x1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x1, x1, fmf);
37406be0e979STom Eccles     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1, fmf);
37416be0e979STom Eccles     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1, fmf);
37426be0e979STom Eccles     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1, fmf);
37436be0e979STom Eccles     auto y1y1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y1, y1, fmf);
37446be0e979STom Eccles     auto d = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, x1x1, y1y1, fmf);
37456be0e979STom Eccles     auto rrn = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xx, yy, fmf);
37466be0e979STom Eccles     auto rin = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, yx, xy, fmf);
37476be0e979STom Eccles     auto rr = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rrn, d, fmf);
37486be0e979STom Eccles     auto ri = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rin, d, fmf);
37497b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
37505c5af910SJeff Niu     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ra, rr, 0);
37515c5af910SJeff Niu     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, r1, ri, 1);
37527b5132daSValentin Clement     rewriter.replaceOp(divc, r0.getResult());
375344e58509SEric Schweitz     return mlir::success();
37547b5132daSValentin Clement   }
37557b5132daSValentin Clement };
37567b5132daSValentin Clement 
37577b5132daSValentin Clement /// Inlined complex negation
3758e9639e9cSValentin Clement (バレンタイン クレメン) struct NegcOpConversion : public fir::FIROpConversion<fir::NegcOp> {
37597b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
37607b5132daSValentin Clement 
3761db791b27SRamkumar Ramachandra   llvm::LogicalResult
37627b5132daSValentin Clement   matchAndRewrite(fir::NegcOp neg, OpAdaptor adaptor,
37637b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
37647b5132daSValentin Clement     // given: -(x + iy)
37657b5132daSValentin Clement     // result: -x - iy
37667b5132daSValentin Clement     auto eleTy = convertType(getComplexEleTy(neg.getType()));
37677b5132daSValentin Clement     auto loc = neg.getLoc();
37687b5132daSValentin Clement     mlir::Value o0 = adaptor.getOperands()[0];
37695c5af910SJeff Niu     auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, o0, 0);
37705c5af910SJeff Niu     auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, o0, 1);
37717b5132daSValentin Clement     auto nrp = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, rp);
37727b5132daSValentin Clement     auto nip = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, ip);
37735c5af910SJeff Niu     auto r = rewriter.create<mlir::LLVM::InsertValueOp>(loc, o0, nrp, 0);
37745c5af910SJeff Niu     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(neg, r, nip, 1);
377544e58509SEric Schweitz     return mlir::success();
37767b5132daSValentin Clement   }
37777b5132daSValentin Clement };
37787b5132daSValentin Clement 
3779e9639e9cSValentin Clement (バレンタイン クレメン) struct BoxOffsetOpConversion : public fir::FIROpConversion<fir::BoxOffsetOp> {
378091e1b4a6SjeanPerier   using FIROpConversion::FIROpConversion;
378191e1b4a6SjeanPerier 
3782db791b27SRamkumar Ramachandra   llvm::LogicalResult
378391e1b4a6SjeanPerier   matchAndRewrite(fir::BoxOffsetOp boxOffset, OpAdaptor adaptor,
378491e1b4a6SjeanPerier                   mlir::ConversionPatternRewriter &rewriter) const override {
378591e1b4a6SjeanPerier 
378691e1b4a6SjeanPerier     mlir::Type pty = ::getLlvmPtrType(boxOffset.getContext());
378791e1b4a6SjeanPerier     mlir::Type boxType = fir::unwrapRefType(boxOffset.getBoxRef().getType());
378891e1b4a6SjeanPerier     mlir::Type llvmBoxTy =
378991e1b4a6SjeanPerier         lowerTy().convertBoxTypeAsStruct(mlir::cast<fir::BaseBoxType>(boxType));
3790740f14edSjeanPerier     int fieldId = boxOffset.getField() == fir::BoxFieldAttr::derived_type
379191e1b4a6SjeanPerier                       ? getTypeDescFieldId(boxType)
379291e1b4a6SjeanPerier                       : kAddrPosInBox;
379391e1b4a6SjeanPerier     rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(
379491e1b4a6SjeanPerier         boxOffset, pty, llvmBoxTy, adaptor.getBoxRef(),
379591e1b4a6SjeanPerier         llvm::ArrayRef<mlir::LLVM::GEPArg>{0, fieldId});
379691e1b4a6SjeanPerier     return mlir::success();
379791e1b4a6SjeanPerier   }
379891e1b4a6SjeanPerier };
379991e1b4a6SjeanPerier 
38001ed5a90fSValentin Clement /// Conversion pattern for operation that must be dead. The information in these
38011ed5a90fSValentin Clement /// operations is used by other operation. At this point they should not have
38021ed5a90fSValentin Clement /// anymore uses.
38031ed5a90fSValentin Clement /// These operations are normally dead after the pre-codegen pass.
38041ed5a90fSValentin Clement template <typename FromOp>
3805e9639e9cSValentin Clement (バレンタイン クレメン) struct MustBeDeadConversion : public fir::FIROpConversion<FromOp> {
3806ce254598SMatthias Springer   explicit MustBeDeadConversion(const fir::LLVMTypeConverter &lowering,
38074c5dee77SRenaud-K                                 const fir::FIRToLLVMPassOptions &options)
3808e9639e9cSValentin Clement (バレンタイン クレメン)       : fir::FIROpConversion<FromOp>(lowering, options) {}
38091ed5a90fSValentin Clement   using OpAdaptor = typename FromOp::Adaptor;
38101ed5a90fSValentin Clement 
3811db791b27SRamkumar Ramachandra   llvm::LogicalResult
38121ed5a90fSValentin Clement   matchAndRewrite(FromOp op, OpAdaptor adaptor,
38131ed5a90fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const final {
38141ed5a90fSValentin Clement     if (!op->getUses().empty())
38151ed5a90fSValentin Clement       return rewriter.notifyMatchFailure(op, "op must be dead");
38161ed5a90fSValentin Clement     rewriter.eraseOp(op);
381744e58509SEric Schweitz     return mlir::success();
38181ed5a90fSValentin Clement   }
38191ed5a90fSValentin Clement };
38201ed5a90fSValentin Clement 
38211ed5a90fSValentin Clement struct ShapeOpConversion : public MustBeDeadConversion<fir::ShapeOp> {
38221ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
38231ed5a90fSValentin Clement };
38241ed5a90fSValentin Clement 
38251ed5a90fSValentin Clement struct ShapeShiftOpConversion : public MustBeDeadConversion<fir::ShapeShiftOp> {
38261ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
38271ed5a90fSValentin Clement };
38281ed5a90fSValentin Clement 
38291ed5a90fSValentin Clement struct ShiftOpConversion : public MustBeDeadConversion<fir::ShiftOp> {
38301ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
38311ed5a90fSValentin Clement };
38321ed5a90fSValentin Clement 
38331ed5a90fSValentin Clement struct SliceOpConversion : public MustBeDeadConversion<fir::SliceOp> {
38341ed5a90fSValentin Clement   using MustBeDeadConversion::MustBeDeadConversion;
38351ed5a90fSValentin Clement };
38361ed5a90fSValentin Clement 
3837044d5b5dSValentin Clement } // namespace
3838044d5b5dSValentin Clement 
3839044d5b5dSValentin Clement namespace {
384036799dfdSDiana Picus class RenameMSVCLibmCallees
384136799dfdSDiana Picus     : public mlir::OpRewritePattern<mlir::LLVM::CallOp> {
384236799dfdSDiana Picus public:
384336799dfdSDiana Picus   using OpRewritePattern::OpRewritePattern;
384436799dfdSDiana Picus 
3845db791b27SRamkumar Ramachandra   llvm::LogicalResult
384636799dfdSDiana Picus   matchAndRewrite(mlir::LLVM::CallOp op,
384736799dfdSDiana Picus                   mlir::PatternRewriter &rewriter) const override {
38485fcf907bSMatthias Springer     rewriter.startOpModification(op);
384936799dfdSDiana Picus     auto callee = op.getCallee();
385036799dfdSDiana Picus     if (callee)
3851f841ca0cSKazu Hirata       if (*callee == "hypotf")
385236799dfdSDiana Picus         op.setCalleeAttr(mlir::SymbolRefAttr::get(op.getContext(), "_hypotf"));
385336799dfdSDiana Picus 
38545fcf907bSMatthias Springer     rewriter.finalizeOpModification(op);
385536799dfdSDiana Picus     return mlir::success();
385636799dfdSDiana Picus   }
385736799dfdSDiana Picus };
385836799dfdSDiana Picus 
385936799dfdSDiana Picus class RenameMSVCLibmFuncs
386036799dfdSDiana Picus     : public mlir::OpRewritePattern<mlir::LLVM::LLVMFuncOp> {
386136799dfdSDiana Picus public:
386236799dfdSDiana Picus   using OpRewritePattern::OpRewritePattern;
386336799dfdSDiana Picus 
3864db791b27SRamkumar Ramachandra   llvm::LogicalResult
386536799dfdSDiana Picus   matchAndRewrite(mlir::LLVM::LLVMFuncOp op,
386636799dfdSDiana Picus                   mlir::PatternRewriter &rewriter) const override {
38675fcf907bSMatthias Springer     rewriter.startOpModification(op);
3868f841ca0cSKazu Hirata     if (op.getSymName() == "hypotf")
386936799dfdSDiana Picus       op.setSymNameAttr(rewriter.getStringAttr("_hypotf"));
38705fcf907bSMatthias Springer     rewriter.finalizeOpModification(op);
387136799dfdSDiana Picus     return mlir::success();
387236799dfdSDiana Picus   }
387336799dfdSDiana Picus };
387436799dfdSDiana Picus } // namespace
387536799dfdSDiana Picus 
387636799dfdSDiana Picus namespace {
3877044d5b5dSValentin Clement /// Convert FIR dialect to LLVM dialect
3878044d5b5dSValentin Clement ///
3879044d5b5dSValentin Clement /// This pass lowers all FIR dialect operations to LLVM IR dialect. An
3880044d5b5dSValentin Clement /// MLIR pass is used to lower residual Std dialect to LLVM IR dialect.
388167d0d7acSMichele Scuttari class FIRToLLVMLowering
388267d0d7acSMichele Scuttari     : public fir::impl::FIRToLLVMLoweringBase<FIRToLLVMLowering> {
3883044d5b5dSValentin Clement public:
3884013160f6SJean Perier   FIRToLLVMLowering() = default;
3885013160f6SJean Perier   FIRToLLVMLowering(fir::FIRToLLVMPassOptions options) : options{options} {}
3886044d5b5dSValentin Clement   mlir::ModuleOp getModule() { return getOperation(); }
3887044d5b5dSValentin Clement 
3888044d5b5dSValentin Clement   void runOnOperation() override final {
38897b5132daSValentin Clement     auto mod = getModule();
389044e58509SEric Schweitz     if (!forcedTargetTriple.empty())
38917b5132daSValentin Clement       fir::setTargetTriple(mod, forcedTargetTriple);
38927b5132daSValentin Clement 
3893abeb6c9fSagozillon     if (!forcedDataLayout.empty()) {
3894abeb6c9fSagozillon       llvm::DataLayout dl(forcedDataLayout);
3895abeb6c9fSagozillon       fir::support::setMLIRDataLayout(mod, dl);
3896abeb6c9fSagozillon     }
3897abeb6c9fSagozillon 
3898837bff11SSergio Afonso     if (!forcedTargetCPU.empty())
3899837bff11SSergio Afonso       fir::setTargetCPU(mod, forcedTargetCPU);
3900837bff11SSergio Afonso 
3901f1d3fe7aSAlexis Perry-Holby     if (!forcedTuneCPU.empty())
3902f1d3fe7aSAlexis Perry-Holby       fir::setTuneCPU(mod, forcedTuneCPU);
3903f1d3fe7aSAlexis Perry-Holby 
3904837bff11SSergio Afonso     if (!forcedTargetFeatures.empty())
3905837bff11SSergio Afonso       fir::setTargetFeatures(mod, forcedTargetFeatures);
3906837bff11SSergio Afonso 
3907cfd4c180SSlava Zakharin     if (typeDescriptorsRenamedForAssembly)
3908cfd4c180SSlava Zakharin       options.typeDescriptorsRenamedForAssembly =
3909cfd4c180SSlava Zakharin           typeDescriptorsRenamedForAssembly;
3910cfd4c180SSlava Zakharin 
3911bac3aedaSSlava Zakharin     // Run dynamic pass pipeline for converting Math dialect
3912bac3aedaSSlava Zakharin     // operations into other dialects (llvm, func, etc.).
3913bac3aedaSSlava Zakharin     // Some conversions of Math operations cannot be done
3914bac3aedaSSlava Zakharin     // by just using conversion patterns. This is true for
3915bac3aedaSSlava Zakharin     // conversions that affect the ModuleOp, e.g. create new
3916bac3aedaSSlava Zakharin     // function operations in it. We have to run such conversions
3917bac3aedaSSlava Zakharin     // as passes here.
3918bac3aedaSSlava Zakharin     mlir::OpPassManager mathConvertionPM("builtin.module");
39199e8f6772SSlava Zakharin 
39204290e34eSJan Leyonberg     bool isAMDGCN = fir::getTargetTriple(mod).isAMDGCN();
39214290e34eSJan Leyonberg     // If compiling for AMD target some math operations must be lowered to AMD
39224290e34eSJan Leyonberg     // GPU library calls, the rest can be converted to LLVM intrinsics, which
39234290e34eSJan Leyonberg     // is handled in the mathToLLVM conversion. The lowering to libm calls is
39244290e34eSJan Leyonberg     // not needed since all math operations are handled this way.
39254290e34eSJan Leyonberg     if (isAMDGCN)
39264290e34eSJan Leyonberg       mathConvertionPM.addPass(mlir::createConvertMathToROCDL());
39274290e34eSJan Leyonberg 
39289e8f6772SSlava Zakharin     // Convert math::FPowI operations to inline implementation
39299e8f6772SSlava Zakharin     // only if the exponent's width is greater than 32, otherwise,
39309e8f6772SSlava Zakharin     // it will be lowered to LLVM intrinsic operation by a later conversion.
39319e8f6772SSlava Zakharin     mlir::ConvertMathToFuncsOptions mathToFuncsOptions{};
39329e8f6772SSlava Zakharin     mathToFuncsOptions.minWidthOfFPowIExponent = 33;
39339e8f6772SSlava Zakharin     mathConvertionPM.addPass(
39349e8f6772SSlava Zakharin         mlir::createConvertMathToFuncs(mathToFuncsOptions));
3935000de666SDavid Truby     mathConvertionPM.addPass(mlir::createConvertComplexToStandardPass());
3936cf550e61SSlava Zakharin     // Convert Math dialect operations into LLVM dialect operations.
3937cf550e61SSlava Zakharin     // There is no way to prefer MathToLLVM patterns over MathToLibm
3938cf550e61SSlava Zakharin     // patterns (applied below), so we have to run MathToLLVM conversion here.
3939cf550e61SSlava Zakharin     mathConvertionPM.addNestedPass<mlir::func::FuncOp>(
3940cf550e61SSlava Zakharin         mlir::createConvertMathToLLVMPass());
3941bac3aedaSSlava Zakharin     if (mlir::failed(runPipeline(mathConvertionPM, mod)))
3942bac3aedaSSlava Zakharin       return signalPassFailure();
3943bac3aedaSSlava Zakharin 
394427d9a479SjeanPerier     std::optional<mlir::DataLayout> dl =
394527d9a479SjeanPerier         fir::support::getOrSetDataLayout(mod, /*allowDefaultLayout=*/true);
394627d9a479SjeanPerier     if (!dl) {
394727d9a479SjeanPerier       mlir::emitError(mod.getLoc(),
394827d9a479SjeanPerier                       "module operation must carry a data layout attribute "
394927d9a479SjeanPerier                       "to generate llvm IR from FIR");
395027d9a479SjeanPerier       signalPassFailure();
395127d9a479SjeanPerier       return;
395227d9a479SjeanPerier     }
395327d9a479SjeanPerier 
3954044d5b5dSValentin Clement     auto *context = getModule().getContext();
39559c84d20fSSlava Zakharin     fir::LLVMTypeConverter typeConverter{getModule(),
3956ac0015feSTom Eccles                                          options.applyTBAA || applyTBAA,
395727d9a479SjeanPerier                                          options.forceUnifiedTBAATree, *dl};
39589f85c198SRiver Riddle     mlir::RewritePatternSet pattern(context);
3959408d4e13SValentin Clement (バレンタイン クレメン)     fir::populateFIRToLLVMConversionPatterns(typeConverter, pattern, options);
39605a7b9194SRiver Riddle     mlir::populateFuncToLLVMConversionPatterns(typeConverter, pattern);
3961c6ac9370SKiran Chandramohan     mlir::populateOpenMPToLLVMConversionPatterns(typeConverter, pattern);
39626c8d8d10SJakub Kuderski     mlir::arith::populateArithToLLVMConversionPatterns(typeConverter, pattern);
3963ace01605SRiver Riddle     mlir::cf::populateControlFlowToLLVMConversionPatterns(typeConverter,
3964ace01605SRiver Riddle                                                           pattern);
3965599c7399SMatthias Springer     mlir::cf::populateAssertToLLVMConversionPattern(typeConverter, pattern);
3966cf550e61SSlava Zakharin     // Math operations that have not been converted yet must be converted
3967cf550e61SSlava Zakharin     // to Libm.
39684290e34eSJan Leyonberg     if (!isAMDGCN)
3969d61a3d3aSAlexander Belyaev       mlir::populateMathToLibmConversionPatterns(pattern);
3970000de666SDavid Truby     mlir::populateComplexToLLVMConversionPatterns(typeConverter, pattern);
3971a9e1d2e7SKelvin Li     mlir::populateVectorToLLVMConversionPatterns(typeConverter, pattern);
397295fe47caSagozillon 
397395fe47caSagozillon     // Flang specific overloads for OpenMP operations, to allow for special
397495fe47caSagozillon     // handling of things like Box types.
397595fe47caSagozillon     fir::populateOpenMPFIRToLLVMConversionPatterns(typeConverter, pattern);
397695fe47caSagozillon 
3977044d5b5dSValentin Clement     mlir::ConversionTarget target{*context};
3978044d5b5dSValentin Clement     target.addLegalDialect<mlir::LLVM::LLVMDialect>();
3979c6ac9370SKiran Chandramohan     // The OpenMP dialect is legal for Operations without regions, for those
3980c6ac9370SKiran Chandramohan     // which contains regions it is legal if the region contains only the
398100c511b3SNimish Mishra     // LLVM dialect. Add OpenMP dialect as a legal dialect for conversion and
398200c511b3SNimish Mishra     // legalize conversion of OpenMP operations without regions.
398300c511b3SNimish Mishra     mlir::configureOpenMPToLLVMConversionLegality(target, typeConverter);
3984c6ac9370SKiran Chandramohan     target.addLegalDialect<mlir::omp::OpenMPDialect>();
3985cd9cdc68SValentin Clement     target.addLegalDialect<mlir::acc::OpenACCDialect>();
3986e5092c30SValentin Clement (バレンタイン クレメン)     target.addLegalDialect<mlir::gpu::GPUDialect>();
3987044d5b5dSValentin Clement 
3988044d5b5dSValentin Clement     // required NOPs for applying a full conversion
3989044d5b5dSValentin Clement     target.addLegalOp<mlir::ModuleOp>();
3990044d5b5dSValentin Clement 
399136799dfdSDiana Picus     // If we're on Windows, we might need to rename some libm calls.
399236799dfdSDiana Picus     bool isMSVC = fir::getTargetTriple(mod).isOSMSVCRT();
399336799dfdSDiana Picus     if (isMSVC) {
399436799dfdSDiana Picus       pattern.insert<RenameMSVCLibmCallees, RenameMSVCLibmFuncs>(context);
399536799dfdSDiana Picus 
399636799dfdSDiana Picus       target.addDynamicallyLegalOp<mlir::LLVM::CallOp>(
399736799dfdSDiana Picus           [](mlir::LLVM::CallOp op) {
399836799dfdSDiana Picus             auto callee = op.getCallee();
399936799dfdSDiana Picus             if (!callee)
400036799dfdSDiana Picus               return true;
4001f841ca0cSKazu Hirata             return *callee != "hypotf";
400236799dfdSDiana Picus           });
400336799dfdSDiana Picus       target.addDynamicallyLegalOp<mlir::LLVM::LLVMFuncOp>(
400436799dfdSDiana Picus           [](mlir::LLVM::LLVMFuncOp op) {
4005f841ca0cSKazu Hirata             return op.getSymName() != "hypotf";
400636799dfdSDiana Picus           });
400736799dfdSDiana Picus     }
400836799dfdSDiana Picus 
4009044d5b5dSValentin Clement     // apply the patterns
4010044d5b5dSValentin Clement     if (mlir::failed(mlir::applyFullConversion(getModule(), target,
4011044d5b5dSValentin Clement                                                std::move(pattern)))) {
4012044d5b5dSValentin Clement       signalPassFailure();
4013044d5b5dSValentin Clement     }
40145f476b80SDavid Truby 
4015e73cf2f0SMatthias Springer     // Run pass to add comdats to functions that have weak linkage on relevant
4016e73cf2f0SMatthias Springer     // platforms
40175f476b80SDavid Truby     if (fir::getTargetTriple(mod).supportsCOMDAT()) {
40185f476b80SDavid Truby       mlir::OpPassManager comdatPM("builtin.module");
40195f476b80SDavid Truby       comdatPM.addPass(mlir::LLVM::createLLVMAddComdats());
40205f476b80SDavid Truby       if (mlir::failed(runPipeline(comdatPM, mod)))
40215f476b80SDavid Truby         return signalPassFailure();
40225f476b80SDavid Truby     }
4023044d5b5dSValentin Clement   }
4024013160f6SJean Perier 
4025013160f6SJean Perier private:
4026013160f6SJean Perier   fir::FIRToLLVMPassOptions options;
4027044d5b5dSValentin Clement };
4028853e79d8SValentin Clement 
4029853e79d8SValentin Clement /// Lower from LLVM IR dialect to proper LLVM-IR and dump the module
4030853e79d8SValentin Clement struct LLVMIRLoweringPass
4031853e79d8SValentin Clement     : public mlir::PassWrapper<LLVMIRLoweringPass,
4032853e79d8SValentin Clement                                mlir::OperationPass<mlir::ModuleOp>> {
40335e50dd04SRiver Riddle   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(LLVMIRLoweringPass)
40345e50dd04SRiver Riddle 
403544e58509SEric Schweitz   LLVMIRLoweringPass(llvm::raw_ostream &output, fir::LLVMIRLoweringPrinter p)
4036853e79d8SValentin Clement       : output{output}, printer{p} {}
4037853e79d8SValentin Clement 
4038853e79d8SValentin Clement   mlir::ModuleOp getModule() { return getOperation(); }
4039853e79d8SValentin Clement 
4040853e79d8SValentin Clement   void runOnOperation() override final {
4041853e79d8SValentin Clement     auto *ctx = getModule().getContext();
4042853e79d8SValentin Clement     auto optName = getModule().getName();
4043853e79d8SValentin Clement     llvm::LLVMContext llvmCtx;
4044853e79d8SValentin Clement     if (auto llvmModule = mlir::translateModuleToLLVMIR(
4045853e79d8SValentin Clement             getModule(), llvmCtx, optName ? *optName : "FIRModule")) {
4046853e79d8SValentin Clement       printer(*llvmModule, output);
4047853e79d8SValentin Clement       return;
4048853e79d8SValentin Clement     }
4049853e79d8SValentin Clement 
4050853e79d8SValentin Clement     mlir::emitError(mlir::UnknownLoc::get(ctx), "could not emit LLVM-IR\n");
4051853e79d8SValentin Clement     signalPassFailure();
4052853e79d8SValentin Clement   }
4053853e79d8SValentin Clement 
4054853e79d8SValentin Clement private:
405544e58509SEric Schweitz   llvm::raw_ostream &output;
405644e58509SEric Schweitz   fir::LLVMIRLoweringPrinter printer;
4057853e79d8SValentin Clement };
4058853e79d8SValentin Clement 
4059044d5b5dSValentin Clement } // namespace
4060044d5b5dSValentin Clement 
4061044d5b5dSValentin Clement std::unique_ptr<mlir::Pass> fir::createFIRToLLVMPass() {
4062044d5b5dSValentin Clement   return std::make_unique<FIRToLLVMLowering>();
4063044d5b5dSValentin Clement }
4064853e79d8SValentin Clement 
4065853e79d8SValentin Clement std::unique_ptr<mlir::Pass>
406644e58509SEric Schweitz fir::createFIRToLLVMPass(fir::FIRToLLVMPassOptions options) {
4067013160f6SJean Perier   return std::make_unique<FIRToLLVMLowering>(options);
4068013160f6SJean Perier }
4069013160f6SJean Perier 
4070013160f6SJean Perier std::unique_ptr<mlir::Pass>
407144e58509SEric Schweitz fir::createLLVMDialectToLLVMPass(llvm::raw_ostream &output,
4072853e79d8SValentin Clement                                  fir::LLVMIRLoweringPrinter printer) {
4073853e79d8SValentin Clement   return std::make_unique<LLVMIRLoweringPass>(output, printer);
4074853e79d8SValentin Clement }
4075408d4e13SValentin Clement (バレンタイン クレメン) 
4076408d4e13SValentin Clement (バレンタイン クレメン) void fir::populateFIRToLLVMConversionPatterns(
4077206fad0eSMatthias Springer     const fir::LLVMTypeConverter &converter, mlir::RewritePatternSet &patterns,
4078408d4e13SValentin Clement (バレンタイン クレメン)     fir::FIRToLLVMPassOptions &options) {
4079408d4e13SValentin Clement (バレンタイン クレメン)   patterns.insert<
4080408d4e13SValentin Clement (バレンタイン クレメン)       AbsentOpConversion, AddcOpConversion, AddrOfOpConversion,
4081408d4e13SValentin Clement (バレンタイン クレメン)       AllocaOpConversion, AllocMemOpConversion, BoxAddrOpConversion,
4082408d4e13SValentin Clement (バレンタイン クレメン)       BoxCharLenOpConversion, BoxDimsOpConversion, BoxEleSizeOpConversion,
4083408d4e13SValentin Clement (バレンタイン クレメン)       BoxIsAllocOpConversion, BoxIsArrayOpConversion, BoxIsPtrOpConversion,
4084408d4e13SValentin Clement (バレンタイン クレメン)       BoxOffsetOpConversion, BoxProcHostOpConversion, BoxRankOpConversion,
4085408d4e13SValentin Clement (バレンタイン クレメン)       BoxTypeCodeOpConversion, BoxTypeDescOpConversion, CallOpConversion,
4086c2601f17SjeanPerier       CmpcOpConversion, ConvertOpConversion, CoordinateOpConversion,
4087c2601f17SjeanPerier       DTEntryOpConversion, DeclareOpConversion, DivcOpConversion,
4088c2601f17SjeanPerier       EmboxOpConversion, EmboxCharOpConversion, EmboxProcOpConversion,
4089c2601f17SjeanPerier       ExtractValueOpConversion, FieldIndexOpConversion, FirEndOpConversion,
4090c2601f17SjeanPerier       FreeMemOpConversion, GlobalLenOpConversion, GlobalOpConversion,
4091c2601f17SjeanPerier       InsertOnRangeOpConversion, IsPresentOpConversion,
4092e73cf2f0SMatthias Springer       LenParamIndexOpConversion, LoadOpConversion, MulcOpConversion,
4093e73cf2f0SMatthias Springer       NegcOpConversion, NoReassocOpConversion, SelectCaseOpConversion,
4094e73cf2f0SMatthias Springer       SelectOpConversion, SelectRankOpConversion, SelectTypeOpConversion,
4095e73cf2f0SMatthias Springer       ShapeOpConversion, ShapeShiftOpConversion, ShiftOpConversion,
4096e73cf2f0SMatthias Springer       SliceOpConversion, StoreOpConversion, StringLitOpConversion,
4097e73cf2f0SMatthias Springer       SubcOpConversion, TypeDescOpConversion, TypeInfoOpConversion,
4098e73cf2f0SMatthias Springer       UnboxCharOpConversion, UnboxProcOpConversion, UndefOpConversion,
4099e73cf2f0SMatthias Springer       UnreachableOpConversion, XArrayCoorOpConversion, XEmboxOpConversion,
4100e73cf2f0SMatthias Springer       XReboxOpConversion, ZeroOpConversion>(converter, options);
4101e73cf2f0SMatthias Springer 
4102e73cf2f0SMatthias Springer   // Patterns that are populated without a type converter do not trigger
4103e73cf2f0SMatthias Springer   // target materializations for the operands of the root op.
4104e73cf2f0SMatthias Springer   patterns.insert<HasValueOpConversion, InsertValueOpConversion>(
4105e73cf2f0SMatthias Springer       patterns.getContext());
4106408d4e13SValentin Clement (バレンタイン クレメン) }
4107