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 468ddd11b9aSAndrzej Warzynski // `fir.call` -> `llvm.call` 469ddd11b9aSAndrzej Warzynski struct CallOpConversion : public FIROpConversion<fir::CallOp> { 470ddd11b9aSAndrzej Warzynski using FIROpConversion::FIROpConversion; 471ddd11b9aSAndrzej Warzynski 472ddd11b9aSAndrzej Warzynski mlir::LogicalResult 473ddd11b9aSAndrzej Warzynski matchAndRewrite(fir::CallOp call, OpAdaptor adaptor, 474ddd11b9aSAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 475ddd11b9aSAndrzej Warzynski SmallVector<mlir::Type> resultTys; 476ddd11b9aSAndrzej Warzynski for (auto r : call.getResults()) 477ddd11b9aSAndrzej Warzynski resultTys.push_back(convertType(r.getType())); 478ddd11b9aSAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>( 479ddd11b9aSAndrzej Warzynski call, resultTys, adaptor.getOperands(), call->getAttrs()); 480ddd11b9aSAndrzej Warzynski return success(); 481ddd11b9aSAndrzej Warzynski } 482ddd11b9aSAndrzej Warzynski }; 483ddd11b9aSAndrzej Warzynski 484092cee5fSValentin Clement static mlir::Type getComplexEleTy(mlir::Type complex) { 485092cee5fSValentin Clement if (auto cc = complex.dyn_cast<mlir::ComplexType>()) 486092cee5fSValentin Clement return cc.getElementType(); 487092cee5fSValentin Clement return complex.cast<fir::ComplexType>().getElementType(); 488092cee5fSValentin Clement } 489092cee5fSValentin Clement 490092cee5fSValentin Clement /// convert value of from-type to value of to-type 491092cee5fSValentin Clement struct ConvertOpConversion : public FIROpConversion<fir::ConvertOp> { 492092cee5fSValentin Clement using FIROpConversion::FIROpConversion; 493092cee5fSValentin Clement 494092cee5fSValentin Clement static bool isFloatingPointTy(mlir::Type ty) { 495092cee5fSValentin Clement return ty.isa<mlir::FloatType>(); 496092cee5fSValentin Clement } 497092cee5fSValentin Clement 498092cee5fSValentin Clement mlir::LogicalResult 499092cee5fSValentin Clement matchAndRewrite(fir::ConvertOp convert, OpAdaptor adaptor, 500092cee5fSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 501092cee5fSValentin Clement auto fromTy = convertType(convert.value().getType()); 502092cee5fSValentin Clement auto toTy = convertType(convert.res().getType()); 503092cee5fSValentin Clement mlir::Value op0 = adaptor.getOperands()[0]; 504092cee5fSValentin Clement if (fromTy == toTy) { 505092cee5fSValentin Clement rewriter.replaceOp(convert, op0); 506092cee5fSValentin Clement return success(); 507092cee5fSValentin Clement } 508092cee5fSValentin Clement auto loc = convert.getLoc(); 509092cee5fSValentin Clement auto convertFpToFp = [&](mlir::Value val, unsigned fromBits, 510092cee5fSValentin Clement unsigned toBits, mlir::Type toTy) -> mlir::Value { 511092cee5fSValentin Clement if (fromBits == toBits) { 512092cee5fSValentin Clement // TODO: Converting between two floating-point representations with the 513092cee5fSValentin Clement // same bitwidth is not allowed for now. 514092cee5fSValentin Clement mlir::emitError(loc, 515092cee5fSValentin Clement "cannot implicitly convert between two floating-point " 516092cee5fSValentin Clement "representations of the same bitwidth"); 517092cee5fSValentin Clement return {}; 518092cee5fSValentin Clement } 519092cee5fSValentin Clement if (fromBits > toBits) 520092cee5fSValentin Clement return rewriter.create<mlir::LLVM::FPTruncOp>(loc, toTy, val); 521092cee5fSValentin Clement return rewriter.create<mlir::LLVM::FPExtOp>(loc, toTy, val); 522092cee5fSValentin Clement }; 523092cee5fSValentin Clement // Complex to complex conversion. 524092cee5fSValentin Clement if (fir::isa_complex(convert.value().getType()) && 525092cee5fSValentin Clement fir::isa_complex(convert.res().getType())) { 526092cee5fSValentin Clement // Special case: handle the conversion of a complex such that both the 527092cee5fSValentin Clement // real and imaginary parts are converted together. 528092cee5fSValentin Clement auto zero = mlir::ArrayAttr::get(convert.getContext(), 529092cee5fSValentin Clement rewriter.getI32IntegerAttr(0)); 530092cee5fSValentin Clement auto one = mlir::ArrayAttr::get(convert.getContext(), 531092cee5fSValentin Clement rewriter.getI32IntegerAttr(1)); 532092cee5fSValentin Clement auto ty = convertType(getComplexEleTy(convert.value().getType())); 533092cee5fSValentin Clement auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, zero); 534092cee5fSValentin Clement auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, one); 535092cee5fSValentin Clement auto nt = convertType(getComplexEleTy(convert.res().getType())); 536092cee5fSValentin Clement auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(ty); 537092cee5fSValentin Clement auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(nt); 538092cee5fSValentin Clement auto rc = convertFpToFp(rp, fromBits, toBits, nt); 539092cee5fSValentin Clement auto ic = convertFpToFp(ip, fromBits, toBits, nt); 540092cee5fSValentin Clement auto un = rewriter.create<mlir::LLVM::UndefOp>(loc, toTy); 541092cee5fSValentin Clement auto i1 = 542092cee5fSValentin Clement rewriter.create<mlir::LLVM::InsertValueOp>(loc, toTy, un, rc, zero); 543092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(convert, toTy, i1, 544092cee5fSValentin Clement ic, one); 545092cee5fSValentin Clement return mlir::success(); 546092cee5fSValentin Clement } 547092cee5fSValentin Clement // Floating point to floating point conversion. 548092cee5fSValentin Clement if (isFloatingPointTy(fromTy)) { 549092cee5fSValentin Clement if (isFloatingPointTy(toTy)) { 550092cee5fSValentin Clement auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy); 551092cee5fSValentin Clement auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy); 552092cee5fSValentin Clement auto v = convertFpToFp(op0, fromBits, toBits, toTy); 553092cee5fSValentin Clement rewriter.replaceOp(convert, v); 554092cee5fSValentin Clement return mlir::success(); 555092cee5fSValentin Clement } 556092cee5fSValentin Clement if (toTy.isa<mlir::IntegerType>()) { 557092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::FPToSIOp>(convert, toTy, op0); 558092cee5fSValentin Clement return mlir::success(); 559092cee5fSValentin Clement } 560092cee5fSValentin Clement } else if (fromTy.isa<mlir::IntegerType>()) { 561092cee5fSValentin Clement // Integer to integer conversion. 562092cee5fSValentin Clement if (toTy.isa<mlir::IntegerType>()) { 563092cee5fSValentin Clement auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy); 564092cee5fSValentin Clement auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy); 565092cee5fSValentin Clement assert(fromBits != toBits); 566092cee5fSValentin Clement if (fromBits > toBits) { 567092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::TruncOp>(convert, toTy, op0); 568092cee5fSValentin Clement return mlir::success(); 569092cee5fSValentin Clement } 570092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::SExtOp>(convert, toTy, op0); 571092cee5fSValentin Clement return mlir::success(); 572092cee5fSValentin Clement } 573092cee5fSValentin Clement // Integer to floating point conversion. 574092cee5fSValentin Clement if (isFloatingPointTy(toTy)) { 575092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::SIToFPOp>(convert, toTy, op0); 576092cee5fSValentin Clement return mlir::success(); 577092cee5fSValentin Clement } 578092cee5fSValentin Clement // Integer to pointer conversion. 579092cee5fSValentin Clement if (toTy.isa<mlir::LLVM::LLVMPointerType>()) { 580092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(convert, toTy, op0); 581092cee5fSValentin Clement return mlir::success(); 582092cee5fSValentin Clement } 583092cee5fSValentin Clement } else if (fromTy.isa<mlir::LLVM::LLVMPointerType>()) { 584092cee5fSValentin Clement // Pointer to integer conversion. 585092cee5fSValentin Clement if (toTy.isa<mlir::IntegerType>()) { 586092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::PtrToIntOp>(convert, toTy, op0); 587092cee5fSValentin Clement return mlir::success(); 588092cee5fSValentin Clement } 589092cee5fSValentin Clement // Pointer to pointer conversion. 590092cee5fSValentin Clement if (toTy.isa<mlir::LLVM::LLVMPointerType>()) { 591092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(convert, toTy, op0); 592092cee5fSValentin Clement return mlir::success(); 593092cee5fSValentin Clement } 594092cee5fSValentin Clement } 595092cee5fSValentin Clement return emitError(loc) << "cannot convert " << fromTy << " to " << toTy; 596092cee5fSValentin Clement } 597092cee5fSValentin Clement }; 598092cee5fSValentin Clement 5999534e361SValentin Clement /// Lower `fir.dispatch` operation. A virtual call to a method in a dispatch 6009534e361SValentin Clement /// table. 6019534e361SValentin Clement struct DispatchOpConversion : public FIROpConversion<fir::DispatchOp> { 6029534e361SValentin Clement using FIROpConversion::FIROpConversion; 6039534e361SValentin Clement 6049534e361SValentin Clement mlir::LogicalResult 6059534e361SValentin Clement matchAndRewrite(fir::DispatchOp dispatch, OpAdaptor adaptor, 6069534e361SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 6079534e361SValentin Clement return rewriter.notifyMatchFailure( 6089534e361SValentin Clement dispatch, "fir.dispatch codegen is not implemented yet"); 6099534e361SValentin Clement } 6109534e361SValentin Clement }; 6119534e361SValentin Clement 6129534e361SValentin Clement /// Lower `fir.dispatch_table` operation. The dispatch table for a Fortran 6139534e361SValentin Clement /// derived type. 6149534e361SValentin Clement struct DispatchTableOpConversion 6159534e361SValentin Clement : public FIROpConversion<fir::DispatchTableOp> { 6169534e361SValentin Clement using FIROpConversion::FIROpConversion; 6179534e361SValentin Clement 6189534e361SValentin Clement mlir::LogicalResult 6199534e361SValentin Clement matchAndRewrite(fir::DispatchTableOp dispTab, OpAdaptor adaptor, 6209534e361SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 6219534e361SValentin Clement return rewriter.notifyMatchFailure( 6229534e361SValentin Clement dispTab, "fir.dispatch_table codegen is not implemented yet"); 6239534e361SValentin Clement } 6249534e361SValentin Clement }; 6259534e361SValentin Clement 6269534e361SValentin Clement /// Lower `fir.dt_entry` operation. An entry in a dispatch table; binds a 6279534e361SValentin Clement /// method-name to a function. 6289534e361SValentin Clement struct DTEntryOpConversion : public FIROpConversion<fir::DTEntryOp> { 6299534e361SValentin Clement using FIROpConversion::FIROpConversion; 6309534e361SValentin Clement 6319534e361SValentin Clement mlir::LogicalResult 6329534e361SValentin Clement matchAndRewrite(fir::DTEntryOp dtEnt, OpAdaptor adaptor, 6339534e361SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 6349534e361SValentin Clement return rewriter.notifyMatchFailure( 6359534e361SValentin Clement dtEnt, "fir.dt_entry codegen is not implemented yet"); 6369534e361SValentin Clement } 6379534e361SValentin Clement }; 6389534e361SValentin Clement 639*677df8c7SValentin Clement /// Lower `fir.global_len` operation. 640*677df8c7SValentin Clement struct GlobalLenOpConversion : public FIROpConversion<fir::GlobalLenOp> { 641*677df8c7SValentin Clement using FIROpConversion::FIROpConversion; 642*677df8c7SValentin Clement 643*677df8c7SValentin Clement mlir::LogicalResult 644*677df8c7SValentin Clement matchAndRewrite(fir::GlobalLenOp globalLen, OpAdaptor adaptor, 645*677df8c7SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 646*677df8c7SValentin Clement return rewriter.notifyMatchFailure( 647*677df8c7SValentin Clement globalLen, "fir.global_len codegen is not implemented yet"); 648*677df8c7SValentin Clement } 649*677df8c7SValentin Clement }; 650*677df8c7SValentin Clement 6510c4a7a52SValentin Clement /// Lower `fir.has_value` operation to `llvm.return` operation. 652044d5b5dSValentin Clement struct HasValueOpConversion : public FIROpConversion<fir::HasValueOp> { 653044d5b5dSValentin Clement using FIROpConversion::FIROpConversion; 654044d5b5dSValentin Clement 655044d5b5dSValentin Clement mlir::LogicalResult 656044d5b5dSValentin Clement matchAndRewrite(fir::HasValueOp op, OpAdaptor adaptor, 657044d5b5dSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 658044d5b5dSValentin Clement rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, adaptor.getOperands()); 659044d5b5dSValentin Clement return success(); 660044d5b5dSValentin Clement } 661044d5b5dSValentin Clement }; 662044d5b5dSValentin Clement 6630c4a7a52SValentin Clement /// Lower `fir.global` operation to `llvm.global` operation. 6640c4a7a52SValentin Clement /// `fir.insert_on_range` operations are replaced with constant dense attribute 6650c4a7a52SValentin Clement /// if they are applied on the full range. 666044d5b5dSValentin Clement struct GlobalOpConversion : public FIROpConversion<fir::GlobalOp> { 667044d5b5dSValentin Clement using FIROpConversion::FIROpConversion; 668044d5b5dSValentin Clement 669044d5b5dSValentin Clement mlir::LogicalResult 670044d5b5dSValentin Clement matchAndRewrite(fir::GlobalOp global, OpAdaptor adaptor, 671044d5b5dSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 672044d5b5dSValentin Clement auto tyAttr = convertType(global.getType()); 673044d5b5dSValentin Clement if (global.getType().isa<fir::BoxType>()) 674044d5b5dSValentin Clement tyAttr = tyAttr.cast<mlir::LLVM::LLVMPointerType>().getElementType(); 675044d5b5dSValentin Clement auto loc = global.getLoc(); 676044d5b5dSValentin Clement mlir::Attribute initAttr{}; 677044d5b5dSValentin Clement if (global.initVal()) 678044d5b5dSValentin Clement initAttr = global.initVal().getValue(); 679044d5b5dSValentin Clement auto linkage = convertLinkage(global.linkName()); 680044d5b5dSValentin Clement auto isConst = global.constant().hasValue(); 681044d5b5dSValentin Clement auto g = rewriter.create<mlir::LLVM::GlobalOp>( 682044d5b5dSValentin Clement loc, tyAttr, isConst, linkage, global.sym_name(), initAttr); 683044d5b5dSValentin Clement auto &gr = g.getInitializerRegion(); 684044d5b5dSValentin Clement rewriter.inlineRegionBefore(global.region(), gr, gr.end()); 685044d5b5dSValentin Clement if (!gr.empty()) { 686044d5b5dSValentin Clement // Replace insert_on_range with a constant dense attribute if the 687044d5b5dSValentin Clement // initialization is on the full range. 688044d5b5dSValentin Clement auto insertOnRangeOps = gr.front().getOps<fir::InsertOnRangeOp>(); 689044d5b5dSValentin Clement for (auto insertOp : insertOnRangeOps) { 690044d5b5dSValentin Clement if (isFullRange(insertOp.coor(), insertOp.getType())) { 691044d5b5dSValentin Clement auto seqTyAttr = convertType(insertOp.getType()); 692044d5b5dSValentin Clement auto *op = insertOp.val().getDefiningOp(); 693044d5b5dSValentin Clement auto constant = mlir::dyn_cast<mlir::arith::ConstantOp>(op); 694044d5b5dSValentin Clement if (!constant) { 695044d5b5dSValentin Clement auto convertOp = mlir::dyn_cast<fir::ConvertOp>(op); 696044d5b5dSValentin Clement if (!convertOp) 697044d5b5dSValentin Clement continue; 698044d5b5dSValentin Clement constant = cast<mlir::arith::ConstantOp>( 699044d5b5dSValentin Clement convertOp.value().getDefiningOp()); 700044d5b5dSValentin Clement } 701044d5b5dSValentin Clement mlir::Type vecType = mlir::VectorType::get( 702044d5b5dSValentin Clement insertOp.getType().getShape(), constant.getType()); 703044d5b5dSValentin Clement auto denseAttr = mlir::DenseElementsAttr::get( 704044d5b5dSValentin Clement vecType.cast<ShapedType>(), constant.value()); 705044d5b5dSValentin Clement rewriter.setInsertionPointAfter(insertOp); 706044d5b5dSValentin Clement rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>( 707044d5b5dSValentin Clement insertOp, seqTyAttr, denseAttr); 708044d5b5dSValentin Clement } 709044d5b5dSValentin Clement } 710044d5b5dSValentin Clement } 711044d5b5dSValentin Clement rewriter.eraseOp(global); 712044d5b5dSValentin Clement return success(); 713044d5b5dSValentin Clement } 714044d5b5dSValentin Clement 715044d5b5dSValentin Clement bool isFullRange(mlir::ArrayAttr indexes, fir::SequenceType seqTy) const { 716044d5b5dSValentin Clement auto extents = seqTy.getShape(); 717044d5b5dSValentin Clement if (indexes.size() / 2 != extents.size()) 718044d5b5dSValentin Clement return false; 719044d5b5dSValentin Clement for (unsigned i = 0; i < indexes.size(); i += 2) { 720044d5b5dSValentin Clement if (indexes[i].cast<IntegerAttr>().getInt() != 0) 721044d5b5dSValentin Clement return false; 722044d5b5dSValentin Clement if (indexes[i + 1].cast<IntegerAttr>().getInt() != extents[i / 2] - 1) 723044d5b5dSValentin Clement return false; 724044d5b5dSValentin Clement } 725044d5b5dSValentin Clement return true; 726044d5b5dSValentin Clement } 727044d5b5dSValentin Clement 7280c4a7a52SValentin Clement // TODO: String comparaison should be avoided. Replace linkName with an 7290c4a7a52SValentin Clement // enumeration. 730044d5b5dSValentin Clement mlir::LLVM::Linkage convertLinkage(Optional<StringRef> optLinkage) const { 731044d5b5dSValentin Clement if (optLinkage.hasValue()) { 732044d5b5dSValentin Clement auto name = optLinkage.getValue(); 733044d5b5dSValentin Clement if (name == "internal") 734044d5b5dSValentin Clement return mlir::LLVM::Linkage::Internal; 735044d5b5dSValentin Clement if (name == "linkonce") 736044d5b5dSValentin Clement return mlir::LLVM::Linkage::Linkonce; 737044d5b5dSValentin Clement if (name == "common") 738044d5b5dSValentin Clement return mlir::LLVM::Linkage::Common; 739044d5b5dSValentin Clement if (name == "weak") 740044d5b5dSValentin Clement return mlir::LLVM::Linkage::Weak; 741044d5b5dSValentin Clement } 742044d5b5dSValentin Clement return mlir::LLVM::Linkage::External; 743044d5b5dSValentin Clement } 744044d5b5dSValentin Clement }; 745044d5b5dSValentin Clement 74639f4ef81SValentin Clement void genCondBrOp(mlir::Location loc, mlir::Value cmp, mlir::Block *dest, 74739f4ef81SValentin Clement Optional<mlir::ValueRange> destOps, 74839f4ef81SValentin Clement mlir::ConversionPatternRewriter &rewriter, 74939f4ef81SValentin Clement mlir::Block *newBlock) { 75039f4ef81SValentin Clement if (destOps.hasValue()) 75139f4ef81SValentin Clement rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, destOps.getValue(), 75239f4ef81SValentin Clement newBlock, mlir::ValueRange()); 75339f4ef81SValentin Clement else 75439f4ef81SValentin Clement rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, newBlock); 75539f4ef81SValentin Clement } 75639f4ef81SValentin Clement 75739f4ef81SValentin Clement template <typename A, typename B> 75839f4ef81SValentin Clement void genBrOp(A caseOp, mlir::Block *dest, Optional<B> destOps, 75939f4ef81SValentin Clement mlir::ConversionPatternRewriter &rewriter) { 76039f4ef81SValentin Clement if (destOps.hasValue()) 76139f4ef81SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, destOps.getValue(), 76239f4ef81SValentin Clement dest); 76339f4ef81SValentin Clement else 76439f4ef81SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, llvm::None, dest); 76539f4ef81SValentin Clement } 76639f4ef81SValentin Clement 76739f4ef81SValentin Clement void genCaseLadderStep(mlir::Location loc, mlir::Value cmp, mlir::Block *dest, 76839f4ef81SValentin Clement Optional<mlir::ValueRange> destOps, 76939f4ef81SValentin Clement mlir::ConversionPatternRewriter &rewriter) { 77039f4ef81SValentin Clement auto *thisBlock = rewriter.getInsertionBlock(); 77139f4ef81SValentin Clement auto *newBlock = createBlock(rewriter, dest); 77239f4ef81SValentin Clement rewriter.setInsertionPointToEnd(thisBlock); 77339f4ef81SValentin Clement genCondBrOp(loc, cmp, dest, destOps, rewriter, newBlock); 77439f4ef81SValentin Clement rewriter.setInsertionPointToEnd(newBlock); 77539f4ef81SValentin Clement } 77639f4ef81SValentin Clement 77739f4ef81SValentin Clement /// Conversion of `fir.select_case` 77839f4ef81SValentin Clement /// 77939f4ef81SValentin Clement /// The `fir.select_case` operation is converted to a if-then-else ladder. 78039f4ef81SValentin Clement /// Depending on the case condition type, one or several comparison and 78139f4ef81SValentin Clement /// conditional branching can be generated. 78239f4ef81SValentin Clement /// 78339f4ef81SValentin Clement /// A a point value case such as `case(4)`, a lower bound case such as 78439f4ef81SValentin Clement /// `case(5:)` or an upper bound case such as `case(:3)` are converted to a 78539f4ef81SValentin Clement /// simple comparison between the selector value and the constant value in the 78639f4ef81SValentin Clement /// case. The block associated with the case condition is then executed if 78739f4ef81SValentin Clement /// the comparison succeed otherwise it branch to the next block with the 78839f4ef81SValentin Clement /// comparison for the the next case conditon. 78939f4ef81SValentin Clement /// 79039f4ef81SValentin Clement /// A closed interval case condition such as `case(7:10)` is converted with a 79139f4ef81SValentin Clement /// first comparison and conditional branching for the lower bound. If 79239f4ef81SValentin Clement /// successful, it branch to a second block with the comparison for the 79339f4ef81SValentin Clement /// upper bound in the same case condition. 79439f4ef81SValentin Clement /// 79539f4ef81SValentin Clement /// TODO: lowering of CHARACTER type cases is not handled yet. 79639f4ef81SValentin Clement struct SelectCaseOpConversion : public FIROpConversion<fir::SelectCaseOp> { 79739f4ef81SValentin Clement using FIROpConversion::FIROpConversion; 79839f4ef81SValentin Clement 79939f4ef81SValentin Clement mlir::LogicalResult 80039f4ef81SValentin Clement matchAndRewrite(fir::SelectCaseOp caseOp, OpAdaptor adaptor, 80139f4ef81SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 80239f4ef81SValentin Clement unsigned conds = caseOp.getNumConditions(); 80339f4ef81SValentin Clement llvm::ArrayRef<mlir::Attribute> cases = caseOp.getCases().getValue(); 80439f4ef81SValentin Clement // Type can be CHARACTER, INTEGER, or LOGICAL (C1145) 80539f4ef81SValentin Clement LLVM_ATTRIBUTE_UNUSED auto ty = caseOp.getSelector().getType(); 80639f4ef81SValentin Clement if (ty.isa<fir::CharacterType>()) 80739f4ef81SValentin Clement return rewriter.notifyMatchFailure(caseOp, 80839f4ef81SValentin Clement "conversion of fir.select_case with " 80939f4ef81SValentin Clement "character type not implemented yet"); 81039f4ef81SValentin Clement mlir::Value selector = caseOp.getSelector(adaptor.getOperands()); 81139f4ef81SValentin Clement auto loc = caseOp.getLoc(); 81239f4ef81SValentin Clement for (unsigned t = 0; t != conds; ++t) { 81339f4ef81SValentin Clement mlir::Block *dest = caseOp.getSuccessor(t); 81439f4ef81SValentin Clement llvm::Optional<mlir::ValueRange> destOps = 81539f4ef81SValentin Clement caseOp.getSuccessorOperands(adaptor.getOperands(), t); 81639f4ef81SValentin Clement llvm::Optional<mlir::ValueRange> cmpOps = 81739f4ef81SValentin Clement *caseOp.getCompareOperands(adaptor.getOperands(), t); 81839f4ef81SValentin Clement mlir::Value caseArg = *(cmpOps.getValue().begin()); 81939f4ef81SValentin Clement mlir::Attribute attr = cases[t]; 82039f4ef81SValentin Clement if (attr.isa<fir::PointIntervalAttr>()) { 82139f4ef81SValentin Clement auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 82239f4ef81SValentin Clement loc, mlir::LLVM::ICmpPredicate::eq, selector, caseArg); 82339f4ef81SValentin Clement genCaseLadderStep(loc, cmp, dest, destOps, rewriter); 82439f4ef81SValentin Clement continue; 82539f4ef81SValentin Clement } 82639f4ef81SValentin Clement if (attr.isa<fir::LowerBoundAttr>()) { 82739f4ef81SValentin Clement auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 82839f4ef81SValentin Clement loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector); 82939f4ef81SValentin Clement genCaseLadderStep(loc, cmp, dest, destOps, rewriter); 83039f4ef81SValentin Clement continue; 83139f4ef81SValentin Clement } 83239f4ef81SValentin Clement if (attr.isa<fir::UpperBoundAttr>()) { 83339f4ef81SValentin Clement auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 83439f4ef81SValentin Clement loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg); 83539f4ef81SValentin Clement genCaseLadderStep(loc, cmp, dest, destOps, rewriter); 83639f4ef81SValentin Clement continue; 83739f4ef81SValentin Clement } 83839f4ef81SValentin Clement if (attr.isa<fir::ClosedIntervalAttr>()) { 83939f4ef81SValentin Clement auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 84039f4ef81SValentin Clement loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector); 84139f4ef81SValentin Clement auto *thisBlock = rewriter.getInsertionBlock(); 84239f4ef81SValentin Clement auto *newBlock1 = createBlock(rewriter, dest); 84339f4ef81SValentin Clement auto *newBlock2 = createBlock(rewriter, dest); 84439f4ef81SValentin Clement rewriter.setInsertionPointToEnd(thisBlock); 84539f4ef81SValentin Clement rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, newBlock1, newBlock2); 84639f4ef81SValentin Clement rewriter.setInsertionPointToEnd(newBlock1); 84739f4ef81SValentin Clement mlir::Value caseArg0 = *(cmpOps.getValue().begin() + 1); 84839f4ef81SValentin Clement auto cmp0 = rewriter.create<mlir::LLVM::ICmpOp>( 84939f4ef81SValentin Clement loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg0); 85039f4ef81SValentin Clement genCondBrOp(loc, cmp0, dest, destOps, rewriter, newBlock2); 85139f4ef81SValentin Clement rewriter.setInsertionPointToEnd(newBlock2); 85239f4ef81SValentin Clement continue; 85339f4ef81SValentin Clement } 85439f4ef81SValentin Clement assert(attr.isa<mlir::UnitAttr>()); 85539f4ef81SValentin Clement assert((t + 1 == conds) && "unit must be last"); 85639f4ef81SValentin Clement genBrOp(caseOp, dest, destOps, rewriter); 85739f4ef81SValentin Clement } 85839f4ef81SValentin Clement return success(); 85939f4ef81SValentin Clement } 86039f4ef81SValentin Clement }; 86139f4ef81SValentin Clement 8628c239909SValentin Clement template <typename OP> 8638c239909SValentin Clement void selectMatchAndRewrite(fir::LLVMTypeConverter &lowering, OP select, 8648c239909SValentin Clement typename OP::Adaptor adaptor, 8658c239909SValentin Clement mlir::ConversionPatternRewriter &rewriter) { 8668c239909SValentin Clement unsigned conds = select.getNumConditions(); 8678c239909SValentin Clement auto cases = select.getCases().getValue(); 8688c239909SValentin Clement mlir::Value selector = adaptor.selector(); 8698c239909SValentin Clement auto loc = select.getLoc(); 8708c239909SValentin Clement assert(conds > 0 && "select must have cases"); 8718c239909SValentin Clement 8728c239909SValentin Clement llvm::SmallVector<mlir::Block *> destinations; 8738c239909SValentin Clement llvm::SmallVector<mlir::ValueRange> destinationsOperands; 8748c239909SValentin Clement mlir::Block *defaultDestination; 8758c239909SValentin Clement mlir::ValueRange defaultOperands; 8768c239909SValentin Clement llvm::SmallVector<int32_t> caseValues; 8778c239909SValentin Clement 8788c239909SValentin Clement for (unsigned t = 0; t != conds; ++t) { 8798c239909SValentin Clement mlir::Block *dest = select.getSuccessor(t); 8808c239909SValentin Clement auto destOps = select.getSuccessorOperands(adaptor.getOperands(), t); 8818c239909SValentin Clement const mlir::Attribute &attr = cases[t]; 8828c239909SValentin Clement if (auto intAttr = attr.template dyn_cast<mlir::IntegerAttr>()) { 8838c239909SValentin Clement destinations.push_back(dest); 8848c239909SValentin Clement destinationsOperands.push_back(destOps.hasValue() ? *destOps 8858c239909SValentin Clement : ValueRange()); 8868c239909SValentin Clement caseValues.push_back(intAttr.getInt()); 8878c239909SValentin Clement continue; 8888c239909SValentin Clement } 8898c239909SValentin Clement assert(attr.template dyn_cast_or_null<mlir::UnitAttr>()); 8908c239909SValentin Clement assert((t + 1 == conds) && "unit must be last"); 8918c239909SValentin Clement defaultDestination = dest; 8928c239909SValentin Clement defaultOperands = destOps.hasValue() ? *destOps : ValueRange(); 8938c239909SValentin Clement } 8948c239909SValentin Clement 8958c239909SValentin Clement // LLVM::SwitchOp takes a i32 type for the selector. 8968c239909SValentin Clement if (select.getSelector().getType() != rewriter.getI32Type()) 8978c239909SValentin Clement selector = 8988c239909SValentin Clement rewriter.create<LLVM::TruncOp>(loc, rewriter.getI32Type(), selector); 8998c239909SValentin Clement 9008c239909SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>( 9018c239909SValentin Clement select, selector, 9028c239909SValentin Clement /*defaultDestination=*/defaultDestination, 9038c239909SValentin Clement /*defaultOperands=*/defaultOperands, 9048c239909SValentin Clement /*caseValues=*/caseValues, 9058c239909SValentin Clement /*caseDestinations=*/destinations, 9068c239909SValentin Clement /*caseOperands=*/destinationsOperands, 9078c239909SValentin Clement /*branchWeights=*/ArrayRef<int32_t>()); 9088c239909SValentin Clement } 9098c239909SValentin Clement 9108c239909SValentin Clement /// conversion of fir::SelectOp to an if-then-else ladder 9118c239909SValentin Clement struct SelectOpConversion : public FIROpConversion<fir::SelectOp> { 9128c239909SValentin Clement using FIROpConversion::FIROpConversion; 9138c239909SValentin Clement 9148c239909SValentin Clement mlir::LogicalResult 9158c239909SValentin Clement matchAndRewrite(fir::SelectOp op, OpAdaptor adaptor, 9168c239909SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 9178c239909SValentin Clement selectMatchAndRewrite<fir::SelectOp>(lowerTy(), op, adaptor, rewriter); 9188c239909SValentin Clement return success(); 9198c239909SValentin Clement } 9208c239909SValentin Clement }; 9218c239909SValentin Clement 922e3349fa1SAndrzej Warzynski /// `fir.load` --> `llvm.load` 923e3349fa1SAndrzej Warzynski struct LoadOpConversion : public FIROpConversion<fir::LoadOp> { 924e3349fa1SAndrzej Warzynski using FIROpConversion::FIROpConversion; 925e3349fa1SAndrzej Warzynski 926e3349fa1SAndrzej Warzynski mlir::LogicalResult 927e3349fa1SAndrzej Warzynski matchAndRewrite(fir::LoadOp load, OpAdaptor adaptor, 928e3349fa1SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 929e3349fa1SAndrzej Warzynski // fir.box is a special case because it is considered as an ssa values in 930e3349fa1SAndrzej Warzynski // fir, but it is lowered as a pointer to a descriptor. So fir.ref<fir.box> 931e3349fa1SAndrzej Warzynski // and fir.box end up being the same llvm types and loading a 932e3349fa1SAndrzej Warzynski // fir.ref<fir.box> is actually a no op in LLVM. 933e3349fa1SAndrzej Warzynski if (load.getType().isa<fir::BoxType>()) { 934e3349fa1SAndrzej Warzynski rewriter.replaceOp(load, adaptor.getOperands()[0]); 935e3349fa1SAndrzej Warzynski } else { 936e3349fa1SAndrzej Warzynski mlir::Type ty = convertType(load.getType()); 937e3349fa1SAndrzej Warzynski ArrayRef<NamedAttribute> at = load->getAttrs(); 938e3349fa1SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::LoadOp>( 939e3349fa1SAndrzej Warzynski load, ty, adaptor.getOperands(), at); 940e3349fa1SAndrzej Warzynski } 941e3349fa1SAndrzej Warzynski return success(); 942e3349fa1SAndrzej Warzynski } 943e3349fa1SAndrzej Warzynski }; 944e3349fa1SAndrzej Warzynski 9452a299e4fSValentin Clement /// Lower `fir.select_type` to LLVM IR dialect. 9462a299e4fSValentin Clement struct SelectTypeOpConversion : public FIROpConversion<fir::SelectTypeOp> { 9472a299e4fSValentin Clement using FIROpConversion::FIROpConversion; 9482a299e4fSValentin Clement 9492a299e4fSValentin Clement mlir::LogicalResult 9502a299e4fSValentin Clement matchAndRewrite(fir::SelectTypeOp select, OpAdaptor adaptor, 9512a299e4fSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 9522a299e4fSValentin Clement return rewriter.notifyMatchFailure( 9532a299e4fSValentin Clement select, "fir.select_type codegen is not implemented yet"); 9542a299e4fSValentin Clement } 9552a299e4fSValentin Clement }; 9562a299e4fSValentin Clement 9578c239909SValentin Clement /// conversion of fir::SelectRankOp to an if-then-else ladder 9588c239909SValentin Clement struct SelectRankOpConversion : public FIROpConversion<fir::SelectRankOp> { 9598c239909SValentin Clement using FIROpConversion::FIROpConversion; 9608c239909SValentin Clement 9618c239909SValentin Clement mlir::LogicalResult 9628c239909SValentin Clement matchAndRewrite(fir::SelectRankOp op, OpAdaptor adaptor, 9638c239909SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 9648c239909SValentin Clement selectMatchAndRewrite<fir::SelectRankOp>(lowerTy(), op, adaptor, rewriter); 9658c239909SValentin Clement return success(); 9668c239909SValentin Clement } 9678c239909SValentin Clement }; 9688c239909SValentin Clement 969e3349fa1SAndrzej Warzynski /// `fir.store` --> `llvm.store` 970e3349fa1SAndrzej Warzynski struct StoreOpConversion : public FIROpConversion<fir::StoreOp> { 971e3349fa1SAndrzej Warzynski using FIROpConversion::FIROpConversion; 972e3349fa1SAndrzej Warzynski 973e3349fa1SAndrzej Warzynski mlir::LogicalResult 974e3349fa1SAndrzej Warzynski matchAndRewrite(fir::StoreOp store, OpAdaptor adaptor, 975e3349fa1SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 976e3349fa1SAndrzej Warzynski if (store.value().getType().isa<fir::BoxType>()) { 977e3349fa1SAndrzej Warzynski // fir.box value is actually in memory, load it first before storing it. 978e3349fa1SAndrzej Warzynski mlir::Location loc = store.getLoc(); 979e3349fa1SAndrzej Warzynski mlir::Type boxPtrTy = adaptor.getOperands()[0].getType(); 980e3349fa1SAndrzej Warzynski auto val = rewriter.create<mlir::LLVM::LoadOp>( 981e3349fa1SAndrzej Warzynski loc, boxPtrTy.cast<mlir::LLVM::LLVMPointerType>().getElementType(), 982e3349fa1SAndrzej Warzynski adaptor.getOperands()[0]); 983e3349fa1SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>( 984e3349fa1SAndrzej Warzynski store, val, adaptor.getOperands()[1]); 985e3349fa1SAndrzej Warzynski } else { 986e3349fa1SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>( 987e3349fa1SAndrzej Warzynski store, adaptor.getOperands()[0], adaptor.getOperands()[1]); 988e3349fa1SAndrzej Warzynski } 989e3349fa1SAndrzej Warzynski return success(); 990e3349fa1SAndrzej Warzynski } 991e3349fa1SAndrzej Warzynski }; 992e3349fa1SAndrzej Warzynski 993e3349fa1SAndrzej Warzynski /// convert to LLVM IR dialect `undef` 994044d5b5dSValentin Clement struct UndefOpConversion : public FIROpConversion<fir::UndefOp> { 995044d5b5dSValentin Clement using FIROpConversion::FIROpConversion; 996044d5b5dSValentin Clement 997044d5b5dSValentin Clement mlir::LogicalResult 998044d5b5dSValentin Clement matchAndRewrite(fir::UndefOp undef, OpAdaptor, 999044d5b5dSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 1000044d5b5dSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::UndefOp>( 1001044d5b5dSValentin Clement undef, convertType(undef.getType())); 1002044d5b5dSValentin Clement return success(); 1003044d5b5dSValentin Clement } 1004044d5b5dSValentin Clement }; 1005a7a61359SValentin Clement 1006e3349fa1SAndrzej Warzynski /// `fir.unreachable` --> `llvm.unreachable` 100732e08248SAndrzej Warzynski struct UnreachableOpConversion : public FIROpConversion<fir::UnreachableOp> { 100832e08248SAndrzej Warzynski using FIROpConversion::FIROpConversion; 100932e08248SAndrzej Warzynski 101032e08248SAndrzej Warzynski mlir::LogicalResult 101132e08248SAndrzej Warzynski matchAndRewrite(fir::UnreachableOp unreach, OpAdaptor adaptor, 101232e08248SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 101332e08248SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(unreach); 101432e08248SAndrzej Warzynski return success(); 101532e08248SAndrzej Warzynski } 101632e08248SAndrzej Warzynski }; 101732e08248SAndrzej Warzynski 1018a7a61359SValentin Clement struct ZeroOpConversion : public FIROpConversion<fir::ZeroOp> { 1019a7a61359SValentin Clement using FIROpConversion::FIROpConversion; 1020a7a61359SValentin Clement 1021a7a61359SValentin Clement mlir::LogicalResult 1022a7a61359SValentin Clement matchAndRewrite(fir::ZeroOp zero, OpAdaptor, 1023a7a61359SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 1024a7a61359SValentin Clement auto ty = convertType(zero.getType()); 1025a7a61359SValentin Clement if (ty.isa<mlir::LLVM::LLVMPointerType>()) { 1026a7a61359SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(zero, ty); 1027a7a61359SValentin Clement } else if (ty.isa<mlir::IntegerType>()) { 1028a7a61359SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>( 1029a7a61359SValentin Clement zero, ty, mlir::IntegerAttr::get(zero.getType(), 0)); 1030a7a61359SValentin Clement } else if (mlir::LLVM::isCompatibleFloatingPointType(ty)) { 1031a7a61359SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>( 1032a7a61359SValentin Clement zero, ty, mlir::FloatAttr::get(zero.getType(), 0.0)); 1033a7a61359SValentin Clement } else { 1034a7a61359SValentin Clement // TODO: create ConstantAggregateZero for FIR aggregate/array types. 103552d813edSValentin Clement return rewriter.notifyMatchFailure( 103652d813edSValentin Clement zero, 1037a7a61359SValentin Clement "conversion of fir.zero with aggregate type not implemented yet"); 1038a7a61359SValentin Clement } 1039a7a61359SValentin Clement return success(); 1040a7a61359SValentin Clement } 1041a7a61359SValentin Clement }; 104232e08248SAndrzej Warzynski 104354c56347SValentin Clement // Code shared between insert_value and extract_value Ops. 104454c56347SValentin Clement struct ValueOpCommon { 104554c56347SValentin Clement // Translate the arguments pertaining to any multidimensional array to 104654c56347SValentin Clement // row-major order for LLVM-IR. 104754c56347SValentin Clement static void toRowMajor(SmallVectorImpl<mlir::Attribute> &attrs, 104854c56347SValentin Clement mlir::Type ty) { 104954c56347SValentin Clement assert(ty && "type is null"); 105054c56347SValentin Clement const auto end = attrs.size(); 105154c56347SValentin Clement for (std::remove_const_t<decltype(end)> i = 0; i < end; ++i) { 105254c56347SValentin Clement if (auto seq = ty.dyn_cast<mlir::LLVM::LLVMArrayType>()) { 105354c56347SValentin Clement const auto dim = getDimension(seq); 105454c56347SValentin Clement if (dim > 1) { 105554c56347SValentin Clement auto ub = std::min(i + dim, end); 105654c56347SValentin Clement std::reverse(attrs.begin() + i, attrs.begin() + ub); 105754c56347SValentin Clement i += dim - 1; 105854c56347SValentin Clement } 105954c56347SValentin Clement ty = getArrayElementType(seq); 106054c56347SValentin Clement } else if (auto st = ty.dyn_cast<mlir::LLVM::LLVMStructType>()) { 106154c56347SValentin Clement ty = st.getBody()[attrs[i].cast<mlir::IntegerAttr>().getInt()]; 106254c56347SValentin Clement } else { 106354c56347SValentin Clement llvm_unreachable("index into invalid type"); 106454c56347SValentin Clement } 106554c56347SValentin Clement } 106654c56347SValentin Clement } 106754c56347SValentin Clement 106854c56347SValentin Clement static llvm::SmallVector<mlir::Attribute> 106954c56347SValentin Clement collectIndices(mlir::ConversionPatternRewriter &rewriter, 107054c56347SValentin Clement mlir::ArrayAttr arrAttr) { 107154c56347SValentin Clement llvm::SmallVector<mlir::Attribute> attrs; 107254c56347SValentin Clement for (auto i = arrAttr.begin(), e = arrAttr.end(); i != e; ++i) { 107354c56347SValentin Clement if (i->isa<mlir::IntegerAttr>()) { 107454c56347SValentin Clement attrs.push_back(*i); 107554c56347SValentin Clement } else { 107654c56347SValentin Clement auto fieldName = i->cast<mlir::StringAttr>().getValue(); 107754c56347SValentin Clement ++i; 107854c56347SValentin Clement auto ty = i->cast<mlir::TypeAttr>().getValue(); 107954c56347SValentin Clement auto index = ty.cast<fir::RecordType>().getFieldIndex(fieldName); 108054c56347SValentin Clement attrs.push_back(mlir::IntegerAttr::get(rewriter.getI32Type(), index)); 108154c56347SValentin Clement } 108254c56347SValentin Clement } 108354c56347SValentin Clement return attrs; 108454c56347SValentin Clement } 108554c56347SValentin Clement 108654c56347SValentin Clement private: 108754c56347SValentin Clement static unsigned getDimension(mlir::LLVM::LLVMArrayType ty) { 108854c56347SValentin Clement unsigned result = 1; 108954c56347SValentin Clement for (auto eleTy = ty.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>(); 109054c56347SValentin Clement eleTy; 109154c56347SValentin Clement eleTy = eleTy.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>()) 109254c56347SValentin Clement ++result; 109354c56347SValentin Clement return result; 109454c56347SValentin Clement } 109554c56347SValentin Clement 109654c56347SValentin Clement static mlir::Type getArrayElementType(mlir::LLVM::LLVMArrayType ty) { 109754c56347SValentin Clement auto eleTy = ty.getElementType(); 109854c56347SValentin Clement while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>()) 109954c56347SValentin Clement eleTy = arrTy.getElementType(); 110054c56347SValentin Clement return eleTy; 110154c56347SValentin Clement } 110254c56347SValentin Clement }; 110354c56347SValentin Clement 110454c56347SValentin Clement /// Extract a subobject value from an ssa-value of aggregate type 110554c56347SValentin Clement struct ExtractValueOpConversion 110654c56347SValentin Clement : public FIROpAndTypeConversion<fir::ExtractValueOp>, 110754c56347SValentin Clement public ValueOpCommon { 110854c56347SValentin Clement using FIROpAndTypeConversion::FIROpAndTypeConversion; 110954c56347SValentin Clement 111054c56347SValentin Clement mlir::LogicalResult 111154c56347SValentin Clement doRewrite(fir::ExtractValueOp extractVal, mlir::Type ty, OpAdaptor adaptor, 111254c56347SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 111354c56347SValentin Clement auto attrs = collectIndices(rewriter, extractVal.coor()); 111454c56347SValentin Clement toRowMajor(attrs, adaptor.getOperands()[0].getType()); 111554c56347SValentin Clement auto position = mlir::ArrayAttr::get(extractVal.getContext(), attrs); 111654c56347SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>( 111754c56347SValentin Clement extractVal, ty, adaptor.getOperands()[0], position); 111854c56347SValentin Clement return success(); 111954c56347SValentin Clement } 112054c56347SValentin Clement }; 112154c56347SValentin Clement 112254c56347SValentin Clement /// InsertValue is the generalized instruction for the composition of new 112354c56347SValentin Clement /// aggregate type values. 112454c56347SValentin Clement struct InsertValueOpConversion 112554c56347SValentin Clement : public FIROpAndTypeConversion<fir::InsertValueOp>, 112654c56347SValentin Clement public ValueOpCommon { 112754c56347SValentin Clement using FIROpAndTypeConversion::FIROpAndTypeConversion; 112854c56347SValentin Clement 112954c56347SValentin Clement mlir::LogicalResult 113054c56347SValentin Clement doRewrite(fir::InsertValueOp insertVal, mlir::Type ty, OpAdaptor adaptor, 113154c56347SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 113254c56347SValentin Clement auto attrs = collectIndices(rewriter, insertVal.coor()); 113354c56347SValentin Clement toRowMajor(attrs, adaptor.getOperands()[0].getType()); 113454c56347SValentin Clement auto position = mlir::ArrayAttr::get(insertVal.getContext(), attrs); 113554c56347SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 113654c56347SValentin Clement insertVal, ty, adaptor.getOperands()[0], adaptor.getOperands()[1], 113754c56347SValentin Clement position); 113854c56347SValentin Clement return success(); 113954c56347SValentin Clement } 114054c56347SValentin Clement }; 114154c56347SValentin Clement 11423ae8e442SValentin Clement /// InsertOnRange inserts a value into a sequence over a range of offsets. 11433ae8e442SValentin Clement struct InsertOnRangeOpConversion 11443ae8e442SValentin Clement : public FIROpAndTypeConversion<fir::InsertOnRangeOp> { 11453ae8e442SValentin Clement using FIROpAndTypeConversion::FIROpAndTypeConversion; 11463ae8e442SValentin Clement 11473ae8e442SValentin Clement // Increments an array of subscripts in a row major fasion. 11483ae8e442SValentin Clement void incrementSubscripts(const SmallVector<uint64_t> &dims, 11493ae8e442SValentin Clement SmallVector<uint64_t> &subscripts) const { 11503ae8e442SValentin Clement for (size_t i = dims.size(); i > 0; --i) { 11513ae8e442SValentin Clement if (++subscripts[i - 1] < dims[i - 1]) { 11523ae8e442SValentin Clement return; 11533ae8e442SValentin Clement } 11543ae8e442SValentin Clement subscripts[i - 1] = 0; 11553ae8e442SValentin Clement } 11563ae8e442SValentin Clement } 11573ae8e442SValentin Clement 11583ae8e442SValentin Clement mlir::LogicalResult 11593ae8e442SValentin Clement doRewrite(fir::InsertOnRangeOp range, mlir::Type ty, OpAdaptor adaptor, 11603ae8e442SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 11613ae8e442SValentin Clement 11623ae8e442SValentin Clement llvm::SmallVector<uint64_t> dims; 11633ae8e442SValentin Clement auto type = adaptor.getOperands()[0].getType(); 11643ae8e442SValentin Clement 11653ae8e442SValentin Clement // Iteratively extract the array dimensions from the type. 11663ae8e442SValentin Clement while (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) { 11673ae8e442SValentin Clement dims.push_back(t.getNumElements()); 11683ae8e442SValentin Clement type = t.getElementType(); 11693ae8e442SValentin Clement } 11703ae8e442SValentin Clement 11713ae8e442SValentin Clement SmallVector<uint64_t> lBounds; 11723ae8e442SValentin Clement SmallVector<uint64_t> uBounds; 11733ae8e442SValentin Clement 11743ae8e442SValentin Clement // Extract integer value from the attribute 11753ae8e442SValentin Clement SmallVector<int64_t> coordinates = llvm::to_vector<4>( 11763ae8e442SValentin Clement llvm::map_range(range.coor(), [](Attribute a) -> int64_t { 11773ae8e442SValentin Clement return a.cast<IntegerAttr>().getInt(); 11783ae8e442SValentin Clement })); 11793ae8e442SValentin Clement 11803ae8e442SValentin Clement // Unzip the upper and lower bound and convert to a row major format. 11813ae8e442SValentin Clement for (auto i = coordinates.rbegin(), e = coordinates.rend(); i != e; ++i) { 11823ae8e442SValentin Clement uBounds.push_back(*i++); 11833ae8e442SValentin Clement lBounds.push_back(*i); 11843ae8e442SValentin Clement } 11853ae8e442SValentin Clement 11863ae8e442SValentin Clement auto &subscripts = lBounds; 11873ae8e442SValentin Clement auto loc = range.getLoc(); 11883ae8e442SValentin Clement mlir::Value lastOp = adaptor.getOperands()[0]; 11893ae8e442SValentin Clement mlir::Value insertVal = adaptor.getOperands()[1]; 11903ae8e442SValentin Clement 11913ae8e442SValentin Clement auto i64Ty = rewriter.getI64Type(); 11923ae8e442SValentin Clement while (subscripts != uBounds) { 11933ae8e442SValentin Clement // Convert uint64_t's to Attribute's. 11943ae8e442SValentin Clement SmallVector<mlir::Attribute> subscriptAttrs; 11953ae8e442SValentin Clement for (const auto &subscript : subscripts) 11963ae8e442SValentin Clement subscriptAttrs.push_back(IntegerAttr::get(i64Ty, subscript)); 11973ae8e442SValentin Clement lastOp = rewriter.create<mlir::LLVM::InsertValueOp>( 11983ae8e442SValentin Clement loc, ty, lastOp, insertVal, 11993ae8e442SValentin Clement ArrayAttr::get(range.getContext(), subscriptAttrs)); 12003ae8e442SValentin Clement 12013ae8e442SValentin Clement incrementSubscripts(dims, subscripts); 12023ae8e442SValentin Clement } 12033ae8e442SValentin Clement 12043ae8e442SValentin Clement // Convert uint64_t's to Attribute's. 12053ae8e442SValentin Clement SmallVector<mlir::Attribute> subscriptAttrs; 12063ae8e442SValentin Clement for (const auto &subscript : subscripts) 12073ae8e442SValentin Clement subscriptAttrs.push_back( 12083ae8e442SValentin Clement IntegerAttr::get(rewriter.getI64Type(), subscript)); 12093ae8e442SValentin Clement mlir::ArrayRef<mlir::Attribute> arrayRef(subscriptAttrs); 12103ae8e442SValentin Clement 12113ae8e442SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 12123ae8e442SValentin Clement range, ty, lastOp, insertVal, 12133ae8e442SValentin Clement ArrayAttr::get(range.getContext(), arrayRef)); 12143ae8e442SValentin Clement 12153ae8e442SValentin Clement return success(); 12163ae8e442SValentin Clement } 12173ae8e442SValentin Clement }; 12187b5132daSValentin Clement 12197b5132daSValentin Clement // 12207b5132daSValentin Clement // Primitive operations on Complex types 12217b5132daSValentin Clement // 12227b5132daSValentin Clement 12237b5132daSValentin Clement /// Generate inline code for complex addition/subtraction 12247b5132daSValentin Clement template <typename LLVMOP, typename OPTY> 12257b5132daSValentin Clement mlir::LLVM::InsertValueOp complexSum(OPTY sumop, mlir::ValueRange opnds, 12267b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter, 12277b5132daSValentin Clement fir::LLVMTypeConverter &lowering) { 12287b5132daSValentin Clement mlir::Value a = opnds[0]; 12297b5132daSValentin Clement mlir::Value b = opnds[1]; 12307b5132daSValentin Clement auto loc = sumop.getLoc(); 12317b5132daSValentin Clement auto ctx = sumop.getContext(); 12327b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 12337b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 12347b5132daSValentin Clement mlir::Type eleTy = lowering.convertType(getComplexEleTy(sumop.getType())); 12357b5132daSValentin Clement mlir::Type ty = lowering.convertType(sumop.getType()); 12367b5132daSValentin Clement auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0); 12377b5132daSValentin Clement auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1); 12387b5132daSValentin Clement auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0); 12397b5132daSValentin Clement auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1); 12407b5132daSValentin Clement auto rx = rewriter.create<LLVMOP>(loc, eleTy, x0, x1); 12417b5132daSValentin Clement auto ry = rewriter.create<LLVMOP>(loc, eleTy, y0, y1); 12427b5132daSValentin Clement auto r0 = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 12437b5132daSValentin Clement auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r0, rx, c0); 12447b5132daSValentin Clement return rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ry, c1); 12457b5132daSValentin Clement } 12467b5132daSValentin Clement 12477b5132daSValentin Clement struct AddcOpConversion : public FIROpConversion<fir::AddcOp> { 12487b5132daSValentin Clement using FIROpConversion::FIROpConversion; 12497b5132daSValentin Clement 12507b5132daSValentin Clement mlir::LogicalResult 12517b5132daSValentin Clement matchAndRewrite(fir::AddcOp addc, OpAdaptor adaptor, 12527b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 12537b5132daSValentin Clement // given: (x + iy) + (x' + iy') 12547b5132daSValentin Clement // result: (x + x') + i(y + y') 12557b5132daSValentin Clement auto r = complexSum<mlir::LLVM::FAddOp>(addc, adaptor.getOperands(), 12567b5132daSValentin Clement rewriter, lowerTy()); 12577b5132daSValentin Clement rewriter.replaceOp(addc, r.getResult()); 12587b5132daSValentin Clement return success(); 12597b5132daSValentin Clement } 12607b5132daSValentin Clement }; 12617b5132daSValentin Clement 12627b5132daSValentin Clement struct SubcOpConversion : public FIROpConversion<fir::SubcOp> { 12637b5132daSValentin Clement using FIROpConversion::FIROpConversion; 12647b5132daSValentin Clement 12657b5132daSValentin Clement mlir::LogicalResult 12667b5132daSValentin Clement matchAndRewrite(fir::SubcOp subc, OpAdaptor adaptor, 12677b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 12687b5132daSValentin Clement // given: (x + iy) - (x' + iy') 12697b5132daSValentin Clement // result: (x - x') + i(y - y') 12707b5132daSValentin Clement auto r = complexSum<mlir::LLVM::FSubOp>(subc, adaptor.getOperands(), 12717b5132daSValentin Clement rewriter, lowerTy()); 12727b5132daSValentin Clement rewriter.replaceOp(subc, r.getResult()); 12737b5132daSValentin Clement return success(); 12747b5132daSValentin Clement } 12757b5132daSValentin Clement }; 12767b5132daSValentin Clement 12777b5132daSValentin Clement /// Inlined complex multiply 12787b5132daSValentin Clement struct MulcOpConversion : public FIROpConversion<fir::MulcOp> { 12797b5132daSValentin Clement using FIROpConversion::FIROpConversion; 12807b5132daSValentin Clement 12817b5132daSValentin Clement mlir::LogicalResult 12827b5132daSValentin Clement matchAndRewrite(fir::MulcOp mulc, OpAdaptor adaptor, 12837b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 12847b5132daSValentin Clement // TODO: Can we use a call to __muldc3 ? 12857b5132daSValentin Clement // given: (x + iy) * (x' + iy') 12867b5132daSValentin Clement // result: (xx'-yy')+i(xy'+yx') 12877b5132daSValentin Clement mlir::Value a = adaptor.getOperands()[0]; 12887b5132daSValentin Clement mlir::Value b = adaptor.getOperands()[1]; 12897b5132daSValentin Clement auto loc = mulc.getLoc(); 12907b5132daSValentin Clement auto *ctx = mulc.getContext(); 12917b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 12927b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 12937b5132daSValentin Clement mlir::Type eleTy = convertType(getComplexEleTy(mulc.getType())); 12947b5132daSValentin Clement mlir::Type ty = convertType(mulc.getType()); 12957b5132daSValentin Clement auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0); 12967b5132daSValentin Clement auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1); 12977b5132daSValentin Clement auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0); 12987b5132daSValentin Clement auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1); 12997b5132daSValentin Clement auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1); 13007b5132daSValentin Clement auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1); 13017b5132daSValentin Clement auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1); 13027b5132daSValentin Clement auto ri = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xy, yx); 13037b5132daSValentin Clement auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1); 13047b5132daSValentin Clement auto rr = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, xx, yy); 13057b5132daSValentin Clement auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 13067b5132daSValentin Clement auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0); 13077b5132daSValentin Clement auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1); 13087b5132daSValentin Clement rewriter.replaceOp(mulc, r0.getResult()); 13097b5132daSValentin Clement return success(); 13107b5132daSValentin Clement } 13117b5132daSValentin Clement }; 13127b5132daSValentin Clement 13137b5132daSValentin Clement /// Inlined complex division 13147b5132daSValentin Clement struct DivcOpConversion : public FIROpConversion<fir::DivcOp> { 13157b5132daSValentin Clement using FIROpConversion::FIROpConversion; 13167b5132daSValentin Clement 13177b5132daSValentin Clement mlir::LogicalResult 13187b5132daSValentin Clement matchAndRewrite(fir::DivcOp divc, OpAdaptor adaptor, 13197b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 13207b5132daSValentin Clement // TODO: Can we use a call to __divdc3 instead? 13217b5132daSValentin Clement // Just generate inline code for now. 13227b5132daSValentin Clement // given: (x + iy) / (x' + iy') 13237b5132daSValentin Clement // result: ((xx'+yy')/d) + i((yx'-xy')/d) where d = x'x' + y'y' 13247b5132daSValentin Clement mlir::Value a = adaptor.getOperands()[0]; 13257b5132daSValentin Clement mlir::Value b = adaptor.getOperands()[1]; 13267b5132daSValentin Clement auto loc = divc.getLoc(); 13277b5132daSValentin Clement auto *ctx = divc.getContext(); 13287b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 13297b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 13307b5132daSValentin Clement mlir::Type eleTy = convertType(getComplexEleTy(divc.getType())); 13317b5132daSValentin Clement mlir::Type ty = convertType(divc.getType()); 13327b5132daSValentin Clement auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0); 13337b5132daSValentin Clement auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1); 13347b5132daSValentin Clement auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0); 13357b5132daSValentin Clement auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1); 13367b5132daSValentin Clement auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1); 13377b5132daSValentin Clement auto x1x1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x1, x1); 13387b5132daSValentin Clement auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1); 13397b5132daSValentin Clement auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1); 13407b5132daSValentin Clement auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1); 13417b5132daSValentin Clement auto y1y1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y1, y1); 13427b5132daSValentin Clement auto d = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, x1x1, y1y1); 13437b5132daSValentin Clement auto rrn = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xx, yy); 13447b5132daSValentin Clement auto rin = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, yx, xy); 13457b5132daSValentin Clement auto rr = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rrn, d); 13467b5132daSValentin Clement auto ri = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rin, d); 13477b5132daSValentin Clement auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 13487b5132daSValentin Clement auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0); 13497b5132daSValentin Clement auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1); 13507b5132daSValentin Clement rewriter.replaceOp(divc, r0.getResult()); 13517b5132daSValentin Clement return success(); 13527b5132daSValentin Clement } 13537b5132daSValentin Clement }; 13547b5132daSValentin Clement 13557b5132daSValentin Clement /// Inlined complex negation 13567b5132daSValentin Clement struct NegcOpConversion : public FIROpConversion<fir::NegcOp> { 13577b5132daSValentin Clement using FIROpConversion::FIROpConversion; 13587b5132daSValentin Clement 13597b5132daSValentin Clement mlir::LogicalResult 13607b5132daSValentin Clement matchAndRewrite(fir::NegcOp neg, OpAdaptor adaptor, 13617b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 13627b5132daSValentin Clement // given: -(x + iy) 13637b5132daSValentin Clement // result: -x - iy 13647b5132daSValentin Clement auto *ctxt = neg.getContext(); 13657b5132daSValentin Clement auto eleTy = convertType(getComplexEleTy(neg.getType())); 13667b5132daSValentin Clement auto ty = convertType(neg.getType()); 13677b5132daSValentin Clement auto loc = neg.getLoc(); 13687b5132daSValentin Clement mlir::Value o0 = adaptor.getOperands()[0]; 13697b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0)); 13707b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1)); 13717b5132daSValentin Clement auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c0); 13727b5132daSValentin Clement auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c1); 13737b5132daSValentin Clement auto nrp = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, rp); 13747b5132daSValentin Clement auto nip = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, ip); 13757b5132daSValentin Clement auto r = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, o0, nrp, c0); 13767b5132daSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(neg, ty, r, nip, c1); 13777b5132daSValentin Clement return success(); 13787b5132daSValentin Clement } 13797b5132daSValentin Clement }; 13807b5132daSValentin Clement 1381420ad7ceSAndrzej Warzynski /// `fir.is_present` --> 1382420ad7ceSAndrzej Warzynski /// ``` 1383420ad7ceSAndrzej Warzynski /// %0 = llvm.mlir.constant(0 : i64) 1384420ad7ceSAndrzej Warzynski /// %1 = llvm.ptrtoint %0 1385420ad7ceSAndrzej Warzynski /// %2 = llvm.icmp "ne" %1, %0 : i64 1386420ad7ceSAndrzej Warzynski /// ``` 1387420ad7ceSAndrzej Warzynski struct IsPresentOpConversion : public FIROpConversion<fir::IsPresentOp> { 1388420ad7ceSAndrzej Warzynski using FIROpConversion::FIROpConversion; 1389420ad7ceSAndrzej Warzynski 1390420ad7ceSAndrzej Warzynski mlir::LogicalResult 1391420ad7ceSAndrzej Warzynski matchAndRewrite(fir::IsPresentOp isPresent, OpAdaptor adaptor, 1392420ad7ceSAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 1393420ad7ceSAndrzej Warzynski mlir::Type idxTy = lowerTy().indexType(); 1394420ad7ceSAndrzej Warzynski mlir::Location loc = isPresent.getLoc(); 1395420ad7ceSAndrzej Warzynski auto ptr = adaptor.getOperands()[0]; 1396420ad7ceSAndrzej Warzynski 1397420ad7ceSAndrzej Warzynski if (isPresent.val().getType().isa<fir::BoxCharType>()) { 1398420ad7ceSAndrzej Warzynski auto structTy = ptr.getType().cast<mlir::LLVM::LLVMStructType>(); 1399420ad7ceSAndrzej Warzynski assert(!structTy.isOpaque() && !structTy.getBody().empty()); 1400420ad7ceSAndrzej Warzynski 1401420ad7ceSAndrzej Warzynski mlir::Type ty = structTy.getBody()[0]; 1402420ad7ceSAndrzej Warzynski mlir::MLIRContext *ctx = isPresent.getContext(); 1403420ad7ceSAndrzej Warzynski auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 1404420ad7ceSAndrzej Warzynski ptr = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, ptr, c0); 1405420ad7ceSAndrzej Warzynski } 1406420ad7ceSAndrzej Warzynski mlir::LLVM::ConstantOp c0 = 1407420ad7ceSAndrzej Warzynski genConstantIndex(isPresent.getLoc(), idxTy, rewriter, 0); 1408420ad7ceSAndrzej Warzynski auto addr = rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, ptr); 1409420ad7ceSAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>( 1410420ad7ceSAndrzej Warzynski isPresent, mlir::LLVM::ICmpPredicate::ne, addr, c0); 1411420ad7ceSAndrzej Warzynski 1412420ad7ceSAndrzej Warzynski return success(); 1413420ad7ceSAndrzej Warzynski } 1414420ad7ceSAndrzej Warzynski }; 14151e77b095SAndrzej Warzynski 14161e77b095SAndrzej Warzynski /// Convert `!fir.emboxchar<!fir.char<KIND, ?>, #n>` into a sequence of 14171e77b095SAndrzej Warzynski /// instructions that generate `!llvm.struct<(ptr<ik>, i64)>`. The 1st element 14181e77b095SAndrzej Warzynski /// in this struct is a pointer. Its type is determined from `KIND`. The 2nd 14191e77b095SAndrzej Warzynski /// element is the length of the character buffer (`#n`). 14201e77b095SAndrzej Warzynski struct EmboxCharOpConversion : public FIROpConversion<fir::EmboxCharOp> { 14211e77b095SAndrzej Warzynski using FIROpConversion::FIROpConversion; 14221e77b095SAndrzej Warzynski 14231e77b095SAndrzej Warzynski mlir::LogicalResult 14241e77b095SAndrzej Warzynski matchAndRewrite(fir::EmboxCharOp emboxChar, OpAdaptor adaptor, 14251e77b095SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 14261e77b095SAndrzej Warzynski mlir::ValueRange operands = adaptor.getOperands(); 14271e77b095SAndrzej Warzynski MLIRContext *ctx = emboxChar.getContext(); 14281e77b095SAndrzej Warzynski 14291e77b095SAndrzej Warzynski mlir::Value charBuffer = operands[0]; 14301e77b095SAndrzej Warzynski mlir::Value charBufferLen = operands[1]; 14311e77b095SAndrzej Warzynski 14321e77b095SAndrzej Warzynski mlir::Location loc = emboxChar.getLoc(); 14331e77b095SAndrzej Warzynski mlir::Type llvmStructTy = convertType(emboxChar.getType()); 14341e77b095SAndrzej Warzynski auto llvmStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, llvmStructTy); 14351e77b095SAndrzej Warzynski 14361e77b095SAndrzej Warzynski mlir::Type lenTy = 14371e77b095SAndrzej Warzynski llvmStructTy.cast<mlir::LLVM::LLVMStructType>().getBody()[1]; 14381e77b095SAndrzej Warzynski mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, charBufferLen); 14391e77b095SAndrzej Warzynski 14401e77b095SAndrzej Warzynski auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 14411e77b095SAndrzej Warzynski auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 14421e77b095SAndrzej Warzynski auto insertBufferOp = rewriter.create<mlir::LLVM::InsertValueOp>( 14431e77b095SAndrzej Warzynski loc, llvmStructTy, llvmStruct, charBuffer, c0); 14441e77b095SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 14451e77b095SAndrzej Warzynski emboxChar, llvmStructTy, insertBufferOp, lenAfterCast, c1); 14461e77b095SAndrzej Warzynski 14471e77b095SAndrzej Warzynski return success(); 14481e77b095SAndrzej Warzynski } 14491e77b095SAndrzej Warzynski }; 145014867ffcSAndrzej Warzynski 145114867ffcSAndrzej Warzynski /// Construct an `llvm.extractvalue` instruction. It will return value at 145214867ffcSAndrzej Warzynski /// element \p x from \p tuple. 145314867ffcSAndrzej Warzynski mlir::LLVM::ExtractValueOp 145414867ffcSAndrzej Warzynski genExtractValueWithIndex(mlir::Location loc, mlir::Value tuple, mlir::Type ty, 145514867ffcSAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter, 145614867ffcSAndrzej Warzynski mlir::MLIRContext *ctx, int x) { 145714867ffcSAndrzej Warzynski auto cx = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(x)); 145814867ffcSAndrzej Warzynski auto xty = ty.cast<mlir::LLVM::LLVMStructType>().getBody()[x]; 145914867ffcSAndrzej Warzynski return rewriter.create<mlir::LLVM::ExtractValueOp>(loc, xty, tuple, cx); 146014867ffcSAndrzej Warzynski } 146114867ffcSAndrzej Warzynski 146214867ffcSAndrzej Warzynski /// Convert `fir.unboxchar` into two `llvm.extractvalue` instructions. One for 146314867ffcSAndrzej Warzynski /// the character buffer and one for the buffer length. 146414867ffcSAndrzej Warzynski struct UnboxCharOpConversion : public FIROpConversion<fir::UnboxCharOp> { 146514867ffcSAndrzej Warzynski using FIROpConversion::FIROpConversion; 146614867ffcSAndrzej Warzynski 146714867ffcSAndrzej Warzynski mlir::LogicalResult 146814867ffcSAndrzej Warzynski matchAndRewrite(fir::UnboxCharOp unboxchar, OpAdaptor adaptor, 146914867ffcSAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 147014867ffcSAndrzej Warzynski MLIRContext *ctx = unboxchar.getContext(); 147114867ffcSAndrzej Warzynski 147214867ffcSAndrzej Warzynski mlir::Type lenTy = convertType(unboxchar.getType(1)); 147314867ffcSAndrzej Warzynski mlir::Value tuple = adaptor.getOperands()[0]; 147414867ffcSAndrzej Warzynski mlir::Type tupleTy = tuple.getType(); 147514867ffcSAndrzej Warzynski 147614867ffcSAndrzej Warzynski mlir::Location loc = unboxchar.getLoc(); 147714867ffcSAndrzej Warzynski mlir::Value ptrToBuffer = 147814867ffcSAndrzej Warzynski genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 0); 147914867ffcSAndrzej Warzynski 148014867ffcSAndrzej Warzynski mlir::LLVM::ExtractValueOp len = 148114867ffcSAndrzej Warzynski genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 1); 148214867ffcSAndrzej Warzynski mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, len); 148314867ffcSAndrzej Warzynski 148414867ffcSAndrzej Warzynski rewriter.replaceOp(unboxchar, 148514867ffcSAndrzej Warzynski ArrayRef<mlir::Value>{ptrToBuffer, lenAfterCast}); 148614867ffcSAndrzej Warzynski return success(); 148714867ffcSAndrzej Warzynski } 148814867ffcSAndrzej Warzynski }; 148914867ffcSAndrzej Warzynski 1490044d5b5dSValentin Clement } // namespace 1491044d5b5dSValentin Clement 1492044d5b5dSValentin Clement namespace { 1493044d5b5dSValentin Clement /// Convert FIR dialect to LLVM dialect 1494044d5b5dSValentin Clement /// 1495044d5b5dSValentin Clement /// This pass lowers all FIR dialect operations to LLVM IR dialect. An 1496044d5b5dSValentin Clement /// MLIR pass is used to lower residual Std dialect to LLVM IR dialect. 1497044d5b5dSValentin Clement /// 1498044d5b5dSValentin Clement /// This pass is not complete yet. We are upstreaming it in small patches. 1499044d5b5dSValentin Clement class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> { 1500044d5b5dSValentin Clement public: 1501044d5b5dSValentin Clement mlir::ModuleOp getModule() { return getOperation(); } 1502044d5b5dSValentin Clement 1503044d5b5dSValentin Clement void runOnOperation() override final { 15047b5132daSValentin Clement auto mod = getModule(); 15057b5132daSValentin Clement if (!forcedTargetTriple.empty()) { 15067b5132daSValentin Clement fir::setTargetTriple(mod, forcedTargetTriple); 15077b5132daSValentin Clement } 15087b5132daSValentin Clement 1509044d5b5dSValentin Clement auto *context = getModule().getContext(); 1510044d5b5dSValentin Clement fir::LLVMTypeConverter typeConverter{getModule()}; 1511044d5b5dSValentin Clement mlir::OwningRewritePatternList pattern(context); 1512df3b9810SValentin Clement pattern.insert< 1513420ad7ceSAndrzej Warzynski AbsentOpConversion, AddcOpConversion, AddrOfOpConversion, 1514420ad7ceSAndrzej Warzynski AllocaOpConversion, BoxAddrOpConversion, BoxDimsOpConversion, 1515420ad7ceSAndrzej Warzynski BoxEleSizeOpConversion, BoxIsAllocOpConversion, BoxIsArrayOpConversion, 1516420ad7ceSAndrzej Warzynski BoxIsPtrOpConversion, BoxRankOpConversion, CallOpConversion, 1517420ad7ceSAndrzej Warzynski ConvertOpConversion, DispatchOpConversion, DispatchTableOpConversion, 15181e77b095SAndrzej Warzynski DTEntryOpConversion, DivcOpConversion, EmboxCharOpConversion, 1519*677df8c7SValentin Clement ExtractValueOpConversion, HasValueOpConversion, GlobalLenOpConversion, 1520*677df8c7SValentin Clement GlobalOpConversion, InsertOnRangeOpConversion, InsertValueOpConversion, 15211e77b095SAndrzej Warzynski IsPresentOpConversion, LoadOpConversion, NegcOpConversion, 15221e77b095SAndrzej Warzynski MulcOpConversion, SelectCaseOpConversion, SelectOpConversion, 15232a299e4fSValentin Clement SelectRankOpConversion, SelectTypeOpConversion, StoreOpConversion, 152414867ffcSAndrzej Warzynski SubcOpConversion, UnboxCharOpConversion, UndefOpConversion, 152514867ffcSAndrzej Warzynski UnreachableOpConversion, ZeroOpConversion>(typeConverter); 1526044d5b5dSValentin Clement mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern); 1527044d5b5dSValentin Clement mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter, 1528044d5b5dSValentin Clement pattern); 1529044d5b5dSValentin Clement mlir::ConversionTarget target{*context}; 1530044d5b5dSValentin Clement target.addLegalDialect<mlir::LLVM::LLVMDialect>(); 1531044d5b5dSValentin Clement 1532044d5b5dSValentin Clement // required NOPs for applying a full conversion 1533044d5b5dSValentin Clement target.addLegalOp<mlir::ModuleOp>(); 1534044d5b5dSValentin Clement 1535044d5b5dSValentin Clement // apply the patterns 1536044d5b5dSValentin Clement if (mlir::failed(mlir::applyFullConversion(getModule(), target, 1537044d5b5dSValentin Clement std::move(pattern)))) { 1538044d5b5dSValentin Clement signalPassFailure(); 1539044d5b5dSValentin Clement } 1540044d5b5dSValentin Clement } 1541044d5b5dSValentin Clement }; 1542044d5b5dSValentin Clement } // namespace 1543044d5b5dSValentin Clement 1544044d5b5dSValentin Clement std::unique_ptr<mlir::Pass> fir::createFIRToLLVMPass() { 1545044d5b5dSValentin Clement return std::make_unique<FIRToLLVMLowering>(); 1546044d5b5dSValentin Clement } 1547