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" 14044d5b5dSValentin Clement #include "PassDetail.h" 15b6e44ecdSValentin Clement #include "flang/ISO_Fortran_binding.h" 1639f4ef81SValentin Clement #include "flang/Optimizer/Dialect/FIRAttr.h" 17044d5b5dSValentin Clement #include "flang/Optimizer/Dialect/FIROps.h" 18044d5b5dSValentin Clement #include "mlir/Conversion/ArithmeticToLLVM/ArithmeticToLLVM.h" 19044d5b5dSValentin Clement #include "mlir/Conversion/LLVMCommon/Pattern.h" 20044d5b5dSValentin Clement #include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h" 21044d5b5dSValentin Clement #include "mlir/IR/BuiltinTypes.h" 223ae8e442SValentin Clement #include "mlir/IR/Matchers.h" 23044d5b5dSValentin Clement #include "mlir/Pass/Pass.h" 24044d5b5dSValentin Clement #include "llvm/ADT/ArrayRef.h" 25044d5b5dSValentin Clement 26044d5b5dSValentin Clement #define DEBUG_TYPE "flang-codegen" 27044d5b5dSValentin Clement 28044d5b5dSValentin Clement // fir::LLVMTypeConverter for converting to LLVM IR dialect types. 29044d5b5dSValentin Clement #include "TypeConverter.h" 30044d5b5dSValentin Clement 31b6e44ecdSValentin Clement /// `fir.box` attribute values as defined for CFI_attribute_t in 32b6e44ecdSValentin Clement /// flang/ISO_Fortran_binding.h. 33b6e44ecdSValentin Clement static constexpr unsigned kAttrPointer = CFI_attribute_pointer; 34b6e44ecdSValentin Clement static constexpr unsigned kAttrAllocatable = CFI_attribute_allocatable; 35b6e44ecdSValentin Clement 361e6d9c06SDiana Picus static mlir::LLVM::ConstantOp 371e6d9c06SDiana Picus genConstantIndex(mlir::Location loc, mlir::Type ity, 381e6d9c06SDiana Picus mlir::ConversionPatternRewriter &rewriter, 391e6d9c06SDiana Picus std::int64_t offset) { 401e6d9c06SDiana Picus auto cattr = rewriter.getI64IntegerAttr(offset); 411e6d9c06SDiana Picus return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr); 421e6d9c06SDiana Picus } 431e6d9c06SDiana Picus 4439f4ef81SValentin Clement static Block *createBlock(mlir::ConversionPatternRewriter &rewriter, 4539f4ef81SValentin Clement mlir::Block *insertBefore) { 4639f4ef81SValentin Clement assert(insertBefore && "expected valid insertion block"); 4739f4ef81SValentin Clement return rewriter.createBlock(insertBefore->getParent(), 4839f4ef81SValentin Clement mlir::Region::iterator(insertBefore)); 4939f4ef81SValentin Clement } 5039f4ef81SValentin Clement 51044d5b5dSValentin Clement namespace { 52044d5b5dSValentin Clement /// FIR conversion pattern template 53044d5b5dSValentin Clement template <typename FromOp> 54044d5b5dSValentin Clement class FIROpConversion : public mlir::ConvertOpToLLVMPattern<FromOp> { 55044d5b5dSValentin Clement public: 56044d5b5dSValentin Clement explicit FIROpConversion(fir::LLVMTypeConverter &lowering) 57044d5b5dSValentin Clement : mlir::ConvertOpToLLVMPattern<FromOp>(lowering) {} 58044d5b5dSValentin Clement 59044d5b5dSValentin Clement protected: 60044d5b5dSValentin Clement mlir::Type convertType(mlir::Type ty) const { 61044d5b5dSValentin Clement return lowerTy().convertType(ty); 62044d5b5dSValentin Clement } 63044d5b5dSValentin Clement 64df3b9810SValentin Clement mlir::LLVM::ConstantOp 65df3b9810SValentin Clement genConstantOffset(mlir::Location loc, 66df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter, 67df3b9810SValentin Clement int offset) const { 68df3b9810SValentin Clement auto ity = lowerTy().offsetType(); 69df3b9810SValentin Clement auto cattr = rewriter.getI32IntegerAttr(offset); 70df3b9810SValentin Clement return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr); 71df3b9810SValentin Clement } 72df3b9810SValentin Clement 73b6e44ecdSValentin Clement /// Construct code sequence to extract the specifc value from a `fir.box`. 74b6e44ecdSValentin Clement mlir::Value getValueFromBox(mlir::Location loc, mlir::Value box, 75df3b9810SValentin Clement mlir::Type resultTy, 76b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter, 77b6e44ecdSValentin Clement unsigned boxValue) const { 78df3b9810SValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 79b6e44ecdSValentin Clement mlir::LLVM::ConstantOp cValuePos = 80b6e44ecdSValentin Clement genConstantOffset(loc, rewriter, boxValue); 81df3b9810SValentin Clement auto pty = mlir::LLVM::LLVMPointerType::get(resultTy); 82df3b9810SValentin Clement auto p = rewriter.create<mlir::LLVM::GEPOp>( 83b6e44ecdSValentin Clement loc, pty, mlir::ValueRange{box, c0, cValuePos}); 84df3b9810SValentin Clement return rewriter.create<mlir::LLVM::LoadOp>(loc, resultTy, p); 85df3b9810SValentin Clement } 86df3b9810SValentin Clement 87df3b9810SValentin Clement /// Method to construct code sequence to get the triple for dimension `dim` 88df3b9810SValentin Clement /// from a box. 89df3b9810SValentin Clement SmallVector<mlir::Value, 3> 90df3b9810SValentin Clement getDimsFromBox(mlir::Location loc, ArrayRef<mlir::Type> retTys, 91df3b9810SValentin Clement mlir::Value box, mlir::Value dim, 92df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 93df3b9810SValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 94df3b9810SValentin Clement mlir::LLVM::ConstantOp cDims = 95df3b9810SValentin Clement genConstantOffset(loc, rewriter, kDimsPosInBox); 96df3b9810SValentin Clement mlir::LLVM::LoadOp l0 = 97df3b9810SValentin Clement loadFromOffset(loc, box, c0, cDims, dim, 0, retTys[0], rewriter); 98df3b9810SValentin Clement mlir::LLVM::LoadOp l1 = 99df3b9810SValentin Clement loadFromOffset(loc, box, c0, cDims, dim, 1, retTys[1], rewriter); 100df3b9810SValentin Clement mlir::LLVM::LoadOp l2 = 101df3b9810SValentin Clement loadFromOffset(loc, box, c0, cDims, dim, 2, retTys[2], rewriter); 102df3b9810SValentin Clement return {l0.getResult(), l1.getResult(), l2.getResult()}; 103df3b9810SValentin Clement } 104df3b9810SValentin Clement 105df3b9810SValentin Clement mlir::LLVM::LoadOp 106df3b9810SValentin Clement loadFromOffset(mlir::Location loc, mlir::Value a, mlir::LLVM::ConstantOp c0, 107df3b9810SValentin Clement mlir::LLVM::ConstantOp cDims, mlir::Value dim, int off, 108df3b9810SValentin Clement mlir::Type ty, 109df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 110df3b9810SValentin Clement auto pty = mlir::LLVM::LLVMPointerType::get(ty); 111df3b9810SValentin Clement mlir::LLVM::ConstantOp c = genConstantOffset(loc, rewriter, off); 112df3b9810SValentin Clement mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, a, c0, cDims, dim, c); 113df3b9810SValentin Clement return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p); 114df3b9810SValentin Clement } 115df3b9810SValentin Clement 116df3b9810SValentin Clement /// Read base address from a fir.box. Returned address has type ty. 117df3b9810SValentin Clement mlir::Value 118df3b9810SValentin Clement loadBaseAddrFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box, 119df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 120df3b9810SValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 121df3b9810SValentin Clement mlir::LLVM::ConstantOp cAddr = 122df3b9810SValentin Clement genConstantOffset(loc, rewriter, kAddrPosInBox); 123df3b9810SValentin Clement auto pty = mlir::LLVM::LLVMPointerType::get(ty); 124df3b9810SValentin Clement mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cAddr); 125df3b9810SValentin Clement return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p); 126df3b9810SValentin Clement } 127df3b9810SValentin Clement 128df3b9810SValentin Clement mlir::Value 129df3b9810SValentin Clement loadElementSizeFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box, 130df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 131df3b9810SValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 132df3b9810SValentin Clement mlir::LLVM::ConstantOp cElemLen = 133df3b9810SValentin Clement genConstantOffset(loc, rewriter, kElemLenPosInBox); 134df3b9810SValentin Clement auto pty = mlir::LLVM::LLVMPointerType::get(ty); 135df3b9810SValentin Clement mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cElemLen); 136df3b9810SValentin Clement return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p); 137df3b9810SValentin Clement } 138df3b9810SValentin Clement 139b6e44ecdSValentin Clement // Load the attribute from the \p box and perform a check against \p maskValue 140b6e44ecdSValentin Clement // The final comparison is implemented as `(attribute & maskValue) != 0`. 141b6e44ecdSValentin Clement mlir::Value genBoxAttributeCheck(mlir::Location loc, mlir::Value box, 142b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter, 143b6e44ecdSValentin Clement unsigned maskValue) const { 144b6e44ecdSValentin Clement mlir::Type attrTy = rewriter.getI32Type(); 145b6e44ecdSValentin Clement mlir::Value attribute = 146b6e44ecdSValentin Clement getValueFromBox(loc, box, attrTy, rewriter, kAttributePosInBox); 147b6e44ecdSValentin Clement mlir::LLVM::ConstantOp attrMask = 148b6e44ecdSValentin Clement genConstantOffset(loc, rewriter, maskValue); 149b6e44ecdSValentin Clement auto maskRes = 150b6e44ecdSValentin Clement rewriter.create<mlir::LLVM::AndOp>(loc, attrTy, attribute, attrMask); 151b6e44ecdSValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 152b6e44ecdSValentin Clement return rewriter.create<mlir::LLVM::ICmpOp>( 153b6e44ecdSValentin Clement loc, mlir::LLVM::ICmpPredicate::ne, maskRes, c0); 154b6e44ecdSValentin Clement } 155b6e44ecdSValentin Clement 156df3b9810SValentin Clement template <typename... ARGS> 157df3b9810SValentin Clement mlir::LLVM::GEPOp genGEP(mlir::Location loc, mlir::Type ty, 158df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter, 159df3b9810SValentin Clement mlir::Value base, ARGS... args) const { 160df3b9810SValentin Clement SmallVector<mlir::Value> cv{args...}; 161df3b9810SValentin Clement return rewriter.create<mlir::LLVM::GEPOp>(loc, ty, base, cv); 162df3b9810SValentin Clement } 163df3b9810SValentin Clement 1641e6d9c06SDiana Picus /// Perform an extension or truncation as needed on an integer value. Lowering 1651e6d9c06SDiana Picus /// to the specific target may involve some sign-extending or truncation of 1661e6d9c06SDiana Picus /// values, particularly to fit them from abstract box types to the 1671e6d9c06SDiana Picus /// appropriate reified structures. 1681e6d9c06SDiana Picus mlir::Value integerCast(mlir::Location loc, 1691e6d9c06SDiana Picus mlir::ConversionPatternRewriter &rewriter, 1701e6d9c06SDiana Picus mlir::Type ty, mlir::Value val) const { 1711e6d9c06SDiana Picus auto valTy = val.getType(); 1721e6d9c06SDiana Picus // If the value was not yet lowered, lower its type so that it can 1731e6d9c06SDiana Picus // be used in getPrimitiveTypeSizeInBits. 1741e6d9c06SDiana Picus if (!valTy.isa<mlir::IntegerType>()) 1751e6d9c06SDiana Picus valTy = convertType(valTy); 1761e6d9c06SDiana Picus auto toSize = mlir::LLVM::getPrimitiveTypeSizeInBits(ty); 1771e6d9c06SDiana Picus auto fromSize = mlir::LLVM::getPrimitiveTypeSizeInBits(valTy); 1781e6d9c06SDiana Picus if (toSize < fromSize) 1791e6d9c06SDiana Picus return rewriter.create<mlir::LLVM::TruncOp>(loc, ty, val); 1801e6d9c06SDiana Picus if (toSize > fromSize) 1811e6d9c06SDiana Picus return rewriter.create<mlir::LLVM::SExtOp>(loc, ty, val); 1821e6d9c06SDiana Picus return val; 1831e6d9c06SDiana Picus } 1841e6d9c06SDiana Picus 185044d5b5dSValentin Clement fir::LLVMTypeConverter &lowerTy() const { 186044d5b5dSValentin Clement return *static_cast<fir::LLVMTypeConverter *>(this->getTypeConverter()); 187044d5b5dSValentin Clement } 188044d5b5dSValentin Clement }; 189044d5b5dSValentin Clement 1903ae8e442SValentin Clement /// FIR conversion pattern template 1913ae8e442SValentin Clement template <typename FromOp> 1923ae8e442SValentin Clement class FIROpAndTypeConversion : public FIROpConversion<FromOp> { 1933ae8e442SValentin Clement public: 1943ae8e442SValentin Clement using FIROpConversion<FromOp>::FIROpConversion; 1953ae8e442SValentin Clement using OpAdaptor = typename FromOp::Adaptor; 1963ae8e442SValentin Clement 1973ae8e442SValentin Clement mlir::LogicalResult 1983ae8e442SValentin Clement matchAndRewrite(FromOp op, OpAdaptor adaptor, 1993ae8e442SValentin Clement mlir::ConversionPatternRewriter &rewriter) const final { 2003ae8e442SValentin Clement mlir::Type ty = this->convertType(op.getType()); 2013ae8e442SValentin Clement return doRewrite(op, ty, adaptor, rewriter); 2023ae8e442SValentin Clement } 2033ae8e442SValentin Clement 2043ae8e442SValentin Clement virtual mlir::LogicalResult 2053ae8e442SValentin Clement doRewrite(FromOp addr, mlir::Type ty, OpAdaptor adaptor, 2063ae8e442SValentin Clement mlir::ConversionPatternRewriter &rewriter) const = 0; 2073ae8e442SValentin Clement }; 2083ae8e442SValentin Clement 209420ad7ceSAndrzej Warzynski /// Create value signaling an absent optional argument in a call, e.g. 210420ad7ceSAndrzej Warzynski /// `fir.absent !fir.ref<i64>` --> `llvm.mlir.null : !llvm.ptr<i64>` 211420ad7ceSAndrzej Warzynski struct AbsentOpConversion : public FIROpConversion<fir::AbsentOp> { 212420ad7ceSAndrzej Warzynski using FIROpConversion::FIROpConversion; 213420ad7ceSAndrzej Warzynski 214420ad7ceSAndrzej Warzynski mlir::LogicalResult 215420ad7ceSAndrzej Warzynski matchAndRewrite(fir::AbsentOp absent, OpAdaptor, 216420ad7ceSAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 217420ad7ceSAndrzej Warzynski mlir::Type ty = convertType(absent.getType()); 218420ad7ceSAndrzej Warzynski mlir::Location loc = absent.getLoc(); 219420ad7ceSAndrzej Warzynski 220420ad7ceSAndrzej Warzynski if (absent.getType().isa<fir::BoxCharType>()) { 221420ad7ceSAndrzej Warzynski auto structTy = ty.cast<mlir::LLVM::LLVMStructType>(); 222420ad7ceSAndrzej Warzynski assert(!structTy.isOpaque() && !structTy.getBody().empty()); 223420ad7ceSAndrzej Warzynski auto undefStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 224420ad7ceSAndrzej Warzynski auto nullField = 225420ad7ceSAndrzej Warzynski rewriter.create<mlir::LLVM::NullOp>(loc, structTy.getBody()[0]); 226420ad7ceSAndrzej Warzynski mlir::MLIRContext *ctx = absent.getContext(); 227420ad7ceSAndrzej Warzynski auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 228420ad7ceSAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 229420ad7ceSAndrzej Warzynski absent, ty, undefStruct, nullField, c0); 230420ad7ceSAndrzej Warzynski } else { 231420ad7ceSAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(absent, ty); 232420ad7ceSAndrzej Warzynski } 233420ad7ceSAndrzej Warzynski return success(); 234420ad7ceSAndrzej Warzynski } 235420ad7ceSAndrzej Warzynski }; 236420ad7ceSAndrzej Warzynski 2370c4a7a52SValentin Clement // Lower `fir.address_of` operation to `llvm.address_of` operation. 238044d5b5dSValentin Clement struct AddrOfOpConversion : public FIROpConversion<fir::AddrOfOp> { 239044d5b5dSValentin Clement using FIROpConversion::FIROpConversion; 240044d5b5dSValentin Clement 241044d5b5dSValentin Clement mlir::LogicalResult 242044d5b5dSValentin Clement matchAndRewrite(fir::AddrOfOp addr, OpAdaptor adaptor, 243044d5b5dSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 244044d5b5dSValentin Clement auto ty = convertType(addr.getType()); 245044d5b5dSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::AddressOfOp>( 246044d5b5dSValentin Clement addr, ty, addr.symbol().getRootReference().getValue()); 247044d5b5dSValentin Clement return success(); 248044d5b5dSValentin Clement } 249044d5b5dSValentin Clement }; 2501e6d9c06SDiana Picus } // namespace 2511e6d9c06SDiana Picus 2521e6d9c06SDiana Picus /// Lookup the function to compute the memory size of this parametric derived 2531e6d9c06SDiana Picus /// type. The size of the object may depend on the LEN type parameters of the 2541e6d9c06SDiana Picus /// derived type. 2551e6d9c06SDiana Picus static mlir::LLVM::LLVMFuncOp 2561e6d9c06SDiana Picus getDependentTypeMemSizeFn(fir::RecordType recTy, fir::AllocaOp op, 2571e6d9c06SDiana Picus mlir::ConversionPatternRewriter &rewriter) { 2581e6d9c06SDiana Picus auto module = op->getParentOfType<mlir::ModuleOp>(); 2591e6d9c06SDiana Picus std::string name = recTy.getName().str() + "P.mem.size"; 2601e6d9c06SDiana Picus return module.lookupSymbol<mlir::LLVM::LLVMFuncOp>(name); 2611e6d9c06SDiana Picus } 2621e6d9c06SDiana Picus 2631e6d9c06SDiana Picus namespace { 2641e6d9c06SDiana Picus /// convert to LLVM IR dialect `alloca` 2651e6d9c06SDiana Picus struct AllocaOpConversion : public FIROpConversion<fir::AllocaOp> { 2661e6d9c06SDiana Picus using FIROpConversion::FIROpConversion; 2671e6d9c06SDiana Picus 2681e6d9c06SDiana Picus mlir::LogicalResult 2691e6d9c06SDiana Picus matchAndRewrite(fir::AllocaOp alloc, OpAdaptor adaptor, 2701e6d9c06SDiana Picus mlir::ConversionPatternRewriter &rewriter) const override { 2711e6d9c06SDiana Picus mlir::ValueRange operands = adaptor.getOperands(); 2721e6d9c06SDiana Picus auto loc = alloc.getLoc(); 2731e6d9c06SDiana Picus mlir::Type ity = lowerTy().indexType(); 2741e6d9c06SDiana Picus unsigned i = 0; 2751e6d9c06SDiana Picus mlir::Value size = genConstantIndex(loc, ity, rewriter, 1).getResult(); 2761e6d9c06SDiana Picus mlir::Type ty = convertType(alloc.getType()); 2771e6d9c06SDiana Picus mlir::Type resultTy = ty; 2781e6d9c06SDiana Picus if (alloc.hasLenParams()) { 2791e6d9c06SDiana Picus unsigned end = alloc.numLenParams(); 2801e6d9c06SDiana Picus llvm::SmallVector<mlir::Value> lenParams; 2811e6d9c06SDiana Picus for (; i < end; ++i) 2821e6d9c06SDiana Picus lenParams.push_back(operands[i]); 2831e6d9c06SDiana Picus mlir::Type scalarType = fir::unwrapSequenceType(alloc.getInType()); 2841e6d9c06SDiana Picus if (auto chrTy = scalarType.dyn_cast<fir::CharacterType>()) { 2851e6d9c06SDiana Picus fir::CharacterType rawCharTy = fir::CharacterType::getUnknownLen( 2861e6d9c06SDiana Picus chrTy.getContext(), chrTy.getFKind()); 2871e6d9c06SDiana Picus ty = mlir::LLVM::LLVMPointerType::get(convertType(rawCharTy)); 2881e6d9c06SDiana Picus assert(end == 1); 2891e6d9c06SDiana Picus size = integerCast(loc, rewriter, ity, lenParams[0]); 2901e6d9c06SDiana Picus } else if (auto recTy = scalarType.dyn_cast<fir::RecordType>()) { 2911e6d9c06SDiana Picus mlir::LLVM::LLVMFuncOp memSizeFn = 2921e6d9c06SDiana Picus getDependentTypeMemSizeFn(recTy, alloc, rewriter); 2931e6d9c06SDiana Picus if (!memSizeFn) 2941e6d9c06SDiana Picus emitError(loc, "did not find allocation function"); 2951e6d9c06SDiana Picus mlir::NamedAttribute attr = rewriter.getNamedAttr( 2961e6d9c06SDiana Picus "callee", mlir::SymbolRefAttr::get(memSizeFn)); 2971e6d9c06SDiana Picus auto call = rewriter.create<mlir::LLVM::CallOp>( 2981e6d9c06SDiana Picus loc, ity, lenParams, llvm::ArrayRef<mlir::NamedAttribute>{attr}); 2991e6d9c06SDiana Picus size = call.getResult(0); 3001e6d9c06SDiana Picus ty = mlir::LLVM::LLVMPointerType::get( 3011e6d9c06SDiana Picus mlir::IntegerType::get(alloc.getContext(), 8)); 3021e6d9c06SDiana Picus } else { 3031e6d9c06SDiana Picus return emitError(loc, "unexpected type ") 3041e6d9c06SDiana Picus << scalarType << " with type parameters"; 3051e6d9c06SDiana Picus } 3061e6d9c06SDiana Picus } 3071e6d9c06SDiana Picus if (alloc.hasShapeOperands()) { 3081e6d9c06SDiana Picus mlir::Type allocEleTy = fir::unwrapRefType(alloc.getType()); 3091e6d9c06SDiana Picus // Scale the size by constant factors encoded in the array type. 3101e6d9c06SDiana Picus if (auto seqTy = allocEleTy.dyn_cast<fir::SequenceType>()) { 3111e6d9c06SDiana Picus fir::SequenceType::Extent constSize = 1; 3121e6d9c06SDiana Picus for (auto extent : seqTy.getShape()) 3131e6d9c06SDiana Picus if (extent != fir::SequenceType::getUnknownExtent()) 3141e6d9c06SDiana Picus constSize *= extent; 3151e6d9c06SDiana Picus mlir::Value constVal{ 3161e6d9c06SDiana Picus genConstantIndex(loc, ity, rewriter, constSize).getResult()}; 3171e6d9c06SDiana Picus size = rewriter.create<mlir::LLVM::MulOp>(loc, ity, size, constVal); 3181e6d9c06SDiana Picus } 3191e6d9c06SDiana Picus unsigned end = operands.size(); 3201e6d9c06SDiana Picus for (; i < end; ++i) 3211e6d9c06SDiana Picus size = rewriter.create<mlir::LLVM::MulOp>( 3221e6d9c06SDiana Picus loc, ity, size, integerCast(loc, rewriter, ity, operands[i])); 3231e6d9c06SDiana Picus } 3241e6d9c06SDiana Picus if (ty == resultTy) { 3251e6d9c06SDiana Picus // Do not emit the bitcast if ty and resultTy are the same. 3261e6d9c06SDiana Picus rewriter.replaceOpWithNewOp<mlir::LLVM::AllocaOp>(alloc, ty, size, 3271e6d9c06SDiana Picus alloc->getAttrs()); 3281e6d9c06SDiana Picus } else { 3291e6d9c06SDiana Picus auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, ty, size, 3301e6d9c06SDiana Picus alloc->getAttrs()); 3311e6d9c06SDiana Picus rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(alloc, resultTy, al); 3321e6d9c06SDiana Picus } 3331e6d9c06SDiana Picus return success(); 3341e6d9c06SDiana Picus } 3351e6d9c06SDiana Picus }; 336044d5b5dSValentin Clement 337df3b9810SValentin Clement /// Lower `fir.box_addr` to the sequence of operations to extract the first 338df3b9810SValentin Clement /// element of the box. 339df3b9810SValentin Clement struct BoxAddrOpConversion : public FIROpConversion<fir::BoxAddrOp> { 340df3b9810SValentin Clement using FIROpConversion::FIROpConversion; 341df3b9810SValentin Clement 342df3b9810SValentin Clement mlir::LogicalResult 343df3b9810SValentin Clement matchAndRewrite(fir::BoxAddrOp boxaddr, OpAdaptor adaptor, 344df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 345df3b9810SValentin Clement mlir::Value a = adaptor.getOperands()[0]; 346df3b9810SValentin Clement auto loc = boxaddr.getLoc(); 347df3b9810SValentin Clement mlir::Type ty = convertType(boxaddr.getType()); 348df3b9810SValentin Clement if (auto argty = boxaddr.val().getType().dyn_cast<fir::BoxType>()) { 349df3b9810SValentin Clement rewriter.replaceOp(boxaddr, loadBaseAddrFromBox(loc, ty, a, rewriter)); 350df3b9810SValentin Clement } else { 351df3b9810SValentin Clement auto c0attr = rewriter.getI32IntegerAttr(0); 352df3b9810SValentin Clement auto c0 = mlir::ArrayAttr::get(boxaddr.getContext(), c0attr); 353df3b9810SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(boxaddr, ty, a, 354df3b9810SValentin Clement c0); 355df3b9810SValentin Clement } 356df3b9810SValentin Clement return success(); 357df3b9810SValentin Clement } 358df3b9810SValentin Clement }; 359df3b9810SValentin Clement 360df3b9810SValentin Clement /// Lower `fir.box_dims` to a sequence of operations to extract the requested 361df3b9810SValentin Clement /// dimension infomartion from the boxed value. 362df3b9810SValentin Clement /// Result in a triple set of GEPs and loads. 363df3b9810SValentin Clement struct BoxDimsOpConversion : public FIROpConversion<fir::BoxDimsOp> { 364df3b9810SValentin Clement using FIROpConversion::FIROpConversion; 365df3b9810SValentin Clement 366df3b9810SValentin Clement mlir::LogicalResult 367df3b9810SValentin Clement matchAndRewrite(fir::BoxDimsOp boxdims, OpAdaptor adaptor, 368df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 369df3b9810SValentin Clement SmallVector<mlir::Type, 3> resultTypes = { 370df3b9810SValentin Clement convertType(boxdims.getResult(0).getType()), 371df3b9810SValentin Clement convertType(boxdims.getResult(1).getType()), 372df3b9810SValentin Clement convertType(boxdims.getResult(2).getType()), 373df3b9810SValentin Clement }; 374df3b9810SValentin Clement auto results = 375df3b9810SValentin Clement getDimsFromBox(boxdims.getLoc(), resultTypes, adaptor.getOperands()[0], 376df3b9810SValentin Clement adaptor.getOperands()[1], rewriter); 377df3b9810SValentin Clement rewriter.replaceOp(boxdims, results); 378df3b9810SValentin Clement return success(); 379df3b9810SValentin Clement } 380df3b9810SValentin Clement }; 381df3b9810SValentin Clement 382df3b9810SValentin Clement /// Lower `fir.box_elesize` to a sequence of operations ro extract the size of 383df3b9810SValentin Clement /// an element in the boxed value. 384df3b9810SValentin Clement struct BoxEleSizeOpConversion : public FIROpConversion<fir::BoxEleSizeOp> { 385df3b9810SValentin Clement using FIROpConversion::FIROpConversion; 386df3b9810SValentin Clement 387df3b9810SValentin Clement mlir::LogicalResult 388df3b9810SValentin Clement matchAndRewrite(fir::BoxEleSizeOp boxelesz, OpAdaptor adaptor, 389df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 390df3b9810SValentin Clement mlir::Value a = adaptor.getOperands()[0]; 391df3b9810SValentin Clement auto loc = boxelesz.getLoc(); 392df3b9810SValentin Clement auto ty = convertType(boxelesz.getType()); 393b6e44ecdSValentin Clement auto elemSize = getValueFromBox(loc, a, ty, rewriter, kElemLenPosInBox); 394b6e44ecdSValentin Clement rewriter.replaceOp(boxelesz, elemSize); 395b6e44ecdSValentin Clement return success(); 396b6e44ecdSValentin Clement } 397b6e44ecdSValentin Clement }; 398b6e44ecdSValentin Clement 399b6e44ecdSValentin Clement /// Lower `fir.box_isalloc` to a sequence of operations to determine if the 400b6e44ecdSValentin Clement /// boxed value was from an ALLOCATABLE entity. 401b6e44ecdSValentin Clement struct BoxIsAllocOpConversion : public FIROpConversion<fir::BoxIsAllocOp> { 402b6e44ecdSValentin Clement using FIROpConversion::FIROpConversion; 403b6e44ecdSValentin Clement 404b6e44ecdSValentin Clement mlir::LogicalResult 405b6e44ecdSValentin Clement matchAndRewrite(fir::BoxIsAllocOp boxisalloc, OpAdaptor adaptor, 406b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 407b6e44ecdSValentin Clement mlir::Value box = adaptor.getOperands()[0]; 408b6e44ecdSValentin Clement auto loc = boxisalloc.getLoc(); 409b6e44ecdSValentin Clement mlir::Value check = 410b6e44ecdSValentin Clement genBoxAttributeCheck(loc, box, rewriter, kAttrAllocatable); 411b6e44ecdSValentin Clement rewriter.replaceOp(boxisalloc, check); 412b6e44ecdSValentin Clement return success(); 413b6e44ecdSValentin Clement } 414b6e44ecdSValentin Clement }; 415b6e44ecdSValentin Clement 416b6e44ecdSValentin Clement /// Lower `fir.box_isarray` to a sequence of operations to determine if the 417b6e44ecdSValentin Clement /// boxed is an array. 418b6e44ecdSValentin Clement struct BoxIsArrayOpConversion : public FIROpConversion<fir::BoxIsArrayOp> { 419b6e44ecdSValentin Clement using FIROpConversion::FIROpConversion; 420b6e44ecdSValentin Clement 421b6e44ecdSValentin Clement mlir::LogicalResult 422b6e44ecdSValentin Clement matchAndRewrite(fir::BoxIsArrayOp boxisarray, OpAdaptor adaptor, 423b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 424b6e44ecdSValentin Clement mlir::Value a = adaptor.getOperands()[0]; 425b6e44ecdSValentin Clement auto loc = boxisarray.getLoc(); 426b6e44ecdSValentin Clement auto rank = 427b6e44ecdSValentin Clement getValueFromBox(loc, a, rewriter.getI32Type(), rewriter, kRankPosInBox); 428b6e44ecdSValentin Clement auto c0 = genConstantOffset(loc, rewriter, 0); 429b6e44ecdSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>( 430b6e44ecdSValentin Clement boxisarray, mlir::LLVM::ICmpPredicate::ne, rank, c0); 431b6e44ecdSValentin Clement return success(); 432b6e44ecdSValentin Clement } 433b6e44ecdSValentin Clement }; 434b6e44ecdSValentin Clement 435b6e44ecdSValentin Clement /// Lower `fir.box_isptr` to a sequence of operations to determined if the 436b6e44ecdSValentin Clement /// boxed value was from a POINTER entity. 437b6e44ecdSValentin Clement struct BoxIsPtrOpConversion : public FIROpConversion<fir::BoxIsPtrOp> { 438b6e44ecdSValentin Clement using FIROpConversion::FIROpConversion; 439b6e44ecdSValentin Clement 440b6e44ecdSValentin Clement mlir::LogicalResult 441b6e44ecdSValentin Clement matchAndRewrite(fir::BoxIsPtrOp boxisptr, OpAdaptor adaptor, 442b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 443b6e44ecdSValentin Clement mlir::Value box = adaptor.getOperands()[0]; 444b6e44ecdSValentin Clement auto loc = boxisptr.getLoc(); 445b6e44ecdSValentin Clement mlir::Value check = genBoxAttributeCheck(loc, box, rewriter, kAttrPointer); 446b6e44ecdSValentin Clement rewriter.replaceOp(boxisptr, check); 447df3b9810SValentin Clement return success(); 448df3b9810SValentin Clement } 449df3b9810SValentin Clement }; 450df3b9810SValentin Clement 451df3b9810SValentin Clement /// Lower `fir.box_rank` to the sequence of operation to extract the rank from 452df3b9810SValentin Clement /// the box. 453df3b9810SValentin Clement struct BoxRankOpConversion : public FIROpConversion<fir::BoxRankOp> { 454df3b9810SValentin Clement using FIROpConversion::FIROpConversion; 455df3b9810SValentin Clement 456df3b9810SValentin Clement mlir::LogicalResult 457df3b9810SValentin Clement matchAndRewrite(fir::BoxRankOp boxrank, OpAdaptor adaptor, 458df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 459df3b9810SValentin Clement mlir::Value a = adaptor.getOperands()[0]; 460df3b9810SValentin Clement auto loc = boxrank.getLoc(); 461df3b9810SValentin Clement mlir::Type ty = convertType(boxrank.getType()); 462b6e44ecdSValentin Clement auto result = getValueFromBox(loc, a, ty, rewriter, kRankPosInBox); 463df3b9810SValentin Clement rewriter.replaceOp(boxrank, result); 464df3b9810SValentin Clement return success(); 465df3b9810SValentin Clement } 466df3b9810SValentin Clement }; 467df3b9810SValentin Clement 4681a2ec667SValentin Clement /// Lower `fir.string_lit` to LLVM IR dialect operation. 4691a2ec667SValentin Clement struct StringLitOpConversion : public FIROpConversion<fir::StringLitOp> { 4701a2ec667SValentin Clement using FIROpConversion::FIROpConversion; 4711a2ec667SValentin Clement 4721a2ec667SValentin Clement mlir::LogicalResult 4731a2ec667SValentin Clement matchAndRewrite(fir::StringLitOp constop, OpAdaptor adaptor, 4741a2ec667SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 4751a2ec667SValentin Clement auto ty = convertType(constop.getType()); 4761a2ec667SValentin Clement auto attr = constop.getValue(); 4771a2ec667SValentin Clement if (attr.isa<mlir::StringAttr>()) { 4781a2ec667SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(constop, ty, attr); 4791a2ec667SValentin Clement return success(); 4801a2ec667SValentin Clement } 4811a2ec667SValentin Clement 4821a2ec667SValentin Clement auto arr = attr.cast<mlir::ArrayAttr>(); 4831a2ec667SValentin Clement auto charTy = constop.getType().cast<fir::CharacterType>(); 4841a2ec667SValentin Clement unsigned bits = lowerTy().characterBitsize(charTy); 4851a2ec667SValentin Clement mlir::Type intTy = rewriter.getIntegerType(bits); 4861a2ec667SValentin Clement auto attrs = llvm::map_range( 4871a2ec667SValentin Clement arr.getValue(), [intTy, bits](mlir::Attribute attr) -> Attribute { 4881a2ec667SValentin Clement return mlir::IntegerAttr::get( 4891a2ec667SValentin Clement intTy, 4901a2ec667SValentin Clement attr.cast<mlir::IntegerAttr>().getValue().sextOrTrunc(bits)); 4911a2ec667SValentin Clement }); 4921a2ec667SValentin Clement mlir::Type vecType = mlir::VectorType::get(arr.size(), intTy); 4931a2ec667SValentin Clement auto denseAttr = mlir::DenseElementsAttr::get( 4941a2ec667SValentin Clement vecType.cast<mlir::ShapedType>(), llvm::to_vector<8>(attrs)); 4951a2ec667SValentin Clement rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(constop, ty, 4961a2ec667SValentin Clement denseAttr); 4971a2ec667SValentin Clement return success(); 4981a2ec667SValentin Clement } 4991a2ec667SValentin Clement }; 5001a2ec667SValentin Clement 501*e38ef2ffSValentin Clement /// Lower `fir.box_tdesc` to the sequence of operations to extract the type 502*e38ef2ffSValentin Clement /// descriptor from the box. 503*e38ef2ffSValentin Clement struct BoxTypeDescOpConversion : public FIROpConversion<fir::BoxTypeDescOp> { 504*e38ef2ffSValentin Clement using FIROpConversion::FIROpConversion; 505*e38ef2ffSValentin Clement 506*e38ef2ffSValentin Clement mlir::LogicalResult 507*e38ef2ffSValentin Clement matchAndRewrite(fir::BoxTypeDescOp boxtypedesc, OpAdaptor adaptor, 508*e38ef2ffSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 509*e38ef2ffSValentin Clement mlir::Value box = adaptor.getOperands()[0]; 510*e38ef2ffSValentin Clement auto loc = boxtypedesc.getLoc(); 511*e38ef2ffSValentin Clement mlir::Type typeTy = 512*e38ef2ffSValentin Clement fir::getDescFieldTypeModel<kTypePosInBox>()(boxtypedesc.getContext()); 513*e38ef2ffSValentin Clement auto result = getValueFromBox(loc, box, typeTy, rewriter, kTypePosInBox); 514*e38ef2ffSValentin Clement auto typePtrTy = mlir::LLVM::LLVMPointerType::get(typeTy); 515*e38ef2ffSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(boxtypedesc, typePtrTy, 516*e38ef2ffSValentin Clement result); 517*e38ef2ffSValentin Clement return success(); 518*e38ef2ffSValentin Clement } 519*e38ef2ffSValentin Clement }; 520*e38ef2ffSValentin Clement 521ddd11b9aSAndrzej Warzynski // `fir.call` -> `llvm.call` 522ddd11b9aSAndrzej Warzynski struct CallOpConversion : public FIROpConversion<fir::CallOp> { 523ddd11b9aSAndrzej Warzynski using FIROpConversion::FIROpConversion; 524ddd11b9aSAndrzej Warzynski 525ddd11b9aSAndrzej Warzynski mlir::LogicalResult 526ddd11b9aSAndrzej Warzynski matchAndRewrite(fir::CallOp call, OpAdaptor adaptor, 527ddd11b9aSAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 528ddd11b9aSAndrzej Warzynski SmallVector<mlir::Type> resultTys; 529ddd11b9aSAndrzej Warzynski for (auto r : call.getResults()) 530ddd11b9aSAndrzej Warzynski resultTys.push_back(convertType(r.getType())); 531ddd11b9aSAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>( 532ddd11b9aSAndrzej Warzynski call, resultTys, adaptor.getOperands(), call->getAttrs()); 533ddd11b9aSAndrzej Warzynski return success(); 534ddd11b9aSAndrzej Warzynski } 535ddd11b9aSAndrzej Warzynski }; 536ddd11b9aSAndrzej Warzynski 537092cee5fSValentin Clement static mlir::Type getComplexEleTy(mlir::Type complex) { 538092cee5fSValentin Clement if (auto cc = complex.dyn_cast<mlir::ComplexType>()) 539092cee5fSValentin Clement return cc.getElementType(); 540092cee5fSValentin Clement return complex.cast<fir::ComplexType>().getElementType(); 541092cee5fSValentin Clement } 542092cee5fSValentin Clement 543f1dfc027SDiana Picus /// Compare complex values 544f1dfc027SDiana Picus /// 545f1dfc027SDiana Picus /// Per 10.1, the only comparisons available are .EQ. (oeq) and .NE. (une). 546f1dfc027SDiana Picus /// 547f1dfc027SDiana Picus /// For completeness, all other comparison are done on the real component only. 548f1dfc027SDiana Picus struct CmpcOpConversion : public FIROpConversion<fir::CmpcOp> { 549f1dfc027SDiana Picus using FIROpConversion::FIROpConversion; 550f1dfc027SDiana Picus 551f1dfc027SDiana Picus mlir::LogicalResult 552f1dfc027SDiana Picus matchAndRewrite(fir::CmpcOp cmp, OpAdaptor adaptor, 553f1dfc027SDiana Picus mlir::ConversionPatternRewriter &rewriter) const override { 554f1dfc027SDiana Picus mlir::ValueRange operands = adaptor.getOperands(); 555f1dfc027SDiana Picus mlir::MLIRContext *ctxt = cmp.getContext(); 556f1dfc027SDiana Picus mlir::Type eleTy = convertType(getComplexEleTy(cmp.lhs().getType())); 557f1dfc027SDiana Picus mlir::Type resTy = convertType(cmp.getType()); 558f1dfc027SDiana Picus mlir::Location loc = cmp.getLoc(); 559f1dfc027SDiana Picus auto pos0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0)); 560f1dfc027SDiana Picus SmallVector<mlir::Value, 2> rp{rewriter.create<mlir::LLVM::ExtractValueOp>( 561f1dfc027SDiana Picus loc, eleTy, operands[0], pos0), 562f1dfc027SDiana Picus rewriter.create<mlir::LLVM::ExtractValueOp>( 563f1dfc027SDiana Picus loc, eleTy, operands[1], pos0)}; 564f1dfc027SDiana Picus auto rcp = 565f1dfc027SDiana Picus rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, rp, cmp->getAttrs()); 566f1dfc027SDiana Picus auto pos1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1)); 567f1dfc027SDiana Picus SmallVector<mlir::Value, 2> ip{rewriter.create<mlir::LLVM::ExtractValueOp>( 568f1dfc027SDiana Picus loc, eleTy, operands[0], pos1), 569f1dfc027SDiana Picus rewriter.create<mlir::LLVM::ExtractValueOp>( 570f1dfc027SDiana Picus loc, eleTy, operands[1], pos1)}; 571f1dfc027SDiana Picus auto icp = 572f1dfc027SDiana Picus rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, ip, cmp->getAttrs()); 573f1dfc027SDiana Picus SmallVector<mlir::Value, 2> cp{rcp, icp}; 574f1dfc027SDiana Picus switch (cmp.getPredicate()) { 575f1dfc027SDiana Picus case mlir::arith::CmpFPredicate::OEQ: // .EQ. 576f1dfc027SDiana Picus rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(cmp, resTy, cp); 577f1dfc027SDiana Picus break; 578f1dfc027SDiana Picus case mlir::arith::CmpFPredicate::UNE: // .NE. 579f1dfc027SDiana Picus rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(cmp, resTy, cp); 580f1dfc027SDiana Picus break; 581f1dfc027SDiana Picus default: 582f1dfc027SDiana Picus rewriter.replaceOp(cmp, rcp.getResult()); 583f1dfc027SDiana Picus break; 584f1dfc027SDiana Picus } 585f1dfc027SDiana Picus return success(); 586f1dfc027SDiana Picus } 587f1dfc027SDiana Picus }; 588f1dfc027SDiana Picus 589092cee5fSValentin Clement /// convert value of from-type to value of to-type 590092cee5fSValentin Clement struct ConvertOpConversion : public FIROpConversion<fir::ConvertOp> { 591092cee5fSValentin Clement using FIROpConversion::FIROpConversion; 592092cee5fSValentin Clement 593092cee5fSValentin Clement static bool isFloatingPointTy(mlir::Type ty) { 594092cee5fSValentin Clement return ty.isa<mlir::FloatType>(); 595092cee5fSValentin Clement } 596092cee5fSValentin Clement 597092cee5fSValentin Clement mlir::LogicalResult 598092cee5fSValentin Clement matchAndRewrite(fir::ConvertOp convert, OpAdaptor adaptor, 599092cee5fSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 600092cee5fSValentin Clement auto fromTy = convertType(convert.value().getType()); 601092cee5fSValentin Clement auto toTy = convertType(convert.res().getType()); 602092cee5fSValentin Clement mlir::Value op0 = adaptor.getOperands()[0]; 603092cee5fSValentin Clement if (fromTy == toTy) { 604092cee5fSValentin Clement rewriter.replaceOp(convert, op0); 605092cee5fSValentin Clement return success(); 606092cee5fSValentin Clement } 607092cee5fSValentin Clement auto loc = convert.getLoc(); 608092cee5fSValentin Clement auto convertFpToFp = [&](mlir::Value val, unsigned fromBits, 609092cee5fSValentin Clement unsigned toBits, mlir::Type toTy) -> mlir::Value { 610092cee5fSValentin Clement if (fromBits == toBits) { 611092cee5fSValentin Clement // TODO: Converting between two floating-point representations with the 612092cee5fSValentin Clement // same bitwidth is not allowed for now. 613092cee5fSValentin Clement mlir::emitError(loc, 614092cee5fSValentin Clement "cannot implicitly convert between two floating-point " 615092cee5fSValentin Clement "representations of the same bitwidth"); 616092cee5fSValentin Clement return {}; 617092cee5fSValentin Clement } 618092cee5fSValentin Clement if (fromBits > toBits) 619092cee5fSValentin Clement return rewriter.create<mlir::LLVM::FPTruncOp>(loc, toTy, val); 620092cee5fSValentin Clement return rewriter.create<mlir::LLVM::FPExtOp>(loc, toTy, val); 621092cee5fSValentin Clement }; 622092cee5fSValentin Clement // Complex to complex conversion. 623092cee5fSValentin Clement if (fir::isa_complex(convert.value().getType()) && 624092cee5fSValentin Clement fir::isa_complex(convert.res().getType())) { 625092cee5fSValentin Clement // Special case: handle the conversion of a complex such that both the 626092cee5fSValentin Clement // real and imaginary parts are converted together. 627092cee5fSValentin Clement auto zero = mlir::ArrayAttr::get(convert.getContext(), 628092cee5fSValentin Clement rewriter.getI32IntegerAttr(0)); 629092cee5fSValentin Clement auto one = mlir::ArrayAttr::get(convert.getContext(), 630092cee5fSValentin Clement rewriter.getI32IntegerAttr(1)); 631092cee5fSValentin Clement auto ty = convertType(getComplexEleTy(convert.value().getType())); 632092cee5fSValentin Clement auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, zero); 633092cee5fSValentin Clement auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, one); 634092cee5fSValentin Clement auto nt = convertType(getComplexEleTy(convert.res().getType())); 635092cee5fSValentin Clement auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(ty); 636092cee5fSValentin Clement auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(nt); 637092cee5fSValentin Clement auto rc = convertFpToFp(rp, fromBits, toBits, nt); 638092cee5fSValentin Clement auto ic = convertFpToFp(ip, fromBits, toBits, nt); 639092cee5fSValentin Clement auto un = rewriter.create<mlir::LLVM::UndefOp>(loc, toTy); 640092cee5fSValentin Clement auto i1 = 641092cee5fSValentin Clement rewriter.create<mlir::LLVM::InsertValueOp>(loc, toTy, un, rc, zero); 642092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(convert, toTy, i1, 643092cee5fSValentin Clement ic, one); 644092cee5fSValentin Clement return mlir::success(); 645092cee5fSValentin Clement } 646092cee5fSValentin Clement // Floating point to floating point conversion. 647092cee5fSValentin Clement if (isFloatingPointTy(fromTy)) { 648092cee5fSValentin Clement if (isFloatingPointTy(toTy)) { 649092cee5fSValentin Clement auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy); 650092cee5fSValentin Clement auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy); 651092cee5fSValentin Clement auto v = convertFpToFp(op0, fromBits, toBits, toTy); 652092cee5fSValentin Clement rewriter.replaceOp(convert, v); 653092cee5fSValentin Clement return mlir::success(); 654092cee5fSValentin Clement } 655092cee5fSValentin Clement if (toTy.isa<mlir::IntegerType>()) { 656092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::FPToSIOp>(convert, toTy, op0); 657092cee5fSValentin Clement return mlir::success(); 658092cee5fSValentin Clement } 659092cee5fSValentin Clement } else if (fromTy.isa<mlir::IntegerType>()) { 660092cee5fSValentin Clement // Integer to integer conversion. 661092cee5fSValentin Clement if (toTy.isa<mlir::IntegerType>()) { 662092cee5fSValentin Clement auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy); 663092cee5fSValentin Clement auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy); 664092cee5fSValentin Clement assert(fromBits != toBits); 665092cee5fSValentin Clement if (fromBits > toBits) { 666092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::TruncOp>(convert, toTy, op0); 667092cee5fSValentin Clement return mlir::success(); 668092cee5fSValentin Clement } 669092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::SExtOp>(convert, toTy, op0); 670092cee5fSValentin Clement return mlir::success(); 671092cee5fSValentin Clement } 672092cee5fSValentin Clement // Integer to floating point conversion. 673092cee5fSValentin Clement if (isFloatingPointTy(toTy)) { 674092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::SIToFPOp>(convert, toTy, op0); 675092cee5fSValentin Clement return mlir::success(); 676092cee5fSValentin Clement } 677092cee5fSValentin Clement // Integer to pointer conversion. 678092cee5fSValentin Clement if (toTy.isa<mlir::LLVM::LLVMPointerType>()) { 679092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(convert, toTy, op0); 680092cee5fSValentin Clement return mlir::success(); 681092cee5fSValentin Clement } 682092cee5fSValentin Clement } else if (fromTy.isa<mlir::LLVM::LLVMPointerType>()) { 683092cee5fSValentin Clement // Pointer to integer conversion. 684092cee5fSValentin Clement if (toTy.isa<mlir::IntegerType>()) { 685092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::PtrToIntOp>(convert, toTy, op0); 686092cee5fSValentin Clement return mlir::success(); 687092cee5fSValentin Clement } 688092cee5fSValentin Clement // Pointer to pointer conversion. 689092cee5fSValentin Clement if (toTy.isa<mlir::LLVM::LLVMPointerType>()) { 690092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(convert, toTy, op0); 691092cee5fSValentin Clement return mlir::success(); 692092cee5fSValentin Clement } 693092cee5fSValentin Clement } 694092cee5fSValentin Clement return emitError(loc) << "cannot convert " << fromTy << " to " << toTy; 695092cee5fSValentin Clement } 696092cee5fSValentin Clement }; 697092cee5fSValentin Clement 6989534e361SValentin Clement /// Lower `fir.dispatch` operation. A virtual call to a method in a dispatch 6999534e361SValentin Clement /// table. 7009534e361SValentin Clement struct DispatchOpConversion : public FIROpConversion<fir::DispatchOp> { 7019534e361SValentin Clement using FIROpConversion::FIROpConversion; 7029534e361SValentin Clement 7039534e361SValentin Clement mlir::LogicalResult 7049534e361SValentin Clement matchAndRewrite(fir::DispatchOp dispatch, OpAdaptor adaptor, 7059534e361SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 7069534e361SValentin Clement return rewriter.notifyMatchFailure( 7079534e361SValentin Clement dispatch, "fir.dispatch codegen is not implemented yet"); 7089534e361SValentin Clement } 7099534e361SValentin Clement }; 7109534e361SValentin Clement 7119534e361SValentin Clement /// Lower `fir.dispatch_table` operation. The dispatch table for a Fortran 7129534e361SValentin Clement /// derived type. 7139534e361SValentin Clement struct DispatchTableOpConversion 7149534e361SValentin Clement : public FIROpConversion<fir::DispatchTableOp> { 7159534e361SValentin Clement using FIROpConversion::FIROpConversion; 7169534e361SValentin Clement 7179534e361SValentin Clement mlir::LogicalResult 7189534e361SValentin Clement matchAndRewrite(fir::DispatchTableOp dispTab, OpAdaptor adaptor, 7199534e361SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 7209534e361SValentin Clement return rewriter.notifyMatchFailure( 7219534e361SValentin Clement dispTab, "fir.dispatch_table codegen is not implemented yet"); 7229534e361SValentin Clement } 7239534e361SValentin Clement }; 7249534e361SValentin Clement 7259534e361SValentin Clement /// Lower `fir.dt_entry` operation. An entry in a dispatch table; binds a 7269534e361SValentin Clement /// method-name to a function. 7279534e361SValentin Clement struct DTEntryOpConversion : public FIROpConversion<fir::DTEntryOp> { 7289534e361SValentin Clement using FIROpConversion::FIROpConversion; 7299534e361SValentin Clement 7309534e361SValentin Clement mlir::LogicalResult 7319534e361SValentin Clement matchAndRewrite(fir::DTEntryOp dtEnt, OpAdaptor adaptor, 7329534e361SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 7339534e361SValentin Clement return rewriter.notifyMatchFailure( 7349534e361SValentin Clement dtEnt, "fir.dt_entry codegen is not implemented yet"); 7359534e361SValentin Clement } 7369534e361SValentin Clement }; 7379534e361SValentin Clement 738677df8c7SValentin Clement /// Lower `fir.global_len` operation. 739677df8c7SValentin Clement struct GlobalLenOpConversion : public FIROpConversion<fir::GlobalLenOp> { 740677df8c7SValentin Clement using FIROpConversion::FIROpConversion; 741677df8c7SValentin Clement 742677df8c7SValentin Clement mlir::LogicalResult 743677df8c7SValentin Clement matchAndRewrite(fir::GlobalLenOp globalLen, OpAdaptor adaptor, 744677df8c7SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 745677df8c7SValentin Clement return rewriter.notifyMatchFailure( 746677df8c7SValentin Clement globalLen, "fir.global_len codegen is not implemented yet"); 747677df8c7SValentin Clement } 748677df8c7SValentin Clement }; 749677df8c7SValentin Clement 75031246187SValentin Clement /// Lower `fir.gentypedesc` to a global constant. 75131246187SValentin Clement struct GenTypeDescOpConversion : public FIROpConversion<fir::GenTypeDescOp> { 75231246187SValentin Clement using FIROpConversion::FIROpConversion; 75331246187SValentin Clement 75431246187SValentin Clement mlir::LogicalResult 75531246187SValentin Clement matchAndRewrite(fir::GenTypeDescOp gentypedesc, OpAdaptor adaptor, 75631246187SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 75731246187SValentin Clement return rewriter.notifyMatchFailure( 75831246187SValentin Clement gentypedesc, "fir.fir.gentypedesc codegen is not implemented yet"); 75931246187SValentin Clement } 76031246187SValentin Clement }; 76131246187SValentin Clement 7620c4a7a52SValentin Clement /// Lower `fir.has_value` operation to `llvm.return` operation. 763044d5b5dSValentin Clement struct HasValueOpConversion : public FIROpConversion<fir::HasValueOp> { 764044d5b5dSValentin Clement using FIROpConversion::FIROpConversion; 765044d5b5dSValentin Clement 766044d5b5dSValentin Clement mlir::LogicalResult 767044d5b5dSValentin Clement matchAndRewrite(fir::HasValueOp op, OpAdaptor adaptor, 768044d5b5dSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 769044d5b5dSValentin Clement rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, adaptor.getOperands()); 770044d5b5dSValentin Clement return success(); 771044d5b5dSValentin Clement } 772044d5b5dSValentin Clement }; 773044d5b5dSValentin Clement 7740c4a7a52SValentin Clement /// Lower `fir.global` operation to `llvm.global` operation. 7750c4a7a52SValentin Clement /// `fir.insert_on_range` operations are replaced with constant dense attribute 7760c4a7a52SValentin Clement /// if they are applied on the full range. 777044d5b5dSValentin Clement struct GlobalOpConversion : public FIROpConversion<fir::GlobalOp> { 778044d5b5dSValentin Clement using FIROpConversion::FIROpConversion; 779044d5b5dSValentin Clement 780044d5b5dSValentin Clement mlir::LogicalResult 781044d5b5dSValentin Clement matchAndRewrite(fir::GlobalOp global, OpAdaptor adaptor, 782044d5b5dSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 783044d5b5dSValentin Clement auto tyAttr = convertType(global.getType()); 784044d5b5dSValentin Clement if (global.getType().isa<fir::BoxType>()) 785044d5b5dSValentin Clement tyAttr = tyAttr.cast<mlir::LLVM::LLVMPointerType>().getElementType(); 786044d5b5dSValentin Clement auto loc = global.getLoc(); 787044d5b5dSValentin Clement mlir::Attribute initAttr{}; 788044d5b5dSValentin Clement if (global.initVal()) 789044d5b5dSValentin Clement initAttr = global.initVal().getValue(); 790044d5b5dSValentin Clement auto linkage = convertLinkage(global.linkName()); 791044d5b5dSValentin Clement auto isConst = global.constant().hasValue(); 792044d5b5dSValentin Clement auto g = rewriter.create<mlir::LLVM::GlobalOp>( 793044d5b5dSValentin Clement loc, tyAttr, isConst, linkage, global.sym_name(), initAttr); 794044d5b5dSValentin Clement auto &gr = g.getInitializerRegion(); 795044d5b5dSValentin Clement rewriter.inlineRegionBefore(global.region(), gr, gr.end()); 796044d5b5dSValentin Clement if (!gr.empty()) { 797044d5b5dSValentin Clement // Replace insert_on_range with a constant dense attribute if the 798044d5b5dSValentin Clement // initialization is on the full range. 799044d5b5dSValentin Clement auto insertOnRangeOps = gr.front().getOps<fir::InsertOnRangeOp>(); 800044d5b5dSValentin Clement for (auto insertOp : insertOnRangeOps) { 801044d5b5dSValentin Clement if (isFullRange(insertOp.coor(), insertOp.getType())) { 802044d5b5dSValentin Clement auto seqTyAttr = convertType(insertOp.getType()); 803044d5b5dSValentin Clement auto *op = insertOp.val().getDefiningOp(); 804044d5b5dSValentin Clement auto constant = mlir::dyn_cast<mlir::arith::ConstantOp>(op); 805044d5b5dSValentin Clement if (!constant) { 806044d5b5dSValentin Clement auto convertOp = mlir::dyn_cast<fir::ConvertOp>(op); 807044d5b5dSValentin Clement if (!convertOp) 808044d5b5dSValentin Clement continue; 809044d5b5dSValentin Clement constant = cast<mlir::arith::ConstantOp>( 810044d5b5dSValentin Clement convertOp.value().getDefiningOp()); 811044d5b5dSValentin Clement } 812044d5b5dSValentin Clement mlir::Type vecType = mlir::VectorType::get( 813044d5b5dSValentin Clement insertOp.getType().getShape(), constant.getType()); 814044d5b5dSValentin Clement auto denseAttr = mlir::DenseElementsAttr::get( 815044d5b5dSValentin Clement vecType.cast<ShapedType>(), constant.value()); 816044d5b5dSValentin Clement rewriter.setInsertionPointAfter(insertOp); 817044d5b5dSValentin Clement rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>( 818044d5b5dSValentin Clement insertOp, seqTyAttr, denseAttr); 819044d5b5dSValentin Clement } 820044d5b5dSValentin Clement } 821044d5b5dSValentin Clement } 822044d5b5dSValentin Clement rewriter.eraseOp(global); 823044d5b5dSValentin Clement return success(); 824044d5b5dSValentin Clement } 825044d5b5dSValentin Clement 826044d5b5dSValentin Clement bool isFullRange(mlir::ArrayAttr indexes, fir::SequenceType seqTy) const { 827044d5b5dSValentin Clement auto extents = seqTy.getShape(); 828044d5b5dSValentin Clement if (indexes.size() / 2 != extents.size()) 829044d5b5dSValentin Clement return false; 830044d5b5dSValentin Clement for (unsigned i = 0; i < indexes.size(); i += 2) { 831044d5b5dSValentin Clement if (indexes[i].cast<IntegerAttr>().getInt() != 0) 832044d5b5dSValentin Clement return false; 833044d5b5dSValentin Clement if (indexes[i + 1].cast<IntegerAttr>().getInt() != extents[i / 2] - 1) 834044d5b5dSValentin Clement return false; 835044d5b5dSValentin Clement } 836044d5b5dSValentin Clement return true; 837044d5b5dSValentin Clement } 838044d5b5dSValentin Clement 8390c4a7a52SValentin Clement // TODO: String comparaison should be avoided. Replace linkName with an 8400c4a7a52SValentin Clement // enumeration. 841044d5b5dSValentin Clement mlir::LLVM::Linkage convertLinkage(Optional<StringRef> optLinkage) const { 842044d5b5dSValentin Clement if (optLinkage.hasValue()) { 843044d5b5dSValentin Clement auto name = optLinkage.getValue(); 844044d5b5dSValentin Clement if (name == "internal") 845044d5b5dSValentin Clement return mlir::LLVM::Linkage::Internal; 846044d5b5dSValentin Clement if (name == "linkonce") 847044d5b5dSValentin Clement return mlir::LLVM::Linkage::Linkonce; 848044d5b5dSValentin Clement if (name == "common") 849044d5b5dSValentin Clement return mlir::LLVM::Linkage::Common; 850044d5b5dSValentin Clement if (name == "weak") 851044d5b5dSValentin Clement return mlir::LLVM::Linkage::Weak; 852044d5b5dSValentin Clement } 853044d5b5dSValentin Clement return mlir::LLVM::Linkage::External; 854044d5b5dSValentin Clement } 855044d5b5dSValentin Clement }; 856044d5b5dSValentin Clement 85739f4ef81SValentin Clement void genCondBrOp(mlir::Location loc, mlir::Value cmp, mlir::Block *dest, 85839f4ef81SValentin Clement Optional<mlir::ValueRange> destOps, 85939f4ef81SValentin Clement mlir::ConversionPatternRewriter &rewriter, 86039f4ef81SValentin Clement mlir::Block *newBlock) { 86139f4ef81SValentin Clement if (destOps.hasValue()) 86239f4ef81SValentin Clement rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, destOps.getValue(), 86339f4ef81SValentin Clement newBlock, mlir::ValueRange()); 86439f4ef81SValentin Clement else 86539f4ef81SValentin Clement rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, newBlock); 86639f4ef81SValentin Clement } 86739f4ef81SValentin Clement 86839f4ef81SValentin Clement template <typename A, typename B> 86939f4ef81SValentin Clement void genBrOp(A caseOp, mlir::Block *dest, Optional<B> destOps, 87039f4ef81SValentin Clement mlir::ConversionPatternRewriter &rewriter) { 87139f4ef81SValentin Clement if (destOps.hasValue()) 87239f4ef81SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, destOps.getValue(), 87339f4ef81SValentin Clement dest); 87439f4ef81SValentin Clement else 87539f4ef81SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, llvm::None, dest); 87639f4ef81SValentin Clement } 87739f4ef81SValentin Clement 87839f4ef81SValentin Clement void genCaseLadderStep(mlir::Location loc, mlir::Value cmp, mlir::Block *dest, 87939f4ef81SValentin Clement Optional<mlir::ValueRange> destOps, 88039f4ef81SValentin Clement mlir::ConversionPatternRewriter &rewriter) { 88139f4ef81SValentin Clement auto *thisBlock = rewriter.getInsertionBlock(); 88239f4ef81SValentin Clement auto *newBlock = createBlock(rewriter, dest); 88339f4ef81SValentin Clement rewriter.setInsertionPointToEnd(thisBlock); 88439f4ef81SValentin Clement genCondBrOp(loc, cmp, dest, destOps, rewriter, newBlock); 88539f4ef81SValentin Clement rewriter.setInsertionPointToEnd(newBlock); 88639f4ef81SValentin Clement } 88739f4ef81SValentin Clement 88839f4ef81SValentin Clement /// Conversion of `fir.select_case` 88939f4ef81SValentin Clement /// 89039f4ef81SValentin Clement /// The `fir.select_case` operation is converted to a if-then-else ladder. 89139f4ef81SValentin Clement /// Depending on the case condition type, one or several comparison and 89239f4ef81SValentin Clement /// conditional branching can be generated. 89339f4ef81SValentin Clement /// 89439f4ef81SValentin Clement /// A a point value case such as `case(4)`, a lower bound case such as 89539f4ef81SValentin Clement /// `case(5:)` or an upper bound case such as `case(:3)` are converted to a 89639f4ef81SValentin Clement /// simple comparison between the selector value and the constant value in the 89739f4ef81SValentin Clement /// case. The block associated with the case condition is then executed if 89839f4ef81SValentin Clement /// the comparison succeed otherwise it branch to the next block with the 89939f4ef81SValentin Clement /// comparison for the the next case conditon. 90039f4ef81SValentin Clement /// 90139f4ef81SValentin Clement /// A closed interval case condition such as `case(7:10)` is converted with a 90239f4ef81SValentin Clement /// first comparison and conditional branching for the lower bound. If 90339f4ef81SValentin Clement /// successful, it branch to a second block with the comparison for the 90439f4ef81SValentin Clement /// upper bound in the same case condition. 90539f4ef81SValentin Clement /// 90639f4ef81SValentin Clement /// TODO: lowering of CHARACTER type cases is not handled yet. 90739f4ef81SValentin Clement struct SelectCaseOpConversion : public FIROpConversion<fir::SelectCaseOp> { 90839f4ef81SValentin Clement using FIROpConversion::FIROpConversion; 90939f4ef81SValentin Clement 91039f4ef81SValentin Clement mlir::LogicalResult 91139f4ef81SValentin Clement matchAndRewrite(fir::SelectCaseOp caseOp, OpAdaptor adaptor, 91239f4ef81SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 91339f4ef81SValentin Clement unsigned conds = caseOp.getNumConditions(); 91439f4ef81SValentin Clement llvm::ArrayRef<mlir::Attribute> cases = caseOp.getCases().getValue(); 91539f4ef81SValentin Clement // Type can be CHARACTER, INTEGER, or LOGICAL (C1145) 91639f4ef81SValentin Clement LLVM_ATTRIBUTE_UNUSED auto ty = caseOp.getSelector().getType(); 91739f4ef81SValentin Clement if (ty.isa<fir::CharacterType>()) 91839f4ef81SValentin Clement return rewriter.notifyMatchFailure(caseOp, 91939f4ef81SValentin Clement "conversion of fir.select_case with " 92039f4ef81SValentin Clement "character type not implemented yet"); 92139f4ef81SValentin Clement mlir::Value selector = caseOp.getSelector(adaptor.getOperands()); 92239f4ef81SValentin Clement auto loc = caseOp.getLoc(); 92339f4ef81SValentin Clement for (unsigned t = 0; t != conds; ++t) { 92439f4ef81SValentin Clement mlir::Block *dest = caseOp.getSuccessor(t); 92539f4ef81SValentin Clement llvm::Optional<mlir::ValueRange> destOps = 92639f4ef81SValentin Clement caseOp.getSuccessorOperands(adaptor.getOperands(), t); 92739f4ef81SValentin Clement llvm::Optional<mlir::ValueRange> cmpOps = 92839f4ef81SValentin Clement *caseOp.getCompareOperands(adaptor.getOperands(), t); 92939f4ef81SValentin Clement mlir::Value caseArg = *(cmpOps.getValue().begin()); 93039f4ef81SValentin Clement mlir::Attribute attr = cases[t]; 93139f4ef81SValentin Clement if (attr.isa<fir::PointIntervalAttr>()) { 93239f4ef81SValentin Clement auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 93339f4ef81SValentin Clement loc, mlir::LLVM::ICmpPredicate::eq, selector, caseArg); 93439f4ef81SValentin Clement genCaseLadderStep(loc, cmp, dest, destOps, rewriter); 93539f4ef81SValentin Clement continue; 93639f4ef81SValentin Clement } 93739f4ef81SValentin Clement if (attr.isa<fir::LowerBoundAttr>()) { 93839f4ef81SValentin Clement auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 93939f4ef81SValentin Clement loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector); 94039f4ef81SValentin Clement genCaseLadderStep(loc, cmp, dest, destOps, rewriter); 94139f4ef81SValentin Clement continue; 94239f4ef81SValentin Clement } 94339f4ef81SValentin Clement if (attr.isa<fir::UpperBoundAttr>()) { 94439f4ef81SValentin Clement auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 94539f4ef81SValentin Clement loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg); 94639f4ef81SValentin Clement genCaseLadderStep(loc, cmp, dest, destOps, rewriter); 94739f4ef81SValentin Clement continue; 94839f4ef81SValentin Clement } 94939f4ef81SValentin Clement if (attr.isa<fir::ClosedIntervalAttr>()) { 95039f4ef81SValentin Clement auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 95139f4ef81SValentin Clement loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector); 95239f4ef81SValentin Clement auto *thisBlock = rewriter.getInsertionBlock(); 95339f4ef81SValentin Clement auto *newBlock1 = createBlock(rewriter, dest); 95439f4ef81SValentin Clement auto *newBlock2 = createBlock(rewriter, dest); 95539f4ef81SValentin Clement rewriter.setInsertionPointToEnd(thisBlock); 95639f4ef81SValentin Clement rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, newBlock1, newBlock2); 95739f4ef81SValentin Clement rewriter.setInsertionPointToEnd(newBlock1); 95839f4ef81SValentin Clement mlir::Value caseArg0 = *(cmpOps.getValue().begin() + 1); 95939f4ef81SValentin Clement auto cmp0 = rewriter.create<mlir::LLVM::ICmpOp>( 96039f4ef81SValentin Clement loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg0); 96139f4ef81SValentin Clement genCondBrOp(loc, cmp0, dest, destOps, rewriter, newBlock2); 96239f4ef81SValentin Clement rewriter.setInsertionPointToEnd(newBlock2); 96339f4ef81SValentin Clement continue; 96439f4ef81SValentin Clement } 96539f4ef81SValentin Clement assert(attr.isa<mlir::UnitAttr>()); 96639f4ef81SValentin Clement assert((t + 1 == conds) && "unit must be last"); 96739f4ef81SValentin Clement genBrOp(caseOp, dest, destOps, rewriter); 96839f4ef81SValentin Clement } 96939f4ef81SValentin Clement return success(); 97039f4ef81SValentin Clement } 97139f4ef81SValentin Clement }; 97239f4ef81SValentin Clement 9738c239909SValentin Clement template <typename OP> 9748c239909SValentin Clement void selectMatchAndRewrite(fir::LLVMTypeConverter &lowering, OP select, 9758c239909SValentin Clement typename OP::Adaptor adaptor, 9768c239909SValentin Clement mlir::ConversionPatternRewriter &rewriter) { 9778c239909SValentin Clement unsigned conds = select.getNumConditions(); 9788c239909SValentin Clement auto cases = select.getCases().getValue(); 9798c239909SValentin Clement mlir::Value selector = adaptor.selector(); 9808c239909SValentin Clement auto loc = select.getLoc(); 9818c239909SValentin Clement assert(conds > 0 && "select must have cases"); 9828c239909SValentin Clement 9838c239909SValentin Clement llvm::SmallVector<mlir::Block *> destinations; 9848c239909SValentin Clement llvm::SmallVector<mlir::ValueRange> destinationsOperands; 9858c239909SValentin Clement mlir::Block *defaultDestination; 9868c239909SValentin Clement mlir::ValueRange defaultOperands; 9878c239909SValentin Clement llvm::SmallVector<int32_t> caseValues; 9888c239909SValentin Clement 9898c239909SValentin Clement for (unsigned t = 0; t != conds; ++t) { 9908c239909SValentin Clement mlir::Block *dest = select.getSuccessor(t); 9918c239909SValentin Clement auto destOps = select.getSuccessorOperands(adaptor.getOperands(), t); 9928c239909SValentin Clement const mlir::Attribute &attr = cases[t]; 9938c239909SValentin Clement if (auto intAttr = attr.template dyn_cast<mlir::IntegerAttr>()) { 9948c239909SValentin Clement destinations.push_back(dest); 9958c239909SValentin Clement destinationsOperands.push_back(destOps.hasValue() ? *destOps 9968c239909SValentin Clement : ValueRange()); 9978c239909SValentin Clement caseValues.push_back(intAttr.getInt()); 9988c239909SValentin Clement continue; 9998c239909SValentin Clement } 10008c239909SValentin Clement assert(attr.template dyn_cast_or_null<mlir::UnitAttr>()); 10018c239909SValentin Clement assert((t + 1 == conds) && "unit must be last"); 10028c239909SValentin Clement defaultDestination = dest; 10038c239909SValentin Clement defaultOperands = destOps.hasValue() ? *destOps : ValueRange(); 10048c239909SValentin Clement } 10058c239909SValentin Clement 10068c239909SValentin Clement // LLVM::SwitchOp takes a i32 type for the selector. 10078c239909SValentin Clement if (select.getSelector().getType() != rewriter.getI32Type()) 10088c239909SValentin Clement selector = 10098c239909SValentin Clement rewriter.create<LLVM::TruncOp>(loc, rewriter.getI32Type(), selector); 10108c239909SValentin Clement 10118c239909SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>( 10128c239909SValentin Clement select, selector, 10138c239909SValentin Clement /*defaultDestination=*/defaultDestination, 10148c239909SValentin Clement /*defaultOperands=*/defaultOperands, 10158c239909SValentin Clement /*caseValues=*/caseValues, 10168c239909SValentin Clement /*caseDestinations=*/destinations, 10178c239909SValentin Clement /*caseOperands=*/destinationsOperands, 10188c239909SValentin Clement /*branchWeights=*/ArrayRef<int32_t>()); 10198c239909SValentin Clement } 10208c239909SValentin Clement 10218c239909SValentin Clement /// conversion of fir::SelectOp to an if-then-else ladder 10228c239909SValentin Clement struct SelectOpConversion : public FIROpConversion<fir::SelectOp> { 10238c239909SValentin Clement using FIROpConversion::FIROpConversion; 10248c239909SValentin Clement 10258c239909SValentin Clement mlir::LogicalResult 10268c239909SValentin Clement matchAndRewrite(fir::SelectOp op, OpAdaptor adaptor, 10278c239909SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 10288c239909SValentin Clement selectMatchAndRewrite<fir::SelectOp>(lowerTy(), op, adaptor, rewriter); 10298c239909SValentin Clement return success(); 10308c239909SValentin Clement } 10318c239909SValentin Clement }; 10328c239909SValentin Clement 1033e3349fa1SAndrzej Warzynski /// `fir.load` --> `llvm.load` 1034e3349fa1SAndrzej Warzynski struct LoadOpConversion : public FIROpConversion<fir::LoadOp> { 1035e3349fa1SAndrzej Warzynski using FIROpConversion::FIROpConversion; 1036e3349fa1SAndrzej Warzynski 1037e3349fa1SAndrzej Warzynski mlir::LogicalResult 1038e3349fa1SAndrzej Warzynski matchAndRewrite(fir::LoadOp load, OpAdaptor adaptor, 1039e3349fa1SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 1040e3349fa1SAndrzej Warzynski // fir.box is a special case because it is considered as an ssa values in 1041e3349fa1SAndrzej Warzynski // fir, but it is lowered as a pointer to a descriptor. So fir.ref<fir.box> 1042e3349fa1SAndrzej Warzynski // and fir.box end up being the same llvm types and loading a 1043e3349fa1SAndrzej Warzynski // fir.ref<fir.box> is actually a no op in LLVM. 1044e3349fa1SAndrzej Warzynski if (load.getType().isa<fir::BoxType>()) { 1045e3349fa1SAndrzej Warzynski rewriter.replaceOp(load, adaptor.getOperands()[0]); 1046e3349fa1SAndrzej Warzynski } else { 1047e3349fa1SAndrzej Warzynski mlir::Type ty = convertType(load.getType()); 1048e3349fa1SAndrzej Warzynski ArrayRef<NamedAttribute> at = load->getAttrs(); 1049e3349fa1SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::LoadOp>( 1050e3349fa1SAndrzej Warzynski load, ty, adaptor.getOperands(), at); 1051e3349fa1SAndrzej Warzynski } 1052e3349fa1SAndrzej Warzynski return success(); 1053e3349fa1SAndrzej Warzynski } 1054e3349fa1SAndrzej Warzynski }; 1055e3349fa1SAndrzej Warzynski 10562a299e4fSValentin Clement /// Lower `fir.select_type` to LLVM IR dialect. 10572a299e4fSValentin Clement struct SelectTypeOpConversion : public FIROpConversion<fir::SelectTypeOp> { 10582a299e4fSValentin Clement using FIROpConversion::FIROpConversion; 10592a299e4fSValentin Clement 10602a299e4fSValentin Clement mlir::LogicalResult 10612a299e4fSValentin Clement matchAndRewrite(fir::SelectTypeOp select, OpAdaptor adaptor, 10622a299e4fSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 10632a299e4fSValentin Clement return rewriter.notifyMatchFailure( 10642a299e4fSValentin Clement select, "fir.select_type codegen is not implemented yet"); 10652a299e4fSValentin Clement } 10662a299e4fSValentin Clement }; 10672a299e4fSValentin Clement 10688c239909SValentin Clement /// conversion of fir::SelectRankOp to an if-then-else ladder 10698c239909SValentin Clement struct SelectRankOpConversion : public FIROpConversion<fir::SelectRankOp> { 10708c239909SValentin Clement using FIROpConversion::FIROpConversion; 10718c239909SValentin Clement 10728c239909SValentin Clement mlir::LogicalResult 10738c239909SValentin Clement matchAndRewrite(fir::SelectRankOp op, OpAdaptor adaptor, 10748c239909SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 10758c239909SValentin Clement selectMatchAndRewrite<fir::SelectRankOp>(lowerTy(), op, adaptor, rewriter); 10768c239909SValentin Clement return success(); 10778c239909SValentin Clement } 10788c239909SValentin Clement }; 10798c239909SValentin Clement 1080e3349fa1SAndrzej Warzynski /// `fir.store` --> `llvm.store` 1081e3349fa1SAndrzej Warzynski struct StoreOpConversion : public FIROpConversion<fir::StoreOp> { 1082e3349fa1SAndrzej Warzynski using FIROpConversion::FIROpConversion; 1083e3349fa1SAndrzej Warzynski 1084e3349fa1SAndrzej Warzynski mlir::LogicalResult 1085e3349fa1SAndrzej Warzynski matchAndRewrite(fir::StoreOp store, OpAdaptor adaptor, 1086e3349fa1SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 1087e3349fa1SAndrzej Warzynski if (store.value().getType().isa<fir::BoxType>()) { 1088e3349fa1SAndrzej Warzynski // fir.box value is actually in memory, load it first before storing it. 1089e3349fa1SAndrzej Warzynski mlir::Location loc = store.getLoc(); 1090e3349fa1SAndrzej Warzynski mlir::Type boxPtrTy = adaptor.getOperands()[0].getType(); 1091e3349fa1SAndrzej Warzynski auto val = rewriter.create<mlir::LLVM::LoadOp>( 1092e3349fa1SAndrzej Warzynski loc, boxPtrTy.cast<mlir::LLVM::LLVMPointerType>().getElementType(), 1093e3349fa1SAndrzej Warzynski adaptor.getOperands()[0]); 1094e3349fa1SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>( 1095e3349fa1SAndrzej Warzynski store, val, adaptor.getOperands()[1]); 1096e3349fa1SAndrzej Warzynski } else { 1097e3349fa1SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>( 1098e3349fa1SAndrzej Warzynski store, adaptor.getOperands()[0], adaptor.getOperands()[1]); 1099e3349fa1SAndrzej Warzynski } 1100e3349fa1SAndrzej Warzynski return success(); 1101e3349fa1SAndrzej Warzynski } 1102e3349fa1SAndrzej Warzynski }; 1103e3349fa1SAndrzej Warzynski 1104e3349fa1SAndrzej Warzynski /// convert to LLVM IR dialect `undef` 1105044d5b5dSValentin Clement struct UndefOpConversion : public FIROpConversion<fir::UndefOp> { 1106044d5b5dSValentin Clement using FIROpConversion::FIROpConversion; 1107044d5b5dSValentin Clement 1108044d5b5dSValentin Clement mlir::LogicalResult 1109044d5b5dSValentin Clement matchAndRewrite(fir::UndefOp undef, OpAdaptor, 1110044d5b5dSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 1111044d5b5dSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::UndefOp>( 1112044d5b5dSValentin Clement undef, convertType(undef.getType())); 1113044d5b5dSValentin Clement return success(); 1114044d5b5dSValentin Clement } 1115044d5b5dSValentin Clement }; 1116a7a61359SValentin Clement 1117e3349fa1SAndrzej Warzynski /// `fir.unreachable` --> `llvm.unreachable` 111832e08248SAndrzej Warzynski struct UnreachableOpConversion : public FIROpConversion<fir::UnreachableOp> { 111932e08248SAndrzej Warzynski using FIROpConversion::FIROpConversion; 112032e08248SAndrzej Warzynski 112132e08248SAndrzej Warzynski mlir::LogicalResult 112232e08248SAndrzej Warzynski matchAndRewrite(fir::UnreachableOp unreach, OpAdaptor adaptor, 112332e08248SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 112432e08248SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(unreach); 112532e08248SAndrzej Warzynski return success(); 112632e08248SAndrzej Warzynski } 112732e08248SAndrzej Warzynski }; 112832e08248SAndrzej Warzynski 1129a7a61359SValentin Clement struct ZeroOpConversion : public FIROpConversion<fir::ZeroOp> { 1130a7a61359SValentin Clement using FIROpConversion::FIROpConversion; 1131a7a61359SValentin Clement 1132a7a61359SValentin Clement mlir::LogicalResult 1133a7a61359SValentin Clement matchAndRewrite(fir::ZeroOp zero, OpAdaptor, 1134a7a61359SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 1135a7a61359SValentin Clement auto ty = convertType(zero.getType()); 1136a7a61359SValentin Clement if (ty.isa<mlir::LLVM::LLVMPointerType>()) { 1137a7a61359SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(zero, ty); 1138a7a61359SValentin Clement } else if (ty.isa<mlir::IntegerType>()) { 1139a7a61359SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>( 1140a7a61359SValentin Clement zero, ty, mlir::IntegerAttr::get(zero.getType(), 0)); 1141a7a61359SValentin Clement } else if (mlir::LLVM::isCompatibleFloatingPointType(ty)) { 1142a7a61359SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>( 1143a7a61359SValentin Clement zero, ty, mlir::FloatAttr::get(zero.getType(), 0.0)); 1144a7a61359SValentin Clement } else { 1145a7a61359SValentin Clement // TODO: create ConstantAggregateZero for FIR aggregate/array types. 114652d813edSValentin Clement return rewriter.notifyMatchFailure( 114752d813edSValentin Clement zero, 1148a7a61359SValentin Clement "conversion of fir.zero with aggregate type not implemented yet"); 1149a7a61359SValentin Clement } 1150a7a61359SValentin Clement return success(); 1151a7a61359SValentin Clement } 1152a7a61359SValentin Clement }; 115332e08248SAndrzej Warzynski 115454c56347SValentin Clement // Code shared between insert_value and extract_value Ops. 115554c56347SValentin Clement struct ValueOpCommon { 115654c56347SValentin Clement // Translate the arguments pertaining to any multidimensional array to 115754c56347SValentin Clement // row-major order for LLVM-IR. 115854c56347SValentin Clement static void toRowMajor(SmallVectorImpl<mlir::Attribute> &attrs, 115954c56347SValentin Clement mlir::Type ty) { 116054c56347SValentin Clement assert(ty && "type is null"); 116154c56347SValentin Clement const auto end = attrs.size(); 116254c56347SValentin Clement for (std::remove_const_t<decltype(end)> i = 0; i < end; ++i) { 116354c56347SValentin Clement if (auto seq = ty.dyn_cast<mlir::LLVM::LLVMArrayType>()) { 116454c56347SValentin Clement const auto dim = getDimension(seq); 116554c56347SValentin Clement if (dim > 1) { 116654c56347SValentin Clement auto ub = std::min(i + dim, end); 116754c56347SValentin Clement std::reverse(attrs.begin() + i, attrs.begin() + ub); 116854c56347SValentin Clement i += dim - 1; 116954c56347SValentin Clement } 117054c56347SValentin Clement ty = getArrayElementType(seq); 117154c56347SValentin Clement } else if (auto st = ty.dyn_cast<mlir::LLVM::LLVMStructType>()) { 117254c56347SValentin Clement ty = st.getBody()[attrs[i].cast<mlir::IntegerAttr>().getInt()]; 117354c56347SValentin Clement } else { 117454c56347SValentin Clement llvm_unreachable("index into invalid type"); 117554c56347SValentin Clement } 117654c56347SValentin Clement } 117754c56347SValentin Clement } 117854c56347SValentin Clement 117954c56347SValentin Clement static llvm::SmallVector<mlir::Attribute> 118054c56347SValentin Clement collectIndices(mlir::ConversionPatternRewriter &rewriter, 118154c56347SValentin Clement mlir::ArrayAttr arrAttr) { 118254c56347SValentin Clement llvm::SmallVector<mlir::Attribute> attrs; 118354c56347SValentin Clement for (auto i = arrAttr.begin(), e = arrAttr.end(); i != e; ++i) { 118454c56347SValentin Clement if (i->isa<mlir::IntegerAttr>()) { 118554c56347SValentin Clement attrs.push_back(*i); 118654c56347SValentin Clement } else { 118754c56347SValentin Clement auto fieldName = i->cast<mlir::StringAttr>().getValue(); 118854c56347SValentin Clement ++i; 118954c56347SValentin Clement auto ty = i->cast<mlir::TypeAttr>().getValue(); 119054c56347SValentin Clement auto index = ty.cast<fir::RecordType>().getFieldIndex(fieldName); 119154c56347SValentin Clement attrs.push_back(mlir::IntegerAttr::get(rewriter.getI32Type(), index)); 119254c56347SValentin Clement } 119354c56347SValentin Clement } 119454c56347SValentin Clement return attrs; 119554c56347SValentin Clement } 119654c56347SValentin Clement 119754c56347SValentin Clement private: 119854c56347SValentin Clement static unsigned getDimension(mlir::LLVM::LLVMArrayType ty) { 119954c56347SValentin Clement unsigned result = 1; 120054c56347SValentin Clement for (auto eleTy = ty.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>(); 120154c56347SValentin Clement eleTy; 120254c56347SValentin Clement eleTy = eleTy.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>()) 120354c56347SValentin Clement ++result; 120454c56347SValentin Clement return result; 120554c56347SValentin Clement } 120654c56347SValentin Clement 120754c56347SValentin Clement static mlir::Type getArrayElementType(mlir::LLVM::LLVMArrayType ty) { 120854c56347SValentin Clement auto eleTy = ty.getElementType(); 120954c56347SValentin Clement while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>()) 121054c56347SValentin Clement eleTy = arrTy.getElementType(); 121154c56347SValentin Clement return eleTy; 121254c56347SValentin Clement } 121354c56347SValentin Clement }; 121454c56347SValentin Clement 121554c56347SValentin Clement /// Extract a subobject value from an ssa-value of aggregate type 121654c56347SValentin Clement struct ExtractValueOpConversion 121754c56347SValentin Clement : public FIROpAndTypeConversion<fir::ExtractValueOp>, 121854c56347SValentin Clement public ValueOpCommon { 121954c56347SValentin Clement using FIROpAndTypeConversion::FIROpAndTypeConversion; 122054c56347SValentin Clement 122154c56347SValentin Clement mlir::LogicalResult 122254c56347SValentin Clement doRewrite(fir::ExtractValueOp extractVal, mlir::Type ty, OpAdaptor adaptor, 122354c56347SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 122454c56347SValentin Clement auto attrs = collectIndices(rewriter, extractVal.coor()); 122554c56347SValentin Clement toRowMajor(attrs, adaptor.getOperands()[0].getType()); 122654c56347SValentin Clement auto position = mlir::ArrayAttr::get(extractVal.getContext(), attrs); 122754c56347SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>( 122854c56347SValentin Clement extractVal, ty, adaptor.getOperands()[0], position); 122954c56347SValentin Clement return success(); 123054c56347SValentin Clement } 123154c56347SValentin Clement }; 123254c56347SValentin Clement 123354c56347SValentin Clement /// InsertValue is the generalized instruction for the composition of new 123454c56347SValentin Clement /// aggregate type values. 123554c56347SValentin Clement struct InsertValueOpConversion 123654c56347SValentin Clement : public FIROpAndTypeConversion<fir::InsertValueOp>, 123754c56347SValentin Clement public ValueOpCommon { 123854c56347SValentin Clement using FIROpAndTypeConversion::FIROpAndTypeConversion; 123954c56347SValentin Clement 124054c56347SValentin Clement mlir::LogicalResult 124154c56347SValentin Clement doRewrite(fir::InsertValueOp insertVal, mlir::Type ty, OpAdaptor adaptor, 124254c56347SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 124354c56347SValentin Clement auto attrs = collectIndices(rewriter, insertVal.coor()); 124454c56347SValentin Clement toRowMajor(attrs, adaptor.getOperands()[0].getType()); 124554c56347SValentin Clement auto position = mlir::ArrayAttr::get(insertVal.getContext(), attrs); 124654c56347SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 124754c56347SValentin Clement insertVal, ty, adaptor.getOperands()[0], adaptor.getOperands()[1], 124854c56347SValentin Clement position); 124954c56347SValentin Clement return success(); 125054c56347SValentin Clement } 125154c56347SValentin Clement }; 125254c56347SValentin Clement 12533ae8e442SValentin Clement /// InsertOnRange inserts a value into a sequence over a range of offsets. 12543ae8e442SValentin Clement struct InsertOnRangeOpConversion 12553ae8e442SValentin Clement : public FIROpAndTypeConversion<fir::InsertOnRangeOp> { 12563ae8e442SValentin Clement using FIROpAndTypeConversion::FIROpAndTypeConversion; 12573ae8e442SValentin Clement 12583ae8e442SValentin Clement // Increments an array of subscripts in a row major fasion. 12593ae8e442SValentin Clement void incrementSubscripts(const SmallVector<uint64_t> &dims, 12603ae8e442SValentin Clement SmallVector<uint64_t> &subscripts) const { 12613ae8e442SValentin Clement for (size_t i = dims.size(); i > 0; --i) { 12623ae8e442SValentin Clement if (++subscripts[i - 1] < dims[i - 1]) { 12633ae8e442SValentin Clement return; 12643ae8e442SValentin Clement } 12653ae8e442SValentin Clement subscripts[i - 1] = 0; 12663ae8e442SValentin Clement } 12673ae8e442SValentin Clement } 12683ae8e442SValentin Clement 12693ae8e442SValentin Clement mlir::LogicalResult 12703ae8e442SValentin Clement doRewrite(fir::InsertOnRangeOp range, mlir::Type ty, OpAdaptor adaptor, 12713ae8e442SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 12723ae8e442SValentin Clement 12733ae8e442SValentin Clement llvm::SmallVector<uint64_t> dims; 12743ae8e442SValentin Clement auto type = adaptor.getOperands()[0].getType(); 12753ae8e442SValentin Clement 12763ae8e442SValentin Clement // Iteratively extract the array dimensions from the type. 12773ae8e442SValentin Clement while (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) { 12783ae8e442SValentin Clement dims.push_back(t.getNumElements()); 12793ae8e442SValentin Clement type = t.getElementType(); 12803ae8e442SValentin Clement } 12813ae8e442SValentin Clement 12823ae8e442SValentin Clement SmallVector<uint64_t> lBounds; 12833ae8e442SValentin Clement SmallVector<uint64_t> uBounds; 12843ae8e442SValentin Clement 12853ae8e442SValentin Clement // Extract integer value from the attribute 12863ae8e442SValentin Clement SmallVector<int64_t> coordinates = llvm::to_vector<4>( 12873ae8e442SValentin Clement llvm::map_range(range.coor(), [](Attribute a) -> int64_t { 12883ae8e442SValentin Clement return a.cast<IntegerAttr>().getInt(); 12893ae8e442SValentin Clement })); 12903ae8e442SValentin Clement 12913ae8e442SValentin Clement // Unzip the upper and lower bound and convert to a row major format. 12923ae8e442SValentin Clement for (auto i = coordinates.rbegin(), e = coordinates.rend(); i != e; ++i) { 12933ae8e442SValentin Clement uBounds.push_back(*i++); 12943ae8e442SValentin Clement lBounds.push_back(*i); 12953ae8e442SValentin Clement } 12963ae8e442SValentin Clement 12973ae8e442SValentin Clement auto &subscripts = lBounds; 12983ae8e442SValentin Clement auto loc = range.getLoc(); 12993ae8e442SValentin Clement mlir::Value lastOp = adaptor.getOperands()[0]; 13003ae8e442SValentin Clement mlir::Value insertVal = adaptor.getOperands()[1]; 13013ae8e442SValentin Clement 13023ae8e442SValentin Clement auto i64Ty = rewriter.getI64Type(); 13033ae8e442SValentin Clement while (subscripts != uBounds) { 13043ae8e442SValentin Clement // Convert uint64_t's to Attribute's. 13053ae8e442SValentin Clement SmallVector<mlir::Attribute> subscriptAttrs; 13063ae8e442SValentin Clement for (const auto &subscript : subscripts) 13073ae8e442SValentin Clement subscriptAttrs.push_back(IntegerAttr::get(i64Ty, subscript)); 13083ae8e442SValentin Clement lastOp = rewriter.create<mlir::LLVM::InsertValueOp>( 13093ae8e442SValentin Clement loc, ty, lastOp, insertVal, 13103ae8e442SValentin Clement ArrayAttr::get(range.getContext(), subscriptAttrs)); 13113ae8e442SValentin Clement 13123ae8e442SValentin Clement incrementSubscripts(dims, subscripts); 13133ae8e442SValentin Clement } 13143ae8e442SValentin Clement 13153ae8e442SValentin Clement // Convert uint64_t's to Attribute's. 13163ae8e442SValentin Clement SmallVector<mlir::Attribute> subscriptAttrs; 13173ae8e442SValentin Clement for (const auto &subscript : subscripts) 13183ae8e442SValentin Clement subscriptAttrs.push_back( 13193ae8e442SValentin Clement IntegerAttr::get(rewriter.getI64Type(), subscript)); 13203ae8e442SValentin Clement mlir::ArrayRef<mlir::Attribute> arrayRef(subscriptAttrs); 13213ae8e442SValentin Clement 13223ae8e442SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 13233ae8e442SValentin Clement range, ty, lastOp, insertVal, 13243ae8e442SValentin Clement ArrayAttr::get(range.getContext(), arrayRef)); 13253ae8e442SValentin Clement 13263ae8e442SValentin Clement return success(); 13273ae8e442SValentin Clement } 13283ae8e442SValentin Clement }; 13297b5132daSValentin Clement 13307b5132daSValentin Clement // 13317b5132daSValentin Clement // Primitive operations on Complex types 13327b5132daSValentin Clement // 13337b5132daSValentin Clement 13347b5132daSValentin Clement /// Generate inline code for complex addition/subtraction 13357b5132daSValentin Clement template <typename LLVMOP, typename OPTY> 13367b5132daSValentin Clement mlir::LLVM::InsertValueOp complexSum(OPTY sumop, mlir::ValueRange opnds, 13377b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter, 13387b5132daSValentin Clement fir::LLVMTypeConverter &lowering) { 13397b5132daSValentin Clement mlir::Value a = opnds[0]; 13407b5132daSValentin Clement mlir::Value b = opnds[1]; 13417b5132daSValentin Clement auto loc = sumop.getLoc(); 13427b5132daSValentin Clement auto ctx = sumop.getContext(); 13437b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 13447b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 13457b5132daSValentin Clement mlir::Type eleTy = lowering.convertType(getComplexEleTy(sumop.getType())); 13467b5132daSValentin Clement mlir::Type ty = lowering.convertType(sumop.getType()); 13477b5132daSValentin Clement auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0); 13487b5132daSValentin Clement auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1); 13497b5132daSValentin Clement auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0); 13507b5132daSValentin Clement auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1); 13517b5132daSValentin Clement auto rx = rewriter.create<LLVMOP>(loc, eleTy, x0, x1); 13527b5132daSValentin Clement auto ry = rewriter.create<LLVMOP>(loc, eleTy, y0, y1); 13537b5132daSValentin Clement auto r0 = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 13547b5132daSValentin Clement auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r0, rx, c0); 13557b5132daSValentin Clement return rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ry, c1); 13567b5132daSValentin Clement } 13577b5132daSValentin Clement 13587b5132daSValentin Clement struct AddcOpConversion : public FIROpConversion<fir::AddcOp> { 13597b5132daSValentin Clement using FIROpConversion::FIROpConversion; 13607b5132daSValentin Clement 13617b5132daSValentin Clement mlir::LogicalResult 13627b5132daSValentin Clement matchAndRewrite(fir::AddcOp addc, OpAdaptor adaptor, 13637b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 13647b5132daSValentin Clement // given: (x + iy) + (x' + iy') 13657b5132daSValentin Clement // result: (x + x') + i(y + y') 13667b5132daSValentin Clement auto r = complexSum<mlir::LLVM::FAddOp>(addc, adaptor.getOperands(), 13677b5132daSValentin Clement rewriter, lowerTy()); 13687b5132daSValentin Clement rewriter.replaceOp(addc, r.getResult()); 13697b5132daSValentin Clement return success(); 13707b5132daSValentin Clement } 13717b5132daSValentin Clement }; 13727b5132daSValentin Clement 13737b5132daSValentin Clement struct SubcOpConversion : public FIROpConversion<fir::SubcOp> { 13747b5132daSValentin Clement using FIROpConversion::FIROpConversion; 13757b5132daSValentin Clement 13767b5132daSValentin Clement mlir::LogicalResult 13777b5132daSValentin Clement matchAndRewrite(fir::SubcOp subc, OpAdaptor adaptor, 13787b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 13797b5132daSValentin Clement // given: (x + iy) - (x' + iy') 13807b5132daSValentin Clement // result: (x - x') + i(y - y') 13817b5132daSValentin Clement auto r = complexSum<mlir::LLVM::FSubOp>(subc, adaptor.getOperands(), 13827b5132daSValentin Clement rewriter, lowerTy()); 13837b5132daSValentin Clement rewriter.replaceOp(subc, r.getResult()); 13847b5132daSValentin Clement return success(); 13857b5132daSValentin Clement } 13867b5132daSValentin Clement }; 13877b5132daSValentin Clement 13887b5132daSValentin Clement /// Inlined complex multiply 13897b5132daSValentin Clement struct MulcOpConversion : public FIROpConversion<fir::MulcOp> { 13907b5132daSValentin Clement using FIROpConversion::FIROpConversion; 13917b5132daSValentin Clement 13927b5132daSValentin Clement mlir::LogicalResult 13937b5132daSValentin Clement matchAndRewrite(fir::MulcOp mulc, OpAdaptor adaptor, 13947b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 13957b5132daSValentin Clement // TODO: Can we use a call to __muldc3 ? 13967b5132daSValentin Clement // given: (x + iy) * (x' + iy') 13977b5132daSValentin Clement // result: (xx'-yy')+i(xy'+yx') 13987b5132daSValentin Clement mlir::Value a = adaptor.getOperands()[0]; 13997b5132daSValentin Clement mlir::Value b = adaptor.getOperands()[1]; 14007b5132daSValentin Clement auto loc = mulc.getLoc(); 14017b5132daSValentin Clement auto *ctx = mulc.getContext(); 14027b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 14037b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 14047b5132daSValentin Clement mlir::Type eleTy = convertType(getComplexEleTy(mulc.getType())); 14057b5132daSValentin Clement mlir::Type ty = convertType(mulc.getType()); 14067b5132daSValentin Clement auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0); 14077b5132daSValentin Clement auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1); 14087b5132daSValentin Clement auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0); 14097b5132daSValentin Clement auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1); 14107b5132daSValentin Clement auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1); 14117b5132daSValentin Clement auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1); 14127b5132daSValentin Clement auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1); 14137b5132daSValentin Clement auto ri = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xy, yx); 14147b5132daSValentin Clement auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1); 14157b5132daSValentin Clement auto rr = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, xx, yy); 14167b5132daSValentin Clement auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 14177b5132daSValentin Clement auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0); 14187b5132daSValentin Clement auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1); 14197b5132daSValentin Clement rewriter.replaceOp(mulc, r0.getResult()); 14207b5132daSValentin Clement return success(); 14217b5132daSValentin Clement } 14227b5132daSValentin Clement }; 14237b5132daSValentin Clement 14247b5132daSValentin Clement /// Inlined complex division 14257b5132daSValentin Clement struct DivcOpConversion : public FIROpConversion<fir::DivcOp> { 14267b5132daSValentin Clement using FIROpConversion::FIROpConversion; 14277b5132daSValentin Clement 14287b5132daSValentin Clement mlir::LogicalResult 14297b5132daSValentin Clement matchAndRewrite(fir::DivcOp divc, OpAdaptor adaptor, 14307b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 14317b5132daSValentin Clement // TODO: Can we use a call to __divdc3 instead? 14327b5132daSValentin Clement // Just generate inline code for now. 14337b5132daSValentin Clement // given: (x + iy) / (x' + iy') 14347b5132daSValentin Clement // result: ((xx'+yy')/d) + i((yx'-xy')/d) where d = x'x' + y'y' 14357b5132daSValentin Clement mlir::Value a = adaptor.getOperands()[0]; 14367b5132daSValentin Clement mlir::Value b = adaptor.getOperands()[1]; 14377b5132daSValentin Clement auto loc = divc.getLoc(); 14387b5132daSValentin Clement auto *ctx = divc.getContext(); 14397b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 14407b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 14417b5132daSValentin Clement mlir::Type eleTy = convertType(getComplexEleTy(divc.getType())); 14427b5132daSValentin Clement mlir::Type ty = convertType(divc.getType()); 14437b5132daSValentin Clement auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0); 14447b5132daSValentin Clement auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1); 14457b5132daSValentin Clement auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0); 14467b5132daSValentin Clement auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1); 14477b5132daSValentin Clement auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1); 14487b5132daSValentin Clement auto x1x1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x1, x1); 14497b5132daSValentin Clement auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1); 14507b5132daSValentin Clement auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1); 14517b5132daSValentin Clement auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1); 14527b5132daSValentin Clement auto y1y1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y1, y1); 14537b5132daSValentin Clement auto d = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, x1x1, y1y1); 14547b5132daSValentin Clement auto rrn = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xx, yy); 14557b5132daSValentin Clement auto rin = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, yx, xy); 14567b5132daSValentin Clement auto rr = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rrn, d); 14577b5132daSValentin Clement auto ri = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rin, d); 14587b5132daSValentin Clement auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 14597b5132daSValentin Clement auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0); 14607b5132daSValentin Clement auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1); 14617b5132daSValentin Clement rewriter.replaceOp(divc, r0.getResult()); 14627b5132daSValentin Clement return success(); 14637b5132daSValentin Clement } 14647b5132daSValentin Clement }; 14657b5132daSValentin Clement 14667b5132daSValentin Clement /// Inlined complex negation 14677b5132daSValentin Clement struct NegcOpConversion : public FIROpConversion<fir::NegcOp> { 14687b5132daSValentin Clement using FIROpConversion::FIROpConversion; 14697b5132daSValentin Clement 14707b5132daSValentin Clement mlir::LogicalResult 14717b5132daSValentin Clement matchAndRewrite(fir::NegcOp neg, OpAdaptor adaptor, 14727b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 14737b5132daSValentin Clement // given: -(x + iy) 14747b5132daSValentin Clement // result: -x - iy 14757b5132daSValentin Clement auto *ctxt = neg.getContext(); 14767b5132daSValentin Clement auto eleTy = convertType(getComplexEleTy(neg.getType())); 14777b5132daSValentin Clement auto ty = convertType(neg.getType()); 14787b5132daSValentin Clement auto loc = neg.getLoc(); 14797b5132daSValentin Clement mlir::Value o0 = adaptor.getOperands()[0]; 14807b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0)); 14817b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1)); 14827b5132daSValentin Clement auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c0); 14837b5132daSValentin Clement auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c1); 14847b5132daSValentin Clement auto nrp = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, rp); 14857b5132daSValentin Clement auto nip = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, ip); 14867b5132daSValentin Clement auto r = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, o0, nrp, c0); 14877b5132daSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(neg, ty, r, nip, c1); 14887b5132daSValentin Clement return success(); 14897b5132daSValentin Clement } 14907b5132daSValentin Clement }; 14917b5132daSValentin Clement 14921ed5a90fSValentin Clement /// Conversion pattern for operation that must be dead. The information in these 14931ed5a90fSValentin Clement /// operations is used by other operation. At this point they should not have 14941ed5a90fSValentin Clement /// anymore uses. 14951ed5a90fSValentin Clement /// These operations are normally dead after the pre-codegen pass. 14961ed5a90fSValentin Clement template <typename FromOp> 14971ed5a90fSValentin Clement struct MustBeDeadConversion : public FIROpConversion<FromOp> { 14981ed5a90fSValentin Clement explicit MustBeDeadConversion(fir::LLVMTypeConverter &lowering) 14991ed5a90fSValentin Clement : FIROpConversion<FromOp>(lowering) {} 15001ed5a90fSValentin Clement using OpAdaptor = typename FromOp::Adaptor; 15011ed5a90fSValentin Clement 15021ed5a90fSValentin Clement mlir::LogicalResult 15031ed5a90fSValentin Clement matchAndRewrite(FromOp op, OpAdaptor adaptor, 15041ed5a90fSValentin Clement mlir::ConversionPatternRewriter &rewriter) const final { 15051ed5a90fSValentin Clement if (!op->getUses().empty()) 15061ed5a90fSValentin Clement return rewriter.notifyMatchFailure(op, "op must be dead"); 15071ed5a90fSValentin Clement rewriter.eraseOp(op); 15081ed5a90fSValentin Clement return success(); 15091ed5a90fSValentin Clement } 15101ed5a90fSValentin Clement }; 15111ed5a90fSValentin Clement 15121ed5a90fSValentin Clement struct ShapeOpConversion : public MustBeDeadConversion<fir::ShapeOp> { 15131ed5a90fSValentin Clement using MustBeDeadConversion::MustBeDeadConversion; 15141ed5a90fSValentin Clement }; 15151ed5a90fSValentin Clement 15161ed5a90fSValentin Clement struct ShapeShiftOpConversion : public MustBeDeadConversion<fir::ShapeShiftOp> { 15171ed5a90fSValentin Clement using MustBeDeadConversion::MustBeDeadConversion; 15181ed5a90fSValentin Clement }; 15191ed5a90fSValentin Clement 15201ed5a90fSValentin Clement struct ShiftOpConversion : public MustBeDeadConversion<fir::ShiftOp> { 15211ed5a90fSValentin Clement using MustBeDeadConversion::MustBeDeadConversion; 15221ed5a90fSValentin Clement }; 15231ed5a90fSValentin Clement 15241ed5a90fSValentin Clement struct SliceOpConversion : public MustBeDeadConversion<fir::SliceOp> { 15251ed5a90fSValentin Clement using MustBeDeadConversion::MustBeDeadConversion; 15261ed5a90fSValentin Clement }; 15271ed5a90fSValentin Clement 1528420ad7ceSAndrzej Warzynski /// `fir.is_present` --> 1529420ad7ceSAndrzej Warzynski /// ``` 1530420ad7ceSAndrzej Warzynski /// %0 = llvm.mlir.constant(0 : i64) 1531420ad7ceSAndrzej Warzynski /// %1 = llvm.ptrtoint %0 1532420ad7ceSAndrzej Warzynski /// %2 = llvm.icmp "ne" %1, %0 : i64 1533420ad7ceSAndrzej Warzynski /// ``` 1534420ad7ceSAndrzej Warzynski struct IsPresentOpConversion : public FIROpConversion<fir::IsPresentOp> { 1535420ad7ceSAndrzej Warzynski using FIROpConversion::FIROpConversion; 1536420ad7ceSAndrzej Warzynski 1537420ad7ceSAndrzej Warzynski mlir::LogicalResult 1538420ad7ceSAndrzej Warzynski matchAndRewrite(fir::IsPresentOp isPresent, OpAdaptor adaptor, 1539420ad7ceSAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 1540420ad7ceSAndrzej Warzynski mlir::Type idxTy = lowerTy().indexType(); 1541420ad7ceSAndrzej Warzynski mlir::Location loc = isPresent.getLoc(); 1542420ad7ceSAndrzej Warzynski auto ptr = adaptor.getOperands()[0]; 1543420ad7ceSAndrzej Warzynski 1544420ad7ceSAndrzej Warzynski if (isPresent.val().getType().isa<fir::BoxCharType>()) { 1545420ad7ceSAndrzej Warzynski auto structTy = ptr.getType().cast<mlir::LLVM::LLVMStructType>(); 1546420ad7ceSAndrzej Warzynski assert(!structTy.isOpaque() && !structTy.getBody().empty()); 1547420ad7ceSAndrzej Warzynski 1548420ad7ceSAndrzej Warzynski mlir::Type ty = structTy.getBody()[0]; 1549420ad7ceSAndrzej Warzynski mlir::MLIRContext *ctx = isPresent.getContext(); 1550420ad7ceSAndrzej Warzynski auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 1551420ad7ceSAndrzej Warzynski ptr = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, ptr, c0); 1552420ad7ceSAndrzej Warzynski } 1553420ad7ceSAndrzej Warzynski mlir::LLVM::ConstantOp c0 = 1554420ad7ceSAndrzej Warzynski genConstantIndex(isPresent.getLoc(), idxTy, rewriter, 0); 1555420ad7ceSAndrzej Warzynski auto addr = rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, ptr); 1556420ad7ceSAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>( 1557420ad7ceSAndrzej Warzynski isPresent, mlir::LLVM::ICmpPredicate::ne, addr, c0); 1558420ad7ceSAndrzej Warzynski 1559420ad7ceSAndrzej Warzynski return success(); 1560420ad7ceSAndrzej Warzynski } 1561420ad7ceSAndrzej Warzynski }; 15621e77b095SAndrzej Warzynski 15631e77b095SAndrzej Warzynski /// Convert `!fir.emboxchar<!fir.char<KIND, ?>, #n>` into a sequence of 15641e77b095SAndrzej Warzynski /// instructions that generate `!llvm.struct<(ptr<ik>, i64)>`. The 1st element 15651e77b095SAndrzej Warzynski /// in this struct is a pointer. Its type is determined from `KIND`. The 2nd 15661e77b095SAndrzej Warzynski /// element is the length of the character buffer (`#n`). 15671e77b095SAndrzej Warzynski struct EmboxCharOpConversion : public FIROpConversion<fir::EmboxCharOp> { 15681e77b095SAndrzej Warzynski using FIROpConversion::FIROpConversion; 15691e77b095SAndrzej Warzynski 15701e77b095SAndrzej Warzynski mlir::LogicalResult 15711e77b095SAndrzej Warzynski matchAndRewrite(fir::EmboxCharOp emboxChar, OpAdaptor adaptor, 15721e77b095SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 15731e77b095SAndrzej Warzynski mlir::ValueRange operands = adaptor.getOperands(); 15741e77b095SAndrzej Warzynski MLIRContext *ctx = emboxChar.getContext(); 15751e77b095SAndrzej Warzynski 15761e77b095SAndrzej Warzynski mlir::Value charBuffer = operands[0]; 15771e77b095SAndrzej Warzynski mlir::Value charBufferLen = operands[1]; 15781e77b095SAndrzej Warzynski 15791e77b095SAndrzej Warzynski mlir::Location loc = emboxChar.getLoc(); 15801e77b095SAndrzej Warzynski mlir::Type llvmStructTy = convertType(emboxChar.getType()); 15811e77b095SAndrzej Warzynski auto llvmStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, llvmStructTy); 15821e77b095SAndrzej Warzynski 15831e77b095SAndrzej Warzynski mlir::Type lenTy = 15841e77b095SAndrzej Warzynski llvmStructTy.cast<mlir::LLVM::LLVMStructType>().getBody()[1]; 15851e77b095SAndrzej Warzynski mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, charBufferLen); 15861e77b095SAndrzej Warzynski 15871e77b095SAndrzej Warzynski auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 15881e77b095SAndrzej Warzynski auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 15891e77b095SAndrzej Warzynski auto insertBufferOp = rewriter.create<mlir::LLVM::InsertValueOp>( 15901e77b095SAndrzej Warzynski loc, llvmStructTy, llvmStruct, charBuffer, c0); 15911e77b095SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 15921e77b095SAndrzej Warzynski emboxChar, llvmStructTy, insertBufferOp, lenAfterCast, c1); 15931e77b095SAndrzej Warzynski 15941e77b095SAndrzej Warzynski return success(); 15951e77b095SAndrzej Warzynski } 15961e77b095SAndrzej Warzynski }; 159714867ffcSAndrzej Warzynski 159814867ffcSAndrzej Warzynski /// Construct an `llvm.extractvalue` instruction. It will return value at 159914867ffcSAndrzej Warzynski /// element \p x from \p tuple. 160014867ffcSAndrzej Warzynski mlir::LLVM::ExtractValueOp 160114867ffcSAndrzej Warzynski genExtractValueWithIndex(mlir::Location loc, mlir::Value tuple, mlir::Type ty, 160214867ffcSAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter, 160314867ffcSAndrzej Warzynski mlir::MLIRContext *ctx, int x) { 160414867ffcSAndrzej Warzynski auto cx = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(x)); 160514867ffcSAndrzej Warzynski auto xty = ty.cast<mlir::LLVM::LLVMStructType>().getBody()[x]; 160614867ffcSAndrzej Warzynski return rewriter.create<mlir::LLVM::ExtractValueOp>(loc, xty, tuple, cx); 160714867ffcSAndrzej Warzynski } 160814867ffcSAndrzej Warzynski 16096c3d7fd4SAndrzej Warzynski /// Convert `!fir.boxchar_len` to `!llvm.extractvalue` for the 2nd part of the 16106c3d7fd4SAndrzej Warzynski /// boxchar. 16116c3d7fd4SAndrzej Warzynski struct BoxCharLenOpConversion : public FIROpConversion<fir::BoxCharLenOp> { 16126c3d7fd4SAndrzej Warzynski using FIROpConversion::FIROpConversion; 16136c3d7fd4SAndrzej Warzynski 16146c3d7fd4SAndrzej Warzynski mlir::LogicalResult 16156c3d7fd4SAndrzej Warzynski matchAndRewrite(fir::BoxCharLenOp boxCharLen, OpAdaptor adaptor, 16166c3d7fd4SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 16176c3d7fd4SAndrzej Warzynski mlir::Value boxChar = adaptor.getOperands()[0]; 16186c3d7fd4SAndrzej Warzynski mlir::Location loc = boxChar.getLoc(); 16196c3d7fd4SAndrzej Warzynski mlir::MLIRContext *ctx = boxChar.getContext(); 16206c3d7fd4SAndrzej Warzynski mlir::Type returnValTy = boxCharLen.getResult().getType(); 16216c3d7fd4SAndrzej Warzynski 16226c3d7fd4SAndrzej Warzynski constexpr int boxcharLenIdx = 1; 16236c3d7fd4SAndrzej Warzynski mlir::LLVM::ExtractValueOp len = genExtractValueWithIndex( 16246c3d7fd4SAndrzej Warzynski loc, boxChar, boxChar.getType(), rewriter, ctx, boxcharLenIdx); 16256c3d7fd4SAndrzej Warzynski mlir::Value lenAfterCast = integerCast(loc, rewriter, returnValTy, len); 16266c3d7fd4SAndrzej Warzynski rewriter.replaceOp(boxCharLen, lenAfterCast); 16276c3d7fd4SAndrzej Warzynski 16286c3d7fd4SAndrzej Warzynski return success(); 16296c3d7fd4SAndrzej Warzynski } 16306c3d7fd4SAndrzej Warzynski }; 16316c3d7fd4SAndrzej Warzynski 163214867ffcSAndrzej Warzynski /// Convert `fir.unboxchar` into two `llvm.extractvalue` instructions. One for 163314867ffcSAndrzej Warzynski /// the character buffer and one for the buffer length. 163414867ffcSAndrzej Warzynski struct UnboxCharOpConversion : public FIROpConversion<fir::UnboxCharOp> { 163514867ffcSAndrzej Warzynski using FIROpConversion::FIROpConversion; 163614867ffcSAndrzej Warzynski 163714867ffcSAndrzej Warzynski mlir::LogicalResult 163814867ffcSAndrzej Warzynski matchAndRewrite(fir::UnboxCharOp unboxchar, OpAdaptor adaptor, 163914867ffcSAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 164014867ffcSAndrzej Warzynski MLIRContext *ctx = unboxchar.getContext(); 164114867ffcSAndrzej Warzynski 164214867ffcSAndrzej Warzynski mlir::Type lenTy = convertType(unboxchar.getType(1)); 164314867ffcSAndrzej Warzynski mlir::Value tuple = adaptor.getOperands()[0]; 164414867ffcSAndrzej Warzynski mlir::Type tupleTy = tuple.getType(); 164514867ffcSAndrzej Warzynski 164614867ffcSAndrzej Warzynski mlir::Location loc = unboxchar.getLoc(); 164714867ffcSAndrzej Warzynski mlir::Value ptrToBuffer = 164814867ffcSAndrzej Warzynski genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 0); 164914867ffcSAndrzej Warzynski 165014867ffcSAndrzej Warzynski mlir::LLVM::ExtractValueOp len = 165114867ffcSAndrzej Warzynski genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 1); 165214867ffcSAndrzej Warzynski mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, len); 165314867ffcSAndrzej Warzynski 165414867ffcSAndrzej Warzynski rewriter.replaceOp(unboxchar, 165514867ffcSAndrzej Warzynski ArrayRef<mlir::Value>{ptrToBuffer, lenAfterCast}); 165614867ffcSAndrzej Warzynski return success(); 165714867ffcSAndrzej Warzynski } 165814867ffcSAndrzej Warzynski }; 165914867ffcSAndrzej Warzynski 1660044d5b5dSValentin Clement } // namespace 1661044d5b5dSValentin Clement 1662044d5b5dSValentin Clement namespace { 1663044d5b5dSValentin Clement /// Convert FIR dialect to LLVM dialect 1664044d5b5dSValentin Clement /// 1665044d5b5dSValentin Clement /// This pass lowers all FIR dialect operations to LLVM IR dialect. An 1666044d5b5dSValentin Clement /// MLIR pass is used to lower residual Std dialect to LLVM IR dialect. 1667044d5b5dSValentin Clement /// 1668044d5b5dSValentin Clement /// This pass is not complete yet. We are upstreaming it in small patches. 1669044d5b5dSValentin Clement class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> { 1670044d5b5dSValentin Clement public: 1671044d5b5dSValentin Clement mlir::ModuleOp getModule() { return getOperation(); } 1672044d5b5dSValentin Clement 1673044d5b5dSValentin Clement void runOnOperation() override final { 16747b5132daSValentin Clement auto mod = getModule(); 16757b5132daSValentin Clement if (!forcedTargetTriple.empty()) { 16767b5132daSValentin Clement fir::setTargetTriple(mod, forcedTargetTriple); 16777b5132daSValentin Clement } 16787b5132daSValentin Clement 1679044d5b5dSValentin Clement auto *context = getModule().getContext(); 1680044d5b5dSValentin Clement fir::LLVMTypeConverter typeConverter{getModule()}; 1681044d5b5dSValentin Clement mlir::OwningRewritePatternList pattern(context); 1682df3b9810SValentin Clement pattern.insert< 1683420ad7ceSAndrzej Warzynski AbsentOpConversion, AddcOpConversion, AddrOfOpConversion, 16841a2ec667SValentin Clement AllocaOpConversion, BoxAddrOpConversion, BoxCharLenOpConversion, 16851a2ec667SValentin Clement BoxDimsOpConversion, BoxEleSizeOpConversion, BoxIsAllocOpConversion, 16861a2ec667SValentin Clement BoxIsArrayOpConversion, BoxIsPtrOpConversion, BoxRankOpConversion, 1687*e38ef2ffSValentin Clement BoxTypeDescOpConversion, CallOpConversion, CmpcOpConversion, 1688*e38ef2ffSValentin Clement ConvertOpConversion, DispatchOpConversion, DispatchTableOpConversion, 1689*e38ef2ffSValentin Clement DTEntryOpConversion, DivcOpConversion, EmboxCharOpConversion, 1690*e38ef2ffSValentin Clement ExtractValueOpConversion, HasValueOpConversion, GenTypeDescOpConversion, 1691*e38ef2ffSValentin Clement GlobalLenOpConversion, GlobalOpConversion, InsertOnRangeOpConversion, 1692*e38ef2ffSValentin Clement InsertValueOpConversion, IsPresentOpConversion, LoadOpConversion, 1693*e38ef2ffSValentin Clement NegcOpConversion, MulcOpConversion, SelectCaseOpConversion, 1694*e38ef2ffSValentin Clement SelectOpConversion, SelectRankOpConversion, SelectTypeOpConversion, 1695*e38ef2ffSValentin Clement ShapeOpConversion, ShapeShiftOpConversion, ShiftOpConversion, 1696*e38ef2ffSValentin Clement SliceOpConversion, StoreOpConversion, StringLitOpConversion, 1697*e38ef2ffSValentin Clement SubcOpConversion, UnboxCharOpConversion, UndefOpConversion, 1698*e38ef2ffSValentin Clement UnreachableOpConversion, ZeroOpConversion>(typeConverter); 1699044d5b5dSValentin Clement mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern); 1700044d5b5dSValentin Clement mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter, 1701044d5b5dSValentin Clement pattern); 1702044d5b5dSValentin Clement mlir::ConversionTarget target{*context}; 1703044d5b5dSValentin Clement target.addLegalDialect<mlir::LLVM::LLVMDialect>(); 1704044d5b5dSValentin Clement 1705044d5b5dSValentin Clement // required NOPs for applying a full conversion 1706044d5b5dSValentin Clement target.addLegalOp<mlir::ModuleOp>(); 1707044d5b5dSValentin Clement 1708044d5b5dSValentin Clement // apply the patterns 1709044d5b5dSValentin Clement if (mlir::failed(mlir::applyFullConversion(getModule(), target, 1710044d5b5dSValentin Clement std::move(pattern)))) { 1711044d5b5dSValentin Clement signalPassFailure(); 1712044d5b5dSValentin Clement } 1713044d5b5dSValentin Clement } 1714044d5b5dSValentin Clement }; 1715044d5b5dSValentin Clement } // namespace 1716044d5b5dSValentin Clement 1717044d5b5dSValentin Clement std::unique_ptr<mlir::Pass> fir::createFIRToLLVMPass() { 1718044d5b5dSValentin Clement return std::make_unique<FIRToLLVMLowering>(); 1719044d5b5dSValentin Clement } 1720