1044d5b5dSValentin Clement //===-- CodeGen.cpp -- bridge to lower to LLVM ----------------------------===// 2044d5b5dSValentin Clement // 3044d5b5dSValentin Clement // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4044d5b5dSValentin Clement // See https://llvm.org/LICENSE.txt for license information. 5044d5b5dSValentin Clement // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6044d5b5dSValentin Clement // 7044d5b5dSValentin Clement //===----------------------------------------------------------------------===// 8044d5b5dSValentin Clement // 9044d5b5dSValentin Clement // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ 10044d5b5dSValentin Clement // 11044d5b5dSValentin Clement //===----------------------------------------------------------------------===// 12044d5b5dSValentin Clement 13044d5b5dSValentin Clement #include "flang/Optimizer/CodeGen/CodeGen.h" 141f551032SValentin Clement #include "CGOps.h" 15044d5b5dSValentin Clement #include "PassDetail.h" 16b6e44ecdSValentin Clement #include "flang/ISO_Fortran_binding.h" 1739f4ef81SValentin Clement #include "flang/Optimizer/Dialect/FIRAttr.h" 18044d5b5dSValentin Clement #include "flang/Optimizer/Dialect/FIROps.h" 197dd7ccd2SJean Perier #include "flang/Optimizer/Support/InternalNames.h" 20af6ee580SValentin Clement #include "flang/Optimizer/Support/TypeCode.h" 217dd7ccd2SJean Perier #include "flang/Semantics/runtime-type-info.h" 22044d5b5dSValentin Clement #include "mlir/Conversion/ArithmeticToLLVM/ArithmeticToLLVM.h" 23ace01605SRiver Riddle #include "mlir/Conversion/ControlFlowToLLVM/ControlFlowToLLVM.h" 245a7b9194SRiver Riddle #include "mlir/Conversion/FuncToLLVM/ConvertFuncToLLVM.h" 25044d5b5dSValentin Clement #include "mlir/Conversion/LLVMCommon/Pattern.h" 26c6ac9370SKiran Chandramohan #include "mlir/Conversion/OpenMPToLLVM/ConvertOpenMPToLLVM.h" 27044d5b5dSValentin Clement #include "mlir/IR/BuiltinTypes.h" 283ae8e442SValentin Clement #include "mlir/IR/Matchers.h" 29044d5b5dSValentin Clement #include "mlir/Pass/Pass.h" 30853e79d8SValentin Clement #include "mlir/Target/LLVMIR/ModuleTranslation.h" 31044d5b5dSValentin Clement #include "llvm/ADT/ArrayRef.h" 32044d5b5dSValentin Clement 33044d5b5dSValentin Clement #define DEBUG_TYPE "flang-codegen" 34044d5b5dSValentin Clement 35044d5b5dSValentin Clement // fir::LLVMTypeConverter for converting to LLVM IR dialect types. 36044d5b5dSValentin Clement #include "TypeConverter.h" 37044d5b5dSValentin Clement 38af6ee580SValentin Clement // TODO: This should really be recovered from the specified target. 39af6ee580SValentin Clement static constexpr unsigned defaultAlign = 8; 40af6ee580SValentin Clement 41b6e44ecdSValentin Clement /// `fir.box` attribute values as defined for CFI_attribute_t in 42b6e44ecdSValentin Clement /// flang/ISO_Fortran_binding.h. 43b6e44ecdSValentin Clement static constexpr unsigned kAttrPointer = CFI_attribute_pointer; 44b6e44ecdSValentin Clement static constexpr unsigned kAttrAllocatable = CFI_attribute_allocatable; 45b6e44ecdSValentin Clement 46135d5d4aSKiran Chandramohan static inline mlir::Type getVoidPtrType(mlir::MLIRContext *context) { 47fa517555SKiran Chandramohan return mlir::LLVM::LLVMPointerType::get(mlir::IntegerType::get(context, 8)); 48fa517555SKiran Chandramohan } 49fa517555SKiran Chandramohan 501e6d9c06SDiana Picus static mlir::LLVM::ConstantOp 511e6d9c06SDiana Picus genConstantIndex(mlir::Location loc, mlir::Type ity, 521e6d9c06SDiana Picus mlir::ConversionPatternRewriter &rewriter, 531e6d9c06SDiana Picus std::int64_t offset) { 541e6d9c06SDiana Picus auto cattr = rewriter.getI64IntegerAttr(offset); 551e6d9c06SDiana Picus return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr); 561e6d9c06SDiana Picus } 571e6d9c06SDiana Picus 5844e58509SEric Schweitz static mlir::Block *createBlock(mlir::ConversionPatternRewriter &rewriter, 5939f4ef81SValentin Clement mlir::Block *insertBefore) { 6039f4ef81SValentin Clement assert(insertBefore && "expected valid insertion block"); 6139f4ef81SValentin Clement return rewriter.createBlock(insertBefore->getParent(), 6239f4ef81SValentin Clement mlir::Region::iterator(insertBefore)); 6339f4ef81SValentin Clement } 6439f4ef81SValentin Clement 65044d5b5dSValentin Clement namespace { 66044d5b5dSValentin Clement /// FIR conversion pattern template 67044d5b5dSValentin Clement template <typename FromOp> 68044d5b5dSValentin Clement class FIROpConversion : public mlir::ConvertOpToLLVMPattern<FromOp> { 69044d5b5dSValentin Clement public: 70013160f6SJean Perier explicit FIROpConversion(fir::LLVMTypeConverter &lowering, 71013160f6SJean Perier const fir::FIRToLLVMPassOptions &options) 72013160f6SJean Perier : mlir::ConvertOpToLLVMPattern<FromOp>(lowering), options(options) {} 73044d5b5dSValentin Clement 74044d5b5dSValentin Clement protected: 75044d5b5dSValentin Clement mlir::Type convertType(mlir::Type ty) const { 76044d5b5dSValentin Clement return lowerTy().convertType(ty); 77044d5b5dSValentin Clement } 78c2acd453SAlexisPerry mlir::Type voidPtrTy() const { return getVoidPtrType(); } 79044d5b5dSValentin Clement 805d27abe6SValentin Clement mlir::Type getVoidPtrType() const { 815d27abe6SValentin Clement return mlir::LLVM::LLVMPointerType::get( 825d27abe6SValentin Clement mlir::IntegerType::get(&lowerTy().getContext(), 8)); 835d27abe6SValentin Clement } 845d27abe6SValentin Clement 85df3b9810SValentin Clement mlir::LLVM::ConstantOp 86af6ee580SValentin Clement genI32Constant(mlir::Location loc, mlir::ConversionPatternRewriter &rewriter, 87af6ee580SValentin Clement int value) const { 88af6ee580SValentin Clement mlir::Type i32Ty = rewriter.getI32Type(); 89af6ee580SValentin Clement mlir::IntegerAttr attr = rewriter.getI32IntegerAttr(value); 90af6ee580SValentin Clement return rewriter.create<mlir::LLVM::ConstantOp>(loc, i32Ty, attr); 91af6ee580SValentin Clement } 92af6ee580SValentin Clement 93af6ee580SValentin Clement mlir::LLVM::ConstantOp 94df3b9810SValentin Clement genConstantOffset(mlir::Location loc, 95df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter, 96df3b9810SValentin Clement int offset) const { 97af6ee580SValentin Clement mlir::Type ity = lowerTy().offsetType(); 98af6ee580SValentin Clement mlir::IntegerAttr cattr = rewriter.getI32IntegerAttr(offset); 99df3b9810SValentin Clement return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr); 100df3b9810SValentin Clement } 101df3b9810SValentin Clement 102dc48849fSKiran Chandramohan /// Perform an extension or truncation as needed on an integer value. Lowering 103dc48849fSKiran Chandramohan /// to the specific target may involve some sign-extending or truncation of 104dc48849fSKiran Chandramohan /// values, particularly to fit them from abstract box types to the 105dc48849fSKiran Chandramohan /// appropriate reified structures. 106dc48849fSKiran Chandramohan mlir::Value integerCast(mlir::Location loc, 107dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter, 108dc48849fSKiran Chandramohan mlir::Type ty, mlir::Value val) const { 109dc48849fSKiran Chandramohan auto valTy = val.getType(); 110dc48849fSKiran Chandramohan // If the value was not yet lowered, lower its type so that it can 111dc48849fSKiran Chandramohan // be used in getPrimitiveTypeSizeInBits. 112dc48849fSKiran Chandramohan if (!valTy.isa<mlir::IntegerType>()) 113dc48849fSKiran Chandramohan valTy = convertType(valTy); 114dc48849fSKiran Chandramohan auto toSize = mlir::LLVM::getPrimitiveTypeSizeInBits(ty); 115dc48849fSKiran Chandramohan auto fromSize = mlir::LLVM::getPrimitiveTypeSizeInBits(valTy); 116dc48849fSKiran Chandramohan if (toSize < fromSize) 117dc48849fSKiran Chandramohan return rewriter.create<mlir::LLVM::TruncOp>(loc, ty, val); 118dc48849fSKiran Chandramohan if (toSize > fromSize) 119dc48849fSKiran Chandramohan return rewriter.create<mlir::LLVM::SExtOp>(loc, ty, val); 120dc48849fSKiran Chandramohan return val; 121dc48849fSKiran Chandramohan } 122dc48849fSKiran Chandramohan 123b6e44ecdSValentin Clement /// Construct code sequence to extract the specifc value from a `fir.box`. 124b6e44ecdSValentin Clement mlir::Value getValueFromBox(mlir::Location loc, mlir::Value box, 125df3b9810SValentin Clement mlir::Type resultTy, 126b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter, 127b6e44ecdSValentin Clement unsigned boxValue) const { 128df3b9810SValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 129b6e44ecdSValentin Clement mlir::LLVM::ConstantOp cValuePos = 130b6e44ecdSValentin Clement genConstantOffset(loc, rewriter, boxValue); 131df3b9810SValentin Clement auto pty = mlir::LLVM::LLVMPointerType::get(resultTy); 132df3b9810SValentin Clement auto p = rewriter.create<mlir::LLVM::GEPOp>( 13330122656SAlex Zinenko loc, pty, box, mlir::ValueRange{c0, cValuePos}); 134df3b9810SValentin Clement return rewriter.create<mlir::LLVM::LoadOp>(loc, resultTy, p); 135df3b9810SValentin Clement } 136df3b9810SValentin Clement 137df3b9810SValentin Clement /// Method to construct code sequence to get the triple for dimension `dim` 138df3b9810SValentin Clement /// from a box. 13944e58509SEric Schweitz llvm::SmallVector<mlir::Value, 3> 14044e58509SEric Schweitz getDimsFromBox(mlir::Location loc, llvm::ArrayRef<mlir::Type> retTys, 141df3b9810SValentin Clement mlir::Value box, mlir::Value dim, 142df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 143df3b9810SValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 144df3b9810SValentin Clement mlir::LLVM::ConstantOp cDims = 145df3b9810SValentin Clement genConstantOffset(loc, rewriter, kDimsPosInBox); 146df3b9810SValentin Clement mlir::LLVM::LoadOp l0 = 147df3b9810SValentin Clement loadFromOffset(loc, box, c0, cDims, dim, 0, retTys[0], rewriter); 148df3b9810SValentin Clement mlir::LLVM::LoadOp l1 = 149df3b9810SValentin Clement loadFromOffset(loc, box, c0, cDims, dim, 1, retTys[1], rewriter); 150df3b9810SValentin Clement mlir::LLVM::LoadOp l2 = 151df3b9810SValentin Clement loadFromOffset(loc, box, c0, cDims, dim, 2, retTys[2], rewriter); 152df3b9810SValentin Clement return {l0.getResult(), l1.getResult(), l2.getResult()}; 153df3b9810SValentin Clement } 154df3b9810SValentin Clement 155df3b9810SValentin Clement mlir::LLVM::LoadOp 156df3b9810SValentin Clement loadFromOffset(mlir::Location loc, mlir::Value a, mlir::LLVM::ConstantOp c0, 157df3b9810SValentin Clement mlir::LLVM::ConstantOp cDims, mlir::Value dim, int off, 158df3b9810SValentin Clement mlir::Type ty, 159df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 160df3b9810SValentin Clement auto pty = mlir::LLVM::LLVMPointerType::get(ty); 161df3b9810SValentin Clement mlir::LLVM::ConstantOp c = genConstantOffset(loc, rewriter, off); 162df3b9810SValentin Clement mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, a, c0, cDims, dim, c); 163df3b9810SValentin Clement return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p); 164df3b9810SValentin Clement } 165df3b9810SValentin Clement 1665d27abe6SValentin Clement mlir::Value 1675d27abe6SValentin Clement loadStrideFromBox(mlir::Location loc, mlir::Value box, unsigned dim, 1685d27abe6SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 1695d27abe6SValentin Clement auto idxTy = lowerTy().indexType(); 1705d27abe6SValentin Clement auto c0 = genConstantOffset(loc, rewriter, 0); 1715d27abe6SValentin Clement auto cDims = genConstantOffset(loc, rewriter, kDimsPosInBox); 1725d27abe6SValentin Clement auto dimValue = genConstantIndex(loc, idxTy, rewriter, dim); 1735d27abe6SValentin Clement return loadFromOffset(loc, box, c0, cDims, dimValue, kDimStridePos, idxTy, 1745d27abe6SValentin Clement rewriter); 1755d27abe6SValentin Clement } 1765d27abe6SValentin Clement 177df3b9810SValentin Clement /// Read base address from a fir.box. Returned address has type ty. 178df3b9810SValentin Clement mlir::Value 179df3b9810SValentin Clement loadBaseAddrFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box, 180df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 181df3b9810SValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 182df3b9810SValentin Clement mlir::LLVM::ConstantOp cAddr = 183df3b9810SValentin Clement genConstantOffset(loc, rewriter, kAddrPosInBox); 184df3b9810SValentin Clement auto pty = mlir::LLVM::LLVMPointerType::get(ty); 185df3b9810SValentin Clement mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cAddr); 186df3b9810SValentin Clement return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p); 187df3b9810SValentin Clement } 188df3b9810SValentin Clement 189df3b9810SValentin Clement mlir::Value 190df3b9810SValentin Clement loadElementSizeFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box, 191df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 192df3b9810SValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 193df3b9810SValentin Clement mlir::LLVM::ConstantOp cElemLen = 194df3b9810SValentin Clement genConstantOffset(loc, rewriter, kElemLenPosInBox); 195df3b9810SValentin Clement auto pty = mlir::LLVM::LLVMPointerType::get(ty); 196df3b9810SValentin Clement mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cElemLen); 197df3b9810SValentin Clement return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p); 198df3b9810SValentin Clement } 199df3b9810SValentin Clement 200af6ee580SValentin Clement // Get the element type given an LLVM type that is of the form 201af6ee580SValentin Clement // [llvm.ptr](array|struct|vector)+ and the provided indexes. 202af6ee580SValentin Clement static mlir::Type getBoxEleTy(mlir::Type type, 203af6ee580SValentin Clement llvm::ArrayRef<unsigned> indexes) { 204af6ee580SValentin Clement if (auto t = type.dyn_cast<mlir::LLVM::LLVMPointerType>()) 205af6ee580SValentin Clement type = t.getElementType(); 206af6ee580SValentin Clement for (auto i : indexes) { 207af6ee580SValentin Clement if (auto t = type.dyn_cast<mlir::LLVM::LLVMStructType>()) { 208af6ee580SValentin Clement assert(!t.isOpaque() && i < t.getBody().size()); 209af6ee580SValentin Clement type = t.getBody()[i]; 210af6ee580SValentin Clement } else if (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) { 211af6ee580SValentin Clement type = t.getElementType(); 212af6ee580SValentin Clement } else if (auto t = type.dyn_cast<mlir::VectorType>()) { 213af6ee580SValentin Clement type = t.getElementType(); 214af6ee580SValentin Clement } else { 215af6ee580SValentin Clement fir::emitFatalError(mlir::UnknownLoc::get(type.getContext()), 216af6ee580SValentin Clement "request for invalid box element type"); 217af6ee580SValentin Clement } 218af6ee580SValentin Clement } 219af6ee580SValentin Clement return type; 220af6ee580SValentin Clement } 221af6ee580SValentin Clement 2225d27abe6SValentin Clement // Return LLVM type of the base address given the LLVM type 2235d27abe6SValentin Clement // of the related descriptor (lowered fir.box type). 2245d27abe6SValentin Clement static mlir::Type getBaseAddrTypeFromBox(mlir::Type type) { 2255d27abe6SValentin Clement return getBoxEleTy(type, {kAddrPosInBox}); 2265d27abe6SValentin Clement } 2275d27abe6SValentin Clement 228dc48849fSKiran Chandramohan // Load the attribute from the \p box and perform a check against \p maskValue 229dc48849fSKiran Chandramohan // The final comparison is implemented as `(attribute & maskValue) != 0`. 230dc48849fSKiran Chandramohan mlir::Value genBoxAttributeCheck(mlir::Location loc, mlir::Value box, 231dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter, 232dc48849fSKiran Chandramohan unsigned maskValue) const { 233dc48849fSKiran Chandramohan mlir::Type attrTy = rewriter.getI32Type(); 234dc48849fSKiran Chandramohan mlir::Value attribute = 235dc48849fSKiran Chandramohan getValueFromBox(loc, box, attrTy, rewriter, kAttributePosInBox); 236dc48849fSKiran Chandramohan mlir::LLVM::ConstantOp attrMask = 237dc48849fSKiran Chandramohan genConstantOffset(loc, rewriter, maskValue); 238dc48849fSKiran Chandramohan auto maskRes = 239dc48849fSKiran Chandramohan rewriter.create<mlir::LLVM::AndOp>(loc, attrTy, attribute, attrMask); 240dc48849fSKiran Chandramohan mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 241dc48849fSKiran Chandramohan return rewriter.create<mlir::LLVM::ICmpOp>( 242dc48849fSKiran Chandramohan loc, mlir::LLVM::ICmpPredicate::ne, maskRes, c0); 243dc48849fSKiran Chandramohan } 244dc48849fSKiran Chandramohan 245df3b9810SValentin Clement template <typename... ARGS> 246df3b9810SValentin Clement mlir::LLVM::GEPOp genGEP(mlir::Location loc, mlir::Type ty, 247df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter, 248df3b9810SValentin Clement mlir::Value base, ARGS... args) const { 249575c9d6dSValentin Clement llvm::SmallVector<mlir::Value> cv = {args...}; 250df3b9810SValentin Clement return rewriter.create<mlir::LLVM::GEPOp>(loc, ty, base, cv); 251df3b9810SValentin Clement } 252df3b9810SValentin Clement 253044d5b5dSValentin Clement fir::LLVMTypeConverter &lowerTy() const { 254044d5b5dSValentin Clement return *static_cast<fir::LLVMTypeConverter *>(this->getTypeConverter()); 255044d5b5dSValentin Clement } 256013160f6SJean Perier 257013160f6SJean Perier const fir::FIRToLLVMPassOptions &options; 258044d5b5dSValentin Clement }; 259044d5b5dSValentin Clement 2603ae8e442SValentin Clement /// FIR conversion pattern template 2613ae8e442SValentin Clement template <typename FromOp> 2623ae8e442SValentin Clement class FIROpAndTypeConversion : public FIROpConversion<FromOp> { 2633ae8e442SValentin Clement public: 2643ae8e442SValentin Clement using FIROpConversion<FromOp>::FIROpConversion; 2653ae8e442SValentin Clement using OpAdaptor = typename FromOp::Adaptor; 2663ae8e442SValentin Clement 2673ae8e442SValentin Clement mlir::LogicalResult 2683ae8e442SValentin Clement matchAndRewrite(FromOp op, OpAdaptor adaptor, 2693ae8e442SValentin Clement mlir::ConversionPatternRewriter &rewriter) const final { 2703ae8e442SValentin Clement mlir::Type ty = this->convertType(op.getType()); 2713ae8e442SValentin Clement return doRewrite(op, ty, adaptor, rewriter); 2723ae8e442SValentin Clement } 2733ae8e442SValentin Clement 2743ae8e442SValentin Clement virtual mlir::LogicalResult 2753ae8e442SValentin Clement doRewrite(FromOp addr, mlir::Type ty, OpAdaptor adaptor, 2763ae8e442SValentin Clement mlir::ConversionPatternRewriter &rewriter) const = 0; 2773ae8e442SValentin Clement }; 278575c9d6dSValentin Clement } // namespace 2793ae8e442SValentin Clement 280575c9d6dSValentin Clement namespace { 281575c9d6dSValentin Clement /// Lower `fir.address_of` operation to `llvm.address_of` operation. 282044d5b5dSValentin Clement struct AddrOfOpConversion : public FIROpConversion<fir::AddrOfOp> { 283044d5b5dSValentin Clement using FIROpConversion::FIROpConversion; 284044d5b5dSValentin Clement 285044d5b5dSValentin Clement mlir::LogicalResult 286044d5b5dSValentin Clement matchAndRewrite(fir::AddrOfOp addr, OpAdaptor adaptor, 287044d5b5dSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 288044d5b5dSValentin Clement auto ty = convertType(addr.getType()); 289044d5b5dSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::AddressOfOp>( 290149ad3d5SShraiysh Vaishay addr, ty, addr.getSymbol().getRootReference().getValue()); 29144e58509SEric Schweitz return mlir::success(); 292044d5b5dSValentin Clement } 293044d5b5dSValentin Clement }; 2941e6d9c06SDiana Picus } // namespace 2951e6d9c06SDiana Picus 2961e6d9c06SDiana Picus /// Lookup the function to compute the memory size of this parametric derived 2971e6d9c06SDiana Picus /// type. The size of the object may depend on the LEN type parameters of the 2981e6d9c06SDiana Picus /// derived type. 2991e6d9c06SDiana Picus static mlir::LLVM::LLVMFuncOp 3001e6d9c06SDiana Picus getDependentTypeMemSizeFn(fir::RecordType recTy, fir::AllocaOp op, 3011e6d9c06SDiana Picus mlir::ConversionPatternRewriter &rewriter) { 3021e6d9c06SDiana Picus auto module = op->getParentOfType<mlir::ModuleOp>(); 3031e6d9c06SDiana Picus std::string name = recTy.getName().str() + "P.mem.size"; 304575c9d6dSValentin Clement if (auto memSizeFunc = module.lookupSymbol<mlir::LLVM::LLVMFuncOp>(name)) 305575c9d6dSValentin Clement return memSizeFunc; 306575c9d6dSValentin Clement TODO(op.getLoc(), "did not find allocation function"); 3071e6d9c06SDiana Picus } 3081e6d9c06SDiana Picus 309ac0f4c8fSPeixinQiao // Compute the alloc scale size (constant factors encoded in the array type). 310ac0f4c8fSPeixinQiao // We do this for arrays without a constant interior or arrays of character with 311ac0f4c8fSPeixinQiao // dynamic length arrays, since those are the only ones that get decayed to a 312ac0f4c8fSPeixinQiao // pointer to the element type. 313ac0f4c8fSPeixinQiao template <typename OP> 314ac0f4c8fSPeixinQiao static mlir::Value 315ac0f4c8fSPeixinQiao genAllocationScaleSize(OP op, mlir::Type ity, 316ac0f4c8fSPeixinQiao mlir::ConversionPatternRewriter &rewriter) { 317ac0f4c8fSPeixinQiao mlir::Location loc = op.getLoc(); 318ac0f4c8fSPeixinQiao mlir::Type dataTy = op.getInType(); 319ac0f4c8fSPeixinQiao mlir::Type scalarType = fir::unwrapSequenceType(dataTy); 320ac0f4c8fSPeixinQiao auto seqTy = dataTy.dyn_cast<fir::SequenceType>(); 321ac0f4c8fSPeixinQiao if ((op.hasShapeOperands() && seqTy && !seqTy.hasConstantInterior()) || 322ac0f4c8fSPeixinQiao (seqTy && fir::characterWithDynamicLen(scalarType))) { 323ac0f4c8fSPeixinQiao fir::SequenceType::Extent constSize = 1; 324ac0f4c8fSPeixinQiao for (auto extent : seqTy.getShape()) 325ac0f4c8fSPeixinQiao if (extent != fir::SequenceType::getUnknownExtent()) 326ac0f4c8fSPeixinQiao constSize *= extent; 327ac0f4c8fSPeixinQiao if (constSize != 1) { 328ac0f4c8fSPeixinQiao mlir::Value constVal{ 329ac0f4c8fSPeixinQiao genConstantIndex(loc, ity, rewriter, constSize).getResult()}; 330ac0f4c8fSPeixinQiao return constVal; 331ac0f4c8fSPeixinQiao } 332ac0f4c8fSPeixinQiao } 333ac0f4c8fSPeixinQiao return nullptr; 334ac0f4c8fSPeixinQiao } 335ac0f4c8fSPeixinQiao 3361e6d9c06SDiana Picus namespace { 3371e6d9c06SDiana Picus /// convert to LLVM IR dialect `alloca` 3381e6d9c06SDiana Picus struct AllocaOpConversion : public FIROpConversion<fir::AllocaOp> { 3391e6d9c06SDiana Picus using FIROpConversion::FIROpConversion; 3401e6d9c06SDiana Picus 3411e6d9c06SDiana Picus mlir::LogicalResult 3421e6d9c06SDiana Picus matchAndRewrite(fir::AllocaOp alloc, OpAdaptor adaptor, 3431e6d9c06SDiana Picus mlir::ConversionPatternRewriter &rewriter) const override { 3441e6d9c06SDiana Picus mlir::ValueRange operands = adaptor.getOperands(); 3451e6d9c06SDiana Picus auto loc = alloc.getLoc(); 3461e6d9c06SDiana Picus mlir::Type ity = lowerTy().indexType(); 3471e6d9c06SDiana Picus unsigned i = 0; 3481e6d9c06SDiana Picus mlir::Value size = genConstantIndex(loc, ity, rewriter, 1).getResult(); 3491e6d9c06SDiana Picus mlir::Type ty = convertType(alloc.getType()); 3501e6d9c06SDiana Picus mlir::Type resultTy = ty; 3511e6d9c06SDiana Picus if (alloc.hasLenParams()) { 3521e6d9c06SDiana Picus unsigned end = alloc.numLenParams(); 3531e6d9c06SDiana Picus llvm::SmallVector<mlir::Value> lenParams; 3541e6d9c06SDiana Picus for (; i < end; ++i) 3551e6d9c06SDiana Picus lenParams.push_back(operands[i]); 3561e6d9c06SDiana Picus mlir::Type scalarType = fir::unwrapSequenceType(alloc.getInType()); 3571e6d9c06SDiana Picus if (auto chrTy = scalarType.dyn_cast<fir::CharacterType>()) { 3581e6d9c06SDiana Picus fir::CharacterType rawCharTy = fir::CharacterType::getUnknownLen( 3591e6d9c06SDiana Picus chrTy.getContext(), chrTy.getFKind()); 3601e6d9c06SDiana Picus ty = mlir::LLVM::LLVMPointerType::get(convertType(rawCharTy)); 3611e6d9c06SDiana Picus assert(end == 1); 3621e6d9c06SDiana Picus size = integerCast(loc, rewriter, ity, lenParams[0]); 3631e6d9c06SDiana Picus } else if (auto recTy = scalarType.dyn_cast<fir::RecordType>()) { 3641e6d9c06SDiana Picus mlir::LLVM::LLVMFuncOp memSizeFn = 3651e6d9c06SDiana Picus getDependentTypeMemSizeFn(recTy, alloc, rewriter); 3661e6d9c06SDiana Picus if (!memSizeFn) 3671e6d9c06SDiana Picus emitError(loc, "did not find allocation function"); 3681e6d9c06SDiana Picus mlir::NamedAttribute attr = rewriter.getNamedAttr( 3691e6d9c06SDiana Picus "callee", mlir::SymbolRefAttr::get(memSizeFn)); 3701e6d9c06SDiana Picus auto call = rewriter.create<mlir::LLVM::CallOp>( 3711e6d9c06SDiana Picus loc, ity, lenParams, llvm::ArrayRef<mlir::NamedAttribute>{attr}); 3721e6d9c06SDiana Picus size = call.getResult(0); 373575c9d6dSValentin Clement ty = ::getVoidPtrType(alloc.getContext()); 3741e6d9c06SDiana Picus } else { 3751e6d9c06SDiana Picus return emitError(loc, "unexpected type ") 3761e6d9c06SDiana Picus << scalarType << " with type parameters"; 3771e6d9c06SDiana Picus } 3781e6d9c06SDiana Picus } 379ac0f4c8fSPeixinQiao if (auto scaleSize = genAllocationScaleSize(alloc, ity, rewriter)) 380ac0f4c8fSPeixinQiao size = rewriter.create<mlir::LLVM::MulOp>(loc, ity, size, scaleSize); 3811e6d9c06SDiana Picus if (alloc.hasShapeOperands()) { 3821e6d9c06SDiana Picus unsigned end = operands.size(); 3831e6d9c06SDiana Picus for (; i < end; ++i) 3841e6d9c06SDiana Picus size = rewriter.create<mlir::LLVM::MulOp>( 3851e6d9c06SDiana Picus loc, ity, size, integerCast(loc, rewriter, ity, operands[i])); 3861e6d9c06SDiana Picus } 3871e6d9c06SDiana Picus if (ty == resultTy) { 3881e6d9c06SDiana Picus // Do not emit the bitcast if ty and resultTy are the same. 3891e6d9c06SDiana Picus rewriter.replaceOpWithNewOp<mlir::LLVM::AllocaOp>(alloc, ty, size, 3901e6d9c06SDiana Picus alloc->getAttrs()); 3911e6d9c06SDiana Picus } else { 3921e6d9c06SDiana Picus auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, ty, size, 3931e6d9c06SDiana Picus alloc->getAttrs()); 3941e6d9c06SDiana Picus rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(alloc, resultTy, al); 3951e6d9c06SDiana Picus } 39644e58509SEric Schweitz return mlir::success(); 3971e6d9c06SDiana Picus } 3981e6d9c06SDiana Picus }; 399dc48849fSKiran Chandramohan } // namespace 400044d5b5dSValentin Clement 401dc48849fSKiran Chandramohan /// Construct an `llvm.extractvalue` instruction. It will return value at 402dc48849fSKiran Chandramohan /// element \p x from \p tuple. 403dc48849fSKiran Chandramohan static mlir::LLVM::ExtractValueOp 404dc48849fSKiran Chandramohan genExtractValueWithIndex(mlir::Location loc, mlir::Value tuple, mlir::Type ty, 405dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter, 406dc48849fSKiran Chandramohan mlir::MLIRContext *ctx, int x) { 407dc48849fSKiran Chandramohan auto cx = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(x)); 408dc48849fSKiran Chandramohan auto xty = ty.cast<mlir::LLVM::LLVMStructType>().getBody()[x]; 409dc48849fSKiran Chandramohan return rewriter.create<mlir::LLVM::ExtractValueOp>(loc, xty, tuple, cx); 410dc48849fSKiran Chandramohan } 411dc48849fSKiran Chandramohan 412dc48849fSKiran Chandramohan namespace { 413df3b9810SValentin Clement /// Lower `fir.box_addr` to the sequence of operations to extract the first 414df3b9810SValentin Clement /// element of the box. 415df3b9810SValentin Clement struct BoxAddrOpConversion : public FIROpConversion<fir::BoxAddrOp> { 416df3b9810SValentin Clement using FIROpConversion::FIROpConversion; 417df3b9810SValentin Clement 418df3b9810SValentin Clement mlir::LogicalResult 419df3b9810SValentin Clement matchAndRewrite(fir::BoxAddrOp boxaddr, OpAdaptor adaptor, 420df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 421df3b9810SValentin Clement mlir::Value a = adaptor.getOperands()[0]; 422df3b9810SValentin Clement auto loc = boxaddr.getLoc(); 423df3b9810SValentin Clement mlir::Type ty = convertType(boxaddr.getType()); 424149ad3d5SShraiysh Vaishay if (auto argty = boxaddr.getVal().getType().dyn_cast<fir::BoxType>()) { 425df3b9810SValentin Clement rewriter.replaceOp(boxaddr, loadBaseAddrFromBox(loc, ty, a, rewriter)); 426df3b9810SValentin Clement } else { 427df3b9810SValentin Clement auto c0attr = rewriter.getI32IntegerAttr(0); 428df3b9810SValentin Clement auto c0 = mlir::ArrayAttr::get(boxaddr.getContext(), c0attr); 429df3b9810SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(boxaddr, ty, a, 430df3b9810SValentin Clement c0); 431df3b9810SValentin Clement } 43244e58509SEric Schweitz return mlir::success(); 433df3b9810SValentin Clement } 434df3b9810SValentin Clement }; 435df3b9810SValentin Clement 436dc48849fSKiran Chandramohan /// Convert `!fir.boxchar_len` to `!llvm.extractvalue` for the 2nd part of the 437dc48849fSKiran Chandramohan /// boxchar. 438dc48849fSKiran Chandramohan struct BoxCharLenOpConversion : public FIROpConversion<fir::BoxCharLenOp> { 439dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 440dc48849fSKiran Chandramohan 441dc48849fSKiran Chandramohan mlir::LogicalResult 442dc48849fSKiran Chandramohan matchAndRewrite(fir::BoxCharLenOp boxCharLen, OpAdaptor adaptor, 443dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 444dc48849fSKiran Chandramohan mlir::Value boxChar = adaptor.getOperands()[0]; 445dc48849fSKiran Chandramohan mlir::Location loc = boxChar.getLoc(); 446dc48849fSKiran Chandramohan mlir::MLIRContext *ctx = boxChar.getContext(); 447dc48849fSKiran Chandramohan mlir::Type returnValTy = boxCharLen.getResult().getType(); 448dc48849fSKiran Chandramohan 449dc48849fSKiran Chandramohan constexpr int boxcharLenIdx = 1; 450dc48849fSKiran Chandramohan mlir::LLVM::ExtractValueOp len = genExtractValueWithIndex( 451dc48849fSKiran Chandramohan loc, boxChar, boxChar.getType(), rewriter, ctx, boxcharLenIdx); 452dc48849fSKiran Chandramohan mlir::Value lenAfterCast = integerCast(loc, rewriter, returnValTy, len); 453dc48849fSKiran Chandramohan rewriter.replaceOp(boxCharLen, lenAfterCast); 454dc48849fSKiran Chandramohan 45544e58509SEric Schweitz return mlir::success(); 456dc48849fSKiran Chandramohan } 457dc48849fSKiran Chandramohan }; 458dc48849fSKiran Chandramohan 459df3b9810SValentin Clement /// Lower `fir.box_dims` to a sequence of operations to extract the requested 460df3b9810SValentin Clement /// dimension infomartion from the boxed value. 461df3b9810SValentin Clement /// Result in a triple set of GEPs and loads. 462df3b9810SValentin Clement struct BoxDimsOpConversion : public FIROpConversion<fir::BoxDimsOp> { 463df3b9810SValentin Clement using FIROpConversion::FIROpConversion; 464df3b9810SValentin Clement 465df3b9810SValentin Clement mlir::LogicalResult 466df3b9810SValentin Clement matchAndRewrite(fir::BoxDimsOp boxdims, OpAdaptor adaptor, 467df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 46844e58509SEric Schweitz llvm::SmallVector<mlir::Type, 3> resultTypes = { 469df3b9810SValentin Clement convertType(boxdims.getResult(0).getType()), 470df3b9810SValentin Clement convertType(boxdims.getResult(1).getType()), 471df3b9810SValentin Clement convertType(boxdims.getResult(2).getType()), 472df3b9810SValentin Clement }; 473df3b9810SValentin Clement auto results = 474df3b9810SValentin Clement getDimsFromBox(boxdims.getLoc(), resultTypes, adaptor.getOperands()[0], 475df3b9810SValentin Clement adaptor.getOperands()[1], rewriter); 476df3b9810SValentin Clement rewriter.replaceOp(boxdims, results); 47744e58509SEric Schweitz return mlir::success(); 478df3b9810SValentin Clement } 479df3b9810SValentin Clement }; 480df3b9810SValentin Clement 481df3b9810SValentin Clement /// Lower `fir.box_elesize` to a sequence of operations ro extract the size of 482df3b9810SValentin Clement /// an element in the boxed value. 483df3b9810SValentin Clement struct BoxEleSizeOpConversion : public FIROpConversion<fir::BoxEleSizeOp> { 484df3b9810SValentin Clement using FIROpConversion::FIROpConversion; 485df3b9810SValentin Clement 486df3b9810SValentin Clement mlir::LogicalResult 487df3b9810SValentin Clement matchAndRewrite(fir::BoxEleSizeOp boxelesz, OpAdaptor adaptor, 488df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 489df3b9810SValentin Clement mlir::Value a = adaptor.getOperands()[0]; 490df3b9810SValentin Clement auto loc = boxelesz.getLoc(); 491df3b9810SValentin Clement auto ty = convertType(boxelesz.getType()); 492b6e44ecdSValentin Clement auto elemSize = getValueFromBox(loc, a, ty, rewriter, kElemLenPosInBox); 493b6e44ecdSValentin Clement rewriter.replaceOp(boxelesz, elemSize); 49444e58509SEric Schweitz return mlir::success(); 495b6e44ecdSValentin Clement } 496b6e44ecdSValentin Clement }; 497b6e44ecdSValentin Clement 498b6e44ecdSValentin Clement /// Lower `fir.box_isalloc` to a sequence of operations to determine if the 499b6e44ecdSValentin Clement /// boxed value was from an ALLOCATABLE entity. 500b6e44ecdSValentin Clement struct BoxIsAllocOpConversion : public FIROpConversion<fir::BoxIsAllocOp> { 501b6e44ecdSValentin Clement using FIROpConversion::FIROpConversion; 502b6e44ecdSValentin Clement 503b6e44ecdSValentin Clement mlir::LogicalResult 504b6e44ecdSValentin Clement matchAndRewrite(fir::BoxIsAllocOp boxisalloc, OpAdaptor adaptor, 505b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 506b6e44ecdSValentin Clement mlir::Value box = adaptor.getOperands()[0]; 507b6e44ecdSValentin Clement auto loc = boxisalloc.getLoc(); 508b6e44ecdSValentin Clement mlir::Value check = 509b6e44ecdSValentin Clement genBoxAttributeCheck(loc, box, rewriter, kAttrAllocatable); 510b6e44ecdSValentin Clement rewriter.replaceOp(boxisalloc, check); 51144e58509SEric Schweitz return mlir::success(); 512b6e44ecdSValentin Clement } 513b6e44ecdSValentin Clement }; 514b6e44ecdSValentin Clement 515b6e44ecdSValentin Clement /// Lower `fir.box_isarray` to a sequence of operations to determine if the 516b6e44ecdSValentin Clement /// boxed is an array. 517b6e44ecdSValentin Clement struct BoxIsArrayOpConversion : public FIROpConversion<fir::BoxIsArrayOp> { 518b6e44ecdSValentin Clement using FIROpConversion::FIROpConversion; 519b6e44ecdSValentin Clement 520b6e44ecdSValentin Clement mlir::LogicalResult 521b6e44ecdSValentin Clement matchAndRewrite(fir::BoxIsArrayOp boxisarray, OpAdaptor adaptor, 522b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 523b6e44ecdSValentin Clement mlir::Value a = adaptor.getOperands()[0]; 524b6e44ecdSValentin Clement auto loc = boxisarray.getLoc(); 525b6e44ecdSValentin Clement auto rank = 526b6e44ecdSValentin Clement getValueFromBox(loc, a, rewriter.getI32Type(), rewriter, kRankPosInBox); 527b6e44ecdSValentin Clement auto c0 = genConstantOffset(loc, rewriter, 0); 528b6e44ecdSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>( 529b6e44ecdSValentin Clement boxisarray, mlir::LLVM::ICmpPredicate::ne, rank, c0); 53044e58509SEric Schweitz return mlir::success(); 531b6e44ecdSValentin Clement } 532b6e44ecdSValentin Clement }; 533b6e44ecdSValentin Clement 534b6e44ecdSValentin Clement /// Lower `fir.box_isptr` to a sequence of operations to determined if the 535b6e44ecdSValentin Clement /// boxed value was from a POINTER entity. 536b6e44ecdSValentin Clement struct BoxIsPtrOpConversion : public FIROpConversion<fir::BoxIsPtrOp> { 537b6e44ecdSValentin Clement using FIROpConversion::FIROpConversion; 538b6e44ecdSValentin Clement 539b6e44ecdSValentin Clement mlir::LogicalResult 540b6e44ecdSValentin Clement matchAndRewrite(fir::BoxIsPtrOp boxisptr, OpAdaptor adaptor, 541b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 542b6e44ecdSValentin Clement mlir::Value box = adaptor.getOperands()[0]; 543b6e44ecdSValentin Clement auto loc = boxisptr.getLoc(); 544b6e44ecdSValentin Clement mlir::Value check = genBoxAttributeCheck(loc, box, rewriter, kAttrPointer); 545b6e44ecdSValentin Clement rewriter.replaceOp(boxisptr, check); 54644e58509SEric Schweitz return mlir::success(); 547df3b9810SValentin Clement } 548df3b9810SValentin Clement }; 549df3b9810SValentin Clement 550df3b9810SValentin Clement /// Lower `fir.box_rank` to the sequence of operation to extract the rank from 551df3b9810SValentin Clement /// the box. 552df3b9810SValentin Clement struct BoxRankOpConversion : public FIROpConversion<fir::BoxRankOp> { 553df3b9810SValentin Clement using FIROpConversion::FIROpConversion; 554df3b9810SValentin Clement 555df3b9810SValentin Clement mlir::LogicalResult 556df3b9810SValentin Clement matchAndRewrite(fir::BoxRankOp boxrank, OpAdaptor adaptor, 557df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 558df3b9810SValentin Clement mlir::Value a = adaptor.getOperands()[0]; 559df3b9810SValentin Clement auto loc = boxrank.getLoc(); 560df3b9810SValentin Clement mlir::Type ty = convertType(boxrank.getType()); 561b6e44ecdSValentin Clement auto result = getValueFromBox(loc, a, ty, rewriter, kRankPosInBox); 562df3b9810SValentin Clement rewriter.replaceOp(boxrank, result); 56344e58509SEric Schweitz return mlir::success(); 564df3b9810SValentin Clement } 565df3b9810SValentin Clement }; 566df3b9810SValentin Clement 567cc505c0bSKiran Chandramohan /// Lower `fir.boxproc_host` operation. Extracts the host pointer from the 568cc505c0bSKiran Chandramohan /// boxproc. 569cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers. 570cc505c0bSKiran Chandramohan struct BoxProcHostOpConversion : public FIROpConversion<fir::BoxProcHostOp> { 571cc505c0bSKiran Chandramohan using FIROpConversion::FIROpConversion; 572cc505c0bSKiran Chandramohan 573cc505c0bSKiran Chandramohan mlir::LogicalResult 574cc505c0bSKiran Chandramohan matchAndRewrite(fir::BoxProcHostOp boxprochost, OpAdaptor adaptor, 575cc505c0bSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 5767ce8c6fcSKiran Chandramohan TODO(boxprochost.getLoc(), "fir.boxproc_host codegen"); 57744e58509SEric Schweitz return mlir::failure(); 578cc505c0bSKiran Chandramohan } 579cc505c0bSKiran Chandramohan }; 580cc505c0bSKiran Chandramohan 581e38ef2ffSValentin Clement /// Lower `fir.box_tdesc` to the sequence of operations to extract the type 582e38ef2ffSValentin Clement /// descriptor from the box. 583e38ef2ffSValentin Clement struct BoxTypeDescOpConversion : public FIROpConversion<fir::BoxTypeDescOp> { 584e38ef2ffSValentin Clement using FIROpConversion::FIROpConversion; 585e38ef2ffSValentin Clement 586e38ef2ffSValentin Clement mlir::LogicalResult 587e38ef2ffSValentin Clement matchAndRewrite(fir::BoxTypeDescOp boxtypedesc, OpAdaptor adaptor, 588e38ef2ffSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 589e38ef2ffSValentin Clement mlir::Value box = adaptor.getOperands()[0]; 590e38ef2ffSValentin Clement auto loc = boxtypedesc.getLoc(); 591e38ef2ffSValentin Clement mlir::Type typeTy = 592e38ef2ffSValentin Clement fir::getDescFieldTypeModel<kTypePosInBox>()(boxtypedesc.getContext()); 593e38ef2ffSValentin Clement auto result = getValueFromBox(loc, box, typeTy, rewriter, kTypePosInBox); 594e38ef2ffSValentin Clement auto typePtrTy = mlir::LLVM::LLVMPointerType::get(typeTy); 595e38ef2ffSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(boxtypedesc, typePtrTy, 596e38ef2ffSValentin Clement result); 59744e58509SEric Schweitz return mlir::success(); 598e38ef2ffSValentin Clement } 599e38ef2ffSValentin Clement }; 600e38ef2ffSValentin Clement 601dc48849fSKiran Chandramohan /// Lower `fir.string_lit` to LLVM IR dialect operation. 602dc48849fSKiran Chandramohan struct StringLitOpConversion : public FIROpConversion<fir::StringLitOp> { 603dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 604dc48849fSKiran Chandramohan 605dc48849fSKiran Chandramohan mlir::LogicalResult 606dc48849fSKiran Chandramohan matchAndRewrite(fir::StringLitOp constop, OpAdaptor adaptor, 607dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 608dc48849fSKiran Chandramohan auto ty = convertType(constop.getType()); 609dc48849fSKiran Chandramohan auto attr = constop.getValue(); 610dc48849fSKiran Chandramohan if (attr.isa<mlir::StringAttr>()) { 611dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(constop, ty, attr); 61244e58509SEric Schweitz return mlir::success(); 613dc48849fSKiran Chandramohan } 614dc48849fSKiran Chandramohan 615dc48849fSKiran Chandramohan auto charTy = constop.getType().cast<fir::CharacterType>(); 616dc48849fSKiran Chandramohan unsigned bits = lowerTy().characterBitsize(charTy); 617dc48849fSKiran Chandramohan mlir::Type intTy = rewriter.getIntegerType(bits); 618e0c782bdSValentin Clement mlir::Location loc = constop.getLoc(); 619e0c782bdSValentin Clement mlir::Value cst = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 620e0c782bdSValentin Clement if (auto arr = attr.dyn_cast<mlir::DenseElementsAttr>()) { 621e0c782bdSValentin Clement cst = rewriter.create<mlir::LLVM::ConstantOp>(loc, ty, arr); 622e0c782bdSValentin Clement } else if (auto arr = attr.dyn_cast<mlir::ArrayAttr>()) { 623e0c782bdSValentin Clement for (auto a : llvm::enumerate(arr.getValue())) { 624e0c782bdSValentin Clement // convert each character to a precise bitsize 625e0c782bdSValentin Clement auto elemAttr = mlir::IntegerAttr::get( 626dc48849fSKiran Chandramohan intTy, 627e0c782bdSValentin Clement a.value().cast<mlir::IntegerAttr>().getValue().zextOrTrunc(bits)); 628e0c782bdSValentin Clement auto elemCst = 629e0c782bdSValentin Clement rewriter.create<mlir::LLVM::ConstantOp>(loc, intTy, elemAttr); 630e0c782bdSValentin Clement auto index = mlir::ArrayAttr::get( 631e0c782bdSValentin Clement constop.getContext(), rewriter.getI32IntegerAttr(a.index())); 632e0c782bdSValentin Clement cst = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, cst, elemCst, 633e0c782bdSValentin Clement index); 634e0c782bdSValentin Clement } 635e0c782bdSValentin Clement } else { 63644e58509SEric Schweitz return mlir::failure(); 637e0c782bdSValentin Clement } 638e0c782bdSValentin Clement rewriter.replaceOp(constop, cst); 63944e58509SEric Schweitz return mlir::success(); 640dc48849fSKiran Chandramohan } 641dc48849fSKiran Chandramohan }; 642dc48849fSKiran Chandramohan 643575c9d6dSValentin Clement /// `fir.call` -> `llvm.call` 644ddd11b9aSAndrzej Warzynski struct CallOpConversion : public FIROpConversion<fir::CallOp> { 645ddd11b9aSAndrzej Warzynski using FIROpConversion::FIROpConversion; 646ddd11b9aSAndrzej Warzynski 647ddd11b9aSAndrzej Warzynski mlir::LogicalResult 648ddd11b9aSAndrzej Warzynski matchAndRewrite(fir::CallOp call, OpAdaptor adaptor, 649ddd11b9aSAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 65044e58509SEric Schweitz llvm::SmallVector<mlir::Type> resultTys; 651ddd11b9aSAndrzej Warzynski for (auto r : call.getResults()) 652ddd11b9aSAndrzej Warzynski resultTys.push_back(convertType(r.getType())); 653ddd11b9aSAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>( 654ddd11b9aSAndrzej Warzynski call, resultTys, adaptor.getOperands(), call->getAttrs()); 65544e58509SEric Schweitz return mlir::success(); 656ddd11b9aSAndrzej Warzynski } 657ddd11b9aSAndrzej Warzynski }; 658c2acd453SAlexisPerry } // namespace 659ddd11b9aSAndrzej Warzynski 660092cee5fSValentin Clement static mlir::Type getComplexEleTy(mlir::Type complex) { 661092cee5fSValentin Clement if (auto cc = complex.dyn_cast<mlir::ComplexType>()) 662092cee5fSValentin Clement return cc.getElementType(); 663092cee5fSValentin Clement return complex.cast<fir::ComplexType>().getElementType(); 664092cee5fSValentin Clement } 665092cee5fSValentin Clement 666c2acd453SAlexisPerry namespace { 667f1dfc027SDiana Picus /// Compare complex values 668f1dfc027SDiana Picus /// 669f1dfc027SDiana Picus /// Per 10.1, the only comparisons available are .EQ. (oeq) and .NE. (une). 670f1dfc027SDiana Picus /// 671f1dfc027SDiana Picus /// For completeness, all other comparison are done on the real component only. 672f1dfc027SDiana Picus struct CmpcOpConversion : public FIROpConversion<fir::CmpcOp> { 673f1dfc027SDiana Picus using FIROpConversion::FIROpConversion; 674f1dfc027SDiana Picus 675f1dfc027SDiana Picus mlir::LogicalResult 676f1dfc027SDiana Picus matchAndRewrite(fir::CmpcOp cmp, OpAdaptor adaptor, 677f1dfc027SDiana Picus mlir::ConversionPatternRewriter &rewriter) const override { 678f1dfc027SDiana Picus mlir::ValueRange operands = adaptor.getOperands(); 679f1dfc027SDiana Picus mlir::MLIRContext *ctxt = cmp.getContext(); 680149ad3d5SShraiysh Vaishay mlir::Type eleTy = convertType(getComplexEleTy(cmp.getLhs().getType())); 681f1dfc027SDiana Picus mlir::Type resTy = convertType(cmp.getType()); 682f1dfc027SDiana Picus mlir::Location loc = cmp.getLoc(); 683f1dfc027SDiana Picus auto pos0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0)); 684575c9d6dSValentin Clement llvm::SmallVector<mlir::Value, 2> rp = { 68544e58509SEric Schweitz rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, operands[0], 68644e58509SEric Schweitz pos0), 68744e58509SEric Schweitz rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, operands[1], 68844e58509SEric Schweitz pos0)}; 689f1dfc027SDiana Picus auto rcp = 690f1dfc027SDiana Picus rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, rp, cmp->getAttrs()); 691f1dfc027SDiana Picus auto pos1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1)); 692575c9d6dSValentin Clement llvm::SmallVector<mlir::Value, 2> ip = { 69344e58509SEric Schweitz rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, operands[0], 69444e58509SEric Schweitz pos1), 69544e58509SEric Schweitz rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, operands[1], 69644e58509SEric Schweitz pos1)}; 697f1dfc027SDiana Picus auto icp = 698f1dfc027SDiana Picus rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, ip, cmp->getAttrs()); 699575c9d6dSValentin Clement llvm::SmallVector<mlir::Value, 2> cp = {rcp, icp}; 700f1dfc027SDiana Picus switch (cmp.getPredicate()) { 701f1dfc027SDiana Picus case mlir::arith::CmpFPredicate::OEQ: // .EQ. 702f1dfc027SDiana Picus rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(cmp, resTy, cp); 703f1dfc027SDiana Picus break; 704f1dfc027SDiana Picus case mlir::arith::CmpFPredicate::UNE: // .NE. 705f1dfc027SDiana Picus rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(cmp, resTy, cp); 706f1dfc027SDiana Picus break; 707f1dfc027SDiana Picus default: 708f1dfc027SDiana Picus rewriter.replaceOp(cmp, rcp.getResult()); 709f1dfc027SDiana Picus break; 710f1dfc027SDiana Picus } 71144e58509SEric Schweitz return mlir::success(); 712f1dfc027SDiana Picus } 713f1dfc027SDiana Picus }; 714f1dfc027SDiana Picus 715e81d73edSDiana Picus /// Lower complex constants 716e81d73edSDiana Picus struct ConstcOpConversion : public FIROpConversion<fir::ConstcOp> { 717e81d73edSDiana Picus using FIROpConversion::FIROpConversion; 718e81d73edSDiana Picus 719e81d73edSDiana Picus mlir::LogicalResult 720e81d73edSDiana Picus matchAndRewrite(fir::ConstcOp conc, OpAdaptor, 721e81d73edSDiana Picus mlir::ConversionPatternRewriter &rewriter) const override { 722e81d73edSDiana Picus mlir::Location loc = conc.getLoc(); 723e81d73edSDiana Picus mlir::MLIRContext *ctx = conc.getContext(); 724e81d73edSDiana Picus mlir::Type ty = convertType(conc.getType()); 725e81d73edSDiana Picus mlir::Type ety = convertType(getComplexEleTy(conc.getType())); 726e81d73edSDiana Picus auto realFloatAttr = mlir::FloatAttr::get(ety, getValue(conc.getReal())); 727e81d73edSDiana Picus auto realPart = 728e81d73edSDiana Picus rewriter.create<mlir::LLVM::ConstantOp>(loc, ety, realFloatAttr); 729e81d73edSDiana Picus auto imFloatAttr = mlir::FloatAttr::get(ety, getValue(conc.getImaginary())); 730e81d73edSDiana Picus auto imPart = 731e81d73edSDiana Picus rewriter.create<mlir::LLVM::ConstantOp>(loc, ety, imFloatAttr); 732e81d73edSDiana Picus auto realIndex = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 733e81d73edSDiana Picus auto imIndex = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 734e81d73edSDiana Picus auto undef = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 735e81d73edSDiana Picus auto setReal = rewriter.create<mlir::LLVM::InsertValueOp>( 736e81d73edSDiana Picus loc, ty, undef, realPart, realIndex); 737e81d73edSDiana Picus rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(conc, ty, setReal, 738e81d73edSDiana Picus imPart, imIndex); 73944e58509SEric Schweitz return mlir::success(); 740e81d73edSDiana Picus } 741e81d73edSDiana Picus 74244e58509SEric Schweitz inline llvm::APFloat getValue(mlir::Attribute attr) const { 743e81d73edSDiana Picus return attr.cast<fir::RealAttr>().getValue(); 744e81d73edSDiana Picus } 745e81d73edSDiana Picus }; 746e81d73edSDiana Picus 747092cee5fSValentin Clement /// convert value of from-type to value of to-type 748092cee5fSValentin Clement struct ConvertOpConversion : public FIROpConversion<fir::ConvertOp> { 749092cee5fSValentin Clement using FIROpConversion::FIROpConversion; 750092cee5fSValentin Clement 751092cee5fSValentin Clement static bool isFloatingPointTy(mlir::Type ty) { 752092cee5fSValentin Clement return ty.isa<mlir::FloatType>(); 753092cee5fSValentin Clement } 754092cee5fSValentin Clement 755092cee5fSValentin Clement mlir::LogicalResult 756092cee5fSValentin Clement matchAndRewrite(fir::ConvertOp convert, OpAdaptor adaptor, 757092cee5fSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 7583b7ec85aSJean Perier auto fromFirTy = convert.getValue().getType(); 7593b7ec85aSJean Perier auto toFirTy = convert.getRes().getType(); 7603b7ec85aSJean Perier auto fromTy = convertType(fromFirTy); 7613b7ec85aSJean Perier auto toTy = convertType(toFirTy); 762092cee5fSValentin Clement mlir::Value op0 = adaptor.getOperands()[0]; 763092cee5fSValentin Clement if (fromTy == toTy) { 764092cee5fSValentin Clement rewriter.replaceOp(convert, op0); 76544e58509SEric Schweitz return mlir::success(); 766092cee5fSValentin Clement } 767092cee5fSValentin Clement auto loc = convert.getLoc(); 768092cee5fSValentin Clement auto convertFpToFp = [&](mlir::Value val, unsigned fromBits, 769092cee5fSValentin Clement unsigned toBits, mlir::Type toTy) -> mlir::Value { 770092cee5fSValentin Clement if (fromBits == toBits) { 771092cee5fSValentin Clement // TODO: Converting between two floating-point representations with the 772092cee5fSValentin Clement // same bitwidth is not allowed for now. 773092cee5fSValentin Clement mlir::emitError(loc, 774092cee5fSValentin Clement "cannot implicitly convert between two floating-point " 775092cee5fSValentin Clement "representations of the same bitwidth"); 776092cee5fSValentin Clement return {}; 777092cee5fSValentin Clement } 778092cee5fSValentin Clement if (fromBits > toBits) 779092cee5fSValentin Clement return rewriter.create<mlir::LLVM::FPTruncOp>(loc, toTy, val); 780092cee5fSValentin Clement return rewriter.create<mlir::LLVM::FPExtOp>(loc, toTy, val); 781092cee5fSValentin Clement }; 782092cee5fSValentin Clement // Complex to complex conversion. 7833b7ec85aSJean Perier if (fir::isa_complex(fromFirTy) && fir::isa_complex(toFirTy)) { 784092cee5fSValentin Clement // Special case: handle the conversion of a complex such that both the 785092cee5fSValentin Clement // real and imaginary parts are converted together. 786092cee5fSValentin Clement auto zero = mlir::ArrayAttr::get(convert.getContext(), 787092cee5fSValentin Clement rewriter.getI32IntegerAttr(0)); 788092cee5fSValentin Clement auto one = mlir::ArrayAttr::get(convert.getContext(), 789092cee5fSValentin Clement rewriter.getI32IntegerAttr(1)); 790149ad3d5SShraiysh Vaishay auto ty = convertType(getComplexEleTy(convert.getValue().getType())); 791092cee5fSValentin Clement auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, zero); 792092cee5fSValentin Clement auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, one); 793149ad3d5SShraiysh Vaishay auto nt = convertType(getComplexEleTy(convert.getRes().getType())); 794092cee5fSValentin Clement auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(ty); 795092cee5fSValentin Clement auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(nt); 796092cee5fSValentin Clement auto rc = convertFpToFp(rp, fromBits, toBits, nt); 797092cee5fSValentin Clement auto ic = convertFpToFp(ip, fromBits, toBits, nt); 798092cee5fSValentin Clement auto un = rewriter.create<mlir::LLVM::UndefOp>(loc, toTy); 799092cee5fSValentin Clement auto i1 = 800092cee5fSValentin Clement rewriter.create<mlir::LLVM::InsertValueOp>(loc, toTy, un, rc, zero); 801092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(convert, toTy, i1, 802092cee5fSValentin Clement ic, one); 803092cee5fSValentin Clement return mlir::success(); 804092cee5fSValentin Clement } 8053b7ec85aSJean Perier 8063b7ec85aSJean Perier // Follow UNIX F77 convention for logicals: 8073b7ec85aSJean Perier // 1. underlying integer is not zero => logical is .TRUE. 8083b7ec85aSJean Perier // 2. logical is .TRUE. => set underlying integer to 1. 8093b7ec85aSJean Perier auto i1Type = mlir::IntegerType::get(convert.getContext(), 1); 8103b7ec85aSJean Perier if (fromFirTy.isa<fir::LogicalType>() && toFirTy == i1Type) { 8113b7ec85aSJean Perier mlir::Value zero = genConstantIndex(loc, fromTy, rewriter, 0); 8123b7ec85aSJean Perier rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>( 8133b7ec85aSJean Perier convert, mlir::LLVM::ICmpPredicate::ne, op0, zero); 8143b7ec85aSJean Perier return mlir::success(); 8153b7ec85aSJean Perier } 8163b7ec85aSJean Perier if (fromFirTy == i1Type && toFirTy.isa<fir::LogicalType>()) { 8173b7ec85aSJean Perier rewriter.replaceOpWithNewOp<mlir::LLVM::ZExtOp>(convert, toTy, op0); 8183b7ec85aSJean Perier return mlir::success(); 8193b7ec85aSJean Perier } 8203b7ec85aSJean Perier 821092cee5fSValentin Clement // Floating point to floating point conversion. 822092cee5fSValentin Clement if (isFloatingPointTy(fromTy)) { 823092cee5fSValentin Clement if (isFloatingPointTy(toTy)) { 824092cee5fSValentin Clement auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy); 825092cee5fSValentin Clement auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy); 826092cee5fSValentin Clement auto v = convertFpToFp(op0, fromBits, toBits, toTy); 827092cee5fSValentin Clement rewriter.replaceOp(convert, v); 828092cee5fSValentin Clement return mlir::success(); 829092cee5fSValentin Clement } 830092cee5fSValentin Clement if (toTy.isa<mlir::IntegerType>()) { 831092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::FPToSIOp>(convert, toTy, op0); 832092cee5fSValentin Clement return mlir::success(); 833092cee5fSValentin Clement } 834092cee5fSValentin Clement } else if (fromTy.isa<mlir::IntegerType>()) { 835092cee5fSValentin Clement // Integer to integer conversion. 836092cee5fSValentin Clement if (toTy.isa<mlir::IntegerType>()) { 837092cee5fSValentin Clement auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy); 838092cee5fSValentin Clement auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy); 839092cee5fSValentin Clement assert(fromBits != toBits); 840092cee5fSValentin Clement if (fromBits > toBits) { 841092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::TruncOp>(convert, toTy, op0); 842092cee5fSValentin Clement return mlir::success(); 843092cee5fSValentin Clement } 844092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::SExtOp>(convert, toTy, op0); 845092cee5fSValentin Clement return mlir::success(); 846092cee5fSValentin Clement } 847092cee5fSValentin Clement // Integer to floating point conversion. 848092cee5fSValentin Clement if (isFloatingPointTy(toTy)) { 849092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::SIToFPOp>(convert, toTy, op0); 850092cee5fSValentin Clement return mlir::success(); 851092cee5fSValentin Clement } 852092cee5fSValentin Clement // Integer to pointer conversion. 853092cee5fSValentin Clement if (toTy.isa<mlir::LLVM::LLVMPointerType>()) { 854092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(convert, toTy, op0); 855092cee5fSValentin Clement return mlir::success(); 856092cee5fSValentin Clement } 857092cee5fSValentin Clement } else if (fromTy.isa<mlir::LLVM::LLVMPointerType>()) { 858092cee5fSValentin Clement // Pointer to integer conversion. 859092cee5fSValentin Clement if (toTy.isa<mlir::IntegerType>()) { 860092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::PtrToIntOp>(convert, toTy, op0); 861092cee5fSValentin Clement return mlir::success(); 862092cee5fSValentin Clement } 863092cee5fSValentin Clement // Pointer to pointer conversion. 864092cee5fSValentin Clement if (toTy.isa<mlir::LLVM::LLVMPointerType>()) { 865092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(convert, toTy, op0); 866092cee5fSValentin Clement return mlir::success(); 867092cee5fSValentin Clement } 868092cee5fSValentin Clement } 869092cee5fSValentin Clement return emitError(loc) << "cannot convert " << fromTy << " to " << toTy; 870092cee5fSValentin Clement } 871092cee5fSValentin Clement }; 872092cee5fSValentin Clement 8739534e361SValentin Clement /// Lower `fir.dispatch` operation. A virtual call to a method in a dispatch 8749534e361SValentin Clement /// table. 8759534e361SValentin Clement struct DispatchOpConversion : public FIROpConversion<fir::DispatchOp> { 8769534e361SValentin Clement using FIROpConversion::FIROpConversion; 8779534e361SValentin Clement 8789534e361SValentin Clement mlir::LogicalResult 8799534e361SValentin Clement matchAndRewrite(fir::DispatchOp dispatch, OpAdaptor adaptor, 8809534e361SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 8817ce8c6fcSKiran Chandramohan TODO(dispatch.getLoc(), "fir.dispatch codegen"); 88244e58509SEric Schweitz return mlir::failure(); 8839534e361SValentin Clement } 8849534e361SValentin Clement }; 8859534e361SValentin Clement 8869534e361SValentin Clement /// Lower `fir.dispatch_table` operation. The dispatch table for a Fortran 8879534e361SValentin Clement /// derived type. 8889534e361SValentin Clement struct DispatchTableOpConversion 8899534e361SValentin Clement : public FIROpConversion<fir::DispatchTableOp> { 8909534e361SValentin Clement using FIROpConversion::FIROpConversion; 8919534e361SValentin Clement 8929534e361SValentin Clement mlir::LogicalResult 8939534e361SValentin Clement matchAndRewrite(fir::DispatchTableOp dispTab, OpAdaptor adaptor, 8949534e361SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 8957ce8c6fcSKiran Chandramohan TODO(dispTab.getLoc(), "fir.dispatch_table codegen"); 89644e58509SEric Schweitz return mlir::failure(); 8979534e361SValentin Clement } 8989534e361SValentin Clement }; 8999534e361SValentin Clement 9009534e361SValentin Clement /// Lower `fir.dt_entry` operation. An entry in a dispatch table; binds a 9019534e361SValentin Clement /// method-name to a function. 9029534e361SValentin Clement struct DTEntryOpConversion : public FIROpConversion<fir::DTEntryOp> { 9039534e361SValentin Clement using FIROpConversion::FIROpConversion; 9049534e361SValentin Clement 9059534e361SValentin Clement mlir::LogicalResult 9069534e361SValentin Clement matchAndRewrite(fir::DTEntryOp dtEnt, OpAdaptor adaptor, 9079534e361SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 9087ce8c6fcSKiran Chandramohan TODO(dtEnt.getLoc(), "fir.dt_entry codegen"); 90944e58509SEric Schweitz return mlir::failure(); 9109534e361SValentin Clement } 9119534e361SValentin Clement }; 9129534e361SValentin Clement 913677df8c7SValentin Clement /// Lower `fir.global_len` operation. 914677df8c7SValentin Clement struct GlobalLenOpConversion : public FIROpConversion<fir::GlobalLenOp> { 915677df8c7SValentin Clement using FIROpConversion::FIROpConversion; 916677df8c7SValentin Clement 917677df8c7SValentin Clement mlir::LogicalResult 918677df8c7SValentin Clement matchAndRewrite(fir::GlobalLenOp globalLen, OpAdaptor adaptor, 919677df8c7SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 9207ce8c6fcSKiran Chandramohan TODO(globalLen.getLoc(), "fir.global_len codegen"); 92144e58509SEric Schweitz return mlir::failure(); 922677df8c7SValentin Clement } 923677df8c7SValentin Clement }; 924677df8c7SValentin Clement 925cdc476abSDiana Picus /// Lower fir.len_param_index 926cdc476abSDiana Picus struct LenParamIndexOpConversion 927cdc476abSDiana Picus : public FIROpConversion<fir::LenParamIndexOp> { 928cdc476abSDiana Picus using FIROpConversion::FIROpConversion; 929cdc476abSDiana Picus 930cdc476abSDiana Picus // FIXME: this should be specialized by the runtime target 931cdc476abSDiana Picus mlir::LogicalResult 932cdc476abSDiana Picus matchAndRewrite(fir::LenParamIndexOp lenp, OpAdaptor, 933cdc476abSDiana Picus mlir::ConversionPatternRewriter &rewriter) const override { 9347ce8c6fcSKiran Chandramohan TODO(lenp.getLoc(), "fir.len_param_index codegen"); 935cdc476abSDiana Picus } 936cdc476abSDiana Picus }; 937cdc476abSDiana Picus 938dc48849fSKiran Chandramohan /// Convert `!fir.emboxchar<!fir.char<KIND, ?>, #n>` into a sequence of 939dc48849fSKiran Chandramohan /// instructions that generate `!llvm.struct<(ptr<ik>, i64)>`. The 1st element 940dc48849fSKiran Chandramohan /// in this struct is a pointer. Its type is determined from `KIND`. The 2nd 941dc48849fSKiran Chandramohan /// element is the length of the character buffer (`#n`). 942dc48849fSKiran Chandramohan struct EmboxCharOpConversion : public FIROpConversion<fir::EmboxCharOp> { 94331246187SValentin Clement using FIROpConversion::FIROpConversion; 94431246187SValentin Clement 94531246187SValentin Clement mlir::LogicalResult 946dc48849fSKiran Chandramohan matchAndRewrite(fir::EmboxCharOp emboxChar, OpAdaptor adaptor, 94731246187SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 948dc48849fSKiran Chandramohan mlir::ValueRange operands = adaptor.getOperands(); 94944e58509SEric Schweitz auto *ctx = emboxChar.getContext(); 950dc48849fSKiran Chandramohan 951dc48849fSKiran Chandramohan mlir::Value charBuffer = operands[0]; 952dc48849fSKiran Chandramohan mlir::Value charBufferLen = operands[1]; 953dc48849fSKiran Chandramohan 954dc48849fSKiran Chandramohan mlir::Location loc = emboxChar.getLoc(); 955dc48849fSKiran Chandramohan mlir::Type llvmStructTy = convertType(emboxChar.getType()); 956dc48849fSKiran Chandramohan auto llvmStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, llvmStructTy); 957dc48849fSKiran Chandramohan 958dc48849fSKiran Chandramohan mlir::Type lenTy = 959dc48849fSKiran Chandramohan llvmStructTy.cast<mlir::LLVM::LLVMStructType>().getBody()[1]; 960dc48849fSKiran Chandramohan mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, charBufferLen); 961dc48849fSKiran Chandramohan 962dc48849fSKiran Chandramohan auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 963dc48849fSKiran Chandramohan auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 964dc48849fSKiran Chandramohan auto insertBufferOp = rewriter.create<mlir::LLVM::InsertValueOp>( 965dc48849fSKiran Chandramohan loc, llvmStructTy, llvmStruct, charBuffer, c0); 966dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 967dc48849fSKiran Chandramohan emboxChar, llvmStructTy, insertBufferOp, lenAfterCast, c1); 968dc48849fSKiran Chandramohan 96944e58509SEric Schweitz return mlir::success(); 97031246187SValentin Clement } 97131246187SValentin Clement }; 972c2acd453SAlexisPerry } // namespace 973c2acd453SAlexisPerry 974c2acd453SAlexisPerry /// Return the LLVMFuncOp corresponding to the standard malloc call. 975c2acd453SAlexisPerry static mlir::LLVM::LLVMFuncOp 976c2acd453SAlexisPerry getMalloc(fir::AllocMemOp op, mlir::ConversionPatternRewriter &rewriter) { 977c2acd453SAlexisPerry auto module = op->getParentOfType<mlir::ModuleOp>(); 978c2acd453SAlexisPerry if (mlir::LLVM::LLVMFuncOp mallocFunc = 979c2acd453SAlexisPerry module.lookupSymbol<mlir::LLVM::LLVMFuncOp>("malloc")) 980c2acd453SAlexisPerry return mallocFunc; 981c2acd453SAlexisPerry mlir::OpBuilder moduleBuilder( 982c2acd453SAlexisPerry op->getParentOfType<mlir::ModuleOp>().getBodyRegion()); 983c2acd453SAlexisPerry auto indexType = mlir::IntegerType::get(op.getContext(), 64); 984c2acd453SAlexisPerry return moduleBuilder.create<mlir::LLVM::LLVMFuncOp>( 985c2acd453SAlexisPerry rewriter.getUnknownLoc(), "malloc", 986c2acd453SAlexisPerry mlir::LLVM::LLVMFunctionType::get(getVoidPtrType(op.getContext()), 987c2acd453SAlexisPerry indexType, 988c2acd453SAlexisPerry /*isVarArg=*/false)); 989c2acd453SAlexisPerry } 990c2acd453SAlexisPerry 991c2acd453SAlexisPerry /// Helper function for generating the LLVM IR that computes the size 992c2acd453SAlexisPerry /// in bytes for a derived type. 993c2acd453SAlexisPerry static mlir::Value 994c2acd453SAlexisPerry computeDerivedTypeSize(mlir::Location loc, mlir::Type ptrTy, mlir::Type idxTy, 995c2acd453SAlexisPerry mlir::ConversionPatternRewriter &rewriter) { 996c2acd453SAlexisPerry auto nullPtr = rewriter.create<mlir::LLVM::NullOp>(loc, ptrTy); 997c2acd453SAlexisPerry mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1); 998575c9d6dSValentin Clement llvm::SmallVector<mlir::Value> args = {one}; 99930122656SAlex Zinenko auto gep = rewriter.create<mlir::LLVM::GEPOp>(loc, ptrTy, nullPtr, args); 1000c2acd453SAlexisPerry return rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, gep); 1001c2acd453SAlexisPerry } 1002c2acd453SAlexisPerry 1003c2acd453SAlexisPerry namespace { 1004c2acd453SAlexisPerry /// Lower a `fir.allocmem` instruction into `llvm.call @malloc` 1005c2acd453SAlexisPerry struct AllocMemOpConversion : public FIROpConversion<fir::AllocMemOp> { 1006c2acd453SAlexisPerry using FIROpConversion::FIROpConversion; 1007c2acd453SAlexisPerry 1008c2acd453SAlexisPerry mlir::LogicalResult 1009c2acd453SAlexisPerry matchAndRewrite(fir::AllocMemOp heap, OpAdaptor adaptor, 1010c2acd453SAlexisPerry mlir::ConversionPatternRewriter &rewriter) const override { 1011575c9d6dSValentin Clement mlir::Type heapTy = heap.getType(); 1012575c9d6dSValentin Clement mlir::Type ty = convertType(heapTy); 1013c2acd453SAlexisPerry mlir::LLVM::LLVMFuncOp mallocFunc = getMalloc(heap, rewriter); 1014c2acd453SAlexisPerry mlir::Location loc = heap.getLoc(); 1015c2acd453SAlexisPerry auto ity = lowerTy().indexType(); 1016575c9d6dSValentin Clement mlir::Type dataTy = fir::unwrapRefType(heapTy); 1017c45bd4b9SEric Schweitz if (fir::isRecordWithTypeParameters(fir::unwrapSequenceType(dataTy))) 1018c45bd4b9SEric Schweitz TODO(loc, "fir.allocmem codegen of derived type with length parameters"); 1019c2acd453SAlexisPerry mlir::Value size = genTypeSizeInBytes(loc, ity, rewriter, ty); 1020ac0f4c8fSPeixinQiao if (auto scaleSize = genAllocationScaleSize(heap, ity, rewriter)) 1021ac0f4c8fSPeixinQiao size = rewriter.create<mlir::LLVM::MulOp>(loc, ity, size, scaleSize); 1022c2acd453SAlexisPerry for (mlir::Value opnd : adaptor.getOperands()) 1023c2acd453SAlexisPerry size = rewriter.create<mlir::LLVM::MulOp>( 1024c2acd453SAlexisPerry loc, ity, size, integerCast(loc, rewriter, ity, opnd)); 1025c2acd453SAlexisPerry heap->setAttr("callee", mlir::SymbolRefAttr::get(mallocFunc)); 1026c2acd453SAlexisPerry auto malloc = rewriter.create<mlir::LLVM::CallOp>( 1027c2acd453SAlexisPerry loc, ::getVoidPtrType(heap.getContext()), size, heap->getAttrs()); 1028c2acd453SAlexisPerry rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(heap, ty, 1029c2acd453SAlexisPerry malloc.getResult(0)); 103044e58509SEric Schweitz return mlir::success(); 1031c2acd453SAlexisPerry } 1032c2acd453SAlexisPerry 1033c2acd453SAlexisPerry // Compute the (allocation) size of the allocmem type in bytes. 1034c2acd453SAlexisPerry mlir::Value genTypeSizeInBytes(mlir::Location loc, mlir::Type idxTy, 1035c2acd453SAlexisPerry mlir::ConversionPatternRewriter &rewriter, 1036c2acd453SAlexisPerry mlir::Type llTy) const { 1037c2acd453SAlexisPerry // Use the primitive size, if available. 1038c2acd453SAlexisPerry auto ptrTy = llTy.dyn_cast<mlir::LLVM::LLVMPointerType>(); 1039c2acd453SAlexisPerry if (auto size = 1040c2acd453SAlexisPerry mlir::LLVM::getPrimitiveTypeSizeInBits(ptrTy.getElementType())) 1041c2acd453SAlexisPerry return genConstantIndex(loc, idxTy, rewriter, size / 8); 1042c2acd453SAlexisPerry 1043c2acd453SAlexisPerry // Otherwise, generate the GEP trick in LLVM IR to compute the size. 1044c2acd453SAlexisPerry return computeDerivedTypeSize(loc, ptrTy, idxTy, rewriter); 1045c2acd453SAlexisPerry } 1046c2acd453SAlexisPerry }; 1047c2acd453SAlexisPerry } // namespace 1048c2acd453SAlexisPerry 1049c2acd453SAlexisPerry /// Return the LLVMFuncOp corresponding to the standard free call. 1050c2acd453SAlexisPerry static mlir::LLVM::LLVMFuncOp 1051c2acd453SAlexisPerry getFree(fir::FreeMemOp op, mlir::ConversionPatternRewriter &rewriter) { 1052c2acd453SAlexisPerry auto module = op->getParentOfType<mlir::ModuleOp>(); 1053c2acd453SAlexisPerry if (mlir::LLVM::LLVMFuncOp freeFunc = 1054c2acd453SAlexisPerry module.lookupSymbol<mlir::LLVM::LLVMFuncOp>("free")) 1055c2acd453SAlexisPerry return freeFunc; 1056c2acd453SAlexisPerry mlir::OpBuilder moduleBuilder(module.getBodyRegion()); 1057c2acd453SAlexisPerry auto voidType = mlir::LLVM::LLVMVoidType::get(op.getContext()); 1058c2acd453SAlexisPerry return moduleBuilder.create<mlir::LLVM::LLVMFuncOp>( 1059c2acd453SAlexisPerry rewriter.getUnknownLoc(), "free", 1060c2acd453SAlexisPerry mlir::LLVM::LLVMFunctionType::get(voidType, 1061c2acd453SAlexisPerry getVoidPtrType(op.getContext()), 1062c2acd453SAlexisPerry /*isVarArg=*/false)); 1063c2acd453SAlexisPerry } 1064c2acd453SAlexisPerry 1065c2acd453SAlexisPerry namespace { 1066c2acd453SAlexisPerry /// Lower a `fir.freemem` instruction into `llvm.call @free` 1067c2acd453SAlexisPerry struct FreeMemOpConversion : public FIROpConversion<fir::FreeMemOp> { 1068c2acd453SAlexisPerry using FIROpConversion::FIROpConversion; 1069c2acd453SAlexisPerry 1070c2acd453SAlexisPerry mlir::LogicalResult 1071c2acd453SAlexisPerry matchAndRewrite(fir::FreeMemOp freemem, OpAdaptor adaptor, 1072c2acd453SAlexisPerry mlir::ConversionPatternRewriter &rewriter) const override { 1073c2acd453SAlexisPerry mlir::LLVM::LLVMFuncOp freeFunc = getFree(freemem, rewriter); 1074c2acd453SAlexisPerry mlir::Location loc = freemem.getLoc(); 1075c2acd453SAlexisPerry auto bitcast = rewriter.create<mlir::LLVM::BitcastOp>( 1076c2acd453SAlexisPerry freemem.getLoc(), voidPtrTy(), adaptor.getOperands()[0]); 1077c2acd453SAlexisPerry freemem->setAttr("callee", mlir::SymbolRefAttr::get(freeFunc)); 1078c2acd453SAlexisPerry rewriter.create<mlir::LLVM::CallOp>( 1079c2acd453SAlexisPerry loc, mlir::TypeRange{}, mlir::ValueRange{bitcast}, freemem->getAttrs()); 1080c2acd453SAlexisPerry rewriter.eraseOp(freemem); 108144e58509SEric Schweitz return mlir::success(); 1082c2acd453SAlexisPerry } 1083c2acd453SAlexisPerry }; 1084c2acd453SAlexisPerry } // namespace 1085044d5b5dSValentin Clement 1086af6ee580SValentin Clement /// Common base class for embox to descriptor conversion. 1087af6ee580SValentin Clement template <typename OP> 1088af6ee580SValentin Clement struct EmboxCommonConversion : public FIROpConversion<OP> { 1089af6ee580SValentin Clement using FIROpConversion<OP>::FIROpConversion; 1090af6ee580SValentin Clement 1091af6ee580SValentin Clement // Find the LLVMFuncOp in whose entry block the alloca should be inserted. 1092af6ee580SValentin Clement // The order to find the LLVMFuncOp is as follows: 1093af6ee580SValentin Clement // 1. The parent operation of the current block if it is a LLVMFuncOp. 1094af6ee580SValentin Clement // 2. The first ancestor that is a LLVMFuncOp. 1095af6ee580SValentin Clement mlir::LLVM::LLVMFuncOp 1096af6ee580SValentin Clement getFuncForAllocaInsert(mlir::ConversionPatternRewriter &rewriter) const { 1097af6ee580SValentin Clement mlir::Operation *parentOp = rewriter.getInsertionBlock()->getParentOp(); 1098af6ee580SValentin Clement return mlir::isa<mlir::LLVM::LLVMFuncOp>(parentOp) 1099af6ee580SValentin Clement ? mlir::cast<mlir::LLVM::LLVMFuncOp>(parentOp) 1100af6ee580SValentin Clement : parentOp->getParentOfType<mlir::LLVM::LLVMFuncOp>(); 1101af6ee580SValentin Clement } 1102af6ee580SValentin Clement 1103af6ee580SValentin Clement // Generate an alloca of size 1 and type \p toTy. 1104af6ee580SValentin Clement mlir::LLVM::AllocaOp 1105af6ee580SValentin Clement genAllocaWithType(mlir::Location loc, mlir::Type toTy, unsigned alignment, 1106af6ee580SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 1107af6ee580SValentin Clement auto thisPt = rewriter.saveInsertionPoint(); 1108af6ee580SValentin Clement mlir::LLVM::LLVMFuncOp func = getFuncForAllocaInsert(rewriter); 1109af6ee580SValentin Clement rewriter.setInsertionPointToStart(&func.front()); 1110af6ee580SValentin Clement auto size = this->genI32Constant(loc, rewriter, 1); 1111af6ee580SValentin Clement auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, toTy, size, alignment); 1112af6ee580SValentin Clement rewriter.restoreInsertionPoint(thisPt); 1113af6ee580SValentin Clement return al; 1114af6ee580SValentin Clement } 1115af6ee580SValentin Clement 1116af6ee580SValentin Clement static int getCFIAttr(fir::BoxType boxTy) { 1117af6ee580SValentin Clement auto eleTy = boxTy.getEleTy(); 1118af6ee580SValentin Clement if (eleTy.isa<fir::PointerType>()) 1119af6ee580SValentin Clement return CFI_attribute_pointer; 1120af6ee580SValentin Clement if (eleTy.isa<fir::HeapType>()) 1121af6ee580SValentin Clement return CFI_attribute_allocatable; 1122af6ee580SValentin Clement return CFI_attribute_other; 1123af6ee580SValentin Clement } 1124af6ee580SValentin Clement 1125af6ee580SValentin Clement static fir::RecordType unwrapIfDerived(fir::BoxType boxTy) { 1126af6ee580SValentin Clement return fir::unwrapSequenceType(fir::dyn_cast_ptrOrBoxEleTy(boxTy)) 1127af6ee580SValentin Clement .template dyn_cast<fir::RecordType>(); 1128af6ee580SValentin Clement } 1129af6ee580SValentin Clement static bool isDerivedTypeWithLenParams(fir::BoxType boxTy) { 1130af6ee580SValentin Clement auto recTy = unwrapIfDerived(boxTy); 1131af6ee580SValentin Clement return recTy && recTy.getNumLenParams() > 0; 1132af6ee580SValentin Clement } 1133af6ee580SValentin Clement static bool isDerivedType(fir::BoxType boxTy) { 1134575c9d6dSValentin Clement return static_cast<bool>(unwrapIfDerived(boxTy)); 1135af6ee580SValentin Clement } 1136af6ee580SValentin Clement 1137af6ee580SValentin Clement // Get the element size and CFI type code of the boxed value. 1138af6ee580SValentin Clement std::tuple<mlir::Value, mlir::Value> getSizeAndTypeCode( 1139af6ee580SValentin Clement mlir::Location loc, mlir::ConversionPatternRewriter &rewriter, 1140af6ee580SValentin Clement mlir::Type boxEleTy, mlir::ValueRange lenParams = {}) const { 1141af6ee580SValentin Clement auto doInteger = 1142af6ee580SValentin Clement [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> { 1143af6ee580SValentin Clement int typeCode = fir::integerBitsToTypeCode(width); 1144af6ee580SValentin Clement return {this->genConstantOffset(loc, rewriter, width / 8), 1145af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, typeCode)}; 1146af6ee580SValentin Clement }; 1147af6ee580SValentin Clement auto doLogical = 1148af6ee580SValentin Clement [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> { 1149af6ee580SValentin Clement int typeCode = fir::logicalBitsToTypeCode(width); 1150af6ee580SValentin Clement return {this->genConstantOffset(loc, rewriter, width / 8), 1151af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, typeCode)}; 1152af6ee580SValentin Clement }; 1153af6ee580SValentin Clement auto doFloat = [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> { 1154af6ee580SValentin Clement int typeCode = fir::realBitsToTypeCode(width); 1155af6ee580SValentin Clement return {this->genConstantOffset(loc, rewriter, width / 8), 1156af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, typeCode)}; 1157af6ee580SValentin Clement }; 1158af6ee580SValentin Clement auto doComplex = 1159af6ee580SValentin Clement [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> { 1160af6ee580SValentin Clement auto typeCode = fir::complexBitsToTypeCode(width); 1161af6ee580SValentin Clement return {this->genConstantOffset(loc, rewriter, width / 8 * 2), 1162af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, typeCode)}; 1163af6ee580SValentin Clement }; 1164af6ee580SValentin Clement auto doCharacter = 1165af6ee580SValentin Clement [&](unsigned width, 1166af6ee580SValentin Clement mlir::Value len) -> std::tuple<mlir::Value, mlir::Value> { 1167af6ee580SValentin Clement auto typeCode = fir::characterBitsToTypeCode(width); 1168af6ee580SValentin Clement auto typeCodeVal = this->genConstantOffset(loc, rewriter, typeCode); 1169af6ee580SValentin Clement if (width == 8) 1170af6ee580SValentin Clement return {len, typeCodeVal}; 1171af6ee580SValentin Clement auto i64Ty = mlir::IntegerType::get(&this->lowerTy().getContext(), 64); 11726c89c531SEric Schweitz auto byteWidth = genConstantIndex(loc, i64Ty, rewriter, width / 8); 11736c89c531SEric Schweitz auto len64 = FIROpConversion<OP>::integerCast(loc, rewriter, i64Ty, len); 1174af6ee580SValentin Clement auto size = 11756c89c531SEric Schweitz rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, byteWidth, len64); 1176af6ee580SValentin Clement return {size, typeCodeVal}; 1177af6ee580SValentin Clement }; 1178af6ee580SValentin Clement auto getKindMap = [&]() -> fir::KindMapping & { 1179af6ee580SValentin Clement return this->lowerTy().getKindMap(); 1180af6ee580SValentin Clement }; 1181af6ee580SValentin Clement // Pointer-like types. 1182af6ee580SValentin Clement if (auto eleTy = fir::dyn_cast_ptrEleTy(boxEleTy)) 1183af6ee580SValentin Clement boxEleTy = eleTy; 1184af6ee580SValentin Clement // Integer types. 1185af6ee580SValentin Clement if (fir::isa_integer(boxEleTy)) { 1186af6ee580SValentin Clement if (auto ty = boxEleTy.dyn_cast<mlir::IntegerType>()) 1187af6ee580SValentin Clement return doInteger(ty.getWidth()); 1188af6ee580SValentin Clement auto ty = boxEleTy.cast<fir::IntegerType>(); 1189af6ee580SValentin Clement return doInteger(getKindMap().getIntegerBitsize(ty.getFKind())); 1190af6ee580SValentin Clement } 1191af6ee580SValentin Clement // Floating point types. 1192af6ee580SValentin Clement if (fir::isa_real(boxEleTy)) { 1193af6ee580SValentin Clement if (auto ty = boxEleTy.dyn_cast<mlir::FloatType>()) 1194af6ee580SValentin Clement return doFloat(ty.getWidth()); 1195af6ee580SValentin Clement auto ty = boxEleTy.cast<fir::RealType>(); 1196af6ee580SValentin Clement return doFloat(getKindMap().getRealBitsize(ty.getFKind())); 1197af6ee580SValentin Clement } 1198af6ee580SValentin Clement // Complex types. 1199af6ee580SValentin Clement if (fir::isa_complex(boxEleTy)) { 1200af6ee580SValentin Clement if (auto ty = boxEleTy.dyn_cast<mlir::ComplexType>()) 1201af6ee580SValentin Clement return doComplex( 1202af6ee580SValentin Clement ty.getElementType().cast<mlir::FloatType>().getWidth()); 1203af6ee580SValentin Clement auto ty = boxEleTy.cast<fir::ComplexType>(); 1204af6ee580SValentin Clement return doComplex(getKindMap().getRealBitsize(ty.getFKind())); 1205af6ee580SValentin Clement } 1206af6ee580SValentin Clement // Character types. 1207af6ee580SValentin Clement if (auto ty = boxEleTy.dyn_cast<fir::CharacterType>()) { 1208af6ee580SValentin Clement auto charWidth = getKindMap().getCharacterBitsize(ty.getFKind()); 1209af6ee580SValentin Clement if (ty.getLen() != fir::CharacterType::unknownLen()) { 1210af6ee580SValentin Clement auto len = this->genConstantOffset(loc, rewriter, ty.getLen()); 1211af6ee580SValentin Clement return doCharacter(charWidth, len); 1212af6ee580SValentin Clement } 1213af6ee580SValentin Clement assert(!lenParams.empty()); 1214af6ee580SValentin Clement return doCharacter(charWidth, lenParams.back()); 1215af6ee580SValentin Clement } 1216af6ee580SValentin Clement // Logical type. 1217af6ee580SValentin Clement if (auto ty = boxEleTy.dyn_cast<fir::LogicalType>()) 1218af6ee580SValentin Clement return doLogical(getKindMap().getLogicalBitsize(ty.getFKind())); 1219af6ee580SValentin Clement // Array types. 1220af6ee580SValentin Clement if (auto seqTy = boxEleTy.dyn_cast<fir::SequenceType>()) 1221af6ee580SValentin Clement return getSizeAndTypeCode(loc, rewriter, seqTy.getEleTy(), lenParams); 1222af6ee580SValentin Clement // Derived-type types. 1223af6ee580SValentin Clement if (boxEleTy.isa<fir::RecordType>()) { 1224af6ee580SValentin Clement auto ptrTy = mlir::LLVM::LLVMPointerType::get( 1225af6ee580SValentin Clement this->lowerTy().convertType(boxEleTy)); 1226af6ee580SValentin Clement auto nullPtr = rewriter.create<mlir::LLVM::NullOp>(loc, ptrTy); 1227af6ee580SValentin Clement auto one = 1228af6ee580SValentin Clement genConstantIndex(loc, this->lowerTy().offsetType(), rewriter, 1); 122930122656SAlex Zinenko auto gep = rewriter.create<mlir::LLVM::GEPOp>(loc, ptrTy, nullPtr, 123030122656SAlex Zinenko mlir::ValueRange{one}); 1231af6ee580SValentin Clement auto eleSize = rewriter.create<mlir::LLVM::PtrToIntOp>( 1232af6ee580SValentin Clement loc, this->lowerTy().indexType(), gep); 1233af6ee580SValentin Clement return {eleSize, 1234af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, fir::derivedToTypeCode())}; 1235af6ee580SValentin Clement } 1236af6ee580SValentin Clement // Reference type. 1237af6ee580SValentin Clement if (fir::isa_ref_type(boxEleTy)) { 1238af6ee580SValentin Clement // FIXME: use the target pointer size rather than sizeof(void*) 1239af6ee580SValentin Clement return {this->genConstantOffset(loc, rewriter, sizeof(void *)), 1240af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, CFI_type_cptr)}; 1241af6ee580SValentin Clement } 1242af6ee580SValentin Clement fir::emitFatalError(loc, "unhandled type in fir.box code generation"); 1243af6ee580SValentin Clement } 1244af6ee580SValentin Clement 1245af6ee580SValentin Clement /// Basic pattern to write a field in the descriptor 1246af6ee580SValentin Clement mlir::Value insertField(mlir::ConversionPatternRewriter &rewriter, 1247af6ee580SValentin Clement mlir::Location loc, mlir::Value dest, 124844e58509SEric Schweitz llvm::ArrayRef<unsigned> fldIndexes, 124944e58509SEric Schweitz mlir::Value value, bool bitcast = false) const { 1250af6ee580SValentin Clement auto boxTy = dest.getType(); 1251af6ee580SValentin Clement auto fldTy = this->getBoxEleTy(boxTy, fldIndexes); 1252af6ee580SValentin Clement if (bitcast) 1253af6ee580SValentin Clement value = rewriter.create<mlir::LLVM::BitcastOp>(loc, fldTy, value); 1254af6ee580SValentin Clement else 1255af6ee580SValentin Clement value = this->integerCast(loc, rewriter, fldTy, value); 125644e58509SEric Schweitz llvm::SmallVector<mlir::Attribute, 2> attrs; 1257af6ee580SValentin Clement for (auto i : fldIndexes) 1258af6ee580SValentin Clement attrs.push_back(rewriter.getI32IntegerAttr(i)); 1259af6ee580SValentin Clement auto indexesAttr = mlir::ArrayAttr::get(rewriter.getContext(), attrs); 1260af6ee580SValentin Clement return rewriter.create<mlir::LLVM::InsertValueOp>(loc, boxTy, dest, value, 1261af6ee580SValentin Clement indexesAttr); 1262af6ee580SValentin Clement } 1263af6ee580SValentin Clement 1264af6ee580SValentin Clement inline mlir::Value 1265af6ee580SValentin Clement insertBaseAddress(mlir::ConversionPatternRewriter &rewriter, 1266af6ee580SValentin Clement mlir::Location loc, mlir::Value dest, 1267af6ee580SValentin Clement mlir::Value base) const { 12681f551032SValentin Clement return insertField(rewriter, loc, dest, {kAddrPosInBox}, base, 12691f551032SValentin Clement /*bitCast=*/true); 12701f551032SValentin Clement } 12711f551032SValentin Clement 12721f551032SValentin Clement inline mlir::Value insertLowerBound(mlir::ConversionPatternRewriter &rewriter, 12731f551032SValentin Clement mlir::Location loc, mlir::Value dest, 12741f551032SValentin Clement unsigned dim, mlir::Value lb) const { 12751f551032SValentin Clement return insertField(rewriter, loc, dest, 12761f551032SValentin Clement {kDimsPosInBox, dim, kDimLowerBoundPos}, lb); 12771f551032SValentin Clement } 12781f551032SValentin Clement 12791f551032SValentin Clement inline mlir::Value insertExtent(mlir::ConversionPatternRewriter &rewriter, 12801f551032SValentin Clement mlir::Location loc, mlir::Value dest, 12811f551032SValentin Clement unsigned dim, mlir::Value extent) const { 12821f551032SValentin Clement return insertField(rewriter, loc, dest, {kDimsPosInBox, dim, kDimExtentPos}, 12831f551032SValentin Clement extent); 12841f551032SValentin Clement } 12851f551032SValentin Clement 12861f551032SValentin Clement inline mlir::Value insertStride(mlir::ConversionPatternRewriter &rewriter, 12871f551032SValentin Clement mlir::Location loc, mlir::Value dest, 12881f551032SValentin Clement unsigned dim, mlir::Value stride) const { 12891f551032SValentin Clement return insertField(rewriter, loc, dest, {kDimsPosInBox, dim, kDimStridePos}, 12901f551032SValentin Clement stride); 1291af6ee580SValentin Clement } 1292af6ee580SValentin Clement 1293af6ee580SValentin Clement /// Get the address of the type descriptor global variable that was created by 1294af6ee580SValentin Clement /// lowering for derived type \p recType. 1295af6ee580SValentin Clement template <typename BOX> 1296af6ee580SValentin Clement mlir::Value 1297af6ee580SValentin Clement getTypeDescriptor(BOX box, mlir::ConversionPatternRewriter &rewriter, 1298af6ee580SValentin Clement mlir::Location loc, fir::RecordType recType) const { 1299013160f6SJean Perier std::string name = 1300013160f6SJean Perier fir::NameUniquer::getTypeDescriptorName(recType.getName()); 1301af6ee580SValentin Clement auto module = box->template getParentOfType<mlir::ModuleOp>(); 1302af6ee580SValentin Clement if (auto global = module.template lookupSymbol<fir::GlobalOp>(name)) { 1303af6ee580SValentin Clement auto ty = mlir::LLVM::LLVMPointerType::get( 1304af6ee580SValentin Clement this->lowerTy().convertType(global.getType())); 1305af6ee580SValentin Clement return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty, 1306feeee78aSJacques Pienaar global.getSymName()); 1307af6ee580SValentin Clement } 1308af6ee580SValentin Clement if (auto global = 1309af6ee580SValentin Clement module.template lookupSymbol<mlir::LLVM::GlobalOp>(name)) { 1310af6ee580SValentin Clement // The global may have already been translated to LLVM. 1311af6ee580SValentin Clement auto ty = mlir::LLVM::LLVMPointerType::get(global.getType()); 1312af6ee580SValentin Clement return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty, 1313feeee78aSJacques Pienaar global.getSymName()); 1314af6ee580SValentin Clement } 13157dd7ccd2SJean Perier // Type info derived types do not have type descriptors since they are the 13167dd7ccd2SJean Perier // types defining type descriptors. 1317013160f6SJean Perier if (!this->options.ignoreMissingTypeDescriptors && 1318013160f6SJean Perier !fir::NameUniquer::belongsToModule( 1319013160f6SJean Perier name, Fortran::semantics::typeInfoBuiltinModule)) 1320013160f6SJean Perier fir::emitFatalError( 1321013160f6SJean Perier loc, "runtime derived type info descriptor was not generated"); 13225bde97b1SJean Perier return rewriter.create<mlir::LLVM::NullOp>( 13235bde97b1SJean Perier loc, ::getVoidPtrType(box.getContext())); 13247dd7ccd2SJean Perier } 1325af6ee580SValentin Clement 1326af6ee580SValentin Clement template <typename BOX> 1327af6ee580SValentin Clement std::tuple<fir::BoxType, mlir::Value, mlir::Value> 1328af6ee580SValentin Clement consDescriptorPrefix(BOX box, mlir::ConversionPatternRewriter &rewriter, 1329af6ee580SValentin Clement unsigned rank, mlir::ValueRange lenParams) const { 1330af6ee580SValentin Clement auto loc = box.getLoc(); 1331af6ee580SValentin Clement auto boxTy = box.getType().template dyn_cast<fir::BoxType>(); 1332af6ee580SValentin Clement auto convTy = this->lowerTy().convertBoxType(boxTy, rank); 1333af6ee580SValentin Clement auto llvmBoxPtrTy = convTy.template cast<mlir::LLVM::LLVMPointerType>(); 1334af6ee580SValentin Clement auto llvmBoxTy = llvmBoxPtrTy.getElementType(); 1335af6ee580SValentin Clement mlir::Value descriptor = 1336af6ee580SValentin Clement rewriter.create<mlir::LLVM::UndefOp>(loc, llvmBoxTy); 1337af6ee580SValentin Clement 1338af6ee580SValentin Clement llvm::SmallVector<mlir::Value> typeparams = lenParams; 1339af6ee580SValentin Clement if constexpr (!std::is_same_v<BOX, fir::EmboxOp>) { 1340af6ee580SValentin Clement if (!box.substr().empty() && fir::hasDynamicSize(boxTy.getEleTy())) 1341af6ee580SValentin Clement typeparams.push_back(box.substr()[1]); 1342af6ee580SValentin Clement } 1343af6ee580SValentin Clement 1344af6ee580SValentin Clement // Write each of the fields with the appropriate values 1345af6ee580SValentin Clement auto [eleSize, cfiTy] = 1346af6ee580SValentin Clement getSizeAndTypeCode(loc, rewriter, boxTy.getEleTy(), typeparams); 1347af6ee580SValentin Clement descriptor = 1348af6ee580SValentin Clement insertField(rewriter, loc, descriptor, {kElemLenPosInBox}, eleSize); 1349af6ee580SValentin Clement descriptor = insertField(rewriter, loc, descriptor, {kVersionPosInBox}, 1350af6ee580SValentin Clement this->genI32Constant(loc, rewriter, CFI_VERSION)); 1351af6ee580SValentin Clement descriptor = insertField(rewriter, loc, descriptor, {kRankPosInBox}, 1352af6ee580SValentin Clement this->genI32Constant(loc, rewriter, rank)); 1353af6ee580SValentin Clement descriptor = insertField(rewriter, loc, descriptor, {kTypePosInBox}, cfiTy); 1354af6ee580SValentin Clement descriptor = 1355af6ee580SValentin Clement insertField(rewriter, loc, descriptor, {kAttributePosInBox}, 1356af6ee580SValentin Clement this->genI32Constant(loc, rewriter, getCFIAttr(boxTy))); 1357af6ee580SValentin Clement const bool hasAddendum = isDerivedType(boxTy); 1358af6ee580SValentin Clement descriptor = 1359af6ee580SValentin Clement insertField(rewriter, loc, descriptor, {kF18AddendumPosInBox}, 1360af6ee580SValentin Clement this->genI32Constant(loc, rewriter, hasAddendum ? 1 : 0)); 1361af6ee580SValentin Clement 1362af6ee580SValentin Clement if (hasAddendum) { 1363af6ee580SValentin Clement auto isArray = 1364af6ee580SValentin Clement fir::dyn_cast_ptrOrBoxEleTy(boxTy).template isa<fir::SequenceType>(); 1365af6ee580SValentin Clement unsigned typeDescFieldId = isArray ? kOptTypePtrPosInBox : kDimsPosInBox; 1366af6ee580SValentin Clement auto typeDesc = 1367af6ee580SValentin Clement getTypeDescriptor(box, rewriter, loc, unwrapIfDerived(boxTy)); 1368af6ee580SValentin Clement descriptor = 1369af6ee580SValentin Clement insertField(rewriter, loc, descriptor, {typeDescFieldId}, typeDesc, 1370af6ee580SValentin Clement /*bitCast=*/true); 1371af6ee580SValentin Clement } 1372af6ee580SValentin Clement 1373af6ee580SValentin Clement return {boxTy, descriptor, eleSize}; 1374af6ee580SValentin Clement } 1375af6ee580SValentin Clement 13761f551032SValentin Clement /// Compute the base address of a substring given the base address of a scalar 13771f551032SValentin Clement /// string and the zero based string lower bound. 13781f551032SValentin Clement mlir::Value shiftSubstringBase(mlir::ConversionPatternRewriter &rewriter, 13791f551032SValentin Clement mlir::Location loc, mlir::Value base, 13801f551032SValentin Clement mlir::Value lowerBound) const { 13811f551032SValentin Clement llvm::SmallVector<mlir::Value> gepOperands; 13821f551032SValentin Clement auto baseType = 13831f551032SValentin Clement base.getType().cast<mlir::LLVM::LLVMPointerType>().getElementType(); 13841f551032SValentin Clement if (baseType.isa<mlir::LLVM::LLVMArrayType>()) { 13851f551032SValentin Clement auto idxTy = this->lowerTy().indexType(); 13866c89c531SEric Schweitz gepOperands.push_back(genConstantIndex(loc, idxTy, rewriter, 0)); 13871f551032SValentin Clement gepOperands.push_back(lowerBound); 13886c89c531SEric Schweitz } else { 13896c89c531SEric Schweitz gepOperands.push_back(lowerBound); 13906c89c531SEric Schweitz } 13911f551032SValentin Clement return this->genGEP(loc, base.getType(), rewriter, base, gepOperands); 13921f551032SValentin Clement } 13931f551032SValentin Clement 1394af6ee580SValentin Clement /// If the embox is not in a globalOp body, allocate storage for the box; 1395af6ee580SValentin Clement /// store the value inside and return the generated alloca. Return the input 1396af6ee580SValentin Clement /// value otherwise. 1397af6ee580SValentin Clement mlir::Value 1398af6ee580SValentin Clement placeInMemoryIfNotGlobalInit(mlir::ConversionPatternRewriter &rewriter, 1399af6ee580SValentin Clement mlir::Location loc, mlir::Value boxValue) const { 1400af6ee580SValentin Clement auto *thisBlock = rewriter.getInsertionBlock(); 1401af6ee580SValentin Clement if (thisBlock && mlir::isa<mlir::LLVM::GlobalOp>(thisBlock->getParentOp())) 1402af6ee580SValentin Clement return boxValue; 1403af6ee580SValentin Clement auto boxPtrTy = mlir::LLVM::LLVMPointerType::get(boxValue.getType()); 1404af6ee580SValentin Clement auto alloca = genAllocaWithType(loc, boxPtrTy, defaultAlign, rewriter); 1405af6ee580SValentin Clement rewriter.create<mlir::LLVM::StoreOp>(loc, boxValue, alloca); 1406af6ee580SValentin Clement return alloca; 1407af6ee580SValentin Clement } 1408af6ee580SValentin Clement }; 1409af6ee580SValentin Clement 14101f551032SValentin Clement /// Compute the extent of a triplet slice (lb:ub:step). 14111f551032SValentin Clement static mlir::Value 14121f551032SValentin Clement computeTripletExtent(mlir::ConversionPatternRewriter &rewriter, 14131f551032SValentin Clement mlir::Location loc, mlir::Value lb, mlir::Value ub, 14141f551032SValentin Clement mlir::Value step, mlir::Value zero, mlir::Type type) { 14151f551032SValentin Clement mlir::Value extent = rewriter.create<mlir::LLVM::SubOp>(loc, type, ub, lb); 14161f551032SValentin Clement extent = rewriter.create<mlir::LLVM::AddOp>(loc, type, extent, step); 14171f551032SValentin Clement extent = rewriter.create<mlir::LLVM::SDivOp>(loc, type, extent, step); 14181f551032SValentin Clement // If the resulting extent is negative (`ub-lb` and `step` have different 14191f551032SValentin Clement // signs), zero must be returned instead. 14201f551032SValentin Clement auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 14211f551032SValentin Clement loc, mlir::LLVM::ICmpPredicate::sgt, extent, zero); 14221f551032SValentin Clement return rewriter.create<mlir::LLVM::SelectOp>(loc, cmp, extent, zero); 14231f551032SValentin Clement } 14241f551032SValentin Clement 1425af6ee580SValentin Clement /// Create a generic box on a memory reference. This conversions lowers the 1426af6ee580SValentin Clement /// abstract box to the appropriate, initialized descriptor. 1427af6ee580SValentin Clement struct EmboxOpConversion : public EmboxCommonConversion<fir::EmboxOp> { 1428af6ee580SValentin Clement using EmboxCommonConversion::EmboxCommonConversion; 1429af6ee580SValentin Clement 1430af6ee580SValentin Clement mlir::LogicalResult 1431af6ee580SValentin Clement matchAndRewrite(fir::EmboxOp embox, OpAdaptor adaptor, 1432af6ee580SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 1433af6ee580SValentin Clement assert(!embox.getShape() && "There should be no dims on this embox op"); 1434af6ee580SValentin Clement auto [boxTy, dest, eleSize] = 1435af6ee580SValentin Clement consDescriptorPrefix(embox, rewriter, /*rank=*/0, 1436af6ee580SValentin Clement /*lenParams=*/adaptor.getOperands().drop_front(1)); 1437af6ee580SValentin Clement dest = insertBaseAddress(rewriter, embox.getLoc(), dest, 1438af6ee580SValentin Clement adaptor.getOperands()[0]); 14397ce8c6fcSKiran Chandramohan if (isDerivedTypeWithLenParams(boxTy)) { 14407ce8c6fcSKiran Chandramohan TODO(embox.getLoc(), 14417ce8c6fcSKiran Chandramohan "fir.embox codegen of derived with length parameters"); 144244e58509SEric Schweitz return mlir::failure(); 14437ce8c6fcSKiran Chandramohan } 1444af6ee580SValentin Clement auto result = placeInMemoryIfNotGlobalInit(rewriter, embox.getLoc(), dest); 1445af6ee580SValentin Clement rewriter.replaceOp(embox, result); 144644e58509SEric Schweitz return mlir::success(); 1447af6ee580SValentin Clement } 1448af6ee580SValentin Clement }; 1449af6ee580SValentin Clement 14501f551032SValentin Clement /// Create a generic box on a memory reference. 14511f551032SValentin Clement struct XEmboxOpConversion : public EmboxCommonConversion<fir::cg::XEmboxOp> { 14521f551032SValentin Clement using EmboxCommonConversion::EmboxCommonConversion; 14531f551032SValentin Clement 14541f551032SValentin Clement mlir::LogicalResult 14551f551032SValentin Clement matchAndRewrite(fir::cg::XEmboxOp xbox, OpAdaptor adaptor, 14561f551032SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 14571f551032SValentin Clement auto [boxTy, dest, eleSize] = consDescriptorPrefix( 14581f551032SValentin Clement xbox, rewriter, xbox.getOutRank(), 14591f551032SValentin Clement adaptor.getOperands().drop_front(xbox.lenParamOffset())); 14601f551032SValentin Clement // Generate the triples in the dims field of the descriptor 14611f551032SValentin Clement mlir::ValueRange operands = adaptor.getOperands(); 14621f551032SValentin Clement auto i64Ty = mlir::IntegerType::get(xbox.getContext(), 64); 14631f551032SValentin Clement mlir::Value base = operands[0]; 14641f551032SValentin Clement assert(!xbox.shape().empty() && "must have a shape"); 14651f551032SValentin Clement unsigned shapeOffset = xbox.shapeOffset(); 14661f551032SValentin Clement bool hasShift = !xbox.shift().empty(); 14671f551032SValentin Clement unsigned shiftOffset = xbox.shiftOffset(); 14681f551032SValentin Clement bool hasSlice = !xbox.slice().empty(); 14691f551032SValentin Clement unsigned sliceOffset = xbox.sliceOffset(); 14701f551032SValentin Clement mlir::Location loc = xbox.getLoc(); 14711f551032SValentin Clement mlir::Value zero = genConstantIndex(loc, i64Ty, rewriter, 0); 14721f551032SValentin Clement mlir::Value one = genConstantIndex(loc, i64Ty, rewriter, 1); 14731f551032SValentin Clement mlir::Value prevPtrOff = one; 14741f551032SValentin Clement mlir::Type eleTy = boxTy.getEleTy(); 14751f551032SValentin Clement const unsigned rank = xbox.getRank(); 14761f551032SValentin Clement llvm::SmallVector<mlir::Value> gepArgs; 14771f551032SValentin Clement unsigned constRows = 0; 14781f551032SValentin Clement mlir::Value ptrOffset = zero; 14796c89c531SEric Schweitz mlir::Type memEleTy = fir::dyn_cast_ptrEleTy(xbox.memref().getType()); 14806c89c531SEric Schweitz assert(memEleTy.isa<fir::SequenceType>()); 14816c89c531SEric Schweitz auto seqTy = memEleTy.cast<fir::SequenceType>(); 14821f551032SValentin Clement mlir::Type seqEleTy = seqTy.getEleTy(); 14831f551032SValentin Clement // Adjust the element scaling factor if the element is a dependent type. 14841f551032SValentin Clement if (fir::hasDynamicSize(seqEleTy)) { 14856c89c531SEric Schweitz if (auto charTy = seqEleTy.dyn_cast<fir::CharacterType>()) { 14861f551032SValentin Clement assert(xbox.lenParams().size() == 1); 14876c89c531SEric Schweitz mlir::LLVM::ConstantOp charSize = genConstantIndex( 14886c89c531SEric Schweitz loc, i64Ty, rewriter, lowerTy().characterBitsize(charTy) / 8); 14896c89c531SEric Schweitz mlir::Value castedLen = 14906c89c531SEric Schweitz integerCast(loc, rewriter, i64Ty, operands[xbox.lenParamOffset()]); 14916c89c531SEric Schweitz auto byteOffset = 14926c89c531SEric Schweitz rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, charSize, castedLen); 14936c89c531SEric Schweitz prevPtrOff = integerCast(loc, rewriter, i64Ty, byteOffset); 14941f551032SValentin Clement } else if (seqEleTy.isa<fir::RecordType>()) { 14956c89c531SEric Schweitz // prevPtrOff = ; 14961f551032SValentin Clement TODO(loc, "generate call to calculate size of PDT"); 14971f551032SValentin Clement } else { 14986c89c531SEric Schweitz fir::emitFatalError(loc, "unexpected dynamic type"); 14991f551032SValentin Clement } 15001f551032SValentin Clement } else { 15011f551032SValentin Clement constRows = seqTy.getConstantRows(); 15021f551032SValentin Clement } 15031f551032SValentin Clement 15046c89c531SEric Schweitz const auto hasSubcomp = !xbox.subcomponent().empty(); 15056c89c531SEric Schweitz const bool hasSubstr = !xbox.substr().empty(); 15066c89c531SEric Schweitz /// Compute initial element stride that will be use to compute the step in 15076c89c531SEric Schweitz /// each dimension. 15086c89c531SEric Schweitz mlir::Value prevDimByteStride = integerCast(loc, rewriter, i64Ty, eleSize); 15091f551032SValentin Clement if (hasSubcomp) { 15101f551032SValentin Clement // We have a subcomponent. The step value needs to be the number of 15111f551032SValentin Clement // bytes per element (which is a derived type). 15121f551032SValentin Clement auto eleTy = mlir::LLVM::LLVMPointerType::get(convertType(seqEleTy)); 15136c89c531SEric Schweitz prevDimByteStride = computeDerivedTypeSize(loc, eleTy, i64Ty, rewriter); 15146c89c531SEric Schweitz } else if (hasSubstr) { 15156c89c531SEric Schweitz // We have a substring. The step value needs to be the number of bytes 15166c89c531SEric Schweitz // per CHARACTER element. 15176c89c531SEric Schweitz auto charTy = seqEleTy.cast<fir::CharacterType>(); 15186c89c531SEric Schweitz if (fir::hasDynamicSize(charTy)) { 15196c89c531SEric Schweitz prevDimByteStride = prevPtrOff; 15206c89c531SEric Schweitz } else { 15216c89c531SEric Schweitz prevDimByteStride = genConstantIndex( 15226c89c531SEric Schweitz loc, i64Ty, rewriter, 15236c89c531SEric Schweitz charTy.getLen() * lowerTy().characterBitsize(charTy) / 8); 15246c89c531SEric Schweitz } 15251f551032SValentin Clement } 15261f551032SValentin Clement 15271f551032SValentin Clement // Process the array subspace arguments (shape, shift, etc.), if any, 15281f551032SValentin Clement // translating everything to values in the descriptor wherever the entity 15291f551032SValentin Clement // has a dynamic array dimension. 15301f551032SValentin Clement for (unsigned di = 0, descIdx = 0; di < rank; ++di) { 15311f551032SValentin Clement mlir::Value extent = operands[shapeOffset]; 15321f551032SValentin Clement mlir::Value outerExtent = extent; 15331f551032SValentin Clement bool skipNext = false; 15341f551032SValentin Clement if (hasSlice) { 15351f551032SValentin Clement mlir::Value off = operands[sliceOffset]; 15361f551032SValentin Clement mlir::Value adj = one; 15371f551032SValentin Clement if (hasShift) 15381f551032SValentin Clement adj = operands[shiftOffset]; 15391f551032SValentin Clement auto ao = rewriter.create<mlir::LLVM::SubOp>(loc, i64Ty, off, adj); 15401f551032SValentin Clement if (constRows > 0) { 15411f551032SValentin Clement gepArgs.push_back(ao); 15421f551032SValentin Clement } else { 15431f551032SValentin Clement auto dimOff = 15441f551032SValentin Clement rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, ao, prevPtrOff); 15451f551032SValentin Clement ptrOffset = 15461f551032SValentin Clement rewriter.create<mlir::LLVM::AddOp>(loc, i64Ty, dimOff, ptrOffset); 15471f551032SValentin Clement } 15481f551032SValentin Clement if (mlir::isa_and_nonnull<fir::UndefOp>( 15491f551032SValentin Clement xbox.slice()[3 * di + 1].getDefiningOp())) { 15501f551032SValentin Clement // This dimension contains a scalar expression in the array slice op. 15511f551032SValentin Clement // The dimension is loop invariant, will be dropped, and will not 15521f551032SValentin Clement // appear in the descriptor. 15531f551032SValentin Clement skipNext = true; 15541f551032SValentin Clement } 15551f551032SValentin Clement } 15561f551032SValentin Clement if (!skipNext) { 15576c89c531SEric Schweitz // store extent 15581f551032SValentin Clement if (hasSlice) 15591f551032SValentin Clement extent = computeTripletExtent(rewriter, loc, operands[sliceOffset], 15601f551032SValentin Clement operands[sliceOffset + 1], 15611f551032SValentin Clement operands[sliceOffset + 2], zero, i64Ty); 15626c89c531SEric Schweitz // Lower bound is normalized to 0 for BIND(C) interoperability. 1563d3bc3a04SJean Perier mlir::Value lb = zero; 1564d3bc3a04SJean Perier const bool isaPointerOrAllocatable = 1565d3bc3a04SJean Perier eleTy.isa<fir::PointerType>() || eleTy.isa<fir::HeapType>(); 1566d3bc3a04SJean Perier // Lower bound is defaults to 1 for POINTER, ALLOCATABLE, and 1567d3bc3a04SJean Perier // denormalized descriptors. 15686c89c531SEric Schweitz if (isaPointerOrAllocatable || !normalizedLowerBound(xbox)) 1569d3bc3a04SJean Perier lb = one; 1570bb3afae9SJean Perier // If there is a shifted origin, and no fir.slice, and this is not 1571bb3afae9SJean Perier // a normalized descriptor then use the value from the shift op as 1572bb3afae9SJean Perier // the lower bound. 15736c89c531SEric Schweitz if (hasShift && !(hasSlice || hasSubcomp || hasSubstr) && 15746c89c531SEric Schweitz (isaPointerOrAllocatable || !normalizedLowerBound(xbox))) { 1575d3bc3a04SJean Perier lb = operands[shiftOffset]; 1576d3bc3a04SJean Perier auto extentIsEmpty = rewriter.create<mlir::LLVM::ICmpOp>( 1577d3bc3a04SJean Perier loc, mlir::LLVM::ICmpPredicate::eq, extent, zero); 1578d3bc3a04SJean Perier lb = rewriter.create<mlir::LLVM::SelectOp>(loc, extentIsEmpty, one, 1579d3bc3a04SJean Perier lb); 1580d3bc3a04SJean Perier } 1581d3bc3a04SJean Perier dest = insertLowerBound(rewriter, loc, dest, descIdx, lb); 1582d3bc3a04SJean Perier 15831f551032SValentin Clement dest = insertExtent(rewriter, loc, dest, descIdx, extent); 15841f551032SValentin Clement 15851f551032SValentin Clement // store step (scaled by shaped extent) 15866c89c531SEric Schweitz mlir::Value step = prevDimByteStride; 15871f551032SValentin Clement if (hasSlice) 15881f551032SValentin Clement step = rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, step, 15891f551032SValentin Clement operands[sliceOffset + 2]); 15901f551032SValentin Clement dest = insertStride(rewriter, loc, dest, descIdx, step); 15911f551032SValentin Clement ++descIdx; 15921f551032SValentin Clement } 15931f551032SValentin Clement 15941f551032SValentin Clement // compute the stride and offset for the next natural dimension 15956c89c531SEric Schweitz prevDimByteStride = rewriter.create<mlir::LLVM::MulOp>( 15966c89c531SEric Schweitz loc, i64Ty, prevDimByteStride, outerExtent); 15971f551032SValentin Clement if (constRows == 0) 15981f551032SValentin Clement prevPtrOff = rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, prevPtrOff, 15991f551032SValentin Clement outerExtent); 16000601a0dcSJean Perier else 16010601a0dcSJean Perier --constRows; 16021f551032SValentin Clement 16031f551032SValentin Clement // increment iterators 16041f551032SValentin Clement ++shapeOffset; 16051f551032SValentin Clement if (hasShift) 16061f551032SValentin Clement ++shiftOffset; 16071f551032SValentin Clement if (hasSlice) 16081f551032SValentin Clement sliceOffset += 3; 16091f551032SValentin Clement } 16106c89c531SEric Schweitz if (hasSlice || hasSubcomp || hasSubstr) { 161130122656SAlex Zinenko llvm::SmallVector<mlir::Value> args = {ptrOffset}; 16121f551032SValentin Clement args.append(gepArgs.rbegin(), gepArgs.rend()); 16131f551032SValentin Clement if (hasSubcomp) { 16141f551032SValentin Clement // For each field in the path add the offset to base via the args list. 16151f551032SValentin Clement // In the most general case, some offsets must be computed since 16161f551032SValentin Clement // they are not be known until runtime. 16171f551032SValentin Clement if (fir::hasDynamicSize(fir::unwrapSequenceType( 16181f551032SValentin Clement fir::unwrapPassByRefType(xbox.memref().getType())))) 16191f551032SValentin Clement TODO(loc, "fir.embox codegen dynamic size component in derived type"); 16201f551032SValentin Clement args.append(operands.begin() + xbox.subcomponentOffset(), 16211f551032SValentin Clement operands.begin() + xbox.subcomponentOffset() + 16221f551032SValentin Clement xbox.subcomponent().size()); 16231f551032SValentin Clement } 162430122656SAlex Zinenko base = 162530122656SAlex Zinenko rewriter.create<mlir::LLVM::GEPOp>(loc, base.getType(), base, args); 16266c89c531SEric Schweitz if (hasSubstr) 16271f551032SValentin Clement base = shiftSubstringBase(rewriter, loc, base, 16281f551032SValentin Clement operands[xbox.substrOffset()]); 16291f551032SValentin Clement } 16301f551032SValentin Clement dest = insertBaseAddress(rewriter, loc, dest, base); 16311f551032SValentin Clement if (isDerivedTypeWithLenParams(boxTy)) 16321f551032SValentin Clement TODO(loc, "fir.embox codegen of derived with length parameters"); 16331f551032SValentin Clement 16341f551032SValentin Clement mlir::Value result = placeInMemoryIfNotGlobalInit(rewriter, loc, dest); 16351f551032SValentin Clement rewriter.replaceOp(xbox, result); 163644e58509SEric Schweitz return mlir::success(); 16371f551032SValentin Clement } 1638d3bc3a04SJean Perier 1639d3bc3a04SJean Perier /// Return true if `xbox` has a normalized lower bounds attribute. A box value 1640d3bc3a04SJean Perier /// that is neither a POINTER nor an ALLOCATABLE should be normalized to a 1641d3bc3a04SJean Perier /// zero origin lower bound for interoperability with BIND(C). 1642d3bc3a04SJean Perier inline static bool normalizedLowerBound(fir::cg::XEmboxOp xbox) { 1643d3bc3a04SJean Perier return xbox->hasAttr(fir::getNormalizedLowerBoundAttrName()); 1644d3bc3a04SJean Perier } 16451f551032SValentin Clement }; 16461f551032SValentin Clement 1647fa517555SKiran Chandramohan /// Create a new box given a box reference. 1648fa517555SKiran Chandramohan struct XReboxOpConversion : public EmboxCommonConversion<fir::cg::XReboxOp> { 1649fa517555SKiran Chandramohan using EmboxCommonConversion::EmboxCommonConversion; 1650fa517555SKiran Chandramohan 1651fa517555SKiran Chandramohan mlir::LogicalResult 1652fa517555SKiran Chandramohan matchAndRewrite(fir::cg::XReboxOp rebox, OpAdaptor adaptor, 1653fa517555SKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 1654fa517555SKiran Chandramohan mlir::Location loc = rebox.getLoc(); 1655fa517555SKiran Chandramohan mlir::Type idxTy = lowerTy().indexType(); 1656fa517555SKiran Chandramohan mlir::Value loweredBox = adaptor.getOperands()[0]; 1657fa517555SKiran Chandramohan mlir::ValueRange operands = adaptor.getOperands(); 1658fa517555SKiran Chandramohan 1659fa517555SKiran Chandramohan // Create new descriptor and fill its non-shape related data. 1660fa517555SKiran Chandramohan llvm::SmallVector<mlir::Value, 2> lenParams; 1661fa517555SKiran Chandramohan mlir::Type inputEleTy = getInputEleTy(rebox); 1662fa517555SKiran Chandramohan if (auto charTy = inputEleTy.dyn_cast<fir::CharacterType>()) { 1663fa517555SKiran Chandramohan mlir::Value len = 1664fa517555SKiran Chandramohan loadElementSizeFromBox(loc, idxTy, loweredBox, rewriter); 1665fa517555SKiran Chandramohan if (charTy.getFKind() != 1) { 1666fa517555SKiran Chandramohan mlir::Value width = 1667fa517555SKiran Chandramohan genConstantIndex(loc, idxTy, rewriter, charTy.getFKind()); 1668fa517555SKiran Chandramohan len = rewriter.create<mlir::LLVM::SDivOp>(loc, idxTy, len, width); 1669fa517555SKiran Chandramohan } 1670fa517555SKiran Chandramohan lenParams.emplace_back(len); 1671fa517555SKiran Chandramohan } else if (auto recTy = inputEleTy.dyn_cast<fir::RecordType>()) { 1672fa517555SKiran Chandramohan if (recTy.getNumLenParams() != 0) 1673fa517555SKiran Chandramohan TODO(loc, "reboxing descriptor of derived type with length parameters"); 1674fa517555SKiran Chandramohan } 1675fa517555SKiran Chandramohan auto [boxTy, dest, eleSize] = 1676fa517555SKiran Chandramohan consDescriptorPrefix(rebox, rewriter, rebox.getOutRank(), lenParams); 1677fa517555SKiran Chandramohan 1678fa517555SKiran Chandramohan // Read input extents, strides, and base address 1679fa517555SKiran Chandramohan llvm::SmallVector<mlir::Value> inputExtents; 1680fa517555SKiran Chandramohan llvm::SmallVector<mlir::Value> inputStrides; 1681fa517555SKiran Chandramohan const unsigned inputRank = rebox.getRank(); 1682fa517555SKiran Chandramohan for (unsigned i = 0; i < inputRank; ++i) { 1683fa517555SKiran Chandramohan mlir::Value dim = genConstantIndex(loc, idxTy, rewriter, i); 168444e58509SEric Schweitz llvm::SmallVector<mlir::Value, 3> dimInfo = 1685fa517555SKiran Chandramohan getDimsFromBox(loc, {idxTy, idxTy, idxTy}, loweredBox, dim, rewriter); 1686fa517555SKiran Chandramohan inputExtents.emplace_back(dimInfo[1]); 1687fa517555SKiran Chandramohan inputStrides.emplace_back(dimInfo[2]); 1688fa517555SKiran Chandramohan } 1689fa517555SKiran Chandramohan 1690fa517555SKiran Chandramohan mlir::Type baseTy = getBaseAddrTypeFromBox(loweredBox.getType()); 1691fa517555SKiran Chandramohan mlir::Value baseAddr = 1692fa517555SKiran Chandramohan loadBaseAddrFromBox(loc, baseTy, loweredBox, rewriter); 1693fa517555SKiran Chandramohan 1694fa517555SKiran Chandramohan if (!rebox.slice().empty() || !rebox.subcomponent().empty()) 1695fa517555SKiran Chandramohan return sliceBox(rebox, dest, baseAddr, inputExtents, inputStrides, 1696fa517555SKiran Chandramohan operands, rewriter); 1697fa517555SKiran Chandramohan return reshapeBox(rebox, dest, baseAddr, inputExtents, inputStrides, 1698fa517555SKiran Chandramohan operands, rewriter); 1699fa517555SKiran Chandramohan } 1700fa517555SKiran Chandramohan 1701fa517555SKiran Chandramohan private: 1702fa517555SKiran Chandramohan /// Write resulting shape and base address in descriptor, and replace rebox 1703fa517555SKiran Chandramohan /// op. 1704fa517555SKiran Chandramohan mlir::LogicalResult 1705fa517555SKiran Chandramohan finalizeRebox(fir::cg::XReboxOp rebox, mlir::Value dest, mlir::Value base, 1706fa517555SKiran Chandramohan mlir::ValueRange lbounds, mlir::ValueRange extents, 1707fa517555SKiran Chandramohan mlir::ValueRange strides, 1708fa517555SKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const { 1709fa517555SKiran Chandramohan mlir::Location loc = rebox.getLoc(); 1710d3bc3a04SJean Perier mlir::Value zero = 1711d3bc3a04SJean Perier genConstantIndex(loc, lowerTy().indexType(), rewriter, 0); 1712fa517555SKiran Chandramohan mlir::Value one = genConstantIndex(loc, lowerTy().indexType(), rewriter, 1); 1713fa517555SKiran Chandramohan for (auto iter : llvm::enumerate(llvm::zip(extents, strides))) { 1714d3bc3a04SJean Perier mlir::Value extent = std::get<0>(iter.value()); 1715fa517555SKiran Chandramohan unsigned dim = iter.index(); 1716d3bc3a04SJean Perier mlir::Value lb = one; 1717d3bc3a04SJean Perier if (!lbounds.empty()) { 1718d3bc3a04SJean Perier lb = lbounds[dim]; 1719d3bc3a04SJean Perier auto extentIsEmpty = rewriter.create<mlir::LLVM::ICmpOp>( 1720d3bc3a04SJean Perier loc, mlir::LLVM::ICmpPredicate::eq, extent, zero); 1721d3bc3a04SJean Perier lb = rewriter.create<mlir::LLVM::SelectOp>(loc, extentIsEmpty, one, lb); 1722d3bc3a04SJean Perier }; 1723fa517555SKiran Chandramohan dest = insertLowerBound(rewriter, loc, dest, dim, lb); 1724d3bc3a04SJean Perier dest = insertExtent(rewriter, loc, dest, dim, extent); 1725fa517555SKiran Chandramohan dest = insertStride(rewriter, loc, dest, dim, std::get<1>(iter.value())); 1726fa517555SKiran Chandramohan } 1727fa517555SKiran Chandramohan dest = insertBaseAddress(rewriter, loc, dest, base); 1728fa517555SKiran Chandramohan mlir::Value result = 1729fa517555SKiran Chandramohan placeInMemoryIfNotGlobalInit(rewriter, rebox.getLoc(), dest); 1730fa517555SKiran Chandramohan rewriter.replaceOp(rebox, result); 173144e58509SEric Schweitz return mlir::success(); 1732fa517555SKiran Chandramohan } 1733fa517555SKiran Chandramohan 1734fa517555SKiran Chandramohan // Apply slice given the base address, extents and strides of the input box. 1735fa517555SKiran Chandramohan mlir::LogicalResult 1736fa517555SKiran Chandramohan sliceBox(fir::cg::XReboxOp rebox, mlir::Value dest, mlir::Value base, 1737fa517555SKiran Chandramohan mlir::ValueRange inputExtents, mlir::ValueRange inputStrides, 1738fa517555SKiran Chandramohan mlir::ValueRange operands, 1739fa517555SKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const { 1740fa517555SKiran Chandramohan mlir::Location loc = rebox.getLoc(); 1741fa517555SKiran Chandramohan mlir::Type voidPtrTy = ::getVoidPtrType(rebox.getContext()); 1742fa517555SKiran Chandramohan mlir::Type idxTy = lowerTy().indexType(); 1743fa517555SKiran Chandramohan mlir::Value zero = genConstantIndex(loc, idxTy, rewriter, 0); 1744fa517555SKiran Chandramohan // Apply subcomponent and substring shift on base address. 1745fa517555SKiran Chandramohan if (!rebox.subcomponent().empty() || !rebox.substr().empty()) { 1746fa517555SKiran Chandramohan // Cast to inputEleTy* so that a GEP can be used. 1747fa517555SKiran Chandramohan mlir::Type inputEleTy = getInputEleTy(rebox); 1748fa517555SKiran Chandramohan auto llvmElePtrTy = 1749fa517555SKiran Chandramohan mlir::LLVM::LLVMPointerType::get(convertType(inputEleTy)); 1750fa517555SKiran Chandramohan base = rewriter.create<mlir::LLVM::BitcastOp>(loc, llvmElePtrTy, base); 1751fa517555SKiran Chandramohan 1752fa517555SKiran Chandramohan if (!rebox.subcomponent().empty()) { 1753fa517555SKiran Chandramohan llvm::SmallVector<mlir::Value> gepOperands = {zero}; 1754fa517555SKiran Chandramohan for (unsigned i = 0; i < rebox.subcomponent().size(); ++i) 1755fa517555SKiran Chandramohan gepOperands.push_back(operands[rebox.subcomponentOffset() + i]); 1756fa517555SKiran Chandramohan base = genGEP(loc, llvmElePtrTy, rewriter, base, gepOperands); 1757fa517555SKiran Chandramohan } 1758fa517555SKiran Chandramohan if (!rebox.substr().empty()) 1759fa517555SKiran Chandramohan base = shiftSubstringBase(rewriter, loc, base, 1760fa517555SKiran Chandramohan operands[rebox.substrOffset()]); 1761fa517555SKiran Chandramohan } 1762fa517555SKiran Chandramohan 1763fa517555SKiran Chandramohan if (rebox.slice().empty()) 1764fa517555SKiran Chandramohan // The array section is of the form array[%component][substring], keep 1765fa517555SKiran Chandramohan // the input array extents and strides. 1766fa517555SKiran Chandramohan return finalizeRebox(rebox, dest, base, /*lbounds*/ llvm::None, 1767fa517555SKiran Chandramohan inputExtents, inputStrides, rewriter); 1768fa517555SKiran Chandramohan 1769fa517555SKiran Chandramohan // Strides from the fir.box are in bytes. 1770fa517555SKiran Chandramohan base = rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, base); 1771fa517555SKiran Chandramohan 1772fa517555SKiran Chandramohan // The slice is of the form array(i:j:k)[%component]. Compute new extents 1773fa517555SKiran Chandramohan // and strides. 1774fa517555SKiran Chandramohan llvm::SmallVector<mlir::Value> slicedExtents; 1775fa517555SKiran Chandramohan llvm::SmallVector<mlir::Value> slicedStrides; 1776fa517555SKiran Chandramohan mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1); 1777fa517555SKiran Chandramohan const bool sliceHasOrigins = !rebox.shift().empty(); 1778fa517555SKiran Chandramohan unsigned sliceOps = rebox.sliceOffset(); 1779fa517555SKiran Chandramohan unsigned shiftOps = rebox.shiftOffset(); 1780fa517555SKiran Chandramohan auto strideOps = inputStrides.begin(); 1781fa517555SKiran Chandramohan const unsigned inputRank = inputStrides.size(); 1782fa517555SKiran Chandramohan for (unsigned i = 0; i < inputRank; 1783fa517555SKiran Chandramohan ++i, ++strideOps, ++shiftOps, sliceOps += 3) { 1784fa517555SKiran Chandramohan mlir::Value sliceLb = 1785fa517555SKiran Chandramohan integerCast(loc, rewriter, idxTy, operands[sliceOps]); 1786fa517555SKiran Chandramohan mlir::Value inputStride = *strideOps; // already idxTy 1787fa517555SKiran Chandramohan // Apply origin shift: base += (lb-shift)*input_stride 1788fa517555SKiran Chandramohan mlir::Value sliceOrigin = 1789fa517555SKiran Chandramohan sliceHasOrigins 1790fa517555SKiran Chandramohan ? integerCast(loc, rewriter, idxTy, operands[shiftOps]) 1791fa517555SKiran Chandramohan : one; 1792fa517555SKiran Chandramohan mlir::Value diff = 1793fa517555SKiran Chandramohan rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, sliceLb, sliceOrigin); 1794fa517555SKiran Chandramohan mlir::Value offset = 1795fa517555SKiran Chandramohan rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, inputStride); 1796fa517555SKiran Chandramohan base = genGEP(loc, voidPtrTy, rewriter, base, offset); 1797fa517555SKiran Chandramohan // Apply upper bound and step if this is a triplet. Otherwise, the 1798fa517555SKiran Chandramohan // dimension is dropped and no extents/strides are computed. 1799fa517555SKiran Chandramohan mlir::Value upper = operands[sliceOps + 1]; 1800fa517555SKiran Chandramohan const bool isTripletSlice = 1801fa517555SKiran Chandramohan !mlir::isa_and_nonnull<mlir::LLVM::UndefOp>(upper.getDefiningOp()); 1802fa517555SKiran Chandramohan if (isTripletSlice) { 1803fa517555SKiran Chandramohan mlir::Value step = 1804fa517555SKiran Chandramohan integerCast(loc, rewriter, idxTy, operands[sliceOps + 2]); 1805fa517555SKiran Chandramohan // extent = ub-lb+step/step 1806fa517555SKiran Chandramohan mlir::Value sliceUb = integerCast(loc, rewriter, idxTy, upper); 1807fa517555SKiran Chandramohan mlir::Value extent = computeTripletExtent(rewriter, loc, sliceLb, 1808fa517555SKiran Chandramohan sliceUb, step, zero, idxTy); 1809fa517555SKiran Chandramohan slicedExtents.emplace_back(extent); 1810fa517555SKiran Chandramohan // stride = step*input_stride 1811fa517555SKiran Chandramohan mlir::Value stride = 1812fa517555SKiran Chandramohan rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, step, inputStride); 1813fa517555SKiran Chandramohan slicedStrides.emplace_back(stride); 1814fa517555SKiran Chandramohan } 1815fa517555SKiran Chandramohan } 1816fa517555SKiran Chandramohan return finalizeRebox(rebox, dest, base, /*lbounds*/ llvm::None, 1817fa517555SKiran Chandramohan slicedExtents, slicedStrides, rewriter); 1818fa517555SKiran Chandramohan } 1819fa517555SKiran Chandramohan 1820fa517555SKiran Chandramohan /// Apply a new shape to the data described by a box given the base address, 1821fa517555SKiran Chandramohan /// extents and strides of the box. 1822fa517555SKiran Chandramohan mlir::LogicalResult 1823fa517555SKiran Chandramohan reshapeBox(fir::cg::XReboxOp rebox, mlir::Value dest, mlir::Value base, 1824fa517555SKiran Chandramohan mlir::ValueRange inputExtents, mlir::ValueRange inputStrides, 1825fa517555SKiran Chandramohan mlir::ValueRange operands, 1826fa517555SKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const { 1827fa517555SKiran Chandramohan mlir::ValueRange reboxShifts{operands.begin() + rebox.shiftOffset(), 1828fa517555SKiran Chandramohan operands.begin() + rebox.shiftOffset() + 1829fa517555SKiran Chandramohan rebox.shift().size()}; 1830fa517555SKiran Chandramohan if (rebox.shape().empty()) { 1831fa517555SKiran Chandramohan // Only setting new lower bounds. 1832fa517555SKiran Chandramohan return finalizeRebox(rebox, dest, base, reboxShifts, inputExtents, 1833fa517555SKiran Chandramohan inputStrides, rewriter); 1834fa517555SKiran Chandramohan } 1835fa517555SKiran Chandramohan 1836fa517555SKiran Chandramohan mlir::Location loc = rebox.getLoc(); 1837fa517555SKiran Chandramohan // Strides from the fir.box are in bytes. 1838fa517555SKiran Chandramohan mlir::Type voidPtrTy = ::getVoidPtrType(rebox.getContext()); 1839fa517555SKiran Chandramohan base = rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, base); 1840fa517555SKiran Chandramohan 1841fa517555SKiran Chandramohan llvm::SmallVector<mlir::Value> newStrides; 1842fa517555SKiran Chandramohan llvm::SmallVector<mlir::Value> newExtents; 1843fa517555SKiran Chandramohan mlir::Type idxTy = lowerTy().indexType(); 1844fa517555SKiran Chandramohan // First stride from input box is kept. The rest is assumed contiguous 1845fa517555SKiran Chandramohan // (it is not possible to reshape otherwise). If the input is scalar, 1846fa517555SKiran Chandramohan // which may be OK if all new extents are ones, the stride does not 1847fa517555SKiran Chandramohan // matter, use one. 1848fa517555SKiran Chandramohan mlir::Value stride = inputStrides.empty() 1849fa517555SKiran Chandramohan ? genConstantIndex(loc, idxTy, rewriter, 1) 1850fa517555SKiran Chandramohan : inputStrides[0]; 1851fa517555SKiran Chandramohan for (unsigned i = 0; i < rebox.shape().size(); ++i) { 1852fa517555SKiran Chandramohan mlir::Value rawExtent = operands[rebox.shapeOffset() + i]; 1853fa517555SKiran Chandramohan mlir::Value extent = integerCast(loc, rewriter, idxTy, rawExtent); 1854fa517555SKiran Chandramohan newExtents.emplace_back(extent); 1855fa517555SKiran Chandramohan newStrides.emplace_back(stride); 1856fa517555SKiran Chandramohan // nextStride = extent * stride; 1857fa517555SKiran Chandramohan stride = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, extent, stride); 1858fa517555SKiran Chandramohan } 1859fa517555SKiran Chandramohan return finalizeRebox(rebox, dest, base, reboxShifts, newExtents, newStrides, 1860fa517555SKiran Chandramohan rewriter); 1861fa517555SKiran Chandramohan } 1862fa517555SKiran Chandramohan 1863fa517555SKiran Chandramohan /// Return scalar element type of the input box. 1864fa517555SKiran Chandramohan static mlir::Type getInputEleTy(fir::cg::XReboxOp rebox) { 1865fa517555SKiran Chandramohan auto ty = fir::dyn_cast_ptrOrBoxEleTy(rebox.box().getType()); 1866fa517555SKiran Chandramohan if (auto seqTy = ty.dyn_cast<fir::SequenceType>()) 1867fa517555SKiran Chandramohan return seqTy.getEleTy(); 1868fa517555SKiran Chandramohan return ty; 1869fa517555SKiran Chandramohan } 1870fa517555SKiran Chandramohan }; 1871fa517555SKiran Chandramohan 1872dc48849fSKiran Chandramohan /// Lower `fir.emboxproc` operation. Creates a procedure box. 1873dc48849fSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers. 1874dc48849fSKiran Chandramohan struct EmboxProcOpConversion : public FIROpConversion<fir::EmboxProcOp> { 1875dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 1876dc48849fSKiran Chandramohan 1877dc48849fSKiran Chandramohan mlir::LogicalResult 1878dc48849fSKiran Chandramohan matchAndRewrite(fir::EmboxProcOp emboxproc, OpAdaptor adaptor, 1879dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 1880dc48849fSKiran Chandramohan TODO(emboxproc.getLoc(), "fir.emboxproc codegen"); 188144e58509SEric Schweitz return mlir::failure(); 1882dc48849fSKiran Chandramohan } 1883dc48849fSKiran Chandramohan }; 1884dc48849fSKiran Chandramohan 188554c56347SValentin Clement // Code shared between insert_value and extract_value Ops. 188654c56347SValentin Clement struct ValueOpCommon { 188754c56347SValentin Clement // Translate the arguments pertaining to any multidimensional array to 188854c56347SValentin Clement // row-major order for LLVM-IR. 188944e58509SEric Schweitz static void toRowMajor(llvm::SmallVectorImpl<mlir::Attribute> &attrs, 189054c56347SValentin Clement mlir::Type ty) { 189154c56347SValentin Clement assert(ty && "type is null"); 189254c56347SValentin Clement const auto end = attrs.size(); 189354c56347SValentin Clement for (std::remove_const_t<decltype(end)> i = 0; i < end; ++i) { 189454c56347SValentin Clement if (auto seq = ty.dyn_cast<mlir::LLVM::LLVMArrayType>()) { 189554c56347SValentin Clement const auto dim = getDimension(seq); 189654c56347SValentin Clement if (dim > 1) { 189754c56347SValentin Clement auto ub = std::min(i + dim, end); 189854c56347SValentin Clement std::reverse(attrs.begin() + i, attrs.begin() + ub); 189954c56347SValentin Clement i += dim - 1; 190054c56347SValentin Clement } 190154c56347SValentin Clement ty = getArrayElementType(seq); 190254c56347SValentin Clement } else if (auto st = ty.dyn_cast<mlir::LLVM::LLVMStructType>()) { 190354c56347SValentin Clement ty = st.getBody()[attrs[i].cast<mlir::IntegerAttr>().getInt()]; 190454c56347SValentin Clement } else { 190554c56347SValentin Clement llvm_unreachable("index into invalid type"); 190654c56347SValentin Clement } 190754c56347SValentin Clement } 190854c56347SValentin Clement } 190954c56347SValentin Clement 191054c56347SValentin Clement static llvm::SmallVector<mlir::Attribute> 191154c56347SValentin Clement collectIndices(mlir::ConversionPatternRewriter &rewriter, 191254c56347SValentin Clement mlir::ArrayAttr arrAttr) { 191354c56347SValentin Clement llvm::SmallVector<mlir::Attribute> attrs; 191454c56347SValentin Clement for (auto i = arrAttr.begin(), e = arrAttr.end(); i != e; ++i) { 191554c56347SValentin Clement if (i->isa<mlir::IntegerAttr>()) { 191654c56347SValentin Clement attrs.push_back(*i); 191754c56347SValentin Clement } else { 191854c56347SValentin Clement auto fieldName = i->cast<mlir::StringAttr>().getValue(); 191954c56347SValentin Clement ++i; 192054c56347SValentin Clement auto ty = i->cast<mlir::TypeAttr>().getValue(); 192154c56347SValentin Clement auto index = ty.cast<fir::RecordType>().getFieldIndex(fieldName); 192254c56347SValentin Clement attrs.push_back(mlir::IntegerAttr::get(rewriter.getI32Type(), index)); 192354c56347SValentin Clement } 192454c56347SValentin Clement } 192554c56347SValentin Clement return attrs; 192654c56347SValentin Clement } 192754c56347SValentin Clement 192854c56347SValentin Clement private: 192954c56347SValentin Clement static unsigned getDimension(mlir::LLVM::LLVMArrayType ty) { 193054c56347SValentin Clement unsigned result = 1; 193154c56347SValentin Clement for (auto eleTy = ty.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>(); 193254c56347SValentin Clement eleTy; 193354c56347SValentin Clement eleTy = eleTy.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>()) 193454c56347SValentin Clement ++result; 193554c56347SValentin Clement return result; 193654c56347SValentin Clement } 193754c56347SValentin Clement 193854c56347SValentin Clement static mlir::Type getArrayElementType(mlir::LLVM::LLVMArrayType ty) { 193954c56347SValentin Clement auto eleTy = ty.getElementType(); 194054c56347SValentin Clement while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>()) 194154c56347SValentin Clement eleTy = arrTy.getElementType(); 194254c56347SValentin Clement return eleTy; 194354c56347SValentin Clement } 194454c56347SValentin Clement }; 194554c56347SValentin Clement 1946c2acd453SAlexisPerry namespace { 194754c56347SValentin Clement /// Extract a subobject value from an ssa-value of aggregate type 194854c56347SValentin Clement struct ExtractValueOpConversion 194954c56347SValentin Clement : public FIROpAndTypeConversion<fir::ExtractValueOp>, 195054c56347SValentin Clement public ValueOpCommon { 195154c56347SValentin Clement using FIROpAndTypeConversion::FIROpAndTypeConversion; 195254c56347SValentin Clement 195354c56347SValentin Clement mlir::LogicalResult 195454c56347SValentin Clement doRewrite(fir::ExtractValueOp extractVal, mlir::Type ty, OpAdaptor adaptor, 195554c56347SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 1956149ad3d5SShraiysh Vaishay auto attrs = collectIndices(rewriter, extractVal.getCoor()); 195754c56347SValentin Clement toRowMajor(attrs, adaptor.getOperands()[0].getType()); 195854c56347SValentin Clement auto position = mlir::ArrayAttr::get(extractVal.getContext(), attrs); 195954c56347SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>( 196054c56347SValentin Clement extractVal, ty, adaptor.getOperands()[0], position); 196144e58509SEric Schweitz return mlir::success(); 196254c56347SValentin Clement } 196354c56347SValentin Clement }; 196454c56347SValentin Clement 196554c56347SValentin Clement /// InsertValue is the generalized instruction for the composition of new 196654c56347SValentin Clement /// aggregate type values. 196754c56347SValentin Clement struct InsertValueOpConversion 196854c56347SValentin Clement : public FIROpAndTypeConversion<fir::InsertValueOp>, 196954c56347SValentin Clement public ValueOpCommon { 197054c56347SValentin Clement using FIROpAndTypeConversion::FIROpAndTypeConversion; 197154c56347SValentin Clement 197254c56347SValentin Clement mlir::LogicalResult 197354c56347SValentin Clement doRewrite(fir::InsertValueOp insertVal, mlir::Type ty, OpAdaptor adaptor, 197454c56347SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 1975149ad3d5SShraiysh Vaishay auto attrs = collectIndices(rewriter, insertVal.getCoor()); 197654c56347SValentin Clement toRowMajor(attrs, adaptor.getOperands()[0].getType()); 197754c56347SValentin Clement auto position = mlir::ArrayAttr::get(insertVal.getContext(), attrs); 197854c56347SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 197954c56347SValentin Clement insertVal, ty, adaptor.getOperands()[0], adaptor.getOperands()[1], 198054c56347SValentin Clement position); 198144e58509SEric Schweitz return mlir::success(); 198254c56347SValentin Clement } 198354c56347SValentin Clement }; 198454c56347SValentin Clement 19853ae8e442SValentin Clement /// InsertOnRange inserts a value into a sequence over a range of offsets. 19863ae8e442SValentin Clement struct InsertOnRangeOpConversion 19873ae8e442SValentin Clement : public FIROpAndTypeConversion<fir::InsertOnRangeOp> { 19883ae8e442SValentin Clement using FIROpAndTypeConversion::FIROpAndTypeConversion; 19893ae8e442SValentin Clement 19903ae8e442SValentin Clement // Increments an array of subscripts in a row major fasion. 199144e58509SEric Schweitz void incrementSubscripts(const llvm::SmallVector<uint64_t> &dims, 199244e58509SEric Schweitz llvm::SmallVector<uint64_t> &subscripts) const { 19933ae8e442SValentin Clement for (size_t i = dims.size(); i > 0; --i) { 19943ae8e442SValentin Clement if (++subscripts[i - 1] < dims[i - 1]) { 19953ae8e442SValentin Clement return; 19963ae8e442SValentin Clement } 19973ae8e442SValentin Clement subscripts[i - 1] = 0; 19983ae8e442SValentin Clement } 19993ae8e442SValentin Clement } 20003ae8e442SValentin Clement 20013ae8e442SValentin Clement mlir::LogicalResult 20023ae8e442SValentin Clement doRewrite(fir::InsertOnRangeOp range, mlir::Type ty, OpAdaptor adaptor, 20033ae8e442SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 20043ae8e442SValentin Clement 20053ae8e442SValentin Clement llvm::SmallVector<uint64_t> dims; 20063ae8e442SValentin Clement auto type = adaptor.getOperands()[0].getType(); 20073ae8e442SValentin Clement 20083ae8e442SValentin Clement // Iteratively extract the array dimensions from the type. 20093ae8e442SValentin Clement while (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) { 20103ae8e442SValentin Clement dims.push_back(t.getNumElements()); 20113ae8e442SValentin Clement type = t.getElementType(); 20123ae8e442SValentin Clement } 20133ae8e442SValentin Clement 2014575c9d6dSValentin Clement llvm::SmallVector<std::uint64_t> lBounds; 2015575c9d6dSValentin Clement llvm::SmallVector<std::uint64_t> uBounds; 20163ae8e442SValentin Clement 20173ae8e442SValentin Clement // Unzip the upper and lower bound and convert to a row major format. 2018149ad3d5SShraiysh Vaishay mlir::DenseIntElementsAttr coor = range.getCoor(); 20198ec0f221SMehdi Amini auto reversedCoor = llvm::reverse(coor.getValues<int64_t>()); 20208ec0f221SMehdi Amini for (auto i = reversedCoor.begin(), e = reversedCoor.end(); i != e; ++i) { 20213ae8e442SValentin Clement uBounds.push_back(*i++); 20223ae8e442SValentin Clement lBounds.push_back(*i); 20233ae8e442SValentin Clement } 20243ae8e442SValentin Clement 20253ae8e442SValentin Clement auto &subscripts = lBounds; 20263ae8e442SValentin Clement auto loc = range.getLoc(); 20273ae8e442SValentin Clement mlir::Value lastOp = adaptor.getOperands()[0]; 20283ae8e442SValentin Clement mlir::Value insertVal = adaptor.getOperands()[1]; 20293ae8e442SValentin Clement 20303ae8e442SValentin Clement auto i64Ty = rewriter.getI64Type(); 20313ae8e442SValentin Clement while (subscripts != uBounds) { 20323ae8e442SValentin Clement // Convert uint64_t's to Attribute's. 203344e58509SEric Schweitz llvm::SmallVector<mlir::Attribute> subscriptAttrs; 20343ae8e442SValentin Clement for (const auto &subscript : subscripts) 203544e58509SEric Schweitz subscriptAttrs.push_back(mlir::IntegerAttr::get(i64Ty, subscript)); 20363ae8e442SValentin Clement lastOp = rewriter.create<mlir::LLVM::InsertValueOp>( 20373ae8e442SValentin Clement loc, ty, lastOp, insertVal, 203844e58509SEric Schweitz mlir::ArrayAttr::get(range.getContext(), subscriptAttrs)); 20393ae8e442SValentin Clement 20403ae8e442SValentin Clement incrementSubscripts(dims, subscripts); 20413ae8e442SValentin Clement } 20423ae8e442SValentin Clement 20433ae8e442SValentin Clement // Convert uint64_t's to Attribute's. 204444e58509SEric Schweitz llvm::SmallVector<mlir::Attribute> subscriptAttrs; 20453ae8e442SValentin Clement for (const auto &subscript : subscripts) 20463ae8e442SValentin Clement subscriptAttrs.push_back( 204744e58509SEric Schweitz mlir::IntegerAttr::get(rewriter.getI64Type(), subscript)); 20483ae8e442SValentin Clement mlir::ArrayRef<mlir::Attribute> arrayRef(subscriptAttrs); 20493ae8e442SValentin Clement 20503ae8e442SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 20513ae8e442SValentin Clement range, ty, lastOp, insertVal, 205244e58509SEric Schweitz mlir::ArrayAttr::get(range.getContext(), arrayRef)); 20533ae8e442SValentin Clement 205444e58509SEric Schweitz return mlir::success(); 20553ae8e442SValentin Clement } 20563ae8e442SValentin Clement }; 2057c2acd453SAlexisPerry } // namespace 20587b5132daSValentin Clement 2059dc48849fSKiran Chandramohan namespace { 20605d27abe6SValentin Clement /// XArrayCoor is the address arithmetic on a dynamically shaped, sliced, 20615d27abe6SValentin Clement /// shifted etc. array. 20625d27abe6SValentin Clement /// (See the static restriction on coordinate_of.) array_coor determines the 20635d27abe6SValentin Clement /// coordinate (location) of a specific element. 20645d27abe6SValentin Clement struct XArrayCoorOpConversion 20655d27abe6SValentin Clement : public FIROpAndTypeConversion<fir::cg::XArrayCoorOp> { 20665d27abe6SValentin Clement using FIROpAndTypeConversion::FIROpAndTypeConversion; 20675d27abe6SValentin Clement 20685d27abe6SValentin Clement mlir::LogicalResult 20695d27abe6SValentin Clement doRewrite(fir::cg::XArrayCoorOp coor, mlir::Type ty, OpAdaptor adaptor, 20705d27abe6SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 20715d27abe6SValentin Clement auto loc = coor.getLoc(); 20725d27abe6SValentin Clement mlir::ValueRange operands = adaptor.getOperands(); 20735d27abe6SValentin Clement unsigned rank = coor.getRank(); 20745d27abe6SValentin Clement assert(coor.indices().size() == rank); 20755d27abe6SValentin Clement assert(coor.shape().empty() || coor.shape().size() == rank); 20765d27abe6SValentin Clement assert(coor.shift().empty() || coor.shift().size() == rank); 20775d27abe6SValentin Clement assert(coor.slice().empty() || coor.slice().size() == 3 * rank); 20785d27abe6SValentin Clement mlir::Type idxTy = lowerTy().indexType(); 2079914b9eecSKiran Chandramohan unsigned indexOffset = coor.indicesOffset(); 2080914b9eecSKiran Chandramohan unsigned shapeOffset = coor.shapeOffset(); 2081914b9eecSKiran Chandramohan unsigned shiftOffset = coor.shiftOffset(); 2082914b9eecSKiran Chandramohan unsigned sliceOffset = coor.sliceOffset(); 2083914b9eecSKiran Chandramohan auto sliceOps = coor.slice().begin(); 20845d27abe6SValentin Clement mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1); 20855d27abe6SValentin Clement mlir::Value prevExt = one; 20865d27abe6SValentin Clement mlir::Value zero = genConstantIndex(loc, idxTy, rewriter, 0); 20875d27abe6SValentin Clement mlir::Value offset = zero; 20885d27abe6SValentin Clement const bool isShifted = !coor.shift().empty(); 20895d27abe6SValentin Clement const bool isSliced = !coor.slice().empty(); 20905d27abe6SValentin Clement const bool baseIsBoxed = coor.memref().getType().isa<fir::BoxType>(); 20915d27abe6SValentin Clement 20925d27abe6SValentin Clement // For each dimension of the array, generate the offset calculation. 2093914b9eecSKiran Chandramohan for (unsigned i = 0; i < rank; ++i, ++indexOffset, ++shapeOffset, 2094914b9eecSKiran Chandramohan ++shiftOffset, sliceOffset += 3, sliceOps += 3) { 20955d27abe6SValentin Clement mlir::Value index = 2096914b9eecSKiran Chandramohan integerCast(loc, rewriter, idxTy, operands[indexOffset]); 2097914b9eecSKiran Chandramohan mlir::Value lb = 2098914b9eecSKiran Chandramohan isShifted ? integerCast(loc, rewriter, idxTy, operands[shiftOffset]) 20995d27abe6SValentin Clement : one; 21005d27abe6SValentin Clement mlir::Value step = one; 21015d27abe6SValentin Clement bool normalSlice = isSliced; 21025d27abe6SValentin Clement // Compute zero based index in dimension i of the element, applying 21035d27abe6SValentin Clement // potential triplets and lower bounds. 21045d27abe6SValentin Clement if (isSliced) { 2105914b9eecSKiran Chandramohan mlir::Value originalUb = *(sliceOps + 1); 2106914b9eecSKiran Chandramohan normalSlice = 2107914b9eecSKiran Chandramohan !mlir::isa_and_nonnull<fir::UndefOp>(originalUb.getDefiningOp()); 21085d27abe6SValentin Clement if (normalSlice) 2109914b9eecSKiran Chandramohan step = integerCast(loc, rewriter, idxTy, operands[sliceOffset + 2]); 21105d27abe6SValentin Clement } 21115d27abe6SValentin Clement auto idx = rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, index, lb); 21125d27abe6SValentin Clement mlir::Value diff = 21135d27abe6SValentin Clement rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, idx, step); 21145d27abe6SValentin Clement if (normalSlice) { 21155d27abe6SValentin Clement mlir::Value sliceLb = 2116914b9eecSKiran Chandramohan integerCast(loc, rewriter, idxTy, operands[sliceOffset]); 21175d27abe6SValentin Clement auto adj = rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, sliceLb, lb); 21185d27abe6SValentin Clement diff = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, diff, adj); 21195d27abe6SValentin Clement } 21205d27abe6SValentin Clement // Update the offset given the stride and the zero based index `diff` 21215d27abe6SValentin Clement // that was just computed. 21225d27abe6SValentin Clement if (baseIsBoxed) { 21235d27abe6SValentin Clement // Use stride in bytes from the descriptor. 21245d27abe6SValentin Clement mlir::Value stride = 21255d27abe6SValentin Clement loadStrideFromBox(loc, adaptor.getOperands()[0], i, rewriter); 21265d27abe6SValentin Clement auto sc = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, stride); 21275d27abe6SValentin Clement offset = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, offset); 21285d27abe6SValentin Clement } else { 21295d27abe6SValentin Clement // Use stride computed at last iteration. 21305d27abe6SValentin Clement auto sc = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, prevExt); 21315d27abe6SValentin Clement offset = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, offset); 21325d27abe6SValentin Clement // Compute next stride assuming contiguity of the base array 21335d27abe6SValentin Clement // (in element number). 2134914b9eecSKiran Chandramohan auto nextExt = integerCast(loc, rewriter, idxTy, operands[shapeOffset]); 21355d27abe6SValentin Clement prevExt = 21365d27abe6SValentin Clement rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, prevExt, nextExt); 21375d27abe6SValentin Clement } 21385d27abe6SValentin Clement } 21395d27abe6SValentin Clement 21405d27abe6SValentin Clement // Add computed offset to the base address. 21415d27abe6SValentin Clement if (baseIsBoxed) { 21425d27abe6SValentin Clement // Working with byte offsets. The base address is read from the fir.box. 21435d27abe6SValentin Clement // and need to be casted to i8* to do the pointer arithmetic. 21445d27abe6SValentin Clement mlir::Type baseTy = 21455d27abe6SValentin Clement getBaseAddrTypeFromBox(adaptor.getOperands()[0].getType()); 21465d27abe6SValentin Clement mlir::Value base = 21475d27abe6SValentin Clement loadBaseAddrFromBox(loc, baseTy, adaptor.getOperands()[0], rewriter); 21485d27abe6SValentin Clement mlir::Type voidPtrTy = getVoidPtrType(); 21495d27abe6SValentin Clement base = rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, base); 215030122656SAlex Zinenko llvm::SmallVector<mlir::Value> args{offset}; 215130122656SAlex Zinenko auto addr = 215230122656SAlex Zinenko rewriter.create<mlir::LLVM::GEPOp>(loc, voidPtrTy, base, args); 21535d27abe6SValentin Clement if (coor.subcomponent().empty()) { 21545d27abe6SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(coor, baseTy, addr); 215544e58509SEric Schweitz return mlir::success(); 21565d27abe6SValentin Clement } 21575d27abe6SValentin Clement auto casted = rewriter.create<mlir::LLVM::BitcastOp>(loc, baseTy, addr); 21585d27abe6SValentin Clement args.clear(); 21595d27abe6SValentin Clement args.push_back(zero); 21605d27abe6SValentin Clement if (!coor.lenParams().empty()) { 21615d27abe6SValentin Clement // If type parameters are present, then we don't want to use a GEPOp 21625d27abe6SValentin Clement // as below, as the LLVM struct type cannot be statically defined. 21635d27abe6SValentin Clement TODO(loc, "derived type with type parameters"); 21645d27abe6SValentin Clement } 21655d27abe6SValentin Clement // TODO: array offset subcomponents must be converted to LLVM's 21665d27abe6SValentin Clement // row-major layout here. 21675d27abe6SValentin Clement for (auto i = coor.subcomponentOffset(); i != coor.indicesOffset(); ++i) 21685d27abe6SValentin Clement args.push_back(operands[i]); 216930122656SAlex Zinenko rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(coor, baseTy, casted, 217030122656SAlex Zinenko args); 217144e58509SEric Schweitz return mlir::success(); 21725d27abe6SValentin Clement } 21735d27abe6SValentin Clement 21745d27abe6SValentin Clement // The array was not boxed, so it must be contiguous. offset is therefore an 21755d27abe6SValentin Clement // element offset and the base type is kept in the GEP unless the element 21765d27abe6SValentin Clement // type size is itself dynamic. 21775d27abe6SValentin Clement mlir::Value base; 21785d27abe6SValentin Clement if (coor.subcomponent().empty()) { 21795d27abe6SValentin Clement // No subcomponent. 21805d27abe6SValentin Clement if (!coor.lenParams().empty()) { 21815d27abe6SValentin Clement // Type parameters. Adjust element size explicitly. 21825d27abe6SValentin Clement auto eleTy = fir::dyn_cast_ptrEleTy(coor.getType()); 21835d27abe6SValentin Clement assert(eleTy && "result must be a reference-like type"); 21845d27abe6SValentin Clement if (fir::characterWithDynamicLen(eleTy)) { 21855d27abe6SValentin Clement assert(coor.lenParams().size() == 1); 21865d27abe6SValentin Clement auto bitsInChar = lowerTy().getKindMap().getCharacterBitsize( 21875d27abe6SValentin Clement eleTy.cast<fir::CharacterType>().getFKind()); 21885d27abe6SValentin Clement auto scaling = genConstantIndex(loc, idxTy, rewriter, bitsInChar / 8); 21895d27abe6SValentin Clement auto scaledBySize = 21905d27abe6SValentin Clement rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, offset, scaling); 21915d27abe6SValentin Clement auto length = 21925d27abe6SValentin Clement integerCast(loc, rewriter, idxTy, 21935d27abe6SValentin Clement adaptor.getOperands()[coor.lenParamsOffset()]); 21945d27abe6SValentin Clement offset = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, scaledBySize, 21955d27abe6SValentin Clement length); 21965d27abe6SValentin Clement } else { 21975d27abe6SValentin Clement TODO(loc, "compute size of derived type with type parameters"); 21985d27abe6SValentin Clement } 21995d27abe6SValentin Clement } 22005d27abe6SValentin Clement // Cast the base address to a pointer to T. 22015d27abe6SValentin Clement base = rewriter.create<mlir::LLVM::BitcastOp>(loc, ty, 22025d27abe6SValentin Clement adaptor.getOperands()[0]); 22035d27abe6SValentin Clement } else { 22045d27abe6SValentin Clement // Operand #0 must have a pointer type. For subcomponent slicing, we 22055d27abe6SValentin Clement // want to cast away the array type and have a plain struct type. 22065d27abe6SValentin Clement mlir::Type ty0 = adaptor.getOperands()[0].getType(); 22075d27abe6SValentin Clement auto ptrTy = ty0.dyn_cast<mlir::LLVM::LLVMPointerType>(); 22085d27abe6SValentin Clement assert(ptrTy && "expected pointer type"); 22095d27abe6SValentin Clement mlir::Type eleTy = ptrTy.getElementType(); 22105d27abe6SValentin Clement while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>()) 22115d27abe6SValentin Clement eleTy = arrTy.getElementType(); 22125d27abe6SValentin Clement auto newTy = mlir::LLVM::LLVMPointerType::get(eleTy); 22135d27abe6SValentin Clement base = rewriter.create<mlir::LLVM::BitcastOp>(loc, newTy, 22145d27abe6SValentin Clement adaptor.getOperands()[0]); 22155d27abe6SValentin Clement } 221644e58509SEric Schweitz llvm::SmallVector<mlir::Value> args = {offset}; 22175d27abe6SValentin Clement for (auto i = coor.subcomponentOffset(); i != coor.indicesOffset(); ++i) 22185d27abe6SValentin Clement args.push_back(operands[i]); 221930122656SAlex Zinenko rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(coor, ty, base, args); 222044e58509SEric Schweitz return mlir::success(); 22215d27abe6SValentin Clement } 22225d27abe6SValentin Clement }; 2223dc48849fSKiran Chandramohan } // namespace 2224dc48849fSKiran Chandramohan 2225dc48849fSKiran Chandramohan /// Convert to (memory) reference to a reference to a subobject. 2226dc48849fSKiran Chandramohan /// The coordinate_of op is a Swiss army knife operation that can be used on 2227dc48849fSKiran Chandramohan /// (memory) references to records, arrays, complex, etc. as well as boxes. 2228dc48849fSKiran Chandramohan /// With unboxed arrays, there is the restriction that the array have a static 2229dc48849fSKiran Chandramohan /// shape in all but the last column. 2230dc48849fSKiran Chandramohan struct CoordinateOpConversion 2231dc48849fSKiran Chandramohan : public FIROpAndTypeConversion<fir::CoordinateOp> { 2232dc48849fSKiran Chandramohan using FIROpAndTypeConversion::FIROpAndTypeConversion; 2233dc48849fSKiran Chandramohan 2234dc48849fSKiran Chandramohan mlir::LogicalResult 2235dc48849fSKiran Chandramohan doRewrite(fir::CoordinateOp coor, mlir::Type ty, OpAdaptor adaptor, 2236dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 2237dc48849fSKiran Chandramohan mlir::ValueRange operands = adaptor.getOperands(); 2238dc48849fSKiran Chandramohan 2239dc48849fSKiran Chandramohan mlir::Location loc = coor.getLoc(); 2240dc48849fSKiran Chandramohan mlir::Value base = operands[0]; 2241dc48849fSKiran Chandramohan mlir::Type baseObjectTy = coor.getBaseType(); 2242dc48849fSKiran Chandramohan mlir::Type objectTy = fir::dyn_cast_ptrOrBoxEleTy(baseObjectTy); 2243dc48849fSKiran Chandramohan assert(objectTy && "fir.coordinate_of expects a reference type"); 2244dc48849fSKiran Chandramohan 2245dc48849fSKiran Chandramohan // Complex type - basically, extract the real or imaginary part 2246dc48849fSKiran Chandramohan if (fir::isa_complex(objectTy)) { 2247dc48849fSKiran Chandramohan mlir::LLVM::ConstantOp c0 = 2248dc48849fSKiran Chandramohan genConstantIndex(loc, lowerTy().indexType(), rewriter, 0); 224903efa5a3SAndrzej Warzynski llvm::SmallVector<mlir::Value> offs = {c0, operands[1]}; 2250dc48849fSKiran Chandramohan mlir::Value gep = genGEP(loc, ty, rewriter, base, offs); 2251dc48849fSKiran Chandramohan rewriter.replaceOp(coor, gep); 225244e58509SEric Schweitz return mlir::success(); 2253dc48849fSKiran Chandramohan } 2254dc48849fSKiran Chandramohan 2255dc48849fSKiran Chandramohan // Boxed type - get the base pointer from the box 2256dc48849fSKiran Chandramohan if (baseObjectTy.dyn_cast<fir::BoxType>()) 2257dc48849fSKiran Chandramohan return doRewriteBox(coor, ty, operands, loc, rewriter); 2258dc48849fSKiran Chandramohan 225903efa5a3SAndrzej Warzynski // Reference, pointer or a heap type 226003efa5a3SAndrzej Warzynski if (baseObjectTy.isa<fir::ReferenceType, fir::PointerType, fir::HeapType>()) 2261dc48849fSKiran Chandramohan return doRewriteRefOrPtr(coor, ty, operands, loc, rewriter); 2262dc48849fSKiran Chandramohan 2263dc48849fSKiran Chandramohan return rewriter.notifyMatchFailure( 2264dc48849fSKiran Chandramohan coor, "fir.coordinate_of base operand has unsupported type"); 2265dc48849fSKiran Chandramohan } 2266dc48849fSKiran Chandramohan 226703efa5a3SAndrzej Warzynski static unsigned getFieldNumber(fir::RecordType ty, mlir::Value op) { 2268dc48849fSKiran Chandramohan return fir::hasDynamicSize(ty) 2269dc48849fSKiran Chandramohan ? op.getDefiningOp() 2270dc48849fSKiran Chandramohan ->getAttrOfType<mlir::IntegerAttr>("field") 2271dc48849fSKiran Chandramohan .getInt() 2272dc48849fSKiran Chandramohan : getIntValue(op); 2273dc48849fSKiran Chandramohan } 2274dc48849fSKiran Chandramohan 227503efa5a3SAndrzej Warzynski static int64_t getIntValue(mlir::Value val) { 2276dc48849fSKiran Chandramohan assert(val && val.dyn_cast<mlir::OpResult>() && "must not be null value"); 2277dc48849fSKiran Chandramohan mlir::Operation *defop = val.getDefiningOp(); 2278dc48849fSKiran Chandramohan 227944e58509SEric Schweitz if (auto constOp = mlir::dyn_cast<mlir::arith::ConstantIntOp>(defop)) 2280dc48849fSKiran Chandramohan return constOp.value(); 228144e58509SEric Schweitz if (auto llConstOp = mlir::dyn_cast<mlir::LLVM::ConstantOp>(defop)) 2282dc48849fSKiran Chandramohan if (auto attr = llConstOp.getValue().dyn_cast<mlir::IntegerAttr>()) 2283dc48849fSKiran Chandramohan return attr.getValue().getSExtValue(); 2284dc48849fSKiran Chandramohan fir::emitFatalError(val.getLoc(), "must be a constant"); 2285dc48849fSKiran Chandramohan } 2286dc48849fSKiran Chandramohan 228703efa5a3SAndrzej Warzynski static bool hasSubDimensions(mlir::Type type) { 2288dc48849fSKiran Chandramohan return type.isa<fir::SequenceType, fir::RecordType, mlir::TupleType>(); 2289dc48849fSKiran Chandramohan } 2290dc48849fSKiran Chandramohan 2291dc48849fSKiran Chandramohan /// Check whether this form of `!fir.coordinate_of` is supported. These 2292dc48849fSKiran Chandramohan /// additional checks are required, because we are not yet able to convert 2293dc48849fSKiran Chandramohan /// all valid forms of `!fir.coordinate_of`. 2294dc48849fSKiran Chandramohan /// TODO: Either implement the unsupported cases or extend the verifier 2295dc48849fSKiran Chandramohan /// in FIROps.cpp instead. 229603efa5a3SAndrzej Warzynski static bool supportedCoordinate(mlir::Type type, mlir::ValueRange coors) { 2297dc48849fSKiran Chandramohan const std::size_t numOfCoors = coors.size(); 2298dc48849fSKiran Chandramohan std::size_t i = 0; 2299dc48849fSKiran Chandramohan bool subEle = false; 2300dc48849fSKiran Chandramohan bool ptrEle = false; 2301dc48849fSKiran Chandramohan for (; i < numOfCoors; ++i) { 2302dc48849fSKiran Chandramohan mlir::Value nxtOpnd = coors[i]; 2303dc48849fSKiran Chandramohan if (auto arrTy = type.dyn_cast<fir::SequenceType>()) { 2304dc48849fSKiran Chandramohan subEle = true; 2305dc48849fSKiran Chandramohan i += arrTy.getDimension() - 1; 2306dc48849fSKiran Chandramohan type = arrTy.getEleTy(); 2307dc48849fSKiran Chandramohan } else if (auto recTy = type.dyn_cast<fir::RecordType>()) { 2308dc48849fSKiran Chandramohan subEle = true; 2309dc48849fSKiran Chandramohan type = recTy.getType(getFieldNumber(recTy, nxtOpnd)); 2310dc48849fSKiran Chandramohan } else if (auto tupTy = type.dyn_cast<mlir::TupleType>()) { 2311dc48849fSKiran Chandramohan subEle = true; 2312dc48849fSKiran Chandramohan type = tupTy.getType(getIntValue(nxtOpnd)); 2313dc48849fSKiran Chandramohan } else { 2314dc48849fSKiran Chandramohan ptrEle = true; 2315dc48849fSKiran Chandramohan } 2316dc48849fSKiran Chandramohan } 2317dc48849fSKiran Chandramohan if (ptrEle) 2318dc48849fSKiran Chandramohan return (!subEle) && (numOfCoors == 1); 2319dc48849fSKiran Chandramohan return subEle && (i >= numOfCoors); 2320dc48849fSKiran Chandramohan } 2321dc48849fSKiran Chandramohan 2322dc48849fSKiran Chandramohan /// Walk the abstract memory layout and determine if the path traverses any 2323dc48849fSKiran Chandramohan /// array types with unknown shape. Return true iff all the array types have a 2324dc48849fSKiran Chandramohan /// constant shape along the path. 232503efa5a3SAndrzej Warzynski static bool arraysHaveKnownShape(mlir::Type type, mlir::ValueRange coors) { 232603efa5a3SAndrzej Warzynski for (std::size_t i = 0, sz = coors.size(); i < sz; ++i) { 2327dc48849fSKiran Chandramohan mlir::Value nxtOpnd = coors[i]; 2328dc48849fSKiran Chandramohan if (auto arrTy = type.dyn_cast<fir::SequenceType>()) { 2329dc48849fSKiran Chandramohan if (fir::sequenceWithNonConstantShape(arrTy)) 2330dc48849fSKiran Chandramohan return false; 2331dc48849fSKiran Chandramohan i += arrTy.getDimension() - 1; 2332dc48849fSKiran Chandramohan type = arrTy.getEleTy(); 2333dc48849fSKiran Chandramohan } else if (auto strTy = type.dyn_cast<fir::RecordType>()) { 2334dc48849fSKiran Chandramohan type = strTy.getType(getFieldNumber(strTy, nxtOpnd)); 2335dc48849fSKiran Chandramohan } else if (auto strTy = type.dyn_cast<mlir::TupleType>()) { 2336dc48849fSKiran Chandramohan type = strTy.getType(getIntValue(nxtOpnd)); 2337dc48849fSKiran Chandramohan } else { 2338dc48849fSKiran Chandramohan return true; 2339dc48849fSKiran Chandramohan } 2340dc48849fSKiran Chandramohan } 2341dc48849fSKiran Chandramohan return true; 2342dc48849fSKiran Chandramohan } 2343dc48849fSKiran Chandramohan 2344dc48849fSKiran Chandramohan private: 2345dc48849fSKiran Chandramohan mlir::LogicalResult 2346dc48849fSKiran Chandramohan doRewriteBox(fir::CoordinateOp coor, mlir::Type ty, mlir::ValueRange operands, 2347dc48849fSKiran Chandramohan mlir::Location loc, 2348dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const { 2349dc48849fSKiran Chandramohan mlir::Type boxObjTy = coor.getBaseType(); 2350dc48849fSKiran Chandramohan assert(boxObjTy.dyn_cast<fir::BoxType>() && "This is not a `fir.box`"); 2351dc48849fSKiran Chandramohan 2352dc48849fSKiran Chandramohan mlir::Value boxBaseAddr = operands[0]; 2353dc48849fSKiran Chandramohan 2354dc48849fSKiran Chandramohan // 1. SPECIAL CASE (uses `fir.len_param_index`): 2355dc48849fSKiran Chandramohan // %box = ... : !fir.box<!fir.type<derived{len1:i32}>> 2356dc48849fSKiran Chandramohan // %lenp = fir.len_param_index len1, !fir.type<derived{len1:i32}> 2357dc48849fSKiran Chandramohan // %addr = coordinate_of %box, %lenp 2358dc48849fSKiran Chandramohan if (coor.getNumOperands() == 2) { 2359dc48849fSKiran Chandramohan mlir::Operation *coordinateDef = 2360dc48849fSKiran Chandramohan (*coor.getCoor().begin()).getDefiningOp(); 236144e58509SEric Schweitz if (mlir::isa_and_nonnull<fir::LenParamIndexOp>(coordinateDef)) 2362dc48849fSKiran Chandramohan TODO(loc, 2363dc48849fSKiran Chandramohan "fir.coordinate_of - fir.len_param_index is not supported yet"); 2364dc48849fSKiran Chandramohan } 2365dc48849fSKiran Chandramohan 2366dc48849fSKiran Chandramohan // 2. GENERAL CASE: 2367dc48849fSKiran Chandramohan // 2.1. (`fir.array`) 2368dc48849fSKiran Chandramohan // %box = ... : !fix.box<!fir.array<?xU>> 2369dc48849fSKiran Chandramohan // %idx = ... : index 2370dc48849fSKiran Chandramohan // %resultAddr = coordinate_of %box, %idx : !fir.ref<U> 2371dc48849fSKiran Chandramohan // 2.2 (`fir.derived`) 2372dc48849fSKiran Chandramohan // %box = ... : !fix.box<!fir.type<derived_type{field_1:i32}>> 2373dc48849fSKiran Chandramohan // %idx = ... : i32 2374dc48849fSKiran Chandramohan // %resultAddr = coordinate_of %box, %idx : !fir.ref<i32> 2375dc48849fSKiran Chandramohan // 2.3 (`fir.derived` inside `fir.array`) 2376dc48849fSKiran Chandramohan // %box = ... : !fir.box<!fir.array<10 x !fir.type<derived_1{field_1:f32, 2377dc48849fSKiran Chandramohan // field_2:f32}>>> %idx1 = ... : index %idx2 = ... : i32 %resultAddr = 2378dc48849fSKiran Chandramohan // coordinate_of %box, %idx1, %idx2 : !fir.ref<f32> 2379dc48849fSKiran Chandramohan // 2.4. TODO: Either document or disable any other case that the following 2380dc48849fSKiran Chandramohan // implementation might convert. 2381dc48849fSKiran Chandramohan mlir::LLVM::ConstantOp c0 = 2382dc48849fSKiran Chandramohan genConstantIndex(loc, lowerTy().indexType(), rewriter, 0); 2383dc48849fSKiran Chandramohan mlir::Value resultAddr = 2384dc48849fSKiran Chandramohan loadBaseAddrFromBox(loc, getBaseAddrTypeFromBox(boxBaseAddr.getType()), 2385dc48849fSKiran Chandramohan boxBaseAddr, rewriter); 238603efa5a3SAndrzej Warzynski // Component Type 238703efa5a3SAndrzej Warzynski auto cpnTy = fir::dyn_cast_ptrOrBoxEleTy(boxObjTy); 2388dc48849fSKiran Chandramohan mlir::Type voidPtrTy = ::getVoidPtrType(coor.getContext()); 2389dc48849fSKiran Chandramohan 2390dc48849fSKiran Chandramohan for (unsigned i = 1, last = operands.size(); i < last; ++i) { 239103efa5a3SAndrzej Warzynski if (auto arrTy = cpnTy.dyn_cast<fir::SequenceType>()) { 2392dc48849fSKiran Chandramohan if (i != 1) 2393dc48849fSKiran Chandramohan TODO(loc, "fir.array nested inside other array and/or derived type"); 2394dc48849fSKiran Chandramohan // Applies byte strides from the box. Ignore lower bound from box 2395dc48849fSKiran Chandramohan // since fir.coordinate_of indexes are zero based. Lowering takes care 2396dc48849fSKiran Chandramohan // of lower bound aspects. This both accounts for dynamically sized 2397dc48849fSKiran Chandramohan // types and non contiguous arrays. 2398dc48849fSKiran Chandramohan auto idxTy = lowerTy().indexType(); 2399dc48849fSKiran Chandramohan mlir::Value off = genConstantIndex(loc, idxTy, rewriter, 0); 2400dc48849fSKiran Chandramohan for (unsigned index = i, lastIndex = i + arrTy.getDimension(); 2401dc48849fSKiran Chandramohan index < lastIndex; ++index) { 2402dc48849fSKiran Chandramohan mlir::Value stride = 2403dc48849fSKiran Chandramohan loadStrideFromBox(loc, operands[0], index - i, rewriter); 2404dc48849fSKiran Chandramohan auto sc = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, 2405dc48849fSKiran Chandramohan operands[index], stride); 2406dc48849fSKiran Chandramohan off = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, off); 2407dc48849fSKiran Chandramohan } 2408dc48849fSKiran Chandramohan auto voidPtrBase = 2409dc48849fSKiran Chandramohan rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, resultAddr); 2410575c9d6dSValentin Clement llvm::SmallVector<mlir::Value> args = {off}; 2411dc48849fSKiran Chandramohan resultAddr = rewriter.create<mlir::LLVM::GEPOp>(loc, voidPtrTy, 2412dc48849fSKiran Chandramohan voidPtrBase, args); 2413dc48849fSKiran Chandramohan i += arrTy.getDimension() - 1; 241403efa5a3SAndrzej Warzynski cpnTy = arrTy.getEleTy(); 241503efa5a3SAndrzej Warzynski } else if (auto recTy = cpnTy.dyn_cast<fir::RecordType>()) { 2416dc48849fSKiran Chandramohan auto recRefTy = 2417dc48849fSKiran Chandramohan mlir::LLVM::LLVMPointerType::get(lowerTy().convertType(recTy)); 2418dc48849fSKiran Chandramohan mlir::Value nxtOpnd = operands[i]; 2419dc48849fSKiran Chandramohan auto memObj = 2420dc48849fSKiran Chandramohan rewriter.create<mlir::LLVM::BitcastOp>(loc, recRefTy, resultAddr); 2421dc48849fSKiran Chandramohan llvm::SmallVector<mlir::Value> args = {c0, nxtOpnd}; 242203efa5a3SAndrzej Warzynski cpnTy = recTy.getType(getFieldNumber(recTy, nxtOpnd)); 242303efa5a3SAndrzej Warzynski auto llvmCurrentObjTy = lowerTy().convertType(cpnTy); 2424dc48849fSKiran Chandramohan auto gep = rewriter.create<mlir::LLVM::GEPOp>( 2425dc48849fSKiran Chandramohan loc, mlir::LLVM::LLVMPointerType::get(llvmCurrentObjTy), memObj, 2426dc48849fSKiran Chandramohan args); 2427dc48849fSKiran Chandramohan resultAddr = 2428dc48849fSKiran Chandramohan rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, gep); 2429dc48849fSKiran Chandramohan } else { 2430dc48849fSKiran Chandramohan fir::emitFatalError(loc, "unexpected type in coordinate_of"); 2431dc48849fSKiran Chandramohan } 2432dc48849fSKiran Chandramohan } 2433dc48849fSKiran Chandramohan 2434dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(coor, ty, resultAddr); 243544e58509SEric Schweitz return mlir::success(); 2436dc48849fSKiran Chandramohan } 2437dc48849fSKiran Chandramohan 2438dc48849fSKiran Chandramohan mlir::LogicalResult 2439dc48849fSKiran Chandramohan doRewriteRefOrPtr(fir::CoordinateOp coor, mlir::Type ty, 2440dc48849fSKiran Chandramohan mlir::ValueRange operands, mlir::Location loc, 2441dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const { 2442dc48849fSKiran Chandramohan mlir::Type baseObjectTy = coor.getBaseType(); 2443dc48849fSKiran Chandramohan 244403efa5a3SAndrzej Warzynski // Component Type 244503efa5a3SAndrzej Warzynski mlir::Type cpnTy = fir::dyn_cast_ptrOrBoxEleTy(baseObjectTy); 244603efa5a3SAndrzej Warzynski bool hasSubdimension = hasSubDimensions(cpnTy); 2447dc48849fSKiran Chandramohan bool columnIsDeferred = !hasSubdimension; 2448dc48849fSKiran Chandramohan 244903efa5a3SAndrzej Warzynski if (!supportedCoordinate(cpnTy, operands.drop_front(1))) 2450dc48849fSKiran Chandramohan TODO(loc, "unsupported combination of coordinate operands"); 2451dc48849fSKiran Chandramohan 2452dc48849fSKiran Chandramohan const bool hasKnownShape = 245303efa5a3SAndrzej Warzynski arraysHaveKnownShape(cpnTy, operands.drop_front(1)); 2454dc48849fSKiran Chandramohan 2455dc48849fSKiran Chandramohan // If only the column is `?`, then we can simply place the column value in 2456dc48849fSKiran Chandramohan // the 0-th GEP position. 245703efa5a3SAndrzej Warzynski if (auto arrTy = cpnTy.dyn_cast<fir::SequenceType>()) { 2458dc48849fSKiran Chandramohan if (!hasKnownShape) { 2459dc48849fSKiran Chandramohan const unsigned sz = arrTy.getDimension(); 2460dc48849fSKiran Chandramohan if (arraysHaveKnownShape(arrTy.getEleTy(), 2461dc48849fSKiran Chandramohan operands.drop_front(1 + sz))) { 246203efa5a3SAndrzej Warzynski fir::SequenceType::ShapeRef shape = arrTy.getShape(); 2463dc48849fSKiran Chandramohan bool allConst = true; 2464dc48849fSKiran Chandramohan for (unsigned i = 0; i < sz - 1; ++i) { 2465dc48849fSKiran Chandramohan if (shape[i] < 0) { 2466dc48849fSKiran Chandramohan allConst = false; 2467dc48849fSKiran Chandramohan break; 2468dc48849fSKiran Chandramohan } 2469dc48849fSKiran Chandramohan } 2470dc48849fSKiran Chandramohan if (allConst) 2471dc48849fSKiran Chandramohan columnIsDeferred = true; 2472dc48849fSKiran Chandramohan } 2473dc48849fSKiran Chandramohan } 2474dc48849fSKiran Chandramohan } 2475dc48849fSKiran Chandramohan 247603efa5a3SAndrzej Warzynski if (fir::hasDynamicSize(fir::unwrapSequenceType(cpnTy))) 247703efa5a3SAndrzej Warzynski return mlir::emitError( 2478dc48849fSKiran Chandramohan loc, "fir.coordinate_of with a dynamic element size is unsupported"); 2479dc48849fSKiran Chandramohan 2480dc48849fSKiran Chandramohan if (hasKnownShape || columnIsDeferred) { 248144e58509SEric Schweitz llvm::SmallVector<mlir::Value> offs; 2482dc48849fSKiran Chandramohan if (hasKnownShape && hasSubdimension) { 2483dc48849fSKiran Chandramohan mlir::LLVM::ConstantOp c0 = 2484dc48849fSKiran Chandramohan genConstantIndex(loc, lowerTy().indexType(), rewriter, 0); 2485dc48849fSKiran Chandramohan offs.push_back(c0); 2486dc48849fSKiran Chandramohan } 248744e58509SEric Schweitz llvm::Optional<int> dims; 248844e58509SEric Schweitz llvm::SmallVector<mlir::Value> arrIdx; 248903efa5a3SAndrzej Warzynski for (std::size_t i = 1, sz = operands.size(); i < sz; ++i) { 2490dc48849fSKiran Chandramohan mlir::Value nxtOpnd = operands[i]; 2491dc48849fSKiran Chandramohan 249203efa5a3SAndrzej Warzynski if (!cpnTy) 249303efa5a3SAndrzej Warzynski return mlir::emitError(loc, "invalid coordinate/check failed"); 2494dc48849fSKiran Chandramohan 2495dc48849fSKiran Chandramohan // check if the i-th coordinate relates to an array 24965413bf1bSKazu Hirata if (dims) { 2497dc48849fSKiran Chandramohan arrIdx.push_back(nxtOpnd); 2498dc48849fSKiran Chandramohan int dimsLeft = *dims; 2499dc48849fSKiran Chandramohan if (dimsLeft > 1) { 2500dc48849fSKiran Chandramohan dims = dimsLeft - 1; 2501dc48849fSKiran Chandramohan continue; 2502dc48849fSKiran Chandramohan } 250303efa5a3SAndrzej Warzynski cpnTy = cpnTy.cast<fir::SequenceType>().getEleTy(); 2504dc48849fSKiran Chandramohan // append array range in reverse (FIR arrays are column-major) 2505dc48849fSKiran Chandramohan offs.append(arrIdx.rbegin(), arrIdx.rend()); 2506dc48849fSKiran Chandramohan arrIdx.clear(); 2507dc48849fSKiran Chandramohan dims.reset(); 2508dc48849fSKiran Chandramohan continue; 2509dc48849fSKiran Chandramohan } 251003efa5a3SAndrzej Warzynski if (auto arrTy = cpnTy.dyn_cast<fir::SequenceType>()) { 2511dc48849fSKiran Chandramohan int d = arrTy.getDimension() - 1; 2512dc48849fSKiran Chandramohan if (d > 0) { 2513dc48849fSKiran Chandramohan dims = d; 2514dc48849fSKiran Chandramohan arrIdx.push_back(nxtOpnd); 2515dc48849fSKiran Chandramohan continue; 2516dc48849fSKiran Chandramohan } 251703efa5a3SAndrzej Warzynski cpnTy = cpnTy.cast<fir::SequenceType>().getEleTy(); 2518dc48849fSKiran Chandramohan offs.push_back(nxtOpnd); 2519dc48849fSKiran Chandramohan continue; 2520dc48849fSKiran Chandramohan } 2521dc48849fSKiran Chandramohan 2522dc48849fSKiran Chandramohan // check if the i-th coordinate relates to a field 252303efa5a3SAndrzej Warzynski if (auto recTy = cpnTy.dyn_cast<fir::RecordType>()) 252403efa5a3SAndrzej Warzynski cpnTy = recTy.getType(getFieldNumber(recTy, nxtOpnd)); 252503efa5a3SAndrzej Warzynski else if (auto tupTy = cpnTy.dyn_cast<mlir::TupleType>()) 252603efa5a3SAndrzej Warzynski cpnTy = tupTy.getType(getIntValue(nxtOpnd)); 2527dc48849fSKiran Chandramohan else 252803efa5a3SAndrzej Warzynski cpnTy = nullptr; 2529dc48849fSKiran Chandramohan 2530dc48849fSKiran Chandramohan offs.push_back(nxtOpnd); 2531dc48849fSKiran Chandramohan } 25325413bf1bSKazu Hirata if (dims) 2533dc48849fSKiran Chandramohan offs.append(arrIdx.rbegin(), arrIdx.rend()); 2534dc48849fSKiran Chandramohan mlir::Value base = operands[0]; 2535dc48849fSKiran Chandramohan mlir::Value retval = genGEP(loc, ty, rewriter, base, offs); 2536dc48849fSKiran Chandramohan rewriter.replaceOp(coor, retval); 253744e58509SEric Schweitz return mlir::success(); 2538dc48849fSKiran Chandramohan } 2539dc48849fSKiran Chandramohan 254003efa5a3SAndrzej Warzynski return mlir::emitError( 254103efa5a3SAndrzej Warzynski loc, "fir.coordinate_of base operand has unsupported type"); 2542dc48849fSKiran Chandramohan } 2543dc48849fSKiran Chandramohan }; 2544dc48849fSKiran Chandramohan 2545dc48849fSKiran Chandramohan /// Convert `fir.field_index`. The conversion depends on whether the size of 2546dc48849fSKiran Chandramohan /// the record is static or dynamic. 2547dc48849fSKiran Chandramohan struct FieldIndexOpConversion : public FIROpConversion<fir::FieldIndexOp> { 2548dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 2549dc48849fSKiran Chandramohan 2550dc48849fSKiran Chandramohan // NB: most field references should be resolved by this point 2551dc48849fSKiran Chandramohan mlir::LogicalResult 2552dc48849fSKiran Chandramohan matchAndRewrite(fir::FieldIndexOp field, OpAdaptor adaptor, 2553dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 2554dc48849fSKiran Chandramohan auto recTy = field.getOnType().cast<fir::RecordType>(); 2555dc48849fSKiran Chandramohan unsigned index = recTy.getFieldIndex(field.getFieldId()); 2556dc48849fSKiran Chandramohan 2557dc48849fSKiran Chandramohan if (!fir::hasDynamicSize(recTy)) { 2558dc48849fSKiran Chandramohan // Derived type has compile-time constant layout. Return index of the 2559dc48849fSKiran Chandramohan // component type in the parent type (to be used in GEP). 2560dc48849fSKiran Chandramohan rewriter.replaceOp(field, mlir::ValueRange{genConstantOffset( 2561dc48849fSKiran Chandramohan field.getLoc(), rewriter, index)}); 256244e58509SEric Schweitz return mlir::success(); 2563dc48849fSKiran Chandramohan } 2564dc48849fSKiran Chandramohan 2565dc48849fSKiran Chandramohan // Derived type has compile-time constant layout. Call the compiler 2566dc48849fSKiran Chandramohan // generated function to determine the byte offset of the field at runtime. 2567dc48849fSKiran Chandramohan // This returns a non-constant. 256844e58509SEric Schweitz mlir::FlatSymbolRefAttr symAttr = mlir::SymbolRefAttr::get( 2569dc48849fSKiran Chandramohan field.getContext(), getOffsetMethodName(recTy, field.getFieldId())); 257044e58509SEric Schweitz mlir::NamedAttribute callAttr = rewriter.getNamedAttr("callee", symAttr); 257144e58509SEric Schweitz mlir::NamedAttribute fieldAttr = rewriter.getNamedAttr( 2572dc48849fSKiran Chandramohan "field", mlir::IntegerAttr::get(lowerTy().indexType(), index)); 2573dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>( 2574dc48849fSKiran Chandramohan field, lowerTy().offsetType(), adaptor.getOperands(), 2575dc48849fSKiran Chandramohan llvm::ArrayRef<mlir::NamedAttribute>{callAttr, fieldAttr}); 257644e58509SEric Schweitz return mlir::success(); 2577dc48849fSKiran Chandramohan } 2578dc48849fSKiran Chandramohan 2579dc48849fSKiran Chandramohan // Re-Construct the name of the compiler generated method that calculates the 2580dc48849fSKiran Chandramohan // offset 2581dc48849fSKiran Chandramohan inline static std::string getOffsetMethodName(fir::RecordType recTy, 2582dc48849fSKiran Chandramohan llvm::StringRef field) { 2583dc48849fSKiran Chandramohan return recTy.getName().str() + "P." + field.str() + ".offset"; 2584dc48849fSKiran Chandramohan } 2585dc48849fSKiran Chandramohan }; 2586dc48849fSKiran Chandramohan 2587dc48849fSKiran Chandramohan /// Convert `fir.end` 2588dc48849fSKiran Chandramohan struct FirEndOpConversion : public FIROpConversion<fir::FirEndOp> { 2589dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 2590dc48849fSKiran Chandramohan 2591dc48849fSKiran Chandramohan mlir::LogicalResult 2592dc48849fSKiran Chandramohan matchAndRewrite(fir::FirEndOp firEnd, OpAdaptor, 2593dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 2594dc48849fSKiran Chandramohan TODO(firEnd.getLoc(), "fir.end codegen"); 259544e58509SEric Schweitz return mlir::failure(); 2596dc48849fSKiran Chandramohan } 2597dc48849fSKiran Chandramohan }; 2598dc48849fSKiran Chandramohan 2599dc48849fSKiran Chandramohan /// Lower `fir.gentypedesc` to a global constant. 2600dc48849fSKiran Chandramohan struct GenTypeDescOpConversion : public FIROpConversion<fir::GenTypeDescOp> { 2601dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 2602dc48849fSKiran Chandramohan 2603dc48849fSKiran Chandramohan mlir::LogicalResult 2604dc48849fSKiran Chandramohan matchAndRewrite(fir::GenTypeDescOp gentypedesc, OpAdaptor adaptor, 2605dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 2606dc48849fSKiran Chandramohan TODO(gentypedesc.getLoc(), "fir.gentypedesc codegen"); 260744e58509SEric Schweitz return mlir::failure(); 2608dc48849fSKiran Chandramohan } 2609dc48849fSKiran Chandramohan }; 2610dc48849fSKiran Chandramohan 2611dc48849fSKiran Chandramohan /// Lower `fir.has_value` operation to `llvm.return` operation. 2612dc48849fSKiran Chandramohan struct HasValueOpConversion : public FIROpConversion<fir::HasValueOp> { 2613dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 2614dc48849fSKiran Chandramohan 2615dc48849fSKiran Chandramohan mlir::LogicalResult 2616dc48849fSKiran Chandramohan matchAndRewrite(fir::HasValueOp op, OpAdaptor adaptor, 2617dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 261844e58509SEric Schweitz rewriter.replaceOpWithNewOp<mlir::LLVM::ReturnOp>(op, 261944e58509SEric Schweitz adaptor.getOperands()); 262044e58509SEric Schweitz return mlir::success(); 2621dc48849fSKiran Chandramohan } 2622dc48849fSKiran Chandramohan }; 2623dc48849fSKiran Chandramohan 2624dc48849fSKiran Chandramohan /// Lower `fir.global` operation to `llvm.global` operation. 2625dc48849fSKiran Chandramohan /// `fir.insert_on_range` operations are replaced with constant dense attribute 2626dc48849fSKiran Chandramohan /// if they are applied on the full range. 2627dc48849fSKiran Chandramohan struct GlobalOpConversion : public FIROpConversion<fir::GlobalOp> { 2628dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 2629dc48849fSKiran Chandramohan 2630dc48849fSKiran Chandramohan mlir::LogicalResult 2631dc48849fSKiran Chandramohan matchAndRewrite(fir::GlobalOp global, OpAdaptor adaptor, 2632dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 2633dc48849fSKiran Chandramohan auto tyAttr = convertType(global.getType()); 2634dc48849fSKiran Chandramohan if (global.getType().isa<fir::BoxType>()) 2635dc48849fSKiran Chandramohan tyAttr = tyAttr.cast<mlir::LLVM::LLVMPointerType>().getElementType(); 2636dc48849fSKiran Chandramohan auto loc = global.getLoc(); 2637575c9d6dSValentin Clement mlir::Attribute initAttr; 2638dc48849fSKiran Chandramohan if (global.getInitVal()) 26393b7c3a65SKazu Hirata initAttr = global.getInitVal().getValue(); 2640dc48849fSKiran Chandramohan auto linkage = convertLinkage(global.getLinkName()); 26413b7c3a65SKazu Hirata auto isConst = global.getConstant().hasValue(); 2642dc48849fSKiran Chandramohan auto g = rewriter.create<mlir::LLVM::GlobalOp>( 2643dc48849fSKiran Chandramohan loc, tyAttr, isConst, linkage, global.getSymName(), initAttr); 2644dc48849fSKiran Chandramohan auto &gr = g.getInitializerRegion(); 2645dc48849fSKiran Chandramohan rewriter.inlineRegionBefore(global.getRegion(), gr, gr.end()); 2646dc48849fSKiran Chandramohan if (!gr.empty()) { 2647dc48849fSKiran Chandramohan // Replace insert_on_range with a constant dense attribute if the 2648dc48849fSKiran Chandramohan // initialization is on the full range. 2649dc48849fSKiran Chandramohan auto insertOnRangeOps = gr.front().getOps<fir::InsertOnRangeOp>(); 2650dc48849fSKiran Chandramohan for (auto insertOp : insertOnRangeOps) { 2651dc48849fSKiran Chandramohan if (isFullRange(insertOp.getCoor(), insertOp.getType())) { 2652dc48849fSKiran Chandramohan auto seqTyAttr = convertType(insertOp.getType()); 2653dc48849fSKiran Chandramohan auto *op = insertOp.getVal().getDefiningOp(); 2654dc48849fSKiran Chandramohan auto constant = mlir::dyn_cast<mlir::arith::ConstantOp>(op); 2655dc48849fSKiran Chandramohan if (!constant) { 2656dc48849fSKiran Chandramohan auto convertOp = mlir::dyn_cast<fir::ConvertOp>(op); 2657dc48849fSKiran Chandramohan if (!convertOp) 2658dc48849fSKiran Chandramohan continue; 265944e58509SEric Schweitz constant = mlir::cast<mlir::arith::ConstantOp>( 2660dc48849fSKiran Chandramohan convertOp.getValue().getDefiningOp()); 2661dc48849fSKiran Chandramohan } 2662dc48849fSKiran Chandramohan mlir::Type vecType = mlir::VectorType::get( 2663dc48849fSKiran Chandramohan insertOp.getType().getShape(), constant.getType()); 2664dc48849fSKiran Chandramohan auto denseAttr = mlir::DenseElementsAttr::get( 266544e58509SEric Schweitz vecType.cast<mlir::ShapedType>(), constant.getValue()); 2666dc48849fSKiran Chandramohan rewriter.setInsertionPointAfter(insertOp); 2667dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>( 2668dc48849fSKiran Chandramohan insertOp, seqTyAttr, denseAttr); 2669dc48849fSKiran Chandramohan } 2670dc48849fSKiran Chandramohan } 2671dc48849fSKiran Chandramohan } 2672dc48849fSKiran Chandramohan rewriter.eraseOp(global); 267344e58509SEric Schweitz return mlir::success(); 2674dc48849fSKiran Chandramohan } 2675dc48849fSKiran Chandramohan 2676dc48849fSKiran Chandramohan bool isFullRange(mlir::DenseIntElementsAttr indexes, 2677dc48849fSKiran Chandramohan fir::SequenceType seqTy) const { 2678dc48849fSKiran Chandramohan auto extents = seqTy.getShape(); 2679dc48849fSKiran Chandramohan if (indexes.size() / 2 != static_cast<int64_t>(extents.size())) 2680dc48849fSKiran Chandramohan return false; 2681dc48849fSKiran Chandramohan auto cur_index = indexes.value_begin<int64_t>(); 2682dc48849fSKiran Chandramohan for (unsigned i = 0; i < indexes.size(); i += 2) { 2683dc48849fSKiran Chandramohan if (*(cur_index++) != 0) 2684dc48849fSKiran Chandramohan return false; 2685dc48849fSKiran Chandramohan if (*(cur_index++) != extents[i / 2] - 1) 2686dc48849fSKiran Chandramohan return false; 2687dc48849fSKiran Chandramohan } 2688dc48849fSKiran Chandramohan return true; 2689dc48849fSKiran Chandramohan } 2690dc48849fSKiran Chandramohan 2691dc48849fSKiran Chandramohan // TODO: String comparaison should be avoided. Replace linkName with an 2692dc48849fSKiran Chandramohan // enumeration. 269344e58509SEric Schweitz mlir::LLVM::Linkage 269444e58509SEric Schweitz convertLinkage(llvm::Optional<llvm::StringRef> optLinkage) const { 26953b7c3a65SKazu Hirata if (optLinkage.hasValue()) { 26963b7c3a65SKazu Hirata auto name = optLinkage.getValue(); 2697dc48849fSKiran Chandramohan if (name == "internal") 2698dc48849fSKiran Chandramohan return mlir::LLVM::Linkage::Internal; 2699dc48849fSKiran Chandramohan if (name == "linkonce") 2700dc48849fSKiran Chandramohan return mlir::LLVM::Linkage::Linkonce; 270130a0fbf5SJean Perier if (name == "linkonce_odr") 270230a0fbf5SJean Perier return mlir::LLVM::Linkage::LinkonceODR; 2703dc48849fSKiran Chandramohan if (name == "common") 2704dc48849fSKiran Chandramohan return mlir::LLVM::Linkage::Common; 2705dc48849fSKiran Chandramohan if (name == "weak") 2706dc48849fSKiran Chandramohan return mlir::LLVM::Linkage::Weak; 2707dc48849fSKiran Chandramohan } 2708dc48849fSKiran Chandramohan return mlir::LLVM::Linkage::External; 2709dc48849fSKiran Chandramohan } 2710dc48849fSKiran Chandramohan }; 2711dc48849fSKiran Chandramohan 2712dc48849fSKiran Chandramohan /// `fir.load` --> `llvm.load` 2713dc48849fSKiran Chandramohan struct LoadOpConversion : public FIROpConversion<fir::LoadOp> { 2714dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 2715dc48849fSKiran Chandramohan 2716dc48849fSKiran Chandramohan mlir::LogicalResult 2717dc48849fSKiran Chandramohan matchAndRewrite(fir::LoadOp load, OpAdaptor adaptor, 2718dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 2719dc48849fSKiran Chandramohan // fir.box is a special case because it is considered as an ssa values in 2720dc48849fSKiran Chandramohan // fir, but it is lowered as a pointer to a descriptor. So fir.ref<fir.box> 2721dc48849fSKiran Chandramohan // and fir.box end up being the same llvm types and loading a 2722dc48849fSKiran Chandramohan // fir.ref<fir.box> is actually a no op in LLVM. 2723dc48849fSKiran Chandramohan if (load.getType().isa<fir::BoxType>()) { 2724dc48849fSKiran Chandramohan rewriter.replaceOp(load, adaptor.getOperands()[0]); 2725dc48849fSKiran Chandramohan } else { 2726dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::LoadOp>( 272744e58509SEric Schweitz load, convertType(load.getType()), adaptor.getOperands(), 272844e58509SEric Schweitz load->getAttrs()); 2729dc48849fSKiran Chandramohan } 273044e58509SEric Schweitz return mlir::success(); 2731dc48849fSKiran Chandramohan } 2732dc48849fSKiran Chandramohan }; 2733dc48849fSKiran Chandramohan 2734dc48849fSKiran Chandramohan /// Lower `fir.no_reassoc` to LLVM IR dialect. 2735dc48849fSKiran Chandramohan /// TODO: how do we want to enforce this in LLVM-IR? Can we manipulate the fast 2736dc48849fSKiran Chandramohan /// math flags? 2737dc48849fSKiran Chandramohan struct NoReassocOpConversion : public FIROpConversion<fir::NoReassocOp> { 2738dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 2739dc48849fSKiran Chandramohan 2740dc48849fSKiran Chandramohan mlir::LogicalResult 2741dc48849fSKiran Chandramohan matchAndRewrite(fir::NoReassocOp noreassoc, OpAdaptor adaptor, 2742dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 2743dc48849fSKiran Chandramohan rewriter.replaceOp(noreassoc, adaptor.getOperands()[0]); 274444e58509SEric Schweitz return mlir::success(); 2745dc48849fSKiran Chandramohan } 2746dc48849fSKiran Chandramohan }; 2747dc48849fSKiran Chandramohan 2748dc48849fSKiran Chandramohan static void genCondBrOp(mlir::Location loc, mlir::Value cmp, mlir::Block *dest, 274944e58509SEric Schweitz llvm::Optional<mlir::ValueRange> destOps, 2750dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter, 2751dc48849fSKiran Chandramohan mlir::Block *newBlock) { 27523b7c3a65SKazu Hirata if (destOps.hasValue()) 27533b7c3a65SKazu Hirata rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, destOps.getValue(), 27543b7c3a65SKazu Hirata newBlock, mlir::ValueRange()); 2755dc48849fSKiran Chandramohan else 2756dc48849fSKiran Chandramohan rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, newBlock); 2757dc48849fSKiran Chandramohan } 2758dc48849fSKiran Chandramohan 2759dc48849fSKiran Chandramohan template <typename A, typename B> 276044e58509SEric Schweitz static void genBrOp(A caseOp, mlir::Block *dest, llvm::Optional<B> destOps, 2761dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) { 27623b7c3a65SKazu Hirata if (destOps.hasValue()) 27633b7c3a65SKazu Hirata rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, destOps.getValue(), 27643b7c3a65SKazu Hirata dest); 2765dc48849fSKiran Chandramohan else 2766dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, llvm::None, dest); 2767dc48849fSKiran Chandramohan } 2768dc48849fSKiran Chandramohan 2769dc48849fSKiran Chandramohan static void genCaseLadderStep(mlir::Location loc, mlir::Value cmp, 2770dc48849fSKiran Chandramohan mlir::Block *dest, 277144e58509SEric Schweitz llvm::Optional<mlir::ValueRange> destOps, 2772dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) { 2773dc48849fSKiran Chandramohan auto *thisBlock = rewriter.getInsertionBlock(); 2774dc48849fSKiran Chandramohan auto *newBlock = createBlock(rewriter, dest); 2775dc48849fSKiran Chandramohan rewriter.setInsertionPointToEnd(thisBlock); 2776dc48849fSKiran Chandramohan genCondBrOp(loc, cmp, dest, destOps, rewriter, newBlock); 2777dc48849fSKiran Chandramohan rewriter.setInsertionPointToEnd(newBlock); 2778dc48849fSKiran Chandramohan } 2779dc48849fSKiran Chandramohan 2780dc48849fSKiran Chandramohan /// Conversion of `fir.select_case` 2781dc48849fSKiran Chandramohan /// 2782dc48849fSKiran Chandramohan /// The `fir.select_case` operation is converted to a if-then-else ladder. 2783dc48849fSKiran Chandramohan /// Depending on the case condition type, one or several comparison and 2784dc48849fSKiran Chandramohan /// conditional branching can be generated. 2785dc48849fSKiran Chandramohan /// 2786dc48849fSKiran Chandramohan /// A a point value case such as `case(4)`, a lower bound case such as 2787dc48849fSKiran Chandramohan /// `case(5:)` or an upper bound case such as `case(:3)` are converted to a 2788dc48849fSKiran Chandramohan /// simple comparison between the selector value and the constant value in the 2789dc48849fSKiran Chandramohan /// case. The block associated with the case condition is then executed if 2790dc48849fSKiran Chandramohan /// the comparison succeed otherwise it branch to the next block with the 2791dc48849fSKiran Chandramohan /// comparison for the the next case conditon. 2792dc48849fSKiran Chandramohan /// 2793dc48849fSKiran Chandramohan /// A closed interval case condition such as `case(7:10)` is converted with a 2794dc48849fSKiran Chandramohan /// first comparison and conditional branching for the lower bound. If 2795dc48849fSKiran Chandramohan /// successful, it branch to a second block with the comparison for the 2796dc48849fSKiran Chandramohan /// upper bound in the same case condition. 2797dc48849fSKiran Chandramohan /// 2798dc48849fSKiran Chandramohan /// TODO: lowering of CHARACTER type cases is not handled yet. 2799dc48849fSKiran Chandramohan struct SelectCaseOpConversion : public FIROpConversion<fir::SelectCaseOp> { 2800dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 2801dc48849fSKiran Chandramohan 2802dc48849fSKiran Chandramohan mlir::LogicalResult 2803dc48849fSKiran Chandramohan matchAndRewrite(fir::SelectCaseOp caseOp, OpAdaptor adaptor, 2804dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 2805dc48849fSKiran Chandramohan unsigned conds = caseOp.getNumConditions(); 2806dc48849fSKiran Chandramohan llvm::ArrayRef<mlir::Attribute> cases = caseOp.getCases().getValue(); 2807dc48849fSKiran Chandramohan // Type can be CHARACTER, INTEGER, or LOGICAL (C1145) 2808dc48849fSKiran Chandramohan auto ty = caseOp.getSelector().getType(); 2809dc48849fSKiran Chandramohan if (ty.isa<fir::CharacterType>()) { 2810dc48849fSKiran Chandramohan TODO(caseOp.getLoc(), "fir.select_case codegen with character type"); 281144e58509SEric Schweitz return mlir::failure(); 2812dc48849fSKiran Chandramohan } 2813dc48849fSKiran Chandramohan mlir::Value selector = caseOp.getSelector(adaptor.getOperands()); 2814dc48849fSKiran Chandramohan auto loc = caseOp.getLoc(); 2815dc48849fSKiran Chandramohan for (unsigned t = 0; t != conds; ++t) { 2816dc48849fSKiran Chandramohan mlir::Block *dest = caseOp.getSuccessor(t); 2817dc48849fSKiran Chandramohan llvm::Optional<mlir::ValueRange> destOps = 2818dc48849fSKiran Chandramohan caseOp.getSuccessorOperands(adaptor.getOperands(), t); 2819dc48849fSKiran Chandramohan llvm::Optional<mlir::ValueRange> cmpOps = 2820dc48849fSKiran Chandramohan *caseOp.getCompareOperands(adaptor.getOperands(), t); 2821*dc97886fSKazu Hirata mlir::Value caseArg = *(cmpOps.value().begin()); 2822dc48849fSKiran Chandramohan mlir::Attribute attr = cases[t]; 2823dc48849fSKiran Chandramohan if (attr.isa<fir::PointIntervalAttr>()) { 2824dc48849fSKiran Chandramohan auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 2825dc48849fSKiran Chandramohan loc, mlir::LLVM::ICmpPredicate::eq, selector, caseArg); 2826dc48849fSKiran Chandramohan genCaseLadderStep(loc, cmp, dest, destOps, rewriter); 2827dc48849fSKiran Chandramohan continue; 2828dc48849fSKiran Chandramohan } 2829dc48849fSKiran Chandramohan if (attr.isa<fir::LowerBoundAttr>()) { 2830dc48849fSKiran Chandramohan auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 2831dc48849fSKiran Chandramohan loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector); 2832dc48849fSKiran Chandramohan genCaseLadderStep(loc, cmp, dest, destOps, rewriter); 2833dc48849fSKiran Chandramohan continue; 2834dc48849fSKiran Chandramohan } 2835dc48849fSKiran Chandramohan if (attr.isa<fir::UpperBoundAttr>()) { 2836dc48849fSKiran Chandramohan auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 2837dc48849fSKiran Chandramohan loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg); 2838dc48849fSKiran Chandramohan genCaseLadderStep(loc, cmp, dest, destOps, rewriter); 2839dc48849fSKiran Chandramohan continue; 2840dc48849fSKiran Chandramohan } 2841dc48849fSKiran Chandramohan if (attr.isa<fir::ClosedIntervalAttr>()) { 2842dc48849fSKiran Chandramohan auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 2843dc48849fSKiran Chandramohan loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector); 2844dc48849fSKiran Chandramohan auto *thisBlock = rewriter.getInsertionBlock(); 2845dc48849fSKiran Chandramohan auto *newBlock1 = createBlock(rewriter, dest); 2846dc48849fSKiran Chandramohan auto *newBlock2 = createBlock(rewriter, dest); 2847dc48849fSKiran Chandramohan rewriter.setInsertionPointToEnd(thisBlock); 2848dc48849fSKiran Chandramohan rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, newBlock1, newBlock2); 2849dc48849fSKiran Chandramohan rewriter.setInsertionPointToEnd(newBlock1); 2850*dc97886fSKazu Hirata mlir::Value caseArg0 = *(cmpOps.value().begin() + 1); 2851dc48849fSKiran Chandramohan auto cmp0 = rewriter.create<mlir::LLVM::ICmpOp>( 2852dc48849fSKiran Chandramohan loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg0); 2853dc48849fSKiran Chandramohan genCondBrOp(loc, cmp0, dest, destOps, rewriter, newBlock2); 2854dc48849fSKiran Chandramohan rewriter.setInsertionPointToEnd(newBlock2); 2855dc48849fSKiran Chandramohan continue; 2856dc48849fSKiran Chandramohan } 2857dc48849fSKiran Chandramohan assert(attr.isa<mlir::UnitAttr>()); 2858dc48849fSKiran Chandramohan assert((t + 1 == conds) && "unit must be last"); 2859dc48849fSKiran Chandramohan genBrOp(caseOp, dest, destOps, rewriter); 2860dc48849fSKiran Chandramohan } 286144e58509SEric Schweitz return mlir::success(); 2862dc48849fSKiran Chandramohan } 2863dc48849fSKiran Chandramohan }; 2864dc48849fSKiran Chandramohan 2865dc48849fSKiran Chandramohan template <typename OP> 2866dc48849fSKiran Chandramohan static void selectMatchAndRewrite(fir::LLVMTypeConverter &lowering, OP select, 2867dc48849fSKiran Chandramohan typename OP::Adaptor adaptor, 2868dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) { 2869dc48849fSKiran Chandramohan unsigned conds = select.getNumConditions(); 2870dc48849fSKiran Chandramohan auto cases = select.getCases().getValue(); 2871dc48849fSKiran Chandramohan mlir::Value selector = adaptor.getSelector(); 2872dc48849fSKiran Chandramohan auto loc = select.getLoc(); 2873dc48849fSKiran Chandramohan assert(conds > 0 && "select must have cases"); 2874dc48849fSKiran Chandramohan 2875dc48849fSKiran Chandramohan llvm::SmallVector<mlir::Block *> destinations; 2876dc48849fSKiran Chandramohan llvm::SmallVector<mlir::ValueRange> destinationsOperands; 2877dc48849fSKiran Chandramohan mlir::Block *defaultDestination; 2878dc48849fSKiran Chandramohan mlir::ValueRange defaultOperands; 2879dc48849fSKiran Chandramohan llvm::SmallVector<int32_t> caseValues; 2880dc48849fSKiran Chandramohan 2881dc48849fSKiran Chandramohan for (unsigned t = 0; t != conds; ++t) { 2882dc48849fSKiran Chandramohan mlir::Block *dest = select.getSuccessor(t); 2883dc48849fSKiran Chandramohan auto destOps = select.getSuccessorOperands(adaptor.getOperands(), t); 2884dc48849fSKiran Chandramohan const mlir::Attribute &attr = cases[t]; 2885dc48849fSKiran Chandramohan if (auto intAttr = attr.template dyn_cast<mlir::IntegerAttr>()) { 2886dc48849fSKiran Chandramohan destinations.push_back(dest); 28873b7c3a65SKazu Hirata destinationsOperands.push_back(destOps.hasValue() ? *destOps 28883b7c3a65SKazu Hirata : mlir::ValueRange{}); 2889dc48849fSKiran Chandramohan caseValues.push_back(intAttr.getInt()); 2890dc48849fSKiran Chandramohan continue; 2891dc48849fSKiran Chandramohan } 2892dc48849fSKiran Chandramohan assert(attr.template dyn_cast_or_null<mlir::UnitAttr>()); 2893dc48849fSKiran Chandramohan assert((t + 1 == conds) && "unit must be last"); 2894dc48849fSKiran Chandramohan defaultDestination = dest; 28953b7c3a65SKazu Hirata defaultOperands = destOps.hasValue() ? *destOps : mlir::ValueRange{}; 2896dc48849fSKiran Chandramohan } 2897dc48849fSKiran Chandramohan 2898dc48849fSKiran Chandramohan // LLVM::SwitchOp takes a i32 type for the selector. 2899dc48849fSKiran Chandramohan if (select.getSelector().getType() != rewriter.getI32Type()) 290044e58509SEric Schweitz selector = rewriter.create<mlir::LLVM::TruncOp>(loc, rewriter.getI32Type(), 290144e58509SEric Schweitz selector); 2902dc48849fSKiran Chandramohan 2903dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>( 2904dc48849fSKiran Chandramohan select, selector, 2905dc48849fSKiran Chandramohan /*defaultDestination=*/defaultDestination, 2906dc48849fSKiran Chandramohan /*defaultOperands=*/defaultOperands, 2907dc48849fSKiran Chandramohan /*caseValues=*/caseValues, 2908dc48849fSKiran Chandramohan /*caseDestinations=*/destinations, 2909dc48849fSKiran Chandramohan /*caseOperands=*/destinationsOperands, 291044e58509SEric Schweitz /*branchWeights=*/llvm::ArrayRef<std::int32_t>()); 2911dc48849fSKiran Chandramohan } 2912dc48849fSKiran Chandramohan 2913dc48849fSKiran Chandramohan /// conversion of fir::SelectOp to an if-then-else ladder 2914dc48849fSKiran Chandramohan struct SelectOpConversion : public FIROpConversion<fir::SelectOp> { 2915dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 2916dc48849fSKiran Chandramohan 2917dc48849fSKiran Chandramohan mlir::LogicalResult 2918dc48849fSKiran Chandramohan matchAndRewrite(fir::SelectOp op, OpAdaptor adaptor, 2919dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 2920dc48849fSKiran Chandramohan selectMatchAndRewrite<fir::SelectOp>(lowerTy(), op, adaptor, rewriter); 292144e58509SEric Schweitz return mlir::success(); 2922dc48849fSKiran Chandramohan } 2923dc48849fSKiran Chandramohan }; 2924dc48849fSKiran Chandramohan 2925dc48849fSKiran Chandramohan /// conversion of fir::SelectRankOp to an if-then-else ladder 2926dc48849fSKiran Chandramohan struct SelectRankOpConversion : public FIROpConversion<fir::SelectRankOp> { 2927dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 2928dc48849fSKiran Chandramohan 2929dc48849fSKiran Chandramohan mlir::LogicalResult 2930dc48849fSKiran Chandramohan matchAndRewrite(fir::SelectRankOp op, OpAdaptor adaptor, 2931dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 2932dc48849fSKiran Chandramohan selectMatchAndRewrite<fir::SelectRankOp>(lowerTy(), op, adaptor, rewriter); 293344e58509SEric Schweitz return mlir::success(); 2934dc48849fSKiran Chandramohan } 2935dc48849fSKiran Chandramohan }; 2936dc48849fSKiran Chandramohan 2937dc48849fSKiran Chandramohan /// Lower `fir.select_type` to LLVM IR dialect. 2938dc48849fSKiran Chandramohan struct SelectTypeOpConversion : public FIROpConversion<fir::SelectTypeOp> { 2939dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 2940dc48849fSKiran Chandramohan 2941dc48849fSKiran Chandramohan mlir::LogicalResult 2942dc48849fSKiran Chandramohan matchAndRewrite(fir::SelectTypeOp select, OpAdaptor adaptor, 2943dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 2944dc48849fSKiran Chandramohan mlir::emitError(select.getLoc(), 2945dc48849fSKiran Chandramohan "fir.select_type should have already been converted"); 294644e58509SEric Schweitz return mlir::failure(); 2947dc48849fSKiran Chandramohan } 2948dc48849fSKiran Chandramohan }; 2949dc48849fSKiran Chandramohan 2950dc48849fSKiran Chandramohan /// `fir.store` --> `llvm.store` 2951dc48849fSKiran Chandramohan struct StoreOpConversion : public FIROpConversion<fir::StoreOp> { 2952dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 2953dc48849fSKiran Chandramohan 2954dc48849fSKiran Chandramohan mlir::LogicalResult 2955dc48849fSKiran Chandramohan matchAndRewrite(fir::StoreOp store, OpAdaptor adaptor, 2956dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 2957dc48849fSKiran Chandramohan if (store.getValue().getType().isa<fir::BoxType>()) { 2958dc48849fSKiran Chandramohan // fir.box value is actually in memory, load it first before storing it. 2959dc48849fSKiran Chandramohan mlir::Location loc = store.getLoc(); 2960dc48849fSKiran Chandramohan mlir::Type boxPtrTy = adaptor.getOperands()[0].getType(); 2961dc48849fSKiran Chandramohan auto val = rewriter.create<mlir::LLVM::LoadOp>( 2962dc48849fSKiran Chandramohan loc, boxPtrTy.cast<mlir::LLVM::LLVMPointerType>().getElementType(), 2963dc48849fSKiran Chandramohan adaptor.getOperands()[0]); 2964dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>( 2965dc48849fSKiran Chandramohan store, val, adaptor.getOperands()[1]); 2966dc48849fSKiran Chandramohan } else { 2967dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>( 2968dc48849fSKiran Chandramohan store, adaptor.getOperands()[0], adaptor.getOperands()[1]); 2969dc48849fSKiran Chandramohan } 297044e58509SEric Schweitz return mlir::success(); 2971dc48849fSKiran Chandramohan } 2972dc48849fSKiran Chandramohan }; 2973dc48849fSKiran Chandramohan 2974dc48849fSKiran Chandramohan namespace { 2975dc48849fSKiran Chandramohan 2976dc48849fSKiran Chandramohan /// Convert `fir.unboxchar` into two `llvm.extractvalue` instructions. One for 2977dc48849fSKiran Chandramohan /// the character buffer and one for the buffer length. 2978dc48849fSKiran Chandramohan struct UnboxCharOpConversion : public FIROpConversion<fir::UnboxCharOp> { 2979dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 2980dc48849fSKiran Chandramohan 2981dc48849fSKiran Chandramohan mlir::LogicalResult 2982dc48849fSKiran Chandramohan matchAndRewrite(fir::UnboxCharOp unboxchar, OpAdaptor adaptor, 2983dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 298444e58509SEric Schweitz auto *ctx = unboxchar.getContext(); 2985dc48849fSKiran Chandramohan 2986dc48849fSKiran Chandramohan mlir::Type lenTy = convertType(unboxchar.getType(1)); 2987dc48849fSKiran Chandramohan mlir::Value tuple = adaptor.getOperands()[0]; 2988dc48849fSKiran Chandramohan mlir::Type tupleTy = tuple.getType(); 2989dc48849fSKiran Chandramohan 2990dc48849fSKiran Chandramohan mlir::Location loc = unboxchar.getLoc(); 2991dc48849fSKiran Chandramohan mlir::Value ptrToBuffer = 2992dc48849fSKiran Chandramohan genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 0); 2993dc48849fSKiran Chandramohan 2994dc48849fSKiran Chandramohan mlir::LLVM::ExtractValueOp len = 2995dc48849fSKiran Chandramohan genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 1); 2996dc48849fSKiran Chandramohan mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, len); 2997dc48849fSKiran Chandramohan 2998dc48849fSKiran Chandramohan rewriter.replaceOp(unboxchar, 299944e58509SEric Schweitz llvm::ArrayRef<mlir::Value>{ptrToBuffer, lenAfterCast}); 300044e58509SEric Schweitz return mlir::success(); 3001dc48849fSKiran Chandramohan } 3002dc48849fSKiran Chandramohan }; 3003dc48849fSKiran Chandramohan 3004dc48849fSKiran Chandramohan /// Lower `fir.unboxproc` operation. Unbox a procedure box value, yielding its 3005dc48849fSKiran Chandramohan /// components. 3006dc48849fSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers. 3007dc48849fSKiran Chandramohan struct UnboxProcOpConversion : public FIROpConversion<fir::UnboxProcOp> { 3008dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 3009dc48849fSKiran Chandramohan 3010dc48849fSKiran Chandramohan mlir::LogicalResult 3011dc48849fSKiran Chandramohan matchAndRewrite(fir::UnboxProcOp unboxproc, OpAdaptor adaptor, 3012dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 3013dc48849fSKiran Chandramohan TODO(unboxproc.getLoc(), "fir.unboxproc codegen"); 301444e58509SEric Schweitz return mlir::failure(); 3015dc48849fSKiran Chandramohan } 3016dc48849fSKiran Chandramohan }; 3017dc48849fSKiran Chandramohan 3018dc48849fSKiran Chandramohan /// convert to LLVM IR dialect `undef` 3019dc48849fSKiran Chandramohan struct UndefOpConversion : public FIROpConversion<fir::UndefOp> { 3020dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 3021dc48849fSKiran Chandramohan 3022dc48849fSKiran Chandramohan mlir::LogicalResult 3023dc48849fSKiran Chandramohan matchAndRewrite(fir::UndefOp undef, OpAdaptor, 3024dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 3025dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::UndefOp>( 3026dc48849fSKiran Chandramohan undef, convertType(undef.getType())); 302744e58509SEric Schweitz return mlir::success(); 3028dc48849fSKiran Chandramohan } 3029dc48849fSKiran Chandramohan }; 3030dc48849fSKiran Chandramohan 3031dc48849fSKiran Chandramohan struct ZeroOpConversion : public FIROpConversion<fir::ZeroOp> { 3032dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 3033dc48849fSKiran Chandramohan 3034dc48849fSKiran Chandramohan mlir::LogicalResult 3035dc48849fSKiran Chandramohan matchAndRewrite(fir::ZeroOp zero, OpAdaptor, 3036dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 3037dc48849fSKiran Chandramohan mlir::Type ty = convertType(zero.getType()); 3038dc48849fSKiran Chandramohan if (ty.isa<mlir::LLVM::LLVMPointerType>()) { 3039dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(zero, ty); 3040dc48849fSKiran Chandramohan } else if (ty.isa<mlir::IntegerType>()) { 3041dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>( 3042dc48849fSKiran Chandramohan zero, ty, mlir::IntegerAttr::get(zero.getType(), 0)); 3043dc48849fSKiran Chandramohan } else if (mlir::LLVM::isCompatibleFloatingPointType(ty)) { 3044dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>( 3045dc48849fSKiran Chandramohan zero, ty, mlir::FloatAttr::get(zero.getType(), 0.0)); 3046dc48849fSKiran Chandramohan } else { 3047dc48849fSKiran Chandramohan // TODO: create ConstantAggregateZero for FIR aggregate/array types. 3048dc48849fSKiran Chandramohan return rewriter.notifyMatchFailure( 3049dc48849fSKiran Chandramohan zero, 3050dc48849fSKiran Chandramohan "conversion of fir.zero with aggregate type not implemented yet"); 3051dc48849fSKiran Chandramohan } 305244e58509SEric Schweitz return mlir::success(); 3053dc48849fSKiran Chandramohan } 3054dc48849fSKiran Chandramohan }; 3055dc48849fSKiran Chandramohan 3056dc48849fSKiran Chandramohan /// `fir.unreachable` --> `llvm.unreachable` 3057dc48849fSKiran Chandramohan struct UnreachableOpConversion : public FIROpConversion<fir::UnreachableOp> { 3058dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 3059dc48849fSKiran Chandramohan 3060dc48849fSKiran Chandramohan mlir::LogicalResult 3061dc48849fSKiran Chandramohan matchAndRewrite(fir::UnreachableOp unreach, OpAdaptor adaptor, 3062dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 3063dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(unreach); 306444e58509SEric Schweitz return mlir::success(); 3065dc48849fSKiran Chandramohan } 3066dc48849fSKiran Chandramohan }; 3067dc48849fSKiran Chandramohan 3068dc48849fSKiran Chandramohan /// `fir.is_present` --> 3069dc48849fSKiran Chandramohan /// ``` 3070dc48849fSKiran Chandramohan /// %0 = llvm.mlir.constant(0 : i64) 3071dc48849fSKiran Chandramohan /// %1 = llvm.ptrtoint %0 3072dc48849fSKiran Chandramohan /// %2 = llvm.icmp "ne" %1, %0 : i64 3073dc48849fSKiran Chandramohan /// ``` 3074dc48849fSKiran Chandramohan struct IsPresentOpConversion : public FIROpConversion<fir::IsPresentOp> { 3075dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 3076dc48849fSKiran Chandramohan 3077dc48849fSKiran Chandramohan mlir::LogicalResult 3078dc48849fSKiran Chandramohan matchAndRewrite(fir::IsPresentOp isPresent, OpAdaptor adaptor, 3079dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 3080dc48849fSKiran Chandramohan mlir::Type idxTy = lowerTy().indexType(); 3081dc48849fSKiran Chandramohan mlir::Location loc = isPresent.getLoc(); 3082dc48849fSKiran Chandramohan auto ptr = adaptor.getOperands()[0]; 3083dc48849fSKiran Chandramohan 3084dc48849fSKiran Chandramohan if (isPresent.getVal().getType().isa<fir::BoxCharType>()) { 3085dc48849fSKiran Chandramohan auto structTy = ptr.getType().cast<mlir::LLVM::LLVMStructType>(); 3086dc48849fSKiran Chandramohan assert(!structTy.isOpaque() && !structTy.getBody().empty()); 3087dc48849fSKiran Chandramohan 3088dc48849fSKiran Chandramohan mlir::Type ty = structTy.getBody()[0]; 3089dc48849fSKiran Chandramohan mlir::MLIRContext *ctx = isPresent.getContext(); 3090dc48849fSKiran Chandramohan auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 3091dc48849fSKiran Chandramohan ptr = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, ptr, c0); 3092dc48849fSKiran Chandramohan } 3093dc48849fSKiran Chandramohan mlir::LLVM::ConstantOp c0 = 3094dc48849fSKiran Chandramohan genConstantIndex(isPresent.getLoc(), idxTy, rewriter, 0); 3095dc48849fSKiran Chandramohan auto addr = rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, ptr); 3096dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>( 3097dc48849fSKiran Chandramohan isPresent, mlir::LLVM::ICmpPredicate::ne, addr, c0); 3098dc48849fSKiran Chandramohan 309944e58509SEric Schweitz return mlir::success(); 3100dc48849fSKiran Chandramohan } 3101dc48849fSKiran Chandramohan }; 3102dc48849fSKiran Chandramohan 3103dc48849fSKiran Chandramohan /// Create value signaling an absent optional argument in a call, e.g. 3104dc48849fSKiran Chandramohan /// `fir.absent !fir.ref<i64>` --> `llvm.mlir.null : !llvm.ptr<i64>` 3105dc48849fSKiran Chandramohan struct AbsentOpConversion : public FIROpConversion<fir::AbsentOp> { 3106dc48849fSKiran Chandramohan using FIROpConversion::FIROpConversion; 3107dc48849fSKiran Chandramohan 3108dc48849fSKiran Chandramohan mlir::LogicalResult 3109dc48849fSKiran Chandramohan matchAndRewrite(fir::AbsentOp absent, OpAdaptor, 3110dc48849fSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 3111dc48849fSKiran Chandramohan mlir::Type ty = convertType(absent.getType()); 3112dc48849fSKiran Chandramohan mlir::Location loc = absent.getLoc(); 3113dc48849fSKiran Chandramohan 3114dc48849fSKiran Chandramohan if (absent.getType().isa<fir::BoxCharType>()) { 3115dc48849fSKiran Chandramohan auto structTy = ty.cast<mlir::LLVM::LLVMStructType>(); 3116dc48849fSKiran Chandramohan assert(!structTy.isOpaque() && !structTy.getBody().empty()); 3117dc48849fSKiran Chandramohan auto undefStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 3118dc48849fSKiran Chandramohan auto nullField = 3119dc48849fSKiran Chandramohan rewriter.create<mlir::LLVM::NullOp>(loc, structTy.getBody()[0]); 3120dc48849fSKiran Chandramohan mlir::MLIRContext *ctx = absent.getContext(); 3121dc48849fSKiran Chandramohan auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 3122dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 3123dc48849fSKiran Chandramohan absent, ty, undefStruct, nullField, c0); 3124dc48849fSKiran Chandramohan } else { 3125dc48849fSKiran Chandramohan rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(absent, ty); 3126dc48849fSKiran Chandramohan } 312744e58509SEric Schweitz return mlir::success(); 3128dc48849fSKiran Chandramohan } 3129dc48849fSKiran Chandramohan }; 31305d27abe6SValentin Clement 31317b5132daSValentin Clement // 31327b5132daSValentin Clement // Primitive operations on Complex types 31337b5132daSValentin Clement // 31347b5132daSValentin Clement 31357b5132daSValentin Clement /// Generate inline code for complex addition/subtraction 31367b5132daSValentin Clement template <typename LLVMOP, typename OPTY> 3137c2acd453SAlexisPerry static mlir::LLVM::InsertValueOp 3138c2acd453SAlexisPerry complexSum(OPTY sumop, mlir::ValueRange opnds, 31397b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter, 31407b5132daSValentin Clement fir::LLVMTypeConverter &lowering) { 31417b5132daSValentin Clement mlir::Value a = opnds[0]; 31427b5132daSValentin Clement mlir::Value b = opnds[1]; 31437b5132daSValentin Clement auto loc = sumop.getLoc(); 31447b5132daSValentin Clement auto ctx = sumop.getContext(); 31457b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 31467b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 31477b5132daSValentin Clement mlir::Type eleTy = lowering.convertType(getComplexEleTy(sumop.getType())); 31487b5132daSValentin Clement mlir::Type ty = lowering.convertType(sumop.getType()); 31497b5132daSValentin Clement auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0); 31507b5132daSValentin Clement auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1); 31517b5132daSValentin Clement auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0); 31527b5132daSValentin Clement auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1); 31537b5132daSValentin Clement auto rx = rewriter.create<LLVMOP>(loc, eleTy, x0, x1); 31547b5132daSValentin Clement auto ry = rewriter.create<LLVMOP>(loc, eleTy, y0, y1); 31557b5132daSValentin Clement auto r0 = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 31567b5132daSValentin Clement auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r0, rx, c0); 31577b5132daSValentin Clement return rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ry, c1); 31587b5132daSValentin Clement } 3159dc48849fSKiran Chandramohan } // namespace 31607b5132daSValentin Clement 3161c2acd453SAlexisPerry namespace { 31627b5132daSValentin Clement struct AddcOpConversion : public FIROpConversion<fir::AddcOp> { 31637b5132daSValentin Clement using FIROpConversion::FIROpConversion; 31647b5132daSValentin Clement 31657b5132daSValentin Clement mlir::LogicalResult 31667b5132daSValentin Clement matchAndRewrite(fir::AddcOp addc, OpAdaptor adaptor, 31677b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 31687b5132daSValentin Clement // given: (x + iy) + (x' + iy') 31697b5132daSValentin Clement // result: (x + x') + i(y + y') 31707b5132daSValentin Clement auto r = complexSum<mlir::LLVM::FAddOp>(addc, adaptor.getOperands(), 31717b5132daSValentin Clement rewriter, lowerTy()); 31727b5132daSValentin Clement rewriter.replaceOp(addc, r.getResult()); 317344e58509SEric Schweitz return mlir::success(); 31747b5132daSValentin Clement } 31757b5132daSValentin Clement }; 31767b5132daSValentin Clement 31777b5132daSValentin Clement struct SubcOpConversion : public FIROpConversion<fir::SubcOp> { 31787b5132daSValentin Clement using FIROpConversion::FIROpConversion; 31797b5132daSValentin Clement 31807b5132daSValentin Clement mlir::LogicalResult 31817b5132daSValentin Clement matchAndRewrite(fir::SubcOp subc, OpAdaptor adaptor, 31827b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 31837b5132daSValentin Clement // given: (x + iy) - (x' + iy') 31847b5132daSValentin Clement // result: (x - x') + i(y - y') 31857b5132daSValentin Clement auto r = complexSum<mlir::LLVM::FSubOp>(subc, adaptor.getOperands(), 31867b5132daSValentin Clement rewriter, lowerTy()); 31877b5132daSValentin Clement rewriter.replaceOp(subc, r.getResult()); 318844e58509SEric Schweitz return mlir::success(); 31897b5132daSValentin Clement } 31907b5132daSValentin Clement }; 31917b5132daSValentin Clement 31927b5132daSValentin Clement /// Inlined complex multiply 31937b5132daSValentin Clement struct MulcOpConversion : public FIROpConversion<fir::MulcOp> { 31947b5132daSValentin Clement using FIROpConversion::FIROpConversion; 31957b5132daSValentin Clement 31967b5132daSValentin Clement mlir::LogicalResult 31977b5132daSValentin Clement matchAndRewrite(fir::MulcOp mulc, OpAdaptor adaptor, 31987b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 31997b5132daSValentin Clement // TODO: Can we use a call to __muldc3 ? 32007b5132daSValentin Clement // given: (x + iy) * (x' + iy') 32017b5132daSValentin Clement // result: (xx'-yy')+i(xy'+yx') 32027b5132daSValentin Clement mlir::Value a = adaptor.getOperands()[0]; 32037b5132daSValentin Clement mlir::Value b = adaptor.getOperands()[1]; 32047b5132daSValentin Clement auto loc = mulc.getLoc(); 32057b5132daSValentin Clement auto *ctx = mulc.getContext(); 32067b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 32077b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 32087b5132daSValentin Clement mlir::Type eleTy = convertType(getComplexEleTy(mulc.getType())); 32097b5132daSValentin Clement mlir::Type ty = convertType(mulc.getType()); 32107b5132daSValentin Clement auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0); 32117b5132daSValentin Clement auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1); 32127b5132daSValentin Clement auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0); 32137b5132daSValentin Clement auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1); 32147b5132daSValentin Clement auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1); 32157b5132daSValentin Clement auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1); 32167b5132daSValentin Clement auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1); 32177b5132daSValentin Clement auto ri = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xy, yx); 32187b5132daSValentin Clement auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1); 32197b5132daSValentin Clement auto rr = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, xx, yy); 32207b5132daSValentin Clement auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 32217b5132daSValentin Clement auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0); 32227b5132daSValentin Clement auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1); 32237b5132daSValentin Clement rewriter.replaceOp(mulc, r0.getResult()); 322444e58509SEric Schweitz return mlir::success(); 32257b5132daSValentin Clement } 32267b5132daSValentin Clement }; 32277b5132daSValentin Clement 32287b5132daSValentin Clement /// Inlined complex division 32297b5132daSValentin Clement struct DivcOpConversion : public FIROpConversion<fir::DivcOp> { 32307b5132daSValentin Clement using FIROpConversion::FIROpConversion; 32317b5132daSValentin Clement 32327b5132daSValentin Clement mlir::LogicalResult 32337b5132daSValentin Clement matchAndRewrite(fir::DivcOp divc, OpAdaptor adaptor, 32347b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 32357b5132daSValentin Clement // TODO: Can we use a call to __divdc3 instead? 32367b5132daSValentin Clement // Just generate inline code for now. 32377b5132daSValentin Clement // given: (x + iy) / (x' + iy') 32387b5132daSValentin Clement // result: ((xx'+yy')/d) + i((yx'-xy')/d) where d = x'x' + y'y' 32397b5132daSValentin Clement mlir::Value a = adaptor.getOperands()[0]; 32407b5132daSValentin Clement mlir::Value b = adaptor.getOperands()[1]; 32417b5132daSValentin Clement auto loc = divc.getLoc(); 32427b5132daSValentin Clement auto *ctx = divc.getContext(); 32437b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 32447b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 32457b5132daSValentin Clement mlir::Type eleTy = convertType(getComplexEleTy(divc.getType())); 32467b5132daSValentin Clement mlir::Type ty = convertType(divc.getType()); 32477b5132daSValentin Clement auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0); 32487b5132daSValentin Clement auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1); 32497b5132daSValentin Clement auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0); 32507b5132daSValentin Clement auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1); 32517b5132daSValentin Clement auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1); 32527b5132daSValentin Clement auto x1x1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x1, x1); 32537b5132daSValentin Clement auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1); 32547b5132daSValentin Clement auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1); 32557b5132daSValentin Clement auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1); 32567b5132daSValentin Clement auto y1y1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y1, y1); 32577b5132daSValentin Clement auto d = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, x1x1, y1y1); 32587b5132daSValentin Clement auto rrn = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xx, yy); 32597b5132daSValentin Clement auto rin = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, yx, xy); 32607b5132daSValentin Clement auto rr = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rrn, d); 32617b5132daSValentin Clement auto ri = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rin, d); 32627b5132daSValentin Clement auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 32637b5132daSValentin Clement auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0); 32647b5132daSValentin Clement auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1); 32657b5132daSValentin Clement rewriter.replaceOp(divc, r0.getResult()); 326644e58509SEric Schweitz return mlir::success(); 32677b5132daSValentin Clement } 32687b5132daSValentin Clement }; 32697b5132daSValentin Clement 32707b5132daSValentin Clement /// Inlined complex negation 32717b5132daSValentin Clement struct NegcOpConversion : public FIROpConversion<fir::NegcOp> { 32727b5132daSValentin Clement using FIROpConversion::FIROpConversion; 32737b5132daSValentin Clement 32747b5132daSValentin Clement mlir::LogicalResult 32757b5132daSValentin Clement matchAndRewrite(fir::NegcOp neg, OpAdaptor adaptor, 32767b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 32777b5132daSValentin Clement // given: -(x + iy) 32787b5132daSValentin Clement // result: -x - iy 32797b5132daSValentin Clement auto *ctxt = neg.getContext(); 32807b5132daSValentin Clement auto eleTy = convertType(getComplexEleTy(neg.getType())); 32817b5132daSValentin Clement auto ty = convertType(neg.getType()); 32827b5132daSValentin Clement auto loc = neg.getLoc(); 32837b5132daSValentin Clement mlir::Value o0 = adaptor.getOperands()[0]; 32847b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0)); 32857b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1)); 32867b5132daSValentin Clement auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c0); 32877b5132daSValentin Clement auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c1); 32887b5132daSValentin Clement auto nrp = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, rp); 32897b5132daSValentin Clement auto nip = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, ip); 32907b5132daSValentin Clement auto r = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, o0, nrp, c0); 32917b5132daSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(neg, ty, r, nip, c1); 329244e58509SEric Schweitz return mlir::success(); 32937b5132daSValentin Clement } 32947b5132daSValentin Clement }; 32957b5132daSValentin Clement 32961ed5a90fSValentin Clement /// Conversion pattern for operation that must be dead. The information in these 32971ed5a90fSValentin Clement /// operations is used by other operation. At this point they should not have 32981ed5a90fSValentin Clement /// anymore uses. 32991ed5a90fSValentin Clement /// These operations are normally dead after the pre-codegen pass. 33001ed5a90fSValentin Clement template <typename FromOp> 33011ed5a90fSValentin Clement struct MustBeDeadConversion : public FIROpConversion<FromOp> { 3302013160f6SJean Perier explicit MustBeDeadConversion(fir::LLVMTypeConverter &lowering, 3303013160f6SJean Perier const fir::FIRToLLVMPassOptions &options) 3304013160f6SJean Perier : FIROpConversion<FromOp>(lowering, options) {} 33051ed5a90fSValentin Clement using OpAdaptor = typename FromOp::Adaptor; 33061ed5a90fSValentin Clement 33071ed5a90fSValentin Clement mlir::LogicalResult 33081ed5a90fSValentin Clement matchAndRewrite(FromOp op, OpAdaptor adaptor, 33091ed5a90fSValentin Clement mlir::ConversionPatternRewriter &rewriter) const final { 33101ed5a90fSValentin Clement if (!op->getUses().empty()) 33111ed5a90fSValentin Clement return rewriter.notifyMatchFailure(op, "op must be dead"); 33121ed5a90fSValentin Clement rewriter.eraseOp(op); 331344e58509SEric Schweitz return mlir::success(); 33141ed5a90fSValentin Clement } 33151ed5a90fSValentin Clement }; 33161ed5a90fSValentin Clement 33171ed5a90fSValentin Clement struct ShapeOpConversion : public MustBeDeadConversion<fir::ShapeOp> { 33181ed5a90fSValentin Clement using MustBeDeadConversion::MustBeDeadConversion; 33191ed5a90fSValentin Clement }; 33201ed5a90fSValentin Clement 33211ed5a90fSValentin Clement struct ShapeShiftOpConversion : public MustBeDeadConversion<fir::ShapeShiftOp> { 33221ed5a90fSValentin Clement using MustBeDeadConversion::MustBeDeadConversion; 33231ed5a90fSValentin Clement }; 33241ed5a90fSValentin Clement 33251ed5a90fSValentin Clement struct ShiftOpConversion : public MustBeDeadConversion<fir::ShiftOp> { 33261ed5a90fSValentin Clement using MustBeDeadConversion::MustBeDeadConversion; 33271ed5a90fSValentin Clement }; 33281ed5a90fSValentin Clement 33291ed5a90fSValentin Clement struct SliceOpConversion : public MustBeDeadConversion<fir::SliceOp> { 33301ed5a90fSValentin Clement using MustBeDeadConversion::MustBeDeadConversion; 33311ed5a90fSValentin Clement }; 33321ed5a90fSValentin Clement 3333044d5b5dSValentin Clement } // namespace 3334044d5b5dSValentin Clement 3335044d5b5dSValentin Clement namespace { 3336044d5b5dSValentin Clement /// Convert FIR dialect to LLVM dialect 3337044d5b5dSValentin Clement /// 3338044d5b5dSValentin Clement /// This pass lowers all FIR dialect operations to LLVM IR dialect. An 3339044d5b5dSValentin Clement /// MLIR pass is used to lower residual Std dialect to LLVM IR dialect. 3340044d5b5dSValentin Clement class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> { 3341044d5b5dSValentin Clement public: 3342013160f6SJean Perier FIRToLLVMLowering() = default; 3343013160f6SJean Perier FIRToLLVMLowering(fir::FIRToLLVMPassOptions options) : options{options} {} 3344044d5b5dSValentin Clement mlir::ModuleOp getModule() { return getOperation(); } 3345044d5b5dSValentin Clement 3346044d5b5dSValentin Clement void runOnOperation() override final { 33477b5132daSValentin Clement auto mod = getModule(); 334844e58509SEric Schweitz if (!forcedTargetTriple.empty()) 33497b5132daSValentin Clement fir::setTargetTriple(mod, forcedTargetTriple); 33507b5132daSValentin Clement 3351044d5b5dSValentin Clement auto *context = getModule().getContext(); 3352044d5b5dSValentin Clement fir::LLVMTypeConverter typeConverter{getModule()}; 33539f85c198SRiver Riddle mlir::RewritePatternSet pattern(context); 3354df3b9810SValentin Clement pattern.insert< 3355420ad7ceSAndrzej Warzynski AbsentOpConversion, AddcOpConversion, AddrOfOpConversion, 3356c2acd453SAlexisPerry AllocaOpConversion, AllocMemOpConversion, BoxAddrOpConversion, 3357c2acd453SAlexisPerry BoxCharLenOpConversion, BoxDimsOpConversion, BoxEleSizeOpConversion, 3358c2acd453SAlexisPerry BoxIsAllocOpConversion, BoxIsArrayOpConversion, BoxIsPtrOpConversion, 3359c2acd453SAlexisPerry BoxProcHostOpConversion, BoxRankOpConversion, BoxTypeDescOpConversion, 3360c2acd453SAlexisPerry CallOpConversion, CmpcOpConversion, ConstcOpConversion, 3361e6e7da55SAndrzej Warzynski ConvertOpConversion, CoordinateOpConversion, DispatchOpConversion, 3362e6e7da55SAndrzej Warzynski DispatchTableOpConversion, DTEntryOpConversion, DivcOpConversion, 3363e6e7da55SAndrzej Warzynski EmboxOpConversion, EmboxCharOpConversion, EmboxProcOpConversion, 3364e6e7da55SAndrzej Warzynski ExtractValueOpConversion, FieldIndexOpConversion, FirEndOpConversion, 3365dc48849fSKiran Chandramohan FreeMemOpConversion, GenTypeDescOpConversion, GlobalLenOpConversion, 3366dc48849fSKiran Chandramohan GlobalOpConversion, HasValueOpConversion, InsertOnRangeOpConversion, 3367e6e7da55SAndrzej Warzynski InsertValueOpConversion, IsPresentOpConversion, 3368dc48849fSKiran Chandramohan LenParamIndexOpConversion, LoadOpConversion, MulcOpConversion, 3369dc48849fSKiran Chandramohan NegcOpConversion, NoReassocOpConversion, SelectCaseOpConversion, 3370e6e7da55SAndrzej Warzynski SelectOpConversion, SelectRankOpConversion, SelectTypeOpConversion, 3371e6e7da55SAndrzej Warzynski ShapeOpConversion, ShapeShiftOpConversion, ShiftOpConversion, 3372e6e7da55SAndrzej Warzynski SliceOpConversion, StoreOpConversion, StringLitOpConversion, 3373e6e7da55SAndrzej Warzynski SubcOpConversion, UnboxCharOpConversion, UnboxProcOpConversion, 3374e6e7da55SAndrzej Warzynski UndefOpConversion, UnreachableOpConversion, XArrayCoorOpConversion, 3375013160f6SJean Perier XEmboxOpConversion, XReboxOpConversion, ZeroOpConversion>(typeConverter, 3376013160f6SJean Perier options); 33775a7b9194SRiver Riddle mlir::populateFuncToLLVMConversionPatterns(typeConverter, pattern); 3378c6ac9370SKiran Chandramohan mlir::populateOpenMPToLLVMConversionPatterns(typeConverter, pattern); 3379044d5b5dSValentin Clement mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter, 3380044d5b5dSValentin Clement pattern); 3381ace01605SRiver Riddle mlir::cf::populateControlFlowToLLVMConversionPatterns(typeConverter, 3382ace01605SRiver Riddle pattern); 3383044d5b5dSValentin Clement mlir::ConversionTarget target{*context}; 3384044d5b5dSValentin Clement target.addLegalDialect<mlir::LLVM::LLVMDialect>(); 3385c6ac9370SKiran Chandramohan // The OpenMP dialect is legal for Operations without regions, for those 3386c6ac9370SKiran Chandramohan // which contains regions it is legal if the region contains only the 338700c511b3SNimish Mishra // LLVM dialect. Add OpenMP dialect as a legal dialect for conversion and 338800c511b3SNimish Mishra // legalize conversion of OpenMP operations without regions. 338900c511b3SNimish Mishra mlir::configureOpenMPToLLVMConversionLegality(target, typeConverter); 3390c6ac9370SKiran Chandramohan target.addLegalDialect<mlir::omp::OpenMPDialect>(); 3391044d5b5dSValentin Clement 3392044d5b5dSValentin Clement // required NOPs for applying a full conversion 3393044d5b5dSValentin Clement target.addLegalOp<mlir::ModuleOp>(); 3394044d5b5dSValentin Clement 3395044d5b5dSValentin Clement // apply the patterns 3396044d5b5dSValentin Clement if (mlir::failed(mlir::applyFullConversion(getModule(), target, 3397044d5b5dSValentin Clement std::move(pattern)))) { 3398044d5b5dSValentin Clement signalPassFailure(); 3399044d5b5dSValentin Clement } 3400044d5b5dSValentin Clement } 3401013160f6SJean Perier 3402013160f6SJean Perier private: 3403013160f6SJean Perier fir::FIRToLLVMPassOptions options; 3404044d5b5dSValentin Clement }; 3405853e79d8SValentin Clement 3406853e79d8SValentin Clement /// Lower from LLVM IR dialect to proper LLVM-IR and dump the module 3407853e79d8SValentin Clement struct LLVMIRLoweringPass 3408853e79d8SValentin Clement : public mlir::PassWrapper<LLVMIRLoweringPass, 3409853e79d8SValentin Clement mlir::OperationPass<mlir::ModuleOp>> { 34105e50dd04SRiver Riddle MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(LLVMIRLoweringPass) 34115e50dd04SRiver Riddle 341244e58509SEric Schweitz LLVMIRLoweringPass(llvm::raw_ostream &output, fir::LLVMIRLoweringPrinter p) 3413853e79d8SValentin Clement : output{output}, printer{p} {} 3414853e79d8SValentin Clement 3415853e79d8SValentin Clement mlir::ModuleOp getModule() { return getOperation(); } 3416853e79d8SValentin Clement 3417853e79d8SValentin Clement void runOnOperation() override final { 3418853e79d8SValentin Clement auto *ctx = getModule().getContext(); 3419853e79d8SValentin Clement auto optName = getModule().getName(); 3420853e79d8SValentin Clement llvm::LLVMContext llvmCtx; 3421853e79d8SValentin Clement if (auto llvmModule = mlir::translateModuleToLLVMIR( 3422853e79d8SValentin Clement getModule(), llvmCtx, optName ? *optName : "FIRModule")) { 3423853e79d8SValentin Clement printer(*llvmModule, output); 3424853e79d8SValentin Clement return; 3425853e79d8SValentin Clement } 3426853e79d8SValentin Clement 3427853e79d8SValentin Clement mlir::emitError(mlir::UnknownLoc::get(ctx), "could not emit LLVM-IR\n"); 3428853e79d8SValentin Clement signalPassFailure(); 3429853e79d8SValentin Clement } 3430853e79d8SValentin Clement 3431853e79d8SValentin Clement private: 343244e58509SEric Schweitz llvm::raw_ostream &output; 343344e58509SEric Schweitz fir::LLVMIRLoweringPrinter printer; 3434853e79d8SValentin Clement }; 3435853e79d8SValentin Clement 3436044d5b5dSValentin Clement } // namespace 3437044d5b5dSValentin Clement 3438044d5b5dSValentin Clement std::unique_ptr<mlir::Pass> fir::createFIRToLLVMPass() { 3439044d5b5dSValentin Clement return std::make_unique<FIRToLLVMLowering>(); 3440044d5b5dSValentin Clement } 3441853e79d8SValentin Clement 3442853e79d8SValentin Clement std::unique_ptr<mlir::Pass> 344344e58509SEric Schweitz fir::createFIRToLLVMPass(fir::FIRToLLVMPassOptions options) { 3444013160f6SJean Perier return std::make_unique<FIRToLLVMLowering>(options); 3445013160f6SJean Perier } 3446013160f6SJean Perier 3447013160f6SJean Perier std::unique_ptr<mlir::Pass> 344844e58509SEric Schweitz fir::createLLVMDialectToLLVMPass(llvm::raw_ostream &output, 3449853e79d8SValentin Clement fir::LLVMIRLoweringPrinter printer) { 3450853e79d8SValentin Clement return std::make_unique<LLVMIRLoweringPass>(output, printer); 3451853e79d8SValentin Clement } 3452