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