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" 16044d5b5dSValentin Clement #include "flang/Optimizer/Dialect/FIROps.h" 17044d5b5dSValentin Clement #include "mlir/Conversion/ArithmeticToLLVM/ArithmeticToLLVM.h" 18044d5b5dSValentin Clement #include "mlir/Conversion/LLVMCommon/Pattern.h" 19044d5b5dSValentin Clement #include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h" 20044d5b5dSValentin Clement #include "mlir/IR/BuiltinTypes.h" 213ae8e442SValentin Clement #include "mlir/IR/Matchers.h" 22044d5b5dSValentin Clement #include "mlir/Pass/Pass.h" 23044d5b5dSValentin Clement #include "llvm/ADT/ArrayRef.h" 24044d5b5dSValentin Clement 25044d5b5dSValentin Clement #define DEBUG_TYPE "flang-codegen" 26044d5b5dSValentin Clement 27044d5b5dSValentin Clement // fir::LLVMTypeConverter for converting to LLVM IR dialect types. 28044d5b5dSValentin Clement #include "TypeConverter.h" 29044d5b5dSValentin Clement 30b6e44ecdSValentin Clement /// `fir.box` attribute values as defined for CFI_attribute_t in 31b6e44ecdSValentin Clement /// flang/ISO_Fortran_binding.h. 32b6e44ecdSValentin Clement static constexpr unsigned kAttrPointer = CFI_attribute_pointer; 33b6e44ecdSValentin Clement static constexpr unsigned kAttrAllocatable = CFI_attribute_allocatable; 34b6e44ecdSValentin Clement 351e6d9c06SDiana Picus static mlir::LLVM::ConstantOp 361e6d9c06SDiana Picus genConstantIndex(mlir::Location loc, mlir::Type ity, 371e6d9c06SDiana Picus mlir::ConversionPatternRewriter &rewriter, 381e6d9c06SDiana Picus std::int64_t offset) { 391e6d9c06SDiana Picus auto cattr = rewriter.getI64IntegerAttr(offset); 401e6d9c06SDiana Picus return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr); 411e6d9c06SDiana Picus } 421e6d9c06SDiana Picus 43044d5b5dSValentin Clement namespace { 44044d5b5dSValentin Clement /// FIR conversion pattern template 45044d5b5dSValentin Clement template <typename FromOp> 46044d5b5dSValentin Clement class FIROpConversion : public mlir::ConvertOpToLLVMPattern<FromOp> { 47044d5b5dSValentin Clement public: 48044d5b5dSValentin Clement explicit FIROpConversion(fir::LLVMTypeConverter &lowering) 49044d5b5dSValentin Clement : mlir::ConvertOpToLLVMPattern<FromOp>(lowering) {} 50044d5b5dSValentin Clement 51044d5b5dSValentin Clement protected: 52044d5b5dSValentin Clement mlir::Type convertType(mlir::Type ty) const { 53044d5b5dSValentin Clement return lowerTy().convertType(ty); 54044d5b5dSValentin Clement } 55044d5b5dSValentin Clement 56df3b9810SValentin Clement mlir::LLVM::ConstantOp 57df3b9810SValentin Clement genConstantOffset(mlir::Location loc, 58df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter, 59df3b9810SValentin Clement int offset) const { 60df3b9810SValentin Clement auto ity = lowerTy().offsetType(); 61df3b9810SValentin Clement auto cattr = rewriter.getI32IntegerAttr(offset); 62df3b9810SValentin Clement return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr); 63df3b9810SValentin Clement } 64df3b9810SValentin Clement 65b6e44ecdSValentin Clement /// Construct code sequence to extract the specifc value from a `fir.box`. 66b6e44ecdSValentin Clement mlir::Value getValueFromBox(mlir::Location loc, mlir::Value box, 67df3b9810SValentin Clement mlir::Type resultTy, 68b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter, 69b6e44ecdSValentin Clement unsigned boxValue) const { 70df3b9810SValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 71b6e44ecdSValentin Clement mlir::LLVM::ConstantOp cValuePos = 72b6e44ecdSValentin Clement genConstantOffset(loc, rewriter, boxValue); 73df3b9810SValentin Clement auto pty = mlir::LLVM::LLVMPointerType::get(resultTy); 74df3b9810SValentin Clement auto p = rewriter.create<mlir::LLVM::GEPOp>( 75b6e44ecdSValentin Clement loc, pty, mlir::ValueRange{box, c0, cValuePos}); 76df3b9810SValentin Clement return rewriter.create<mlir::LLVM::LoadOp>(loc, resultTy, p); 77df3b9810SValentin Clement } 78df3b9810SValentin Clement 79df3b9810SValentin Clement /// Method to construct code sequence to get the triple for dimension `dim` 80df3b9810SValentin Clement /// from a box. 81df3b9810SValentin Clement SmallVector<mlir::Value, 3> 82df3b9810SValentin Clement getDimsFromBox(mlir::Location loc, ArrayRef<mlir::Type> retTys, 83df3b9810SValentin Clement mlir::Value box, mlir::Value dim, 84df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 85df3b9810SValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 86df3b9810SValentin Clement mlir::LLVM::ConstantOp cDims = 87df3b9810SValentin Clement genConstantOffset(loc, rewriter, kDimsPosInBox); 88df3b9810SValentin Clement mlir::LLVM::LoadOp l0 = 89df3b9810SValentin Clement loadFromOffset(loc, box, c0, cDims, dim, 0, retTys[0], rewriter); 90df3b9810SValentin Clement mlir::LLVM::LoadOp l1 = 91df3b9810SValentin Clement loadFromOffset(loc, box, c0, cDims, dim, 1, retTys[1], rewriter); 92df3b9810SValentin Clement mlir::LLVM::LoadOp l2 = 93df3b9810SValentin Clement loadFromOffset(loc, box, c0, cDims, dim, 2, retTys[2], rewriter); 94df3b9810SValentin Clement return {l0.getResult(), l1.getResult(), l2.getResult()}; 95df3b9810SValentin Clement } 96df3b9810SValentin Clement 97df3b9810SValentin Clement mlir::LLVM::LoadOp 98df3b9810SValentin Clement loadFromOffset(mlir::Location loc, mlir::Value a, mlir::LLVM::ConstantOp c0, 99df3b9810SValentin Clement mlir::LLVM::ConstantOp cDims, mlir::Value dim, int off, 100df3b9810SValentin Clement mlir::Type ty, 101df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 102df3b9810SValentin Clement auto pty = mlir::LLVM::LLVMPointerType::get(ty); 103df3b9810SValentin Clement mlir::LLVM::ConstantOp c = genConstantOffset(loc, rewriter, off); 104df3b9810SValentin Clement mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, a, c0, cDims, dim, c); 105df3b9810SValentin Clement return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p); 106df3b9810SValentin Clement } 107df3b9810SValentin Clement 108df3b9810SValentin Clement /// Read base address from a fir.box. Returned address has type ty. 109df3b9810SValentin Clement mlir::Value 110df3b9810SValentin Clement loadBaseAddrFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box, 111df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 112df3b9810SValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 113df3b9810SValentin Clement mlir::LLVM::ConstantOp cAddr = 114df3b9810SValentin Clement genConstantOffset(loc, rewriter, kAddrPosInBox); 115df3b9810SValentin Clement auto pty = mlir::LLVM::LLVMPointerType::get(ty); 116df3b9810SValentin Clement mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cAddr); 117df3b9810SValentin Clement return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p); 118df3b9810SValentin Clement } 119df3b9810SValentin Clement 120df3b9810SValentin Clement mlir::Value 121df3b9810SValentin Clement loadElementSizeFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box, 122df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 123df3b9810SValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 124df3b9810SValentin Clement mlir::LLVM::ConstantOp cElemLen = 125df3b9810SValentin Clement genConstantOffset(loc, rewriter, kElemLenPosInBox); 126df3b9810SValentin Clement auto pty = mlir::LLVM::LLVMPointerType::get(ty); 127df3b9810SValentin Clement mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cElemLen); 128df3b9810SValentin Clement return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p); 129df3b9810SValentin Clement } 130df3b9810SValentin Clement 131b6e44ecdSValentin Clement // Load the attribute from the \p box and perform a check against \p maskValue 132b6e44ecdSValentin Clement // The final comparison is implemented as `(attribute & maskValue) != 0`. 133b6e44ecdSValentin Clement mlir::Value genBoxAttributeCheck(mlir::Location loc, mlir::Value box, 134b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter, 135b6e44ecdSValentin Clement unsigned maskValue) const { 136b6e44ecdSValentin Clement mlir::Type attrTy = rewriter.getI32Type(); 137b6e44ecdSValentin Clement mlir::Value attribute = 138b6e44ecdSValentin Clement getValueFromBox(loc, box, attrTy, rewriter, kAttributePosInBox); 139b6e44ecdSValentin Clement mlir::LLVM::ConstantOp attrMask = 140b6e44ecdSValentin Clement genConstantOffset(loc, rewriter, maskValue); 141b6e44ecdSValentin Clement auto maskRes = 142b6e44ecdSValentin Clement rewriter.create<mlir::LLVM::AndOp>(loc, attrTy, attribute, attrMask); 143b6e44ecdSValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 144b6e44ecdSValentin Clement return rewriter.create<mlir::LLVM::ICmpOp>( 145b6e44ecdSValentin Clement loc, mlir::LLVM::ICmpPredicate::ne, maskRes, c0); 146b6e44ecdSValentin Clement } 147b6e44ecdSValentin Clement 148df3b9810SValentin Clement template <typename... ARGS> 149df3b9810SValentin Clement mlir::LLVM::GEPOp genGEP(mlir::Location loc, mlir::Type ty, 150df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter, 151df3b9810SValentin Clement mlir::Value base, ARGS... args) const { 152df3b9810SValentin Clement SmallVector<mlir::Value> cv{args...}; 153df3b9810SValentin Clement return rewriter.create<mlir::LLVM::GEPOp>(loc, ty, base, cv); 154df3b9810SValentin Clement } 155df3b9810SValentin Clement 1561e6d9c06SDiana Picus /// Perform an extension or truncation as needed on an integer value. Lowering 1571e6d9c06SDiana Picus /// to the specific target may involve some sign-extending or truncation of 1581e6d9c06SDiana Picus /// values, particularly to fit them from abstract box types to the 1591e6d9c06SDiana Picus /// appropriate reified structures. 1601e6d9c06SDiana Picus mlir::Value integerCast(mlir::Location loc, 1611e6d9c06SDiana Picus mlir::ConversionPatternRewriter &rewriter, 1621e6d9c06SDiana Picus mlir::Type ty, mlir::Value val) const { 1631e6d9c06SDiana Picus auto valTy = val.getType(); 1641e6d9c06SDiana Picus // If the value was not yet lowered, lower its type so that it can 1651e6d9c06SDiana Picus // be used in getPrimitiveTypeSizeInBits. 1661e6d9c06SDiana Picus if (!valTy.isa<mlir::IntegerType>()) 1671e6d9c06SDiana Picus valTy = convertType(valTy); 1681e6d9c06SDiana Picus auto toSize = mlir::LLVM::getPrimitiveTypeSizeInBits(ty); 1691e6d9c06SDiana Picus auto fromSize = mlir::LLVM::getPrimitiveTypeSizeInBits(valTy); 1701e6d9c06SDiana Picus if (toSize < fromSize) 1711e6d9c06SDiana Picus return rewriter.create<mlir::LLVM::TruncOp>(loc, ty, val); 1721e6d9c06SDiana Picus if (toSize > fromSize) 1731e6d9c06SDiana Picus return rewriter.create<mlir::LLVM::SExtOp>(loc, ty, val); 1741e6d9c06SDiana Picus return val; 1751e6d9c06SDiana Picus } 1761e6d9c06SDiana Picus 177044d5b5dSValentin Clement fir::LLVMTypeConverter &lowerTy() const { 178044d5b5dSValentin Clement return *static_cast<fir::LLVMTypeConverter *>(this->getTypeConverter()); 179044d5b5dSValentin Clement } 180044d5b5dSValentin Clement }; 181044d5b5dSValentin Clement 1823ae8e442SValentin Clement /// FIR conversion pattern template 1833ae8e442SValentin Clement template <typename FromOp> 1843ae8e442SValentin Clement class FIROpAndTypeConversion : public FIROpConversion<FromOp> { 1853ae8e442SValentin Clement public: 1863ae8e442SValentin Clement using FIROpConversion<FromOp>::FIROpConversion; 1873ae8e442SValentin Clement using OpAdaptor = typename FromOp::Adaptor; 1883ae8e442SValentin Clement 1893ae8e442SValentin Clement mlir::LogicalResult 1903ae8e442SValentin Clement matchAndRewrite(FromOp op, OpAdaptor adaptor, 1913ae8e442SValentin Clement mlir::ConversionPatternRewriter &rewriter) const final { 1923ae8e442SValentin Clement mlir::Type ty = this->convertType(op.getType()); 1933ae8e442SValentin Clement return doRewrite(op, ty, adaptor, rewriter); 1943ae8e442SValentin Clement } 1953ae8e442SValentin Clement 1963ae8e442SValentin Clement virtual mlir::LogicalResult 1973ae8e442SValentin Clement doRewrite(FromOp addr, mlir::Type ty, OpAdaptor adaptor, 1983ae8e442SValentin Clement mlir::ConversionPatternRewriter &rewriter) const = 0; 1993ae8e442SValentin Clement }; 2003ae8e442SValentin Clement 2010c4a7a52SValentin Clement // Lower `fir.address_of` operation to `llvm.address_of` operation. 202044d5b5dSValentin Clement struct AddrOfOpConversion : public FIROpConversion<fir::AddrOfOp> { 203044d5b5dSValentin Clement using FIROpConversion::FIROpConversion; 204044d5b5dSValentin Clement 205044d5b5dSValentin Clement mlir::LogicalResult 206044d5b5dSValentin Clement matchAndRewrite(fir::AddrOfOp addr, OpAdaptor adaptor, 207044d5b5dSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 208044d5b5dSValentin Clement auto ty = convertType(addr.getType()); 209044d5b5dSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::AddressOfOp>( 210044d5b5dSValentin Clement addr, ty, addr.symbol().getRootReference().getValue()); 211044d5b5dSValentin Clement return success(); 212044d5b5dSValentin Clement } 213044d5b5dSValentin Clement }; 2141e6d9c06SDiana Picus } // namespace 2151e6d9c06SDiana Picus 2161e6d9c06SDiana Picus /// Lookup the function to compute the memory size of this parametric derived 2171e6d9c06SDiana Picus /// type. The size of the object may depend on the LEN type parameters of the 2181e6d9c06SDiana Picus /// derived type. 2191e6d9c06SDiana Picus static mlir::LLVM::LLVMFuncOp 2201e6d9c06SDiana Picus getDependentTypeMemSizeFn(fir::RecordType recTy, fir::AllocaOp op, 2211e6d9c06SDiana Picus mlir::ConversionPatternRewriter &rewriter) { 2221e6d9c06SDiana Picus auto module = op->getParentOfType<mlir::ModuleOp>(); 2231e6d9c06SDiana Picus std::string name = recTy.getName().str() + "P.mem.size"; 2241e6d9c06SDiana Picus return module.lookupSymbol<mlir::LLVM::LLVMFuncOp>(name); 2251e6d9c06SDiana Picus } 2261e6d9c06SDiana Picus 2271e6d9c06SDiana Picus namespace { 2281e6d9c06SDiana Picus /// convert to LLVM IR dialect `alloca` 2291e6d9c06SDiana Picus struct AllocaOpConversion : public FIROpConversion<fir::AllocaOp> { 2301e6d9c06SDiana Picus using FIROpConversion::FIROpConversion; 2311e6d9c06SDiana Picus 2321e6d9c06SDiana Picus mlir::LogicalResult 2331e6d9c06SDiana Picus matchAndRewrite(fir::AllocaOp alloc, OpAdaptor adaptor, 2341e6d9c06SDiana Picus mlir::ConversionPatternRewriter &rewriter) const override { 2351e6d9c06SDiana Picus mlir::ValueRange operands = adaptor.getOperands(); 2361e6d9c06SDiana Picus auto loc = alloc.getLoc(); 2371e6d9c06SDiana Picus mlir::Type ity = lowerTy().indexType(); 2381e6d9c06SDiana Picus unsigned i = 0; 2391e6d9c06SDiana Picus mlir::Value size = genConstantIndex(loc, ity, rewriter, 1).getResult(); 2401e6d9c06SDiana Picus mlir::Type ty = convertType(alloc.getType()); 2411e6d9c06SDiana Picus mlir::Type resultTy = ty; 2421e6d9c06SDiana Picus if (alloc.hasLenParams()) { 2431e6d9c06SDiana Picus unsigned end = alloc.numLenParams(); 2441e6d9c06SDiana Picus llvm::SmallVector<mlir::Value> lenParams; 2451e6d9c06SDiana Picus for (; i < end; ++i) 2461e6d9c06SDiana Picus lenParams.push_back(operands[i]); 2471e6d9c06SDiana Picus mlir::Type scalarType = fir::unwrapSequenceType(alloc.getInType()); 2481e6d9c06SDiana Picus if (auto chrTy = scalarType.dyn_cast<fir::CharacterType>()) { 2491e6d9c06SDiana Picus fir::CharacterType rawCharTy = fir::CharacterType::getUnknownLen( 2501e6d9c06SDiana Picus chrTy.getContext(), chrTy.getFKind()); 2511e6d9c06SDiana Picus ty = mlir::LLVM::LLVMPointerType::get(convertType(rawCharTy)); 2521e6d9c06SDiana Picus assert(end == 1); 2531e6d9c06SDiana Picus size = integerCast(loc, rewriter, ity, lenParams[0]); 2541e6d9c06SDiana Picus } else if (auto recTy = scalarType.dyn_cast<fir::RecordType>()) { 2551e6d9c06SDiana Picus mlir::LLVM::LLVMFuncOp memSizeFn = 2561e6d9c06SDiana Picus getDependentTypeMemSizeFn(recTy, alloc, rewriter); 2571e6d9c06SDiana Picus if (!memSizeFn) 2581e6d9c06SDiana Picus emitError(loc, "did not find allocation function"); 2591e6d9c06SDiana Picus mlir::NamedAttribute attr = rewriter.getNamedAttr( 2601e6d9c06SDiana Picus "callee", mlir::SymbolRefAttr::get(memSizeFn)); 2611e6d9c06SDiana Picus auto call = rewriter.create<mlir::LLVM::CallOp>( 2621e6d9c06SDiana Picus loc, ity, lenParams, llvm::ArrayRef<mlir::NamedAttribute>{attr}); 2631e6d9c06SDiana Picus size = call.getResult(0); 2641e6d9c06SDiana Picus ty = mlir::LLVM::LLVMPointerType::get( 2651e6d9c06SDiana Picus mlir::IntegerType::get(alloc.getContext(), 8)); 2661e6d9c06SDiana Picus } else { 2671e6d9c06SDiana Picus return emitError(loc, "unexpected type ") 2681e6d9c06SDiana Picus << scalarType << " with type parameters"; 2691e6d9c06SDiana Picus } 2701e6d9c06SDiana Picus } 2711e6d9c06SDiana Picus if (alloc.hasShapeOperands()) { 2721e6d9c06SDiana Picus mlir::Type allocEleTy = fir::unwrapRefType(alloc.getType()); 2731e6d9c06SDiana Picus // Scale the size by constant factors encoded in the array type. 2741e6d9c06SDiana Picus if (auto seqTy = allocEleTy.dyn_cast<fir::SequenceType>()) { 2751e6d9c06SDiana Picus fir::SequenceType::Extent constSize = 1; 2761e6d9c06SDiana Picus for (auto extent : seqTy.getShape()) 2771e6d9c06SDiana Picus if (extent != fir::SequenceType::getUnknownExtent()) 2781e6d9c06SDiana Picus constSize *= extent; 2791e6d9c06SDiana Picus mlir::Value constVal{ 2801e6d9c06SDiana Picus genConstantIndex(loc, ity, rewriter, constSize).getResult()}; 2811e6d9c06SDiana Picus size = rewriter.create<mlir::LLVM::MulOp>(loc, ity, size, constVal); 2821e6d9c06SDiana Picus } 2831e6d9c06SDiana Picus unsigned end = operands.size(); 2841e6d9c06SDiana Picus for (; i < end; ++i) 2851e6d9c06SDiana Picus size = rewriter.create<mlir::LLVM::MulOp>( 2861e6d9c06SDiana Picus loc, ity, size, integerCast(loc, rewriter, ity, operands[i])); 2871e6d9c06SDiana Picus } 2881e6d9c06SDiana Picus if (ty == resultTy) { 2891e6d9c06SDiana Picus // Do not emit the bitcast if ty and resultTy are the same. 2901e6d9c06SDiana Picus rewriter.replaceOpWithNewOp<mlir::LLVM::AllocaOp>(alloc, ty, size, 2911e6d9c06SDiana Picus alloc->getAttrs()); 2921e6d9c06SDiana Picus } else { 2931e6d9c06SDiana Picus auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, ty, size, 2941e6d9c06SDiana Picus alloc->getAttrs()); 2951e6d9c06SDiana Picus rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(alloc, resultTy, al); 2961e6d9c06SDiana Picus } 2971e6d9c06SDiana Picus return success(); 2981e6d9c06SDiana Picus } 2991e6d9c06SDiana Picus }; 300044d5b5dSValentin Clement 301df3b9810SValentin Clement /// Lower `fir.box_addr` to the sequence of operations to extract the first 302df3b9810SValentin Clement /// element of the box. 303df3b9810SValentin Clement struct BoxAddrOpConversion : public FIROpConversion<fir::BoxAddrOp> { 304df3b9810SValentin Clement using FIROpConversion::FIROpConversion; 305df3b9810SValentin Clement 306df3b9810SValentin Clement mlir::LogicalResult 307df3b9810SValentin Clement matchAndRewrite(fir::BoxAddrOp boxaddr, OpAdaptor adaptor, 308df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 309df3b9810SValentin Clement mlir::Value a = adaptor.getOperands()[0]; 310df3b9810SValentin Clement auto loc = boxaddr.getLoc(); 311df3b9810SValentin Clement mlir::Type ty = convertType(boxaddr.getType()); 312df3b9810SValentin Clement if (auto argty = boxaddr.val().getType().dyn_cast<fir::BoxType>()) { 313df3b9810SValentin Clement rewriter.replaceOp(boxaddr, loadBaseAddrFromBox(loc, ty, a, rewriter)); 314df3b9810SValentin Clement } else { 315df3b9810SValentin Clement auto c0attr = rewriter.getI32IntegerAttr(0); 316df3b9810SValentin Clement auto c0 = mlir::ArrayAttr::get(boxaddr.getContext(), c0attr); 317df3b9810SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(boxaddr, ty, a, 318df3b9810SValentin Clement c0); 319df3b9810SValentin Clement } 320df3b9810SValentin Clement return success(); 321df3b9810SValentin Clement } 322df3b9810SValentin Clement }; 323df3b9810SValentin Clement 324df3b9810SValentin Clement /// Lower `fir.box_dims` to a sequence of operations to extract the requested 325df3b9810SValentin Clement /// dimension infomartion from the boxed value. 326df3b9810SValentin Clement /// Result in a triple set of GEPs and loads. 327df3b9810SValentin Clement struct BoxDimsOpConversion : public FIROpConversion<fir::BoxDimsOp> { 328df3b9810SValentin Clement using FIROpConversion::FIROpConversion; 329df3b9810SValentin Clement 330df3b9810SValentin Clement mlir::LogicalResult 331df3b9810SValentin Clement matchAndRewrite(fir::BoxDimsOp boxdims, OpAdaptor adaptor, 332df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 333df3b9810SValentin Clement SmallVector<mlir::Type, 3> resultTypes = { 334df3b9810SValentin Clement convertType(boxdims.getResult(0).getType()), 335df3b9810SValentin Clement convertType(boxdims.getResult(1).getType()), 336df3b9810SValentin Clement convertType(boxdims.getResult(2).getType()), 337df3b9810SValentin Clement }; 338df3b9810SValentin Clement auto results = 339df3b9810SValentin Clement getDimsFromBox(boxdims.getLoc(), resultTypes, adaptor.getOperands()[0], 340df3b9810SValentin Clement adaptor.getOperands()[1], rewriter); 341df3b9810SValentin Clement rewriter.replaceOp(boxdims, results); 342df3b9810SValentin Clement return success(); 343df3b9810SValentin Clement } 344df3b9810SValentin Clement }; 345df3b9810SValentin Clement 346df3b9810SValentin Clement /// Lower `fir.box_elesize` to a sequence of operations ro extract the size of 347df3b9810SValentin Clement /// an element in the boxed value. 348df3b9810SValentin Clement struct BoxEleSizeOpConversion : public FIROpConversion<fir::BoxEleSizeOp> { 349df3b9810SValentin Clement using FIROpConversion::FIROpConversion; 350df3b9810SValentin Clement 351df3b9810SValentin Clement mlir::LogicalResult 352df3b9810SValentin Clement matchAndRewrite(fir::BoxEleSizeOp boxelesz, OpAdaptor adaptor, 353df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 354df3b9810SValentin Clement mlir::Value a = adaptor.getOperands()[0]; 355df3b9810SValentin Clement auto loc = boxelesz.getLoc(); 356df3b9810SValentin Clement auto ty = convertType(boxelesz.getType()); 357b6e44ecdSValentin Clement auto elemSize = getValueFromBox(loc, a, ty, rewriter, kElemLenPosInBox); 358b6e44ecdSValentin Clement rewriter.replaceOp(boxelesz, elemSize); 359b6e44ecdSValentin Clement return success(); 360b6e44ecdSValentin Clement } 361b6e44ecdSValentin Clement }; 362b6e44ecdSValentin Clement 363b6e44ecdSValentin Clement /// Lower `fir.box_isalloc` to a sequence of operations to determine if the 364b6e44ecdSValentin Clement /// boxed value was from an ALLOCATABLE entity. 365b6e44ecdSValentin Clement struct BoxIsAllocOpConversion : public FIROpConversion<fir::BoxIsAllocOp> { 366b6e44ecdSValentin Clement using FIROpConversion::FIROpConversion; 367b6e44ecdSValentin Clement 368b6e44ecdSValentin Clement mlir::LogicalResult 369b6e44ecdSValentin Clement matchAndRewrite(fir::BoxIsAllocOp boxisalloc, OpAdaptor adaptor, 370b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 371b6e44ecdSValentin Clement mlir::Value box = adaptor.getOperands()[0]; 372b6e44ecdSValentin Clement auto loc = boxisalloc.getLoc(); 373b6e44ecdSValentin Clement mlir::Value check = 374b6e44ecdSValentin Clement genBoxAttributeCheck(loc, box, rewriter, kAttrAllocatable); 375b6e44ecdSValentin Clement rewriter.replaceOp(boxisalloc, check); 376b6e44ecdSValentin Clement return success(); 377b6e44ecdSValentin Clement } 378b6e44ecdSValentin Clement }; 379b6e44ecdSValentin Clement 380b6e44ecdSValentin Clement /// Lower `fir.box_isarray` to a sequence of operations to determine if the 381b6e44ecdSValentin Clement /// boxed is an array. 382b6e44ecdSValentin Clement struct BoxIsArrayOpConversion : public FIROpConversion<fir::BoxIsArrayOp> { 383b6e44ecdSValentin Clement using FIROpConversion::FIROpConversion; 384b6e44ecdSValentin Clement 385b6e44ecdSValentin Clement mlir::LogicalResult 386b6e44ecdSValentin Clement matchAndRewrite(fir::BoxIsArrayOp boxisarray, OpAdaptor adaptor, 387b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 388b6e44ecdSValentin Clement mlir::Value a = adaptor.getOperands()[0]; 389b6e44ecdSValentin Clement auto loc = boxisarray.getLoc(); 390b6e44ecdSValentin Clement auto rank = 391b6e44ecdSValentin Clement getValueFromBox(loc, a, rewriter.getI32Type(), rewriter, kRankPosInBox); 392b6e44ecdSValentin Clement auto c0 = genConstantOffset(loc, rewriter, 0); 393b6e44ecdSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>( 394b6e44ecdSValentin Clement boxisarray, mlir::LLVM::ICmpPredicate::ne, rank, c0); 395b6e44ecdSValentin Clement return success(); 396b6e44ecdSValentin Clement } 397b6e44ecdSValentin Clement }; 398b6e44ecdSValentin Clement 399b6e44ecdSValentin Clement /// Lower `fir.box_isptr` to a sequence of operations to determined if the 400b6e44ecdSValentin Clement /// boxed value was from a POINTER entity. 401b6e44ecdSValentin Clement struct BoxIsPtrOpConversion : public FIROpConversion<fir::BoxIsPtrOp> { 402b6e44ecdSValentin Clement using FIROpConversion::FIROpConversion; 403b6e44ecdSValentin Clement 404b6e44ecdSValentin Clement mlir::LogicalResult 405b6e44ecdSValentin Clement matchAndRewrite(fir::BoxIsPtrOp boxisptr, OpAdaptor adaptor, 406b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 407b6e44ecdSValentin Clement mlir::Value box = adaptor.getOperands()[0]; 408b6e44ecdSValentin Clement auto loc = boxisptr.getLoc(); 409b6e44ecdSValentin Clement mlir::Value check = genBoxAttributeCheck(loc, box, rewriter, kAttrPointer); 410b6e44ecdSValentin Clement rewriter.replaceOp(boxisptr, check); 411df3b9810SValentin Clement return success(); 412df3b9810SValentin Clement } 413df3b9810SValentin Clement }; 414df3b9810SValentin Clement 415df3b9810SValentin Clement /// Lower `fir.box_rank` to the sequence of operation to extract the rank from 416df3b9810SValentin Clement /// the box. 417df3b9810SValentin Clement struct BoxRankOpConversion : public FIROpConversion<fir::BoxRankOp> { 418df3b9810SValentin Clement using FIROpConversion::FIROpConversion; 419df3b9810SValentin Clement 420df3b9810SValentin Clement mlir::LogicalResult 421df3b9810SValentin Clement matchAndRewrite(fir::BoxRankOp boxrank, OpAdaptor adaptor, 422df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 423df3b9810SValentin Clement mlir::Value a = adaptor.getOperands()[0]; 424df3b9810SValentin Clement auto loc = boxrank.getLoc(); 425df3b9810SValentin Clement mlir::Type ty = convertType(boxrank.getType()); 426b6e44ecdSValentin Clement auto result = getValueFromBox(loc, a, ty, rewriter, kRankPosInBox); 427df3b9810SValentin Clement rewriter.replaceOp(boxrank, result); 428df3b9810SValentin Clement return success(); 429df3b9810SValentin Clement } 430df3b9810SValentin Clement }; 431df3b9810SValentin Clement 432ddd11b9aSAndrzej Warzynski // `fir.call` -> `llvm.call` 433ddd11b9aSAndrzej Warzynski struct CallOpConversion : public FIROpConversion<fir::CallOp> { 434ddd11b9aSAndrzej Warzynski using FIROpConversion::FIROpConversion; 435ddd11b9aSAndrzej Warzynski 436ddd11b9aSAndrzej Warzynski mlir::LogicalResult 437ddd11b9aSAndrzej Warzynski matchAndRewrite(fir::CallOp call, OpAdaptor adaptor, 438ddd11b9aSAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 439ddd11b9aSAndrzej Warzynski SmallVector<mlir::Type> resultTys; 440ddd11b9aSAndrzej Warzynski for (auto r : call.getResults()) 441ddd11b9aSAndrzej Warzynski resultTys.push_back(convertType(r.getType())); 442ddd11b9aSAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>( 443ddd11b9aSAndrzej Warzynski call, resultTys, adaptor.getOperands(), call->getAttrs()); 444ddd11b9aSAndrzej Warzynski return success(); 445ddd11b9aSAndrzej Warzynski } 446ddd11b9aSAndrzej Warzynski }; 447ddd11b9aSAndrzej Warzynski 448092cee5fSValentin Clement static mlir::Type getComplexEleTy(mlir::Type complex) { 449092cee5fSValentin Clement if (auto cc = complex.dyn_cast<mlir::ComplexType>()) 450092cee5fSValentin Clement return cc.getElementType(); 451092cee5fSValentin Clement return complex.cast<fir::ComplexType>().getElementType(); 452092cee5fSValentin Clement } 453092cee5fSValentin Clement 454092cee5fSValentin Clement /// convert value of from-type to value of to-type 455092cee5fSValentin Clement struct ConvertOpConversion : public FIROpConversion<fir::ConvertOp> { 456092cee5fSValentin Clement using FIROpConversion::FIROpConversion; 457092cee5fSValentin Clement 458092cee5fSValentin Clement static bool isFloatingPointTy(mlir::Type ty) { 459092cee5fSValentin Clement return ty.isa<mlir::FloatType>(); 460092cee5fSValentin Clement } 461092cee5fSValentin Clement 462092cee5fSValentin Clement mlir::LogicalResult 463092cee5fSValentin Clement matchAndRewrite(fir::ConvertOp convert, OpAdaptor adaptor, 464092cee5fSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 465092cee5fSValentin Clement auto fromTy = convertType(convert.value().getType()); 466092cee5fSValentin Clement auto toTy = convertType(convert.res().getType()); 467092cee5fSValentin Clement mlir::Value op0 = adaptor.getOperands()[0]; 468092cee5fSValentin Clement if (fromTy == toTy) { 469092cee5fSValentin Clement rewriter.replaceOp(convert, op0); 470092cee5fSValentin Clement return success(); 471092cee5fSValentin Clement } 472092cee5fSValentin Clement auto loc = convert.getLoc(); 473092cee5fSValentin Clement auto convertFpToFp = [&](mlir::Value val, unsigned fromBits, 474092cee5fSValentin Clement unsigned toBits, mlir::Type toTy) -> mlir::Value { 475092cee5fSValentin Clement if (fromBits == toBits) { 476092cee5fSValentin Clement // TODO: Converting between two floating-point representations with the 477092cee5fSValentin Clement // same bitwidth is not allowed for now. 478092cee5fSValentin Clement mlir::emitError(loc, 479092cee5fSValentin Clement "cannot implicitly convert between two floating-point " 480092cee5fSValentin Clement "representations of the same bitwidth"); 481092cee5fSValentin Clement return {}; 482092cee5fSValentin Clement } 483092cee5fSValentin Clement if (fromBits > toBits) 484092cee5fSValentin Clement return rewriter.create<mlir::LLVM::FPTruncOp>(loc, toTy, val); 485092cee5fSValentin Clement return rewriter.create<mlir::LLVM::FPExtOp>(loc, toTy, val); 486092cee5fSValentin Clement }; 487092cee5fSValentin Clement // Complex to complex conversion. 488092cee5fSValentin Clement if (fir::isa_complex(convert.value().getType()) && 489092cee5fSValentin Clement fir::isa_complex(convert.res().getType())) { 490092cee5fSValentin Clement // Special case: handle the conversion of a complex such that both the 491092cee5fSValentin Clement // real and imaginary parts are converted together. 492092cee5fSValentin Clement auto zero = mlir::ArrayAttr::get(convert.getContext(), 493092cee5fSValentin Clement rewriter.getI32IntegerAttr(0)); 494092cee5fSValentin Clement auto one = mlir::ArrayAttr::get(convert.getContext(), 495092cee5fSValentin Clement rewriter.getI32IntegerAttr(1)); 496092cee5fSValentin Clement auto ty = convertType(getComplexEleTy(convert.value().getType())); 497092cee5fSValentin Clement auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, zero); 498092cee5fSValentin Clement auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, one); 499092cee5fSValentin Clement auto nt = convertType(getComplexEleTy(convert.res().getType())); 500092cee5fSValentin Clement auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(ty); 501092cee5fSValentin Clement auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(nt); 502092cee5fSValentin Clement auto rc = convertFpToFp(rp, fromBits, toBits, nt); 503092cee5fSValentin Clement auto ic = convertFpToFp(ip, fromBits, toBits, nt); 504092cee5fSValentin Clement auto un = rewriter.create<mlir::LLVM::UndefOp>(loc, toTy); 505092cee5fSValentin Clement auto i1 = 506092cee5fSValentin Clement rewriter.create<mlir::LLVM::InsertValueOp>(loc, toTy, un, rc, zero); 507092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(convert, toTy, i1, 508092cee5fSValentin Clement ic, one); 509092cee5fSValentin Clement return mlir::success(); 510092cee5fSValentin Clement } 511092cee5fSValentin Clement // Floating point to floating point conversion. 512092cee5fSValentin Clement if (isFloatingPointTy(fromTy)) { 513092cee5fSValentin Clement if (isFloatingPointTy(toTy)) { 514092cee5fSValentin Clement auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy); 515092cee5fSValentin Clement auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy); 516092cee5fSValentin Clement auto v = convertFpToFp(op0, fromBits, toBits, toTy); 517092cee5fSValentin Clement rewriter.replaceOp(convert, v); 518092cee5fSValentin Clement return mlir::success(); 519092cee5fSValentin Clement } 520092cee5fSValentin Clement if (toTy.isa<mlir::IntegerType>()) { 521092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::FPToSIOp>(convert, toTy, op0); 522092cee5fSValentin Clement return mlir::success(); 523092cee5fSValentin Clement } 524092cee5fSValentin Clement } else if (fromTy.isa<mlir::IntegerType>()) { 525092cee5fSValentin Clement // Integer to integer conversion. 526092cee5fSValentin Clement if (toTy.isa<mlir::IntegerType>()) { 527092cee5fSValentin Clement auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy); 528092cee5fSValentin Clement auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy); 529092cee5fSValentin Clement assert(fromBits != toBits); 530092cee5fSValentin Clement if (fromBits > toBits) { 531092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::TruncOp>(convert, toTy, op0); 532092cee5fSValentin Clement return mlir::success(); 533092cee5fSValentin Clement } 534092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::SExtOp>(convert, toTy, op0); 535092cee5fSValentin Clement return mlir::success(); 536092cee5fSValentin Clement } 537092cee5fSValentin Clement // Integer to floating point conversion. 538092cee5fSValentin Clement if (isFloatingPointTy(toTy)) { 539092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::SIToFPOp>(convert, toTy, op0); 540092cee5fSValentin Clement return mlir::success(); 541092cee5fSValentin Clement } 542092cee5fSValentin Clement // Integer to pointer conversion. 543092cee5fSValentin Clement if (toTy.isa<mlir::LLVM::LLVMPointerType>()) { 544092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(convert, toTy, op0); 545092cee5fSValentin Clement return mlir::success(); 546092cee5fSValentin Clement } 547092cee5fSValentin Clement } else if (fromTy.isa<mlir::LLVM::LLVMPointerType>()) { 548092cee5fSValentin Clement // Pointer to integer conversion. 549092cee5fSValentin Clement if (toTy.isa<mlir::IntegerType>()) { 550092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::PtrToIntOp>(convert, toTy, op0); 551092cee5fSValentin Clement return mlir::success(); 552092cee5fSValentin Clement } 553092cee5fSValentin Clement // Pointer to pointer conversion. 554092cee5fSValentin Clement if (toTy.isa<mlir::LLVM::LLVMPointerType>()) { 555092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(convert, toTy, op0); 556092cee5fSValentin Clement return mlir::success(); 557092cee5fSValentin Clement } 558092cee5fSValentin Clement } 559092cee5fSValentin Clement return emitError(loc) << "cannot convert " << fromTy << " to " << toTy; 560092cee5fSValentin Clement } 561092cee5fSValentin Clement }; 562092cee5fSValentin Clement 563*9534e361SValentin Clement /// Lower `fir.dispatch` operation. A virtual call to a method in a dispatch 564*9534e361SValentin Clement /// table. 565*9534e361SValentin Clement struct DispatchOpConversion : public FIROpConversion<fir::DispatchOp> { 566*9534e361SValentin Clement using FIROpConversion::FIROpConversion; 567*9534e361SValentin Clement 568*9534e361SValentin Clement mlir::LogicalResult 569*9534e361SValentin Clement matchAndRewrite(fir::DispatchOp dispatch, OpAdaptor adaptor, 570*9534e361SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 571*9534e361SValentin Clement return rewriter.notifyMatchFailure( 572*9534e361SValentin Clement dispatch, "fir.dispatch codegen is not implemented yet"); 573*9534e361SValentin Clement } 574*9534e361SValentin Clement }; 575*9534e361SValentin Clement 576*9534e361SValentin Clement /// Lower `fir.dispatch_table` operation. The dispatch table for a Fortran 577*9534e361SValentin Clement /// derived type. 578*9534e361SValentin Clement struct DispatchTableOpConversion 579*9534e361SValentin Clement : public FIROpConversion<fir::DispatchTableOp> { 580*9534e361SValentin Clement using FIROpConversion::FIROpConversion; 581*9534e361SValentin Clement 582*9534e361SValentin Clement mlir::LogicalResult 583*9534e361SValentin Clement matchAndRewrite(fir::DispatchTableOp dispTab, OpAdaptor adaptor, 584*9534e361SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 585*9534e361SValentin Clement return rewriter.notifyMatchFailure( 586*9534e361SValentin Clement dispTab, "fir.dispatch_table codegen is not implemented yet"); 587*9534e361SValentin Clement } 588*9534e361SValentin Clement }; 589*9534e361SValentin Clement 590*9534e361SValentin Clement /// Lower `fir.dt_entry` operation. An entry in a dispatch table; binds a 591*9534e361SValentin Clement /// method-name to a function. 592*9534e361SValentin Clement struct DTEntryOpConversion : public FIROpConversion<fir::DTEntryOp> { 593*9534e361SValentin Clement using FIROpConversion::FIROpConversion; 594*9534e361SValentin Clement 595*9534e361SValentin Clement mlir::LogicalResult 596*9534e361SValentin Clement matchAndRewrite(fir::DTEntryOp dtEnt, OpAdaptor adaptor, 597*9534e361SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 598*9534e361SValentin Clement return rewriter.notifyMatchFailure( 599*9534e361SValentin Clement dtEnt, "fir.dt_entry codegen is not implemented yet"); 600*9534e361SValentin Clement } 601*9534e361SValentin Clement }; 602*9534e361SValentin Clement 6030c4a7a52SValentin Clement /// Lower `fir.has_value` operation to `llvm.return` operation. 604044d5b5dSValentin Clement struct HasValueOpConversion : public FIROpConversion<fir::HasValueOp> { 605044d5b5dSValentin Clement using FIROpConversion::FIROpConversion; 606044d5b5dSValentin Clement 607044d5b5dSValentin Clement mlir::LogicalResult 608044d5b5dSValentin Clement matchAndRewrite(fir::HasValueOp op, OpAdaptor adaptor, 609044d5b5dSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 610044d5b5dSValentin Clement rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, adaptor.getOperands()); 611044d5b5dSValentin Clement return success(); 612044d5b5dSValentin Clement } 613044d5b5dSValentin Clement }; 614044d5b5dSValentin Clement 6150c4a7a52SValentin Clement /// Lower `fir.global` operation to `llvm.global` operation. 6160c4a7a52SValentin Clement /// `fir.insert_on_range` operations are replaced with constant dense attribute 6170c4a7a52SValentin Clement /// if they are applied on the full range. 618044d5b5dSValentin Clement struct GlobalOpConversion : public FIROpConversion<fir::GlobalOp> { 619044d5b5dSValentin Clement using FIROpConversion::FIROpConversion; 620044d5b5dSValentin Clement 621044d5b5dSValentin Clement mlir::LogicalResult 622044d5b5dSValentin Clement matchAndRewrite(fir::GlobalOp global, OpAdaptor adaptor, 623044d5b5dSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 624044d5b5dSValentin Clement auto tyAttr = convertType(global.getType()); 625044d5b5dSValentin Clement if (global.getType().isa<fir::BoxType>()) 626044d5b5dSValentin Clement tyAttr = tyAttr.cast<mlir::LLVM::LLVMPointerType>().getElementType(); 627044d5b5dSValentin Clement auto loc = global.getLoc(); 628044d5b5dSValentin Clement mlir::Attribute initAttr{}; 629044d5b5dSValentin Clement if (global.initVal()) 630044d5b5dSValentin Clement initAttr = global.initVal().getValue(); 631044d5b5dSValentin Clement auto linkage = convertLinkage(global.linkName()); 632044d5b5dSValentin Clement auto isConst = global.constant().hasValue(); 633044d5b5dSValentin Clement auto g = rewriter.create<mlir::LLVM::GlobalOp>( 634044d5b5dSValentin Clement loc, tyAttr, isConst, linkage, global.sym_name(), initAttr); 635044d5b5dSValentin Clement auto &gr = g.getInitializerRegion(); 636044d5b5dSValentin Clement rewriter.inlineRegionBefore(global.region(), gr, gr.end()); 637044d5b5dSValentin Clement if (!gr.empty()) { 638044d5b5dSValentin Clement // Replace insert_on_range with a constant dense attribute if the 639044d5b5dSValentin Clement // initialization is on the full range. 640044d5b5dSValentin Clement auto insertOnRangeOps = gr.front().getOps<fir::InsertOnRangeOp>(); 641044d5b5dSValentin Clement for (auto insertOp : insertOnRangeOps) { 642044d5b5dSValentin Clement if (isFullRange(insertOp.coor(), insertOp.getType())) { 643044d5b5dSValentin Clement auto seqTyAttr = convertType(insertOp.getType()); 644044d5b5dSValentin Clement auto *op = insertOp.val().getDefiningOp(); 645044d5b5dSValentin Clement auto constant = mlir::dyn_cast<mlir::arith::ConstantOp>(op); 646044d5b5dSValentin Clement if (!constant) { 647044d5b5dSValentin Clement auto convertOp = mlir::dyn_cast<fir::ConvertOp>(op); 648044d5b5dSValentin Clement if (!convertOp) 649044d5b5dSValentin Clement continue; 650044d5b5dSValentin Clement constant = cast<mlir::arith::ConstantOp>( 651044d5b5dSValentin Clement convertOp.value().getDefiningOp()); 652044d5b5dSValentin Clement } 653044d5b5dSValentin Clement mlir::Type vecType = mlir::VectorType::get( 654044d5b5dSValentin Clement insertOp.getType().getShape(), constant.getType()); 655044d5b5dSValentin Clement auto denseAttr = mlir::DenseElementsAttr::get( 656044d5b5dSValentin Clement vecType.cast<ShapedType>(), constant.value()); 657044d5b5dSValentin Clement rewriter.setInsertionPointAfter(insertOp); 658044d5b5dSValentin Clement rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>( 659044d5b5dSValentin Clement insertOp, seqTyAttr, denseAttr); 660044d5b5dSValentin Clement } 661044d5b5dSValentin Clement } 662044d5b5dSValentin Clement } 663044d5b5dSValentin Clement rewriter.eraseOp(global); 664044d5b5dSValentin Clement return success(); 665044d5b5dSValentin Clement } 666044d5b5dSValentin Clement 667044d5b5dSValentin Clement bool isFullRange(mlir::ArrayAttr indexes, fir::SequenceType seqTy) const { 668044d5b5dSValentin Clement auto extents = seqTy.getShape(); 669044d5b5dSValentin Clement if (indexes.size() / 2 != extents.size()) 670044d5b5dSValentin Clement return false; 671044d5b5dSValentin Clement for (unsigned i = 0; i < indexes.size(); i += 2) { 672044d5b5dSValentin Clement if (indexes[i].cast<IntegerAttr>().getInt() != 0) 673044d5b5dSValentin Clement return false; 674044d5b5dSValentin Clement if (indexes[i + 1].cast<IntegerAttr>().getInt() != extents[i / 2] - 1) 675044d5b5dSValentin Clement return false; 676044d5b5dSValentin Clement } 677044d5b5dSValentin Clement return true; 678044d5b5dSValentin Clement } 679044d5b5dSValentin Clement 6800c4a7a52SValentin Clement // TODO: String comparaison should be avoided. Replace linkName with an 6810c4a7a52SValentin Clement // enumeration. 682044d5b5dSValentin Clement mlir::LLVM::Linkage convertLinkage(Optional<StringRef> optLinkage) const { 683044d5b5dSValentin Clement if (optLinkage.hasValue()) { 684044d5b5dSValentin Clement auto name = optLinkage.getValue(); 685044d5b5dSValentin Clement if (name == "internal") 686044d5b5dSValentin Clement return mlir::LLVM::Linkage::Internal; 687044d5b5dSValentin Clement if (name == "linkonce") 688044d5b5dSValentin Clement return mlir::LLVM::Linkage::Linkonce; 689044d5b5dSValentin Clement if (name == "common") 690044d5b5dSValentin Clement return mlir::LLVM::Linkage::Common; 691044d5b5dSValentin Clement if (name == "weak") 692044d5b5dSValentin Clement return mlir::LLVM::Linkage::Weak; 693044d5b5dSValentin Clement } 694044d5b5dSValentin Clement return mlir::LLVM::Linkage::External; 695044d5b5dSValentin Clement } 696044d5b5dSValentin Clement }; 697044d5b5dSValentin Clement 6988c239909SValentin Clement template <typename OP> 6998c239909SValentin Clement void selectMatchAndRewrite(fir::LLVMTypeConverter &lowering, OP select, 7008c239909SValentin Clement typename OP::Adaptor adaptor, 7018c239909SValentin Clement mlir::ConversionPatternRewriter &rewriter) { 7028c239909SValentin Clement unsigned conds = select.getNumConditions(); 7038c239909SValentin Clement auto cases = select.getCases().getValue(); 7048c239909SValentin Clement mlir::Value selector = adaptor.selector(); 7058c239909SValentin Clement auto loc = select.getLoc(); 7068c239909SValentin Clement assert(conds > 0 && "select must have cases"); 7078c239909SValentin Clement 7088c239909SValentin Clement llvm::SmallVector<mlir::Block *> destinations; 7098c239909SValentin Clement llvm::SmallVector<mlir::ValueRange> destinationsOperands; 7108c239909SValentin Clement mlir::Block *defaultDestination; 7118c239909SValentin Clement mlir::ValueRange defaultOperands; 7128c239909SValentin Clement llvm::SmallVector<int32_t> caseValues; 7138c239909SValentin Clement 7148c239909SValentin Clement for (unsigned t = 0; t != conds; ++t) { 7158c239909SValentin Clement mlir::Block *dest = select.getSuccessor(t); 7168c239909SValentin Clement auto destOps = select.getSuccessorOperands(adaptor.getOperands(), t); 7178c239909SValentin Clement const mlir::Attribute &attr = cases[t]; 7188c239909SValentin Clement if (auto intAttr = attr.template dyn_cast<mlir::IntegerAttr>()) { 7198c239909SValentin Clement destinations.push_back(dest); 7208c239909SValentin Clement destinationsOperands.push_back(destOps.hasValue() ? *destOps 7218c239909SValentin Clement : ValueRange()); 7228c239909SValentin Clement caseValues.push_back(intAttr.getInt()); 7238c239909SValentin Clement continue; 7248c239909SValentin Clement } 7258c239909SValentin Clement assert(attr.template dyn_cast_or_null<mlir::UnitAttr>()); 7268c239909SValentin Clement assert((t + 1 == conds) && "unit must be last"); 7278c239909SValentin Clement defaultDestination = dest; 7288c239909SValentin Clement defaultOperands = destOps.hasValue() ? *destOps : ValueRange(); 7298c239909SValentin Clement } 7308c239909SValentin Clement 7318c239909SValentin Clement // LLVM::SwitchOp takes a i32 type for the selector. 7328c239909SValentin Clement if (select.getSelector().getType() != rewriter.getI32Type()) 7338c239909SValentin Clement selector = 7348c239909SValentin Clement rewriter.create<LLVM::TruncOp>(loc, rewriter.getI32Type(), selector); 7358c239909SValentin Clement 7368c239909SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>( 7378c239909SValentin Clement select, selector, 7388c239909SValentin Clement /*defaultDestination=*/defaultDestination, 7398c239909SValentin Clement /*defaultOperands=*/defaultOperands, 7408c239909SValentin Clement /*caseValues=*/caseValues, 7418c239909SValentin Clement /*caseDestinations=*/destinations, 7428c239909SValentin Clement /*caseOperands=*/destinationsOperands, 7438c239909SValentin Clement /*branchWeights=*/ArrayRef<int32_t>()); 7448c239909SValentin Clement } 7458c239909SValentin Clement 7468c239909SValentin Clement /// conversion of fir::SelectOp to an if-then-else ladder 7478c239909SValentin Clement struct SelectOpConversion : public FIROpConversion<fir::SelectOp> { 7488c239909SValentin Clement using FIROpConversion::FIROpConversion; 7498c239909SValentin Clement 7508c239909SValentin Clement mlir::LogicalResult 7518c239909SValentin Clement matchAndRewrite(fir::SelectOp op, OpAdaptor adaptor, 7528c239909SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 7538c239909SValentin Clement selectMatchAndRewrite<fir::SelectOp>(lowerTy(), op, adaptor, rewriter); 7548c239909SValentin Clement return success(); 7558c239909SValentin Clement } 7568c239909SValentin Clement }; 7578c239909SValentin Clement 758e3349fa1SAndrzej Warzynski /// `fir.load` --> `llvm.load` 759e3349fa1SAndrzej Warzynski struct LoadOpConversion : public FIROpConversion<fir::LoadOp> { 760e3349fa1SAndrzej Warzynski using FIROpConversion::FIROpConversion; 761e3349fa1SAndrzej Warzynski 762e3349fa1SAndrzej Warzynski mlir::LogicalResult 763e3349fa1SAndrzej Warzynski matchAndRewrite(fir::LoadOp load, OpAdaptor adaptor, 764e3349fa1SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 765e3349fa1SAndrzej Warzynski // fir.box is a special case because it is considered as an ssa values in 766e3349fa1SAndrzej Warzynski // fir, but it is lowered as a pointer to a descriptor. So fir.ref<fir.box> 767e3349fa1SAndrzej Warzynski // and fir.box end up being the same llvm types and loading a 768e3349fa1SAndrzej Warzynski // fir.ref<fir.box> is actually a no op in LLVM. 769e3349fa1SAndrzej Warzynski if (load.getType().isa<fir::BoxType>()) { 770e3349fa1SAndrzej Warzynski rewriter.replaceOp(load, adaptor.getOperands()[0]); 771e3349fa1SAndrzej Warzynski } else { 772e3349fa1SAndrzej Warzynski mlir::Type ty = convertType(load.getType()); 773e3349fa1SAndrzej Warzynski ArrayRef<NamedAttribute> at = load->getAttrs(); 774e3349fa1SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::LoadOp>( 775e3349fa1SAndrzej Warzynski load, ty, adaptor.getOperands(), at); 776e3349fa1SAndrzej Warzynski } 777e3349fa1SAndrzej Warzynski return success(); 778e3349fa1SAndrzej Warzynski } 779e3349fa1SAndrzej Warzynski }; 780e3349fa1SAndrzej Warzynski 7818c239909SValentin Clement /// conversion of fir::SelectRankOp to an if-then-else ladder 7828c239909SValentin Clement struct SelectRankOpConversion : public FIROpConversion<fir::SelectRankOp> { 7838c239909SValentin Clement using FIROpConversion::FIROpConversion; 7848c239909SValentin Clement 7858c239909SValentin Clement mlir::LogicalResult 7868c239909SValentin Clement matchAndRewrite(fir::SelectRankOp op, OpAdaptor adaptor, 7878c239909SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 7888c239909SValentin Clement selectMatchAndRewrite<fir::SelectRankOp>(lowerTy(), op, adaptor, rewriter); 7898c239909SValentin Clement return success(); 7908c239909SValentin Clement } 7918c239909SValentin Clement }; 7928c239909SValentin Clement 793e3349fa1SAndrzej Warzynski /// `fir.store` --> `llvm.store` 794e3349fa1SAndrzej Warzynski struct StoreOpConversion : public FIROpConversion<fir::StoreOp> { 795e3349fa1SAndrzej Warzynski using FIROpConversion::FIROpConversion; 796e3349fa1SAndrzej Warzynski 797e3349fa1SAndrzej Warzynski mlir::LogicalResult 798e3349fa1SAndrzej Warzynski matchAndRewrite(fir::StoreOp store, OpAdaptor adaptor, 799e3349fa1SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 800e3349fa1SAndrzej Warzynski if (store.value().getType().isa<fir::BoxType>()) { 801e3349fa1SAndrzej Warzynski // fir.box value is actually in memory, load it first before storing it. 802e3349fa1SAndrzej Warzynski mlir::Location loc = store.getLoc(); 803e3349fa1SAndrzej Warzynski mlir::Type boxPtrTy = adaptor.getOperands()[0].getType(); 804e3349fa1SAndrzej Warzynski auto val = rewriter.create<mlir::LLVM::LoadOp>( 805e3349fa1SAndrzej Warzynski loc, boxPtrTy.cast<mlir::LLVM::LLVMPointerType>().getElementType(), 806e3349fa1SAndrzej Warzynski adaptor.getOperands()[0]); 807e3349fa1SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>( 808e3349fa1SAndrzej Warzynski store, val, adaptor.getOperands()[1]); 809e3349fa1SAndrzej Warzynski } else { 810e3349fa1SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>( 811e3349fa1SAndrzej Warzynski store, adaptor.getOperands()[0], adaptor.getOperands()[1]); 812e3349fa1SAndrzej Warzynski } 813e3349fa1SAndrzej Warzynski return success(); 814e3349fa1SAndrzej Warzynski } 815e3349fa1SAndrzej Warzynski }; 816e3349fa1SAndrzej Warzynski 817e3349fa1SAndrzej Warzynski /// convert to LLVM IR dialect `undef` 818044d5b5dSValentin Clement struct UndefOpConversion : public FIROpConversion<fir::UndefOp> { 819044d5b5dSValentin Clement using FIROpConversion::FIROpConversion; 820044d5b5dSValentin Clement 821044d5b5dSValentin Clement mlir::LogicalResult 822044d5b5dSValentin Clement matchAndRewrite(fir::UndefOp undef, OpAdaptor, 823044d5b5dSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 824044d5b5dSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::UndefOp>( 825044d5b5dSValentin Clement undef, convertType(undef.getType())); 826044d5b5dSValentin Clement return success(); 827044d5b5dSValentin Clement } 828044d5b5dSValentin Clement }; 829a7a61359SValentin Clement 830e3349fa1SAndrzej Warzynski /// `fir.unreachable` --> `llvm.unreachable` 83132e08248SAndrzej Warzynski struct UnreachableOpConversion : public FIROpConversion<fir::UnreachableOp> { 83232e08248SAndrzej Warzynski using FIROpConversion::FIROpConversion; 83332e08248SAndrzej Warzynski 83432e08248SAndrzej Warzynski mlir::LogicalResult 83532e08248SAndrzej Warzynski matchAndRewrite(fir::UnreachableOp unreach, OpAdaptor adaptor, 83632e08248SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 83732e08248SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(unreach); 83832e08248SAndrzej Warzynski return success(); 83932e08248SAndrzej Warzynski } 84032e08248SAndrzej Warzynski }; 84132e08248SAndrzej Warzynski 842a7a61359SValentin Clement struct ZeroOpConversion : public FIROpConversion<fir::ZeroOp> { 843a7a61359SValentin Clement using FIROpConversion::FIROpConversion; 844a7a61359SValentin Clement 845a7a61359SValentin Clement mlir::LogicalResult 846a7a61359SValentin Clement matchAndRewrite(fir::ZeroOp zero, OpAdaptor, 847a7a61359SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 848a7a61359SValentin Clement auto ty = convertType(zero.getType()); 849a7a61359SValentin Clement if (ty.isa<mlir::LLVM::LLVMPointerType>()) { 850a7a61359SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(zero, ty); 851a7a61359SValentin Clement } else if (ty.isa<mlir::IntegerType>()) { 852a7a61359SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>( 853a7a61359SValentin Clement zero, ty, mlir::IntegerAttr::get(zero.getType(), 0)); 854a7a61359SValentin Clement } else if (mlir::LLVM::isCompatibleFloatingPointType(ty)) { 855a7a61359SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>( 856a7a61359SValentin Clement zero, ty, mlir::FloatAttr::get(zero.getType(), 0.0)); 857a7a61359SValentin Clement } else { 858a7a61359SValentin Clement // TODO: create ConstantAggregateZero for FIR aggregate/array types. 85952d813edSValentin Clement return rewriter.notifyMatchFailure( 86052d813edSValentin Clement zero, 861a7a61359SValentin Clement "conversion of fir.zero with aggregate type not implemented yet"); 862a7a61359SValentin Clement } 863a7a61359SValentin Clement return success(); 864a7a61359SValentin Clement } 865a7a61359SValentin Clement }; 86632e08248SAndrzej Warzynski 86754c56347SValentin Clement // Code shared between insert_value and extract_value Ops. 86854c56347SValentin Clement struct ValueOpCommon { 86954c56347SValentin Clement // Translate the arguments pertaining to any multidimensional array to 87054c56347SValentin Clement // row-major order for LLVM-IR. 87154c56347SValentin Clement static void toRowMajor(SmallVectorImpl<mlir::Attribute> &attrs, 87254c56347SValentin Clement mlir::Type ty) { 87354c56347SValentin Clement assert(ty && "type is null"); 87454c56347SValentin Clement const auto end = attrs.size(); 87554c56347SValentin Clement for (std::remove_const_t<decltype(end)> i = 0; i < end; ++i) { 87654c56347SValentin Clement if (auto seq = ty.dyn_cast<mlir::LLVM::LLVMArrayType>()) { 87754c56347SValentin Clement const auto dim = getDimension(seq); 87854c56347SValentin Clement if (dim > 1) { 87954c56347SValentin Clement auto ub = std::min(i + dim, end); 88054c56347SValentin Clement std::reverse(attrs.begin() + i, attrs.begin() + ub); 88154c56347SValentin Clement i += dim - 1; 88254c56347SValentin Clement } 88354c56347SValentin Clement ty = getArrayElementType(seq); 88454c56347SValentin Clement } else if (auto st = ty.dyn_cast<mlir::LLVM::LLVMStructType>()) { 88554c56347SValentin Clement ty = st.getBody()[attrs[i].cast<mlir::IntegerAttr>().getInt()]; 88654c56347SValentin Clement } else { 88754c56347SValentin Clement llvm_unreachable("index into invalid type"); 88854c56347SValentin Clement } 88954c56347SValentin Clement } 89054c56347SValentin Clement } 89154c56347SValentin Clement 89254c56347SValentin Clement static llvm::SmallVector<mlir::Attribute> 89354c56347SValentin Clement collectIndices(mlir::ConversionPatternRewriter &rewriter, 89454c56347SValentin Clement mlir::ArrayAttr arrAttr) { 89554c56347SValentin Clement llvm::SmallVector<mlir::Attribute> attrs; 89654c56347SValentin Clement for (auto i = arrAttr.begin(), e = arrAttr.end(); i != e; ++i) { 89754c56347SValentin Clement if (i->isa<mlir::IntegerAttr>()) { 89854c56347SValentin Clement attrs.push_back(*i); 89954c56347SValentin Clement } else { 90054c56347SValentin Clement auto fieldName = i->cast<mlir::StringAttr>().getValue(); 90154c56347SValentin Clement ++i; 90254c56347SValentin Clement auto ty = i->cast<mlir::TypeAttr>().getValue(); 90354c56347SValentin Clement auto index = ty.cast<fir::RecordType>().getFieldIndex(fieldName); 90454c56347SValentin Clement attrs.push_back(mlir::IntegerAttr::get(rewriter.getI32Type(), index)); 90554c56347SValentin Clement } 90654c56347SValentin Clement } 90754c56347SValentin Clement return attrs; 90854c56347SValentin Clement } 90954c56347SValentin Clement 91054c56347SValentin Clement private: 91154c56347SValentin Clement static unsigned getDimension(mlir::LLVM::LLVMArrayType ty) { 91254c56347SValentin Clement unsigned result = 1; 91354c56347SValentin Clement for (auto eleTy = ty.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>(); 91454c56347SValentin Clement eleTy; 91554c56347SValentin Clement eleTy = eleTy.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>()) 91654c56347SValentin Clement ++result; 91754c56347SValentin Clement return result; 91854c56347SValentin Clement } 91954c56347SValentin Clement 92054c56347SValentin Clement static mlir::Type getArrayElementType(mlir::LLVM::LLVMArrayType ty) { 92154c56347SValentin Clement auto eleTy = ty.getElementType(); 92254c56347SValentin Clement while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>()) 92354c56347SValentin Clement eleTy = arrTy.getElementType(); 92454c56347SValentin Clement return eleTy; 92554c56347SValentin Clement } 92654c56347SValentin Clement }; 92754c56347SValentin Clement 92854c56347SValentin Clement /// Extract a subobject value from an ssa-value of aggregate type 92954c56347SValentin Clement struct ExtractValueOpConversion 93054c56347SValentin Clement : public FIROpAndTypeConversion<fir::ExtractValueOp>, 93154c56347SValentin Clement public ValueOpCommon { 93254c56347SValentin Clement using FIROpAndTypeConversion::FIROpAndTypeConversion; 93354c56347SValentin Clement 93454c56347SValentin Clement mlir::LogicalResult 93554c56347SValentin Clement doRewrite(fir::ExtractValueOp extractVal, mlir::Type ty, OpAdaptor adaptor, 93654c56347SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 93754c56347SValentin Clement auto attrs = collectIndices(rewriter, extractVal.coor()); 93854c56347SValentin Clement toRowMajor(attrs, adaptor.getOperands()[0].getType()); 93954c56347SValentin Clement auto position = mlir::ArrayAttr::get(extractVal.getContext(), attrs); 94054c56347SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>( 94154c56347SValentin Clement extractVal, ty, adaptor.getOperands()[0], position); 94254c56347SValentin Clement return success(); 94354c56347SValentin Clement } 94454c56347SValentin Clement }; 94554c56347SValentin Clement 94654c56347SValentin Clement /// InsertValue is the generalized instruction for the composition of new 94754c56347SValentin Clement /// aggregate type values. 94854c56347SValentin Clement struct InsertValueOpConversion 94954c56347SValentin Clement : public FIROpAndTypeConversion<fir::InsertValueOp>, 95054c56347SValentin Clement public ValueOpCommon { 95154c56347SValentin Clement using FIROpAndTypeConversion::FIROpAndTypeConversion; 95254c56347SValentin Clement 95354c56347SValentin Clement mlir::LogicalResult 95454c56347SValentin Clement doRewrite(fir::InsertValueOp insertVal, mlir::Type ty, OpAdaptor adaptor, 95554c56347SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 95654c56347SValentin Clement auto attrs = collectIndices(rewriter, insertVal.coor()); 95754c56347SValentin Clement toRowMajor(attrs, adaptor.getOperands()[0].getType()); 95854c56347SValentin Clement auto position = mlir::ArrayAttr::get(insertVal.getContext(), attrs); 95954c56347SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 96054c56347SValentin Clement insertVal, ty, adaptor.getOperands()[0], adaptor.getOperands()[1], 96154c56347SValentin Clement position); 96254c56347SValentin Clement return success(); 96354c56347SValentin Clement } 96454c56347SValentin Clement }; 96554c56347SValentin Clement 9663ae8e442SValentin Clement /// InsertOnRange inserts a value into a sequence over a range of offsets. 9673ae8e442SValentin Clement struct InsertOnRangeOpConversion 9683ae8e442SValentin Clement : public FIROpAndTypeConversion<fir::InsertOnRangeOp> { 9693ae8e442SValentin Clement using FIROpAndTypeConversion::FIROpAndTypeConversion; 9703ae8e442SValentin Clement 9713ae8e442SValentin Clement // Increments an array of subscripts in a row major fasion. 9723ae8e442SValentin Clement void incrementSubscripts(const SmallVector<uint64_t> &dims, 9733ae8e442SValentin Clement SmallVector<uint64_t> &subscripts) const { 9743ae8e442SValentin Clement for (size_t i = dims.size(); i > 0; --i) { 9753ae8e442SValentin Clement if (++subscripts[i - 1] < dims[i - 1]) { 9763ae8e442SValentin Clement return; 9773ae8e442SValentin Clement } 9783ae8e442SValentin Clement subscripts[i - 1] = 0; 9793ae8e442SValentin Clement } 9803ae8e442SValentin Clement } 9813ae8e442SValentin Clement 9823ae8e442SValentin Clement mlir::LogicalResult 9833ae8e442SValentin Clement doRewrite(fir::InsertOnRangeOp range, mlir::Type ty, OpAdaptor adaptor, 9843ae8e442SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 9853ae8e442SValentin Clement 9863ae8e442SValentin Clement llvm::SmallVector<uint64_t> dims; 9873ae8e442SValentin Clement auto type = adaptor.getOperands()[0].getType(); 9883ae8e442SValentin Clement 9893ae8e442SValentin Clement // Iteratively extract the array dimensions from the type. 9903ae8e442SValentin Clement while (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) { 9913ae8e442SValentin Clement dims.push_back(t.getNumElements()); 9923ae8e442SValentin Clement type = t.getElementType(); 9933ae8e442SValentin Clement } 9943ae8e442SValentin Clement 9953ae8e442SValentin Clement SmallVector<uint64_t> lBounds; 9963ae8e442SValentin Clement SmallVector<uint64_t> uBounds; 9973ae8e442SValentin Clement 9983ae8e442SValentin Clement // Extract integer value from the attribute 9993ae8e442SValentin Clement SmallVector<int64_t> coordinates = llvm::to_vector<4>( 10003ae8e442SValentin Clement llvm::map_range(range.coor(), [](Attribute a) -> int64_t { 10013ae8e442SValentin Clement return a.cast<IntegerAttr>().getInt(); 10023ae8e442SValentin Clement })); 10033ae8e442SValentin Clement 10043ae8e442SValentin Clement // Unzip the upper and lower bound and convert to a row major format. 10053ae8e442SValentin Clement for (auto i = coordinates.rbegin(), e = coordinates.rend(); i != e; ++i) { 10063ae8e442SValentin Clement uBounds.push_back(*i++); 10073ae8e442SValentin Clement lBounds.push_back(*i); 10083ae8e442SValentin Clement } 10093ae8e442SValentin Clement 10103ae8e442SValentin Clement auto &subscripts = lBounds; 10113ae8e442SValentin Clement auto loc = range.getLoc(); 10123ae8e442SValentin Clement mlir::Value lastOp = adaptor.getOperands()[0]; 10133ae8e442SValentin Clement mlir::Value insertVal = adaptor.getOperands()[1]; 10143ae8e442SValentin Clement 10153ae8e442SValentin Clement auto i64Ty = rewriter.getI64Type(); 10163ae8e442SValentin Clement while (subscripts != uBounds) { 10173ae8e442SValentin Clement // Convert uint64_t's to Attribute's. 10183ae8e442SValentin Clement SmallVector<mlir::Attribute> subscriptAttrs; 10193ae8e442SValentin Clement for (const auto &subscript : subscripts) 10203ae8e442SValentin Clement subscriptAttrs.push_back(IntegerAttr::get(i64Ty, subscript)); 10213ae8e442SValentin Clement lastOp = rewriter.create<mlir::LLVM::InsertValueOp>( 10223ae8e442SValentin Clement loc, ty, lastOp, insertVal, 10233ae8e442SValentin Clement ArrayAttr::get(range.getContext(), subscriptAttrs)); 10243ae8e442SValentin Clement 10253ae8e442SValentin Clement incrementSubscripts(dims, subscripts); 10263ae8e442SValentin Clement } 10273ae8e442SValentin Clement 10283ae8e442SValentin Clement // Convert uint64_t's to Attribute's. 10293ae8e442SValentin Clement SmallVector<mlir::Attribute> subscriptAttrs; 10303ae8e442SValentin Clement for (const auto &subscript : subscripts) 10313ae8e442SValentin Clement subscriptAttrs.push_back( 10323ae8e442SValentin Clement IntegerAttr::get(rewriter.getI64Type(), subscript)); 10333ae8e442SValentin Clement mlir::ArrayRef<mlir::Attribute> arrayRef(subscriptAttrs); 10343ae8e442SValentin Clement 10353ae8e442SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 10363ae8e442SValentin Clement range, ty, lastOp, insertVal, 10373ae8e442SValentin Clement ArrayAttr::get(range.getContext(), arrayRef)); 10383ae8e442SValentin Clement 10393ae8e442SValentin Clement return success(); 10403ae8e442SValentin Clement } 10413ae8e442SValentin Clement }; 10427b5132daSValentin Clement 10437b5132daSValentin Clement // 10447b5132daSValentin Clement // Primitive operations on Complex types 10457b5132daSValentin Clement // 10467b5132daSValentin Clement 10477b5132daSValentin Clement /// Generate inline code for complex addition/subtraction 10487b5132daSValentin Clement template <typename LLVMOP, typename OPTY> 10497b5132daSValentin Clement mlir::LLVM::InsertValueOp complexSum(OPTY sumop, mlir::ValueRange opnds, 10507b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter, 10517b5132daSValentin Clement fir::LLVMTypeConverter &lowering) { 10527b5132daSValentin Clement mlir::Value a = opnds[0]; 10537b5132daSValentin Clement mlir::Value b = opnds[1]; 10547b5132daSValentin Clement auto loc = sumop.getLoc(); 10557b5132daSValentin Clement auto ctx = sumop.getContext(); 10567b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 10577b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 10587b5132daSValentin Clement mlir::Type eleTy = lowering.convertType(getComplexEleTy(sumop.getType())); 10597b5132daSValentin Clement mlir::Type ty = lowering.convertType(sumop.getType()); 10607b5132daSValentin Clement auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0); 10617b5132daSValentin Clement auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1); 10627b5132daSValentin Clement auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0); 10637b5132daSValentin Clement auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1); 10647b5132daSValentin Clement auto rx = rewriter.create<LLVMOP>(loc, eleTy, x0, x1); 10657b5132daSValentin Clement auto ry = rewriter.create<LLVMOP>(loc, eleTy, y0, y1); 10667b5132daSValentin Clement auto r0 = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 10677b5132daSValentin Clement auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r0, rx, c0); 10687b5132daSValentin Clement return rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ry, c1); 10697b5132daSValentin Clement } 10707b5132daSValentin Clement 10717b5132daSValentin Clement struct AddcOpConversion : public FIROpConversion<fir::AddcOp> { 10727b5132daSValentin Clement using FIROpConversion::FIROpConversion; 10737b5132daSValentin Clement 10747b5132daSValentin Clement mlir::LogicalResult 10757b5132daSValentin Clement matchAndRewrite(fir::AddcOp addc, OpAdaptor adaptor, 10767b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 10777b5132daSValentin Clement // given: (x + iy) + (x' + iy') 10787b5132daSValentin Clement // result: (x + x') + i(y + y') 10797b5132daSValentin Clement auto r = complexSum<mlir::LLVM::FAddOp>(addc, adaptor.getOperands(), 10807b5132daSValentin Clement rewriter, lowerTy()); 10817b5132daSValentin Clement rewriter.replaceOp(addc, r.getResult()); 10827b5132daSValentin Clement return success(); 10837b5132daSValentin Clement } 10847b5132daSValentin Clement }; 10857b5132daSValentin Clement 10867b5132daSValentin Clement struct SubcOpConversion : public FIROpConversion<fir::SubcOp> { 10877b5132daSValentin Clement using FIROpConversion::FIROpConversion; 10887b5132daSValentin Clement 10897b5132daSValentin Clement mlir::LogicalResult 10907b5132daSValentin Clement matchAndRewrite(fir::SubcOp subc, OpAdaptor adaptor, 10917b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 10927b5132daSValentin Clement // given: (x + iy) - (x' + iy') 10937b5132daSValentin Clement // result: (x - x') + i(y - y') 10947b5132daSValentin Clement auto r = complexSum<mlir::LLVM::FSubOp>(subc, adaptor.getOperands(), 10957b5132daSValentin Clement rewriter, lowerTy()); 10967b5132daSValentin Clement rewriter.replaceOp(subc, r.getResult()); 10977b5132daSValentin Clement return success(); 10987b5132daSValentin Clement } 10997b5132daSValentin Clement }; 11007b5132daSValentin Clement 11017b5132daSValentin Clement /// Inlined complex multiply 11027b5132daSValentin Clement struct MulcOpConversion : public FIROpConversion<fir::MulcOp> { 11037b5132daSValentin Clement using FIROpConversion::FIROpConversion; 11047b5132daSValentin Clement 11057b5132daSValentin Clement mlir::LogicalResult 11067b5132daSValentin Clement matchAndRewrite(fir::MulcOp mulc, OpAdaptor adaptor, 11077b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 11087b5132daSValentin Clement // TODO: Can we use a call to __muldc3 ? 11097b5132daSValentin Clement // given: (x + iy) * (x' + iy') 11107b5132daSValentin Clement // result: (xx'-yy')+i(xy'+yx') 11117b5132daSValentin Clement mlir::Value a = adaptor.getOperands()[0]; 11127b5132daSValentin Clement mlir::Value b = adaptor.getOperands()[1]; 11137b5132daSValentin Clement auto loc = mulc.getLoc(); 11147b5132daSValentin Clement auto *ctx = mulc.getContext(); 11157b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 11167b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 11177b5132daSValentin Clement mlir::Type eleTy = convertType(getComplexEleTy(mulc.getType())); 11187b5132daSValentin Clement mlir::Type ty = convertType(mulc.getType()); 11197b5132daSValentin Clement auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0); 11207b5132daSValentin Clement auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1); 11217b5132daSValentin Clement auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0); 11227b5132daSValentin Clement auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1); 11237b5132daSValentin Clement auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1); 11247b5132daSValentin Clement auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1); 11257b5132daSValentin Clement auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1); 11267b5132daSValentin Clement auto ri = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xy, yx); 11277b5132daSValentin Clement auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1); 11287b5132daSValentin Clement auto rr = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, xx, yy); 11297b5132daSValentin Clement auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 11307b5132daSValentin Clement auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0); 11317b5132daSValentin Clement auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1); 11327b5132daSValentin Clement rewriter.replaceOp(mulc, r0.getResult()); 11337b5132daSValentin Clement return success(); 11347b5132daSValentin Clement } 11357b5132daSValentin Clement }; 11367b5132daSValentin Clement 11377b5132daSValentin Clement /// Inlined complex division 11387b5132daSValentin Clement struct DivcOpConversion : public FIROpConversion<fir::DivcOp> { 11397b5132daSValentin Clement using FIROpConversion::FIROpConversion; 11407b5132daSValentin Clement 11417b5132daSValentin Clement mlir::LogicalResult 11427b5132daSValentin Clement matchAndRewrite(fir::DivcOp divc, OpAdaptor adaptor, 11437b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 11447b5132daSValentin Clement // TODO: Can we use a call to __divdc3 instead? 11457b5132daSValentin Clement // Just generate inline code for now. 11467b5132daSValentin Clement // given: (x + iy) / (x' + iy') 11477b5132daSValentin Clement // result: ((xx'+yy')/d) + i((yx'-xy')/d) where d = x'x' + y'y' 11487b5132daSValentin Clement mlir::Value a = adaptor.getOperands()[0]; 11497b5132daSValentin Clement mlir::Value b = adaptor.getOperands()[1]; 11507b5132daSValentin Clement auto loc = divc.getLoc(); 11517b5132daSValentin Clement auto *ctx = divc.getContext(); 11527b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 11537b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 11547b5132daSValentin Clement mlir::Type eleTy = convertType(getComplexEleTy(divc.getType())); 11557b5132daSValentin Clement mlir::Type ty = convertType(divc.getType()); 11567b5132daSValentin Clement auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0); 11577b5132daSValentin Clement auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1); 11587b5132daSValentin Clement auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0); 11597b5132daSValentin Clement auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1); 11607b5132daSValentin Clement auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1); 11617b5132daSValentin Clement auto x1x1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x1, x1); 11627b5132daSValentin Clement auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1); 11637b5132daSValentin Clement auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1); 11647b5132daSValentin Clement auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1); 11657b5132daSValentin Clement auto y1y1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y1, y1); 11667b5132daSValentin Clement auto d = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, x1x1, y1y1); 11677b5132daSValentin Clement auto rrn = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xx, yy); 11687b5132daSValentin Clement auto rin = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, yx, xy); 11697b5132daSValentin Clement auto rr = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rrn, d); 11707b5132daSValentin Clement auto ri = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rin, d); 11717b5132daSValentin Clement auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 11727b5132daSValentin Clement auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0); 11737b5132daSValentin Clement auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1); 11747b5132daSValentin Clement rewriter.replaceOp(divc, r0.getResult()); 11757b5132daSValentin Clement return success(); 11767b5132daSValentin Clement } 11777b5132daSValentin Clement }; 11787b5132daSValentin Clement 11797b5132daSValentin Clement /// Inlined complex negation 11807b5132daSValentin Clement struct NegcOpConversion : public FIROpConversion<fir::NegcOp> { 11817b5132daSValentin Clement using FIROpConversion::FIROpConversion; 11827b5132daSValentin Clement 11837b5132daSValentin Clement mlir::LogicalResult 11847b5132daSValentin Clement matchAndRewrite(fir::NegcOp neg, OpAdaptor adaptor, 11857b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 11867b5132daSValentin Clement // given: -(x + iy) 11877b5132daSValentin Clement // result: -x - iy 11887b5132daSValentin Clement auto *ctxt = neg.getContext(); 11897b5132daSValentin Clement auto eleTy = convertType(getComplexEleTy(neg.getType())); 11907b5132daSValentin Clement auto ty = convertType(neg.getType()); 11917b5132daSValentin Clement auto loc = neg.getLoc(); 11927b5132daSValentin Clement mlir::Value o0 = adaptor.getOperands()[0]; 11937b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0)); 11947b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1)); 11957b5132daSValentin Clement auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c0); 11967b5132daSValentin Clement auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c1); 11977b5132daSValentin Clement auto nrp = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, rp); 11987b5132daSValentin Clement auto nip = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, ip); 11997b5132daSValentin Clement auto r = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, o0, nrp, c0); 12007b5132daSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(neg, ty, r, nip, c1); 12017b5132daSValentin Clement return success(); 12027b5132daSValentin Clement } 12037b5132daSValentin Clement }; 12047b5132daSValentin Clement 1205044d5b5dSValentin Clement } // namespace 1206044d5b5dSValentin Clement 1207044d5b5dSValentin Clement namespace { 1208044d5b5dSValentin Clement /// Convert FIR dialect to LLVM dialect 1209044d5b5dSValentin Clement /// 1210044d5b5dSValentin Clement /// This pass lowers all FIR dialect operations to LLVM IR dialect. An 1211044d5b5dSValentin Clement /// MLIR pass is used to lower residual Std dialect to LLVM IR dialect. 1212044d5b5dSValentin Clement /// 1213044d5b5dSValentin Clement /// This pass is not complete yet. We are upstreaming it in small patches. 1214044d5b5dSValentin Clement class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> { 1215044d5b5dSValentin Clement public: 1216044d5b5dSValentin Clement mlir::ModuleOp getModule() { return getOperation(); } 1217044d5b5dSValentin Clement 1218044d5b5dSValentin Clement void runOnOperation() override final { 12197b5132daSValentin Clement auto mod = getModule(); 12207b5132daSValentin Clement if (!forcedTargetTriple.empty()) { 12217b5132daSValentin Clement fir::setTargetTriple(mod, forcedTargetTriple); 12227b5132daSValentin Clement } 12237b5132daSValentin Clement 1224044d5b5dSValentin Clement auto *context = getModule().getContext(); 1225044d5b5dSValentin Clement fir::LLVMTypeConverter typeConverter{getModule()}; 1226044d5b5dSValentin Clement mlir::OwningRewritePatternList pattern(context); 1227df3b9810SValentin Clement pattern.insert< 12281e6d9c06SDiana Picus AddcOpConversion, AddrOfOpConversion, AllocaOpConversion, 12291e6d9c06SDiana Picus BoxAddrOpConversion, BoxDimsOpConversion, BoxEleSizeOpConversion, 12301e6d9c06SDiana Picus BoxIsAllocOpConversion, BoxIsArrayOpConversion, BoxIsPtrOpConversion, 12311e6d9c06SDiana Picus BoxRankOpConversion, CallOpConversion, ConvertOpConversion, 1232*9534e361SValentin Clement DispatchOpConversion, DispatchTableOpConversion, DTEntryOpConversion, 12331e6d9c06SDiana Picus DivcOpConversion, ExtractValueOpConversion, HasValueOpConversion, 12341e6d9c06SDiana Picus GlobalOpConversion, InsertOnRangeOpConversion, InsertValueOpConversion, 12351e6d9c06SDiana Picus LoadOpConversion, NegcOpConversion, MulcOpConversion, 12361e6d9c06SDiana Picus SelectOpConversion, SelectRankOpConversion, StoreOpConversion, 12371e6d9c06SDiana Picus SubcOpConversion, UndefOpConversion, UnreachableOpConversion, 12381e6d9c06SDiana Picus ZeroOpConversion>(typeConverter); 1239044d5b5dSValentin Clement mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern); 1240044d5b5dSValentin Clement mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter, 1241044d5b5dSValentin Clement pattern); 1242044d5b5dSValentin Clement mlir::ConversionTarget target{*context}; 1243044d5b5dSValentin Clement target.addLegalDialect<mlir::LLVM::LLVMDialect>(); 1244044d5b5dSValentin Clement 1245044d5b5dSValentin Clement // required NOPs for applying a full conversion 1246044d5b5dSValentin Clement target.addLegalOp<mlir::ModuleOp>(); 1247044d5b5dSValentin Clement 1248044d5b5dSValentin Clement // apply the patterns 1249044d5b5dSValentin Clement if (mlir::failed(mlir::applyFullConversion(getModule(), target, 1250044d5b5dSValentin Clement std::move(pattern)))) { 1251044d5b5dSValentin Clement signalPassFailure(); 1252044d5b5dSValentin Clement } 1253044d5b5dSValentin Clement } 1254044d5b5dSValentin Clement }; 1255044d5b5dSValentin Clement } // namespace 1256044d5b5dSValentin Clement 1257044d5b5dSValentin Clement std::unique_ptr<mlir::Pass> fir::createFIRToLLVMPass() { 1258044d5b5dSValentin Clement return std::make_unique<FIRToLLVMLowering>(); 1259044d5b5dSValentin Clement } 1260