1044d5b5dSValentin Clement //===-- CodeGen.cpp -- bridge to lower to LLVM ----------------------------===// 2044d5b5dSValentin Clement // 3044d5b5dSValentin Clement // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4044d5b5dSValentin Clement // See https://llvm.org/LICENSE.txt for license information. 5044d5b5dSValentin Clement // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6044d5b5dSValentin Clement // 7044d5b5dSValentin Clement //===----------------------------------------------------------------------===// 8044d5b5dSValentin Clement // 9044d5b5dSValentin Clement // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ 10044d5b5dSValentin Clement // 11044d5b5dSValentin Clement //===----------------------------------------------------------------------===// 12044d5b5dSValentin Clement 13044d5b5dSValentin Clement #include "flang/Optimizer/CodeGen/CodeGen.h" 141f551032SValentin Clement #include "CGOps.h" 15044d5b5dSValentin Clement #include "PassDetail.h" 16b6e44ecdSValentin Clement #include "flang/ISO_Fortran_binding.h" 1739f4ef81SValentin Clement #include "flang/Optimizer/Dialect/FIRAttr.h" 18044d5b5dSValentin Clement #include "flang/Optimizer/Dialect/FIROps.h" 197dd7ccd2SJean Perier #include "flang/Optimizer/Support/InternalNames.h" 20af6ee580SValentin Clement #include "flang/Optimizer/Support/TypeCode.h" 217dd7ccd2SJean Perier #include "flang/Semantics/runtime-type-info.h" 22044d5b5dSValentin Clement #include "mlir/Conversion/ArithmeticToLLVM/ArithmeticToLLVM.h" 23ace01605SRiver Riddle #include "mlir/Conversion/ControlFlowToLLVM/ControlFlowToLLVM.h" 245a7b9194SRiver Riddle #include "mlir/Conversion/FuncToLLVM/ConvertFuncToLLVM.h" 25044d5b5dSValentin Clement #include "mlir/Conversion/LLVMCommon/Pattern.h" 26*c6ac9370SKiran Chandramohan #include "mlir/Conversion/OpenMPToLLVM/ConvertOpenMPToLLVM.h" 27044d5b5dSValentin Clement #include "mlir/IR/BuiltinTypes.h" 283ae8e442SValentin Clement #include "mlir/IR/Matchers.h" 29044d5b5dSValentin Clement #include "mlir/Pass/Pass.h" 30853e79d8SValentin Clement #include "mlir/Target/LLVMIR/ModuleTranslation.h" 31044d5b5dSValentin Clement #include "llvm/ADT/ArrayRef.h" 32044d5b5dSValentin Clement 33044d5b5dSValentin Clement #define DEBUG_TYPE "flang-codegen" 34044d5b5dSValentin Clement 35092601d4SAndrzej Warzynski using namespace mlir; 36092601d4SAndrzej Warzynski 37044d5b5dSValentin Clement // fir::LLVMTypeConverter for converting to LLVM IR dialect types. 38044d5b5dSValentin Clement #include "TypeConverter.h" 39044d5b5dSValentin Clement 40af6ee580SValentin Clement // TODO: This should really be recovered from the specified target. 41af6ee580SValentin Clement static constexpr unsigned defaultAlign = 8; 42af6ee580SValentin Clement 43b6e44ecdSValentin Clement /// `fir.box` attribute values as defined for CFI_attribute_t in 44b6e44ecdSValentin Clement /// flang/ISO_Fortran_binding.h. 45b6e44ecdSValentin Clement static constexpr unsigned kAttrPointer = CFI_attribute_pointer; 46b6e44ecdSValentin Clement static constexpr unsigned kAttrAllocatable = CFI_attribute_allocatable; 47b6e44ecdSValentin Clement 48135d5d4aSKiran Chandramohan static inline mlir::Type getVoidPtrType(mlir::MLIRContext *context) { 49fa517555SKiran Chandramohan return mlir::LLVM::LLVMPointerType::get(mlir::IntegerType::get(context, 8)); 50fa517555SKiran Chandramohan } 51fa517555SKiran Chandramohan 521e6d9c06SDiana Picus static mlir::LLVM::ConstantOp 531e6d9c06SDiana Picus genConstantIndex(mlir::Location loc, mlir::Type ity, 541e6d9c06SDiana Picus mlir::ConversionPatternRewriter &rewriter, 551e6d9c06SDiana Picus std::int64_t offset) { 561e6d9c06SDiana Picus auto cattr = rewriter.getI64IntegerAttr(offset); 571e6d9c06SDiana Picus return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr); 581e6d9c06SDiana Picus } 591e6d9c06SDiana Picus 6039f4ef81SValentin Clement static Block *createBlock(mlir::ConversionPatternRewriter &rewriter, 6139f4ef81SValentin Clement mlir::Block *insertBefore) { 6239f4ef81SValentin Clement assert(insertBefore && "expected valid insertion block"); 6339f4ef81SValentin Clement return rewriter.createBlock(insertBefore->getParent(), 6439f4ef81SValentin Clement mlir::Region::iterator(insertBefore)); 6539f4ef81SValentin Clement } 6639f4ef81SValentin Clement 67044d5b5dSValentin Clement namespace { 68044d5b5dSValentin Clement /// FIR conversion pattern template 69044d5b5dSValentin Clement template <typename FromOp> 70044d5b5dSValentin Clement class FIROpConversion : public mlir::ConvertOpToLLVMPattern<FromOp> { 71044d5b5dSValentin Clement public: 72013160f6SJean Perier explicit FIROpConversion(fir::LLVMTypeConverter &lowering, 73013160f6SJean Perier const fir::FIRToLLVMPassOptions &options) 74013160f6SJean Perier : mlir::ConvertOpToLLVMPattern<FromOp>(lowering), options(options) {} 75044d5b5dSValentin Clement 76044d5b5dSValentin Clement protected: 77044d5b5dSValentin Clement mlir::Type convertType(mlir::Type ty) const { 78044d5b5dSValentin Clement return lowerTy().convertType(ty); 79044d5b5dSValentin Clement } 80c2acd453SAlexisPerry mlir::Type voidPtrTy() const { return getVoidPtrType(); } 81044d5b5dSValentin Clement 825d27abe6SValentin Clement mlir::Type getVoidPtrType() const { 835d27abe6SValentin Clement return mlir::LLVM::LLVMPointerType::get( 845d27abe6SValentin Clement mlir::IntegerType::get(&lowerTy().getContext(), 8)); 855d27abe6SValentin Clement } 865d27abe6SValentin Clement 87df3b9810SValentin Clement mlir::LLVM::ConstantOp 88af6ee580SValentin Clement genI32Constant(mlir::Location loc, mlir::ConversionPatternRewriter &rewriter, 89af6ee580SValentin Clement int value) const { 90af6ee580SValentin Clement mlir::Type i32Ty = rewriter.getI32Type(); 91af6ee580SValentin Clement mlir::IntegerAttr attr = rewriter.getI32IntegerAttr(value); 92af6ee580SValentin Clement return rewriter.create<mlir::LLVM::ConstantOp>(loc, i32Ty, attr); 93af6ee580SValentin Clement } 94af6ee580SValentin Clement 95af6ee580SValentin Clement mlir::LLVM::ConstantOp 96df3b9810SValentin Clement genConstantOffset(mlir::Location loc, 97df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter, 98df3b9810SValentin Clement int offset) const { 99af6ee580SValentin Clement mlir::Type ity = lowerTy().offsetType(); 100af6ee580SValentin Clement mlir::IntegerAttr cattr = rewriter.getI32IntegerAttr(offset); 101df3b9810SValentin Clement return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr); 102df3b9810SValentin Clement } 103df3b9810SValentin Clement 104dc48849fSKiran Chandramohan /// Perform an extension or truncation as needed on an integer value. Lowering 105dc48849fSKiran Chandramohan /// to the specific target may involve some sign-extending or truncation of 106dc48849fSKiran Chandramohan /// values, particularly to fit them from abstract box types to the 107dc48849fSKiran Chandramohan /// appropriate reified structures. 108dc48849fSKiran Chandramohan mlir::Value integerCast(mlir::Location loc, 109dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter, 110dc48849fSKiran Chandramohan mlir::Type ty, mlir::Value val) const { 111dc48849fSKiran Chandramohan auto valTy = val.getType(); 112dc48849fSKiran Chandramohan // If the value was not yet lowered, lower its type so that it can 113dc48849fSKiran Chandramohan // be used in getPrimitiveTypeSizeInBits. 114dc48849fSKiran Chandramohan if (!valTy.isa<mlir::IntegerType>()) 115dc48849fSKiran Chandramohan valTy = convertType(valTy); 116dc48849fSKiran Chandramohan auto toSize = mlir::LLVM::getPrimitiveTypeSizeInBits(ty); 117dc48849fSKiran Chandramohan auto fromSize = mlir::LLVM::getPrimitiveTypeSizeInBits(valTy); 118dc48849fSKiran Chandramohan if (toSize < fromSize) 119dc48849fSKiran Chandramohan return rewriter.create<mlir::LLVM::TruncOp>(loc, ty, val); 120dc48849fSKiran Chandramohan if (toSize > fromSize) 121dc48849fSKiran Chandramohan return rewriter.create<mlir::LLVM::SExtOp>(loc, ty, val); 122dc48849fSKiran Chandramohan return val; 123dc48849fSKiran Chandramohan } 124dc48849fSKiran Chandramohan 125b6e44ecdSValentin Clement /// Construct code sequence to extract the specifc value from a `fir.box`. 126b6e44ecdSValentin Clement mlir::Value getValueFromBox(mlir::Location loc, mlir::Value box, 127df3b9810SValentin Clement mlir::Type resultTy, 128b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter, 129b6e44ecdSValentin Clement unsigned boxValue) const { 130df3b9810SValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 131b6e44ecdSValentin Clement mlir::LLVM::ConstantOp cValuePos = 132b6e44ecdSValentin Clement genConstantOffset(loc, rewriter, boxValue); 133df3b9810SValentin Clement auto pty = mlir::LLVM::LLVMPointerType::get(resultTy); 134df3b9810SValentin Clement auto p = rewriter.create<mlir::LLVM::GEPOp>( 13530122656SAlex Zinenko loc, pty, box, mlir::ValueRange{c0, cValuePos}); 136df3b9810SValentin Clement return rewriter.create<mlir::LLVM::LoadOp>(loc, resultTy, p); 137df3b9810SValentin Clement } 138df3b9810SValentin Clement 139df3b9810SValentin Clement /// Method to construct code sequence to get the triple for dimension `dim` 140df3b9810SValentin Clement /// from a box. 141df3b9810SValentin Clement SmallVector<mlir::Value, 3> 142df3b9810SValentin Clement getDimsFromBox(mlir::Location loc, ArrayRef<mlir::Type> retTys, 143df3b9810SValentin Clement mlir::Value box, mlir::Value dim, 144df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 145df3b9810SValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 146df3b9810SValentin Clement mlir::LLVM::ConstantOp cDims = 147df3b9810SValentin Clement genConstantOffset(loc, rewriter, kDimsPosInBox); 148df3b9810SValentin Clement mlir::LLVM::LoadOp l0 = 149df3b9810SValentin Clement loadFromOffset(loc, box, c0, cDims, dim, 0, retTys[0], rewriter); 150df3b9810SValentin Clement mlir::LLVM::LoadOp l1 = 151df3b9810SValentin Clement loadFromOffset(loc, box, c0, cDims, dim, 1, retTys[1], rewriter); 152df3b9810SValentin Clement mlir::LLVM::LoadOp l2 = 153df3b9810SValentin Clement loadFromOffset(loc, box, c0, cDims, dim, 2, retTys[2], rewriter); 154df3b9810SValentin Clement return {l0.getResult(), l1.getResult(), l2.getResult()}; 155df3b9810SValentin Clement } 156df3b9810SValentin Clement 157df3b9810SValentin Clement mlir::LLVM::LoadOp 158df3b9810SValentin Clement loadFromOffset(mlir::Location loc, mlir::Value a, mlir::LLVM::ConstantOp c0, 159df3b9810SValentin Clement mlir::LLVM::ConstantOp cDims, mlir::Value dim, int off, 160df3b9810SValentin Clement mlir::Type ty, 161df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 162df3b9810SValentin Clement auto pty = mlir::LLVM::LLVMPointerType::get(ty); 163df3b9810SValentin Clement mlir::LLVM::ConstantOp c = genConstantOffset(loc, rewriter, off); 164df3b9810SValentin Clement mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, a, c0, cDims, dim, c); 165df3b9810SValentin Clement return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p); 166df3b9810SValentin Clement } 167df3b9810SValentin Clement 1685d27abe6SValentin Clement mlir::Value 1695d27abe6SValentin Clement loadStrideFromBox(mlir::Location loc, mlir::Value box, unsigned dim, 1705d27abe6SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 1715d27abe6SValentin Clement auto idxTy = lowerTy().indexType(); 1725d27abe6SValentin Clement auto c0 = genConstantOffset(loc, rewriter, 0); 1735d27abe6SValentin Clement auto cDims = genConstantOffset(loc, rewriter, kDimsPosInBox); 1745d27abe6SValentin Clement auto dimValue = genConstantIndex(loc, idxTy, rewriter, dim); 1755d27abe6SValentin Clement return loadFromOffset(loc, box, c0, cDims, dimValue, kDimStridePos, idxTy, 1765d27abe6SValentin Clement rewriter); 1775d27abe6SValentin Clement } 1785d27abe6SValentin Clement 179df3b9810SValentin Clement /// Read base address from a fir.box. Returned address has type ty. 180df3b9810SValentin Clement mlir::Value 181df3b9810SValentin Clement loadBaseAddrFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box, 182df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 183df3b9810SValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 184df3b9810SValentin Clement mlir::LLVM::ConstantOp cAddr = 185df3b9810SValentin Clement genConstantOffset(loc, rewriter, kAddrPosInBox); 186df3b9810SValentin Clement auto pty = mlir::LLVM::LLVMPointerType::get(ty); 187df3b9810SValentin Clement mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cAddr); 188df3b9810SValentin Clement return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p); 189df3b9810SValentin Clement } 190df3b9810SValentin Clement 191df3b9810SValentin Clement mlir::Value 192df3b9810SValentin Clement loadElementSizeFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box, 193df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 194df3b9810SValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 195df3b9810SValentin Clement mlir::LLVM::ConstantOp cElemLen = 196df3b9810SValentin Clement genConstantOffset(loc, rewriter, kElemLenPosInBox); 197df3b9810SValentin Clement auto pty = mlir::LLVM::LLVMPointerType::get(ty); 198df3b9810SValentin Clement mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cElemLen); 199df3b9810SValentin Clement return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p); 200df3b9810SValentin Clement } 201df3b9810SValentin Clement 202af6ee580SValentin Clement // Get the element type given an LLVM type that is of the form 203af6ee580SValentin Clement // [llvm.ptr](array|struct|vector)+ and the provided indexes. 204af6ee580SValentin Clement static mlir::Type getBoxEleTy(mlir::Type type, 205af6ee580SValentin Clement llvm::ArrayRef<unsigned> indexes) { 206af6ee580SValentin Clement if (auto t = type.dyn_cast<mlir::LLVM::LLVMPointerType>()) 207af6ee580SValentin Clement type = t.getElementType(); 208af6ee580SValentin Clement for (auto i : indexes) { 209af6ee580SValentin Clement if (auto t = type.dyn_cast<mlir::LLVM::LLVMStructType>()) { 210af6ee580SValentin Clement assert(!t.isOpaque() && i < t.getBody().size()); 211af6ee580SValentin Clement type = t.getBody()[i]; 212af6ee580SValentin Clement } else if (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) { 213af6ee580SValentin Clement type = t.getElementType(); 214af6ee580SValentin Clement } else if (auto t = type.dyn_cast<mlir::VectorType>()) { 215af6ee580SValentin Clement type = t.getElementType(); 216af6ee580SValentin Clement } else { 217af6ee580SValentin Clement fir::emitFatalError(mlir::UnknownLoc::get(type.getContext()), 218af6ee580SValentin Clement "request for invalid box element type"); 219af6ee580SValentin Clement } 220af6ee580SValentin Clement } 221af6ee580SValentin Clement return type; 222af6ee580SValentin Clement } 223af6ee580SValentin Clement 2245d27abe6SValentin Clement // Return LLVM type of the base address given the LLVM type 2255d27abe6SValentin Clement // of the related descriptor (lowered fir.box type). 2265d27abe6SValentin Clement static mlir::Type getBaseAddrTypeFromBox(mlir::Type type) { 2275d27abe6SValentin Clement return getBoxEleTy(type, {kAddrPosInBox}); 2285d27abe6SValentin Clement } 2295d27abe6SValentin Clement 230dc48849fSKiran Chandramohan // Load the attribute from the \p box and perform a check against \p maskValue 231dc48849fSKiran Chandramohan // The final comparison is implemented as `(attribute & maskValue) != 0`. 232dc48849fSKiran Chandramohan mlir::Value genBoxAttributeCheck(mlir::Location loc, mlir::Value box, 233dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter, 234dc48849fSKiran Chandramohan unsigned maskValue) const { 235dc48849fSKiran Chandramohan mlir::Type attrTy = rewriter.getI32Type(); 236dc48849fSKiran Chandramohan mlir::Value attribute = 237dc48849fSKiran Chandramohan getValueFromBox(loc, box, attrTy, rewriter, kAttributePosInBox); 238dc48849fSKiran Chandramohan mlir::LLVM::ConstantOp attrMask = 239dc48849fSKiran Chandramohan genConstantOffset(loc, rewriter, maskValue); 240dc48849fSKiran Chandramohan auto maskRes = 241dc48849fSKiran Chandramohan rewriter.create<mlir::LLVM::AndOp>(loc, attrTy, attribute, attrMask); 242dc48849fSKiran Chandramohan mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 243dc48849fSKiran Chandramohan return rewriter.create<mlir::LLVM::ICmpOp>( 244dc48849fSKiran Chandramohan loc, mlir::LLVM::ICmpPredicate::ne, maskRes, c0); 245dc48849fSKiran Chandramohan } 246dc48849fSKiran Chandramohan 247df3b9810SValentin Clement template <typename... ARGS> 248df3b9810SValentin Clement mlir::LLVM::GEPOp genGEP(mlir::Location loc, mlir::Type ty, 249df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter, 250df3b9810SValentin Clement mlir::Value base, ARGS... args) const { 251df3b9810SValentin Clement SmallVector<mlir::Value> cv{args...}; 252df3b9810SValentin Clement return rewriter.create<mlir::LLVM::GEPOp>(loc, ty, base, cv); 253df3b9810SValentin Clement } 254df3b9810SValentin Clement 255044d5b5dSValentin Clement fir::LLVMTypeConverter &lowerTy() const { 256044d5b5dSValentin Clement return *static_cast<fir::LLVMTypeConverter *>(this->getTypeConverter()); 257044d5b5dSValentin Clement } 258013160f6SJean Perier 259013160f6SJean Perier const fir::FIRToLLVMPassOptions &options; 260044d5b5dSValentin Clement }; 261044d5b5dSValentin Clement 2623ae8e442SValentin Clement /// FIR conversion pattern template 2633ae8e442SValentin Clement template <typename FromOp> 2643ae8e442SValentin Clement class FIROpAndTypeConversion : public FIROpConversion<FromOp> { 2653ae8e442SValentin Clement public: 2663ae8e442SValentin Clement using FIROpConversion<FromOp>::FIROpConversion; 2673ae8e442SValentin Clement using OpAdaptor = typename FromOp::Adaptor; 2683ae8e442SValentin Clement 2693ae8e442SValentin Clement mlir::LogicalResult 2703ae8e442SValentin Clement matchAndRewrite(FromOp op, OpAdaptor adaptor, 2713ae8e442SValentin Clement mlir::ConversionPatternRewriter &rewriter) const final { 2723ae8e442SValentin Clement mlir::Type ty = this->convertType(op.getType()); 2733ae8e442SValentin Clement return doRewrite(op, ty, adaptor, rewriter); 2743ae8e442SValentin Clement } 2753ae8e442SValentin Clement 2763ae8e442SValentin Clement virtual mlir::LogicalResult 2773ae8e442SValentin Clement doRewrite(FromOp addr, mlir::Type ty, OpAdaptor adaptor, 2783ae8e442SValentin Clement mlir::ConversionPatternRewriter &rewriter) const = 0; 2793ae8e442SValentin Clement }; 2803ae8e442SValentin Clement 2810c4a7a52SValentin Clement // Lower `fir.address_of` operation to `llvm.address_of` operation. 282044d5b5dSValentin Clement struct AddrOfOpConversion : public FIROpConversion<fir::AddrOfOp> { 283044d5b5dSValentin Clement using FIROpConversion::FIROpConversion; 284044d5b5dSValentin Clement 285044d5b5dSValentin Clement mlir::LogicalResult 286044d5b5dSValentin Clement matchAndRewrite(fir::AddrOfOp addr, OpAdaptor adaptor, 287044d5b5dSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 288044d5b5dSValentin Clement auto ty = convertType(addr.getType()); 289044d5b5dSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::AddressOfOp>( 290149ad3d5SShraiysh Vaishay addr, ty, addr.getSymbol().getRootReference().getValue()); 291044d5b5dSValentin Clement return success(); 292044d5b5dSValentin Clement } 293044d5b5dSValentin Clement }; 2941e6d9c06SDiana Picus } // namespace 2951e6d9c06SDiana Picus 2961e6d9c06SDiana Picus /// Lookup the function to compute the memory size of this parametric derived 2971e6d9c06SDiana Picus /// type. The size of the object may depend on the LEN type parameters of the 2981e6d9c06SDiana Picus /// derived type. 2991e6d9c06SDiana Picus static mlir::LLVM::LLVMFuncOp 3001e6d9c06SDiana Picus getDependentTypeMemSizeFn(fir::RecordType recTy, fir::AllocaOp op, 3011e6d9c06SDiana Picus mlir::ConversionPatternRewriter &rewriter) { 3021e6d9c06SDiana Picus auto module = op->getParentOfType<mlir::ModuleOp>(); 3031e6d9c06SDiana Picus std::string name = recTy.getName().str() + "P.mem.size"; 3041e6d9c06SDiana Picus return module.lookupSymbol<mlir::LLVM::LLVMFuncOp>(name); 3051e6d9c06SDiana Picus } 3061e6d9c06SDiana Picus 3071e6d9c06SDiana Picus namespace { 3081e6d9c06SDiana Picus /// convert to LLVM IR dialect `alloca` 3091e6d9c06SDiana Picus struct AllocaOpConversion : public FIROpConversion<fir::AllocaOp> { 3101e6d9c06SDiana Picus using FIROpConversion::FIROpConversion; 3111e6d9c06SDiana Picus 3121e6d9c06SDiana Picus mlir::LogicalResult 3131e6d9c06SDiana Picus matchAndRewrite(fir::AllocaOp alloc, OpAdaptor adaptor, 3141e6d9c06SDiana Picus mlir::ConversionPatternRewriter &rewriter) const override { 3151e6d9c06SDiana Picus mlir::ValueRange operands = adaptor.getOperands(); 3161e6d9c06SDiana Picus auto loc = alloc.getLoc(); 3171e6d9c06SDiana Picus mlir::Type ity = lowerTy().indexType(); 3181e6d9c06SDiana Picus unsigned i = 0; 3191e6d9c06SDiana Picus mlir::Value size = genConstantIndex(loc, ity, rewriter, 1).getResult(); 3201e6d9c06SDiana Picus mlir::Type ty = convertType(alloc.getType()); 3211e6d9c06SDiana Picus mlir::Type resultTy = ty; 3221e6d9c06SDiana Picus if (alloc.hasLenParams()) { 3231e6d9c06SDiana Picus unsigned end = alloc.numLenParams(); 3241e6d9c06SDiana Picus llvm::SmallVector<mlir::Value> lenParams; 3251e6d9c06SDiana Picus for (; i < end; ++i) 3261e6d9c06SDiana Picus lenParams.push_back(operands[i]); 3271e6d9c06SDiana Picus mlir::Type scalarType = fir::unwrapSequenceType(alloc.getInType()); 3281e6d9c06SDiana Picus if (auto chrTy = scalarType.dyn_cast<fir::CharacterType>()) { 3291e6d9c06SDiana Picus fir::CharacterType rawCharTy = fir::CharacterType::getUnknownLen( 3301e6d9c06SDiana Picus chrTy.getContext(), chrTy.getFKind()); 3311e6d9c06SDiana Picus ty = mlir::LLVM::LLVMPointerType::get(convertType(rawCharTy)); 3321e6d9c06SDiana Picus assert(end == 1); 3331e6d9c06SDiana Picus size = integerCast(loc, rewriter, ity, lenParams[0]); 3341e6d9c06SDiana Picus } else if (auto recTy = scalarType.dyn_cast<fir::RecordType>()) { 3351e6d9c06SDiana Picus mlir::LLVM::LLVMFuncOp memSizeFn = 3361e6d9c06SDiana Picus getDependentTypeMemSizeFn(recTy, alloc, rewriter); 3371e6d9c06SDiana Picus if (!memSizeFn) 3381e6d9c06SDiana Picus emitError(loc, "did not find allocation function"); 3391e6d9c06SDiana Picus mlir::NamedAttribute attr = rewriter.getNamedAttr( 3401e6d9c06SDiana Picus "callee", mlir::SymbolRefAttr::get(memSizeFn)); 3411e6d9c06SDiana Picus auto call = rewriter.create<mlir::LLVM::CallOp>( 3421e6d9c06SDiana Picus loc, ity, lenParams, llvm::ArrayRef<mlir::NamedAttribute>{attr}); 3431e6d9c06SDiana Picus size = call.getResult(0); 3441e6d9c06SDiana Picus ty = mlir::LLVM::LLVMPointerType::get( 3451e6d9c06SDiana Picus mlir::IntegerType::get(alloc.getContext(), 8)); 3461e6d9c06SDiana Picus } else { 3471e6d9c06SDiana Picus return emitError(loc, "unexpected type ") 3481e6d9c06SDiana Picus << scalarType << " with type parameters"; 3491e6d9c06SDiana Picus } 3501e6d9c06SDiana Picus } 3511e6d9c06SDiana Picus if (alloc.hasShapeOperands()) { 3521e6d9c06SDiana Picus mlir::Type allocEleTy = fir::unwrapRefType(alloc.getType()); 3531e6d9c06SDiana Picus // Scale the size by constant factors encoded in the array type. 354776d0ed6SDiana Picus // We only do this for arrays that don't have a constant interior, since 355776d0ed6SDiana Picus // those are the only ones that get decayed to a pointer to the element 356776d0ed6SDiana Picus // type. 3571e6d9c06SDiana Picus if (auto seqTy = allocEleTy.dyn_cast<fir::SequenceType>()) { 358776d0ed6SDiana Picus if (!seqTy.hasConstantInterior()) { 3591e6d9c06SDiana Picus fir::SequenceType::Extent constSize = 1; 3601e6d9c06SDiana Picus for (auto extent : seqTy.getShape()) 3611e6d9c06SDiana Picus if (extent != fir::SequenceType::getUnknownExtent()) 3621e6d9c06SDiana Picus constSize *= extent; 3631e6d9c06SDiana Picus mlir::Value constVal{ 3641e6d9c06SDiana Picus genConstantIndex(loc, ity, rewriter, constSize).getResult()}; 3651e6d9c06SDiana Picus size = rewriter.create<mlir::LLVM::MulOp>(loc, ity, size, constVal); 3661e6d9c06SDiana Picus } 367776d0ed6SDiana Picus } 3681e6d9c06SDiana Picus unsigned end = operands.size(); 3691e6d9c06SDiana Picus for (; i < end; ++i) 3701e6d9c06SDiana Picus size = rewriter.create<mlir::LLVM::MulOp>( 3711e6d9c06SDiana Picus loc, ity, size, integerCast(loc, rewriter, ity, operands[i])); 3721e6d9c06SDiana Picus } 3731e6d9c06SDiana Picus if (ty == resultTy) { 3741e6d9c06SDiana Picus // Do not emit the bitcast if ty and resultTy are the same. 3751e6d9c06SDiana Picus rewriter.replaceOpWithNewOp<mlir::LLVM::AllocaOp>(alloc, ty, size, 3761e6d9c06SDiana Picus alloc->getAttrs()); 3771e6d9c06SDiana Picus } else { 3781e6d9c06SDiana Picus auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, ty, size, 3791e6d9c06SDiana Picus alloc->getAttrs()); 3801e6d9c06SDiana Picus rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(alloc, resultTy, al); 3811e6d9c06SDiana Picus } 3821e6d9c06SDiana Picus return success(); 3831e6d9c06SDiana Picus } 3841e6d9c06SDiana Picus }; 385dc48849fSKiran Chandramohan } // namespace 386044d5b5dSValentin Clement 387dc48849fSKiran Chandramohan /// Construct an `llvm.extractvalue` instruction. It will return value at 388dc48849fSKiran Chandramohan /// element \p x from \p tuple. 389dc48849fSKiran Chandramohan static mlir::LLVM::ExtractValueOp 390dc48849fSKiran Chandramohan genExtractValueWithIndex(mlir::Location loc, mlir::Value tuple, mlir::Type ty, 391dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter, 392dc48849fSKiran Chandramohan mlir::MLIRContext *ctx, int x) { 393dc48849fSKiran Chandramohan auto cx = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(x)); 394dc48849fSKiran Chandramohan auto xty = ty.cast<mlir::LLVM::LLVMStructType>().getBody()[x]; 395dc48849fSKiran Chandramohan return rewriter.create<mlir::LLVM::ExtractValueOp>(loc, xty, tuple, cx); 396dc48849fSKiran Chandramohan } 397dc48849fSKiran Chandramohan 398dc48849fSKiran Chandramohan namespace { 399df3b9810SValentin Clement /// Lower `fir.box_addr` to the sequence of operations to extract the first 400df3b9810SValentin Clement /// element of the box. 401df3b9810SValentin Clement struct BoxAddrOpConversion : public FIROpConversion<fir::BoxAddrOp> { 402df3b9810SValentin Clement using FIROpConversion::FIROpConversion; 403df3b9810SValentin Clement 404df3b9810SValentin Clement mlir::LogicalResult 405df3b9810SValentin Clement matchAndRewrite(fir::BoxAddrOp boxaddr, OpAdaptor adaptor, 406df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 407df3b9810SValentin Clement mlir::Value a = adaptor.getOperands()[0]; 408df3b9810SValentin Clement auto loc = boxaddr.getLoc(); 409df3b9810SValentin Clement mlir::Type ty = convertType(boxaddr.getType()); 410149ad3d5SShraiysh Vaishay if (auto argty = boxaddr.getVal().getType().dyn_cast<fir::BoxType>()) { 411df3b9810SValentin Clement rewriter.replaceOp(boxaddr, loadBaseAddrFromBox(loc, ty, a, rewriter)); 412df3b9810SValentin Clement } else { 413df3b9810SValentin Clement auto c0attr = rewriter.getI32IntegerAttr(0); 414df3b9810SValentin Clement auto c0 = mlir::ArrayAttr::get(boxaddr.getContext(), c0attr); 415df3b9810SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(boxaddr, ty, a, 416df3b9810SValentin Clement c0); 417df3b9810SValentin Clement } 418df3b9810SValentin Clement return success(); 419df3b9810SValentin Clement } 420df3b9810SValentin Clement }; 421df3b9810SValentin Clement 422dc48849fSKiran Chandramohan /// Convert `!fir.boxchar_len` to `!llvm.extractvalue` for the 2nd part of the 423dc48849fSKiran Chandramohan /// boxchar. 424dc48849fSKiran Chandramohan struct BoxCharLenOpConversion : public FIROpConversion<fir::BoxCharLenOp> { 425dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 426dc48849fSKiran Chandramohan 427dc48849fSKiran Chandramohan mlir::LogicalResult 428dc48849fSKiran Chandramohan matchAndRewrite(fir::BoxCharLenOp boxCharLen, OpAdaptor adaptor, 429dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 430dc48849fSKiran Chandramohan mlir::Value boxChar = adaptor.getOperands()[0]; 431dc48849fSKiran Chandramohan mlir::Location loc = boxChar.getLoc(); 432dc48849fSKiran Chandramohan mlir::MLIRContext *ctx = boxChar.getContext(); 433dc48849fSKiran Chandramohan mlir::Type returnValTy = boxCharLen.getResult().getType(); 434dc48849fSKiran Chandramohan 435dc48849fSKiran Chandramohan constexpr int boxcharLenIdx = 1; 436dc48849fSKiran Chandramohan mlir::LLVM::ExtractValueOp len = genExtractValueWithIndex( 437dc48849fSKiran Chandramohan loc, boxChar, boxChar.getType(), rewriter, ctx, boxcharLenIdx); 438dc48849fSKiran Chandramohan mlir::Value lenAfterCast = integerCast(loc, rewriter, returnValTy, len); 439dc48849fSKiran Chandramohan rewriter.replaceOp(boxCharLen, lenAfterCast); 440dc48849fSKiran Chandramohan 441dc48849fSKiran Chandramohan return success(); 442dc48849fSKiran Chandramohan } 443dc48849fSKiran Chandramohan }; 444dc48849fSKiran Chandramohan 445df3b9810SValentin Clement /// Lower `fir.box_dims` to a sequence of operations to extract the requested 446df3b9810SValentin Clement /// dimension infomartion from the boxed value. 447df3b9810SValentin Clement /// Result in a triple set of GEPs and loads. 448df3b9810SValentin Clement struct BoxDimsOpConversion : public FIROpConversion<fir::BoxDimsOp> { 449df3b9810SValentin Clement using FIROpConversion::FIROpConversion; 450df3b9810SValentin Clement 451df3b9810SValentin Clement mlir::LogicalResult 452df3b9810SValentin Clement matchAndRewrite(fir::BoxDimsOp boxdims, OpAdaptor adaptor, 453df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 454df3b9810SValentin Clement SmallVector<mlir::Type, 3> resultTypes = { 455df3b9810SValentin Clement convertType(boxdims.getResult(0).getType()), 456df3b9810SValentin Clement convertType(boxdims.getResult(1).getType()), 457df3b9810SValentin Clement convertType(boxdims.getResult(2).getType()), 458df3b9810SValentin Clement }; 459df3b9810SValentin Clement auto results = 460df3b9810SValentin Clement getDimsFromBox(boxdims.getLoc(), resultTypes, adaptor.getOperands()[0], 461df3b9810SValentin Clement adaptor.getOperands()[1], rewriter); 462df3b9810SValentin Clement rewriter.replaceOp(boxdims, results); 463df3b9810SValentin Clement return success(); 464df3b9810SValentin Clement } 465df3b9810SValentin Clement }; 466df3b9810SValentin Clement 467df3b9810SValentin Clement /// Lower `fir.box_elesize` to a sequence of operations ro extract the size of 468df3b9810SValentin Clement /// an element in the boxed value. 469df3b9810SValentin Clement struct BoxEleSizeOpConversion : public FIROpConversion<fir::BoxEleSizeOp> { 470df3b9810SValentin Clement using FIROpConversion::FIROpConversion; 471df3b9810SValentin Clement 472df3b9810SValentin Clement mlir::LogicalResult 473df3b9810SValentin Clement matchAndRewrite(fir::BoxEleSizeOp boxelesz, OpAdaptor adaptor, 474df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 475df3b9810SValentin Clement mlir::Value a = adaptor.getOperands()[0]; 476df3b9810SValentin Clement auto loc = boxelesz.getLoc(); 477df3b9810SValentin Clement auto ty = convertType(boxelesz.getType()); 478b6e44ecdSValentin Clement auto elemSize = getValueFromBox(loc, a, ty, rewriter, kElemLenPosInBox); 479b6e44ecdSValentin Clement rewriter.replaceOp(boxelesz, elemSize); 480b6e44ecdSValentin Clement return success(); 481b6e44ecdSValentin Clement } 482b6e44ecdSValentin Clement }; 483b6e44ecdSValentin Clement 484b6e44ecdSValentin Clement /// Lower `fir.box_isalloc` to a sequence of operations to determine if the 485b6e44ecdSValentin Clement /// boxed value was from an ALLOCATABLE entity. 486b6e44ecdSValentin Clement struct BoxIsAllocOpConversion : public FIROpConversion<fir::BoxIsAllocOp> { 487b6e44ecdSValentin Clement using FIROpConversion::FIROpConversion; 488b6e44ecdSValentin Clement 489b6e44ecdSValentin Clement mlir::LogicalResult 490b6e44ecdSValentin Clement matchAndRewrite(fir::BoxIsAllocOp boxisalloc, OpAdaptor adaptor, 491b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 492b6e44ecdSValentin Clement mlir::Value box = adaptor.getOperands()[0]; 493b6e44ecdSValentin Clement auto loc = boxisalloc.getLoc(); 494b6e44ecdSValentin Clement mlir::Value check = 495b6e44ecdSValentin Clement genBoxAttributeCheck(loc, box, rewriter, kAttrAllocatable); 496b6e44ecdSValentin Clement rewriter.replaceOp(boxisalloc, check); 497b6e44ecdSValentin Clement return success(); 498b6e44ecdSValentin Clement } 499b6e44ecdSValentin Clement }; 500b6e44ecdSValentin Clement 501b6e44ecdSValentin Clement /// Lower `fir.box_isarray` to a sequence of operations to determine if the 502b6e44ecdSValentin Clement /// boxed is an array. 503b6e44ecdSValentin Clement struct BoxIsArrayOpConversion : public FIROpConversion<fir::BoxIsArrayOp> { 504b6e44ecdSValentin Clement using FIROpConversion::FIROpConversion; 505b6e44ecdSValentin Clement 506b6e44ecdSValentin Clement mlir::LogicalResult 507b6e44ecdSValentin Clement matchAndRewrite(fir::BoxIsArrayOp boxisarray, OpAdaptor adaptor, 508b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 509b6e44ecdSValentin Clement mlir::Value a = adaptor.getOperands()[0]; 510b6e44ecdSValentin Clement auto loc = boxisarray.getLoc(); 511b6e44ecdSValentin Clement auto rank = 512b6e44ecdSValentin Clement getValueFromBox(loc, a, rewriter.getI32Type(), rewriter, kRankPosInBox); 513b6e44ecdSValentin Clement auto c0 = genConstantOffset(loc, rewriter, 0); 514b6e44ecdSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>( 515b6e44ecdSValentin Clement boxisarray, mlir::LLVM::ICmpPredicate::ne, rank, c0); 516b6e44ecdSValentin Clement return success(); 517b6e44ecdSValentin Clement } 518b6e44ecdSValentin Clement }; 519b6e44ecdSValentin Clement 520b6e44ecdSValentin Clement /// Lower `fir.box_isptr` to a sequence of operations to determined if the 521b6e44ecdSValentin Clement /// boxed value was from a POINTER entity. 522b6e44ecdSValentin Clement struct BoxIsPtrOpConversion : public FIROpConversion<fir::BoxIsPtrOp> { 523b6e44ecdSValentin Clement using FIROpConversion::FIROpConversion; 524b6e44ecdSValentin Clement 525b6e44ecdSValentin Clement mlir::LogicalResult 526b6e44ecdSValentin Clement matchAndRewrite(fir::BoxIsPtrOp boxisptr, OpAdaptor adaptor, 527b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 528b6e44ecdSValentin Clement mlir::Value box = adaptor.getOperands()[0]; 529b6e44ecdSValentin Clement auto loc = boxisptr.getLoc(); 530b6e44ecdSValentin Clement mlir::Value check = genBoxAttributeCheck(loc, box, rewriter, kAttrPointer); 531b6e44ecdSValentin Clement rewriter.replaceOp(boxisptr, check); 532df3b9810SValentin Clement return success(); 533df3b9810SValentin Clement } 534df3b9810SValentin Clement }; 535df3b9810SValentin Clement 536df3b9810SValentin Clement /// Lower `fir.box_rank` to the sequence of operation to extract the rank from 537df3b9810SValentin Clement /// the box. 538df3b9810SValentin Clement struct BoxRankOpConversion : public FIROpConversion<fir::BoxRankOp> { 539df3b9810SValentin Clement using FIROpConversion::FIROpConversion; 540df3b9810SValentin Clement 541df3b9810SValentin Clement mlir::LogicalResult 542df3b9810SValentin Clement matchAndRewrite(fir::BoxRankOp boxrank, OpAdaptor adaptor, 543df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 544df3b9810SValentin Clement mlir::Value a = adaptor.getOperands()[0]; 545df3b9810SValentin Clement auto loc = boxrank.getLoc(); 546df3b9810SValentin Clement mlir::Type ty = convertType(boxrank.getType()); 547b6e44ecdSValentin Clement auto result = getValueFromBox(loc, a, ty, rewriter, kRankPosInBox); 548df3b9810SValentin Clement rewriter.replaceOp(boxrank, result); 549df3b9810SValentin Clement return success(); 550df3b9810SValentin Clement } 551df3b9810SValentin Clement }; 552df3b9810SValentin Clement 553cc505c0bSKiran Chandramohan /// Lower `fir.boxproc_host` operation. Extracts the host pointer from the 554cc505c0bSKiran Chandramohan /// boxproc. 555cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers. 556cc505c0bSKiran Chandramohan struct BoxProcHostOpConversion : public FIROpConversion<fir::BoxProcHostOp> { 557cc505c0bSKiran Chandramohan using FIROpConversion::FIROpConversion; 558cc505c0bSKiran Chandramohan 559cc505c0bSKiran Chandramohan mlir::LogicalResult 560cc505c0bSKiran Chandramohan matchAndRewrite(fir::BoxProcHostOp boxprochost, OpAdaptor adaptor, 561cc505c0bSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 5627ce8c6fcSKiran Chandramohan TODO(boxprochost.getLoc(), "fir.boxproc_host codegen"); 5637ce8c6fcSKiran Chandramohan return failure(); 564cc505c0bSKiran Chandramohan } 565cc505c0bSKiran Chandramohan }; 566cc505c0bSKiran Chandramohan 567e38ef2ffSValentin Clement /// Lower `fir.box_tdesc` to the sequence of operations to extract the type 568e38ef2ffSValentin Clement /// descriptor from the box. 569e38ef2ffSValentin Clement struct BoxTypeDescOpConversion : public FIROpConversion<fir::BoxTypeDescOp> { 570e38ef2ffSValentin Clement using FIROpConversion::FIROpConversion; 571e38ef2ffSValentin Clement 572e38ef2ffSValentin Clement mlir::LogicalResult 573e38ef2ffSValentin Clement matchAndRewrite(fir::BoxTypeDescOp boxtypedesc, OpAdaptor adaptor, 574e38ef2ffSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 575e38ef2ffSValentin Clement mlir::Value box = adaptor.getOperands()[0]; 576e38ef2ffSValentin Clement auto loc = boxtypedesc.getLoc(); 577e38ef2ffSValentin Clement mlir::Type typeTy = 578e38ef2ffSValentin Clement fir::getDescFieldTypeModel<kTypePosInBox>()(boxtypedesc.getContext()); 579e38ef2ffSValentin Clement auto result = getValueFromBox(loc, box, typeTy, rewriter, kTypePosInBox); 580e38ef2ffSValentin Clement auto typePtrTy = mlir::LLVM::LLVMPointerType::get(typeTy); 581e38ef2ffSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(boxtypedesc, typePtrTy, 582e38ef2ffSValentin Clement result); 583e38ef2ffSValentin Clement return success(); 584e38ef2ffSValentin Clement } 585e38ef2ffSValentin Clement }; 586e38ef2ffSValentin Clement 587dc48849fSKiran Chandramohan /// Lower `fir.string_lit` to LLVM IR dialect operation. 588dc48849fSKiran Chandramohan struct StringLitOpConversion : public FIROpConversion<fir::StringLitOp> { 589dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 590dc48849fSKiran Chandramohan 591dc48849fSKiran Chandramohan mlir::LogicalResult 592dc48849fSKiran Chandramohan matchAndRewrite(fir::StringLitOp constop, OpAdaptor adaptor, 593dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 594dc48849fSKiran Chandramohan auto ty = convertType(constop.getType()); 595dc48849fSKiran Chandramohan auto attr = constop.getValue(); 596dc48849fSKiran Chandramohan if (attr.isa<mlir::StringAttr>()) { 597dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(constop, ty, attr); 598dc48849fSKiran Chandramohan return success(); 599dc48849fSKiran Chandramohan } 600dc48849fSKiran Chandramohan 601dc48849fSKiran Chandramohan auto arr = attr.cast<mlir::ArrayAttr>(); 602dc48849fSKiran Chandramohan auto charTy = constop.getType().cast<fir::CharacterType>(); 603dc48849fSKiran Chandramohan unsigned bits = lowerTy().characterBitsize(charTy); 604dc48849fSKiran Chandramohan mlir::Type intTy = rewriter.getIntegerType(bits); 605dc48849fSKiran Chandramohan auto attrs = llvm::map_range( 606dc48849fSKiran Chandramohan arr.getValue(), [intTy, bits](mlir::Attribute attr) -> Attribute { 607dc48849fSKiran Chandramohan return mlir::IntegerAttr::get( 608dc48849fSKiran Chandramohan intTy, 609dc48849fSKiran Chandramohan attr.cast<mlir::IntegerAttr>().getValue().sextOrTrunc(bits)); 610dc48849fSKiran Chandramohan }); 611dc48849fSKiran Chandramohan mlir::Type vecType = mlir::VectorType::get(arr.size(), intTy); 612dc48849fSKiran Chandramohan auto denseAttr = mlir::DenseElementsAttr::get( 613dc48849fSKiran Chandramohan vecType.cast<mlir::ShapedType>(), llvm::to_vector<8>(attrs)); 614dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(constop, ty, 615dc48849fSKiran Chandramohan denseAttr); 616dc48849fSKiran Chandramohan return success(); 617dc48849fSKiran Chandramohan } 618dc48849fSKiran Chandramohan }; 619dc48849fSKiran Chandramohan 620ddd11b9aSAndrzej Warzynski // `fir.call` -> `llvm.call` 621ddd11b9aSAndrzej Warzynski struct CallOpConversion : public FIROpConversion<fir::CallOp> { 622ddd11b9aSAndrzej Warzynski using FIROpConversion::FIROpConversion; 623ddd11b9aSAndrzej Warzynski 624ddd11b9aSAndrzej Warzynski mlir::LogicalResult 625ddd11b9aSAndrzej Warzynski matchAndRewrite(fir::CallOp call, OpAdaptor adaptor, 626ddd11b9aSAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 627ddd11b9aSAndrzej Warzynski SmallVector<mlir::Type> resultTys; 628ddd11b9aSAndrzej Warzynski for (auto r : call.getResults()) 629ddd11b9aSAndrzej Warzynski resultTys.push_back(convertType(r.getType())); 630ddd11b9aSAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>( 631ddd11b9aSAndrzej Warzynski call, resultTys, adaptor.getOperands(), call->getAttrs()); 632ddd11b9aSAndrzej Warzynski return success(); 633ddd11b9aSAndrzej Warzynski } 634ddd11b9aSAndrzej Warzynski }; 635c2acd453SAlexisPerry } // namespace 636ddd11b9aSAndrzej Warzynski 637092cee5fSValentin Clement static mlir::Type getComplexEleTy(mlir::Type complex) { 638092cee5fSValentin Clement if (auto cc = complex.dyn_cast<mlir::ComplexType>()) 639092cee5fSValentin Clement return cc.getElementType(); 640092cee5fSValentin Clement return complex.cast<fir::ComplexType>().getElementType(); 641092cee5fSValentin Clement } 642092cee5fSValentin Clement 643c2acd453SAlexisPerry namespace { 644f1dfc027SDiana Picus /// Compare complex values 645f1dfc027SDiana Picus /// 646f1dfc027SDiana Picus /// Per 10.1, the only comparisons available are .EQ. (oeq) and .NE. (une). 647f1dfc027SDiana Picus /// 648f1dfc027SDiana Picus /// For completeness, all other comparison are done on the real component only. 649f1dfc027SDiana Picus struct CmpcOpConversion : public FIROpConversion<fir::CmpcOp> { 650f1dfc027SDiana Picus using FIROpConversion::FIROpConversion; 651f1dfc027SDiana Picus 652f1dfc027SDiana Picus mlir::LogicalResult 653f1dfc027SDiana Picus matchAndRewrite(fir::CmpcOp cmp, OpAdaptor adaptor, 654f1dfc027SDiana Picus mlir::ConversionPatternRewriter &rewriter) const override { 655f1dfc027SDiana Picus mlir::ValueRange operands = adaptor.getOperands(); 656f1dfc027SDiana Picus mlir::MLIRContext *ctxt = cmp.getContext(); 657149ad3d5SShraiysh Vaishay mlir::Type eleTy = convertType(getComplexEleTy(cmp.getLhs().getType())); 658f1dfc027SDiana Picus mlir::Type resTy = convertType(cmp.getType()); 659f1dfc027SDiana Picus mlir::Location loc = cmp.getLoc(); 660f1dfc027SDiana Picus auto pos0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0)); 661f1dfc027SDiana Picus SmallVector<mlir::Value, 2> rp{rewriter.create<mlir::LLVM::ExtractValueOp>( 662f1dfc027SDiana Picus loc, eleTy, operands[0], pos0), 663f1dfc027SDiana Picus rewriter.create<mlir::LLVM::ExtractValueOp>( 664f1dfc027SDiana Picus loc, eleTy, operands[1], pos0)}; 665f1dfc027SDiana Picus auto rcp = 666f1dfc027SDiana Picus rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, rp, cmp->getAttrs()); 667f1dfc027SDiana Picus auto pos1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1)); 668f1dfc027SDiana Picus SmallVector<mlir::Value, 2> ip{rewriter.create<mlir::LLVM::ExtractValueOp>( 669f1dfc027SDiana Picus loc, eleTy, operands[0], pos1), 670f1dfc027SDiana Picus rewriter.create<mlir::LLVM::ExtractValueOp>( 671f1dfc027SDiana Picus loc, eleTy, operands[1], pos1)}; 672f1dfc027SDiana Picus auto icp = 673f1dfc027SDiana Picus rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, ip, cmp->getAttrs()); 674f1dfc027SDiana Picus SmallVector<mlir::Value, 2> cp{rcp, icp}; 675f1dfc027SDiana Picus switch (cmp.getPredicate()) { 676f1dfc027SDiana Picus case mlir::arith::CmpFPredicate::OEQ: // .EQ. 677f1dfc027SDiana Picus rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(cmp, resTy, cp); 678f1dfc027SDiana Picus break; 679f1dfc027SDiana Picus case mlir::arith::CmpFPredicate::UNE: // .NE. 680f1dfc027SDiana Picus rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(cmp, resTy, cp); 681f1dfc027SDiana Picus break; 682f1dfc027SDiana Picus default: 683f1dfc027SDiana Picus rewriter.replaceOp(cmp, rcp.getResult()); 684f1dfc027SDiana Picus break; 685f1dfc027SDiana Picus } 686f1dfc027SDiana Picus return success(); 687f1dfc027SDiana Picus } 688f1dfc027SDiana Picus }; 689f1dfc027SDiana Picus 690e81d73edSDiana Picus /// Lower complex constants 691e81d73edSDiana Picus struct ConstcOpConversion : public FIROpConversion<fir::ConstcOp> { 692e81d73edSDiana Picus using FIROpConversion::FIROpConversion; 693e81d73edSDiana Picus 694e81d73edSDiana Picus mlir::LogicalResult 695e81d73edSDiana Picus matchAndRewrite(fir::ConstcOp conc, OpAdaptor, 696e81d73edSDiana Picus mlir::ConversionPatternRewriter &rewriter) const override { 697e81d73edSDiana Picus mlir::Location loc = conc.getLoc(); 698e81d73edSDiana Picus mlir::MLIRContext *ctx = conc.getContext(); 699e81d73edSDiana Picus mlir::Type ty = convertType(conc.getType()); 700e81d73edSDiana Picus mlir::Type ety = convertType(getComplexEleTy(conc.getType())); 701e81d73edSDiana Picus auto realFloatAttr = mlir::FloatAttr::get(ety, getValue(conc.getReal())); 702e81d73edSDiana Picus auto realPart = 703e81d73edSDiana Picus rewriter.create<mlir::LLVM::ConstantOp>(loc, ety, realFloatAttr); 704e81d73edSDiana Picus auto imFloatAttr = mlir::FloatAttr::get(ety, getValue(conc.getImaginary())); 705e81d73edSDiana Picus auto imPart = 706e81d73edSDiana Picus rewriter.create<mlir::LLVM::ConstantOp>(loc, ety, imFloatAttr); 707e81d73edSDiana Picus auto realIndex = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 708e81d73edSDiana Picus auto imIndex = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 709e81d73edSDiana Picus auto undef = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 710e81d73edSDiana Picus auto setReal = rewriter.create<mlir::LLVM::InsertValueOp>( 711e81d73edSDiana Picus loc, ty, undef, realPart, realIndex); 712e81d73edSDiana Picus rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(conc, ty, setReal, 713e81d73edSDiana Picus imPart, imIndex); 714e81d73edSDiana Picus return success(); 715e81d73edSDiana Picus } 716e81d73edSDiana Picus 717e81d73edSDiana Picus inline APFloat getValue(mlir::Attribute attr) const { 718e81d73edSDiana Picus return attr.cast<fir::RealAttr>().getValue(); 719e81d73edSDiana Picus } 720e81d73edSDiana Picus }; 721e81d73edSDiana Picus 722092cee5fSValentin Clement /// convert value of from-type to value of to-type 723092cee5fSValentin Clement struct ConvertOpConversion : public FIROpConversion<fir::ConvertOp> { 724092cee5fSValentin Clement using FIROpConversion::FIROpConversion; 725092cee5fSValentin Clement 726092cee5fSValentin Clement static bool isFloatingPointTy(mlir::Type ty) { 727092cee5fSValentin Clement return ty.isa<mlir::FloatType>(); 728092cee5fSValentin Clement } 729092cee5fSValentin Clement 730092cee5fSValentin Clement mlir::LogicalResult 731092cee5fSValentin Clement matchAndRewrite(fir::ConvertOp convert, OpAdaptor adaptor, 732092cee5fSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 7333b7ec85aSJean Perier auto fromFirTy = convert.getValue().getType(); 7343b7ec85aSJean Perier auto toFirTy = convert.getRes().getType(); 7353b7ec85aSJean Perier auto fromTy = convertType(fromFirTy); 7363b7ec85aSJean Perier auto toTy = convertType(toFirTy); 737092cee5fSValentin Clement mlir::Value op0 = adaptor.getOperands()[0]; 738092cee5fSValentin Clement if (fromTy == toTy) { 739092cee5fSValentin Clement rewriter.replaceOp(convert, op0); 740092cee5fSValentin Clement return success(); 741092cee5fSValentin Clement } 742092cee5fSValentin Clement auto loc = convert.getLoc(); 743092cee5fSValentin Clement auto convertFpToFp = [&](mlir::Value val, unsigned fromBits, 744092cee5fSValentin Clement unsigned toBits, mlir::Type toTy) -> mlir::Value { 745092cee5fSValentin Clement if (fromBits == toBits) { 746092cee5fSValentin Clement // TODO: Converting between two floating-point representations with the 747092cee5fSValentin Clement // same bitwidth is not allowed for now. 748092cee5fSValentin Clement mlir::emitError(loc, 749092cee5fSValentin Clement "cannot implicitly convert between two floating-point " 750092cee5fSValentin Clement "representations of the same bitwidth"); 751092cee5fSValentin Clement return {}; 752092cee5fSValentin Clement } 753092cee5fSValentin Clement if (fromBits > toBits) 754092cee5fSValentin Clement return rewriter.create<mlir::LLVM::FPTruncOp>(loc, toTy, val); 755092cee5fSValentin Clement return rewriter.create<mlir::LLVM::FPExtOp>(loc, toTy, val); 756092cee5fSValentin Clement }; 757092cee5fSValentin Clement // Complex to complex conversion. 7583b7ec85aSJean Perier if (fir::isa_complex(fromFirTy) && fir::isa_complex(toFirTy)) { 759092cee5fSValentin Clement // Special case: handle the conversion of a complex such that both the 760092cee5fSValentin Clement // real and imaginary parts are converted together. 761092cee5fSValentin Clement auto zero = mlir::ArrayAttr::get(convert.getContext(), 762092cee5fSValentin Clement rewriter.getI32IntegerAttr(0)); 763092cee5fSValentin Clement auto one = mlir::ArrayAttr::get(convert.getContext(), 764092cee5fSValentin Clement rewriter.getI32IntegerAttr(1)); 765149ad3d5SShraiysh Vaishay auto ty = convertType(getComplexEleTy(convert.getValue().getType())); 766092cee5fSValentin Clement auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, zero); 767092cee5fSValentin Clement auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, one); 768149ad3d5SShraiysh Vaishay auto nt = convertType(getComplexEleTy(convert.getRes().getType())); 769092cee5fSValentin Clement auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(ty); 770092cee5fSValentin Clement auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(nt); 771092cee5fSValentin Clement auto rc = convertFpToFp(rp, fromBits, toBits, nt); 772092cee5fSValentin Clement auto ic = convertFpToFp(ip, fromBits, toBits, nt); 773092cee5fSValentin Clement auto un = rewriter.create<mlir::LLVM::UndefOp>(loc, toTy); 774092cee5fSValentin Clement auto i1 = 775092cee5fSValentin Clement rewriter.create<mlir::LLVM::InsertValueOp>(loc, toTy, un, rc, zero); 776092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(convert, toTy, i1, 777092cee5fSValentin Clement ic, one); 778092cee5fSValentin Clement return mlir::success(); 779092cee5fSValentin Clement } 7803b7ec85aSJean Perier 7813b7ec85aSJean Perier // Follow UNIX F77 convention for logicals: 7823b7ec85aSJean Perier // 1. underlying integer is not zero => logical is .TRUE. 7833b7ec85aSJean Perier // 2. logical is .TRUE. => set underlying integer to 1. 7843b7ec85aSJean Perier auto i1Type = mlir::IntegerType::get(convert.getContext(), 1); 7853b7ec85aSJean Perier if (fromFirTy.isa<fir::LogicalType>() && toFirTy == i1Type) { 7863b7ec85aSJean Perier mlir::Value zero = genConstantIndex(loc, fromTy, rewriter, 0); 7873b7ec85aSJean Perier rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>( 7883b7ec85aSJean Perier convert, mlir::LLVM::ICmpPredicate::ne, op0, zero); 7893b7ec85aSJean Perier return mlir::success(); 7903b7ec85aSJean Perier } 7913b7ec85aSJean Perier if (fromFirTy == i1Type && toFirTy.isa<fir::LogicalType>()) { 7923b7ec85aSJean Perier rewriter.replaceOpWithNewOp<mlir::LLVM::ZExtOp>(convert, toTy, op0); 7933b7ec85aSJean Perier return mlir::success(); 7943b7ec85aSJean Perier } 7953b7ec85aSJean Perier 796092cee5fSValentin Clement // Floating point to floating point conversion. 797092cee5fSValentin Clement if (isFloatingPointTy(fromTy)) { 798092cee5fSValentin Clement if (isFloatingPointTy(toTy)) { 799092cee5fSValentin Clement auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy); 800092cee5fSValentin Clement auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy); 801092cee5fSValentin Clement auto v = convertFpToFp(op0, fromBits, toBits, toTy); 802092cee5fSValentin Clement rewriter.replaceOp(convert, v); 803092cee5fSValentin Clement return mlir::success(); 804092cee5fSValentin Clement } 805092cee5fSValentin Clement if (toTy.isa<mlir::IntegerType>()) { 806092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::FPToSIOp>(convert, toTy, op0); 807092cee5fSValentin Clement return mlir::success(); 808092cee5fSValentin Clement } 809092cee5fSValentin Clement } else if (fromTy.isa<mlir::IntegerType>()) { 810092cee5fSValentin Clement // Integer to integer conversion. 811092cee5fSValentin Clement if (toTy.isa<mlir::IntegerType>()) { 812092cee5fSValentin Clement auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy); 813092cee5fSValentin Clement auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy); 814092cee5fSValentin Clement assert(fromBits != toBits); 815092cee5fSValentin Clement if (fromBits > toBits) { 816092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::TruncOp>(convert, toTy, op0); 817092cee5fSValentin Clement return mlir::success(); 818092cee5fSValentin Clement } 819092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::SExtOp>(convert, toTy, op0); 820092cee5fSValentin Clement return mlir::success(); 821092cee5fSValentin Clement } 822092cee5fSValentin Clement // Integer to floating point conversion. 823092cee5fSValentin Clement if (isFloatingPointTy(toTy)) { 824092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::SIToFPOp>(convert, toTy, op0); 825092cee5fSValentin Clement return mlir::success(); 826092cee5fSValentin Clement } 827092cee5fSValentin Clement // Integer to pointer conversion. 828092cee5fSValentin Clement if (toTy.isa<mlir::LLVM::LLVMPointerType>()) { 829092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(convert, toTy, op0); 830092cee5fSValentin Clement return mlir::success(); 831092cee5fSValentin Clement } 832092cee5fSValentin Clement } else if (fromTy.isa<mlir::LLVM::LLVMPointerType>()) { 833092cee5fSValentin Clement // Pointer to integer conversion. 834092cee5fSValentin Clement if (toTy.isa<mlir::IntegerType>()) { 835092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::PtrToIntOp>(convert, toTy, op0); 836092cee5fSValentin Clement return mlir::success(); 837092cee5fSValentin Clement } 838092cee5fSValentin Clement // Pointer to pointer conversion. 839092cee5fSValentin Clement if (toTy.isa<mlir::LLVM::LLVMPointerType>()) { 840092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(convert, toTy, op0); 841092cee5fSValentin Clement return mlir::success(); 842092cee5fSValentin Clement } 843092cee5fSValentin Clement } 844092cee5fSValentin Clement return emitError(loc) << "cannot convert " << fromTy << " to " << toTy; 845092cee5fSValentin Clement } 846092cee5fSValentin Clement }; 847092cee5fSValentin Clement 8489534e361SValentin Clement /// Lower `fir.dispatch` operation. A virtual call to a method in a dispatch 8499534e361SValentin Clement /// table. 8509534e361SValentin Clement struct DispatchOpConversion : public FIROpConversion<fir::DispatchOp> { 8519534e361SValentin Clement using FIROpConversion::FIROpConversion; 8529534e361SValentin Clement 8539534e361SValentin Clement mlir::LogicalResult 8549534e361SValentin Clement matchAndRewrite(fir::DispatchOp dispatch, OpAdaptor adaptor, 8559534e361SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 8567ce8c6fcSKiran Chandramohan TODO(dispatch.getLoc(), "fir.dispatch codegen"); 8577ce8c6fcSKiran Chandramohan return failure(); 8589534e361SValentin Clement } 8599534e361SValentin Clement }; 8609534e361SValentin Clement 8619534e361SValentin Clement /// Lower `fir.dispatch_table` operation. The dispatch table for a Fortran 8629534e361SValentin Clement /// derived type. 8639534e361SValentin Clement struct DispatchTableOpConversion 8649534e361SValentin Clement : public FIROpConversion<fir::DispatchTableOp> { 8659534e361SValentin Clement using FIROpConversion::FIROpConversion; 8669534e361SValentin Clement 8679534e361SValentin Clement mlir::LogicalResult 8689534e361SValentin Clement matchAndRewrite(fir::DispatchTableOp dispTab, OpAdaptor adaptor, 8699534e361SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 8707ce8c6fcSKiran Chandramohan TODO(dispTab.getLoc(), "fir.dispatch_table codegen"); 8717ce8c6fcSKiran Chandramohan return failure(); 8729534e361SValentin Clement } 8739534e361SValentin Clement }; 8749534e361SValentin Clement 8759534e361SValentin Clement /// Lower `fir.dt_entry` operation. An entry in a dispatch table; binds a 8769534e361SValentin Clement /// method-name to a function. 8779534e361SValentin Clement struct DTEntryOpConversion : public FIROpConversion<fir::DTEntryOp> { 8789534e361SValentin Clement using FIROpConversion::FIROpConversion; 8799534e361SValentin Clement 8809534e361SValentin Clement mlir::LogicalResult 8819534e361SValentin Clement matchAndRewrite(fir::DTEntryOp dtEnt, OpAdaptor adaptor, 8829534e361SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 8837ce8c6fcSKiran Chandramohan TODO(dtEnt.getLoc(), "fir.dt_entry codegen"); 8847ce8c6fcSKiran Chandramohan return failure(); 8859534e361SValentin Clement } 8869534e361SValentin Clement }; 8879534e361SValentin Clement 888677df8c7SValentin Clement /// Lower `fir.global_len` operation. 889677df8c7SValentin Clement struct GlobalLenOpConversion : public FIROpConversion<fir::GlobalLenOp> { 890677df8c7SValentin Clement using FIROpConversion::FIROpConversion; 891677df8c7SValentin Clement 892677df8c7SValentin Clement mlir::LogicalResult 893677df8c7SValentin Clement matchAndRewrite(fir::GlobalLenOp globalLen, OpAdaptor adaptor, 894677df8c7SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 8957ce8c6fcSKiran Chandramohan TODO(globalLen.getLoc(), "fir.global_len codegen"); 8967ce8c6fcSKiran Chandramohan return failure(); 897677df8c7SValentin Clement } 898677df8c7SValentin Clement }; 899677df8c7SValentin Clement 900cdc476abSDiana Picus /// Lower fir.len_param_index 901cdc476abSDiana Picus struct LenParamIndexOpConversion 902cdc476abSDiana Picus : public FIROpConversion<fir::LenParamIndexOp> { 903cdc476abSDiana Picus using FIROpConversion::FIROpConversion; 904cdc476abSDiana Picus 905cdc476abSDiana Picus // FIXME: this should be specialized by the runtime target 906cdc476abSDiana Picus mlir::LogicalResult 907cdc476abSDiana Picus matchAndRewrite(fir::LenParamIndexOp lenp, OpAdaptor, 908cdc476abSDiana Picus mlir::ConversionPatternRewriter &rewriter) const override { 9097ce8c6fcSKiran Chandramohan TODO(lenp.getLoc(), "fir.len_param_index codegen"); 910cdc476abSDiana Picus } 911cdc476abSDiana Picus }; 912cdc476abSDiana Picus 913dc48849fSKiran Chandramohan /// Convert `!fir.emboxchar<!fir.char<KIND, ?>, #n>` into a sequence of 914dc48849fSKiran Chandramohan /// instructions that generate `!llvm.struct<(ptr<ik>, i64)>`. The 1st element 915dc48849fSKiran Chandramohan /// in this struct is a pointer. Its type is determined from `KIND`. The 2nd 916dc48849fSKiran Chandramohan /// element is the length of the character buffer (`#n`). 917dc48849fSKiran Chandramohan struct EmboxCharOpConversion : public FIROpConversion<fir::EmboxCharOp> { 91831246187SValentin Clement using FIROpConversion::FIROpConversion; 91931246187SValentin Clement 92031246187SValentin Clement mlir::LogicalResult 921dc48849fSKiran Chandramohan matchAndRewrite(fir::EmboxCharOp emboxChar, OpAdaptor adaptor, 92231246187SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 923dc48849fSKiran Chandramohan mlir::ValueRange operands = adaptor.getOperands(); 924dc48849fSKiran Chandramohan MLIRContext *ctx = emboxChar.getContext(); 925dc48849fSKiran Chandramohan 926dc48849fSKiran Chandramohan mlir::Value charBuffer = operands[0]; 927dc48849fSKiran Chandramohan mlir::Value charBufferLen = operands[1]; 928dc48849fSKiran Chandramohan 929dc48849fSKiran Chandramohan mlir::Location loc = emboxChar.getLoc(); 930dc48849fSKiran Chandramohan mlir::Type llvmStructTy = convertType(emboxChar.getType()); 931dc48849fSKiran Chandramohan auto llvmStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, llvmStructTy); 932dc48849fSKiran Chandramohan 933dc48849fSKiran Chandramohan mlir::Type lenTy = 934dc48849fSKiran Chandramohan llvmStructTy.cast<mlir::LLVM::LLVMStructType>().getBody()[1]; 935dc48849fSKiran Chandramohan mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, charBufferLen); 936dc48849fSKiran Chandramohan 937dc48849fSKiran Chandramohan auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 938dc48849fSKiran Chandramohan auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 939dc48849fSKiran Chandramohan auto insertBufferOp = rewriter.create<mlir::LLVM::InsertValueOp>( 940dc48849fSKiran Chandramohan loc, llvmStructTy, llvmStruct, charBuffer, c0); 941dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 942dc48849fSKiran Chandramohan emboxChar, llvmStructTy, insertBufferOp, lenAfterCast, c1); 943dc48849fSKiran Chandramohan 944dc48849fSKiran Chandramohan return success(); 94531246187SValentin Clement } 94631246187SValentin Clement }; 947c2acd453SAlexisPerry } // namespace 948c2acd453SAlexisPerry 949c2acd453SAlexisPerry /// Return the LLVMFuncOp corresponding to the standard malloc call. 950c2acd453SAlexisPerry static mlir::LLVM::LLVMFuncOp 951c2acd453SAlexisPerry getMalloc(fir::AllocMemOp op, mlir::ConversionPatternRewriter &rewriter) { 952c2acd453SAlexisPerry auto module = op->getParentOfType<mlir::ModuleOp>(); 953c2acd453SAlexisPerry if (mlir::LLVM::LLVMFuncOp mallocFunc = 954c2acd453SAlexisPerry module.lookupSymbol<mlir::LLVM::LLVMFuncOp>("malloc")) 955c2acd453SAlexisPerry return mallocFunc; 956c2acd453SAlexisPerry mlir::OpBuilder moduleBuilder( 957c2acd453SAlexisPerry op->getParentOfType<mlir::ModuleOp>().getBodyRegion()); 958c2acd453SAlexisPerry auto indexType = mlir::IntegerType::get(op.getContext(), 64); 959c2acd453SAlexisPerry return moduleBuilder.create<mlir::LLVM::LLVMFuncOp>( 960c2acd453SAlexisPerry rewriter.getUnknownLoc(), "malloc", 961c2acd453SAlexisPerry mlir::LLVM::LLVMFunctionType::get(getVoidPtrType(op.getContext()), 962c2acd453SAlexisPerry indexType, 963c2acd453SAlexisPerry /*isVarArg=*/false)); 964c2acd453SAlexisPerry } 965c2acd453SAlexisPerry 966c2acd453SAlexisPerry /// Helper function for generating the LLVM IR that computes the size 967c2acd453SAlexisPerry /// in bytes for a derived type. 968c2acd453SAlexisPerry static mlir::Value 969c2acd453SAlexisPerry computeDerivedTypeSize(mlir::Location loc, mlir::Type ptrTy, mlir::Type idxTy, 970c2acd453SAlexisPerry mlir::ConversionPatternRewriter &rewriter) { 971c2acd453SAlexisPerry auto nullPtr = rewriter.create<mlir::LLVM::NullOp>(loc, ptrTy); 972c2acd453SAlexisPerry mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1); 97330122656SAlex Zinenko llvm::SmallVector<mlir::Value> args{one}; 97430122656SAlex Zinenko auto gep = rewriter.create<mlir::LLVM::GEPOp>(loc, ptrTy, nullPtr, args); 975c2acd453SAlexisPerry return rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, gep); 976c2acd453SAlexisPerry } 977c2acd453SAlexisPerry 978c2acd453SAlexisPerry namespace { 979c2acd453SAlexisPerry /// Lower a `fir.allocmem` instruction into `llvm.call @malloc` 980c2acd453SAlexisPerry struct AllocMemOpConversion : public FIROpConversion<fir::AllocMemOp> { 981c2acd453SAlexisPerry using FIROpConversion::FIROpConversion; 982c2acd453SAlexisPerry 983c2acd453SAlexisPerry mlir::LogicalResult 984c2acd453SAlexisPerry matchAndRewrite(fir::AllocMemOp heap, OpAdaptor adaptor, 985c2acd453SAlexisPerry mlir::ConversionPatternRewriter &rewriter) const override { 986c45bd4b9SEric Schweitz auto heapTy = heap.getType(); 987c45bd4b9SEric Schweitz auto ty = convertType(heapTy); 988c2acd453SAlexisPerry mlir::LLVM::LLVMFuncOp mallocFunc = getMalloc(heap, rewriter); 989c2acd453SAlexisPerry mlir::Location loc = heap.getLoc(); 990c2acd453SAlexisPerry auto ity = lowerTy().indexType(); 991c45bd4b9SEric Schweitz auto dataTy = fir::unwrapRefType(heapTy); 992c45bd4b9SEric Schweitz if (fir::isRecordWithTypeParameters(fir::unwrapSequenceType(dataTy))) 993c45bd4b9SEric Schweitz TODO(loc, "fir.allocmem codegen of derived type with length parameters"); 994c2acd453SAlexisPerry mlir::Value size = genTypeSizeInBytes(loc, ity, rewriter, ty); 995c45bd4b9SEric Schweitz // !fir.array<NxMx!fir.char<K,?>> sets `size` to the width of !fir.char<K>. 996c45bd4b9SEric Schweitz // So multiply the constant dimensions here. 997c45bd4b9SEric Schweitz if (fir::hasDynamicSize(dataTy)) 998c45bd4b9SEric Schweitz if (auto seqTy = dataTy.dyn_cast<fir::SequenceType>()) 999c45bd4b9SEric Schweitz if (fir::characterWithDynamicLen(seqTy.getEleTy())) { 1000c45bd4b9SEric Schweitz fir::SequenceType::Extent arrSize = 1; 1001c45bd4b9SEric Schweitz for (auto d : seqTy.getShape()) 1002c45bd4b9SEric Schweitz if (d != fir::SequenceType::getUnknownExtent()) 1003c45bd4b9SEric Schweitz arrSize *= d; 1004c45bd4b9SEric Schweitz size = rewriter.create<mlir::LLVM::MulOp>( 1005c45bd4b9SEric Schweitz loc, ity, size, genConstantIndex(loc, ity, rewriter, arrSize)); 1006c45bd4b9SEric Schweitz } 1007c2acd453SAlexisPerry for (mlir::Value opnd : adaptor.getOperands()) 1008c2acd453SAlexisPerry size = rewriter.create<mlir::LLVM::MulOp>( 1009c2acd453SAlexisPerry loc, ity, size, integerCast(loc, rewriter, ity, opnd)); 1010c2acd453SAlexisPerry heap->setAttr("callee", mlir::SymbolRefAttr::get(mallocFunc)); 1011c2acd453SAlexisPerry auto malloc = rewriter.create<mlir::LLVM::CallOp>( 1012c2acd453SAlexisPerry loc, ::getVoidPtrType(heap.getContext()), size, heap->getAttrs()); 1013c2acd453SAlexisPerry rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(heap, ty, 1014c2acd453SAlexisPerry malloc.getResult(0)); 1015c2acd453SAlexisPerry return success(); 1016c2acd453SAlexisPerry } 1017c2acd453SAlexisPerry 1018c2acd453SAlexisPerry // Compute the (allocation) size of the allocmem type in bytes. 1019c2acd453SAlexisPerry mlir::Value genTypeSizeInBytes(mlir::Location loc, mlir::Type idxTy, 1020c2acd453SAlexisPerry mlir::ConversionPatternRewriter &rewriter, 1021c2acd453SAlexisPerry mlir::Type llTy) const { 1022c2acd453SAlexisPerry // Use the primitive size, if available. 1023c2acd453SAlexisPerry auto ptrTy = llTy.dyn_cast<mlir::LLVM::LLVMPointerType>(); 1024c2acd453SAlexisPerry if (auto size = 1025c2acd453SAlexisPerry mlir::LLVM::getPrimitiveTypeSizeInBits(ptrTy.getElementType())) 1026c2acd453SAlexisPerry return genConstantIndex(loc, idxTy, rewriter, size / 8); 1027c2acd453SAlexisPerry 1028c2acd453SAlexisPerry // Otherwise, generate the GEP trick in LLVM IR to compute the size. 1029c2acd453SAlexisPerry return computeDerivedTypeSize(loc, ptrTy, idxTy, rewriter); 1030c2acd453SAlexisPerry } 1031c2acd453SAlexisPerry }; 1032c2acd453SAlexisPerry } // namespace 1033c2acd453SAlexisPerry 1034c2acd453SAlexisPerry /// Return the LLVMFuncOp corresponding to the standard free call. 1035c2acd453SAlexisPerry static mlir::LLVM::LLVMFuncOp 1036c2acd453SAlexisPerry getFree(fir::FreeMemOp op, mlir::ConversionPatternRewriter &rewriter) { 1037c2acd453SAlexisPerry auto module = op->getParentOfType<mlir::ModuleOp>(); 1038c2acd453SAlexisPerry if (mlir::LLVM::LLVMFuncOp freeFunc = 1039c2acd453SAlexisPerry module.lookupSymbol<mlir::LLVM::LLVMFuncOp>("free")) 1040c2acd453SAlexisPerry return freeFunc; 1041c2acd453SAlexisPerry mlir::OpBuilder moduleBuilder(module.getBodyRegion()); 1042c2acd453SAlexisPerry auto voidType = mlir::LLVM::LLVMVoidType::get(op.getContext()); 1043c2acd453SAlexisPerry return moduleBuilder.create<mlir::LLVM::LLVMFuncOp>( 1044c2acd453SAlexisPerry rewriter.getUnknownLoc(), "free", 1045c2acd453SAlexisPerry mlir::LLVM::LLVMFunctionType::get(voidType, 1046c2acd453SAlexisPerry getVoidPtrType(op.getContext()), 1047c2acd453SAlexisPerry /*isVarArg=*/false)); 1048c2acd453SAlexisPerry } 1049c2acd453SAlexisPerry 1050c2acd453SAlexisPerry namespace { 1051c2acd453SAlexisPerry /// Lower a `fir.freemem` instruction into `llvm.call @free` 1052c2acd453SAlexisPerry struct FreeMemOpConversion : public FIROpConversion<fir::FreeMemOp> { 1053c2acd453SAlexisPerry using FIROpConversion::FIROpConversion; 1054c2acd453SAlexisPerry 1055c2acd453SAlexisPerry mlir::LogicalResult 1056c2acd453SAlexisPerry matchAndRewrite(fir::FreeMemOp freemem, OpAdaptor adaptor, 1057c2acd453SAlexisPerry mlir::ConversionPatternRewriter &rewriter) const override { 1058c2acd453SAlexisPerry mlir::LLVM::LLVMFuncOp freeFunc = getFree(freemem, rewriter); 1059c2acd453SAlexisPerry mlir::Location loc = freemem.getLoc(); 1060c2acd453SAlexisPerry auto bitcast = rewriter.create<mlir::LLVM::BitcastOp>( 1061c2acd453SAlexisPerry freemem.getLoc(), voidPtrTy(), adaptor.getOperands()[0]); 1062c2acd453SAlexisPerry freemem->setAttr("callee", mlir::SymbolRefAttr::get(freeFunc)); 1063c2acd453SAlexisPerry rewriter.create<mlir::LLVM::CallOp>( 1064c2acd453SAlexisPerry loc, mlir::TypeRange{}, mlir::ValueRange{bitcast}, freemem->getAttrs()); 1065c2acd453SAlexisPerry rewriter.eraseOp(freemem); 1066c2acd453SAlexisPerry return success(); 1067c2acd453SAlexisPerry } 1068c2acd453SAlexisPerry }; 1069c2acd453SAlexisPerry } // namespace 1070044d5b5dSValentin Clement 1071dc48849fSKiran Chandramohan namespace {} // namespace 107232e08248SAndrzej Warzynski 1073af6ee580SValentin Clement /// Common base class for embox to descriptor conversion. 1074af6ee580SValentin Clement template <typename OP> 1075af6ee580SValentin Clement struct EmboxCommonConversion : public FIROpConversion<OP> { 1076af6ee580SValentin Clement using FIROpConversion<OP>::FIROpConversion; 1077af6ee580SValentin Clement 1078af6ee580SValentin Clement // Find the LLVMFuncOp in whose entry block the alloca should be inserted. 1079af6ee580SValentin Clement // The order to find the LLVMFuncOp is as follows: 1080af6ee580SValentin Clement // 1. The parent operation of the current block if it is a LLVMFuncOp. 1081af6ee580SValentin Clement // 2. The first ancestor that is a LLVMFuncOp. 1082af6ee580SValentin Clement mlir::LLVM::LLVMFuncOp 1083af6ee580SValentin Clement getFuncForAllocaInsert(mlir::ConversionPatternRewriter &rewriter) const { 1084af6ee580SValentin Clement mlir::Operation *parentOp = rewriter.getInsertionBlock()->getParentOp(); 1085af6ee580SValentin Clement return mlir::isa<mlir::LLVM::LLVMFuncOp>(parentOp) 1086af6ee580SValentin Clement ? mlir::cast<mlir::LLVM::LLVMFuncOp>(parentOp) 1087af6ee580SValentin Clement : parentOp->getParentOfType<mlir::LLVM::LLVMFuncOp>(); 1088af6ee580SValentin Clement } 1089af6ee580SValentin Clement 1090af6ee580SValentin Clement // Generate an alloca of size 1 and type \p toTy. 1091af6ee580SValentin Clement mlir::LLVM::AllocaOp 1092af6ee580SValentin Clement genAllocaWithType(mlir::Location loc, mlir::Type toTy, unsigned alignment, 1093af6ee580SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 1094af6ee580SValentin Clement auto thisPt = rewriter.saveInsertionPoint(); 1095af6ee580SValentin Clement mlir::LLVM::LLVMFuncOp func = getFuncForAllocaInsert(rewriter); 1096af6ee580SValentin Clement rewriter.setInsertionPointToStart(&func.front()); 1097af6ee580SValentin Clement auto size = this->genI32Constant(loc, rewriter, 1); 1098af6ee580SValentin Clement auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, toTy, size, alignment); 1099af6ee580SValentin Clement rewriter.restoreInsertionPoint(thisPt); 1100af6ee580SValentin Clement return al; 1101af6ee580SValentin Clement } 1102af6ee580SValentin Clement 1103af6ee580SValentin Clement static int getCFIAttr(fir::BoxType boxTy) { 1104af6ee580SValentin Clement auto eleTy = boxTy.getEleTy(); 1105af6ee580SValentin Clement if (eleTy.isa<fir::PointerType>()) 1106af6ee580SValentin Clement return CFI_attribute_pointer; 1107af6ee580SValentin Clement if (eleTy.isa<fir::HeapType>()) 1108af6ee580SValentin Clement return CFI_attribute_allocatable; 1109af6ee580SValentin Clement return CFI_attribute_other; 1110af6ee580SValentin Clement } 1111af6ee580SValentin Clement 1112af6ee580SValentin Clement static fir::RecordType unwrapIfDerived(fir::BoxType boxTy) { 1113af6ee580SValentin Clement return fir::unwrapSequenceType(fir::dyn_cast_ptrOrBoxEleTy(boxTy)) 1114af6ee580SValentin Clement .template dyn_cast<fir::RecordType>(); 1115af6ee580SValentin Clement } 1116af6ee580SValentin Clement static bool isDerivedTypeWithLenParams(fir::BoxType boxTy) { 1117af6ee580SValentin Clement auto recTy = unwrapIfDerived(boxTy); 1118af6ee580SValentin Clement return recTy && recTy.getNumLenParams() > 0; 1119af6ee580SValentin Clement } 1120af6ee580SValentin Clement static bool isDerivedType(fir::BoxType boxTy) { 1121af6ee580SValentin Clement return unwrapIfDerived(boxTy) != nullptr; 1122af6ee580SValentin Clement } 1123af6ee580SValentin Clement 1124af6ee580SValentin Clement // Get the element size and CFI type code of the boxed value. 1125af6ee580SValentin Clement std::tuple<mlir::Value, mlir::Value> getSizeAndTypeCode( 1126af6ee580SValentin Clement mlir::Location loc, mlir::ConversionPatternRewriter &rewriter, 1127af6ee580SValentin Clement mlir::Type boxEleTy, mlir::ValueRange lenParams = {}) const { 1128af6ee580SValentin Clement auto doInteger = 1129af6ee580SValentin Clement [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> { 1130af6ee580SValentin Clement int typeCode = fir::integerBitsToTypeCode(width); 1131af6ee580SValentin Clement return {this->genConstantOffset(loc, rewriter, width / 8), 1132af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, typeCode)}; 1133af6ee580SValentin Clement }; 1134af6ee580SValentin Clement auto doLogical = 1135af6ee580SValentin Clement [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> { 1136af6ee580SValentin Clement int typeCode = fir::logicalBitsToTypeCode(width); 1137af6ee580SValentin Clement return {this->genConstantOffset(loc, rewriter, width / 8), 1138af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, typeCode)}; 1139af6ee580SValentin Clement }; 1140af6ee580SValentin Clement auto doFloat = [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> { 1141af6ee580SValentin Clement int typeCode = fir::realBitsToTypeCode(width); 1142af6ee580SValentin Clement return {this->genConstantOffset(loc, rewriter, width / 8), 1143af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, typeCode)}; 1144af6ee580SValentin Clement }; 1145af6ee580SValentin Clement auto doComplex = 1146af6ee580SValentin Clement [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> { 1147af6ee580SValentin Clement auto typeCode = fir::complexBitsToTypeCode(width); 1148af6ee580SValentin Clement return {this->genConstantOffset(loc, rewriter, width / 8 * 2), 1149af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, typeCode)}; 1150af6ee580SValentin Clement }; 1151af6ee580SValentin Clement auto doCharacter = 1152af6ee580SValentin Clement [&](unsigned width, 1153af6ee580SValentin Clement mlir::Value len) -> std::tuple<mlir::Value, mlir::Value> { 1154af6ee580SValentin Clement auto typeCode = fir::characterBitsToTypeCode(width); 1155af6ee580SValentin Clement auto typeCodeVal = this->genConstantOffset(loc, rewriter, typeCode); 1156af6ee580SValentin Clement if (width == 8) 1157af6ee580SValentin Clement return {len, typeCodeVal}; 1158af6ee580SValentin Clement auto byteWidth = this->genConstantOffset(loc, rewriter, width / 8); 1159af6ee580SValentin Clement auto i64Ty = mlir::IntegerType::get(&this->lowerTy().getContext(), 64); 1160af6ee580SValentin Clement auto size = 1161af6ee580SValentin Clement rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, byteWidth, len); 1162af6ee580SValentin Clement return {size, typeCodeVal}; 1163af6ee580SValentin Clement }; 1164af6ee580SValentin Clement auto getKindMap = [&]() -> fir::KindMapping & { 1165af6ee580SValentin Clement return this->lowerTy().getKindMap(); 1166af6ee580SValentin Clement }; 1167af6ee580SValentin Clement // Pointer-like types. 1168af6ee580SValentin Clement if (auto eleTy = fir::dyn_cast_ptrEleTy(boxEleTy)) 1169af6ee580SValentin Clement boxEleTy = eleTy; 1170af6ee580SValentin Clement // Integer types. 1171af6ee580SValentin Clement if (fir::isa_integer(boxEleTy)) { 1172af6ee580SValentin Clement if (auto ty = boxEleTy.dyn_cast<mlir::IntegerType>()) 1173af6ee580SValentin Clement return doInteger(ty.getWidth()); 1174af6ee580SValentin Clement auto ty = boxEleTy.cast<fir::IntegerType>(); 1175af6ee580SValentin Clement return doInteger(getKindMap().getIntegerBitsize(ty.getFKind())); 1176af6ee580SValentin Clement } 1177af6ee580SValentin Clement // Floating point types. 1178af6ee580SValentin Clement if (fir::isa_real(boxEleTy)) { 1179af6ee580SValentin Clement if (auto ty = boxEleTy.dyn_cast<mlir::FloatType>()) 1180af6ee580SValentin Clement return doFloat(ty.getWidth()); 1181af6ee580SValentin Clement auto ty = boxEleTy.cast<fir::RealType>(); 1182af6ee580SValentin Clement return doFloat(getKindMap().getRealBitsize(ty.getFKind())); 1183af6ee580SValentin Clement } 1184af6ee580SValentin Clement // Complex types. 1185af6ee580SValentin Clement if (fir::isa_complex(boxEleTy)) { 1186af6ee580SValentin Clement if (auto ty = boxEleTy.dyn_cast<mlir::ComplexType>()) 1187af6ee580SValentin Clement return doComplex( 1188af6ee580SValentin Clement ty.getElementType().cast<mlir::FloatType>().getWidth()); 1189af6ee580SValentin Clement auto ty = boxEleTy.cast<fir::ComplexType>(); 1190af6ee580SValentin Clement return doComplex(getKindMap().getRealBitsize(ty.getFKind())); 1191af6ee580SValentin Clement } 1192af6ee580SValentin Clement // Character types. 1193af6ee580SValentin Clement if (auto ty = boxEleTy.dyn_cast<fir::CharacterType>()) { 1194af6ee580SValentin Clement auto charWidth = getKindMap().getCharacterBitsize(ty.getFKind()); 1195af6ee580SValentin Clement if (ty.getLen() != fir::CharacterType::unknownLen()) { 1196af6ee580SValentin Clement auto len = this->genConstantOffset(loc, rewriter, ty.getLen()); 1197af6ee580SValentin Clement return doCharacter(charWidth, len); 1198af6ee580SValentin Clement } 1199af6ee580SValentin Clement assert(!lenParams.empty()); 1200af6ee580SValentin Clement return doCharacter(charWidth, lenParams.back()); 1201af6ee580SValentin Clement } 1202af6ee580SValentin Clement // Logical type. 1203af6ee580SValentin Clement if (auto ty = boxEleTy.dyn_cast<fir::LogicalType>()) 1204af6ee580SValentin Clement return doLogical(getKindMap().getLogicalBitsize(ty.getFKind())); 1205af6ee580SValentin Clement // Array types. 1206af6ee580SValentin Clement if (auto seqTy = boxEleTy.dyn_cast<fir::SequenceType>()) 1207af6ee580SValentin Clement return getSizeAndTypeCode(loc, rewriter, seqTy.getEleTy(), lenParams); 1208af6ee580SValentin Clement // Derived-type types. 1209af6ee580SValentin Clement if (boxEleTy.isa<fir::RecordType>()) { 1210af6ee580SValentin Clement auto ptrTy = mlir::LLVM::LLVMPointerType::get( 1211af6ee580SValentin Clement this->lowerTy().convertType(boxEleTy)); 1212af6ee580SValentin Clement auto nullPtr = rewriter.create<mlir::LLVM::NullOp>(loc, ptrTy); 1213af6ee580SValentin Clement auto one = 1214af6ee580SValentin Clement genConstantIndex(loc, this->lowerTy().offsetType(), rewriter, 1); 121530122656SAlex Zinenko auto gep = rewriter.create<mlir::LLVM::GEPOp>(loc, ptrTy, nullPtr, 121630122656SAlex Zinenko mlir::ValueRange{one}); 1217af6ee580SValentin Clement auto eleSize = rewriter.create<mlir::LLVM::PtrToIntOp>( 1218af6ee580SValentin Clement loc, this->lowerTy().indexType(), gep); 1219af6ee580SValentin Clement return {eleSize, 1220af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, fir::derivedToTypeCode())}; 1221af6ee580SValentin Clement } 1222af6ee580SValentin Clement // Reference type. 1223af6ee580SValentin Clement if (fir::isa_ref_type(boxEleTy)) { 1224af6ee580SValentin Clement // FIXME: use the target pointer size rather than sizeof(void*) 1225af6ee580SValentin Clement return {this->genConstantOffset(loc, rewriter, sizeof(void *)), 1226af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, CFI_type_cptr)}; 1227af6ee580SValentin Clement } 1228af6ee580SValentin Clement fir::emitFatalError(loc, "unhandled type in fir.box code generation"); 1229af6ee580SValentin Clement } 1230af6ee580SValentin Clement 1231af6ee580SValentin Clement /// Basic pattern to write a field in the descriptor 1232af6ee580SValentin Clement mlir::Value insertField(mlir::ConversionPatternRewriter &rewriter, 1233af6ee580SValentin Clement mlir::Location loc, mlir::Value dest, 1234af6ee580SValentin Clement ArrayRef<unsigned> fldIndexes, mlir::Value value, 1235af6ee580SValentin Clement bool bitcast = false) const { 1236af6ee580SValentin Clement auto boxTy = dest.getType(); 1237af6ee580SValentin Clement auto fldTy = this->getBoxEleTy(boxTy, fldIndexes); 1238af6ee580SValentin Clement if (bitcast) 1239af6ee580SValentin Clement value = rewriter.create<mlir::LLVM::BitcastOp>(loc, fldTy, value); 1240af6ee580SValentin Clement else 1241af6ee580SValentin Clement value = this->integerCast(loc, rewriter, fldTy, value); 1242af6ee580SValentin Clement SmallVector<mlir::Attribute, 2> attrs; 1243af6ee580SValentin Clement for (auto i : fldIndexes) 1244af6ee580SValentin Clement attrs.push_back(rewriter.getI32IntegerAttr(i)); 1245af6ee580SValentin Clement auto indexesAttr = mlir::ArrayAttr::get(rewriter.getContext(), attrs); 1246af6ee580SValentin Clement return rewriter.create<mlir::LLVM::InsertValueOp>(loc, boxTy, dest, value, 1247af6ee580SValentin Clement indexesAttr); 1248af6ee580SValentin Clement } 1249af6ee580SValentin Clement 1250af6ee580SValentin Clement inline mlir::Value 1251af6ee580SValentin Clement insertBaseAddress(mlir::ConversionPatternRewriter &rewriter, 1252af6ee580SValentin Clement mlir::Location loc, mlir::Value dest, 1253af6ee580SValentin Clement mlir::Value base) const { 12541f551032SValentin Clement return insertField(rewriter, loc, dest, {kAddrPosInBox}, base, 12551f551032SValentin Clement /*bitCast=*/true); 12561f551032SValentin Clement } 12571f551032SValentin Clement 12581f551032SValentin Clement inline mlir::Value insertLowerBound(mlir::ConversionPatternRewriter &rewriter, 12591f551032SValentin Clement mlir::Location loc, mlir::Value dest, 12601f551032SValentin Clement unsigned dim, mlir::Value lb) const { 12611f551032SValentin Clement return insertField(rewriter, loc, dest, 12621f551032SValentin Clement {kDimsPosInBox, dim, kDimLowerBoundPos}, lb); 12631f551032SValentin Clement } 12641f551032SValentin Clement 12651f551032SValentin Clement inline mlir::Value insertExtent(mlir::ConversionPatternRewriter &rewriter, 12661f551032SValentin Clement mlir::Location loc, mlir::Value dest, 12671f551032SValentin Clement unsigned dim, mlir::Value extent) const { 12681f551032SValentin Clement return insertField(rewriter, loc, dest, {kDimsPosInBox, dim, kDimExtentPos}, 12691f551032SValentin Clement extent); 12701f551032SValentin Clement } 12711f551032SValentin Clement 12721f551032SValentin Clement inline mlir::Value insertStride(mlir::ConversionPatternRewriter &rewriter, 12731f551032SValentin Clement mlir::Location loc, mlir::Value dest, 12741f551032SValentin Clement unsigned dim, mlir::Value stride) const { 12751f551032SValentin Clement return insertField(rewriter, loc, dest, {kDimsPosInBox, dim, kDimStridePos}, 12761f551032SValentin Clement stride); 1277af6ee580SValentin Clement } 1278af6ee580SValentin Clement 1279af6ee580SValentin Clement /// Get the address of the type descriptor global variable that was created by 1280af6ee580SValentin Clement /// lowering for derived type \p recType. 1281af6ee580SValentin Clement template <typename BOX> 1282af6ee580SValentin Clement mlir::Value 1283af6ee580SValentin Clement getTypeDescriptor(BOX box, mlir::ConversionPatternRewriter &rewriter, 1284af6ee580SValentin Clement mlir::Location loc, fir::RecordType recType) const { 1285013160f6SJean Perier std::string name = 1286013160f6SJean Perier fir::NameUniquer::getTypeDescriptorName(recType.getName()); 1287af6ee580SValentin Clement auto module = box->template getParentOfType<mlir::ModuleOp>(); 1288af6ee580SValentin Clement if (auto global = module.template lookupSymbol<fir::GlobalOp>(name)) { 1289af6ee580SValentin Clement auto ty = mlir::LLVM::LLVMPointerType::get( 1290af6ee580SValentin Clement this->lowerTy().convertType(global.getType())); 1291af6ee580SValentin Clement return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty, 1292feeee78aSJacques Pienaar global.getSymName()); 1293af6ee580SValentin Clement } 1294af6ee580SValentin Clement if (auto global = 1295af6ee580SValentin Clement module.template lookupSymbol<mlir::LLVM::GlobalOp>(name)) { 1296af6ee580SValentin Clement // The global may have already been translated to LLVM. 1297af6ee580SValentin Clement auto ty = mlir::LLVM::LLVMPointerType::get(global.getType()); 1298af6ee580SValentin Clement return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty, 1299feeee78aSJacques Pienaar global.getSymName()); 1300af6ee580SValentin Clement } 13017dd7ccd2SJean Perier // Type info derived types do not have type descriptors since they are the 13027dd7ccd2SJean Perier // types defining type descriptors. 1303013160f6SJean Perier if (!this->options.ignoreMissingTypeDescriptors && 1304013160f6SJean Perier !fir::NameUniquer::belongsToModule( 1305013160f6SJean Perier name, Fortran::semantics::typeInfoBuiltinModule)) 1306013160f6SJean Perier fir::emitFatalError( 1307013160f6SJean Perier loc, "runtime derived type info descriptor was not generated"); 13085bde97b1SJean Perier return rewriter.create<mlir::LLVM::NullOp>( 13095bde97b1SJean Perier loc, ::getVoidPtrType(box.getContext())); 13107dd7ccd2SJean Perier } 1311af6ee580SValentin Clement 1312af6ee580SValentin Clement template <typename BOX> 1313af6ee580SValentin Clement std::tuple<fir::BoxType, mlir::Value, mlir::Value> 1314af6ee580SValentin Clement consDescriptorPrefix(BOX box, mlir::ConversionPatternRewriter &rewriter, 1315af6ee580SValentin Clement unsigned rank, mlir::ValueRange lenParams) const { 1316af6ee580SValentin Clement auto loc = box.getLoc(); 1317af6ee580SValentin Clement auto boxTy = box.getType().template dyn_cast<fir::BoxType>(); 1318af6ee580SValentin Clement auto convTy = this->lowerTy().convertBoxType(boxTy, rank); 1319af6ee580SValentin Clement auto llvmBoxPtrTy = convTy.template cast<mlir::LLVM::LLVMPointerType>(); 1320af6ee580SValentin Clement auto llvmBoxTy = llvmBoxPtrTy.getElementType(); 1321af6ee580SValentin Clement mlir::Value descriptor = 1322af6ee580SValentin Clement rewriter.create<mlir::LLVM::UndefOp>(loc, llvmBoxTy); 1323af6ee580SValentin Clement 1324af6ee580SValentin Clement llvm::SmallVector<mlir::Value> typeparams = lenParams; 1325af6ee580SValentin Clement if constexpr (!std::is_same_v<BOX, fir::EmboxOp>) { 1326af6ee580SValentin Clement if (!box.substr().empty() && fir::hasDynamicSize(boxTy.getEleTy())) 1327af6ee580SValentin Clement typeparams.push_back(box.substr()[1]); 1328af6ee580SValentin Clement } 1329af6ee580SValentin Clement 1330af6ee580SValentin Clement // Write each of the fields with the appropriate values 1331af6ee580SValentin Clement auto [eleSize, cfiTy] = 1332af6ee580SValentin Clement getSizeAndTypeCode(loc, rewriter, boxTy.getEleTy(), typeparams); 1333af6ee580SValentin Clement descriptor = 1334af6ee580SValentin Clement insertField(rewriter, loc, descriptor, {kElemLenPosInBox}, eleSize); 1335af6ee580SValentin Clement descriptor = insertField(rewriter, loc, descriptor, {kVersionPosInBox}, 1336af6ee580SValentin Clement this->genI32Constant(loc, rewriter, CFI_VERSION)); 1337af6ee580SValentin Clement descriptor = insertField(rewriter, loc, descriptor, {kRankPosInBox}, 1338af6ee580SValentin Clement this->genI32Constant(loc, rewriter, rank)); 1339af6ee580SValentin Clement descriptor = insertField(rewriter, loc, descriptor, {kTypePosInBox}, cfiTy); 1340af6ee580SValentin Clement descriptor = 1341af6ee580SValentin Clement insertField(rewriter, loc, descriptor, {kAttributePosInBox}, 1342af6ee580SValentin Clement this->genI32Constant(loc, rewriter, getCFIAttr(boxTy))); 1343af6ee580SValentin Clement const bool hasAddendum = isDerivedType(boxTy); 1344af6ee580SValentin Clement descriptor = 1345af6ee580SValentin Clement insertField(rewriter, loc, descriptor, {kF18AddendumPosInBox}, 1346af6ee580SValentin Clement this->genI32Constant(loc, rewriter, hasAddendum ? 1 : 0)); 1347af6ee580SValentin Clement 1348af6ee580SValentin Clement if (hasAddendum) { 1349af6ee580SValentin Clement auto isArray = 1350af6ee580SValentin Clement fir::dyn_cast_ptrOrBoxEleTy(boxTy).template isa<fir::SequenceType>(); 1351af6ee580SValentin Clement unsigned typeDescFieldId = isArray ? kOptTypePtrPosInBox : kDimsPosInBox; 1352af6ee580SValentin Clement auto typeDesc = 1353af6ee580SValentin Clement getTypeDescriptor(box, rewriter, loc, unwrapIfDerived(boxTy)); 1354af6ee580SValentin Clement descriptor = 1355af6ee580SValentin Clement insertField(rewriter, loc, descriptor, {typeDescFieldId}, typeDesc, 1356af6ee580SValentin Clement /*bitCast=*/true); 1357af6ee580SValentin Clement } 1358af6ee580SValentin Clement 1359af6ee580SValentin Clement return {boxTy, descriptor, eleSize}; 1360af6ee580SValentin Clement } 1361af6ee580SValentin Clement 13621f551032SValentin Clement /// Compute the base address of a substring given the base address of a scalar 13631f551032SValentin Clement /// string and the zero based string lower bound. 13641f551032SValentin Clement mlir::Value shiftSubstringBase(mlir::ConversionPatternRewriter &rewriter, 13651f551032SValentin Clement mlir::Location loc, mlir::Value base, 13661f551032SValentin Clement mlir::Value lowerBound) const { 13671f551032SValentin Clement llvm::SmallVector<mlir::Value> gepOperands; 13681f551032SValentin Clement auto baseType = 13691f551032SValentin Clement base.getType().cast<mlir::LLVM::LLVMPointerType>().getElementType(); 13701f551032SValentin Clement if (baseType.isa<mlir::LLVM::LLVMArrayType>()) { 13711f551032SValentin Clement auto idxTy = this->lowerTy().indexType(); 13721f551032SValentin Clement mlir::Value zero = genConstantIndex(loc, idxTy, rewriter, 0); 13731f551032SValentin Clement gepOperands.push_back(zero); 13741f551032SValentin Clement } 13751f551032SValentin Clement gepOperands.push_back(lowerBound); 13761f551032SValentin Clement return this->genGEP(loc, base.getType(), rewriter, base, gepOperands); 13771f551032SValentin Clement } 13781f551032SValentin Clement 1379af6ee580SValentin Clement /// If the embox is not in a globalOp body, allocate storage for the box; 1380af6ee580SValentin Clement /// store the value inside and return the generated alloca. Return the input 1381af6ee580SValentin Clement /// value otherwise. 1382af6ee580SValentin Clement mlir::Value 1383af6ee580SValentin Clement placeInMemoryIfNotGlobalInit(mlir::ConversionPatternRewriter &rewriter, 1384af6ee580SValentin Clement mlir::Location loc, mlir::Value boxValue) const { 1385af6ee580SValentin Clement auto *thisBlock = rewriter.getInsertionBlock(); 1386af6ee580SValentin Clement if (thisBlock && mlir::isa<mlir::LLVM::GlobalOp>(thisBlock->getParentOp())) 1387af6ee580SValentin Clement return boxValue; 1388af6ee580SValentin Clement auto boxPtrTy = mlir::LLVM::LLVMPointerType::get(boxValue.getType()); 1389af6ee580SValentin Clement auto alloca = genAllocaWithType(loc, boxPtrTy, defaultAlign, rewriter); 1390af6ee580SValentin Clement rewriter.create<mlir::LLVM::StoreOp>(loc, boxValue, alloca); 1391af6ee580SValentin Clement return alloca; 1392af6ee580SValentin Clement } 1393af6ee580SValentin Clement }; 1394af6ee580SValentin Clement 13951f551032SValentin Clement /// Compute the extent of a triplet slice (lb:ub:step). 13961f551032SValentin Clement static mlir::Value 13971f551032SValentin Clement computeTripletExtent(mlir::ConversionPatternRewriter &rewriter, 13981f551032SValentin Clement mlir::Location loc, mlir::Value lb, mlir::Value ub, 13991f551032SValentin Clement mlir::Value step, mlir::Value zero, mlir::Type type) { 14001f551032SValentin Clement mlir::Value extent = rewriter.create<mlir::LLVM::SubOp>(loc, type, ub, lb); 14011f551032SValentin Clement extent = rewriter.create<mlir::LLVM::AddOp>(loc, type, extent, step); 14021f551032SValentin Clement extent = rewriter.create<mlir::LLVM::SDivOp>(loc, type, extent, step); 14031f551032SValentin Clement // If the resulting extent is negative (`ub-lb` and `step` have different 14041f551032SValentin Clement // signs), zero must be returned instead. 14051f551032SValentin Clement auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 14061f551032SValentin Clement loc, mlir::LLVM::ICmpPredicate::sgt, extent, zero); 14071f551032SValentin Clement return rewriter.create<mlir::LLVM::SelectOp>(loc, cmp, extent, zero); 14081f551032SValentin Clement } 14091f551032SValentin Clement 1410af6ee580SValentin Clement /// Create a generic box on a memory reference. This conversions lowers the 1411af6ee580SValentin Clement /// abstract box to the appropriate, initialized descriptor. 1412af6ee580SValentin Clement struct EmboxOpConversion : public EmboxCommonConversion<fir::EmboxOp> { 1413af6ee580SValentin Clement using EmboxCommonConversion::EmboxCommonConversion; 1414af6ee580SValentin Clement 1415af6ee580SValentin Clement mlir::LogicalResult 1416af6ee580SValentin Clement matchAndRewrite(fir::EmboxOp embox, OpAdaptor adaptor, 1417af6ee580SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 1418af6ee580SValentin Clement assert(!embox.getShape() && "There should be no dims on this embox op"); 1419af6ee580SValentin Clement auto [boxTy, dest, eleSize] = 1420af6ee580SValentin Clement consDescriptorPrefix(embox, rewriter, /*rank=*/0, 1421af6ee580SValentin Clement /*lenParams=*/adaptor.getOperands().drop_front(1)); 1422af6ee580SValentin Clement dest = insertBaseAddress(rewriter, embox.getLoc(), dest, 1423af6ee580SValentin Clement adaptor.getOperands()[0]); 14247ce8c6fcSKiran Chandramohan if (isDerivedTypeWithLenParams(boxTy)) { 14257ce8c6fcSKiran Chandramohan TODO(embox.getLoc(), 14267ce8c6fcSKiran Chandramohan "fir.embox codegen of derived with length parameters"); 14277ce8c6fcSKiran Chandramohan return failure(); 14287ce8c6fcSKiran Chandramohan } 1429af6ee580SValentin Clement auto result = placeInMemoryIfNotGlobalInit(rewriter, embox.getLoc(), dest); 1430af6ee580SValentin Clement rewriter.replaceOp(embox, result); 1431af6ee580SValentin Clement return success(); 1432af6ee580SValentin Clement } 1433af6ee580SValentin Clement }; 1434af6ee580SValentin Clement 14351f551032SValentin Clement /// Create a generic box on a memory reference. 14361f551032SValentin Clement struct XEmboxOpConversion : public EmboxCommonConversion<fir::cg::XEmboxOp> { 14371f551032SValentin Clement using EmboxCommonConversion::EmboxCommonConversion; 14381f551032SValentin Clement 14391f551032SValentin Clement mlir::LogicalResult 14401f551032SValentin Clement matchAndRewrite(fir::cg::XEmboxOp xbox, OpAdaptor adaptor, 14411f551032SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 14421f551032SValentin Clement auto [boxTy, dest, eleSize] = consDescriptorPrefix( 14431f551032SValentin Clement xbox, rewriter, xbox.getOutRank(), 14441f551032SValentin Clement adaptor.getOperands().drop_front(xbox.lenParamOffset())); 14451f551032SValentin Clement // Generate the triples in the dims field of the descriptor 14461f551032SValentin Clement mlir::ValueRange operands = adaptor.getOperands(); 14471f551032SValentin Clement auto i64Ty = mlir::IntegerType::get(xbox.getContext(), 64); 14481f551032SValentin Clement mlir::Value base = operands[0]; 14491f551032SValentin Clement assert(!xbox.shape().empty() && "must have a shape"); 14501f551032SValentin Clement unsigned shapeOffset = xbox.shapeOffset(); 14511f551032SValentin Clement bool hasShift = !xbox.shift().empty(); 14521f551032SValentin Clement unsigned shiftOffset = xbox.shiftOffset(); 14531f551032SValentin Clement bool hasSlice = !xbox.slice().empty(); 14541f551032SValentin Clement unsigned sliceOffset = xbox.sliceOffset(); 14551f551032SValentin Clement mlir::Location loc = xbox.getLoc(); 14561f551032SValentin Clement mlir::Value zero = genConstantIndex(loc, i64Ty, rewriter, 0); 14571f551032SValentin Clement mlir::Value one = genConstantIndex(loc, i64Ty, rewriter, 1); 14581f551032SValentin Clement mlir::Value prevDim = integerCast(loc, rewriter, i64Ty, eleSize); 14591f551032SValentin Clement mlir::Value prevPtrOff = one; 14601f551032SValentin Clement mlir::Type eleTy = boxTy.getEleTy(); 14611f551032SValentin Clement const unsigned rank = xbox.getRank(); 14621f551032SValentin Clement llvm::SmallVector<mlir::Value> gepArgs; 14631f551032SValentin Clement unsigned constRows = 0; 14641f551032SValentin Clement mlir::Value ptrOffset = zero; 14651f551032SValentin Clement if (auto memEleTy = fir::dyn_cast_ptrEleTy(xbox.memref().getType())) 14661f551032SValentin Clement if (auto seqTy = memEleTy.dyn_cast<fir::SequenceType>()) { 14671f551032SValentin Clement mlir::Type seqEleTy = seqTy.getEleTy(); 14681f551032SValentin Clement // Adjust the element scaling factor if the element is a dependent type. 14691f551032SValentin Clement if (fir::hasDynamicSize(seqEleTy)) { 14701f551032SValentin Clement if (fir::isa_char(seqEleTy)) { 14711f551032SValentin Clement assert(xbox.lenParams().size() == 1); 14721f551032SValentin Clement prevPtrOff = integerCast(loc, rewriter, i64Ty, 14731f551032SValentin Clement operands[xbox.lenParamOffset()]); 14741f551032SValentin Clement } else if (seqEleTy.isa<fir::RecordType>()) { 14751f551032SValentin Clement TODO(loc, "generate call to calculate size of PDT"); 14761f551032SValentin Clement } else { 14771f551032SValentin Clement return rewriter.notifyMatchFailure(xbox, "unexpected dynamic type"); 14781f551032SValentin Clement } 14791f551032SValentin Clement } else { 14801f551032SValentin Clement constRows = seqTy.getConstantRows(); 14811f551032SValentin Clement } 14821f551032SValentin Clement } 14831f551032SValentin Clement 14841f551032SValentin Clement bool hasSubcomp = !xbox.subcomponent().empty(); 14851f551032SValentin Clement mlir::Value stepExpr; 14861f551032SValentin Clement if (hasSubcomp) { 14871f551032SValentin Clement // We have a subcomponent. The step value needs to be the number of 14881f551032SValentin Clement // bytes per element (which is a derived type). 14891f551032SValentin Clement mlir::Type ty0 = base.getType(); 14901f551032SValentin Clement [[maybe_unused]] auto ptrTy = ty0.dyn_cast<mlir::LLVM::LLVMPointerType>(); 14911f551032SValentin Clement assert(ptrTy && "expected pointer type"); 14921f551032SValentin Clement mlir::Type memEleTy = fir::dyn_cast_ptrEleTy(xbox.memref().getType()); 14931f551032SValentin Clement assert(memEleTy && "expected fir pointer type"); 14941f551032SValentin Clement auto seqTy = memEleTy.dyn_cast<fir::SequenceType>(); 14951f551032SValentin Clement assert(seqTy && "expected sequence type"); 14961f551032SValentin Clement mlir::Type seqEleTy = seqTy.getEleTy(); 14971f551032SValentin Clement auto eleTy = mlir::LLVM::LLVMPointerType::get(convertType(seqEleTy)); 14981f551032SValentin Clement stepExpr = computeDerivedTypeSize(loc, eleTy, i64Ty, rewriter); 14991f551032SValentin Clement } 15001f551032SValentin Clement 15011f551032SValentin Clement // Process the array subspace arguments (shape, shift, etc.), if any, 15021f551032SValentin Clement // translating everything to values in the descriptor wherever the entity 15031f551032SValentin Clement // has a dynamic array dimension. 15041f551032SValentin Clement for (unsigned di = 0, descIdx = 0; di < rank; ++di) { 15051f551032SValentin Clement mlir::Value extent = operands[shapeOffset]; 15061f551032SValentin Clement mlir::Value outerExtent = extent; 15071f551032SValentin Clement bool skipNext = false; 15081f551032SValentin Clement if (hasSlice) { 15091f551032SValentin Clement mlir::Value off = operands[sliceOffset]; 15101f551032SValentin Clement mlir::Value adj = one; 15111f551032SValentin Clement if (hasShift) 15121f551032SValentin Clement adj = operands[shiftOffset]; 15131f551032SValentin Clement auto ao = rewriter.create<mlir::LLVM::SubOp>(loc, i64Ty, off, adj); 15141f551032SValentin Clement if (constRows > 0) { 15151f551032SValentin Clement gepArgs.push_back(ao); 15161f551032SValentin Clement --constRows; 15171f551032SValentin Clement } else { 15181f551032SValentin Clement auto dimOff = 15191f551032SValentin Clement rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, ao, prevPtrOff); 15201f551032SValentin Clement ptrOffset = 15211f551032SValentin Clement rewriter.create<mlir::LLVM::AddOp>(loc, i64Ty, dimOff, ptrOffset); 15221f551032SValentin Clement } 15231f551032SValentin Clement if (mlir::isa_and_nonnull<fir::UndefOp>( 15241f551032SValentin Clement xbox.slice()[3 * di + 1].getDefiningOp())) { 15251f551032SValentin Clement // This dimension contains a scalar expression in the array slice op. 15261f551032SValentin Clement // The dimension is loop invariant, will be dropped, and will not 15271f551032SValentin Clement // appear in the descriptor. 15281f551032SValentin Clement skipNext = true; 15291f551032SValentin Clement } 15301f551032SValentin Clement } 15311f551032SValentin Clement if (!skipNext) { 15321f551032SValentin Clement // store lower bound (normally 0) 15331f551032SValentin Clement mlir::Value lb = zero; 15341f551032SValentin Clement if (eleTy.isa<fir::PointerType>() || eleTy.isa<fir::HeapType>()) { 15351f551032SValentin Clement lb = one; 15361f551032SValentin Clement if (hasShift) 15371f551032SValentin Clement lb = operands[shiftOffset]; 15381f551032SValentin Clement } 15391f551032SValentin Clement dest = insertLowerBound(rewriter, loc, dest, descIdx, lb); 15401f551032SValentin Clement 15411f551032SValentin Clement // store extent 15421f551032SValentin Clement if (hasSlice) 15431f551032SValentin Clement extent = computeTripletExtent(rewriter, loc, operands[sliceOffset], 15441f551032SValentin Clement operands[sliceOffset + 1], 15451f551032SValentin Clement operands[sliceOffset + 2], zero, i64Ty); 15461f551032SValentin Clement dest = insertExtent(rewriter, loc, dest, descIdx, extent); 15471f551032SValentin Clement 15481f551032SValentin Clement // store step (scaled by shaped extent) 15491f551032SValentin Clement 15501f551032SValentin Clement mlir::Value step = hasSubcomp ? stepExpr : prevDim; 15511f551032SValentin Clement if (hasSlice) 15521f551032SValentin Clement step = rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, step, 15531f551032SValentin Clement operands[sliceOffset + 2]); 15541f551032SValentin Clement dest = insertStride(rewriter, loc, dest, descIdx, step); 15551f551032SValentin Clement ++descIdx; 15561f551032SValentin Clement } 15571f551032SValentin Clement 15581f551032SValentin Clement // compute the stride and offset for the next natural dimension 15591f551032SValentin Clement prevDim = 15601f551032SValentin Clement rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, prevDim, outerExtent); 15611f551032SValentin Clement if (constRows == 0) 15621f551032SValentin Clement prevPtrOff = rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, prevPtrOff, 15631f551032SValentin Clement outerExtent); 15641f551032SValentin Clement 15651f551032SValentin Clement // increment iterators 15661f551032SValentin Clement ++shapeOffset; 15671f551032SValentin Clement if (hasShift) 15681f551032SValentin Clement ++shiftOffset; 15691f551032SValentin Clement if (hasSlice) 15701f551032SValentin Clement sliceOffset += 3; 15711f551032SValentin Clement } 15721f551032SValentin Clement if (hasSlice || hasSubcomp || !xbox.substr().empty()) { 157330122656SAlex Zinenko llvm::SmallVector<mlir::Value> args = {ptrOffset}; 15741f551032SValentin Clement args.append(gepArgs.rbegin(), gepArgs.rend()); 15751f551032SValentin Clement if (hasSubcomp) { 15761f551032SValentin Clement // For each field in the path add the offset to base via the args list. 15771f551032SValentin Clement // In the most general case, some offsets must be computed since 15781f551032SValentin Clement // they are not be known until runtime. 15791f551032SValentin Clement if (fir::hasDynamicSize(fir::unwrapSequenceType( 15801f551032SValentin Clement fir::unwrapPassByRefType(xbox.memref().getType())))) 15811f551032SValentin Clement TODO(loc, "fir.embox codegen dynamic size component in derived type"); 15821f551032SValentin Clement args.append(operands.begin() + xbox.subcomponentOffset(), 15831f551032SValentin Clement operands.begin() + xbox.subcomponentOffset() + 15841f551032SValentin Clement xbox.subcomponent().size()); 15851f551032SValentin Clement } 158630122656SAlex Zinenko base = 158730122656SAlex Zinenko rewriter.create<mlir::LLVM::GEPOp>(loc, base.getType(), base, args); 15881f551032SValentin Clement if (!xbox.substr().empty()) 15891f551032SValentin Clement base = shiftSubstringBase(rewriter, loc, base, 15901f551032SValentin Clement operands[xbox.substrOffset()]); 15911f551032SValentin Clement } 15921f551032SValentin Clement dest = insertBaseAddress(rewriter, loc, dest, base); 15931f551032SValentin Clement if (isDerivedTypeWithLenParams(boxTy)) 15941f551032SValentin Clement TODO(loc, "fir.embox codegen of derived with length parameters"); 15951f551032SValentin Clement 15961f551032SValentin Clement mlir::Value result = placeInMemoryIfNotGlobalInit(rewriter, loc, dest); 15971f551032SValentin Clement rewriter.replaceOp(xbox, result); 15981f551032SValentin Clement return success(); 15991f551032SValentin Clement } 16001f551032SValentin Clement }; 16011f551032SValentin Clement 1602fa517555SKiran Chandramohan /// Create a new box given a box reference. 1603fa517555SKiran Chandramohan struct XReboxOpConversion : public EmboxCommonConversion<fir::cg::XReboxOp> { 1604fa517555SKiran Chandramohan using EmboxCommonConversion::EmboxCommonConversion; 1605fa517555SKiran Chandramohan 1606fa517555SKiran Chandramohan mlir::LogicalResult 1607fa517555SKiran Chandramohan matchAndRewrite(fir::cg::XReboxOp rebox, OpAdaptor adaptor, 1608fa517555SKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 1609fa517555SKiran Chandramohan mlir::Location loc = rebox.getLoc(); 1610fa517555SKiran Chandramohan mlir::Type idxTy = lowerTy().indexType(); 1611fa517555SKiran Chandramohan mlir::Value loweredBox = adaptor.getOperands()[0]; 1612fa517555SKiran Chandramohan mlir::ValueRange operands = adaptor.getOperands(); 1613fa517555SKiran Chandramohan 1614fa517555SKiran Chandramohan // Create new descriptor and fill its non-shape related data. 1615fa517555SKiran Chandramohan llvm::SmallVector<mlir::Value, 2> lenParams; 1616fa517555SKiran Chandramohan mlir::Type inputEleTy = getInputEleTy(rebox); 1617fa517555SKiran Chandramohan if (auto charTy = inputEleTy.dyn_cast<fir::CharacterType>()) { 1618fa517555SKiran Chandramohan mlir::Value len = 1619fa517555SKiran Chandramohan loadElementSizeFromBox(loc, idxTy, loweredBox, rewriter); 1620fa517555SKiran Chandramohan if (charTy.getFKind() != 1) { 1621fa517555SKiran Chandramohan mlir::Value width = 1622fa517555SKiran Chandramohan genConstantIndex(loc, idxTy, rewriter, charTy.getFKind()); 1623fa517555SKiran Chandramohan len = rewriter.create<mlir::LLVM::SDivOp>(loc, idxTy, len, width); 1624fa517555SKiran Chandramohan } 1625fa517555SKiran Chandramohan lenParams.emplace_back(len); 1626fa517555SKiran Chandramohan } else if (auto recTy = inputEleTy.dyn_cast<fir::RecordType>()) { 1627fa517555SKiran Chandramohan if (recTy.getNumLenParams() != 0) 1628fa517555SKiran Chandramohan TODO(loc, "reboxing descriptor of derived type with length parameters"); 1629fa517555SKiran Chandramohan } 1630fa517555SKiran Chandramohan auto [boxTy, dest, eleSize] = 1631fa517555SKiran Chandramohan consDescriptorPrefix(rebox, rewriter, rebox.getOutRank(), lenParams); 1632fa517555SKiran Chandramohan 1633fa517555SKiran Chandramohan // Read input extents, strides, and base address 1634fa517555SKiran Chandramohan llvm::SmallVector<mlir::Value> inputExtents; 1635fa517555SKiran Chandramohan llvm::SmallVector<mlir::Value> inputStrides; 1636fa517555SKiran Chandramohan const unsigned inputRank = rebox.getRank(); 1637fa517555SKiran Chandramohan for (unsigned i = 0; i < inputRank; ++i) { 1638fa517555SKiran Chandramohan mlir::Value dim = genConstantIndex(loc, idxTy, rewriter, i); 1639fa517555SKiran Chandramohan SmallVector<mlir::Value, 3> dimInfo = 1640fa517555SKiran Chandramohan getDimsFromBox(loc, {idxTy, idxTy, idxTy}, loweredBox, dim, rewriter); 1641fa517555SKiran Chandramohan inputExtents.emplace_back(dimInfo[1]); 1642fa517555SKiran Chandramohan inputStrides.emplace_back(dimInfo[2]); 1643fa517555SKiran Chandramohan } 1644fa517555SKiran Chandramohan 1645fa517555SKiran Chandramohan mlir::Type baseTy = getBaseAddrTypeFromBox(loweredBox.getType()); 1646fa517555SKiran Chandramohan mlir::Value baseAddr = 1647fa517555SKiran Chandramohan loadBaseAddrFromBox(loc, baseTy, loweredBox, rewriter); 1648fa517555SKiran Chandramohan 1649fa517555SKiran Chandramohan if (!rebox.slice().empty() || !rebox.subcomponent().empty()) 1650fa517555SKiran Chandramohan return sliceBox(rebox, dest, baseAddr, inputExtents, inputStrides, 1651fa517555SKiran Chandramohan operands, rewriter); 1652fa517555SKiran Chandramohan return reshapeBox(rebox, dest, baseAddr, inputExtents, inputStrides, 1653fa517555SKiran Chandramohan operands, rewriter); 1654fa517555SKiran Chandramohan } 1655fa517555SKiran Chandramohan 1656fa517555SKiran Chandramohan private: 1657fa517555SKiran Chandramohan /// Write resulting shape and base address in descriptor, and replace rebox 1658fa517555SKiran Chandramohan /// op. 1659fa517555SKiran Chandramohan mlir::LogicalResult 1660fa517555SKiran Chandramohan finalizeRebox(fir::cg::XReboxOp rebox, mlir::Value dest, mlir::Value base, 1661fa517555SKiran Chandramohan mlir::ValueRange lbounds, mlir::ValueRange extents, 1662fa517555SKiran Chandramohan mlir::ValueRange strides, 1663fa517555SKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const { 1664fa517555SKiran Chandramohan mlir::Location loc = rebox.getLoc(); 1665fa517555SKiran Chandramohan mlir::Value one = genConstantIndex(loc, lowerTy().indexType(), rewriter, 1); 1666fa517555SKiran Chandramohan for (auto iter : llvm::enumerate(llvm::zip(extents, strides))) { 1667fa517555SKiran Chandramohan unsigned dim = iter.index(); 1668fa517555SKiran Chandramohan mlir::Value lb = lbounds.empty() ? one : lbounds[dim]; 1669fa517555SKiran Chandramohan dest = insertLowerBound(rewriter, loc, dest, dim, lb); 1670fa517555SKiran Chandramohan dest = insertExtent(rewriter, loc, dest, dim, std::get<0>(iter.value())); 1671fa517555SKiran Chandramohan dest = insertStride(rewriter, loc, dest, dim, std::get<1>(iter.value())); 1672fa517555SKiran Chandramohan } 1673fa517555SKiran Chandramohan dest = insertBaseAddress(rewriter, loc, dest, base); 1674fa517555SKiran Chandramohan mlir::Value result = 1675fa517555SKiran Chandramohan placeInMemoryIfNotGlobalInit(rewriter, rebox.getLoc(), dest); 1676fa517555SKiran Chandramohan rewriter.replaceOp(rebox, result); 1677fa517555SKiran Chandramohan return success(); 1678fa517555SKiran Chandramohan } 1679fa517555SKiran Chandramohan 1680fa517555SKiran Chandramohan // Apply slice given the base address, extents and strides of the input box. 1681fa517555SKiran Chandramohan mlir::LogicalResult 1682fa517555SKiran Chandramohan sliceBox(fir::cg::XReboxOp rebox, mlir::Value dest, mlir::Value base, 1683fa517555SKiran Chandramohan mlir::ValueRange inputExtents, mlir::ValueRange inputStrides, 1684fa517555SKiran Chandramohan mlir::ValueRange operands, 1685fa517555SKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const { 1686fa517555SKiran Chandramohan mlir::Location loc = rebox.getLoc(); 1687fa517555SKiran Chandramohan mlir::Type voidPtrTy = ::getVoidPtrType(rebox.getContext()); 1688fa517555SKiran Chandramohan mlir::Type idxTy = lowerTy().indexType(); 1689fa517555SKiran Chandramohan mlir::Value zero = genConstantIndex(loc, idxTy, rewriter, 0); 1690fa517555SKiran Chandramohan // Apply subcomponent and substring shift on base address. 1691fa517555SKiran Chandramohan if (!rebox.subcomponent().empty() || !rebox.substr().empty()) { 1692fa517555SKiran Chandramohan // Cast to inputEleTy* so that a GEP can be used. 1693fa517555SKiran Chandramohan mlir::Type inputEleTy = getInputEleTy(rebox); 1694fa517555SKiran Chandramohan auto llvmElePtrTy = 1695fa517555SKiran Chandramohan mlir::LLVM::LLVMPointerType::get(convertType(inputEleTy)); 1696fa517555SKiran Chandramohan base = rewriter.create<mlir::LLVM::BitcastOp>(loc, llvmElePtrTy, base); 1697fa517555SKiran Chandramohan 1698fa517555SKiran Chandramohan if (!rebox.subcomponent().empty()) { 1699fa517555SKiran Chandramohan llvm::SmallVector<mlir::Value> gepOperands = {zero}; 1700fa517555SKiran Chandramohan for (unsigned i = 0; i < rebox.subcomponent().size(); ++i) 1701fa517555SKiran Chandramohan gepOperands.push_back(operands[rebox.subcomponentOffset() + i]); 1702fa517555SKiran Chandramohan base = genGEP(loc, llvmElePtrTy, rewriter, base, gepOperands); 1703fa517555SKiran Chandramohan } 1704fa517555SKiran Chandramohan if (!rebox.substr().empty()) 1705fa517555SKiran Chandramohan base = shiftSubstringBase(rewriter, loc, base, 1706fa517555SKiran Chandramohan operands[rebox.substrOffset()]); 1707fa517555SKiran Chandramohan } 1708fa517555SKiran Chandramohan 1709fa517555SKiran Chandramohan if (rebox.slice().empty()) 1710fa517555SKiran Chandramohan // The array section is of the form array[%component][substring], keep 1711fa517555SKiran Chandramohan // the input array extents and strides. 1712fa517555SKiran Chandramohan return finalizeRebox(rebox, dest, base, /*lbounds*/ llvm::None, 1713fa517555SKiran Chandramohan inputExtents, inputStrides, rewriter); 1714fa517555SKiran Chandramohan 1715fa517555SKiran Chandramohan // Strides from the fir.box are in bytes. 1716fa517555SKiran Chandramohan base = rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, base); 1717fa517555SKiran Chandramohan 1718fa517555SKiran Chandramohan // The slice is of the form array(i:j:k)[%component]. Compute new extents 1719fa517555SKiran Chandramohan // and strides. 1720fa517555SKiran Chandramohan llvm::SmallVector<mlir::Value> slicedExtents; 1721fa517555SKiran Chandramohan llvm::SmallVector<mlir::Value> slicedStrides; 1722fa517555SKiran Chandramohan mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1); 1723fa517555SKiran Chandramohan const bool sliceHasOrigins = !rebox.shift().empty(); 1724fa517555SKiran Chandramohan unsigned sliceOps = rebox.sliceOffset(); 1725fa517555SKiran Chandramohan unsigned shiftOps = rebox.shiftOffset(); 1726fa517555SKiran Chandramohan auto strideOps = inputStrides.begin(); 1727fa517555SKiran Chandramohan const unsigned inputRank = inputStrides.size(); 1728fa517555SKiran Chandramohan for (unsigned i = 0; i < inputRank; 1729fa517555SKiran Chandramohan ++i, ++strideOps, ++shiftOps, sliceOps += 3) { 1730fa517555SKiran Chandramohan mlir::Value sliceLb = 1731fa517555SKiran Chandramohan integerCast(loc, rewriter, idxTy, operands[sliceOps]); 1732fa517555SKiran Chandramohan mlir::Value inputStride = *strideOps; // already idxTy 1733fa517555SKiran Chandramohan // Apply origin shift: base += (lb-shift)*input_stride 1734fa517555SKiran Chandramohan mlir::Value sliceOrigin = 1735fa517555SKiran Chandramohan sliceHasOrigins 1736fa517555SKiran Chandramohan ? integerCast(loc, rewriter, idxTy, operands[shiftOps]) 1737fa517555SKiran Chandramohan : one; 1738fa517555SKiran Chandramohan mlir::Value diff = 1739fa517555SKiran Chandramohan rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, sliceLb, sliceOrigin); 1740fa517555SKiran Chandramohan mlir::Value offset = 1741fa517555SKiran Chandramohan rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, inputStride); 1742fa517555SKiran Chandramohan base = genGEP(loc, voidPtrTy, rewriter, base, offset); 1743fa517555SKiran Chandramohan // Apply upper bound and step if this is a triplet. Otherwise, the 1744fa517555SKiran Chandramohan // dimension is dropped and no extents/strides are computed. 1745fa517555SKiran Chandramohan mlir::Value upper = operands[sliceOps + 1]; 1746fa517555SKiran Chandramohan const bool isTripletSlice = 1747fa517555SKiran Chandramohan !mlir::isa_and_nonnull<mlir::LLVM::UndefOp>(upper.getDefiningOp()); 1748fa517555SKiran Chandramohan if (isTripletSlice) { 1749fa517555SKiran Chandramohan mlir::Value step = 1750fa517555SKiran Chandramohan integerCast(loc, rewriter, idxTy, operands[sliceOps + 2]); 1751fa517555SKiran Chandramohan // extent = ub-lb+step/step 1752fa517555SKiran Chandramohan mlir::Value sliceUb = integerCast(loc, rewriter, idxTy, upper); 1753fa517555SKiran Chandramohan mlir::Value extent = computeTripletExtent(rewriter, loc, sliceLb, 1754fa517555SKiran Chandramohan sliceUb, step, zero, idxTy); 1755fa517555SKiran Chandramohan slicedExtents.emplace_back(extent); 1756fa517555SKiran Chandramohan // stride = step*input_stride 1757fa517555SKiran Chandramohan mlir::Value stride = 1758fa517555SKiran Chandramohan rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, step, inputStride); 1759fa517555SKiran Chandramohan slicedStrides.emplace_back(stride); 1760fa517555SKiran Chandramohan } 1761fa517555SKiran Chandramohan } 1762fa517555SKiran Chandramohan return finalizeRebox(rebox, dest, base, /*lbounds*/ llvm::None, 1763fa517555SKiran Chandramohan slicedExtents, slicedStrides, rewriter); 1764fa517555SKiran Chandramohan } 1765fa517555SKiran Chandramohan 1766fa517555SKiran Chandramohan /// Apply a new shape to the data described by a box given the base address, 1767fa517555SKiran Chandramohan /// extents and strides of the box. 1768fa517555SKiran Chandramohan mlir::LogicalResult 1769fa517555SKiran Chandramohan reshapeBox(fir::cg::XReboxOp rebox, mlir::Value dest, mlir::Value base, 1770fa517555SKiran Chandramohan mlir::ValueRange inputExtents, mlir::ValueRange inputStrides, 1771fa517555SKiran Chandramohan mlir::ValueRange operands, 1772fa517555SKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const { 1773fa517555SKiran Chandramohan mlir::ValueRange reboxShifts{operands.begin() + rebox.shiftOffset(), 1774fa517555SKiran Chandramohan operands.begin() + rebox.shiftOffset() + 1775fa517555SKiran Chandramohan rebox.shift().size()}; 1776fa517555SKiran Chandramohan if (rebox.shape().empty()) { 1777fa517555SKiran Chandramohan // Only setting new lower bounds. 1778fa517555SKiran Chandramohan return finalizeRebox(rebox, dest, base, reboxShifts, inputExtents, 1779fa517555SKiran Chandramohan inputStrides, rewriter); 1780fa517555SKiran Chandramohan } 1781fa517555SKiran Chandramohan 1782fa517555SKiran Chandramohan mlir::Location loc = rebox.getLoc(); 1783fa517555SKiran Chandramohan // Strides from the fir.box are in bytes. 1784fa517555SKiran Chandramohan mlir::Type voidPtrTy = ::getVoidPtrType(rebox.getContext()); 1785fa517555SKiran Chandramohan base = rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, base); 1786fa517555SKiran Chandramohan 1787fa517555SKiran Chandramohan llvm::SmallVector<mlir::Value> newStrides; 1788fa517555SKiran Chandramohan llvm::SmallVector<mlir::Value> newExtents; 1789fa517555SKiran Chandramohan mlir::Type idxTy = lowerTy().indexType(); 1790fa517555SKiran Chandramohan // First stride from input box is kept. The rest is assumed contiguous 1791fa517555SKiran Chandramohan // (it is not possible to reshape otherwise). If the input is scalar, 1792fa517555SKiran Chandramohan // which may be OK if all new extents are ones, the stride does not 1793fa517555SKiran Chandramohan // matter, use one. 1794fa517555SKiran Chandramohan mlir::Value stride = inputStrides.empty() 1795fa517555SKiran Chandramohan ? genConstantIndex(loc, idxTy, rewriter, 1) 1796fa517555SKiran Chandramohan : inputStrides[0]; 1797fa517555SKiran Chandramohan for (unsigned i = 0; i < rebox.shape().size(); ++i) { 1798fa517555SKiran Chandramohan mlir::Value rawExtent = operands[rebox.shapeOffset() + i]; 1799fa517555SKiran Chandramohan mlir::Value extent = integerCast(loc, rewriter, idxTy, rawExtent); 1800fa517555SKiran Chandramohan newExtents.emplace_back(extent); 1801fa517555SKiran Chandramohan newStrides.emplace_back(stride); 1802fa517555SKiran Chandramohan // nextStride = extent * stride; 1803fa517555SKiran Chandramohan stride = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, extent, stride); 1804fa517555SKiran Chandramohan } 1805fa517555SKiran Chandramohan return finalizeRebox(rebox, dest, base, reboxShifts, newExtents, newStrides, 1806fa517555SKiran Chandramohan rewriter); 1807fa517555SKiran Chandramohan } 1808fa517555SKiran Chandramohan 1809fa517555SKiran Chandramohan /// Return scalar element type of the input box. 1810fa517555SKiran Chandramohan static mlir::Type getInputEleTy(fir::cg::XReboxOp rebox) { 1811fa517555SKiran Chandramohan auto ty = fir::dyn_cast_ptrOrBoxEleTy(rebox.box().getType()); 1812fa517555SKiran Chandramohan if (auto seqTy = ty.dyn_cast<fir::SequenceType>()) 1813fa517555SKiran Chandramohan return seqTy.getEleTy(); 1814fa517555SKiran Chandramohan return ty; 1815fa517555SKiran Chandramohan } 1816fa517555SKiran Chandramohan }; 1817fa517555SKiran Chandramohan 1818dc48849fSKiran Chandramohan /// Lower `fir.emboxproc` operation. Creates a procedure box. 1819dc48849fSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers. 1820dc48849fSKiran Chandramohan struct EmboxProcOpConversion : public FIROpConversion<fir::EmboxProcOp> { 1821dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 1822dc48849fSKiran Chandramohan 1823dc48849fSKiran Chandramohan mlir::LogicalResult 1824dc48849fSKiran Chandramohan matchAndRewrite(fir::EmboxProcOp emboxproc, OpAdaptor adaptor, 1825dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 1826dc48849fSKiran Chandramohan TODO(emboxproc.getLoc(), "fir.emboxproc codegen"); 1827dc48849fSKiran Chandramohan return failure(); 1828dc48849fSKiran Chandramohan } 1829dc48849fSKiran Chandramohan }; 1830dc48849fSKiran Chandramohan 183154c56347SValentin Clement // Code shared between insert_value and extract_value Ops. 183254c56347SValentin Clement struct ValueOpCommon { 183354c56347SValentin Clement // Translate the arguments pertaining to any multidimensional array to 183454c56347SValentin Clement // row-major order for LLVM-IR. 183554c56347SValentin Clement static void toRowMajor(SmallVectorImpl<mlir::Attribute> &attrs, 183654c56347SValentin Clement mlir::Type ty) { 183754c56347SValentin Clement assert(ty && "type is null"); 183854c56347SValentin Clement const auto end = attrs.size(); 183954c56347SValentin Clement for (std::remove_const_t<decltype(end)> i = 0; i < end; ++i) { 184054c56347SValentin Clement if (auto seq = ty.dyn_cast<mlir::LLVM::LLVMArrayType>()) { 184154c56347SValentin Clement const auto dim = getDimension(seq); 184254c56347SValentin Clement if (dim > 1) { 184354c56347SValentin Clement auto ub = std::min(i + dim, end); 184454c56347SValentin Clement std::reverse(attrs.begin() + i, attrs.begin() + ub); 184554c56347SValentin Clement i += dim - 1; 184654c56347SValentin Clement } 184754c56347SValentin Clement ty = getArrayElementType(seq); 184854c56347SValentin Clement } else if (auto st = ty.dyn_cast<mlir::LLVM::LLVMStructType>()) { 184954c56347SValentin Clement ty = st.getBody()[attrs[i].cast<mlir::IntegerAttr>().getInt()]; 185054c56347SValentin Clement } else { 185154c56347SValentin Clement llvm_unreachable("index into invalid type"); 185254c56347SValentin Clement } 185354c56347SValentin Clement } 185454c56347SValentin Clement } 185554c56347SValentin Clement 185654c56347SValentin Clement static llvm::SmallVector<mlir::Attribute> 185754c56347SValentin Clement collectIndices(mlir::ConversionPatternRewriter &rewriter, 185854c56347SValentin Clement mlir::ArrayAttr arrAttr) { 185954c56347SValentin Clement llvm::SmallVector<mlir::Attribute> attrs; 186054c56347SValentin Clement for (auto i = arrAttr.begin(), e = arrAttr.end(); i != e; ++i) { 186154c56347SValentin Clement if (i->isa<mlir::IntegerAttr>()) { 186254c56347SValentin Clement attrs.push_back(*i); 186354c56347SValentin Clement } else { 186454c56347SValentin Clement auto fieldName = i->cast<mlir::StringAttr>().getValue(); 186554c56347SValentin Clement ++i; 186654c56347SValentin Clement auto ty = i->cast<mlir::TypeAttr>().getValue(); 186754c56347SValentin Clement auto index = ty.cast<fir::RecordType>().getFieldIndex(fieldName); 186854c56347SValentin Clement attrs.push_back(mlir::IntegerAttr::get(rewriter.getI32Type(), index)); 186954c56347SValentin Clement } 187054c56347SValentin Clement } 187154c56347SValentin Clement return attrs; 187254c56347SValentin Clement } 187354c56347SValentin Clement 187454c56347SValentin Clement private: 187554c56347SValentin Clement static unsigned getDimension(mlir::LLVM::LLVMArrayType ty) { 187654c56347SValentin Clement unsigned result = 1; 187754c56347SValentin Clement for (auto eleTy = ty.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>(); 187854c56347SValentin Clement eleTy; 187954c56347SValentin Clement eleTy = eleTy.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>()) 188054c56347SValentin Clement ++result; 188154c56347SValentin Clement return result; 188254c56347SValentin Clement } 188354c56347SValentin Clement 188454c56347SValentin Clement static mlir::Type getArrayElementType(mlir::LLVM::LLVMArrayType ty) { 188554c56347SValentin Clement auto eleTy = ty.getElementType(); 188654c56347SValentin Clement while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>()) 188754c56347SValentin Clement eleTy = arrTy.getElementType(); 188854c56347SValentin Clement return eleTy; 188954c56347SValentin Clement } 189054c56347SValentin Clement }; 189154c56347SValentin Clement 1892c2acd453SAlexisPerry namespace { 189354c56347SValentin Clement /// Extract a subobject value from an ssa-value of aggregate type 189454c56347SValentin Clement struct ExtractValueOpConversion 189554c56347SValentin Clement : public FIROpAndTypeConversion<fir::ExtractValueOp>, 189654c56347SValentin Clement public ValueOpCommon { 189754c56347SValentin Clement using FIROpAndTypeConversion::FIROpAndTypeConversion; 189854c56347SValentin Clement 189954c56347SValentin Clement mlir::LogicalResult 190054c56347SValentin Clement doRewrite(fir::ExtractValueOp extractVal, mlir::Type ty, OpAdaptor adaptor, 190154c56347SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 1902149ad3d5SShraiysh Vaishay auto attrs = collectIndices(rewriter, extractVal.getCoor()); 190354c56347SValentin Clement toRowMajor(attrs, adaptor.getOperands()[0].getType()); 190454c56347SValentin Clement auto position = mlir::ArrayAttr::get(extractVal.getContext(), attrs); 190554c56347SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>( 190654c56347SValentin Clement extractVal, ty, adaptor.getOperands()[0], position); 190754c56347SValentin Clement return success(); 190854c56347SValentin Clement } 190954c56347SValentin Clement }; 191054c56347SValentin Clement 191154c56347SValentin Clement /// InsertValue is the generalized instruction for the composition of new 191254c56347SValentin Clement /// aggregate type values. 191354c56347SValentin Clement struct InsertValueOpConversion 191454c56347SValentin Clement : public FIROpAndTypeConversion<fir::InsertValueOp>, 191554c56347SValentin Clement public ValueOpCommon { 191654c56347SValentin Clement using FIROpAndTypeConversion::FIROpAndTypeConversion; 191754c56347SValentin Clement 191854c56347SValentin Clement mlir::LogicalResult 191954c56347SValentin Clement doRewrite(fir::InsertValueOp insertVal, mlir::Type ty, OpAdaptor adaptor, 192054c56347SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 1921149ad3d5SShraiysh Vaishay auto attrs = collectIndices(rewriter, insertVal.getCoor()); 192254c56347SValentin Clement toRowMajor(attrs, adaptor.getOperands()[0].getType()); 192354c56347SValentin Clement auto position = mlir::ArrayAttr::get(insertVal.getContext(), attrs); 192454c56347SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 192554c56347SValentin Clement insertVal, ty, adaptor.getOperands()[0], adaptor.getOperands()[1], 192654c56347SValentin Clement position); 192754c56347SValentin Clement return success(); 192854c56347SValentin Clement } 192954c56347SValentin Clement }; 193054c56347SValentin Clement 19313ae8e442SValentin Clement /// InsertOnRange inserts a value into a sequence over a range of offsets. 19323ae8e442SValentin Clement struct InsertOnRangeOpConversion 19333ae8e442SValentin Clement : public FIROpAndTypeConversion<fir::InsertOnRangeOp> { 19343ae8e442SValentin Clement using FIROpAndTypeConversion::FIROpAndTypeConversion; 19353ae8e442SValentin Clement 19363ae8e442SValentin Clement // Increments an array of subscripts in a row major fasion. 19373ae8e442SValentin Clement void incrementSubscripts(const SmallVector<uint64_t> &dims, 19383ae8e442SValentin Clement SmallVector<uint64_t> &subscripts) const { 19393ae8e442SValentin Clement for (size_t i = dims.size(); i > 0; --i) { 19403ae8e442SValentin Clement if (++subscripts[i - 1] < dims[i - 1]) { 19413ae8e442SValentin Clement return; 19423ae8e442SValentin Clement } 19433ae8e442SValentin Clement subscripts[i - 1] = 0; 19443ae8e442SValentin Clement } 19453ae8e442SValentin Clement } 19463ae8e442SValentin Clement 19473ae8e442SValentin Clement mlir::LogicalResult 19483ae8e442SValentin Clement doRewrite(fir::InsertOnRangeOp range, mlir::Type ty, OpAdaptor adaptor, 19493ae8e442SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 19503ae8e442SValentin Clement 19513ae8e442SValentin Clement llvm::SmallVector<uint64_t> dims; 19523ae8e442SValentin Clement auto type = adaptor.getOperands()[0].getType(); 19533ae8e442SValentin Clement 19543ae8e442SValentin Clement // Iteratively extract the array dimensions from the type. 19553ae8e442SValentin Clement while (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) { 19563ae8e442SValentin Clement dims.push_back(t.getNumElements()); 19573ae8e442SValentin Clement type = t.getElementType(); 19583ae8e442SValentin Clement } 19593ae8e442SValentin Clement 19603ae8e442SValentin Clement SmallVector<uint64_t> lBounds; 19613ae8e442SValentin Clement SmallVector<uint64_t> uBounds; 19623ae8e442SValentin Clement 19633ae8e442SValentin Clement // Unzip the upper and lower bound and convert to a row major format. 1964149ad3d5SShraiysh Vaishay mlir::DenseIntElementsAttr coor = range.getCoor(); 19658ec0f221SMehdi Amini auto reversedCoor = llvm::reverse(coor.getValues<int64_t>()); 19668ec0f221SMehdi Amini for (auto i = reversedCoor.begin(), e = reversedCoor.end(); i != e; ++i) { 19673ae8e442SValentin Clement uBounds.push_back(*i++); 19683ae8e442SValentin Clement lBounds.push_back(*i); 19693ae8e442SValentin Clement } 19703ae8e442SValentin Clement 19713ae8e442SValentin Clement auto &subscripts = lBounds; 19723ae8e442SValentin Clement auto loc = range.getLoc(); 19733ae8e442SValentin Clement mlir::Value lastOp = adaptor.getOperands()[0]; 19743ae8e442SValentin Clement mlir::Value insertVal = adaptor.getOperands()[1]; 19753ae8e442SValentin Clement 19763ae8e442SValentin Clement auto i64Ty = rewriter.getI64Type(); 19773ae8e442SValentin Clement while (subscripts != uBounds) { 19783ae8e442SValentin Clement // Convert uint64_t's to Attribute's. 19793ae8e442SValentin Clement SmallVector<mlir::Attribute> subscriptAttrs; 19803ae8e442SValentin Clement for (const auto &subscript : subscripts) 19813ae8e442SValentin Clement subscriptAttrs.push_back(IntegerAttr::get(i64Ty, subscript)); 19823ae8e442SValentin Clement lastOp = rewriter.create<mlir::LLVM::InsertValueOp>( 19833ae8e442SValentin Clement loc, ty, lastOp, insertVal, 19843ae8e442SValentin Clement ArrayAttr::get(range.getContext(), subscriptAttrs)); 19853ae8e442SValentin Clement 19863ae8e442SValentin Clement incrementSubscripts(dims, subscripts); 19873ae8e442SValentin Clement } 19883ae8e442SValentin Clement 19893ae8e442SValentin Clement // Convert uint64_t's to Attribute's. 19903ae8e442SValentin Clement SmallVector<mlir::Attribute> subscriptAttrs; 19913ae8e442SValentin Clement for (const auto &subscript : subscripts) 19923ae8e442SValentin Clement subscriptAttrs.push_back( 19933ae8e442SValentin Clement IntegerAttr::get(rewriter.getI64Type(), subscript)); 19943ae8e442SValentin Clement mlir::ArrayRef<mlir::Attribute> arrayRef(subscriptAttrs); 19953ae8e442SValentin Clement 19963ae8e442SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 19973ae8e442SValentin Clement range, ty, lastOp, insertVal, 19983ae8e442SValentin Clement ArrayAttr::get(range.getContext(), arrayRef)); 19993ae8e442SValentin Clement 20003ae8e442SValentin Clement return success(); 20013ae8e442SValentin Clement } 20023ae8e442SValentin Clement }; 2003c2acd453SAlexisPerry } // namespace 20047b5132daSValentin Clement 2005dc48849fSKiran Chandramohan namespace { 20065d27abe6SValentin Clement /// XArrayCoor is the address arithmetic on a dynamically shaped, sliced, 20075d27abe6SValentin Clement /// shifted etc. array. 20085d27abe6SValentin Clement /// (See the static restriction on coordinate_of.) array_coor determines the 20095d27abe6SValentin Clement /// coordinate (location) of a specific element. 20105d27abe6SValentin Clement struct XArrayCoorOpConversion 20115d27abe6SValentin Clement : public FIROpAndTypeConversion<fir::cg::XArrayCoorOp> { 20125d27abe6SValentin Clement using FIROpAndTypeConversion::FIROpAndTypeConversion; 20135d27abe6SValentin Clement 20145d27abe6SValentin Clement mlir::LogicalResult 20155d27abe6SValentin Clement doRewrite(fir::cg::XArrayCoorOp coor, mlir::Type ty, OpAdaptor adaptor, 20165d27abe6SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 20175d27abe6SValentin Clement auto loc = coor.getLoc(); 20185d27abe6SValentin Clement mlir::ValueRange operands = adaptor.getOperands(); 20195d27abe6SValentin Clement unsigned rank = coor.getRank(); 20205d27abe6SValentin Clement assert(coor.indices().size() == rank); 20215d27abe6SValentin Clement assert(coor.shape().empty() || coor.shape().size() == rank); 20225d27abe6SValentin Clement assert(coor.shift().empty() || coor.shift().size() == rank); 20235d27abe6SValentin Clement assert(coor.slice().empty() || coor.slice().size() == 3 * rank); 20245d27abe6SValentin Clement mlir::Type idxTy = lowerTy().indexType(); 20255d27abe6SValentin Clement mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1); 20265d27abe6SValentin Clement mlir::Value prevExt = one; 20275d27abe6SValentin Clement mlir::Value zero = genConstantIndex(loc, idxTy, rewriter, 0); 20285d27abe6SValentin Clement mlir::Value offset = zero; 20295d27abe6SValentin Clement const bool isShifted = !coor.shift().empty(); 20305d27abe6SValentin Clement const bool isSliced = !coor.slice().empty(); 20315d27abe6SValentin Clement const bool baseIsBoxed = coor.memref().getType().isa<fir::BoxType>(); 20325d27abe6SValentin Clement 20335d27abe6SValentin Clement auto indexOps = coor.indices().begin(); 20345d27abe6SValentin Clement auto shapeOps = coor.shape().begin(); 20355d27abe6SValentin Clement auto shiftOps = coor.shift().begin(); 20365d27abe6SValentin Clement auto sliceOps = coor.slice().begin(); 20375d27abe6SValentin Clement // For each dimension of the array, generate the offset calculation. 20385d27abe6SValentin Clement for (unsigned i = 0; i < rank; 20395d27abe6SValentin Clement ++i, ++indexOps, ++shapeOps, ++shiftOps, sliceOps += 3) { 20405d27abe6SValentin Clement mlir::Value index = 20415d27abe6SValentin Clement integerCast(loc, rewriter, idxTy, operands[coor.indicesOffset() + i]); 20425d27abe6SValentin Clement mlir::Value lb = isShifted ? integerCast(loc, rewriter, idxTy, 20435d27abe6SValentin Clement operands[coor.shiftOffset() + i]) 20445d27abe6SValentin Clement : one; 20455d27abe6SValentin Clement mlir::Value step = one; 20465d27abe6SValentin Clement bool normalSlice = isSliced; 20475d27abe6SValentin Clement // Compute zero based index in dimension i of the element, applying 20485d27abe6SValentin Clement // potential triplets and lower bounds. 20495d27abe6SValentin Clement if (isSliced) { 20505d27abe6SValentin Clement mlir::Value ub = *(sliceOps + 1); 20515d27abe6SValentin Clement normalSlice = !mlir::isa_and_nonnull<fir::UndefOp>(ub.getDefiningOp()); 20525d27abe6SValentin Clement if (normalSlice) 20535d27abe6SValentin Clement step = integerCast(loc, rewriter, idxTy, *(sliceOps + 2)); 20545d27abe6SValentin Clement } 20555d27abe6SValentin Clement auto idx = rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, index, lb); 20565d27abe6SValentin Clement mlir::Value diff = 20575d27abe6SValentin Clement rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, idx, step); 20585d27abe6SValentin Clement if (normalSlice) { 20595d27abe6SValentin Clement mlir::Value sliceLb = 20605d27abe6SValentin Clement integerCast(loc, rewriter, idxTy, operands[coor.sliceOffset() + i]); 20615d27abe6SValentin Clement auto adj = rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, sliceLb, lb); 20625d27abe6SValentin Clement diff = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, diff, adj); 20635d27abe6SValentin Clement } 20645d27abe6SValentin Clement // Update the offset given the stride and the zero based index `diff` 20655d27abe6SValentin Clement // that was just computed. 20665d27abe6SValentin Clement if (baseIsBoxed) { 20675d27abe6SValentin Clement // Use stride in bytes from the descriptor. 20685d27abe6SValentin Clement mlir::Value stride = 20695d27abe6SValentin Clement loadStrideFromBox(loc, adaptor.getOperands()[0], i, rewriter); 20705d27abe6SValentin Clement auto sc = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, stride); 20715d27abe6SValentin Clement offset = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, offset); 20725d27abe6SValentin Clement } else { 20735d27abe6SValentin Clement // Use stride computed at last iteration. 20745d27abe6SValentin Clement auto sc = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, prevExt); 20755d27abe6SValentin Clement offset = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, offset); 20765d27abe6SValentin Clement // Compute next stride assuming contiguity of the base array 20775d27abe6SValentin Clement // (in element number). 20785d27abe6SValentin Clement auto nextExt = 20795d27abe6SValentin Clement integerCast(loc, rewriter, idxTy, operands[coor.shapeOffset() + i]); 20805d27abe6SValentin Clement prevExt = 20815d27abe6SValentin Clement rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, prevExt, nextExt); 20825d27abe6SValentin Clement } 20835d27abe6SValentin Clement } 20845d27abe6SValentin Clement 20855d27abe6SValentin Clement // Add computed offset to the base address. 20865d27abe6SValentin Clement if (baseIsBoxed) { 20875d27abe6SValentin Clement // Working with byte offsets. The base address is read from the fir.box. 20885d27abe6SValentin Clement // and need to be casted to i8* to do the pointer arithmetic. 20895d27abe6SValentin Clement mlir::Type baseTy = 20905d27abe6SValentin Clement getBaseAddrTypeFromBox(adaptor.getOperands()[0].getType()); 20915d27abe6SValentin Clement mlir::Value base = 20925d27abe6SValentin Clement loadBaseAddrFromBox(loc, baseTy, adaptor.getOperands()[0], rewriter); 20935d27abe6SValentin Clement mlir::Type voidPtrTy = getVoidPtrType(); 20945d27abe6SValentin Clement base = rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, base); 209530122656SAlex Zinenko llvm::SmallVector<mlir::Value> args{offset}; 209630122656SAlex Zinenko auto addr = 209730122656SAlex Zinenko rewriter.create<mlir::LLVM::GEPOp>(loc, voidPtrTy, base, args); 20985d27abe6SValentin Clement if (coor.subcomponent().empty()) { 20995d27abe6SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(coor, baseTy, addr); 21005d27abe6SValentin Clement return success(); 21015d27abe6SValentin Clement } 21025d27abe6SValentin Clement auto casted = rewriter.create<mlir::LLVM::BitcastOp>(loc, baseTy, addr); 21035d27abe6SValentin Clement args.clear(); 21045d27abe6SValentin Clement args.push_back(zero); 21055d27abe6SValentin Clement if (!coor.lenParams().empty()) { 21065d27abe6SValentin Clement // If type parameters are present, then we don't want to use a GEPOp 21075d27abe6SValentin Clement // as below, as the LLVM struct type cannot be statically defined. 21085d27abe6SValentin Clement TODO(loc, "derived type with type parameters"); 21095d27abe6SValentin Clement } 21105d27abe6SValentin Clement // TODO: array offset subcomponents must be converted to LLVM's 21115d27abe6SValentin Clement // row-major layout here. 21125d27abe6SValentin Clement for (auto i = coor.subcomponentOffset(); i != coor.indicesOffset(); ++i) 21135d27abe6SValentin Clement args.push_back(operands[i]); 211430122656SAlex Zinenko rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(coor, baseTy, casted, 211530122656SAlex Zinenko args); 21165d27abe6SValentin Clement return success(); 21175d27abe6SValentin Clement } 21185d27abe6SValentin Clement 21195d27abe6SValentin Clement // The array was not boxed, so it must be contiguous. offset is therefore an 21205d27abe6SValentin Clement // element offset and the base type is kept in the GEP unless the element 21215d27abe6SValentin Clement // type size is itself dynamic. 21225d27abe6SValentin Clement mlir::Value base; 21235d27abe6SValentin Clement if (coor.subcomponent().empty()) { 21245d27abe6SValentin Clement // No subcomponent. 21255d27abe6SValentin Clement if (!coor.lenParams().empty()) { 21265d27abe6SValentin Clement // Type parameters. Adjust element size explicitly. 21275d27abe6SValentin Clement auto eleTy = fir::dyn_cast_ptrEleTy(coor.getType()); 21285d27abe6SValentin Clement assert(eleTy && "result must be a reference-like type"); 21295d27abe6SValentin Clement if (fir::characterWithDynamicLen(eleTy)) { 21305d27abe6SValentin Clement assert(coor.lenParams().size() == 1); 21315d27abe6SValentin Clement auto bitsInChar = lowerTy().getKindMap().getCharacterBitsize( 21325d27abe6SValentin Clement eleTy.cast<fir::CharacterType>().getFKind()); 21335d27abe6SValentin Clement auto scaling = genConstantIndex(loc, idxTy, rewriter, bitsInChar / 8); 21345d27abe6SValentin Clement auto scaledBySize = 21355d27abe6SValentin Clement rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, offset, scaling); 21365d27abe6SValentin Clement auto length = 21375d27abe6SValentin Clement integerCast(loc, rewriter, idxTy, 21385d27abe6SValentin Clement adaptor.getOperands()[coor.lenParamsOffset()]); 21395d27abe6SValentin Clement offset = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, scaledBySize, 21405d27abe6SValentin Clement length); 21415d27abe6SValentin Clement } else { 21425d27abe6SValentin Clement TODO(loc, "compute size of derived type with type parameters"); 21435d27abe6SValentin Clement } 21445d27abe6SValentin Clement } 21455d27abe6SValentin Clement // Cast the base address to a pointer to T. 21465d27abe6SValentin Clement base = rewriter.create<mlir::LLVM::BitcastOp>(loc, ty, 21475d27abe6SValentin Clement adaptor.getOperands()[0]); 21485d27abe6SValentin Clement } else { 21495d27abe6SValentin Clement // Operand #0 must have a pointer type. For subcomponent slicing, we 21505d27abe6SValentin Clement // want to cast away the array type and have a plain struct type. 21515d27abe6SValentin Clement mlir::Type ty0 = adaptor.getOperands()[0].getType(); 21525d27abe6SValentin Clement auto ptrTy = ty0.dyn_cast<mlir::LLVM::LLVMPointerType>(); 21535d27abe6SValentin Clement assert(ptrTy && "expected pointer type"); 21545d27abe6SValentin Clement mlir::Type eleTy = ptrTy.getElementType(); 21555d27abe6SValentin Clement while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>()) 21565d27abe6SValentin Clement eleTy = arrTy.getElementType(); 21575d27abe6SValentin Clement auto newTy = mlir::LLVM::LLVMPointerType::get(eleTy); 21585d27abe6SValentin Clement base = rewriter.create<mlir::LLVM::BitcastOp>(loc, newTy, 21595d27abe6SValentin Clement adaptor.getOperands()[0]); 21605d27abe6SValentin Clement } 216130122656SAlex Zinenko SmallVector<mlir::Value> args = {offset}; 21625d27abe6SValentin Clement for (auto i = coor.subcomponentOffset(); i != coor.indicesOffset(); ++i) 21635d27abe6SValentin Clement args.push_back(operands[i]); 216430122656SAlex Zinenko rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(coor, ty, base, args); 21655d27abe6SValentin Clement return success(); 21665d27abe6SValentin Clement } 21675d27abe6SValentin Clement }; 2168dc48849fSKiran Chandramohan } // namespace 2169dc48849fSKiran Chandramohan 2170dc48849fSKiran Chandramohan /// Convert to (memory) reference to a reference to a subobject. 2171dc48849fSKiran Chandramohan /// The coordinate_of op is a Swiss army knife operation that can be used on 2172dc48849fSKiran Chandramohan /// (memory) references to records, arrays, complex, etc. as well as boxes. 2173dc48849fSKiran Chandramohan /// With unboxed arrays, there is the restriction that the array have a static 2174dc48849fSKiran Chandramohan /// shape in all but the last column. 2175dc48849fSKiran Chandramohan struct CoordinateOpConversion 2176dc48849fSKiran Chandramohan : public FIROpAndTypeConversion<fir::CoordinateOp> { 2177dc48849fSKiran Chandramohan using FIROpAndTypeConversion::FIROpAndTypeConversion; 2178dc48849fSKiran Chandramohan 2179dc48849fSKiran Chandramohan mlir::LogicalResult 2180dc48849fSKiran Chandramohan doRewrite(fir::CoordinateOp coor, mlir::Type ty, OpAdaptor adaptor, 2181dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 2182dc48849fSKiran Chandramohan mlir::ValueRange operands = adaptor.getOperands(); 2183dc48849fSKiran Chandramohan 2184dc48849fSKiran Chandramohan mlir::Location loc = coor.getLoc(); 2185dc48849fSKiran Chandramohan mlir::Value base = operands[0]; 2186dc48849fSKiran Chandramohan mlir::Type baseObjectTy = coor.getBaseType(); 2187dc48849fSKiran Chandramohan mlir::Type objectTy = fir::dyn_cast_ptrOrBoxEleTy(baseObjectTy); 2188dc48849fSKiran Chandramohan assert(objectTy && "fir.coordinate_of expects a reference type"); 2189dc48849fSKiran Chandramohan 2190dc48849fSKiran Chandramohan // Complex type - basically, extract the real or imaginary part 2191dc48849fSKiran Chandramohan if (fir::isa_complex(objectTy)) { 2192dc48849fSKiran Chandramohan mlir::LLVM::ConstantOp c0 = 2193dc48849fSKiran Chandramohan genConstantIndex(loc, lowerTy().indexType(), rewriter, 0); 2194dc48849fSKiran Chandramohan SmallVector<mlir::Value> offs = {c0, operands[1]}; 2195dc48849fSKiran Chandramohan mlir::Value gep = genGEP(loc, ty, rewriter, base, offs); 2196dc48849fSKiran Chandramohan rewriter.replaceOp(coor, gep); 2197dc48849fSKiran Chandramohan return success(); 2198dc48849fSKiran Chandramohan } 2199dc48849fSKiran Chandramohan 2200dc48849fSKiran Chandramohan // Boxed type - get the base pointer from the box 2201dc48849fSKiran Chandramohan if (baseObjectTy.dyn_cast<fir::BoxType>()) 2202dc48849fSKiran Chandramohan return doRewriteBox(coor, ty, operands, loc, rewriter); 2203dc48849fSKiran Chandramohan 2204dc48849fSKiran Chandramohan // Reference or pointer type 2205dc48849fSKiran Chandramohan if (baseObjectTy.isa<fir::ReferenceType, fir::PointerType>()) 2206dc48849fSKiran Chandramohan return doRewriteRefOrPtr(coor, ty, operands, loc, rewriter); 2207dc48849fSKiran Chandramohan 2208dc48849fSKiran Chandramohan return rewriter.notifyMatchFailure( 2209dc48849fSKiran Chandramohan coor, "fir.coordinate_of base operand has unsupported type"); 2210dc48849fSKiran Chandramohan } 2211dc48849fSKiran Chandramohan 2212dc48849fSKiran Chandramohan unsigned getFieldNumber(fir::RecordType ty, mlir::Value op) const { 2213dc48849fSKiran Chandramohan return fir::hasDynamicSize(ty) 2214dc48849fSKiran Chandramohan ? op.getDefiningOp() 2215dc48849fSKiran Chandramohan ->getAttrOfType<mlir::IntegerAttr>("field") 2216dc48849fSKiran Chandramohan .getInt() 2217dc48849fSKiran Chandramohan : getIntValue(op); 2218dc48849fSKiran Chandramohan } 2219dc48849fSKiran Chandramohan 2220dc48849fSKiran Chandramohan int64_t getIntValue(mlir::Value val) const { 2221dc48849fSKiran Chandramohan assert(val && val.dyn_cast<mlir::OpResult>() && "must not be null value"); 2222dc48849fSKiran Chandramohan mlir::Operation *defop = val.getDefiningOp(); 2223dc48849fSKiran Chandramohan 2224dc48849fSKiran Chandramohan if (auto constOp = dyn_cast<mlir::arith::ConstantIntOp>(defop)) 2225dc48849fSKiran Chandramohan return constOp.value(); 2226dc48849fSKiran Chandramohan if (auto llConstOp = dyn_cast<mlir::LLVM::ConstantOp>(defop)) 2227dc48849fSKiran Chandramohan if (auto attr = llConstOp.getValue().dyn_cast<mlir::IntegerAttr>()) 2228dc48849fSKiran Chandramohan return attr.getValue().getSExtValue(); 2229dc48849fSKiran Chandramohan fir::emitFatalError(val.getLoc(), "must be a constant"); 2230dc48849fSKiran Chandramohan } 2231dc48849fSKiran Chandramohan 2232dc48849fSKiran Chandramohan bool hasSubDimensions(mlir::Type type) const { 2233dc48849fSKiran Chandramohan return type.isa<fir::SequenceType, fir::RecordType, mlir::TupleType>(); 2234dc48849fSKiran Chandramohan } 2235dc48849fSKiran Chandramohan 2236dc48849fSKiran Chandramohan /// Check whether this form of `!fir.coordinate_of` is supported. These 2237dc48849fSKiran Chandramohan /// additional checks are required, because we are not yet able to convert 2238dc48849fSKiran Chandramohan /// all valid forms of `!fir.coordinate_of`. 2239dc48849fSKiran Chandramohan /// TODO: Either implement the unsupported cases or extend the verifier 2240dc48849fSKiran Chandramohan /// in FIROps.cpp instead. 2241dc48849fSKiran Chandramohan bool supportedCoordinate(mlir::Type type, mlir::ValueRange coors) const { 2242dc48849fSKiran Chandramohan const std::size_t numOfCoors = coors.size(); 2243dc48849fSKiran Chandramohan std::size_t i = 0; 2244dc48849fSKiran Chandramohan bool subEle = false; 2245dc48849fSKiran Chandramohan bool ptrEle = false; 2246dc48849fSKiran Chandramohan for (; i < numOfCoors; ++i) { 2247dc48849fSKiran Chandramohan mlir::Value nxtOpnd = coors[i]; 2248dc48849fSKiran Chandramohan if (auto arrTy = type.dyn_cast<fir::SequenceType>()) { 2249dc48849fSKiran Chandramohan subEle = true; 2250dc48849fSKiran Chandramohan i += arrTy.getDimension() - 1; 2251dc48849fSKiran Chandramohan type = arrTy.getEleTy(); 2252dc48849fSKiran Chandramohan } else if (auto recTy = type.dyn_cast<fir::RecordType>()) { 2253dc48849fSKiran Chandramohan subEle = true; 2254dc48849fSKiran Chandramohan type = recTy.getType(getFieldNumber(recTy, nxtOpnd)); 2255dc48849fSKiran Chandramohan } else if (auto tupTy = type.dyn_cast<mlir::TupleType>()) { 2256dc48849fSKiran Chandramohan subEle = true; 2257dc48849fSKiran Chandramohan type = tupTy.getType(getIntValue(nxtOpnd)); 2258dc48849fSKiran Chandramohan } else { 2259dc48849fSKiran Chandramohan ptrEle = true; 2260dc48849fSKiran Chandramohan } 2261dc48849fSKiran Chandramohan } 2262dc48849fSKiran Chandramohan if (ptrEle) 2263dc48849fSKiran Chandramohan return (!subEle) && (numOfCoors == 1); 2264dc48849fSKiran Chandramohan return subEle && (i >= numOfCoors); 2265dc48849fSKiran Chandramohan } 2266dc48849fSKiran Chandramohan 2267dc48849fSKiran Chandramohan /// Walk the abstract memory layout and determine if the path traverses any 2268dc48849fSKiran Chandramohan /// array types with unknown shape. Return true iff all the array types have a 2269dc48849fSKiran Chandramohan /// constant shape along the path. 2270dc48849fSKiran Chandramohan bool arraysHaveKnownShape(mlir::Type type, mlir::ValueRange coors) const { 2271dc48849fSKiran Chandramohan const std::size_t sz = coors.size(); 2272dc48849fSKiran Chandramohan std::size_t i = 0; 2273dc48849fSKiran Chandramohan for (; i < sz; ++i) { 2274dc48849fSKiran Chandramohan mlir::Value nxtOpnd = coors[i]; 2275dc48849fSKiran Chandramohan if (auto arrTy = type.dyn_cast<fir::SequenceType>()) { 2276dc48849fSKiran Chandramohan if (fir::sequenceWithNonConstantShape(arrTy)) 2277dc48849fSKiran Chandramohan return false; 2278dc48849fSKiran Chandramohan i += arrTy.getDimension() - 1; 2279dc48849fSKiran Chandramohan type = arrTy.getEleTy(); 2280dc48849fSKiran Chandramohan } else if (auto strTy = type.dyn_cast<fir::RecordType>()) { 2281dc48849fSKiran Chandramohan type = strTy.getType(getFieldNumber(strTy, nxtOpnd)); 2282dc48849fSKiran Chandramohan } else if (auto strTy = type.dyn_cast<mlir::TupleType>()) { 2283dc48849fSKiran Chandramohan type = strTy.getType(getIntValue(nxtOpnd)); 2284dc48849fSKiran Chandramohan } else { 2285dc48849fSKiran Chandramohan return true; 2286dc48849fSKiran Chandramohan } 2287dc48849fSKiran Chandramohan } 2288dc48849fSKiran Chandramohan return true; 2289dc48849fSKiran Chandramohan } 2290dc48849fSKiran Chandramohan 2291dc48849fSKiran Chandramohan private: 2292dc48849fSKiran Chandramohan mlir::LogicalResult 2293dc48849fSKiran Chandramohan doRewriteBox(fir::CoordinateOp coor, mlir::Type ty, mlir::ValueRange operands, 2294dc48849fSKiran Chandramohan mlir::Location loc, 2295dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const { 2296dc48849fSKiran Chandramohan mlir::Type boxObjTy = coor.getBaseType(); 2297dc48849fSKiran Chandramohan assert(boxObjTy.dyn_cast<fir::BoxType>() && "This is not a `fir.box`"); 2298dc48849fSKiran Chandramohan 2299dc48849fSKiran Chandramohan mlir::Value boxBaseAddr = operands[0]; 2300dc48849fSKiran Chandramohan 2301dc48849fSKiran Chandramohan // 1. SPECIAL CASE (uses `fir.len_param_index`): 2302dc48849fSKiran Chandramohan // %box = ... : !fir.box<!fir.type<derived{len1:i32}>> 2303dc48849fSKiran Chandramohan // %lenp = fir.len_param_index len1, !fir.type<derived{len1:i32}> 2304dc48849fSKiran Chandramohan // %addr = coordinate_of %box, %lenp 2305dc48849fSKiran Chandramohan if (coor.getNumOperands() == 2) { 2306dc48849fSKiran Chandramohan mlir::Operation *coordinateDef = 2307dc48849fSKiran Chandramohan (*coor.getCoor().begin()).getDefiningOp(); 2308dc48849fSKiran Chandramohan if (isa_and_nonnull<fir::LenParamIndexOp>(coordinateDef)) { 2309dc48849fSKiran Chandramohan TODO(loc, 2310dc48849fSKiran Chandramohan "fir.coordinate_of - fir.len_param_index is not supported yet"); 2311dc48849fSKiran Chandramohan } 2312dc48849fSKiran Chandramohan } 2313dc48849fSKiran Chandramohan 2314dc48849fSKiran Chandramohan // 2. GENERAL CASE: 2315dc48849fSKiran Chandramohan // 2.1. (`fir.array`) 2316dc48849fSKiran Chandramohan // %box = ... : !fix.box<!fir.array<?xU>> 2317dc48849fSKiran Chandramohan // %idx = ... : index 2318dc48849fSKiran Chandramohan // %resultAddr = coordinate_of %box, %idx : !fir.ref<U> 2319dc48849fSKiran Chandramohan // 2.2 (`fir.derived`) 2320dc48849fSKiran Chandramohan // %box = ... : !fix.box<!fir.type<derived_type{field_1:i32}>> 2321dc48849fSKiran Chandramohan // %idx = ... : i32 2322dc48849fSKiran Chandramohan // %resultAddr = coordinate_of %box, %idx : !fir.ref<i32> 2323dc48849fSKiran Chandramohan // 2.3 (`fir.derived` inside `fir.array`) 2324dc48849fSKiran Chandramohan // %box = ... : !fir.box<!fir.array<10 x !fir.type<derived_1{field_1:f32, 2325dc48849fSKiran Chandramohan // field_2:f32}>>> %idx1 = ... : index %idx2 = ... : i32 %resultAddr = 2326dc48849fSKiran Chandramohan // coordinate_of %box, %idx1, %idx2 : !fir.ref<f32> 2327dc48849fSKiran Chandramohan // 2.4. TODO: Either document or disable any other case that the following 2328dc48849fSKiran Chandramohan // implementation might convert. 2329dc48849fSKiran Chandramohan mlir::LLVM::ConstantOp c0 = 2330dc48849fSKiran Chandramohan genConstantIndex(loc, lowerTy().indexType(), rewriter, 0); 2331dc48849fSKiran Chandramohan mlir::Value resultAddr = 2332dc48849fSKiran Chandramohan loadBaseAddrFromBox(loc, getBaseAddrTypeFromBox(boxBaseAddr.getType()), 2333dc48849fSKiran Chandramohan boxBaseAddr, rewriter); 2334dc48849fSKiran Chandramohan auto currentObjTy = fir::dyn_cast_ptrOrBoxEleTy(boxObjTy); 2335dc48849fSKiran Chandramohan mlir::Type voidPtrTy = ::getVoidPtrType(coor.getContext()); 2336dc48849fSKiran Chandramohan 2337dc48849fSKiran Chandramohan for (unsigned i = 1, last = operands.size(); i < last; ++i) { 2338dc48849fSKiran Chandramohan if (auto arrTy = currentObjTy.dyn_cast<fir::SequenceType>()) { 2339dc48849fSKiran Chandramohan if (i != 1) 2340dc48849fSKiran Chandramohan TODO(loc, "fir.array nested inside other array and/or derived type"); 2341dc48849fSKiran Chandramohan // Applies byte strides from the box. Ignore lower bound from box 2342dc48849fSKiran Chandramohan // since fir.coordinate_of indexes are zero based. Lowering takes care 2343dc48849fSKiran Chandramohan // of lower bound aspects. This both accounts for dynamically sized 2344dc48849fSKiran Chandramohan // types and non contiguous arrays. 2345dc48849fSKiran Chandramohan auto idxTy = lowerTy().indexType(); 2346dc48849fSKiran Chandramohan mlir::Value off = genConstantIndex(loc, idxTy, rewriter, 0); 2347dc48849fSKiran Chandramohan for (unsigned index = i, lastIndex = i + arrTy.getDimension(); 2348dc48849fSKiran Chandramohan index < lastIndex; ++index) { 2349dc48849fSKiran Chandramohan mlir::Value stride = 2350dc48849fSKiran Chandramohan loadStrideFromBox(loc, operands[0], index - i, rewriter); 2351dc48849fSKiran Chandramohan auto sc = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, 2352dc48849fSKiran Chandramohan operands[index], stride); 2353dc48849fSKiran Chandramohan off = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, off); 2354dc48849fSKiran Chandramohan } 2355dc48849fSKiran Chandramohan auto voidPtrBase = 2356dc48849fSKiran Chandramohan rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, resultAddr); 2357dc48849fSKiran Chandramohan SmallVector<mlir::Value> args{off}; 2358dc48849fSKiran Chandramohan resultAddr = rewriter.create<mlir::LLVM::GEPOp>(loc, voidPtrTy, 2359dc48849fSKiran Chandramohan voidPtrBase, args); 2360dc48849fSKiran Chandramohan i += arrTy.getDimension() - 1; 2361dc48849fSKiran Chandramohan currentObjTy = arrTy.getEleTy(); 2362dc48849fSKiran Chandramohan } else if (auto recTy = currentObjTy.dyn_cast<fir::RecordType>()) { 2363dc48849fSKiran Chandramohan auto recRefTy = 2364dc48849fSKiran Chandramohan mlir::LLVM::LLVMPointerType::get(lowerTy().convertType(recTy)); 2365dc48849fSKiran Chandramohan mlir::Value nxtOpnd = operands[i]; 2366dc48849fSKiran Chandramohan auto memObj = 2367dc48849fSKiran Chandramohan rewriter.create<mlir::LLVM::BitcastOp>(loc, recRefTy, resultAddr); 2368dc48849fSKiran Chandramohan llvm::SmallVector<mlir::Value> args = {c0, nxtOpnd}; 2369dc48849fSKiran Chandramohan currentObjTy = recTy.getType(getFieldNumber(recTy, nxtOpnd)); 2370dc48849fSKiran Chandramohan auto llvmCurrentObjTy = lowerTy().convertType(currentObjTy); 2371dc48849fSKiran Chandramohan auto gep = rewriter.create<mlir::LLVM::GEPOp>( 2372dc48849fSKiran Chandramohan loc, mlir::LLVM::LLVMPointerType::get(llvmCurrentObjTy), memObj, 2373dc48849fSKiran Chandramohan args); 2374dc48849fSKiran Chandramohan resultAddr = 2375dc48849fSKiran Chandramohan rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, gep); 2376dc48849fSKiran Chandramohan } else { 2377dc48849fSKiran Chandramohan fir::emitFatalError(loc, "unexpected type in coordinate_of"); 2378dc48849fSKiran Chandramohan } 2379dc48849fSKiran Chandramohan } 2380dc48849fSKiran Chandramohan 2381dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(coor, ty, resultAddr); 2382dc48849fSKiran Chandramohan return success(); 2383dc48849fSKiran Chandramohan } 2384dc48849fSKiran Chandramohan 2385dc48849fSKiran Chandramohan mlir::LogicalResult 2386dc48849fSKiran Chandramohan doRewriteRefOrPtr(fir::CoordinateOp coor, mlir::Type ty, 2387dc48849fSKiran Chandramohan mlir::ValueRange operands, mlir::Location loc, 2388dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const { 2389dc48849fSKiran Chandramohan mlir::Type baseObjectTy = coor.getBaseType(); 2390dc48849fSKiran Chandramohan 2391dc48849fSKiran Chandramohan mlir::Type currentObjTy = fir::dyn_cast_ptrOrBoxEleTy(baseObjectTy); 2392dc48849fSKiran Chandramohan bool hasSubdimension = hasSubDimensions(currentObjTy); 2393dc48849fSKiran Chandramohan bool columnIsDeferred = !hasSubdimension; 2394dc48849fSKiran Chandramohan 2395dc48849fSKiran Chandramohan if (!supportedCoordinate(currentObjTy, operands.drop_front(1))) { 2396dc48849fSKiran Chandramohan TODO(loc, "unsupported combination of coordinate operands"); 2397dc48849fSKiran Chandramohan } 2398dc48849fSKiran Chandramohan 2399dc48849fSKiran Chandramohan const bool hasKnownShape = 2400dc48849fSKiran Chandramohan arraysHaveKnownShape(currentObjTy, operands.drop_front(1)); 2401dc48849fSKiran Chandramohan 2402dc48849fSKiran Chandramohan // If only the column is `?`, then we can simply place the column value in 2403dc48849fSKiran Chandramohan // the 0-th GEP position. 2404dc48849fSKiran Chandramohan if (auto arrTy = currentObjTy.dyn_cast<fir::SequenceType>()) { 2405dc48849fSKiran Chandramohan if (!hasKnownShape) { 2406dc48849fSKiran Chandramohan const unsigned sz = arrTy.getDimension(); 2407dc48849fSKiran Chandramohan if (arraysHaveKnownShape(arrTy.getEleTy(), 2408dc48849fSKiran Chandramohan operands.drop_front(1 + sz))) { 2409dc48849fSKiran Chandramohan llvm::ArrayRef<int64_t> shape = arrTy.getShape(); 2410dc48849fSKiran Chandramohan bool allConst = true; 2411dc48849fSKiran Chandramohan for (unsigned i = 0; i < sz - 1; ++i) { 2412dc48849fSKiran Chandramohan if (shape[i] < 0) { 2413dc48849fSKiran Chandramohan allConst = false; 2414dc48849fSKiran Chandramohan break; 2415dc48849fSKiran Chandramohan } 2416dc48849fSKiran Chandramohan } 2417dc48849fSKiran Chandramohan if (allConst) 2418dc48849fSKiran Chandramohan columnIsDeferred = true; 2419dc48849fSKiran Chandramohan } 2420dc48849fSKiran Chandramohan } 2421dc48849fSKiran Chandramohan } 2422dc48849fSKiran Chandramohan 2423dc48849fSKiran Chandramohan if (fir::hasDynamicSize(fir::unwrapSequenceType(currentObjTy))) { 2424dc48849fSKiran Chandramohan mlir::emitError( 2425dc48849fSKiran Chandramohan loc, "fir.coordinate_of with a dynamic element size is unsupported"); 2426dc48849fSKiran Chandramohan return failure(); 2427dc48849fSKiran Chandramohan } 2428dc48849fSKiran Chandramohan 2429dc48849fSKiran Chandramohan if (hasKnownShape || columnIsDeferred) { 2430dc48849fSKiran Chandramohan SmallVector<mlir::Value> offs; 2431dc48849fSKiran Chandramohan if (hasKnownShape && hasSubdimension) { 2432dc48849fSKiran Chandramohan mlir::LLVM::ConstantOp c0 = 2433dc48849fSKiran Chandramohan genConstantIndex(loc, lowerTy().indexType(), rewriter, 0); 2434dc48849fSKiran Chandramohan offs.push_back(c0); 2435dc48849fSKiran Chandramohan } 2436dc48849fSKiran Chandramohan const std::size_t sz = operands.size(); 2437dc48849fSKiran Chandramohan Optional<int> dims; 2438dc48849fSKiran Chandramohan SmallVector<mlir::Value> arrIdx; 2439dc48849fSKiran Chandramohan for (std::size_t i = 1; i < sz; ++i) { 2440dc48849fSKiran Chandramohan mlir::Value nxtOpnd = operands[i]; 2441dc48849fSKiran Chandramohan 2442dc48849fSKiran Chandramohan if (!currentObjTy) { 2443dc48849fSKiran Chandramohan mlir::emitError(loc, "invalid coordinate/check failed"); 2444dc48849fSKiran Chandramohan return failure(); 2445dc48849fSKiran Chandramohan } 2446dc48849fSKiran Chandramohan 2447dc48849fSKiran Chandramohan // check if the i-th coordinate relates to an array 2448dc48849fSKiran Chandramohan if (dims.hasValue()) { 2449dc48849fSKiran Chandramohan arrIdx.push_back(nxtOpnd); 2450dc48849fSKiran Chandramohan int dimsLeft = *dims; 2451dc48849fSKiran Chandramohan if (dimsLeft > 1) { 2452dc48849fSKiran Chandramohan dims = dimsLeft - 1; 2453dc48849fSKiran Chandramohan continue; 2454dc48849fSKiran Chandramohan } 2455dc48849fSKiran Chandramohan currentObjTy = currentObjTy.cast<fir::SequenceType>().getEleTy(); 2456dc48849fSKiran Chandramohan // append array range in reverse (FIR arrays are column-major) 2457dc48849fSKiran Chandramohan offs.append(arrIdx.rbegin(), arrIdx.rend()); 2458dc48849fSKiran Chandramohan arrIdx.clear(); 2459dc48849fSKiran Chandramohan dims.reset(); 2460dc48849fSKiran Chandramohan continue; 2461dc48849fSKiran Chandramohan } 2462dc48849fSKiran Chandramohan if (auto arrTy = currentObjTy.dyn_cast<fir::SequenceType>()) { 2463dc48849fSKiran Chandramohan int d = arrTy.getDimension() - 1; 2464dc48849fSKiran Chandramohan if (d > 0) { 2465dc48849fSKiran Chandramohan dims = d; 2466dc48849fSKiran Chandramohan arrIdx.push_back(nxtOpnd); 2467dc48849fSKiran Chandramohan continue; 2468dc48849fSKiran Chandramohan } 2469dc48849fSKiran Chandramohan currentObjTy = currentObjTy.cast<fir::SequenceType>().getEleTy(); 2470dc48849fSKiran Chandramohan offs.push_back(nxtOpnd); 2471dc48849fSKiran Chandramohan continue; 2472dc48849fSKiran Chandramohan } 2473dc48849fSKiran Chandramohan 2474dc48849fSKiran Chandramohan // check if the i-th coordinate relates to a field 2475dc48849fSKiran Chandramohan if (auto recTy = currentObjTy.dyn_cast<fir::RecordType>()) 2476dc48849fSKiran Chandramohan currentObjTy = recTy.getType(getFieldNumber(recTy, nxtOpnd)); 2477dc48849fSKiran Chandramohan else if (auto tupTy = currentObjTy.dyn_cast<mlir::TupleType>()) 2478dc48849fSKiran Chandramohan currentObjTy = tupTy.getType(getIntValue(nxtOpnd)); 2479dc48849fSKiran Chandramohan else 2480dc48849fSKiran Chandramohan currentObjTy = nullptr; 2481dc48849fSKiran Chandramohan 2482dc48849fSKiran Chandramohan offs.push_back(nxtOpnd); 2483dc48849fSKiran Chandramohan } 2484dc48849fSKiran Chandramohan if (dims.hasValue()) 2485dc48849fSKiran Chandramohan offs.append(arrIdx.rbegin(), arrIdx.rend()); 2486dc48849fSKiran Chandramohan mlir::Value base = operands[0]; 2487dc48849fSKiran Chandramohan mlir::Value retval = genGEP(loc, ty, rewriter, base, offs); 2488dc48849fSKiran Chandramohan rewriter.replaceOp(coor, retval); 2489dc48849fSKiran Chandramohan return success(); 2490dc48849fSKiran Chandramohan } 2491dc48849fSKiran Chandramohan 2492dc48849fSKiran Chandramohan mlir::emitError(loc, "fir.coordinate_of base operand has unsupported type"); 2493dc48849fSKiran Chandramohan return failure(); 2494dc48849fSKiran Chandramohan } 2495dc48849fSKiran Chandramohan }; 2496dc48849fSKiran Chandramohan 2497dc48849fSKiran Chandramohan /// Convert `fir.field_index`. The conversion depends on whether the size of 2498dc48849fSKiran Chandramohan /// the record is static or dynamic. 2499dc48849fSKiran Chandramohan struct FieldIndexOpConversion : public FIROpConversion<fir::FieldIndexOp> { 2500dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 2501dc48849fSKiran Chandramohan 2502dc48849fSKiran Chandramohan // NB: most field references should be resolved by this point 2503dc48849fSKiran Chandramohan mlir::LogicalResult 2504dc48849fSKiran Chandramohan matchAndRewrite(fir::FieldIndexOp field, OpAdaptor adaptor, 2505dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 2506dc48849fSKiran Chandramohan auto recTy = field.getOnType().cast<fir::RecordType>(); 2507dc48849fSKiran Chandramohan unsigned index = recTy.getFieldIndex(field.getFieldId()); 2508dc48849fSKiran Chandramohan 2509dc48849fSKiran Chandramohan if (!fir::hasDynamicSize(recTy)) { 2510dc48849fSKiran Chandramohan // Derived type has compile-time constant layout. Return index of the 2511dc48849fSKiran Chandramohan // component type in the parent type (to be used in GEP). 2512dc48849fSKiran Chandramohan rewriter.replaceOp(field, mlir::ValueRange{genConstantOffset( 2513dc48849fSKiran Chandramohan field.getLoc(), rewriter, index)}); 2514dc48849fSKiran Chandramohan return success(); 2515dc48849fSKiran Chandramohan } 2516dc48849fSKiran Chandramohan 2517dc48849fSKiran Chandramohan // Derived type has compile-time constant layout. Call the compiler 2518dc48849fSKiran Chandramohan // generated function to determine the byte offset of the field at runtime. 2519dc48849fSKiran Chandramohan // This returns a non-constant. 2520dc48849fSKiran Chandramohan FlatSymbolRefAttr symAttr = mlir::SymbolRefAttr::get( 2521dc48849fSKiran Chandramohan field.getContext(), getOffsetMethodName(recTy, field.getFieldId())); 2522dc48849fSKiran Chandramohan NamedAttribute callAttr = rewriter.getNamedAttr("callee", symAttr); 2523dc48849fSKiran Chandramohan NamedAttribute fieldAttr = rewriter.getNamedAttr( 2524dc48849fSKiran Chandramohan "field", mlir::IntegerAttr::get(lowerTy().indexType(), index)); 2525dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>( 2526dc48849fSKiran Chandramohan field, lowerTy().offsetType(), adaptor.getOperands(), 2527dc48849fSKiran Chandramohan llvm::ArrayRef<mlir::NamedAttribute>{callAttr, fieldAttr}); 2528dc48849fSKiran Chandramohan return success(); 2529dc48849fSKiran Chandramohan } 2530dc48849fSKiran Chandramohan 2531dc48849fSKiran Chandramohan // Re-Construct the name of the compiler generated method that calculates the 2532dc48849fSKiran Chandramohan // offset 2533dc48849fSKiran Chandramohan inline static std::string getOffsetMethodName(fir::RecordType recTy, 2534dc48849fSKiran Chandramohan llvm::StringRef field) { 2535dc48849fSKiran Chandramohan return recTy.getName().str() + "P." + field.str() + ".offset"; 2536dc48849fSKiran Chandramohan } 2537dc48849fSKiran Chandramohan }; 2538dc48849fSKiran Chandramohan 2539dc48849fSKiran Chandramohan /// Convert `fir.end` 2540dc48849fSKiran Chandramohan struct FirEndOpConversion : public FIROpConversion<fir::FirEndOp> { 2541dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 2542dc48849fSKiran Chandramohan 2543dc48849fSKiran Chandramohan mlir::LogicalResult 2544dc48849fSKiran Chandramohan matchAndRewrite(fir::FirEndOp firEnd, OpAdaptor, 2545dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 2546dc48849fSKiran Chandramohan TODO(firEnd.getLoc(), "fir.end codegen"); 2547dc48849fSKiran Chandramohan return failure(); 2548dc48849fSKiran Chandramohan } 2549dc48849fSKiran Chandramohan }; 2550dc48849fSKiran Chandramohan 2551dc48849fSKiran Chandramohan /// Lower `fir.gentypedesc` to a global constant. 2552dc48849fSKiran Chandramohan struct GenTypeDescOpConversion : public FIROpConversion<fir::GenTypeDescOp> { 2553dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 2554dc48849fSKiran Chandramohan 2555dc48849fSKiran Chandramohan mlir::LogicalResult 2556dc48849fSKiran Chandramohan matchAndRewrite(fir::GenTypeDescOp gentypedesc, OpAdaptor adaptor, 2557dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 2558dc48849fSKiran Chandramohan TODO(gentypedesc.getLoc(), "fir.gentypedesc codegen"); 2559dc48849fSKiran Chandramohan return failure(); 2560dc48849fSKiran Chandramohan } 2561dc48849fSKiran Chandramohan }; 2562dc48849fSKiran Chandramohan 2563dc48849fSKiran Chandramohan /// Lower `fir.has_value` operation to `llvm.return` operation. 2564dc48849fSKiran Chandramohan struct HasValueOpConversion : public FIROpConversion<fir::HasValueOp> { 2565dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 2566dc48849fSKiran Chandramohan 2567dc48849fSKiran Chandramohan mlir::LogicalResult 2568dc48849fSKiran Chandramohan matchAndRewrite(fir::HasValueOp op, OpAdaptor adaptor, 2569dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 2570dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, adaptor.getOperands()); 2571dc48849fSKiran Chandramohan return success(); 2572dc48849fSKiran Chandramohan } 2573dc48849fSKiran Chandramohan }; 2574dc48849fSKiran Chandramohan 2575dc48849fSKiran Chandramohan /// Lower `fir.global` operation to `llvm.global` operation. 2576dc48849fSKiran Chandramohan /// `fir.insert_on_range` operations are replaced with constant dense attribute 2577dc48849fSKiran Chandramohan /// if they are applied on the full range. 2578dc48849fSKiran Chandramohan struct GlobalOpConversion : public FIROpConversion<fir::GlobalOp> { 2579dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 2580dc48849fSKiran Chandramohan 2581dc48849fSKiran Chandramohan mlir::LogicalResult 2582dc48849fSKiran Chandramohan matchAndRewrite(fir::GlobalOp global, OpAdaptor adaptor, 2583dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 2584dc48849fSKiran Chandramohan auto tyAttr = convertType(global.getType()); 2585dc48849fSKiran Chandramohan if (global.getType().isa<fir::BoxType>()) 2586dc48849fSKiran Chandramohan tyAttr = tyAttr.cast<mlir::LLVM::LLVMPointerType>().getElementType(); 2587dc48849fSKiran Chandramohan auto loc = global.getLoc(); 2588dc48849fSKiran Chandramohan mlir::Attribute initAttr{}; 2589dc48849fSKiran Chandramohan if (global.getInitVal()) 2590dc48849fSKiran Chandramohan initAttr = global.getInitVal().getValue(); 2591dc48849fSKiran Chandramohan auto linkage = convertLinkage(global.getLinkName()); 2592dc48849fSKiran Chandramohan auto isConst = global.getConstant().hasValue(); 2593dc48849fSKiran Chandramohan auto g = rewriter.create<mlir::LLVM::GlobalOp>( 2594dc48849fSKiran Chandramohan loc, tyAttr, isConst, linkage, global.getSymName(), initAttr); 2595dc48849fSKiran Chandramohan auto &gr = g.getInitializerRegion(); 2596dc48849fSKiran Chandramohan rewriter.inlineRegionBefore(global.getRegion(), gr, gr.end()); 2597dc48849fSKiran Chandramohan if (!gr.empty()) { 2598dc48849fSKiran Chandramohan // Replace insert_on_range with a constant dense attribute if the 2599dc48849fSKiran Chandramohan // initialization is on the full range. 2600dc48849fSKiran Chandramohan auto insertOnRangeOps = gr.front().getOps<fir::InsertOnRangeOp>(); 2601dc48849fSKiran Chandramohan for (auto insertOp : insertOnRangeOps) { 2602dc48849fSKiran Chandramohan if (isFullRange(insertOp.getCoor(), insertOp.getType())) { 2603dc48849fSKiran Chandramohan auto seqTyAttr = convertType(insertOp.getType()); 2604dc48849fSKiran Chandramohan auto *op = insertOp.getVal().getDefiningOp(); 2605dc48849fSKiran Chandramohan auto constant = mlir::dyn_cast<mlir::arith::ConstantOp>(op); 2606dc48849fSKiran Chandramohan if (!constant) { 2607dc48849fSKiran Chandramohan auto convertOp = mlir::dyn_cast<fir::ConvertOp>(op); 2608dc48849fSKiran Chandramohan if (!convertOp) 2609dc48849fSKiran Chandramohan continue; 2610dc48849fSKiran Chandramohan constant = cast<mlir::arith::ConstantOp>( 2611dc48849fSKiran Chandramohan convertOp.getValue().getDefiningOp()); 2612dc48849fSKiran Chandramohan } 2613dc48849fSKiran Chandramohan mlir::Type vecType = mlir::VectorType::get( 2614dc48849fSKiran Chandramohan insertOp.getType().getShape(), constant.getType()); 2615dc48849fSKiran Chandramohan auto denseAttr = mlir::DenseElementsAttr::get( 2616dc48849fSKiran Chandramohan vecType.cast<ShapedType>(), constant.getValue()); 2617dc48849fSKiran Chandramohan rewriter.setInsertionPointAfter(insertOp); 2618dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>( 2619dc48849fSKiran Chandramohan insertOp, seqTyAttr, denseAttr); 2620dc48849fSKiran Chandramohan } 2621dc48849fSKiran Chandramohan } 2622dc48849fSKiran Chandramohan } 2623dc48849fSKiran Chandramohan rewriter.eraseOp(global); 2624dc48849fSKiran Chandramohan return success(); 2625dc48849fSKiran Chandramohan } 2626dc48849fSKiran Chandramohan 2627dc48849fSKiran Chandramohan bool isFullRange(mlir::DenseIntElementsAttr indexes, 2628dc48849fSKiran Chandramohan fir::SequenceType seqTy) const { 2629dc48849fSKiran Chandramohan auto extents = seqTy.getShape(); 2630dc48849fSKiran Chandramohan if (indexes.size() / 2 != static_cast<int64_t>(extents.size())) 2631dc48849fSKiran Chandramohan return false; 2632dc48849fSKiran Chandramohan auto cur_index = indexes.value_begin<int64_t>(); 2633dc48849fSKiran Chandramohan for (unsigned i = 0; i < indexes.size(); i += 2) { 2634dc48849fSKiran Chandramohan if (*(cur_index++) != 0) 2635dc48849fSKiran Chandramohan return false; 2636dc48849fSKiran Chandramohan if (*(cur_index++) != extents[i / 2] - 1) 2637dc48849fSKiran Chandramohan return false; 2638dc48849fSKiran Chandramohan } 2639dc48849fSKiran Chandramohan return true; 2640dc48849fSKiran Chandramohan } 2641dc48849fSKiran Chandramohan 2642dc48849fSKiran Chandramohan // TODO: String comparaison should be avoided. Replace linkName with an 2643dc48849fSKiran Chandramohan // enumeration. 2644dc48849fSKiran Chandramohan mlir::LLVM::Linkage convertLinkage(Optional<StringRef> optLinkage) const { 2645dc48849fSKiran Chandramohan if (optLinkage.hasValue()) { 2646dc48849fSKiran Chandramohan auto name = optLinkage.getValue(); 2647dc48849fSKiran Chandramohan if (name == "internal") 2648dc48849fSKiran Chandramohan return mlir::LLVM::Linkage::Internal; 2649dc48849fSKiran Chandramohan if (name == "linkonce") 2650dc48849fSKiran Chandramohan return mlir::LLVM::Linkage::Linkonce; 265130a0fbf5SJean Perier if (name == "linkonce_odr") 265230a0fbf5SJean Perier return mlir::LLVM::Linkage::LinkonceODR; 2653dc48849fSKiran Chandramohan if (name == "common") 2654dc48849fSKiran Chandramohan return mlir::LLVM::Linkage::Common; 2655dc48849fSKiran Chandramohan if (name == "weak") 2656dc48849fSKiran Chandramohan return mlir::LLVM::Linkage::Weak; 2657dc48849fSKiran Chandramohan } 2658dc48849fSKiran Chandramohan return mlir::LLVM::Linkage::External; 2659dc48849fSKiran Chandramohan } 2660dc48849fSKiran Chandramohan }; 2661dc48849fSKiran Chandramohan 2662dc48849fSKiran Chandramohan /// `fir.load` --> `llvm.load` 2663dc48849fSKiran Chandramohan struct LoadOpConversion : public FIROpConversion<fir::LoadOp> { 2664dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 2665dc48849fSKiran Chandramohan 2666dc48849fSKiran Chandramohan mlir::LogicalResult 2667dc48849fSKiran Chandramohan matchAndRewrite(fir::LoadOp load, OpAdaptor adaptor, 2668dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 2669dc48849fSKiran Chandramohan // fir.box is a special case because it is considered as an ssa values in 2670dc48849fSKiran Chandramohan // fir, but it is lowered as a pointer to a descriptor. So fir.ref<fir.box> 2671dc48849fSKiran Chandramohan // and fir.box end up being the same llvm types and loading a 2672dc48849fSKiran Chandramohan // fir.ref<fir.box> is actually a no op in LLVM. 2673dc48849fSKiran Chandramohan if (load.getType().isa<fir::BoxType>()) { 2674dc48849fSKiran Chandramohan rewriter.replaceOp(load, adaptor.getOperands()[0]); 2675dc48849fSKiran Chandramohan } else { 2676dc48849fSKiran Chandramohan mlir::Type ty = convertType(load.getType()); 2677dc48849fSKiran Chandramohan ArrayRef<NamedAttribute> at = load->getAttrs(); 2678dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::LoadOp>( 2679dc48849fSKiran Chandramohan load, ty, adaptor.getOperands(), at); 2680dc48849fSKiran Chandramohan } 2681dc48849fSKiran Chandramohan return success(); 2682dc48849fSKiran Chandramohan } 2683dc48849fSKiran Chandramohan }; 2684dc48849fSKiran Chandramohan 2685dc48849fSKiran Chandramohan /// Lower `fir.no_reassoc` to LLVM IR dialect. 2686dc48849fSKiran Chandramohan /// TODO: how do we want to enforce this in LLVM-IR? Can we manipulate the fast 2687dc48849fSKiran Chandramohan /// math flags? 2688dc48849fSKiran Chandramohan struct NoReassocOpConversion : public FIROpConversion<fir::NoReassocOp> { 2689dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 2690dc48849fSKiran Chandramohan 2691dc48849fSKiran Chandramohan mlir::LogicalResult 2692dc48849fSKiran Chandramohan matchAndRewrite(fir::NoReassocOp noreassoc, OpAdaptor adaptor, 2693dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 2694dc48849fSKiran Chandramohan rewriter.replaceOp(noreassoc, adaptor.getOperands()[0]); 2695dc48849fSKiran Chandramohan return success(); 2696dc48849fSKiran Chandramohan } 2697dc48849fSKiran Chandramohan }; 2698dc48849fSKiran Chandramohan 2699dc48849fSKiran Chandramohan static void genCondBrOp(mlir::Location loc, mlir::Value cmp, mlir::Block *dest, 2700dc48849fSKiran Chandramohan Optional<mlir::ValueRange> destOps, 2701dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter, 2702dc48849fSKiran Chandramohan mlir::Block *newBlock) { 2703dc48849fSKiran Chandramohan if (destOps.hasValue()) 2704dc48849fSKiran Chandramohan rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, destOps.getValue(), 2705dc48849fSKiran Chandramohan newBlock, mlir::ValueRange()); 2706dc48849fSKiran Chandramohan else 2707dc48849fSKiran Chandramohan rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, newBlock); 2708dc48849fSKiran Chandramohan } 2709dc48849fSKiran Chandramohan 2710dc48849fSKiran Chandramohan template <typename A, typename B> 2711dc48849fSKiran Chandramohan static void genBrOp(A caseOp, mlir::Block *dest, Optional<B> destOps, 2712dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) { 2713dc48849fSKiran Chandramohan if (destOps.hasValue()) 2714dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, destOps.getValue(), 2715dc48849fSKiran Chandramohan dest); 2716dc48849fSKiran Chandramohan else 2717dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, llvm::None, dest); 2718dc48849fSKiran Chandramohan } 2719dc48849fSKiran Chandramohan 2720dc48849fSKiran Chandramohan static void genCaseLadderStep(mlir::Location loc, mlir::Value cmp, 2721dc48849fSKiran Chandramohan mlir::Block *dest, 2722dc48849fSKiran Chandramohan Optional<mlir::ValueRange> destOps, 2723dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) { 2724dc48849fSKiran Chandramohan auto *thisBlock = rewriter.getInsertionBlock(); 2725dc48849fSKiran Chandramohan auto *newBlock = createBlock(rewriter, dest); 2726dc48849fSKiran Chandramohan rewriter.setInsertionPointToEnd(thisBlock); 2727dc48849fSKiran Chandramohan genCondBrOp(loc, cmp, dest, destOps, rewriter, newBlock); 2728dc48849fSKiran Chandramohan rewriter.setInsertionPointToEnd(newBlock); 2729dc48849fSKiran Chandramohan } 2730dc48849fSKiran Chandramohan 2731dc48849fSKiran Chandramohan /// Conversion of `fir.select_case` 2732dc48849fSKiran Chandramohan /// 2733dc48849fSKiran Chandramohan /// The `fir.select_case` operation is converted to a if-then-else ladder. 2734dc48849fSKiran Chandramohan /// Depending on the case condition type, one or several comparison and 2735dc48849fSKiran Chandramohan /// conditional branching can be generated. 2736dc48849fSKiran Chandramohan /// 2737dc48849fSKiran Chandramohan /// A a point value case such as `case(4)`, a lower bound case such as 2738dc48849fSKiran Chandramohan /// `case(5:)` or an upper bound case such as `case(:3)` are converted to a 2739dc48849fSKiran Chandramohan /// simple comparison between the selector value and the constant value in the 2740dc48849fSKiran Chandramohan /// case. The block associated with the case condition is then executed if 2741dc48849fSKiran Chandramohan /// the comparison succeed otherwise it branch to the next block with the 2742dc48849fSKiran Chandramohan /// comparison for the the next case conditon. 2743dc48849fSKiran Chandramohan /// 2744dc48849fSKiran Chandramohan /// A closed interval case condition such as `case(7:10)` is converted with a 2745dc48849fSKiran Chandramohan /// first comparison and conditional branching for the lower bound. If 2746dc48849fSKiran Chandramohan /// successful, it branch to a second block with the comparison for the 2747dc48849fSKiran Chandramohan /// upper bound in the same case condition. 2748dc48849fSKiran Chandramohan /// 2749dc48849fSKiran Chandramohan /// TODO: lowering of CHARACTER type cases is not handled yet. 2750dc48849fSKiran Chandramohan struct SelectCaseOpConversion : public FIROpConversion<fir::SelectCaseOp> { 2751dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 2752dc48849fSKiran Chandramohan 2753dc48849fSKiran Chandramohan mlir::LogicalResult 2754dc48849fSKiran Chandramohan matchAndRewrite(fir::SelectCaseOp caseOp, OpAdaptor adaptor, 2755dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 2756dc48849fSKiran Chandramohan unsigned conds = caseOp.getNumConditions(); 2757dc48849fSKiran Chandramohan llvm::ArrayRef<mlir::Attribute> cases = caseOp.getCases().getValue(); 2758dc48849fSKiran Chandramohan // Type can be CHARACTER, INTEGER, or LOGICAL (C1145) 2759dc48849fSKiran Chandramohan auto ty = caseOp.getSelector().getType(); 2760dc48849fSKiran Chandramohan if (ty.isa<fir::CharacterType>()) { 2761dc48849fSKiran Chandramohan TODO(caseOp.getLoc(), "fir.select_case codegen with character type"); 2762dc48849fSKiran Chandramohan return failure(); 2763dc48849fSKiran Chandramohan } 2764dc48849fSKiran Chandramohan mlir::Value selector = caseOp.getSelector(adaptor.getOperands()); 2765dc48849fSKiran Chandramohan auto loc = caseOp.getLoc(); 2766dc48849fSKiran Chandramohan for (unsigned t = 0; t != conds; ++t) { 2767dc48849fSKiran Chandramohan mlir::Block *dest = caseOp.getSuccessor(t); 2768dc48849fSKiran Chandramohan llvm::Optional<mlir::ValueRange> destOps = 2769dc48849fSKiran Chandramohan caseOp.getSuccessorOperands(adaptor.getOperands(), t); 2770dc48849fSKiran Chandramohan llvm::Optional<mlir::ValueRange> cmpOps = 2771dc48849fSKiran Chandramohan *caseOp.getCompareOperands(adaptor.getOperands(), t); 2772dc48849fSKiran Chandramohan mlir::Value caseArg = *(cmpOps.getValue().begin()); 2773dc48849fSKiran Chandramohan mlir::Attribute attr = cases[t]; 2774dc48849fSKiran Chandramohan if (attr.isa<fir::PointIntervalAttr>()) { 2775dc48849fSKiran Chandramohan auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 2776dc48849fSKiran Chandramohan loc, mlir::LLVM::ICmpPredicate::eq, selector, caseArg); 2777dc48849fSKiran Chandramohan genCaseLadderStep(loc, cmp, dest, destOps, rewriter); 2778dc48849fSKiran Chandramohan continue; 2779dc48849fSKiran Chandramohan } 2780dc48849fSKiran Chandramohan if (attr.isa<fir::LowerBoundAttr>()) { 2781dc48849fSKiran Chandramohan auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 2782dc48849fSKiran Chandramohan loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector); 2783dc48849fSKiran Chandramohan genCaseLadderStep(loc, cmp, dest, destOps, rewriter); 2784dc48849fSKiran Chandramohan continue; 2785dc48849fSKiran Chandramohan } 2786dc48849fSKiran Chandramohan if (attr.isa<fir::UpperBoundAttr>()) { 2787dc48849fSKiran Chandramohan auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 2788dc48849fSKiran Chandramohan loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg); 2789dc48849fSKiran Chandramohan genCaseLadderStep(loc, cmp, dest, destOps, rewriter); 2790dc48849fSKiran Chandramohan continue; 2791dc48849fSKiran Chandramohan } 2792dc48849fSKiran Chandramohan if (attr.isa<fir::ClosedIntervalAttr>()) { 2793dc48849fSKiran Chandramohan auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 2794dc48849fSKiran Chandramohan loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector); 2795dc48849fSKiran Chandramohan auto *thisBlock = rewriter.getInsertionBlock(); 2796dc48849fSKiran Chandramohan auto *newBlock1 = createBlock(rewriter, dest); 2797dc48849fSKiran Chandramohan auto *newBlock2 = createBlock(rewriter, dest); 2798dc48849fSKiran Chandramohan rewriter.setInsertionPointToEnd(thisBlock); 2799dc48849fSKiran Chandramohan rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, newBlock1, newBlock2); 2800dc48849fSKiran Chandramohan rewriter.setInsertionPointToEnd(newBlock1); 2801dc48849fSKiran Chandramohan mlir::Value caseArg0 = *(cmpOps.getValue().begin() + 1); 2802dc48849fSKiran Chandramohan auto cmp0 = rewriter.create<mlir::LLVM::ICmpOp>( 2803dc48849fSKiran Chandramohan loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg0); 2804dc48849fSKiran Chandramohan genCondBrOp(loc, cmp0, dest, destOps, rewriter, newBlock2); 2805dc48849fSKiran Chandramohan rewriter.setInsertionPointToEnd(newBlock2); 2806dc48849fSKiran Chandramohan continue; 2807dc48849fSKiran Chandramohan } 2808dc48849fSKiran Chandramohan assert(attr.isa<mlir::UnitAttr>()); 2809dc48849fSKiran Chandramohan assert((t + 1 == conds) && "unit must be last"); 2810dc48849fSKiran Chandramohan genBrOp(caseOp, dest, destOps, rewriter); 2811dc48849fSKiran Chandramohan } 2812dc48849fSKiran Chandramohan return success(); 2813dc48849fSKiran Chandramohan } 2814dc48849fSKiran Chandramohan }; 2815dc48849fSKiran Chandramohan 2816dc48849fSKiran Chandramohan template <typename OP> 2817dc48849fSKiran Chandramohan static void selectMatchAndRewrite(fir::LLVMTypeConverter &lowering, OP select, 2818dc48849fSKiran Chandramohan typename OP::Adaptor adaptor, 2819dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) { 2820dc48849fSKiran Chandramohan unsigned conds = select.getNumConditions(); 2821dc48849fSKiran Chandramohan auto cases = select.getCases().getValue(); 2822dc48849fSKiran Chandramohan mlir::Value selector = adaptor.getSelector(); 2823dc48849fSKiran Chandramohan auto loc = select.getLoc(); 2824dc48849fSKiran Chandramohan assert(conds > 0 && "select must have cases"); 2825dc48849fSKiran Chandramohan 2826dc48849fSKiran Chandramohan llvm::SmallVector<mlir::Block *> destinations; 2827dc48849fSKiran Chandramohan llvm::SmallVector<mlir::ValueRange> destinationsOperands; 2828dc48849fSKiran Chandramohan mlir::Block *defaultDestination; 2829dc48849fSKiran Chandramohan mlir::ValueRange defaultOperands; 2830dc48849fSKiran Chandramohan llvm::SmallVector<int32_t> caseValues; 2831dc48849fSKiran Chandramohan 2832dc48849fSKiran Chandramohan for (unsigned t = 0; t != conds; ++t) { 2833dc48849fSKiran Chandramohan mlir::Block *dest = select.getSuccessor(t); 2834dc48849fSKiran Chandramohan auto destOps = select.getSuccessorOperands(adaptor.getOperands(), t); 2835dc48849fSKiran Chandramohan const mlir::Attribute &attr = cases[t]; 2836dc48849fSKiran Chandramohan if (auto intAttr = attr.template dyn_cast<mlir::IntegerAttr>()) { 2837dc48849fSKiran Chandramohan destinations.push_back(dest); 2838dc48849fSKiran Chandramohan destinationsOperands.push_back(destOps.hasValue() ? *destOps 2839dc48849fSKiran Chandramohan : ValueRange()); 2840dc48849fSKiran Chandramohan caseValues.push_back(intAttr.getInt()); 2841dc48849fSKiran Chandramohan continue; 2842dc48849fSKiran Chandramohan } 2843dc48849fSKiran Chandramohan assert(attr.template dyn_cast_or_null<mlir::UnitAttr>()); 2844dc48849fSKiran Chandramohan assert((t + 1 == conds) && "unit must be last"); 2845dc48849fSKiran Chandramohan defaultDestination = dest; 2846dc48849fSKiran Chandramohan defaultOperands = destOps.hasValue() ? *destOps : ValueRange(); 2847dc48849fSKiran Chandramohan } 2848dc48849fSKiran Chandramohan 2849dc48849fSKiran Chandramohan // LLVM::SwitchOp takes a i32 type for the selector. 2850dc48849fSKiran Chandramohan if (select.getSelector().getType() != rewriter.getI32Type()) 2851dc48849fSKiran Chandramohan selector = 2852dc48849fSKiran Chandramohan rewriter.create<LLVM::TruncOp>(loc, rewriter.getI32Type(), selector); 2853dc48849fSKiran Chandramohan 2854dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>( 2855dc48849fSKiran Chandramohan select, selector, 2856dc48849fSKiran Chandramohan /*defaultDestination=*/defaultDestination, 2857dc48849fSKiran Chandramohan /*defaultOperands=*/defaultOperands, 2858dc48849fSKiran Chandramohan /*caseValues=*/caseValues, 2859dc48849fSKiran Chandramohan /*caseDestinations=*/destinations, 2860dc48849fSKiran Chandramohan /*caseOperands=*/destinationsOperands, 2861dc48849fSKiran Chandramohan /*branchWeights=*/ArrayRef<int32_t>()); 2862dc48849fSKiran Chandramohan } 2863dc48849fSKiran Chandramohan 2864dc48849fSKiran Chandramohan /// conversion of fir::SelectOp to an if-then-else ladder 2865dc48849fSKiran Chandramohan struct SelectOpConversion : public FIROpConversion<fir::SelectOp> { 2866dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 2867dc48849fSKiran Chandramohan 2868dc48849fSKiran Chandramohan mlir::LogicalResult 2869dc48849fSKiran Chandramohan matchAndRewrite(fir::SelectOp op, OpAdaptor adaptor, 2870dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 2871dc48849fSKiran Chandramohan selectMatchAndRewrite<fir::SelectOp>(lowerTy(), op, adaptor, rewriter); 2872dc48849fSKiran Chandramohan return success(); 2873dc48849fSKiran Chandramohan } 2874dc48849fSKiran Chandramohan }; 2875dc48849fSKiran Chandramohan 2876dc48849fSKiran Chandramohan /// conversion of fir::SelectRankOp to an if-then-else ladder 2877dc48849fSKiran Chandramohan struct SelectRankOpConversion : public FIROpConversion<fir::SelectRankOp> { 2878dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 2879dc48849fSKiran Chandramohan 2880dc48849fSKiran Chandramohan mlir::LogicalResult 2881dc48849fSKiran Chandramohan matchAndRewrite(fir::SelectRankOp op, OpAdaptor adaptor, 2882dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 2883dc48849fSKiran Chandramohan selectMatchAndRewrite<fir::SelectRankOp>(lowerTy(), op, adaptor, rewriter); 2884dc48849fSKiran Chandramohan return success(); 2885dc48849fSKiran Chandramohan } 2886dc48849fSKiran Chandramohan }; 2887dc48849fSKiran Chandramohan 2888dc48849fSKiran Chandramohan /// Lower `fir.select_type` to LLVM IR dialect. 2889dc48849fSKiran Chandramohan struct SelectTypeOpConversion : public FIROpConversion<fir::SelectTypeOp> { 2890dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 2891dc48849fSKiran Chandramohan 2892dc48849fSKiran Chandramohan mlir::LogicalResult 2893dc48849fSKiran Chandramohan matchAndRewrite(fir::SelectTypeOp select, OpAdaptor adaptor, 2894dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 2895dc48849fSKiran Chandramohan mlir::emitError(select.getLoc(), 2896dc48849fSKiran Chandramohan "fir.select_type should have already been converted"); 2897dc48849fSKiran Chandramohan return failure(); 2898dc48849fSKiran Chandramohan } 2899dc48849fSKiran Chandramohan }; 2900dc48849fSKiran Chandramohan 2901dc48849fSKiran Chandramohan /// `fir.store` --> `llvm.store` 2902dc48849fSKiran Chandramohan struct StoreOpConversion : public FIROpConversion<fir::StoreOp> { 2903dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 2904dc48849fSKiran Chandramohan 2905dc48849fSKiran Chandramohan mlir::LogicalResult 2906dc48849fSKiran Chandramohan matchAndRewrite(fir::StoreOp store, OpAdaptor adaptor, 2907dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 2908dc48849fSKiran Chandramohan if (store.getValue().getType().isa<fir::BoxType>()) { 2909dc48849fSKiran Chandramohan // fir.box value is actually in memory, load it first before storing it. 2910dc48849fSKiran Chandramohan mlir::Location loc = store.getLoc(); 2911dc48849fSKiran Chandramohan mlir::Type boxPtrTy = adaptor.getOperands()[0].getType(); 2912dc48849fSKiran Chandramohan auto val = rewriter.create<mlir::LLVM::LoadOp>( 2913dc48849fSKiran Chandramohan loc, boxPtrTy.cast<mlir::LLVM::LLVMPointerType>().getElementType(), 2914dc48849fSKiran Chandramohan adaptor.getOperands()[0]); 2915dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>( 2916dc48849fSKiran Chandramohan store, val, adaptor.getOperands()[1]); 2917dc48849fSKiran Chandramohan } else { 2918dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>( 2919dc48849fSKiran Chandramohan store, adaptor.getOperands()[0], adaptor.getOperands()[1]); 2920dc48849fSKiran Chandramohan } 2921dc48849fSKiran Chandramohan return success(); 2922dc48849fSKiran Chandramohan } 2923dc48849fSKiran Chandramohan }; 2924dc48849fSKiran Chandramohan 2925dc48849fSKiran Chandramohan namespace { 2926dc48849fSKiran Chandramohan 2927dc48849fSKiran Chandramohan /// Convert `fir.unboxchar` into two `llvm.extractvalue` instructions. One for 2928dc48849fSKiran Chandramohan /// the character buffer and one for the buffer length. 2929dc48849fSKiran Chandramohan struct UnboxCharOpConversion : public FIROpConversion<fir::UnboxCharOp> { 2930dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 2931dc48849fSKiran Chandramohan 2932dc48849fSKiran Chandramohan mlir::LogicalResult 2933dc48849fSKiran Chandramohan matchAndRewrite(fir::UnboxCharOp unboxchar, OpAdaptor adaptor, 2934dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 2935dc48849fSKiran Chandramohan MLIRContext *ctx = unboxchar.getContext(); 2936dc48849fSKiran Chandramohan 2937dc48849fSKiran Chandramohan mlir::Type lenTy = convertType(unboxchar.getType(1)); 2938dc48849fSKiran Chandramohan mlir::Value tuple = adaptor.getOperands()[0]; 2939dc48849fSKiran Chandramohan mlir::Type tupleTy = tuple.getType(); 2940dc48849fSKiran Chandramohan 2941dc48849fSKiran Chandramohan mlir::Location loc = unboxchar.getLoc(); 2942dc48849fSKiran Chandramohan mlir::Value ptrToBuffer = 2943dc48849fSKiran Chandramohan genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 0); 2944dc48849fSKiran Chandramohan 2945dc48849fSKiran Chandramohan mlir::LLVM::ExtractValueOp len = 2946dc48849fSKiran Chandramohan genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 1); 2947dc48849fSKiran Chandramohan mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, len); 2948dc48849fSKiran Chandramohan 2949dc48849fSKiran Chandramohan rewriter.replaceOp(unboxchar, 2950dc48849fSKiran Chandramohan ArrayRef<mlir::Value>{ptrToBuffer, lenAfterCast}); 2951dc48849fSKiran Chandramohan return success(); 2952dc48849fSKiran Chandramohan } 2953dc48849fSKiran Chandramohan }; 2954dc48849fSKiran Chandramohan 2955dc48849fSKiran Chandramohan /// Lower `fir.unboxproc` operation. Unbox a procedure box value, yielding its 2956dc48849fSKiran Chandramohan /// components. 2957dc48849fSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers. 2958dc48849fSKiran Chandramohan struct UnboxProcOpConversion : public FIROpConversion<fir::UnboxProcOp> { 2959dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 2960dc48849fSKiran Chandramohan 2961dc48849fSKiran Chandramohan mlir::LogicalResult 2962dc48849fSKiran Chandramohan matchAndRewrite(fir::UnboxProcOp unboxproc, OpAdaptor adaptor, 2963dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 2964dc48849fSKiran Chandramohan TODO(unboxproc.getLoc(), "fir.unboxproc codegen"); 2965dc48849fSKiran Chandramohan return failure(); 2966dc48849fSKiran Chandramohan } 2967dc48849fSKiran Chandramohan }; 2968dc48849fSKiran Chandramohan 2969dc48849fSKiran Chandramohan /// convert to LLVM IR dialect `undef` 2970dc48849fSKiran Chandramohan struct UndefOpConversion : public FIROpConversion<fir::UndefOp> { 2971dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 2972dc48849fSKiran Chandramohan 2973dc48849fSKiran Chandramohan mlir::LogicalResult 2974dc48849fSKiran Chandramohan matchAndRewrite(fir::UndefOp undef, OpAdaptor, 2975dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 2976dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::UndefOp>( 2977dc48849fSKiran Chandramohan undef, convertType(undef.getType())); 2978dc48849fSKiran Chandramohan return success(); 2979dc48849fSKiran Chandramohan } 2980dc48849fSKiran Chandramohan }; 2981dc48849fSKiran Chandramohan 2982dc48849fSKiran Chandramohan struct ZeroOpConversion : public FIROpConversion<fir::ZeroOp> { 2983dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 2984dc48849fSKiran Chandramohan 2985dc48849fSKiran Chandramohan mlir::LogicalResult 2986dc48849fSKiran Chandramohan matchAndRewrite(fir::ZeroOp zero, OpAdaptor, 2987dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 2988dc48849fSKiran Chandramohan mlir::Type ty = convertType(zero.getType()); 2989dc48849fSKiran Chandramohan if (ty.isa<mlir::LLVM::LLVMPointerType>()) { 2990dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(zero, ty); 2991dc48849fSKiran Chandramohan } else if (ty.isa<mlir::IntegerType>()) { 2992dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>( 2993dc48849fSKiran Chandramohan zero, ty, mlir::IntegerAttr::get(zero.getType(), 0)); 2994dc48849fSKiran Chandramohan } else if (mlir::LLVM::isCompatibleFloatingPointType(ty)) { 2995dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>( 2996dc48849fSKiran Chandramohan zero, ty, mlir::FloatAttr::get(zero.getType(), 0.0)); 2997dc48849fSKiran Chandramohan } else { 2998dc48849fSKiran Chandramohan // TODO: create ConstantAggregateZero for FIR aggregate/array types. 2999dc48849fSKiran Chandramohan return rewriter.notifyMatchFailure( 3000dc48849fSKiran Chandramohan zero, 3001dc48849fSKiran Chandramohan "conversion of fir.zero with aggregate type not implemented yet"); 3002dc48849fSKiran Chandramohan } 3003dc48849fSKiran Chandramohan return success(); 3004dc48849fSKiran Chandramohan } 3005dc48849fSKiran Chandramohan }; 3006dc48849fSKiran Chandramohan 3007dc48849fSKiran Chandramohan /// `fir.unreachable` --> `llvm.unreachable` 3008dc48849fSKiran Chandramohan struct UnreachableOpConversion : public FIROpConversion<fir::UnreachableOp> { 3009dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 3010dc48849fSKiran Chandramohan 3011dc48849fSKiran Chandramohan mlir::LogicalResult 3012dc48849fSKiran Chandramohan matchAndRewrite(fir::UnreachableOp unreach, OpAdaptor adaptor, 3013dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 3014dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(unreach); 3015dc48849fSKiran Chandramohan return success(); 3016dc48849fSKiran Chandramohan } 3017dc48849fSKiran Chandramohan }; 3018dc48849fSKiran Chandramohan 3019dc48849fSKiran Chandramohan /// `fir.is_present` --> 3020dc48849fSKiran Chandramohan /// ``` 3021dc48849fSKiran Chandramohan /// %0 = llvm.mlir.constant(0 : i64) 3022dc48849fSKiran Chandramohan /// %1 = llvm.ptrtoint %0 3023dc48849fSKiran Chandramohan /// %2 = llvm.icmp "ne" %1, %0 : i64 3024dc48849fSKiran Chandramohan /// ``` 3025dc48849fSKiran Chandramohan struct IsPresentOpConversion : public FIROpConversion<fir::IsPresentOp> { 3026dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 3027dc48849fSKiran Chandramohan 3028dc48849fSKiran Chandramohan mlir::LogicalResult 3029dc48849fSKiran Chandramohan matchAndRewrite(fir::IsPresentOp isPresent, OpAdaptor adaptor, 3030dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 3031dc48849fSKiran Chandramohan mlir::Type idxTy = lowerTy().indexType(); 3032dc48849fSKiran Chandramohan mlir::Location loc = isPresent.getLoc(); 3033dc48849fSKiran Chandramohan auto ptr = adaptor.getOperands()[0]; 3034dc48849fSKiran Chandramohan 3035dc48849fSKiran Chandramohan if (isPresent.getVal().getType().isa<fir::BoxCharType>()) { 3036dc48849fSKiran Chandramohan auto structTy = ptr.getType().cast<mlir::LLVM::LLVMStructType>(); 3037dc48849fSKiran Chandramohan assert(!structTy.isOpaque() && !structTy.getBody().empty()); 3038dc48849fSKiran Chandramohan 3039dc48849fSKiran Chandramohan mlir::Type ty = structTy.getBody()[0]; 3040dc48849fSKiran Chandramohan mlir::MLIRContext *ctx = isPresent.getContext(); 3041dc48849fSKiran Chandramohan auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 3042dc48849fSKiran Chandramohan ptr = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, ptr, c0); 3043dc48849fSKiran Chandramohan } 3044dc48849fSKiran Chandramohan mlir::LLVM::ConstantOp c0 = 3045dc48849fSKiran Chandramohan genConstantIndex(isPresent.getLoc(), idxTy, rewriter, 0); 3046dc48849fSKiran Chandramohan auto addr = rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, ptr); 3047dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>( 3048dc48849fSKiran Chandramohan isPresent, mlir::LLVM::ICmpPredicate::ne, addr, c0); 3049dc48849fSKiran Chandramohan 3050dc48849fSKiran Chandramohan return success(); 3051dc48849fSKiran Chandramohan } 3052dc48849fSKiran Chandramohan }; 3053dc48849fSKiran Chandramohan 3054dc48849fSKiran Chandramohan /// Create value signaling an absent optional argument in a call, e.g. 3055dc48849fSKiran Chandramohan /// `fir.absent !fir.ref<i64>` --> `llvm.mlir.null : !llvm.ptr<i64>` 3056dc48849fSKiran Chandramohan struct AbsentOpConversion : public FIROpConversion<fir::AbsentOp> { 3057dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 3058dc48849fSKiran Chandramohan 3059dc48849fSKiran Chandramohan mlir::LogicalResult 3060dc48849fSKiran Chandramohan matchAndRewrite(fir::AbsentOp absent, OpAdaptor, 3061dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 3062dc48849fSKiran Chandramohan mlir::Type ty = convertType(absent.getType()); 3063dc48849fSKiran Chandramohan mlir::Location loc = absent.getLoc(); 3064dc48849fSKiran Chandramohan 3065dc48849fSKiran Chandramohan if (absent.getType().isa<fir::BoxCharType>()) { 3066dc48849fSKiran Chandramohan auto structTy = ty.cast<mlir::LLVM::LLVMStructType>(); 3067dc48849fSKiran Chandramohan assert(!structTy.isOpaque() && !structTy.getBody().empty()); 3068dc48849fSKiran Chandramohan auto undefStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 3069dc48849fSKiran Chandramohan auto nullField = 3070dc48849fSKiran Chandramohan rewriter.create<mlir::LLVM::NullOp>(loc, structTy.getBody()[0]); 3071dc48849fSKiran Chandramohan mlir::MLIRContext *ctx = absent.getContext(); 3072dc48849fSKiran Chandramohan auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 3073dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 3074dc48849fSKiran Chandramohan absent, ty, undefStruct, nullField, c0); 3075dc48849fSKiran Chandramohan } else { 3076dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(absent, ty); 3077dc48849fSKiran Chandramohan } 3078dc48849fSKiran Chandramohan return success(); 3079dc48849fSKiran Chandramohan } 3080dc48849fSKiran Chandramohan }; 30815d27abe6SValentin Clement 30827b5132daSValentin Clement // 30837b5132daSValentin Clement // Primitive operations on Complex types 30847b5132daSValentin Clement // 30857b5132daSValentin Clement 30867b5132daSValentin Clement /// Generate inline code for complex addition/subtraction 30877b5132daSValentin Clement template <typename LLVMOP, typename OPTY> 3088c2acd453SAlexisPerry static mlir::LLVM::InsertValueOp 3089c2acd453SAlexisPerry complexSum(OPTY sumop, mlir::ValueRange opnds, 30907b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter, 30917b5132daSValentin Clement fir::LLVMTypeConverter &lowering) { 30927b5132daSValentin Clement mlir::Value a = opnds[0]; 30937b5132daSValentin Clement mlir::Value b = opnds[1]; 30947b5132daSValentin Clement auto loc = sumop.getLoc(); 30957b5132daSValentin Clement auto ctx = sumop.getContext(); 30967b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 30977b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 30987b5132daSValentin Clement mlir::Type eleTy = lowering.convertType(getComplexEleTy(sumop.getType())); 30997b5132daSValentin Clement mlir::Type ty = lowering.convertType(sumop.getType()); 31007b5132daSValentin Clement auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0); 31017b5132daSValentin Clement auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1); 31027b5132daSValentin Clement auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0); 31037b5132daSValentin Clement auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1); 31047b5132daSValentin Clement auto rx = rewriter.create<LLVMOP>(loc, eleTy, x0, x1); 31057b5132daSValentin Clement auto ry = rewriter.create<LLVMOP>(loc, eleTy, y0, y1); 31067b5132daSValentin Clement auto r0 = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 31077b5132daSValentin Clement auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r0, rx, c0); 31087b5132daSValentin Clement return rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ry, c1); 31097b5132daSValentin Clement } 3110dc48849fSKiran Chandramohan } // namespace 31117b5132daSValentin Clement 3112c2acd453SAlexisPerry namespace { 31137b5132daSValentin Clement struct AddcOpConversion : public FIROpConversion<fir::AddcOp> { 31147b5132daSValentin Clement using FIROpConversion::FIROpConversion; 31157b5132daSValentin Clement 31167b5132daSValentin Clement mlir::LogicalResult 31177b5132daSValentin Clement matchAndRewrite(fir::AddcOp addc, OpAdaptor adaptor, 31187b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 31197b5132daSValentin Clement // given: (x + iy) + (x' + iy') 31207b5132daSValentin Clement // result: (x + x') + i(y + y') 31217b5132daSValentin Clement auto r = complexSum<mlir::LLVM::FAddOp>(addc, adaptor.getOperands(), 31227b5132daSValentin Clement rewriter, lowerTy()); 31237b5132daSValentin Clement rewriter.replaceOp(addc, r.getResult()); 31247b5132daSValentin Clement return success(); 31257b5132daSValentin Clement } 31267b5132daSValentin Clement }; 31277b5132daSValentin Clement 31287b5132daSValentin Clement struct SubcOpConversion : public FIROpConversion<fir::SubcOp> { 31297b5132daSValentin Clement using FIROpConversion::FIROpConversion; 31307b5132daSValentin Clement 31317b5132daSValentin Clement mlir::LogicalResult 31327b5132daSValentin Clement matchAndRewrite(fir::SubcOp subc, OpAdaptor adaptor, 31337b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 31347b5132daSValentin Clement // given: (x + iy) - (x' + iy') 31357b5132daSValentin Clement // result: (x - x') + i(y - y') 31367b5132daSValentin Clement auto r = complexSum<mlir::LLVM::FSubOp>(subc, adaptor.getOperands(), 31377b5132daSValentin Clement rewriter, lowerTy()); 31387b5132daSValentin Clement rewriter.replaceOp(subc, r.getResult()); 31397b5132daSValentin Clement return success(); 31407b5132daSValentin Clement } 31417b5132daSValentin Clement }; 31427b5132daSValentin Clement 31437b5132daSValentin Clement /// Inlined complex multiply 31447b5132daSValentin Clement struct MulcOpConversion : public FIROpConversion<fir::MulcOp> { 31457b5132daSValentin Clement using FIROpConversion::FIROpConversion; 31467b5132daSValentin Clement 31477b5132daSValentin Clement mlir::LogicalResult 31487b5132daSValentin Clement matchAndRewrite(fir::MulcOp mulc, OpAdaptor adaptor, 31497b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 31507b5132daSValentin Clement // TODO: Can we use a call to __muldc3 ? 31517b5132daSValentin Clement // given: (x + iy) * (x' + iy') 31527b5132daSValentin Clement // result: (xx'-yy')+i(xy'+yx') 31537b5132daSValentin Clement mlir::Value a = adaptor.getOperands()[0]; 31547b5132daSValentin Clement mlir::Value b = adaptor.getOperands()[1]; 31557b5132daSValentin Clement auto loc = mulc.getLoc(); 31567b5132daSValentin Clement auto *ctx = mulc.getContext(); 31577b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 31587b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 31597b5132daSValentin Clement mlir::Type eleTy = convertType(getComplexEleTy(mulc.getType())); 31607b5132daSValentin Clement mlir::Type ty = convertType(mulc.getType()); 31617b5132daSValentin Clement auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0); 31627b5132daSValentin Clement auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1); 31637b5132daSValentin Clement auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0); 31647b5132daSValentin Clement auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1); 31657b5132daSValentin Clement auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1); 31667b5132daSValentin Clement auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1); 31677b5132daSValentin Clement auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1); 31687b5132daSValentin Clement auto ri = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xy, yx); 31697b5132daSValentin Clement auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1); 31707b5132daSValentin Clement auto rr = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, xx, yy); 31717b5132daSValentin Clement auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 31727b5132daSValentin Clement auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0); 31737b5132daSValentin Clement auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1); 31747b5132daSValentin Clement rewriter.replaceOp(mulc, r0.getResult()); 31757b5132daSValentin Clement return success(); 31767b5132daSValentin Clement } 31777b5132daSValentin Clement }; 31787b5132daSValentin Clement 31797b5132daSValentin Clement /// Inlined complex division 31807b5132daSValentin Clement struct DivcOpConversion : public FIROpConversion<fir::DivcOp> { 31817b5132daSValentin Clement using FIROpConversion::FIROpConversion; 31827b5132daSValentin Clement 31837b5132daSValentin Clement mlir::LogicalResult 31847b5132daSValentin Clement matchAndRewrite(fir::DivcOp divc, OpAdaptor adaptor, 31857b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 31867b5132daSValentin Clement // TODO: Can we use a call to __divdc3 instead? 31877b5132daSValentin Clement // Just generate inline code for now. 31887b5132daSValentin Clement // given: (x + iy) / (x' + iy') 31897b5132daSValentin Clement // result: ((xx'+yy')/d) + i((yx'-xy')/d) where d = x'x' + y'y' 31907b5132daSValentin Clement mlir::Value a = adaptor.getOperands()[0]; 31917b5132daSValentin Clement mlir::Value b = adaptor.getOperands()[1]; 31927b5132daSValentin Clement auto loc = divc.getLoc(); 31937b5132daSValentin Clement auto *ctx = divc.getContext(); 31947b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 31957b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 31967b5132daSValentin Clement mlir::Type eleTy = convertType(getComplexEleTy(divc.getType())); 31977b5132daSValentin Clement mlir::Type ty = convertType(divc.getType()); 31987b5132daSValentin Clement auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0); 31997b5132daSValentin Clement auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1); 32007b5132daSValentin Clement auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0); 32017b5132daSValentin Clement auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1); 32027b5132daSValentin Clement auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1); 32037b5132daSValentin Clement auto x1x1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x1, x1); 32047b5132daSValentin Clement auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1); 32057b5132daSValentin Clement auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1); 32067b5132daSValentin Clement auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1); 32077b5132daSValentin Clement auto y1y1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y1, y1); 32087b5132daSValentin Clement auto d = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, x1x1, y1y1); 32097b5132daSValentin Clement auto rrn = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xx, yy); 32107b5132daSValentin Clement auto rin = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, yx, xy); 32117b5132daSValentin Clement auto rr = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rrn, d); 32127b5132daSValentin Clement auto ri = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rin, d); 32137b5132daSValentin Clement auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 32147b5132daSValentin Clement auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0); 32157b5132daSValentin Clement auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1); 32167b5132daSValentin Clement rewriter.replaceOp(divc, r0.getResult()); 32177b5132daSValentin Clement return success(); 32187b5132daSValentin Clement } 32197b5132daSValentin Clement }; 32207b5132daSValentin Clement 32217b5132daSValentin Clement /// Inlined complex negation 32227b5132daSValentin Clement struct NegcOpConversion : public FIROpConversion<fir::NegcOp> { 32237b5132daSValentin Clement using FIROpConversion::FIROpConversion; 32247b5132daSValentin Clement 32257b5132daSValentin Clement mlir::LogicalResult 32267b5132daSValentin Clement matchAndRewrite(fir::NegcOp neg, OpAdaptor adaptor, 32277b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 32287b5132daSValentin Clement // given: -(x + iy) 32297b5132daSValentin Clement // result: -x - iy 32307b5132daSValentin Clement auto *ctxt = neg.getContext(); 32317b5132daSValentin Clement auto eleTy = convertType(getComplexEleTy(neg.getType())); 32327b5132daSValentin Clement auto ty = convertType(neg.getType()); 32337b5132daSValentin Clement auto loc = neg.getLoc(); 32347b5132daSValentin Clement mlir::Value o0 = adaptor.getOperands()[0]; 32357b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0)); 32367b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1)); 32377b5132daSValentin Clement auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c0); 32387b5132daSValentin Clement auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c1); 32397b5132daSValentin Clement auto nrp = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, rp); 32407b5132daSValentin Clement auto nip = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, ip); 32417b5132daSValentin Clement auto r = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, o0, nrp, c0); 32427b5132daSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(neg, ty, r, nip, c1); 32437b5132daSValentin Clement return success(); 32447b5132daSValentin Clement } 32457b5132daSValentin Clement }; 32467b5132daSValentin Clement 32471ed5a90fSValentin Clement /// Conversion pattern for operation that must be dead. The information in these 32481ed5a90fSValentin Clement /// operations is used by other operation. At this point they should not have 32491ed5a90fSValentin Clement /// anymore uses. 32501ed5a90fSValentin Clement /// These operations are normally dead after the pre-codegen pass. 32511ed5a90fSValentin Clement template <typename FromOp> 32521ed5a90fSValentin Clement struct MustBeDeadConversion : public FIROpConversion<FromOp> { 3253013160f6SJean Perier explicit MustBeDeadConversion(fir::LLVMTypeConverter &lowering, 3254013160f6SJean Perier const fir::FIRToLLVMPassOptions &options) 3255013160f6SJean Perier : FIROpConversion<FromOp>(lowering, options) {} 32561ed5a90fSValentin Clement using OpAdaptor = typename FromOp::Adaptor; 32571ed5a90fSValentin Clement 32581ed5a90fSValentin Clement mlir::LogicalResult 32591ed5a90fSValentin Clement matchAndRewrite(FromOp op, OpAdaptor adaptor, 32601ed5a90fSValentin Clement mlir::ConversionPatternRewriter &rewriter) const final { 32611ed5a90fSValentin Clement if (!op->getUses().empty()) 32621ed5a90fSValentin Clement return rewriter.notifyMatchFailure(op, "op must be dead"); 32631ed5a90fSValentin Clement rewriter.eraseOp(op); 32641ed5a90fSValentin Clement return success(); 32651ed5a90fSValentin Clement } 32661ed5a90fSValentin Clement }; 32671ed5a90fSValentin Clement 32681ed5a90fSValentin Clement struct ShapeOpConversion : public MustBeDeadConversion<fir::ShapeOp> { 32691ed5a90fSValentin Clement using MustBeDeadConversion::MustBeDeadConversion; 32701ed5a90fSValentin Clement }; 32711ed5a90fSValentin Clement 32721ed5a90fSValentin Clement struct ShapeShiftOpConversion : public MustBeDeadConversion<fir::ShapeShiftOp> { 32731ed5a90fSValentin Clement using MustBeDeadConversion::MustBeDeadConversion; 32741ed5a90fSValentin Clement }; 32751ed5a90fSValentin Clement 32761ed5a90fSValentin Clement struct ShiftOpConversion : public MustBeDeadConversion<fir::ShiftOp> { 32771ed5a90fSValentin Clement using MustBeDeadConversion::MustBeDeadConversion; 32781ed5a90fSValentin Clement }; 32791ed5a90fSValentin Clement 32801ed5a90fSValentin Clement struct SliceOpConversion : public MustBeDeadConversion<fir::SliceOp> { 32811ed5a90fSValentin Clement using MustBeDeadConversion::MustBeDeadConversion; 32821ed5a90fSValentin Clement }; 32831ed5a90fSValentin Clement 3284044d5b5dSValentin Clement } // namespace 3285044d5b5dSValentin Clement 3286044d5b5dSValentin Clement namespace { 3287044d5b5dSValentin Clement /// Convert FIR dialect to LLVM dialect 3288044d5b5dSValentin Clement /// 3289044d5b5dSValentin Clement /// This pass lowers all FIR dialect operations to LLVM IR dialect. An 3290044d5b5dSValentin Clement /// MLIR pass is used to lower residual Std dialect to LLVM IR dialect. 3291044d5b5dSValentin Clement /// 3292044d5b5dSValentin Clement /// This pass is not complete yet. We are upstreaming it in small patches. 3293044d5b5dSValentin Clement class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> { 3294044d5b5dSValentin Clement public: 3295013160f6SJean Perier FIRToLLVMLowering() = default; 3296013160f6SJean Perier FIRToLLVMLowering(fir::FIRToLLVMPassOptions options) : options{options} {} 3297044d5b5dSValentin Clement mlir::ModuleOp getModule() { return getOperation(); } 3298044d5b5dSValentin Clement 3299044d5b5dSValentin Clement void runOnOperation() override final { 33007b5132daSValentin Clement auto mod = getModule(); 33017b5132daSValentin Clement if (!forcedTargetTriple.empty()) { 33027b5132daSValentin Clement fir::setTargetTriple(mod, forcedTargetTriple); 33037b5132daSValentin Clement } 33047b5132daSValentin Clement 3305044d5b5dSValentin Clement auto *context = getModule().getContext(); 3306044d5b5dSValentin Clement fir::LLVMTypeConverter typeConverter{getModule()}; 33079f85c198SRiver Riddle mlir::RewritePatternSet pattern(context); 3308df3b9810SValentin Clement pattern.insert< 3309420ad7ceSAndrzej Warzynski AbsentOpConversion, AddcOpConversion, AddrOfOpConversion, 3310c2acd453SAlexisPerry AllocaOpConversion, AllocMemOpConversion, BoxAddrOpConversion, 3311c2acd453SAlexisPerry BoxCharLenOpConversion, BoxDimsOpConversion, BoxEleSizeOpConversion, 3312c2acd453SAlexisPerry BoxIsAllocOpConversion, BoxIsArrayOpConversion, BoxIsPtrOpConversion, 3313c2acd453SAlexisPerry BoxProcHostOpConversion, BoxRankOpConversion, BoxTypeDescOpConversion, 3314c2acd453SAlexisPerry CallOpConversion, CmpcOpConversion, ConstcOpConversion, 3315e6e7da55SAndrzej Warzynski ConvertOpConversion, CoordinateOpConversion, DispatchOpConversion, 3316e6e7da55SAndrzej Warzynski DispatchTableOpConversion, DTEntryOpConversion, DivcOpConversion, 3317e6e7da55SAndrzej Warzynski EmboxOpConversion, EmboxCharOpConversion, EmboxProcOpConversion, 3318e6e7da55SAndrzej Warzynski ExtractValueOpConversion, FieldIndexOpConversion, FirEndOpConversion, 3319dc48849fSKiran Chandramohan FreeMemOpConversion, GenTypeDescOpConversion, GlobalLenOpConversion, 3320dc48849fSKiran Chandramohan GlobalOpConversion, HasValueOpConversion, InsertOnRangeOpConversion, 3321e6e7da55SAndrzej Warzynski InsertValueOpConversion, IsPresentOpConversion, 3322dc48849fSKiran Chandramohan LenParamIndexOpConversion, LoadOpConversion, MulcOpConversion, 3323dc48849fSKiran Chandramohan NegcOpConversion, NoReassocOpConversion, SelectCaseOpConversion, 3324e6e7da55SAndrzej Warzynski SelectOpConversion, SelectRankOpConversion, SelectTypeOpConversion, 3325e6e7da55SAndrzej Warzynski ShapeOpConversion, ShapeShiftOpConversion, ShiftOpConversion, 3326e6e7da55SAndrzej Warzynski SliceOpConversion, StoreOpConversion, StringLitOpConversion, 3327e6e7da55SAndrzej Warzynski SubcOpConversion, UnboxCharOpConversion, UnboxProcOpConversion, 3328e6e7da55SAndrzej Warzynski UndefOpConversion, UnreachableOpConversion, XArrayCoorOpConversion, 3329013160f6SJean Perier XEmboxOpConversion, XReboxOpConversion, ZeroOpConversion>(typeConverter, 3330013160f6SJean Perier options); 33315a7b9194SRiver Riddle mlir::populateFuncToLLVMConversionPatterns(typeConverter, pattern); 3332*c6ac9370SKiran Chandramohan mlir::populateOpenMPToLLVMConversionPatterns(typeConverter, pattern); 3333044d5b5dSValentin Clement mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter, 3334044d5b5dSValentin Clement pattern); 3335ace01605SRiver Riddle mlir::cf::populateControlFlowToLLVMConversionPatterns(typeConverter, 3336ace01605SRiver Riddle pattern); 3337044d5b5dSValentin Clement mlir::ConversionTarget target{*context}; 3338044d5b5dSValentin Clement target.addLegalDialect<mlir::LLVM::LLVMDialect>(); 3339*c6ac9370SKiran Chandramohan // The OpenMP dialect is legal for Operations without regions, for those 3340*c6ac9370SKiran Chandramohan // which contains regions it is legal if the region contains only the 3341*c6ac9370SKiran Chandramohan // LLVM dialect. 3342*c6ac9370SKiran Chandramohan target.addDynamicallyLegalOp<mlir::omp::ParallelOp, mlir::omp::WsLoopOp, 3343*c6ac9370SKiran Chandramohan mlir::omp::MasterOp>([&](Operation *op) { 3344*c6ac9370SKiran Chandramohan return typeConverter.isLegal(&op->getRegion(0)); 3345*c6ac9370SKiran Chandramohan }); 3346*c6ac9370SKiran Chandramohan target.addLegalDialect<mlir::omp::OpenMPDialect>(); 3347044d5b5dSValentin Clement 3348044d5b5dSValentin Clement // required NOPs for applying a full conversion 3349044d5b5dSValentin Clement target.addLegalOp<mlir::ModuleOp>(); 3350044d5b5dSValentin Clement 3351044d5b5dSValentin Clement // apply the patterns 3352044d5b5dSValentin Clement if (mlir::failed(mlir::applyFullConversion(getModule(), target, 3353044d5b5dSValentin Clement std::move(pattern)))) { 3354044d5b5dSValentin Clement signalPassFailure(); 3355044d5b5dSValentin Clement } 3356044d5b5dSValentin Clement } 3357013160f6SJean Perier 3358013160f6SJean Perier private: 3359013160f6SJean Perier fir::FIRToLLVMPassOptions options; 3360044d5b5dSValentin Clement }; 3361853e79d8SValentin Clement 3362853e79d8SValentin Clement /// Lower from LLVM IR dialect to proper LLVM-IR and dump the module 3363853e79d8SValentin Clement struct LLVMIRLoweringPass 3364853e79d8SValentin Clement : public mlir::PassWrapper<LLVMIRLoweringPass, 3365853e79d8SValentin Clement mlir::OperationPass<mlir::ModuleOp>> { 3366853e79d8SValentin Clement using Printer = fir::LLVMIRLoweringPrinter; 3367853e79d8SValentin Clement LLVMIRLoweringPass(raw_ostream &output, Printer p) 3368853e79d8SValentin Clement : output{output}, printer{p} {} 3369853e79d8SValentin Clement 3370853e79d8SValentin Clement mlir::ModuleOp getModule() { return getOperation(); } 3371853e79d8SValentin Clement 3372853e79d8SValentin Clement void runOnOperation() override final { 3373853e79d8SValentin Clement auto *ctx = getModule().getContext(); 3374853e79d8SValentin Clement auto optName = getModule().getName(); 3375853e79d8SValentin Clement llvm::LLVMContext llvmCtx; 3376853e79d8SValentin Clement if (auto llvmModule = mlir::translateModuleToLLVMIR( 3377853e79d8SValentin Clement getModule(), llvmCtx, optName ? *optName : "FIRModule")) { 3378853e79d8SValentin Clement printer(*llvmModule, output); 3379853e79d8SValentin Clement return; 3380853e79d8SValentin Clement } 3381853e79d8SValentin Clement 3382853e79d8SValentin Clement mlir::emitError(mlir::UnknownLoc::get(ctx), "could not emit LLVM-IR\n"); 3383853e79d8SValentin Clement signalPassFailure(); 3384853e79d8SValentin Clement } 3385853e79d8SValentin Clement 3386853e79d8SValentin Clement private: 3387853e79d8SValentin Clement raw_ostream &output; 3388853e79d8SValentin Clement Printer printer; 3389853e79d8SValentin Clement }; 3390853e79d8SValentin Clement 3391044d5b5dSValentin Clement } // namespace 3392044d5b5dSValentin Clement 3393044d5b5dSValentin Clement std::unique_ptr<mlir::Pass> fir::createFIRToLLVMPass() { 3394044d5b5dSValentin Clement return std::make_unique<FIRToLLVMLowering>(); 3395044d5b5dSValentin Clement } 3396853e79d8SValentin Clement 3397853e79d8SValentin Clement std::unique_ptr<mlir::Pass> 3398013160f6SJean Perier fir::createFIRToLLVMPass(FIRToLLVMPassOptions options) { 3399013160f6SJean Perier return std::make_unique<FIRToLLVMLowering>(options); 3400013160f6SJean Perier } 3401013160f6SJean Perier 3402013160f6SJean Perier std::unique_ptr<mlir::Pass> 3403853e79d8SValentin Clement fir::createLLVMDialectToLLVMPass(raw_ostream &output, 3404853e79d8SValentin Clement fir::LLVMIRLoweringPrinter printer) { 3405853e79d8SValentin Clement return std::make_unique<LLVMIRLoweringPass>(output, printer); 3406853e79d8SValentin Clement } 3407