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" 18af6ee580SValentin Clement #include "flang/Optimizer/Support/TypeCode.h" 19044d5b5dSValentin Clement #include "mlir/Conversion/ArithmeticToLLVM/ArithmeticToLLVM.h" 20044d5b5dSValentin Clement #include "mlir/Conversion/LLVMCommon/Pattern.h" 21044d5b5dSValentin Clement #include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h" 22044d5b5dSValentin Clement #include "mlir/IR/BuiltinTypes.h" 233ae8e442SValentin Clement #include "mlir/IR/Matchers.h" 24044d5b5dSValentin Clement #include "mlir/Pass/Pass.h" 25044d5b5dSValentin Clement #include "llvm/ADT/ArrayRef.h" 26044d5b5dSValentin Clement 27044d5b5dSValentin Clement #define DEBUG_TYPE "flang-codegen" 28044d5b5dSValentin Clement 29044d5b5dSValentin Clement // fir::LLVMTypeConverter for converting to LLVM IR dialect types. 30044d5b5dSValentin Clement #include "TypeConverter.h" 31044d5b5dSValentin Clement 32af6ee580SValentin Clement // TODO: This should really be recovered from the specified target. 33af6ee580SValentin Clement static constexpr unsigned defaultAlign = 8; 34af6ee580SValentin Clement 35b6e44ecdSValentin Clement /// `fir.box` attribute values as defined for CFI_attribute_t in 36b6e44ecdSValentin Clement /// flang/ISO_Fortran_binding.h. 37b6e44ecdSValentin Clement static constexpr unsigned kAttrPointer = CFI_attribute_pointer; 38b6e44ecdSValentin Clement static constexpr unsigned kAttrAllocatable = CFI_attribute_allocatable; 39b6e44ecdSValentin Clement 401e6d9c06SDiana Picus static mlir::LLVM::ConstantOp 411e6d9c06SDiana Picus genConstantIndex(mlir::Location loc, mlir::Type ity, 421e6d9c06SDiana Picus mlir::ConversionPatternRewriter &rewriter, 431e6d9c06SDiana Picus std::int64_t offset) { 441e6d9c06SDiana Picus auto cattr = rewriter.getI64IntegerAttr(offset); 451e6d9c06SDiana Picus return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr); 461e6d9c06SDiana Picus } 471e6d9c06SDiana Picus 4839f4ef81SValentin Clement static Block *createBlock(mlir::ConversionPatternRewriter &rewriter, 4939f4ef81SValentin Clement mlir::Block *insertBefore) { 5039f4ef81SValentin Clement assert(insertBefore && "expected valid insertion block"); 5139f4ef81SValentin Clement return rewriter.createBlock(insertBefore->getParent(), 5239f4ef81SValentin Clement mlir::Region::iterator(insertBefore)); 5339f4ef81SValentin Clement } 5439f4ef81SValentin Clement 55044d5b5dSValentin Clement namespace { 56044d5b5dSValentin Clement /// FIR conversion pattern template 57044d5b5dSValentin Clement template <typename FromOp> 58044d5b5dSValentin Clement class FIROpConversion : public mlir::ConvertOpToLLVMPattern<FromOp> { 59044d5b5dSValentin Clement public: 60044d5b5dSValentin Clement explicit FIROpConversion(fir::LLVMTypeConverter &lowering) 61044d5b5dSValentin Clement : mlir::ConvertOpToLLVMPattern<FromOp>(lowering) {} 62044d5b5dSValentin Clement 63044d5b5dSValentin Clement protected: 64044d5b5dSValentin Clement mlir::Type convertType(mlir::Type ty) const { 65044d5b5dSValentin Clement return lowerTy().convertType(ty); 66044d5b5dSValentin Clement } 67044d5b5dSValentin Clement 68df3b9810SValentin Clement mlir::LLVM::ConstantOp 69af6ee580SValentin Clement genI32Constant(mlir::Location loc, mlir::ConversionPatternRewriter &rewriter, 70af6ee580SValentin Clement int value) const { 71af6ee580SValentin Clement mlir::Type i32Ty = rewriter.getI32Type(); 72af6ee580SValentin Clement mlir::IntegerAttr attr = rewriter.getI32IntegerAttr(value); 73af6ee580SValentin Clement return rewriter.create<mlir::LLVM::ConstantOp>(loc, i32Ty, attr); 74af6ee580SValentin Clement } 75af6ee580SValentin Clement 76af6ee580SValentin Clement mlir::LLVM::ConstantOp 77df3b9810SValentin Clement genConstantOffset(mlir::Location loc, 78df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter, 79df3b9810SValentin Clement int offset) const { 80af6ee580SValentin Clement mlir::Type ity = lowerTy().offsetType(); 81af6ee580SValentin Clement mlir::IntegerAttr cattr = rewriter.getI32IntegerAttr(offset); 82df3b9810SValentin Clement return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr); 83df3b9810SValentin Clement } 84df3b9810SValentin Clement 85b6e44ecdSValentin Clement /// Construct code sequence to extract the specifc value from a `fir.box`. 86b6e44ecdSValentin Clement mlir::Value getValueFromBox(mlir::Location loc, mlir::Value box, 87df3b9810SValentin Clement mlir::Type resultTy, 88b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter, 89b6e44ecdSValentin Clement unsigned boxValue) const { 90df3b9810SValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 91b6e44ecdSValentin Clement mlir::LLVM::ConstantOp cValuePos = 92b6e44ecdSValentin Clement genConstantOffset(loc, rewriter, boxValue); 93df3b9810SValentin Clement auto pty = mlir::LLVM::LLVMPointerType::get(resultTy); 94df3b9810SValentin Clement auto p = rewriter.create<mlir::LLVM::GEPOp>( 95b6e44ecdSValentin Clement loc, pty, mlir::ValueRange{box, c0, cValuePos}); 96df3b9810SValentin Clement return rewriter.create<mlir::LLVM::LoadOp>(loc, resultTy, p); 97df3b9810SValentin Clement } 98df3b9810SValentin Clement 99df3b9810SValentin Clement /// Method to construct code sequence to get the triple for dimension `dim` 100df3b9810SValentin Clement /// from a box. 101df3b9810SValentin Clement SmallVector<mlir::Value, 3> 102df3b9810SValentin Clement getDimsFromBox(mlir::Location loc, ArrayRef<mlir::Type> retTys, 103df3b9810SValentin Clement mlir::Value box, mlir::Value dim, 104df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 105df3b9810SValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 106df3b9810SValentin Clement mlir::LLVM::ConstantOp cDims = 107df3b9810SValentin Clement genConstantOffset(loc, rewriter, kDimsPosInBox); 108df3b9810SValentin Clement mlir::LLVM::LoadOp l0 = 109df3b9810SValentin Clement loadFromOffset(loc, box, c0, cDims, dim, 0, retTys[0], rewriter); 110df3b9810SValentin Clement mlir::LLVM::LoadOp l1 = 111df3b9810SValentin Clement loadFromOffset(loc, box, c0, cDims, dim, 1, retTys[1], rewriter); 112df3b9810SValentin Clement mlir::LLVM::LoadOp l2 = 113df3b9810SValentin Clement loadFromOffset(loc, box, c0, cDims, dim, 2, retTys[2], rewriter); 114df3b9810SValentin Clement return {l0.getResult(), l1.getResult(), l2.getResult()}; 115df3b9810SValentin Clement } 116df3b9810SValentin Clement 117df3b9810SValentin Clement mlir::LLVM::LoadOp 118df3b9810SValentin Clement loadFromOffset(mlir::Location loc, mlir::Value a, mlir::LLVM::ConstantOp c0, 119df3b9810SValentin Clement mlir::LLVM::ConstantOp cDims, mlir::Value dim, int off, 120df3b9810SValentin Clement mlir::Type ty, 121df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 122df3b9810SValentin Clement auto pty = mlir::LLVM::LLVMPointerType::get(ty); 123df3b9810SValentin Clement mlir::LLVM::ConstantOp c = genConstantOffset(loc, rewriter, off); 124df3b9810SValentin Clement mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, a, c0, cDims, dim, c); 125df3b9810SValentin Clement return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p); 126df3b9810SValentin Clement } 127df3b9810SValentin Clement 128df3b9810SValentin Clement /// Read base address from a fir.box. Returned address has type ty. 129df3b9810SValentin Clement mlir::Value 130df3b9810SValentin Clement loadBaseAddrFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box, 131df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 132df3b9810SValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 133df3b9810SValentin Clement mlir::LLVM::ConstantOp cAddr = 134df3b9810SValentin Clement genConstantOffset(loc, rewriter, kAddrPosInBox); 135df3b9810SValentin Clement auto pty = mlir::LLVM::LLVMPointerType::get(ty); 136df3b9810SValentin Clement mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cAddr); 137df3b9810SValentin Clement return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p); 138df3b9810SValentin Clement } 139df3b9810SValentin Clement 140df3b9810SValentin Clement mlir::Value 141df3b9810SValentin Clement loadElementSizeFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box, 142df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 143df3b9810SValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 144df3b9810SValentin Clement mlir::LLVM::ConstantOp cElemLen = 145df3b9810SValentin Clement genConstantOffset(loc, rewriter, kElemLenPosInBox); 146df3b9810SValentin Clement auto pty = mlir::LLVM::LLVMPointerType::get(ty); 147df3b9810SValentin Clement mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cElemLen); 148df3b9810SValentin Clement return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p); 149df3b9810SValentin Clement } 150df3b9810SValentin Clement 151b6e44ecdSValentin Clement // Load the attribute from the \p box and perform a check against \p maskValue 152b6e44ecdSValentin Clement // The final comparison is implemented as `(attribute & maskValue) != 0`. 153b6e44ecdSValentin Clement mlir::Value genBoxAttributeCheck(mlir::Location loc, mlir::Value box, 154b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter, 155b6e44ecdSValentin Clement unsigned maskValue) const { 156b6e44ecdSValentin Clement mlir::Type attrTy = rewriter.getI32Type(); 157b6e44ecdSValentin Clement mlir::Value attribute = 158b6e44ecdSValentin Clement getValueFromBox(loc, box, attrTy, rewriter, kAttributePosInBox); 159b6e44ecdSValentin Clement mlir::LLVM::ConstantOp attrMask = 160b6e44ecdSValentin Clement genConstantOffset(loc, rewriter, maskValue); 161b6e44ecdSValentin Clement auto maskRes = 162b6e44ecdSValentin Clement rewriter.create<mlir::LLVM::AndOp>(loc, attrTy, attribute, attrMask); 163b6e44ecdSValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 164b6e44ecdSValentin Clement return rewriter.create<mlir::LLVM::ICmpOp>( 165b6e44ecdSValentin Clement loc, mlir::LLVM::ICmpPredicate::ne, maskRes, c0); 166b6e44ecdSValentin Clement } 167b6e44ecdSValentin Clement 168af6ee580SValentin Clement // Get the element type given an LLVM type that is of the form 169af6ee580SValentin Clement // [llvm.ptr](array|struct|vector)+ and the provided indexes. 170af6ee580SValentin Clement static mlir::Type getBoxEleTy(mlir::Type type, 171af6ee580SValentin Clement llvm::ArrayRef<unsigned> indexes) { 172af6ee580SValentin Clement if (auto t = type.dyn_cast<mlir::LLVM::LLVMPointerType>()) 173af6ee580SValentin Clement type = t.getElementType(); 174af6ee580SValentin Clement for (auto i : indexes) { 175af6ee580SValentin Clement if (auto t = type.dyn_cast<mlir::LLVM::LLVMStructType>()) { 176af6ee580SValentin Clement assert(!t.isOpaque() && i < t.getBody().size()); 177af6ee580SValentin Clement type = t.getBody()[i]; 178af6ee580SValentin Clement } else if (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) { 179af6ee580SValentin Clement type = t.getElementType(); 180af6ee580SValentin Clement } else if (auto t = type.dyn_cast<mlir::VectorType>()) { 181af6ee580SValentin Clement type = t.getElementType(); 182af6ee580SValentin Clement } else { 183af6ee580SValentin Clement fir::emitFatalError(mlir::UnknownLoc::get(type.getContext()), 184af6ee580SValentin Clement "request for invalid box element type"); 185af6ee580SValentin Clement } 186af6ee580SValentin Clement } 187af6ee580SValentin Clement return type; 188af6ee580SValentin Clement } 189af6ee580SValentin Clement 190df3b9810SValentin Clement template <typename... ARGS> 191df3b9810SValentin Clement mlir::LLVM::GEPOp genGEP(mlir::Location loc, mlir::Type ty, 192df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter, 193df3b9810SValentin Clement mlir::Value base, ARGS... args) const { 194df3b9810SValentin Clement SmallVector<mlir::Value> cv{args...}; 195df3b9810SValentin Clement return rewriter.create<mlir::LLVM::GEPOp>(loc, ty, base, cv); 196df3b9810SValentin Clement } 197df3b9810SValentin Clement 1981e6d9c06SDiana Picus /// Perform an extension or truncation as needed on an integer value. Lowering 1991e6d9c06SDiana Picus /// to the specific target may involve some sign-extending or truncation of 2001e6d9c06SDiana Picus /// values, particularly to fit them from abstract box types to the 2011e6d9c06SDiana Picus /// appropriate reified structures. 2021e6d9c06SDiana Picus mlir::Value integerCast(mlir::Location loc, 2031e6d9c06SDiana Picus mlir::ConversionPatternRewriter &rewriter, 2041e6d9c06SDiana Picus mlir::Type ty, mlir::Value val) const { 2051e6d9c06SDiana Picus auto valTy = val.getType(); 2061e6d9c06SDiana Picus // If the value was not yet lowered, lower its type so that it can 2071e6d9c06SDiana Picus // be used in getPrimitiveTypeSizeInBits. 2081e6d9c06SDiana Picus if (!valTy.isa<mlir::IntegerType>()) 2091e6d9c06SDiana Picus valTy = convertType(valTy); 2101e6d9c06SDiana Picus auto toSize = mlir::LLVM::getPrimitiveTypeSizeInBits(ty); 2111e6d9c06SDiana Picus auto fromSize = mlir::LLVM::getPrimitiveTypeSizeInBits(valTy); 2121e6d9c06SDiana Picus if (toSize < fromSize) 2131e6d9c06SDiana Picus return rewriter.create<mlir::LLVM::TruncOp>(loc, ty, val); 2141e6d9c06SDiana Picus if (toSize > fromSize) 2151e6d9c06SDiana Picus return rewriter.create<mlir::LLVM::SExtOp>(loc, ty, val); 2161e6d9c06SDiana Picus return val; 2171e6d9c06SDiana Picus } 2181e6d9c06SDiana Picus 219044d5b5dSValentin Clement fir::LLVMTypeConverter &lowerTy() const { 220044d5b5dSValentin Clement return *static_cast<fir::LLVMTypeConverter *>(this->getTypeConverter()); 221044d5b5dSValentin Clement } 222044d5b5dSValentin Clement }; 223044d5b5dSValentin Clement 2243ae8e442SValentin Clement /// FIR conversion pattern template 2253ae8e442SValentin Clement template <typename FromOp> 2263ae8e442SValentin Clement class FIROpAndTypeConversion : public FIROpConversion<FromOp> { 2273ae8e442SValentin Clement public: 2283ae8e442SValentin Clement using FIROpConversion<FromOp>::FIROpConversion; 2293ae8e442SValentin Clement using OpAdaptor = typename FromOp::Adaptor; 2303ae8e442SValentin Clement 2313ae8e442SValentin Clement mlir::LogicalResult 2323ae8e442SValentin Clement matchAndRewrite(FromOp op, OpAdaptor adaptor, 2333ae8e442SValentin Clement mlir::ConversionPatternRewriter &rewriter) const final { 2343ae8e442SValentin Clement mlir::Type ty = this->convertType(op.getType()); 2353ae8e442SValentin Clement return doRewrite(op, ty, adaptor, rewriter); 2363ae8e442SValentin Clement } 2373ae8e442SValentin Clement 2383ae8e442SValentin Clement virtual mlir::LogicalResult 2393ae8e442SValentin Clement doRewrite(FromOp addr, mlir::Type ty, OpAdaptor adaptor, 2403ae8e442SValentin Clement mlir::ConversionPatternRewriter &rewriter) const = 0; 2413ae8e442SValentin Clement }; 2423ae8e442SValentin Clement 243420ad7ceSAndrzej Warzynski /// Create value signaling an absent optional argument in a call, e.g. 244420ad7ceSAndrzej Warzynski /// `fir.absent !fir.ref<i64>` --> `llvm.mlir.null : !llvm.ptr<i64>` 245420ad7ceSAndrzej Warzynski struct AbsentOpConversion : public FIROpConversion<fir::AbsentOp> { 246420ad7ceSAndrzej Warzynski using FIROpConversion::FIROpConversion; 247420ad7ceSAndrzej Warzynski 248420ad7ceSAndrzej Warzynski mlir::LogicalResult 249420ad7ceSAndrzej Warzynski matchAndRewrite(fir::AbsentOp absent, OpAdaptor, 250420ad7ceSAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 251420ad7ceSAndrzej Warzynski mlir::Type ty = convertType(absent.getType()); 252420ad7ceSAndrzej Warzynski mlir::Location loc = absent.getLoc(); 253420ad7ceSAndrzej Warzynski 254420ad7ceSAndrzej Warzynski if (absent.getType().isa<fir::BoxCharType>()) { 255420ad7ceSAndrzej Warzynski auto structTy = ty.cast<mlir::LLVM::LLVMStructType>(); 256420ad7ceSAndrzej Warzynski assert(!structTy.isOpaque() && !structTy.getBody().empty()); 257420ad7ceSAndrzej Warzynski auto undefStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 258420ad7ceSAndrzej Warzynski auto nullField = 259420ad7ceSAndrzej Warzynski rewriter.create<mlir::LLVM::NullOp>(loc, structTy.getBody()[0]); 260420ad7ceSAndrzej Warzynski mlir::MLIRContext *ctx = absent.getContext(); 261420ad7ceSAndrzej Warzynski auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 262420ad7ceSAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 263420ad7ceSAndrzej Warzynski absent, ty, undefStruct, nullField, c0); 264420ad7ceSAndrzej Warzynski } else { 265420ad7ceSAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(absent, ty); 266420ad7ceSAndrzej Warzynski } 267420ad7ceSAndrzej Warzynski return success(); 268420ad7ceSAndrzej Warzynski } 269420ad7ceSAndrzej Warzynski }; 270420ad7ceSAndrzej Warzynski 2710c4a7a52SValentin Clement // Lower `fir.address_of` operation to `llvm.address_of` operation. 272044d5b5dSValentin Clement struct AddrOfOpConversion : public FIROpConversion<fir::AddrOfOp> { 273044d5b5dSValentin Clement using FIROpConversion::FIROpConversion; 274044d5b5dSValentin Clement 275044d5b5dSValentin Clement mlir::LogicalResult 276044d5b5dSValentin Clement matchAndRewrite(fir::AddrOfOp addr, OpAdaptor adaptor, 277044d5b5dSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 278044d5b5dSValentin Clement auto ty = convertType(addr.getType()); 279044d5b5dSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::AddressOfOp>( 280044d5b5dSValentin Clement addr, ty, addr.symbol().getRootReference().getValue()); 281044d5b5dSValentin Clement return success(); 282044d5b5dSValentin Clement } 283044d5b5dSValentin Clement }; 2841e6d9c06SDiana Picus } // namespace 2851e6d9c06SDiana Picus 2861e6d9c06SDiana Picus /// Lookup the function to compute the memory size of this parametric derived 2871e6d9c06SDiana Picus /// type. The size of the object may depend on the LEN type parameters of the 2881e6d9c06SDiana Picus /// derived type. 2891e6d9c06SDiana Picus static mlir::LLVM::LLVMFuncOp 2901e6d9c06SDiana Picus getDependentTypeMemSizeFn(fir::RecordType recTy, fir::AllocaOp op, 2911e6d9c06SDiana Picus mlir::ConversionPatternRewriter &rewriter) { 2921e6d9c06SDiana Picus auto module = op->getParentOfType<mlir::ModuleOp>(); 2931e6d9c06SDiana Picus std::string name = recTy.getName().str() + "P.mem.size"; 2941e6d9c06SDiana Picus return module.lookupSymbol<mlir::LLVM::LLVMFuncOp>(name); 2951e6d9c06SDiana Picus } 2961e6d9c06SDiana Picus 2971e6d9c06SDiana Picus namespace { 2981e6d9c06SDiana Picus /// convert to LLVM IR dialect `alloca` 2991e6d9c06SDiana Picus struct AllocaOpConversion : public FIROpConversion<fir::AllocaOp> { 3001e6d9c06SDiana Picus using FIROpConversion::FIROpConversion; 3011e6d9c06SDiana Picus 3021e6d9c06SDiana Picus mlir::LogicalResult 3031e6d9c06SDiana Picus matchAndRewrite(fir::AllocaOp alloc, OpAdaptor adaptor, 3041e6d9c06SDiana Picus mlir::ConversionPatternRewriter &rewriter) const override { 3051e6d9c06SDiana Picus mlir::ValueRange operands = adaptor.getOperands(); 3061e6d9c06SDiana Picus auto loc = alloc.getLoc(); 3071e6d9c06SDiana Picus mlir::Type ity = lowerTy().indexType(); 3081e6d9c06SDiana Picus unsigned i = 0; 3091e6d9c06SDiana Picus mlir::Value size = genConstantIndex(loc, ity, rewriter, 1).getResult(); 3101e6d9c06SDiana Picus mlir::Type ty = convertType(alloc.getType()); 3111e6d9c06SDiana Picus mlir::Type resultTy = ty; 3121e6d9c06SDiana Picus if (alloc.hasLenParams()) { 3131e6d9c06SDiana Picus unsigned end = alloc.numLenParams(); 3141e6d9c06SDiana Picus llvm::SmallVector<mlir::Value> lenParams; 3151e6d9c06SDiana Picus for (; i < end; ++i) 3161e6d9c06SDiana Picus lenParams.push_back(operands[i]); 3171e6d9c06SDiana Picus mlir::Type scalarType = fir::unwrapSequenceType(alloc.getInType()); 3181e6d9c06SDiana Picus if (auto chrTy = scalarType.dyn_cast<fir::CharacterType>()) { 3191e6d9c06SDiana Picus fir::CharacterType rawCharTy = fir::CharacterType::getUnknownLen( 3201e6d9c06SDiana Picus chrTy.getContext(), chrTy.getFKind()); 3211e6d9c06SDiana Picus ty = mlir::LLVM::LLVMPointerType::get(convertType(rawCharTy)); 3221e6d9c06SDiana Picus assert(end == 1); 3231e6d9c06SDiana Picus size = integerCast(loc, rewriter, ity, lenParams[0]); 3241e6d9c06SDiana Picus } else if (auto recTy = scalarType.dyn_cast<fir::RecordType>()) { 3251e6d9c06SDiana Picus mlir::LLVM::LLVMFuncOp memSizeFn = 3261e6d9c06SDiana Picus getDependentTypeMemSizeFn(recTy, alloc, rewriter); 3271e6d9c06SDiana Picus if (!memSizeFn) 3281e6d9c06SDiana Picus emitError(loc, "did not find allocation function"); 3291e6d9c06SDiana Picus mlir::NamedAttribute attr = rewriter.getNamedAttr( 3301e6d9c06SDiana Picus "callee", mlir::SymbolRefAttr::get(memSizeFn)); 3311e6d9c06SDiana Picus auto call = rewriter.create<mlir::LLVM::CallOp>( 3321e6d9c06SDiana Picus loc, ity, lenParams, llvm::ArrayRef<mlir::NamedAttribute>{attr}); 3331e6d9c06SDiana Picus size = call.getResult(0); 3341e6d9c06SDiana Picus ty = mlir::LLVM::LLVMPointerType::get( 3351e6d9c06SDiana Picus mlir::IntegerType::get(alloc.getContext(), 8)); 3361e6d9c06SDiana Picus } else { 3371e6d9c06SDiana Picus return emitError(loc, "unexpected type ") 3381e6d9c06SDiana Picus << scalarType << " with type parameters"; 3391e6d9c06SDiana Picus } 3401e6d9c06SDiana Picus } 3411e6d9c06SDiana Picus if (alloc.hasShapeOperands()) { 3421e6d9c06SDiana Picus mlir::Type allocEleTy = fir::unwrapRefType(alloc.getType()); 3431e6d9c06SDiana Picus // Scale the size by constant factors encoded in the array type. 3441e6d9c06SDiana Picus if (auto seqTy = allocEleTy.dyn_cast<fir::SequenceType>()) { 3451e6d9c06SDiana Picus fir::SequenceType::Extent constSize = 1; 3461e6d9c06SDiana Picus for (auto extent : seqTy.getShape()) 3471e6d9c06SDiana Picus if (extent != fir::SequenceType::getUnknownExtent()) 3481e6d9c06SDiana Picus constSize *= extent; 3491e6d9c06SDiana Picus mlir::Value constVal{ 3501e6d9c06SDiana Picus genConstantIndex(loc, ity, rewriter, constSize).getResult()}; 3511e6d9c06SDiana Picus size = rewriter.create<mlir::LLVM::MulOp>(loc, ity, size, constVal); 3521e6d9c06SDiana Picus } 3531e6d9c06SDiana Picus unsigned end = operands.size(); 3541e6d9c06SDiana Picus for (; i < end; ++i) 3551e6d9c06SDiana Picus size = rewriter.create<mlir::LLVM::MulOp>( 3561e6d9c06SDiana Picus loc, ity, size, integerCast(loc, rewriter, ity, operands[i])); 3571e6d9c06SDiana Picus } 3581e6d9c06SDiana Picus if (ty == resultTy) { 3591e6d9c06SDiana Picus // Do not emit the bitcast if ty and resultTy are the same. 3601e6d9c06SDiana Picus rewriter.replaceOpWithNewOp<mlir::LLVM::AllocaOp>(alloc, ty, size, 3611e6d9c06SDiana Picus alloc->getAttrs()); 3621e6d9c06SDiana Picus } else { 3631e6d9c06SDiana Picus auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, ty, size, 3641e6d9c06SDiana Picus alloc->getAttrs()); 3651e6d9c06SDiana Picus rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(alloc, resultTy, al); 3661e6d9c06SDiana Picus } 3671e6d9c06SDiana Picus return success(); 3681e6d9c06SDiana Picus } 3691e6d9c06SDiana Picus }; 370044d5b5dSValentin Clement 371df3b9810SValentin Clement /// Lower `fir.box_addr` to the sequence of operations to extract the first 372df3b9810SValentin Clement /// element of the box. 373df3b9810SValentin Clement struct BoxAddrOpConversion : public FIROpConversion<fir::BoxAddrOp> { 374df3b9810SValentin Clement using FIROpConversion::FIROpConversion; 375df3b9810SValentin Clement 376df3b9810SValentin Clement mlir::LogicalResult 377df3b9810SValentin Clement matchAndRewrite(fir::BoxAddrOp boxaddr, OpAdaptor adaptor, 378df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 379df3b9810SValentin Clement mlir::Value a = adaptor.getOperands()[0]; 380df3b9810SValentin Clement auto loc = boxaddr.getLoc(); 381df3b9810SValentin Clement mlir::Type ty = convertType(boxaddr.getType()); 382df3b9810SValentin Clement if (auto argty = boxaddr.val().getType().dyn_cast<fir::BoxType>()) { 383df3b9810SValentin Clement rewriter.replaceOp(boxaddr, loadBaseAddrFromBox(loc, ty, a, rewriter)); 384df3b9810SValentin Clement } else { 385df3b9810SValentin Clement auto c0attr = rewriter.getI32IntegerAttr(0); 386df3b9810SValentin Clement auto c0 = mlir::ArrayAttr::get(boxaddr.getContext(), c0attr); 387df3b9810SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(boxaddr, ty, a, 388df3b9810SValentin Clement c0); 389df3b9810SValentin Clement } 390df3b9810SValentin Clement return success(); 391df3b9810SValentin Clement } 392df3b9810SValentin Clement }; 393df3b9810SValentin Clement 394df3b9810SValentin Clement /// Lower `fir.box_dims` to a sequence of operations to extract the requested 395df3b9810SValentin Clement /// dimension infomartion from the boxed value. 396df3b9810SValentin Clement /// Result in a triple set of GEPs and loads. 397df3b9810SValentin Clement struct BoxDimsOpConversion : public FIROpConversion<fir::BoxDimsOp> { 398df3b9810SValentin Clement using FIROpConversion::FIROpConversion; 399df3b9810SValentin Clement 400df3b9810SValentin Clement mlir::LogicalResult 401df3b9810SValentin Clement matchAndRewrite(fir::BoxDimsOp boxdims, OpAdaptor adaptor, 402df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 403df3b9810SValentin Clement SmallVector<mlir::Type, 3> resultTypes = { 404df3b9810SValentin Clement convertType(boxdims.getResult(0).getType()), 405df3b9810SValentin Clement convertType(boxdims.getResult(1).getType()), 406df3b9810SValentin Clement convertType(boxdims.getResult(2).getType()), 407df3b9810SValentin Clement }; 408df3b9810SValentin Clement auto results = 409df3b9810SValentin Clement getDimsFromBox(boxdims.getLoc(), resultTypes, adaptor.getOperands()[0], 410df3b9810SValentin Clement adaptor.getOperands()[1], rewriter); 411df3b9810SValentin Clement rewriter.replaceOp(boxdims, results); 412df3b9810SValentin Clement return success(); 413df3b9810SValentin Clement } 414df3b9810SValentin Clement }; 415df3b9810SValentin Clement 416df3b9810SValentin Clement /// Lower `fir.box_elesize` to a sequence of operations ro extract the size of 417df3b9810SValentin Clement /// an element in the boxed value. 418df3b9810SValentin Clement struct BoxEleSizeOpConversion : public FIROpConversion<fir::BoxEleSizeOp> { 419df3b9810SValentin Clement using FIROpConversion::FIROpConversion; 420df3b9810SValentin Clement 421df3b9810SValentin Clement mlir::LogicalResult 422df3b9810SValentin Clement matchAndRewrite(fir::BoxEleSizeOp boxelesz, OpAdaptor adaptor, 423df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 424df3b9810SValentin Clement mlir::Value a = adaptor.getOperands()[0]; 425df3b9810SValentin Clement auto loc = boxelesz.getLoc(); 426df3b9810SValentin Clement auto ty = convertType(boxelesz.getType()); 427b6e44ecdSValentin Clement auto elemSize = getValueFromBox(loc, a, ty, rewriter, kElemLenPosInBox); 428b6e44ecdSValentin Clement rewriter.replaceOp(boxelesz, elemSize); 429b6e44ecdSValentin Clement return success(); 430b6e44ecdSValentin Clement } 431b6e44ecdSValentin Clement }; 432b6e44ecdSValentin Clement 433b6e44ecdSValentin Clement /// Lower `fir.box_isalloc` to a sequence of operations to determine if the 434b6e44ecdSValentin Clement /// boxed value was from an ALLOCATABLE entity. 435b6e44ecdSValentin Clement struct BoxIsAllocOpConversion : public FIROpConversion<fir::BoxIsAllocOp> { 436b6e44ecdSValentin Clement using FIROpConversion::FIROpConversion; 437b6e44ecdSValentin Clement 438b6e44ecdSValentin Clement mlir::LogicalResult 439b6e44ecdSValentin Clement matchAndRewrite(fir::BoxIsAllocOp boxisalloc, OpAdaptor adaptor, 440b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 441b6e44ecdSValentin Clement mlir::Value box = adaptor.getOperands()[0]; 442b6e44ecdSValentin Clement auto loc = boxisalloc.getLoc(); 443b6e44ecdSValentin Clement mlir::Value check = 444b6e44ecdSValentin Clement genBoxAttributeCheck(loc, box, rewriter, kAttrAllocatable); 445b6e44ecdSValentin Clement rewriter.replaceOp(boxisalloc, check); 446b6e44ecdSValentin Clement return success(); 447b6e44ecdSValentin Clement } 448b6e44ecdSValentin Clement }; 449b6e44ecdSValentin Clement 450b6e44ecdSValentin Clement /// Lower `fir.box_isarray` to a sequence of operations to determine if the 451b6e44ecdSValentin Clement /// boxed is an array. 452b6e44ecdSValentin Clement struct BoxIsArrayOpConversion : public FIROpConversion<fir::BoxIsArrayOp> { 453b6e44ecdSValentin Clement using FIROpConversion::FIROpConversion; 454b6e44ecdSValentin Clement 455b6e44ecdSValentin Clement mlir::LogicalResult 456b6e44ecdSValentin Clement matchAndRewrite(fir::BoxIsArrayOp boxisarray, OpAdaptor adaptor, 457b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 458b6e44ecdSValentin Clement mlir::Value a = adaptor.getOperands()[0]; 459b6e44ecdSValentin Clement auto loc = boxisarray.getLoc(); 460b6e44ecdSValentin Clement auto rank = 461b6e44ecdSValentin Clement getValueFromBox(loc, a, rewriter.getI32Type(), rewriter, kRankPosInBox); 462b6e44ecdSValentin Clement auto c0 = genConstantOffset(loc, rewriter, 0); 463b6e44ecdSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>( 464b6e44ecdSValentin Clement boxisarray, mlir::LLVM::ICmpPredicate::ne, rank, c0); 465b6e44ecdSValentin Clement return success(); 466b6e44ecdSValentin Clement } 467b6e44ecdSValentin Clement }; 468b6e44ecdSValentin Clement 469b6e44ecdSValentin Clement /// Lower `fir.box_isptr` to a sequence of operations to determined if the 470b6e44ecdSValentin Clement /// boxed value was from a POINTER entity. 471b6e44ecdSValentin Clement struct BoxIsPtrOpConversion : public FIROpConversion<fir::BoxIsPtrOp> { 472b6e44ecdSValentin Clement using FIROpConversion::FIROpConversion; 473b6e44ecdSValentin Clement 474b6e44ecdSValentin Clement mlir::LogicalResult 475b6e44ecdSValentin Clement matchAndRewrite(fir::BoxIsPtrOp boxisptr, OpAdaptor adaptor, 476b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 477b6e44ecdSValentin Clement mlir::Value box = adaptor.getOperands()[0]; 478b6e44ecdSValentin Clement auto loc = boxisptr.getLoc(); 479b6e44ecdSValentin Clement mlir::Value check = genBoxAttributeCheck(loc, box, rewriter, kAttrPointer); 480b6e44ecdSValentin Clement rewriter.replaceOp(boxisptr, check); 481df3b9810SValentin Clement return success(); 482df3b9810SValentin Clement } 483df3b9810SValentin Clement }; 484df3b9810SValentin Clement 485df3b9810SValentin Clement /// Lower `fir.box_rank` to the sequence of operation to extract the rank from 486df3b9810SValentin Clement /// the box. 487df3b9810SValentin Clement struct BoxRankOpConversion : public FIROpConversion<fir::BoxRankOp> { 488df3b9810SValentin Clement using FIROpConversion::FIROpConversion; 489df3b9810SValentin Clement 490df3b9810SValentin Clement mlir::LogicalResult 491df3b9810SValentin Clement matchAndRewrite(fir::BoxRankOp boxrank, OpAdaptor adaptor, 492df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 493df3b9810SValentin Clement mlir::Value a = adaptor.getOperands()[0]; 494df3b9810SValentin Clement auto loc = boxrank.getLoc(); 495df3b9810SValentin Clement mlir::Type ty = convertType(boxrank.getType()); 496b6e44ecdSValentin Clement auto result = getValueFromBox(loc, a, ty, rewriter, kRankPosInBox); 497df3b9810SValentin Clement rewriter.replaceOp(boxrank, result); 498df3b9810SValentin Clement return success(); 499df3b9810SValentin Clement } 500df3b9810SValentin Clement }; 501df3b9810SValentin Clement 5021a2ec667SValentin Clement /// Lower `fir.string_lit` to LLVM IR dialect operation. 5031a2ec667SValentin Clement struct StringLitOpConversion : public FIROpConversion<fir::StringLitOp> { 5041a2ec667SValentin Clement using FIROpConversion::FIROpConversion; 5051a2ec667SValentin Clement 5061a2ec667SValentin Clement mlir::LogicalResult 5071a2ec667SValentin Clement matchAndRewrite(fir::StringLitOp constop, OpAdaptor adaptor, 5081a2ec667SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 5091a2ec667SValentin Clement auto ty = convertType(constop.getType()); 5101a2ec667SValentin Clement auto attr = constop.getValue(); 5111a2ec667SValentin Clement if (attr.isa<mlir::StringAttr>()) { 5121a2ec667SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(constop, ty, attr); 5131a2ec667SValentin Clement return success(); 5141a2ec667SValentin Clement } 5151a2ec667SValentin Clement 5161a2ec667SValentin Clement auto arr = attr.cast<mlir::ArrayAttr>(); 5171a2ec667SValentin Clement auto charTy = constop.getType().cast<fir::CharacterType>(); 5181a2ec667SValentin Clement unsigned bits = lowerTy().characterBitsize(charTy); 5191a2ec667SValentin Clement mlir::Type intTy = rewriter.getIntegerType(bits); 5201a2ec667SValentin Clement auto attrs = llvm::map_range( 5211a2ec667SValentin Clement arr.getValue(), [intTy, bits](mlir::Attribute attr) -> Attribute { 5221a2ec667SValentin Clement return mlir::IntegerAttr::get( 5231a2ec667SValentin Clement intTy, 5241a2ec667SValentin Clement attr.cast<mlir::IntegerAttr>().getValue().sextOrTrunc(bits)); 5251a2ec667SValentin Clement }); 5261a2ec667SValentin Clement mlir::Type vecType = mlir::VectorType::get(arr.size(), intTy); 5271a2ec667SValentin Clement auto denseAttr = mlir::DenseElementsAttr::get( 5281a2ec667SValentin Clement vecType.cast<mlir::ShapedType>(), llvm::to_vector<8>(attrs)); 5291a2ec667SValentin Clement rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(constop, ty, 5301a2ec667SValentin Clement denseAttr); 5311a2ec667SValentin Clement return success(); 5321a2ec667SValentin Clement } 5331a2ec667SValentin Clement }; 5341a2ec667SValentin Clement 535*cc505c0bSKiran Chandramohan /// Lower `fir.boxproc_host` operation. Extracts the host pointer from the 536*cc505c0bSKiran Chandramohan /// boxproc. 537*cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers. 538*cc505c0bSKiran Chandramohan struct BoxProcHostOpConversion : public FIROpConversion<fir::BoxProcHostOp> { 539*cc505c0bSKiran Chandramohan using FIROpConversion::FIROpConversion; 540*cc505c0bSKiran Chandramohan 541*cc505c0bSKiran Chandramohan mlir::LogicalResult 542*cc505c0bSKiran Chandramohan matchAndRewrite(fir::BoxProcHostOp boxprochost, OpAdaptor adaptor, 543*cc505c0bSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 544*cc505c0bSKiran Chandramohan return rewriter.notifyMatchFailure( 545*cc505c0bSKiran Chandramohan boxprochost, "fir.boxproc_host codegen is not implemented yet"); 546*cc505c0bSKiran Chandramohan } 547*cc505c0bSKiran Chandramohan }; 548*cc505c0bSKiran Chandramohan 549e38ef2ffSValentin Clement /// Lower `fir.box_tdesc` to the sequence of operations to extract the type 550e38ef2ffSValentin Clement /// descriptor from the box. 551e38ef2ffSValentin Clement struct BoxTypeDescOpConversion : public FIROpConversion<fir::BoxTypeDescOp> { 552e38ef2ffSValentin Clement using FIROpConversion::FIROpConversion; 553e38ef2ffSValentin Clement 554e38ef2ffSValentin Clement mlir::LogicalResult 555e38ef2ffSValentin Clement matchAndRewrite(fir::BoxTypeDescOp boxtypedesc, OpAdaptor adaptor, 556e38ef2ffSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 557e38ef2ffSValentin Clement mlir::Value box = adaptor.getOperands()[0]; 558e38ef2ffSValentin Clement auto loc = boxtypedesc.getLoc(); 559e38ef2ffSValentin Clement mlir::Type typeTy = 560e38ef2ffSValentin Clement fir::getDescFieldTypeModel<kTypePosInBox>()(boxtypedesc.getContext()); 561e38ef2ffSValentin Clement auto result = getValueFromBox(loc, box, typeTy, rewriter, kTypePosInBox); 562e38ef2ffSValentin Clement auto typePtrTy = mlir::LLVM::LLVMPointerType::get(typeTy); 563e38ef2ffSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(boxtypedesc, typePtrTy, 564e38ef2ffSValentin Clement result); 565e38ef2ffSValentin Clement return success(); 566e38ef2ffSValentin Clement } 567e38ef2ffSValentin Clement }; 568e38ef2ffSValentin Clement 569ddd11b9aSAndrzej Warzynski // `fir.call` -> `llvm.call` 570ddd11b9aSAndrzej Warzynski struct CallOpConversion : public FIROpConversion<fir::CallOp> { 571ddd11b9aSAndrzej Warzynski using FIROpConversion::FIROpConversion; 572ddd11b9aSAndrzej Warzynski 573ddd11b9aSAndrzej Warzynski mlir::LogicalResult 574ddd11b9aSAndrzej Warzynski matchAndRewrite(fir::CallOp call, OpAdaptor adaptor, 575ddd11b9aSAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 576ddd11b9aSAndrzej Warzynski SmallVector<mlir::Type> resultTys; 577ddd11b9aSAndrzej Warzynski for (auto r : call.getResults()) 578ddd11b9aSAndrzej Warzynski resultTys.push_back(convertType(r.getType())); 579ddd11b9aSAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>( 580ddd11b9aSAndrzej Warzynski call, resultTys, adaptor.getOperands(), call->getAttrs()); 581ddd11b9aSAndrzej Warzynski return success(); 582ddd11b9aSAndrzej Warzynski } 583ddd11b9aSAndrzej Warzynski }; 584ddd11b9aSAndrzej Warzynski 585092cee5fSValentin Clement static mlir::Type getComplexEleTy(mlir::Type complex) { 586092cee5fSValentin Clement if (auto cc = complex.dyn_cast<mlir::ComplexType>()) 587092cee5fSValentin Clement return cc.getElementType(); 588092cee5fSValentin Clement return complex.cast<fir::ComplexType>().getElementType(); 589092cee5fSValentin Clement } 590092cee5fSValentin Clement 591f1dfc027SDiana Picus /// Compare complex values 592f1dfc027SDiana Picus /// 593f1dfc027SDiana Picus /// Per 10.1, the only comparisons available are .EQ. (oeq) and .NE. (une). 594f1dfc027SDiana Picus /// 595f1dfc027SDiana Picus /// For completeness, all other comparison are done on the real component only. 596f1dfc027SDiana Picus struct CmpcOpConversion : public FIROpConversion<fir::CmpcOp> { 597f1dfc027SDiana Picus using FIROpConversion::FIROpConversion; 598f1dfc027SDiana Picus 599f1dfc027SDiana Picus mlir::LogicalResult 600f1dfc027SDiana Picus matchAndRewrite(fir::CmpcOp cmp, OpAdaptor adaptor, 601f1dfc027SDiana Picus mlir::ConversionPatternRewriter &rewriter) const override { 602f1dfc027SDiana Picus mlir::ValueRange operands = adaptor.getOperands(); 603f1dfc027SDiana Picus mlir::MLIRContext *ctxt = cmp.getContext(); 604f1dfc027SDiana Picus mlir::Type eleTy = convertType(getComplexEleTy(cmp.lhs().getType())); 605f1dfc027SDiana Picus mlir::Type resTy = convertType(cmp.getType()); 606f1dfc027SDiana Picus mlir::Location loc = cmp.getLoc(); 607f1dfc027SDiana Picus auto pos0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0)); 608f1dfc027SDiana Picus SmallVector<mlir::Value, 2> rp{rewriter.create<mlir::LLVM::ExtractValueOp>( 609f1dfc027SDiana Picus loc, eleTy, operands[0], pos0), 610f1dfc027SDiana Picus rewriter.create<mlir::LLVM::ExtractValueOp>( 611f1dfc027SDiana Picus loc, eleTy, operands[1], pos0)}; 612f1dfc027SDiana Picus auto rcp = 613f1dfc027SDiana Picus rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, rp, cmp->getAttrs()); 614f1dfc027SDiana Picus auto pos1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1)); 615f1dfc027SDiana Picus SmallVector<mlir::Value, 2> ip{rewriter.create<mlir::LLVM::ExtractValueOp>( 616f1dfc027SDiana Picus loc, eleTy, operands[0], pos1), 617f1dfc027SDiana Picus rewriter.create<mlir::LLVM::ExtractValueOp>( 618f1dfc027SDiana Picus loc, eleTy, operands[1], pos1)}; 619f1dfc027SDiana Picus auto icp = 620f1dfc027SDiana Picus rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, ip, cmp->getAttrs()); 621f1dfc027SDiana Picus SmallVector<mlir::Value, 2> cp{rcp, icp}; 622f1dfc027SDiana Picus switch (cmp.getPredicate()) { 623f1dfc027SDiana Picus case mlir::arith::CmpFPredicate::OEQ: // .EQ. 624f1dfc027SDiana Picus rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(cmp, resTy, cp); 625f1dfc027SDiana Picus break; 626f1dfc027SDiana Picus case mlir::arith::CmpFPredicate::UNE: // .NE. 627f1dfc027SDiana Picus rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(cmp, resTy, cp); 628f1dfc027SDiana Picus break; 629f1dfc027SDiana Picus default: 630f1dfc027SDiana Picus rewriter.replaceOp(cmp, rcp.getResult()); 631f1dfc027SDiana Picus break; 632f1dfc027SDiana Picus } 633f1dfc027SDiana Picus return success(); 634f1dfc027SDiana Picus } 635f1dfc027SDiana Picus }; 636f1dfc027SDiana Picus 637e81d73edSDiana Picus /// Lower complex constants 638e81d73edSDiana Picus struct ConstcOpConversion : public FIROpConversion<fir::ConstcOp> { 639e81d73edSDiana Picus using FIROpConversion::FIROpConversion; 640e81d73edSDiana Picus 641e81d73edSDiana Picus mlir::LogicalResult 642e81d73edSDiana Picus matchAndRewrite(fir::ConstcOp conc, OpAdaptor, 643e81d73edSDiana Picus mlir::ConversionPatternRewriter &rewriter) const override { 644e81d73edSDiana Picus mlir::Location loc = conc.getLoc(); 645e81d73edSDiana Picus mlir::MLIRContext *ctx = conc.getContext(); 646e81d73edSDiana Picus mlir::Type ty = convertType(conc.getType()); 647e81d73edSDiana Picus mlir::Type ety = convertType(getComplexEleTy(conc.getType())); 648e81d73edSDiana Picus auto realFloatAttr = mlir::FloatAttr::get(ety, getValue(conc.getReal())); 649e81d73edSDiana Picus auto realPart = 650e81d73edSDiana Picus rewriter.create<mlir::LLVM::ConstantOp>(loc, ety, realFloatAttr); 651e81d73edSDiana Picus auto imFloatAttr = mlir::FloatAttr::get(ety, getValue(conc.getImaginary())); 652e81d73edSDiana Picus auto imPart = 653e81d73edSDiana Picus rewriter.create<mlir::LLVM::ConstantOp>(loc, ety, imFloatAttr); 654e81d73edSDiana Picus auto realIndex = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 655e81d73edSDiana Picus auto imIndex = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 656e81d73edSDiana Picus auto undef = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 657e81d73edSDiana Picus auto setReal = rewriter.create<mlir::LLVM::InsertValueOp>( 658e81d73edSDiana Picus loc, ty, undef, realPart, realIndex); 659e81d73edSDiana Picus rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(conc, ty, setReal, 660e81d73edSDiana Picus imPart, imIndex); 661e81d73edSDiana Picus return success(); 662e81d73edSDiana Picus } 663e81d73edSDiana Picus 664e81d73edSDiana Picus inline APFloat getValue(mlir::Attribute attr) const { 665e81d73edSDiana Picus return attr.cast<fir::RealAttr>().getValue(); 666e81d73edSDiana Picus } 667e81d73edSDiana Picus }; 668e81d73edSDiana Picus 669092cee5fSValentin Clement /// convert value of from-type to value of to-type 670092cee5fSValentin Clement struct ConvertOpConversion : public FIROpConversion<fir::ConvertOp> { 671092cee5fSValentin Clement using FIROpConversion::FIROpConversion; 672092cee5fSValentin Clement 673092cee5fSValentin Clement static bool isFloatingPointTy(mlir::Type ty) { 674092cee5fSValentin Clement return ty.isa<mlir::FloatType>(); 675092cee5fSValentin Clement } 676092cee5fSValentin Clement 677092cee5fSValentin Clement mlir::LogicalResult 678092cee5fSValentin Clement matchAndRewrite(fir::ConvertOp convert, OpAdaptor adaptor, 679092cee5fSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 680092cee5fSValentin Clement auto fromTy = convertType(convert.value().getType()); 681092cee5fSValentin Clement auto toTy = convertType(convert.res().getType()); 682092cee5fSValentin Clement mlir::Value op0 = adaptor.getOperands()[0]; 683092cee5fSValentin Clement if (fromTy == toTy) { 684092cee5fSValentin Clement rewriter.replaceOp(convert, op0); 685092cee5fSValentin Clement return success(); 686092cee5fSValentin Clement } 687092cee5fSValentin Clement auto loc = convert.getLoc(); 688092cee5fSValentin Clement auto convertFpToFp = [&](mlir::Value val, unsigned fromBits, 689092cee5fSValentin Clement unsigned toBits, mlir::Type toTy) -> mlir::Value { 690092cee5fSValentin Clement if (fromBits == toBits) { 691092cee5fSValentin Clement // TODO: Converting between two floating-point representations with the 692092cee5fSValentin Clement // same bitwidth is not allowed for now. 693092cee5fSValentin Clement mlir::emitError(loc, 694092cee5fSValentin Clement "cannot implicitly convert between two floating-point " 695092cee5fSValentin Clement "representations of the same bitwidth"); 696092cee5fSValentin Clement return {}; 697092cee5fSValentin Clement } 698092cee5fSValentin Clement if (fromBits > toBits) 699092cee5fSValentin Clement return rewriter.create<mlir::LLVM::FPTruncOp>(loc, toTy, val); 700092cee5fSValentin Clement return rewriter.create<mlir::LLVM::FPExtOp>(loc, toTy, val); 701092cee5fSValentin Clement }; 702092cee5fSValentin Clement // Complex to complex conversion. 703092cee5fSValentin Clement if (fir::isa_complex(convert.value().getType()) && 704092cee5fSValentin Clement fir::isa_complex(convert.res().getType())) { 705092cee5fSValentin Clement // Special case: handle the conversion of a complex such that both the 706092cee5fSValentin Clement // real and imaginary parts are converted together. 707092cee5fSValentin Clement auto zero = mlir::ArrayAttr::get(convert.getContext(), 708092cee5fSValentin Clement rewriter.getI32IntegerAttr(0)); 709092cee5fSValentin Clement auto one = mlir::ArrayAttr::get(convert.getContext(), 710092cee5fSValentin Clement rewriter.getI32IntegerAttr(1)); 711092cee5fSValentin Clement auto ty = convertType(getComplexEleTy(convert.value().getType())); 712092cee5fSValentin Clement auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, zero); 713092cee5fSValentin Clement auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, one); 714092cee5fSValentin Clement auto nt = convertType(getComplexEleTy(convert.res().getType())); 715092cee5fSValentin Clement auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(ty); 716092cee5fSValentin Clement auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(nt); 717092cee5fSValentin Clement auto rc = convertFpToFp(rp, fromBits, toBits, nt); 718092cee5fSValentin Clement auto ic = convertFpToFp(ip, fromBits, toBits, nt); 719092cee5fSValentin Clement auto un = rewriter.create<mlir::LLVM::UndefOp>(loc, toTy); 720092cee5fSValentin Clement auto i1 = 721092cee5fSValentin Clement rewriter.create<mlir::LLVM::InsertValueOp>(loc, toTy, un, rc, zero); 722092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(convert, toTy, i1, 723092cee5fSValentin Clement ic, one); 724092cee5fSValentin Clement return mlir::success(); 725092cee5fSValentin Clement } 726092cee5fSValentin Clement // Floating point to floating point conversion. 727092cee5fSValentin Clement if (isFloatingPointTy(fromTy)) { 728092cee5fSValentin Clement if (isFloatingPointTy(toTy)) { 729092cee5fSValentin Clement auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy); 730092cee5fSValentin Clement auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy); 731092cee5fSValentin Clement auto v = convertFpToFp(op0, fromBits, toBits, toTy); 732092cee5fSValentin Clement rewriter.replaceOp(convert, v); 733092cee5fSValentin Clement return mlir::success(); 734092cee5fSValentin Clement } 735092cee5fSValentin Clement if (toTy.isa<mlir::IntegerType>()) { 736092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::FPToSIOp>(convert, toTy, op0); 737092cee5fSValentin Clement return mlir::success(); 738092cee5fSValentin Clement } 739092cee5fSValentin Clement } else if (fromTy.isa<mlir::IntegerType>()) { 740092cee5fSValentin Clement // Integer to integer conversion. 741092cee5fSValentin Clement if (toTy.isa<mlir::IntegerType>()) { 742092cee5fSValentin Clement auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy); 743092cee5fSValentin Clement auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy); 744092cee5fSValentin Clement assert(fromBits != toBits); 745092cee5fSValentin Clement if (fromBits > toBits) { 746092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::TruncOp>(convert, toTy, op0); 747092cee5fSValentin Clement return mlir::success(); 748092cee5fSValentin Clement } 749092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::SExtOp>(convert, toTy, op0); 750092cee5fSValentin Clement return mlir::success(); 751092cee5fSValentin Clement } 752092cee5fSValentin Clement // Integer to floating point conversion. 753092cee5fSValentin Clement if (isFloatingPointTy(toTy)) { 754092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::SIToFPOp>(convert, toTy, op0); 755092cee5fSValentin Clement return mlir::success(); 756092cee5fSValentin Clement } 757092cee5fSValentin Clement // Integer to pointer conversion. 758092cee5fSValentin Clement if (toTy.isa<mlir::LLVM::LLVMPointerType>()) { 759092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(convert, toTy, op0); 760092cee5fSValentin Clement return mlir::success(); 761092cee5fSValentin Clement } 762092cee5fSValentin Clement } else if (fromTy.isa<mlir::LLVM::LLVMPointerType>()) { 763092cee5fSValentin Clement // Pointer to integer conversion. 764092cee5fSValentin Clement if (toTy.isa<mlir::IntegerType>()) { 765092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::PtrToIntOp>(convert, toTy, op0); 766092cee5fSValentin Clement return mlir::success(); 767092cee5fSValentin Clement } 768092cee5fSValentin Clement // Pointer to pointer conversion. 769092cee5fSValentin Clement if (toTy.isa<mlir::LLVM::LLVMPointerType>()) { 770092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(convert, toTy, op0); 771092cee5fSValentin Clement return mlir::success(); 772092cee5fSValentin Clement } 773092cee5fSValentin Clement } 774092cee5fSValentin Clement return emitError(loc) << "cannot convert " << fromTy << " to " << toTy; 775092cee5fSValentin Clement } 776092cee5fSValentin Clement }; 777092cee5fSValentin Clement 7789534e361SValentin Clement /// Lower `fir.dispatch` operation. A virtual call to a method in a dispatch 7799534e361SValentin Clement /// table. 7809534e361SValentin Clement struct DispatchOpConversion : public FIROpConversion<fir::DispatchOp> { 7819534e361SValentin Clement using FIROpConversion::FIROpConversion; 7829534e361SValentin Clement 7839534e361SValentin Clement mlir::LogicalResult 7849534e361SValentin Clement matchAndRewrite(fir::DispatchOp dispatch, OpAdaptor adaptor, 7859534e361SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 7869534e361SValentin Clement return rewriter.notifyMatchFailure( 7879534e361SValentin Clement dispatch, "fir.dispatch codegen is not implemented yet"); 7889534e361SValentin Clement } 7899534e361SValentin Clement }; 7909534e361SValentin Clement 7919534e361SValentin Clement /// Lower `fir.dispatch_table` operation. The dispatch table for a Fortran 7929534e361SValentin Clement /// derived type. 7939534e361SValentin Clement struct DispatchTableOpConversion 7949534e361SValentin Clement : public FIROpConversion<fir::DispatchTableOp> { 7959534e361SValentin Clement using FIROpConversion::FIROpConversion; 7969534e361SValentin Clement 7979534e361SValentin Clement mlir::LogicalResult 7989534e361SValentin Clement matchAndRewrite(fir::DispatchTableOp dispTab, OpAdaptor adaptor, 7999534e361SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 8009534e361SValentin Clement return rewriter.notifyMatchFailure( 8019534e361SValentin Clement dispTab, "fir.dispatch_table codegen is not implemented yet"); 8029534e361SValentin Clement } 8039534e361SValentin Clement }; 8049534e361SValentin Clement 8059534e361SValentin Clement /// Lower `fir.dt_entry` operation. An entry in a dispatch table; binds a 8069534e361SValentin Clement /// method-name to a function. 8079534e361SValentin Clement struct DTEntryOpConversion : public FIROpConversion<fir::DTEntryOp> { 8089534e361SValentin Clement using FIROpConversion::FIROpConversion; 8099534e361SValentin Clement 8109534e361SValentin Clement mlir::LogicalResult 8119534e361SValentin Clement matchAndRewrite(fir::DTEntryOp dtEnt, OpAdaptor adaptor, 8129534e361SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 8139534e361SValentin Clement return rewriter.notifyMatchFailure( 8149534e361SValentin Clement dtEnt, "fir.dt_entry codegen is not implemented yet"); 8159534e361SValentin Clement } 8169534e361SValentin Clement }; 8179534e361SValentin Clement 818677df8c7SValentin Clement /// Lower `fir.global_len` operation. 819677df8c7SValentin Clement struct GlobalLenOpConversion : public FIROpConversion<fir::GlobalLenOp> { 820677df8c7SValentin Clement using FIROpConversion::FIROpConversion; 821677df8c7SValentin Clement 822677df8c7SValentin Clement mlir::LogicalResult 823677df8c7SValentin Clement matchAndRewrite(fir::GlobalLenOp globalLen, OpAdaptor adaptor, 824677df8c7SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 825677df8c7SValentin Clement return rewriter.notifyMatchFailure( 826677df8c7SValentin Clement globalLen, "fir.global_len codegen is not implemented yet"); 827677df8c7SValentin Clement } 828677df8c7SValentin Clement }; 829677df8c7SValentin Clement 83031246187SValentin Clement /// Lower `fir.gentypedesc` to a global constant. 83131246187SValentin Clement struct GenTypeDescOpConversion : public FIROpConversion<fir::GenTypeDescOp> { 83231246187SValentin Clement using FIROpConversion::FIROpConversion; 83331246187SValentin Clement 83431246187SValentin Clement mlir::LogicalResult 83531246187SValentin Clement matchAndRewrite(fir::GenTypeDescOp gentypedesc, OpAdaptor adaptor, 83631246187SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 83731246187SValentin Clement return rewriter.notifyMatchFailure( 83831246187SValentin Clement gentypedesc, "fir.fir.gentypedesc codegen is not implemented yet"); 83931246187SValentin Clement } 84031246187SValentin Clement }; 84131246187SValentin Clement 8420c4a7a52SValentin Clement /// Lower `fir.has_value` operation to `llvm.return` operation. 843044d5b5dSValentin Clement struct HasValueOpConversion : public FIROpConversion<fir::HasValueOp> { 844044d5b5dSValentin Clement using FIROpConversion::FIROpConversion; 845044d5b5dSValentin Clement 846044d5b5dSValentin Clement mlir::LogicalResult 847044d5b5dSValentin Clement matchAndRewrite(fir::HasValueOp op, OpAdaptor adaptor, 848044d5b5dSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 849044d5b5dSValentin Clement rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, adaptor.getOperands()); 850044d5b5dSValentin Clement return success(); 851044d5b5dSValentin Clement } 852044d5b5dSValentin Clement }; 853044d5b5dSValentin Clement 8540c4a7a52SValentin Clement /// Lower `fir.global` operation to `llvm.global` operation. 8550c4a7a52SValentin Clement /// `fir.insert_on_range` operations are replaced with constant dense attribute 8560c4a7a52SValentin Clement /// if they are applied on the full range. 857044d5b5dSValentin Clement struct GlobalOpConversion : public FIROpConversion<fir::GlobalOp> { 858044d5b5dSValentin Clement using FIROpConversion::FIROpConversion; 859044d5b5dSValentin Clement 860044d5b5dSValentin Clement mlir::LogicalResult 861044d5b5dSValentin Clement matchAndRewrite(fir::GlobalOp global, OpAdaptor adaptor, 862044d5b5dSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 863044d5b5dSValentin Clement auto tyAttr = convertType(global.getType()); 864044d5b5dSValentin Clement if (global.getType().isa<fir::BoxType>()) 865044d5b5dSValentin Clement tyAttr = tyAttr.cast<mlir::LLVM::LLVMPointerType>().getElementType(); 866044d5b5dSValentin Clement auto loc = global.getLoc(); 867044d5b5dSValentin Clement mlir::Attribute initAttr{}; 868044d5b5dSValentin Clement if (global.initVal()) 869044d5b5dSValentin Clement initAttr = global.initVal().getValue(); 870044d5b5dSValentin Clement auto linkage = convertLinkage(global.linkName()); 871044d5b5dSValentin Clement auto isConst = global.constant().hasValue(); 872044d5b5dSValentin Clement auto g = rewriter.create<mlir::LLVM::GlobalOp>( 873044d5b5dSValentin Clement loc, tyAttr, isConst, linkage, global.sym_name(), initAttr); 874044d5b5dSValentin Clement auto &gr = g.getInitializerRegion(); 875044d5b5dSValentin Clement rewriter.inlineRegionBefore(global.region(), gr, gr.end()); 876044d5b5dSValentin Clement if (!gr.empty()) { 877044d5b5dSValentin Clement // Replace insert_on_range with a constant dense attribute if the 878044d5b5dSValentin Clement // initialization is on the full range. 879044d5b5dSValentin Clement auto insertOnRangeOps = gr.front().getOps<fir::InsertOnRangeOp>(); 880044d5b5dSValentin Clement for (auto insertOp : insertOnRangeOps) { 881044d5b5dSValentin Clement if (isFullRange(insertOp.coor(), insertOp.getType())) { 882044d5b5dSValentin Clement auto seqTyAttr = convertType(insertOp.getType()); 883044d5b5dSValentin Clement auto *op = insertOp.val().getDefiningOp(); 884044d5b5dSValentin Clement auto constant = mlir::dyn_cast<mlir::arith::ConstantOp>(op); 885044d5b5dSValentin Clement if (!constant) { 886044d5b5dSValentin Clement auto convertOp = mlir::dyn_cast<fir::ConvertOp>(op); 887044d5b5dSValentin Clement if (!convertOp) 888044d5b5dSValentin Clement continue; 889044d5b5dSValentin Clement constant = cast<mlir::arith::ConstantOp>( 890044d5b5dSValentin Clement convertOp.value().getDefiningOp()); 891044d5b5dSValentin Clement } 892044d5b5dSValentin Clement mlir::Type vecType = mlir::VectorType::get( 893044d5b5dSValentin Clement insertOp.getType().getShape(), constant.getType()); 894044d5b5dSValentin Clement auto denseAttr = mlir::DenseElementsAttr::get( 895044d5b5dSValentin Clement vecType.cast<ShapedType>(), constant.value()); 896044d5b5dSValentin Clement rewriter.setInsertionPointAfter(insertOp); 897044d5b5dSValentin Clement rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>( 898044d5b5dSValentin Clement insertOp, seqTyAttr, denseAttr); 899044d5b5dSValentin Clement } 900044d5b5dSValentin Clement } 901044d5b5dSValentin Clement } 902044d5b5dSValentin Clement rewriter.eraseOp(global); 903044d5b5dSValentin Clement return success(); 904044d5b5dSValentin Clement } 905044d5b5dSValentin Clement 906044d5b5dSValentin Clement bool isFullRange(mlir::ArrayAttr indexes, fir::SequenceType seqTy) const { 907044d5b5dSValentin Clement auto extents = seqTy.getShape(); 908044d5b5dSValentin Clement if (indexes.size() / 2 != extents.size()) 909044d5b5dSValentin Clement return false; 910044d5b5dSValentin Clement for (unsigned i = 0; i < indexes.size(); i += 2) { 911044d5b5dSValentin Clement if (indexes[i].cast<IntegerAttr>().getInt() != 0) 912044d5b5dSValentin Clement return false; 913044d5b5dSValentin Clement if (indexes[i + 1].cast<IntegerAttr>().getInt() != extents[i / 2] - 1) 914044d5b5dSValentin Clement return false; 915044d5b5dSValentin Clement } 916044d5b5dSValentin Clement return true; 917044d5b5dSValentin Clement } 918044d5b5dSValentin Clement 9190c4a7a52SValentin Clement // TODO: String comparaison should be avoided. Replace linkName with an 9200c4a7a52SValentin Clement // enumeration. 921044d5b5dSValentin Clement mlir::LLVM::Linkage convertLinkage(Optional<StringRef> optLinkage) const { 922044d5b5dSValentin Clement if (optLinkage.hasValue()) { 923044d5b5dSValentin Clement auto name = optLinkage.getValue(); 924044d5b5dSValentin Clement if (name == "internal") 925044d5b5dSValentin Clement return mlir::LLVM::Linkage::Internal; 926044d5b5dSValentin Clement if (name == "linkonce") 927044d5b5dSValentin Clement return mlir::LLVM::Linkage::Linkonce; 928044d5b5dSValentin Clement if (name == "common") 929044d5b5dSValentin Clement return mlir::LLVM::Linkage::Common; 930044d5b5dSValentin Clement if (name == "weak") 931044d5b5dSValentin Clement return mlir::LLVM::Linkage::Weak; 932044d5b5dSValentin Clement } 933044d5b5dSValentin Clement return mlir::LLVM::Linkage::External; 934044d5b5dSValentin Clement } 935044d5b5dSValentin Clement }; 936044d5b5dSValentin Clement 93739f4ef81SValentin Clement void genCondBrOp(mlir::Location loc, mlir::Value cmp, mlir::Block *dest, 93839f4ef81SValentin Clement Optional<mlir::ValueRange> destOps, 93939f4ef81SValentin Clement mlir::ConversionPatternRewriter &rewriter, 94039f4ef81SValentin Clement mlir::Block *newBlock) { 94139f4ef81SValentin Clement if (destOps.hasValue()) 94239f4ef81SValentin Clement rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, destOps.getValue(), 94339f4ef81SValentin Clement newBlock, mlir::ValueRange()); 94439f4ef81SValentin Clement else 94539f4ef81SValentin Clement rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, newBlock); 94639f4ef81SValentin Clement } 94739f4ef81SValentin Clement 94839f4ef81SValentin Clement template <typename A, typename B> 94939f4ef81SValentin Clement void genBrOp(A caseOp, mlir::Block *dest, Optional<B> destOps, 95039f4ef81SValentin Clement mlir::ConversionPatternRewriter &rewriter) { 95139f4ef81SValentin Clement if (destOps.hasValue()) 95239f4ef81SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, destOps.getValue(), 95339f4ef81SValentin Clement dest); 95439f4ef81SValentin Clement else 95539f4ef81SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, llvm::None, dest); 95639f4ef81SValentin Clement } 95739f4ef81SValentin Clement 95839f4ef81SValentin Clement void genCaseLadderStep(mlir::Location loc, mlir::Value cmp, mlir::Block *dest, 95939f4ef81SValentin Clement Optional<mlir::ValueRange> destOps, 96039f4ef81SValentin Clement mlir::ConversionPatternRewriter &rewriter) { 96139f4ef81SValentin Clement auto *thisBlock = rewriter.getInsertionBlock(); 96239f4ef81SValentin Clement auto *newBlock = createBlock(rewriter, dest); 96339f4ef81SValentin Clement rewriter.setInsertionPointToEnd(thisBlock); 96439f4ef81SValentin Clement genCondBrOp(loc, cmp, dest, destOps, rewriter, newBlock); 96539f4ef81SValentin Clement rewriter.setInsertionPointToEnd(newBlock); 96639f4ef81SValentin Clement } 96739f4ef81SValentin Clement 96839f4ef81SValentin Clement /// Conversion of `fir.select_case` 96939f4ef81SValentin Clement /// 97039f4ef81SValentin Clement /// The `fir.select_case` operation is converted to a if-then-else ladder. 97139f4ef81SValentin Clement /// Depending on the case condition type, one or several comparison and 97239f4ef81SValentin Clement /// conditional branching can be generated. 97339f4ef81SValentin Clement /// 97439f4ef81SValentin Clement /// A a point value case such as `case(4)`, a lower bound case such as 97539f4ef81SValentin Clement /// `case(5:)` or an upper bound case such as `case(:3)` are converted to a 97639f4ef81SValentin Clement /// simple comparison between the selector value and the constant value in the 97739f4ef81SValentin Clement /// case. The block associated with the case condition is then executed if 97839f4ef81SValentin Clement /// the comparison succeed otherwise it branch to the next block with the 97939f4ef81SValentin Clement /// comparison for the the next case conditon. 98039f4ef81SValentin Clement /// 98139f4ef81SValentin Clement /// A closed interval case condition such as `case(7:10)` is converted with a 98239f4ef81SValentin Clement /// first comparison and conditional branching for the lower bound. If 98339f4ef81SValentin Clement /// successful, it branch to a second block with the comparison for the 98439f4ef81SValentin Clement /// upper bound in the same case condition. 98539f4ef81SValentin Clement /// 98639f4ef81SValentin Clement /// TODO: lowering of CHARACTER type cases is not handled yet. 98739f4ef81SValentin Clement struct SelectCaseOpConversion : public FIROpConversion<fir::SelectCaseOp> { 98839f4ef81SValentin Clement using FIROpConversion::FIROpConversion; 98939f4ef81SValentin Clement 99039f4ef81SValentin Clement mlir::LogicalResult 99139f4ef81SValentin Clement matchAndRewrite(fir::SelectCaseOp caseOp, OpAdaptor adaptor, 99239f4ef81SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 99339f4ef81SValentin Clement unsigned conds = caseOp.getNumConditions(); 99439f4ef81SValentin Clement llvm::ArrayRef<mlir::Attribute> cases = caseOp.getCases().getValue(); 99539f4ef81SValentin Clement // Type can be CHARACTER, INTEGER, or LOGICAL (C1145) 99639f4ef81SValentin Clement LLVM_ATTRIBUTE_UNUSED auto ty = caseOp.getSelector().getType(); 99739f4ef81SValentin Clement if (ty.isa<fir::CharacterType>()) 99839f4ef81SValentin Clement return rewriter.notifyMatchFailure(caseOp, 99939f4ef81SValentin Clement "conversion of fir.select_case with " 100039f4ef81SValentin Clement "character type not implemented yet"); 100139f4ef81SValentin Clement mlir::Value selector = caseOp.getSelector(adaptor.getOperands()); 100239f4ef81SValentin Clement auto loc = caseOp.getLoc(); 100339f4ef81SValentin Clement for (unsigned t = 0; t != conds; ++t) { 100439f4ef81SValentin Clement mlir::Block *dest = caseOp.getSuccessor(t); 100539f4ef81SValentin Clement llvm::Optional<mlir::ValueRange> destOps = 100639f4ef81SValentin Clement caseOp.getSuccessorOperands(adaptor.getOperands(), t); 100739f4ef81SValentin Clement llvm::Optional<mlir::ValueRange> cmpOps = 100839f4ef81SValentin Clement *caseOp.getCompareOperands(adaptor.getOperands(), t); 100939f4ef81SValentin Clement mlir::Value caseArg = *(cmpOps.getValue().begin()); 101039f4ef81SValentin Clement mlir::Attribute attr = cases[t]; 101139f4ef81SValentin Clement if (attr.isa<fir::PointIntervalAttr>()) { 101239f4ef81SValentin Clement auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 101339f4ef81SValentin Clement loc, mlir::LLVM::ICmpPredicate::eq, selector, caseArg); 101439f4ef81SValentin Clement genCaseLadderStep(loc, cmp, dest, destOps, rewriter); 101539f4ef81SValentin Clement continue; 101639f4ef81SValentin Clement } 101739f4ef81SValentin Clement if (attr.isa<fir::LowerBoundAttr>()) { 101839f4ef81SValentin Clement auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 101939f4ef81SValentin Clement loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector); 102039f4ef81SValentin Clement genCaseLadderStep(loc, cmp, dest, destOps, rewriter); 102139f4ef81SValentin Clement continue; 102239f4ef81SValentin Clement } 102339f4ef81SValentin Clement if (attr.isa<fir::UpperBoundAttr>()) { 102439f4ef81SValentin Clement auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 102539f4ef81SValentin Clement loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg); 102639f4ef81SValentin Clement genCaseLadderStep(loc, cmp, dest, destOps, rewriter); 102739f4ef81SValentin Clement continue; 102839f4ef81SValentin Clement } 102939f4ef81SValentin Clement if (attr.isa<fir::ClosedIntervalAttr>()) { 103039f4ef81SValentin Clement auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 103139f4ef81SValentin Clement loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector); 103239f4ef81SValentin Clement auto *thisBlock = rewriter.getInsertionBlock(); 103339f4ef81SValentin Clement auto *newBlock1 = createBlock(rewriter, dest); 103439f4ef81SValentin Clement auto *newBlock2 = createBlock(rewriter, dest); 103539f4ef81SValentin Clement rewriter.setInsertionPointToEnd(thisBlock); 103639f4ef81SValentin Clement rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, newBlock1, newBlock2); 103739f4ef81SValentin Clement rewriter.setInsertionPointToEnd(newBlock1); 103839f4ef81SValentin Clement mlir::Value caseArg0 = *(cmpOps.getValue().begin() + 1); 103939f4ef81SValentin Clement auto cmp0 = rewriter.create<mlir::LLVM::ICmpOp>( 104039f4ef81SValentin Clement loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg0); 104139f4ef81SValentin Clement genCondBrOp(loc, cmp0, dest, destOps, rewriter, newBlock2); 104239f4ef81SValentin Clement rewriter.setInsertionPointToEnd(newBlock2); 104339f4ef81SValentin Clement continue; 104439f4ef81SValentin Clement } 104539f4ef81SValentin Clement assert(attr.isa<mlir::UnitAttr>()); 104639f4ef81SValentin Clement assert((t + 1 == conds) && "unit must be last"); 104739f4ef81SValentin Clement genBrOp(caseOp, dest, destOps, rewriter); 104839f4ef81SValentin Clement } 104939f4ef81SValentin Clement return success(); 105039f4ef81SValentin Clement } 105139f4ef81SValentin Clement }; 105239f4ef81SValentin Clement 10538c239909SValentin Clement template <typename OP> 10548c239909SValentin Clement void selectMatchAndRewrite(fir::LLVMTypeConverter &lowering, OP select, 10558c239909SValentin Clement typename OP::Adaptor adaptor, 10568c239909SValentin Clement mlir::ConversionPatternRewriter &rewriter) { 10578c239909SValentin Clement unsigned conds = select.getNumConditions(); 10588c239909SValentin Clement auto cases = select.getCases().getValue(); 10598c239909SValentin Clement mlir::Value selector = adaptor.selector(); 10608c239909SValentin Clement auto loc = select.getLoc(); 10618c239909SValentin Clement assert(conds > 0 && "select must have cases"); 10628c239909SValentin Clement 10638c239909SValentin Clement llvm::SmallVector<mlir::Block *> destinations; 10648c239909SValentin Clement llvm::SmallVector<mlir::ValueRange> destinationsOperands; 10658c239909SValentin Clement mlir::Block *defaultDestination; 10668c239909SValentin Clement mlir::ValueRange defaultOperands; 10678c239909SValentin Clement llvm::SmallVector<int32_t> caseValues; 10688c239909SValentin Clement 10698c239909SValentin Clement for (unsigned t = 0; t != conds; ++t) { 10708c239909SValentin Clement mlir::Block *dest = select.getSuccessor(t); 10718c239909SValentin Clement auto destOps = select.getSuccessorOperands(adaptor.getOperands(), t); 10728c239909SValentin Clement const mlir::Attribute &attr = cases[t]; 10738c239909SValentin Clement if (auto intAttr = attr.template dyn_cast<mlir::IntegerAttr>()) { 10748c239909SValentin Clement destinations.push_back(dest); 10758c239909SValentin Clement destinationsOperands.push_back(destOps.hasValue() ? *destOps 10768c239909SValentin Clement : ValueRange()); 10778c239909SValentin Clement caseValues.push_back(intAttr.getInt()); 10788c239909SValentin Clement continue; 10798c239909SValentin Clement } 10808c239909SValentin Clement assert(attr.template dyn_cast_or_null<mlir::UnitAttr>()); 10818c239909SValentin Clement assert((t + 1 == conds) && "unit must be last"); 10828c239909SValentin Clement defaultDestination = dest; 10838c239909SValentin Clement defaultOperands = destOps.hasValue() ? *destOps : ValueRange(); 10848c239909SValentin Clement } 10858c239909SValentin Clement 10868c239909SValentin Clement // LLVM::SwitchOp takes a i32 type for the selector. 10878c239909SValentin Clement if (select.getSelector().getType() != rewriter.getI32Type()) 10888c239909SValentin Clement selector = 10898c239909SValentin Clement rewriter.create<LLVM::TruncOp>(loc, rewriter.getI32Type(), selector); 10908c239909SValentin Clement 10918c239909SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>( 10928c239909SValentin Clement select, selector, 10938c239909SValentin Clement /*defaultDestination=*/defaultDestination, 10948c239909SValentin Clement /*defaultOperands=*/defaultOperands, 10958c239909SValentin Clement /*caseValues=*/caseValues, 10968c239909SValentin Clement /*caseDestinations=*/destinations, 10978c239909SValentin Clement /*caseOperands=*/destinationsOperands, 10988c239909SValentin Clement /*branchWeights=*/ArrayRef<int32_t>()); 10998c239909SValentin Clement } 11008c239909SValentin Clement 11018c239909SValentin Clement /// conversion of fir::SelectOp to an if-then-else ladder 11028c239909SValentin Clement struct SelectOpConversion : public FIROpConversion<fir::SelectOp> { 11038c239909SValentin Clement using FIROpConversion::FIROpConversion; 11048c239909SValentin Clement 11058c239909SValentin Clement mlir::LogicalResult 11068c239909SValentin Clement matchAndRewrite(fir::SelectOp op, OpAdaptor adaptor, 11078c239909SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 11088c239909SValentin Clement selectMatchAndRewrite<fir::SelectOp>(lowerTy(), op, adaptor, rewriter); 11098c239909SValentin Clement return success(); 11108c239909SValentin Clement } 11118c239909SValentin Clement }; 11128c239909SValentin Clement 1113e3349fa1SAndrzej Warzynski /// `fir.load` --> `llvm.load` 1114e3349fa1SAndrzej Warzynski struct LoadOpConversion : public FIROpConversion<fir::LoadOp> { 1115e3349fa1SAndrzej Warzynski using FIROpConversion::FIROpConversion; 1116e3349fa1SAndrzej Warzynski 1117e3349fa1SAndrzej Warzynski mlir::LogicalResult 1118e3349fa1SAndrzej Warzynski matchAndRewrite(fir::LoadOp load, OpAdaptor adaptor, 1119e3349fa1SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 1120e3349fa1SAndrzej Warzynski // fir.box is a special case because it is considered as an ssa values in 1121e3349fa1SAndrzej Warzynski // fir, but it is lowered as a pointer to a descriptor. So fir.ref<fir.box> 1122e3349fa1SAndrzej Warzynski // and fir.box end up being the same llvm types and loading a 1123e3349fa1SAndrzej Warzynski // fir.ref<fir.box> is actually a no op in LLVM. 1124e3349fa1SAndrzej Warzynski if (load.getType().isa<fir::BoxType>()) { 1125e3349fa1SAndrzej Warzynski rewriter.replaceOp(load, adaptor.getOperands()[0]); 1126e3349fa1SAndrzej Warzynski } else { 1127e3349fa1SAndrzej Warzynski mlir::Type ty = convertType(load.getType()); 1128e3349fa1SAndrzej Warzynski ArrayRef<NamedAttribute> at = load->getAttrs(); 1129e3349fa1SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::LoadOp>( 1130e3349fa1SAndrzej Warzynski load, ty, adaptor.getOperands(), at); 1131e3349fa1SAndrzej Warzynski } 1132e3349fa1SAndrzej Warzynski return success(); 1133e3349fa1SAndrzej Warzynski } 1134e3349fa1SAndrzej Warzynski }; 1135e3349fa1SAndrzej Warzynski 11362a299e4fSValentin Clement /// Lower `fir.select_type` to LLVM IR dialect. 11372a299e4fSValentin Clement struct SelectTypeOpConversion : public FIROpConversion<fir::SelectTypeOp> { 11382a299e4fSValentin Clement using FIROpConversion::FIROpConversion; 11392a299e4fSValentin Clement 11402a299e4fSValentin Clement mlir::LogicalResult 11412a299e4fSValentin Clement matchAndRewrite(fir::SelectTypeOp select, OpAdaptor adaptor, 11422a299e4fSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 11432a299e4fSValentin Clement return rewriter.notifyMatchFailure( 11442a299e4fSValentin Clement select, "fir.select_type codegen is not implemented yet"); 11452a299e4fSValentin Clement } 11462a299e4fSValentin Clement }; 11472a299e4fSValentin Clement 11488c239909SValentin Clement /// conversion of fir::SelectRankOp to an if-then-else ladder 11498c239909SValentin Clement struct SelectRankOpConversion : public FIROpConversion<fir::SelectRankOp> { 11508c239909SValentin Clement using FIROpConversion::FIROpConversion; 11518c239909SValentin Clement 11528c239909SValentin Clement mlir::LogicalResult 11538c239909SValentin Clement matchAndRewrite(fir::SelectRankOp op, OpAdaptor adaptor, 11548c239909SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 11558c239909SValentin Clement selectMatchAndRewrite<fir::SelectRankOp>(lowerTy(), op, adaptor, rewriter); 11568c239909SValentin Clement return success(); 11578c239909SValentin Clement } 11588c239909SValentin Clement }; 11598c239909SValentin Clement 1160e3349fa1SAndrzej Warzynski /// `fir.store` --> `llvm.store` 1161e3349fa1SAndrzej Warzynski struct StoreOpConversion : public FIROpConversion<fir::StoreOp> { 1162e3349fa1SAndrzej Warzynski using FIROpConversion::FIROpConversion; 1163e3349fa1SAndrzej Warzynski 1164e3349fa1SAndrzej Warzynski mlir::LogicalResult 1165e3349fa1SAndrzej Warzynski matchAndRewrite(fir::StoreOp store, OpAdaptor adaptor, 1166e3349fa1SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 1167e3349fa1SAndrzej Warzynski if (store.value().getType().isa<fir::BoxType>()) { 1168e3349fa1SAndrzej Warzynski // fir.box value is actually in memory, load it first before storing it. 1169e3349fa1SAndrzej Warzynski mlir::Location loc = store.getLoc(); 1170e3349fa1SAndrzej Warzynski mlir::Type boxPtrTy = adaptor.getOperands()[0].getType(); 1171e3349fa1SAndrzej Warzynski auto val = rewriter.create<mlir::LLVM::LoadOp>( 1172e3349fa1SAndrzej Warzynski loc, boxPtrTy.cast<mlir::LLVM::LLVMPointerType>().getElementType(), 1173e3349fa1SAndrzej Warzynski adaptor.getOperands()[0]); 1174e3349fa1SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>( 1175e3349fa1SAndrzej Warzynski store, val, adaptor.getOperands()[1]); 1176e3349fa1SAndrzej Warzynski } else { 1177e3349fa1SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>( 1178e3349fa1SAndrzej Warzynski store, adaptor.getOperands()[0], adaptor.getOperands()[1]); 1179e3349fa1SAndrzej Warzynski } 1180e3349fa1SAndrzej Warzynski return success(); 1181e3349fa1SAndrzej Warzynski } 1182e3349fa1SAndrzej Warzynski }; 1183e3349fa1SAndrzej Warzynski 1184e3349fa1SAndrzej Warzynski /// convert to LLVM IR dialect `undef` 1185044d5b5dSValentin Clement struct UndefOpConversion : public FIROpConversion<fir::UndefOp> { 1186044d5b5dSValentin Clement using FIROpConversion::FIROpConversion; 1187044d5b5dSValentin Clement 1188044d5b5dSValentin Clement mlir::LogicalResult 1189044d5b5dSValentin Clement matchAndRewrite(fir::UndefOp undef, OpAdaptor, 1190044d5b5dSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 1191044d5b5dSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::UndefOp>( 1192044d5b5dSValentin Clement undef, convertType(undef.getType())); 1193044d5b5dSValentin Clement return success(); 1194044d5b5dSValentin Clement } 1195044d5b5dSValentin Clement }; 1196a7a61359SValentin Clement 1197e3349fa1SAndrzej Warzynski /// `fir.unreachable` --> `llvm.unreachable` 119832e08248SAndrzej Warzynski struct UnreachableOpConversion : public FIROpConversion<fir::UnreachableOp> { 119932e08248SAndrzej Warzynski using FIROpConversion::FIROpConversion; 120032e08248SAndrzej Warzynski 120132e08248SAndrzej Warzynski mlir::LogicalResult 120232e08248SAndrzej Warzynski matchAndRewrite(fir::UnreachableOp unreach, OpAdaptor adaptor, 120332e08248SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 120432e08248SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(unreach); 120532e08248SAndrzej Warzynski return success(); 120632e08248SAndrzej Warzynski } 120732e08248SAndrzej Warzynski }; 120832e08248SAndrzej Warzynski 1209a7a61359SValentin Clement struct ZeroOpConversion : public FIROpConversion<fir::ZeroOp> { 1210a7a61359SValentin Clement using FIROpConversion::FIROpConversion; 1211a7a61359SValentin Clement 1212a7a61359SValentin Clement mlir::LogicalResult 1213a7a61359SValentin Clement matchAndRewrite(fir::ZeroOp zero, OpAdaptor, 1214a7a61359SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 1215a7a61359SValentin Clement auto ty = convertType(zero.getType()); 1216a7a61359SValentin Clement if (ty.isa<mlir::LLVM::LLVMPointerType>()) { 1217a7a61359SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(zero, ty); 1218a7a61359SValentin Clement } else if (ty.isa<mlir::IntegerType>()) { 1219a7a61359SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>( 1220a7a61359SValentin Clement zero, ty, mlir::IntegerAttr::get(zero.getType(), 0)); 1221a7a61359SValentin Clement } else if (mlir::LLVM::isCompatibleFloatingPointType(ty)) { 1222a7a61359SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>( 1223a7a61359SValentin Clement zero, ty, mlir::FloatAttr::get(zero.getType(), 0.0)); 1224a7a61359SValentin Clement } else { 1225a7a61359SValentin Clement // TODO: create ConstantAggregateZero for FIR aggregate/array types. 122652d813edSValentin Clement return rewriter.notifyMatchFailure( 122752d813edSValentin Clement zero, 1228a7a61359SValentin Clement "conversion of fir.zero with aggregate type not implemented yet"); 1229a7a61359SValentin Clement } 1230a7a61359SValentin Clement return success(); 1231a7a61359SValentin Clement } 1232a7a61359SValentin Clement }; 123332e08248SAndrzej Warzynski 1234af6ee580SValentin Clement /// Common base class for embox to descriptor conversion. 1235af6ee580SValentin Clement template <typename OP> 1236af6ee580SValentin Clement struct EmboxCommonConversion : public FIROpConversion<OP> { 1237af6ee580SValentin Clement using FIROpConversion<OP>::FIROpConversion; 1238af6ee580SValentin Clement 1239af6ee580SValentin Clement // Find the LLVMFuncOp in whose entry block the alloca should be inserted. 1240af6ee580SValentin Clement // The order to find the LLVMFuncOp is as follows: 1241af6ee580SValentin Clement // 1. The parent operation of the current block if it is a LLVMFuncOp. 1242af6ee580SValentin Clement // 2. The first ancestor that is a LLVMFuncOp. 1243af6ee580SValentin Clement mlir::LLVM::LLVMFuncOp 1244af6ee580SValentin Clement getFuncForAllocaInsert(mlir::ConversionPatternRewriter &rewriter) const { 1245af6ee580SValentin Clement mlir::Operation *parentOp = rewriter.getInsertionBlock()->getParentOp(); 1246af6ee580SValentin Clement return mlir::isa<mlir::LLVM::LLVMFuncOp>(parentOp) 1247af6ee580SValentin Clement ? mlir::cast<mlir::LLVM::LLVMFuncOp>(parentOp) 1248af6ee580SValentin Clement : parentOp->getParentOfType<mlir::LLVM::LLVMFuncOp>(); 1249af6ee580SValentin Clement } 1250af6ee580SValentin Clement 1251af6ee580SValentin Clement // Generate an alloca of size 1 and type \p toTy. 1252af6ee580SValentin Clement mlir::LLVM::AllocaOp 1253af6ee580SValentin Clement genAllocaWithType(mlir::Location loc, mlir::Type toTy, unsigned alignment, 1254af6ee580SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 1255af6ee580SValentin Clement auto thisPt = rewriter.saveInsertionPoint(); 1256af6ee580SValentin Clement mlir::LLVM::LLVMFuncOp func = getFuncForAllocaInsert(rewriter); 1257af6ee580SValentin Clement rewriter.setInsertionPointToStart(&func.front()); 1258af6ee580SValentin Clement auto size = this->genI32Constant(loc, rewriter, 1); 1259af6ee580SValentin Clement auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, toTy, size, alignment); 1260af6ee580SValentin Clement rewriter.restoreInsertionPoint(thisPt); 1261af6ee580SValentin Clement return al; 1262af6ee580SValentin Clement } 1263af6ee580SValentin Clement 1264af6ee580SValentin Clement static int getCFIAttr(fir::BoxType boxTy) { 1265af6ee580SValentin Clement auto eleTy = boxTy.getEleTy(); 1266af6ee580SValentin Clement if (eleTy.isa<fir::PointerType>()) 1267af6ee580SValentin Clement return CFI_attribute_pointer; 1268af6ee580SValentin Clement if (eleTy.isa<fir::HeapType>()) 1269af6ee580SValentin Clement return CFI_attribute_allocatable; 1270af6ee580SValentin Clement return CFI_attribute_other; 1271af6ee580SValentin Clement } 1272af6ee580SValentin Clement 1273af6ee580SValentin Clement static fir::RecordType unwrapIfDerived(fir::BoxType boxTy) { 1274af6ee580SValentin Clement return fir::unwrapSequenceType(fir::dyn_cast_ptrOrBoxEleTy(boxTy)) 1275af6ee580SValentin Clement .template dyn_cast<fir::RecordType>(); 1276af6ee580SValentin Clement } 1277af6ee580SValentin Clement static bool isDerivedTypeWithLenParams(fir::BoxType boxTy) { 1278af6ee580SValentin Clement auto recTy = unwrapIfDerived(boxTy); 1279af6ee580SValentin Clement return recTy && recTy.getNumLenParams() > 0; 1280af6ee580SValentin Clement } 1281af6ee580SValentin Clement static bool isDerivedType(fir::BoxType boxTy) { 1282af6ee580SValentin Clement return unwrapIfDerived(boxTy) != nullptr; 1283af6ee580SValentin Clement } 1284af6ee580SValentin Clement 1285af6ee580SValentin Clement // Get the element size and CFI type code of the boxed value. 1286af6ee580SValentin Clement std::tuple<mlir::Value, mlir::Value> getSizeAndTypeCode( 1287af6ee580SValentin Clement mlir::Location loc, mlir::ConversionPatternRewriter &rewriter, 1288af6ee580SValentin Clement mlir::Type boxEleTy, mlir::ValueRange lenParams = {}) const { 1289af6ee580SValentin Clement auto doInteger = 1290af6ee580SValentin Clement [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> { 1291af6ee580SValentin Clement int typeCode = fir::integerBitsToTypeCode(width); 1292af6ee580SValentin Clement return {this->genConstantOffset(loc, rewriter, width / 8), 1293af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, typeCode)}; 1294af6ee580SValentin Clement }; 1295af6ee580SValentin Clement auto doLogical = 1296af6ee580SValentin Clement [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> { 1297af6ee580SValentin Clement int typeCode = fir::logicalBitsToTypeCode(width); 1298af6ee580SValentin Clement return {this->genConstantOffset(loc, rewriter, width / 8), 1299af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, typeCode)}; 1300af6ee580SValentin Clement }; 1301af6ee580SValentin Clement auto doFloat = [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> { 1302af6ee580SValentin Clement int typeCode = fir::realBitsToTypeCode(width); 1303af6ee580SValentin Clement return {this->genConstantOffset(loc, rewriter, width / 8), 1304af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, typeCode)}; 1305af6ee580SValentin Clement }; 1306af6ee580SValentin Clement auto doComplex = 1307af6ee580SValentin Clement [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> { 1308af6ee580SValentin Clement auto typeCode = fir::complexBitsToTypeCode(width); 1309af6ee580SValentin Clement return {this->genConstantOffset(loc, rewriter, width / 8 * 2), 1310af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, typeCode)}; 1311af6ee580SValentin Clement }; 1312af6ee580SValentin Clement auto doCharacter = 1313af6ee580SValentin Clement [&](unsigned width, 1314af6ee580SValentin Clement mlir::Value len) -> std::tuple<mlir::Value, mlir::Value> { 1315af6ee580SValentin Clement auto typeCode = fir::characterBitsToTypeCode(width); 1316af6ee580SValentin Clement auto typeCodeVal = this->genConstantOffset(loc, rewriter, typeCode); 1317af6ee580SValentin Clement if (width == 8) 1318af6ee580SValentin Clement return {len, typeCodeVal}; 1319af6ee580SValentin Clement auto byteWidth = this->genConstantOffset(loc, rewriter, width / 8); 1320af6ee580SValentin Clement auto i64Ty = mlir::IntegerType::get(&this->lowerTy().getContext(), 64); 1321af6ee580SValentin Clement auto size = 1322af6ee580SValentin Clement rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, byteWidth, len); 1323af6ee580SValentin Clement return {size, typeCodeVal}; 1324af6ee580SValentin Clement }; 1325af6ee580SValentin Clement auto getKindMap = [&]() -> fir::KindMapping & { 1326af6ee580SValentin Clement return this->lowerTy().getKindMap(); 1327af6ee580SValentin Clement }; 1328af6ee580SValentin Clement // Pointer-like types. 1329af6ee580SValentin Clement if (auto eleTy = fir::dyn_cast_ptrEleTy(boxEleTy)) 1330af6ee580SValentin Clement boxEleTy = eleTy; 1331af6ee580SValentin Clement // Integer types. 1332af6ee580SValentin Clement if (fir::isa_integer(boxEleTy)) { 1333af6ee580SValentin Clement if (auto ty = boxEleTy.dyn_cast<mlir::IntegerType>()) 1334af6ee580SValentin Clement return doInteger(ty.getWidth()); 1335af6ee580SValentin Clement auto ty = boxEleTy.cast<fir::IntegerType>(); 1336af6ee580SValentin Clement return doInteger(getKindMap().getIntegerBitsize(ty.getFKind())); 1337af6ee580SValentin Clement } 1338af6ee580SValentin Clement // Floating point types. 1339af6ee580SValentin Clement if (fir::isa_real(boxEleTy)) { 1340af6ee580SValentin Clement if (auto ty = boxEleTy.dyn_cast<mlir::FloatType>()) 1341af6ee580SValentin Clement return doFloat(ty.getWidth()); 1342af6ee580SValentin Clement auto ty = boxEleTy.cast<fir::RealType>(); 1343af6ee580SValentin Clement return doFloat(getKindMap().getRealBitsize(ty.getFKind())); 1344af6ee580SValentin Clement } 1345af6ee580SValentin Clement // Complex types. 1346af6ee580SValentin Clement if (fir::isa_complex(boxEleTy)) { 1347af6ee580SValentin Clement if (auto ty = boxEleTy.dyn_cast<mlir::ComplexType>()) 1348af6ee580SValentin Clement return doComplex( 1349af6ee580SValentin Clement ty.getElementType().cast<mlir::FloatType>().getWidth()); 1350af6ee580SValentin Clement auto ty = boxEleTy.cast<fir::ComplexType>(); 1351af6ee580SValentin Clement return doComplex(getKindMap().getRealBitsize(ty.getFKind())); 1352af6ee580SValentin Clement } 1353af6ee580SValentin Clement // Character types. 1354af6ee580SValentin Clement if (auto ty = boxEleTy.dyn_cast<fir::CharacterType>()) { 1355af6ee580SValentin Clement auto charWidth = getKindMap().getCharacterBitsize(ty.getFKind()); 1356af6ee580SValentin Clement if (ty.getLen() != fir::CharacterType::unknownLen()) { 1357af6ee580SValentin Clement auto len = this->genConstantOffset(loc, rewriter, ty.getLen()); 1358af6ee580SValentin Clement return doCharacter(charWidth, len); 1359af6ee580SValentin Clement } 1360af6ee580SValentin Clement assert(!lenParams.empty()); 1361af6ee580SValentin Clement return doCharacter(charWidth, lenParams.back()); 1362af6ee580SValentin Clement } 1363af6ee580SValentin Clement // Logical type. 1364af6ee580SValentin Clement if (auto ty = boxEleTy.dyn_cast<fir::LogicalType>()) 1365af6ee580SValentin Clement return doLogical(getKindMap().getLogicalBitsize(ty.getFKind())); 1366af6ee580SValentin Clement // Array types. 1367af6ee580SValentin Clement if (auto seqTy = boxEleTy.dyn_cast<fir::SequenceType>()) 1368af6ee580SValentin Clement return getSizeAndTypeCode(loc, rewriter, seqTy.getEleTy(), lenParams); 1369af6ee580SValentin Clement // Derived-type types. 1370af6ee580SValentin Clement if (boxEleTy.isa<fir::RecordType>()) { 1371af6ee580SValentin Clement auto ptrTy = mlir::LLVM::LLVMPointerType::get( 1372af6ee580SValentin Clement this->lowerTy().convertType(boxEleTy)); 1373af6ee580SValentin Clement auto nullPtr = rewriter.create<mlir::LLVM::NullOp>(loc, ptrTy); 1374af6ee580SValentin Clement auto one = 1375af6ee580SValentin Clement genConstantIndex(loc, this->lowerTy().offsetType(), rewriter, 1); 1376af6ee580SValentin Clement auto gep = rewriter.create<mlir::LLVM::GEPOp>( 1377af6ee580SValentin Clement loc, ptrTy, mlir::ValueRange{nullPtr, one}); 1378af6ee580SValentin Clement auto eleSize = rewriter.create<mlir::LLVM::PtrToIntOp>( 1379af6ee580SValentin Clement loc, this->lowerTy().indexType(), gep); 1380af6ee580SValentin Clement return {eleSize, 1381af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, fir::derivedToTypeCode())}; 1382af6ee580SValentin Clement } 1383af6ee580SValentin Clement // Reference type. 1384af6ee580SValentin Clement if (fir::isa_ref_type(boxEleTy)) { 1385af6ee580SValentin Clement // FIXME: use the target pointer size rather than sizeof(void*) 1386af6ee580SValentin Clement return {this->genConstantOffset(loc, rewriter, sizeof(void *)), 1387af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, CFI_type_cptr)}; 1388af6ee580SValentin Clement } 1389af6ee580SValentin Clement fir::emitFatalError(loc, "unhandled type in fir.box code generation"); 1390af6ee580SValentin Clement } 1391af6ee580SValentin Clement 1392af6ee580SValentin Clement /// Basic pattern to write a field in the descriptor 1393af6ee580SValentin Clement mlir::Value insertField(mlir::ConversionPatternRewriter &rewriter, 1394af6ee580SValentin Clement mlir::Location loc, mlir::Value dest, 1395af6ee580SValentin Clement ArrayRef<unsigned> fldIndexes, mlir::Value value, 1396af6ee580SValentin Clement bool bitcast = false) const { 1397af6ee580SValentin Clement auto boxTy = dest.getType(); 1398af6ee580SValentin Clement auto fldTy = this->getBoxEleTy(boxTy, fldIndexes); 1399af6ee580SValentin Clement if (bitcast) 1400af6ee580SValentin Clement value = rewriter.create<mlir::LLVM::BitcastOp>(loc, fldTy, value); 1401af6ee580SValentin Clement else 1402af6ee580SValentin Clement value = this->integerCast(loc, rewriter, fldTy, value); 1403af6ee580SValentin Clement SmallVector<mlir::Attribute, 2> attrs; 1404af6ee580SValentin Clement for (auto i : fldIndexes) 1405af6ee580SValentin Clement attrs.push_back(rewriter.getI32IntegerAttr(i)); 1406af6ee580SValentin Clement auto indexesAttr = mlir::ArrayAttr::get(rewriter.getContext(), attrs); 1407af6ee580SValentin Clement return rewriter.create<mlir::LLVM::InsertValueOp>(loc, boxTy, dest, value, 1408af6ee580SValentin Clement indexesAttr); 1409af6ee580SValentin Clement } 1410af6ee580SValentin Clement 1411af6ee580SValentin Clement inline mlir::Value 1412af6ee580SValentin Clement insertBaseAddress(mlir::ConversionPatternRewriter &rewriter, 1413af6ee580SValentin Clement mlir::Location loc, mlir::Value dest, 1414af6ee580SValentin Clement mlir::Value base) const { 1415af6ee580SValentin Clement return insertField(rewriter, loc, dest, {0}, base, /*bitCast=*/true); 1416af6ee580SValentin Clement } 1417af6ee580SValentin Clement 1418af6ee580SValentin Clement /// Get the address of the type descriptor global variable that was created by 1419af6ee580SValentin Clement /// lowering for derived type \p recType. 1420af6ee580SValentin Clement template <typename BOX> 1421af6ee580SValentin Clement mlir::Value 1422af6ee580SValentin Clement getTypeDescriptor(BOX box, mlir::ConversionPatternRewriter &rewriter, 1423af6ee580SValentin Clement mlir::Location loc, fir::RecordType recType) const { 1424af6ee580SValentin Clement std::string name = recType.getLoweredName(); 1425af6ee580SValentin Clement auto module = box->template getParentOfType<mlir::ModuleOp>(); 1426af6ee580SValentin Clement if (auto global = module.template lookupSymbol<fir::GlobalOp>(name)) { 1427af6ee580SValentin Clement auto ty = mlir::LLVM::LLVMPointerType::get( 1428af6ee580SValentin Clement this->lowerTy().convertType(global.getType())); 1429af6ee580SValentin Clement return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty, 1430af6ee580SValentin Clement global.sym_name()); 1431af6ee580SValentin Clement } 1432af6ee580SValentin Clement if (auto global = 1433af6ee580SValentin Clement module.template lookupSymbol<mlir::LLVM::GlobalOp>(name)) { 1434af6ee580SValentin Clement // The global may have already been translated to LLVM. 1435af6ee580SValentin Clement auto ty = mlir::LLVM::LLVMPointerType::get(global.getType()); 1436af6ee580SValentin Clement return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty, 1437af6ee580SValentin Clement global.sym_name()); 1438af6ee580SValentin Clement } 1439af6ee580SValentin Clement // The global does not exist in the current translation unit, but may be 1440af6ee580SValentin Clement // defined elsewhere (e.g., type defined in a module). 1441af6ee580SValentin Clement // For now, create a extern_weak symbol (will become nullptr if unresolved) 1442af6ee580SValentin Clement // to support generating code without the front-end generated symbols. 1443af6ee580SValentin Clement // These could be made available_externally to require the symbols to be 1444af6ee580SValentin Clement // defined elsewhere and to cause link-time failure otherwise. 1445af6ee580SValentin Clement auto i8Ty = rewriter.getIntegerType(8); 1446af6ee580SValentin Clement mlir::OpBuilder modBuilder(module.getBodyRegion()); 1447af6ee580SValentin Clement // TODO: The symbol should be lowered to constant in lowering, they are read 1448af6ee580SValentin Clement // only. 1449af6ee580SValentin Clement modBuilder.create<mlir::LLVM::GlobalOp>(loc, i8Ty, /*isConstant=*/false, 1450af6ee580SValentin Clement mlir::LLVM::Linkage::ExternWeak, 1451af6ee580SValentin Clement name, mlir::Attribute{}); 1452af6ee580SValentin Clement auto ty = mlir::LLVM::LLVMPointerType::get(i8Ty); 1453af6ee580SValentin Clement return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty, name); 1454af6ee580SValentin Clement } 1455af6ee580SValentin Clement 1456af6ee580SValentin Clement template <typename BOX> 1457af6ee580SValentin Clement std::tuple<fir::BoxType, mlir::Value, mlir::Value> 1458af6ee580SValentin Clement consDescriptorPrefix(BOX box, mlir::ConversionPatternRewriter &rewriter, 1459af6ee580SValentin Clement unsigned rank, mlir::ValueRange lenParams) const { 1460af6ee580SValentin Clement auto loc = box.getLoc(); 1461af6ee580SValentin Clement auto boxTy = box.getType().template dyn_cast<fir::BoxType>(); 1462af6ee580SValentin Clement auto convTy = this->lowerTy().convertBoxType(boxTy, rank); 1463af6ee580SValentin Clement auto llvmBoxPtrTy = convTy.template cast<mlir::LLVM::LLVMPointerType>(); 1464af6ee580SValentin Clement auto llvmBoxTy = llvmBoxPtrTy.getElementType(); 1465af6ee580SValentin Clement mlir::Value descriptor = 1466af6ee580SValentin Clement rewriter.create<mlir::LLVM::UndefOp>(loc, llvmBoxTy); 1467af6ee580SValentin Clement 1468af6ee580SValentin Clement llvm::SmallVector<mlir::Value> typeparams = lenParams; 1469af6ee580SValentin Clement if constexpr (!std::is_same_v<BOX, fir::EmboxOp>) { 1470af6ee580SValentin Clement if (!box.substr().empty() && fir::hasDynamicSize(boxTy.getEleTy())) 1471af6ee580SValentin Clement typeparams.push_back(box.substr()[1]); 1472af6ee580SValentin Clement } 1473af6ee580SValentin Clement 1474af6ee580SValentin Clement // Write each of the fields with the appropriate values 1475af6ee580SValentin Clement auto [eleSize, cfiTy] = 1476af6ee580SValentin Clement getSizeAndTypeCode(loc, rewriter, boxTy.getEleTy(), typeparams); 1477af6ee580SValentin Clement descriptor = 1478af6ee580SValentin Clement insertField(rewriter, loc, descriptor, {kElemLenPosInBox}, eleSize); 1479af6ee580SValentin Clement descriptor = insertField(rewriter, loc, descriptor, {kVersionPosInBox}, 1480af6ee580SValentin Clement this->genI32Constant(loc, rewriter, CFI_VERSION)); 1481af6ee580SValentin Clement descriptor = insertField(rewriter, loc, descriptor, {kRankPosInBox}, 1482af6ee580SValentin Clement this->genI32Constant(loc, rewriter, rank)); 1483af6ee580SValentin Clement descriptor = insertField(rewriter, loc, descriptor, {kTypePosInBox}, cfiTy); 1484af6ee580SValentin Clement descriptor = 1485af6ee580SValentin Clement insertField(rewriter, loc, descriptor, {kAttributePosInBox}, 1486af6ee580SValentin Clement this->genI32Constant(loc, rewriter, getCFIAttr(boxTy))); 1487af6ee580SValentin Clement const bool hasAddendum = isDerivedType(boxTy); 1488af6ee580SValentin Clement descriptor = 1489af6ee580SValentin Clement insertField(rewriter, loc, descriptor, {kF18AddendumPosInBox}, 1490af6ee580SValentin Clement this->genI32Constant(loc, rewriter, hasAddendum ? 1 : 0)); 1491af6ee580SValentin Clement 1492af6ee580SValentin Clement if (hasAddendum) { 1493af6ee580SValentin Clement auto isArray = 1494af6ee580SValentin Clement fir::dyn_cast_ptrOrBoxEleTy(boxTy).template isa<fir::SequenceType>(); 1495af6ee580SValentin Clement unsigned typeDescFieldId = isArray ? kOptTypePtrPosInBox : kDimsPosInBox; 1496af6ee580SValentin Clement auto typeDesc = 1497af6ee580SValentin Clement getTypeDescriptor(box, rewriter, loc, unwrapIfDerived(boxTy)); 1498af6ee580SValentin Clement descriptor = 1499af6ee580SValentin Clement insertField(rewriter, loc, descriptor, {typeDescFieldId}, typeDesc, 1500af6ee580SValentin Clement /*bitCast=*/true); 1501af6ee580SValentin Clement } 1502af6ee580SValentin Clement 1503af6ee580SValentin Clement return {boxTy, descriptor, eleSize}; 1504af6ee580SValentin Clement } 1505af6ee580SValentin Clement 1506af6ee580SValentin Clement /// If the embox is not in a globalOp body, allocate storage for the box; 1507af6ee580SValentin Clement /// store the value inside and return the generated alloca. Return the input 1508af6ee580SValentin Clement /// value otherwise. 1509af6ee580SValentin Clement mlir::Value 1510af6ee580SValentin Clement placeInMemoryIfNotGlobalInit(mlir::ConversionPatternRewriter &rewriter, 1511af6ee580SValentin Clement mlir::Location loc, mlir::Value boxValue) const { 1512af6ee580SValentin Clement auto *thisBlock = rewriter.getInsertionBlock(); 1513af6ee580SValentin Clement if (thisBlock && mlir::isa<mlir::LLVM::GlobalOp>(thisBlock->getParentOp())) 1514af6ee580SValentin Clement return boxValue; 1515af6ee580SValentin Clement auto boxPtrTy = mlir::LLVM::LLVMPointerType::get(boxValue.getType()); 1516af6ee580SValentin Clement auto alloca = genAllocaWithType(loc, boxPtrTy, defaultAlign, rewriter); 1517af6ee580SValentin Clement rewriter.create<mlir::LLVM::StoreOp>(loc, boxValue, alloca); 1518af6ee580SValentin Clement return alloca; 1519af6ee580SValentin Clement } 1520af6ee580SValentin Clement }; 1521af6ee580SValentin Clement 1522af6ee580SValentin Clement /// Create a generic box on a memory reference. This conversions lowers the 1523af6ee580SValentin Clement /// abstract box to the appropriate, initialized descriptor. 1524af6ee580SValentin Clement struct EmboxOpConversion : public EmboxCommonConversion<fir::EmboxOp> { 1525af6ee580SValentin Clement using EmboxCommonConversion::EmboxCommonConversion; 1526af6ee580SValentin Clement 1527af6ee580SValentin Clement mlir::LogicalResult 1528af6ee580SValentin Clement matchAndRewrite(fir::EmboxOp embox, OpAdaptor adaptor, 1529af6ee580SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 1530af6ee580SValentin Clement assert(!embox.getShape() && "There should be no dims on this embox op"); 1531af6ee580SValentin Clement auto [boxTy, dest, eleSize] = 1532af6ee580SValentin Clement consDescriptorPrefix(embox, rewriter, /*rank=*/0, 1533af6ee580SValentin Clement /*lenParams=*/adaptor.getOperands().drop_front(1)); 1534af6ee580SValentin Clement dest = insertBaseAddress(rewriter, embox.getLoc(), dest, 1535af6ee580SValentin Clement adaptor.getOperands()[0]); 1536af6ee580SValentin Clement if (isDerivedTypeWithLenParams(boxTy)) 1537af6ee580SValentin Clement return rewriter.notifyMatchFailure( 1538af6ee580SValentin Clement embox, "fir.embox codegen of derived with length parameters not " 1539af6ee580SValentin Clement "implemented yet"); 1540af6ee580SValentin Clement auto result = placeInMemoryIfNotGlobalInit(rewriter, embox.getLoc(), dest); 1541af6ee580SValentin Clement rewriter.replaceOp(embox, result); 1542af6ee580SValentin Clement return success(); 1543af6ee580SValentin Clement } 1544af6ee580SValentin Clement }; 1545af6ee580SValentin Clement 1546*cc505c0bSKiran Chandramohan /// Lower `fir.emboxproc` operation. Creates a procedure box. 1547*cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers. 1548*cc505c0bSKiran Chandramohan struct EmboxProcOpConversion : public FIROpConversion<fir::EmboxProcOp> { 1549*cc505c0bSKiran Chandramohan using FIROpConversion::FIROpConversion; 1550*cc505c0bSKiran Chandramohan 1551*cc505c0bSKiran Chandramohan mlir::LogicalResult 1552*cc505c0bSKiran Chandramohan matchAndRewrite(fir::EmboxProcOp emboxproc, OpAdaptor adaptor, 1553*cc505c0bSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 1554*cc505c0bSKiran Chandramohan return rewriter.notifyMatchFailure( 1555*cc505c0bSKiran Chandramohan emboxproc, "fir.emboxproc codegen is not implemented yet"); 1556*cc505c0bSKiran Chandramohan } 1557*cc505c0bSKiran Chandramohan }; 1558*cc505c0bSKiran Chandramohan 1559*cc505c0bSKiran Chandramohan 156054c56347SValentin Clement // Code shared between insert_value and extract_value Ops. 156154c56347SValentin Clement struct ValueOpCommon { 156254c56347SValentin Clement // Translate the arguments pertaining to any multidimensional array to 156354c56347SValentin Clement // row-major order for LLVM-IR. 156454c56347SValentin Clement static void toRowMajor(SmallVectorImpl<mlir::Attribute> &attrs, 156554c56347SValentin Clement mlir::Type ty) { 156654c56347SValentin Clement assert(ty && "type is null"); 156754c56347SValentin Clement const auto end = attrs.size(); 156854c56347SValentin Clement for (std::remove_const_t<decltype(end)> i = 0; i < end; ++i) { 156954c56347SValentin Clement if (auto seq = ty.dyn_cast<mlir::LLVM::LLVMArrayType>()) { 157054c56347SValentin Clement const auto dim = getDimension(seq); 157154c56347SValentin Clement if (dim > 1) { 157254c56347SValentin Clement auto ub = std::min(i + dim, end); 157354c56347SValentin Clement std::reverse(attrs.begin() + i, attrs.begin() + ub); 157454c56347SValentin Clement i += dim - 1; 157554c56347SValentin Clement } 157654c56347SValentin Clement ty = getArrayElementType(seq); 157754c56347SValentin Clement } else if (auto st = ty.dyn_cast<mlir::LLVM::LLVMStructType>()) { 157854c56347SValentin Clement ty = st.getBody()[attrs[i].cast<mlir::IntegerAttr>().getInt()]; 157954c56347SValentin Clement } else { 158054c56347SValentin Clement llvm_unreachable("index into invalid type"); 158154c56347SValentin Clement } 158254c56347SValentin Clement } 158354c56347SValentin Clement } 158454c56347SValentin Clement 158554c56347SValentin Clement static llvm::SmallVector<mlir::Attribute> 158654c56347SValentin Clement collectIndices(mlir::ConversionPatternRewriter &rewriter, 158754c56347SValentin Clement mlir::ArrayAttr arrAttr) { 158854c56347SValentin Clement llvm::SmallVector<mlir::Attribute> attrs; 158954c56347SValentin Clement for (auto i = arrAttr.begin(), e = arrAttr.end(); i != e; ++i) { 159054c56347SValentin Clement if (i->isa<mlir::IntegerAttr>()) { 159154c56347SValentin Clement attrs.push_back(*i); 159254c56347SValentin Clement } else { 159354c56347SValentin Clement auto fieldName = i->cast<mlir::StringAttr>().getValue(); 159454c56347SValentin Clement ++i; 159554c56347SValentin Clement auto ty = i->cast<mlir::TypeAttr>().getValue(); 159654c56347SValentin Clement auto index = ty.cast<fir::RecordType>().getFieldIndex(fieldName); 159754c56347SValentin Clement attrs.push_back(mlir::IntegerAttr::get(rewriter.getI32Type(), index)); 159854c56347SValentin Clement } 159954c56347SValentin Clement } 160054c56347SValentin Clement return attrs; 160154c56347SValentin Clement } 160254c56347SValentin Clement 160354c56347SValentin Clement private: 160454c56347SValentin Clement static unsigned getDimension(mlir::LLVM::LLVMArrayType ty) { 160554c56347SValentin Clement unsigned result = 1; 160654c56347SValentin Clement for (auto eleTy = ty.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>(); 160754c56347SValentin Clement eleTy; 160854c56347SValentin Clement eleTy = eleTy.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>()) 160954c56347SValentin Clement ++result; 161054c56347SValentin Clement return result; 161154c56347SValentin Clement } 161254c56347SValentin Clement 161354c56347SValentin Clement static mlir::Type getArrayElementType(mlir::LLVM::LLVMArrayType ty) { 161454c56347SValentin Clement auto eleTy = ty.getElementType(); 161554c56347SValentin Clement while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>()) 161654c56347SValentin Clement eleTy = arrTy.getElementType(); 161754c56347SValentin Clement return eleTy; 161854c56347SValentin Clement } 161954c56347SValentin Clement }; 162054c56347SValentin Clement 162154c56347SValentin Clement /// Extract a subobject value from an ssa-value of aggregate type 162254c56347SValentin Clement struct ExtractValueOpConversion 162354c56347SValentin Clement : public FIROpAndTypeConversion<fir::ExtractValueOp>, 162454c56347SValentin Clement public ValueOpCommon { 162554c56347SValentin Clement using FIROpAndTypeConversion::FIROpAndTypeConversion; 162654c56347SValentin Clement 162754c56347SValentin Clement mlir::LogicalResult 162854c56347SValentin Clement doRewrite(fir::ExtractValueOp extractVal, mlir::Type ty, OpAdaptor adaptor, 162954c56347SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 163054c56347SValentin Clement auto attrs = collectIndices(rewriter, extractVal.coor()); 163154c56347SValentin Clement toRowMajor(attrs, adaptor.getOperands()[0].getType()); 163254c56347SValentin Clement auto position = mlir::ArrayAttr::get(extractVal.getContext(), attrs); 163354c56347SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>( 163454c56347SValentin Clement extractVal, ty, adaptor.getOperands()[0], position); 163554c56347SValentin Clement return success(); 163654c56347SValentin Clement } 163754c56347SValentin Clement }; 163854c56347SValentin Clement 163954c56347SValentin Clement /// InsertValue is the generalized instruction for the composition of new 164054c56347SValentin Clement /// aggregate type values. 164154c56347SValentin Clement struct InsertValueOpConversion 164254c56347SValentin Clement : public FIROpAndTypeConversion<fir::InsertValueOp>, 164354c56347SValentin Clement public ValueOpCommon { 164454c56347SValentin Clement using FIROpAndTypeConversion::FIROpAndTypeConversion; 164554c56347SValentin Clement 164654c56347SValentin Clement mlir::LogicalResult 164754c56347SValentin Clement doRewrite(fir::InsertValueOp insertVal, mlir::Type ty, OpAdaptor adaptor, 164854c56347SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 164954c56347SValentin Clement auto attrs = collectIndices(rewriter, insertVal.coor()); 165054c56347SValentin Clement toRowMajor(attrs, adaptor.getOperands()[0].getType()); 165154c56347SValentin Clement auto position = mlir::ArrayAttr::get(insertVal.getContext(), attrs); 165254c56347SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 165354c56347SValentin Clement insertVal, ty, adaptor.getOperands()[0], adaptor.getOperands()[1], 165454c56347SValentin Clement position); 165554c56347SValentin Clement return success(); 165654c56347SValentin Clement } 165754c56347SValentin Clement }; 165854c56347SValentin Clement 16593ae8e442SValentin Clement /// InsertOnRange inserts a value into a sequence over a range of offsets. 16603ae8e442SValentin Clement struct InsertOnRangeOpConversion 16613ae8e442SValentin Clement : public FIROpAndTypeConversion<fir::InsertOnRangeOp> { 16623ae8e442SValentin Clement using FIROpAndTypeConversion::FIROpAndTypeConversion; 16633ae8e442SValentin Clement 16643ae8e442SValentin Clement // Increments an array of subscripts in a row major fasion. 16653ae8e442SValentin Clement void incrementSubscripts(const SmallVector<uint64_t> &dims, 16663ae8e442SValentin Clement SmallVector<uint64_t> &subscripts) const { 16673ae8e442SValentin Clement for (size_t i = dims.size(); i > 0; --i) { 16683ae8e442SValentin Clement if (++subscripts[i - 1] < dims[i - 1]) { 16693ae8e442SValentin Clement return; 16703ae8e442SValentin Clement } 16713ae8e442SValentin Clement subscripts[i - 1] = 0; 16723ae8e442SValentin Clement } 16733ae8e442SValentin Clement } 16743ae8e442SValentin Clement 16753ae8e442SValentin Clement mlir::LogicalResult 16763ae8e442SValentin Clement doRewrite(fir::InsertOnRangeOp range, mlir::Type ty, OpAdaptor adaptor, 16773ae8e442SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 16783ae8e442SValentin Clement 16793ae8e442SValentin Clement llvm::SmallVector<uint64_t> dims; 16803ae8e442SValentin Clement auto type = adaptor.getOperands()[0].getType(); 16813ae8e442SValentin Clement 16823ae8e442SValentin Clement // Iteratively extract the array dimensions from the type. 16833ae8e442SValentin Clement while (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) { 16843ae8e442SValentin Clement dims.push_back(t.getNumElements()); 16853ae8e442SValentin Clement type = t.getElementType(); 16863ae8e442SValentin Clement } 16873ae8e442SValentin Clement 16883ae8e442SValentin Clement SmallVector<uint64_t> lBounds; 16893ae8e442SValentin Clement SmallVector<uint64_t> uBounds; 16903ae8e442SValentin Clement 16913ae8e442SValentin Clement // Extract integer value from the attribute 16923ae8e442SValentin Clement SmallVector<int64_t> coordinates = llvm::to_vector<4>( 16933ae8e442SValentin Clement llvm::map_range(range.coor(), [](Attribute a) -> int64_t { 16943ae8e442SValentin Clement return a.cast<IntegerAttr>().getInt(); 16953ae8e442SValentin Clement })); 16963ae8e442SValentin Clement 16973ae8e442SValentin Clement // Unzip the upper and lower bound and convert to a row major format. 16983ae8e442SValentin Clement for (auto i = coordinates.rbegin(), e = coordinates.rend(); i != e; ++i) { 16993ae8e442SValentin Clement uBounds.push_back(*i++); 17003ae8e442SValentin Clement lBounds.push_back(*i); 17013ae8e442SValentin Clement } 17023ae8e442SValentin Clement 17033ae8e442SValentin Clement auto &subscripts = lBounds; 17043ae8e442SValentin Clement auto loc = range.getLoc(); 17053ae8e442SValentin Clement mlir::Value lastOp = adaptor.getOperands()[0]; 17063ae8e442SValentin Clement mlir::Value insertVal = adaptor.getOperands()[1]; 17073ae8e442SValentin Clement 17083ae8e442SValentin Clement auto i64Ty = rewriter.getI64Type(); 17093ae8e442SValentin Clement while (subscripts != uBounds) { 17103ae8e442SValentin Clement // Convert uint64_t's to Attribute's. 17113ae8e442SValentin Clement SmallVector<mlir::Attribute> subscriptAttrs; 17123ae8e442SValentin Clement for (const auto &subscript : subscripts) 17133ae8e442SValentin Clement subscriptAttrs.push_back(IntegerAttr::get(i64Ty, subscript)); 17143ae8e442SValentin Clement lastOp = rewriter.create<mlir::LLVM::InsertValueOp>( 17153ae8e442SValentin Clement loc, ty, lastOp, insertVal, 17163ae8e442SValentin Clement ArrayAttr::get(range.getContext(), subscriptAttrs)); 17173ae8e442SValentin Clement 17183ae8e442SValentin Clement incrementSubscripts(dims, subscripts); 17193ae8e442SValentin Clement } 17203ae8e442SValentin Clement 17213ae8e442SValentin Clement // Convert uint64_t's to Attribute's. 17223ae8e442SValentin Clement SmallVector<mlir::Attribute> subscriptAttrs; 17233ae8e442SValentin Clement for (const auto &subscript : subscripts) 17243ae8e442SValentin Clement subscriptAttrs.push_back( 17253ae8e442SValentin Clement IntegerAttr::get(rewriter.getI64Type(), subscript)); 17263ae8e442SValentin Clement mlir::ArrayRef<mlir::Attribute> arrayRef(subscriptAttrs); 17273ae8e442SValentin Clement 17283ae8e442SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 17293ae8e442SValentin Clement range, ty, lastOp, insertVal, 17303ae8e442SValentin Clement ArrayAttr::get(range.getContext(), arrayRef)); 17313ae8e442SValentin Clement 17323ae8e442SValentin Clement return success(); 17333ae8e442SValentin Clement } 17343ae8e442SValentin Clement }; 17357b5132daSValentin Clement 17367b5132daSValentin Clement // 17377b5132daSValentin Clement // Primitive operations on Complex types 17387b5132daSValentin Clement // 17397b5132daSValentin Clement 17407b5132daSValentin Clement /// Generate inline code for complex addition/subtraction 17417b5132daSValentin Clement template <typename LLVMOP, typename OPTY> 17427b5132daSValentin Clement mlir::LLVM::InsertValueOp complexSum(OPTY sumop, mlir::ValueRange opnds, 17437b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter, 17447b5132daSValentin Clement fir::LLVMTypeConverter &lowering) { 17457b5132daSValentin Clement mlir::Value a = opnds[0]; 17467b5132daSValentin Clement mlir::Value b = opnds[1]; 17477b5132daSValentin Clement auto loc = sumop.getLoc(); 17487b5132daSValentin Clement auto ctx = sumop.getContext(); 17497b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 17507b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 17517b5132daSValentin Clement mlir::Type eleTy = lowering.convertType(getComplexEleTy(sumop.getType())); 17527b5132daSValentin Clement mlir::Type ty = lowering.convertType(sumop.getType()); 17537b5132daSValentin Clement auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0); 17547b5132daSValentin Clement auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1); 17557b5132daSValentin Clement auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0); 17567b5132daSValentin Clement auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1); 17577b5132daSValentin Clement auto rx = rewriter.create<LLVMOP>(loc, eleTy, x0, x1); 17587b5132daSValentin Clement auto ry = rewriter.create<LLVMOP>(loc, eleTy, y0, y1); 17597b5132daSValentin Clement auto r0 = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 17607b5132daSValentin Clement auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r0, rx, c0); 17617b5132daSValentin Clement return rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ry, c1); 17627b5132daSValentin Clement } 17637b5132daSValentin Clement 17647b5132daSValentin Clement struct AddcOpConversion : public FIROpConversion<fir::AddcOp> { 17657b5132daSValentin Clement using FIROpConversion::FIROpConversion; 17667b5132daSValentin Clement 17677b5132daSValentin Clement mlir::LogicalResult 17687b5132daSValentin Clement matchAndRewrite(fir::AddcOp addc, OpAdaptor adaptor, 17697b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 17707b5132daSValentin Clement // given: (x + iy) + (x' + iy') 17717b5132daSValentin Clement // result: (x + x') + i(y + y') 17727b5132daSValentin Clement auto r = complexSum<mlir::LLVM::FAddOp>(addc, adaptor.getOperands(), 17737b5132daSValentin Clement rewriter, lowerTy()); 17747b5132daSValentin Clement rewriter.replaceOp(addc, r.getResult()); 17757b5132daSValentin Clement return success(); 17767b5132daSValentin Clement } 17777b5132daSValentin Clement }; 17787b5132daSValentin Clement 17797b5132daSValentin Clement struct SubcOpConversion : public FIROpConversion<fir::SubcOp> { 17807b5132daSValentin Clement using FIROpConversion::FIROpConversion; 17817b5132daSValentin Clement 17827b5132daSValentin Clement mlir::LogicalResult 17837b5132daSValentin Clement matchAndRewrite(fir::SubcOp subc, OpAdaptor adaptor, 17847b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 17857b5132daSValentin Clement // given: (x + iy) - (x' + iy') 17867b5132daSValentin Clement // result: (x - x') + i(y - y') 17877b5132daSValentin Clement auto r = complexSum<mlir::LLVM::FSubOp>(subc, adaptor.getOperands(), 17887b5132daSValentin Clement rewriter, lowerTy()); 17897b5132daSValentin Clement rewriter.replaceOp(subc, r.getResult()); 17907b5132daSValentin Clement return success(); 17917b5132daSValentin Clement } 17927b5132daSValentin Clement }; 17937b5132daSValentin Clement 17947b5132daSValentin Clement /// Inlined complex multiply 17957b5132daSValentin Clement struct MulcOpConversion : public FIROpConversion<fir::MulcOp> { 17967b5132daSValentin Clement using FIROpConversion::FIROpConversion; 17977b5132daSValentin Clement 17987b5132daSValentin Clement mlir::LogicalResult 17997b5132daSValentin Clement matchAndRewrite(fir::MulcOp mulc, OpAdaptor adaptor, 18007b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 18017b5132daSValentin Clement // TODO: Can we use a call to __muldc3 ? 18027b5132daSValentin Clement // given: (x + iy) * (x' + iy') 18037b5132daSValentin Clement // result: (xx'-yy')+i(xy'+yx') 18047b5132daSValentin Clement mlir::Value a = adaptor.getOperands()[0]; 18057b5132daSValentin Clement mlir::Value b = adaptor.getOperands()[1]; 18067b5132daSValentin Clement auto loc = mulc.getLoc(); 18077b5132daSValentin Clement auto *ctx = mulc.getContext(); 18087b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 18097b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 18107b5132daSValentin Clement mlir::Type eleTy = convertType(getComplexEleTy(mulc.getType())); 18117b5132daSValentin Clement mlir::Type ty = convertType(mulc.getType()); 18127b5132daSValentin Clement auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0); 18137b5132daSValentin Clement auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1); 18147b5132daSValentin Clement auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0); 18157b5132daSValentin Clement auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1); 18167b5132daSValentin Clement auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1); 18177b5132daSValentin Clement auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1); 18187b5132daSValentin Clement auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1); 18197b5132daSValentin Clement auto ri = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xy, yx); 18207b5132daSValentin Clement auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1); 18217b5132daSValentin Clement auto rr = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, xx, yy); 18227b5132daSValentin Clement auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 18237b5132daSValentin Clement auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0); 18247b5132daSValentin Clement auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1); 18257b5132daSValentin Clement rewriter.replaceOp(mulc, r0.getResult()); 18267b5132daSValentin Clement return success(); 18277b5132daSValentin Clement } 18287b5132daSValentin Clement }; 18297b5132daSValentin Clement 18307b5132daSValentin Clement /// Inlined complex division 18317b5132daSValentin Clement struct DivcOpConversion : public FIROpConversion<fir::DivcOp> { 18327b5132daSValentin Clement using FIROpConversion::FIROpConversion; 18337b5132daSValentin Clement 18347b5132daSValentin Clement mlir::LogicalResult 18357b5132daSValentin Clement matchAndRewrite(fir::DivcOp divc, OpAdaptor adaptor, 18367b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 18377b5132daSValentin Clement // TODO: Can we use a call to __divdc3 instead? 18387b5132daSValentin Clement // Just generate inline code for now. 18397b5132daSValentin Clement // given: (x + iy) / (x' + iy') 18407b5132daSValentin Clement // result: ((xx'+yy')/d) + i((yx'-xy')/d) where d = x'x' + y'y' 18417b5132daSValentin Clement mlir::Value a = adaptor.getOperands()[0]; 18427b5132daSValentin Clement mlir::Value b = adaptor.getOperands()[1]; 18437b5132daSValentin Clement auto loc = divc.getLoc(); 18447b5132daSValentin Clement auto *ctx = divc.getContext(); 18457b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 18467b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 18477b5132daSValentin Clement mlir::Type eleTy = convertType(getComplexEleTy(divc.getType())); 18487b5132daSValentin Clement mlir::Type ty = convertType(divc.getType()); 18497b5132daSValentin Clement auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0); 18507b5132daSValentin Clement auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1); 18517b5132daSValentin Clement auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0); 18527b5132daSValentin Clement auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1); 18537b5132daSValentin Clement auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1); 18547b5132daSValentin Clement auto x1x1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x1, x1); 18557b5132daSValentin Clement auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1); 18567b5132daSValentin Clement auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1); 18577b5132daSValentin Clement auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1); 18587b5132daSValentin Clement auto y1y1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y1, y1); 18597b5132daSValentin Clement auto d = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, x1x1, y1y1); 18607b5132daSValentin Clement auto rrn = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xx, yy); 18617b5132daSValentin Clement auto rin = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, yx, xy); 18627b5132daSValentin Clement auto rr = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rrn, d); 18637b5132daSValentin Clement auto ri = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rin, d); 18647b5132daSValentin Clement auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 18657b5132daSValentin Clement auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0); 18667b5132daSValentin Clement auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1); 18677b5132daSValentin Clement rewriter.replaceOp(divc, r0.getResult()); 18687b5132daSValentin Clement return success(); 18697b5132daSValentin Clement } 18707b5132daSValentin Clement }; 18717b5132daSValentin Clement 18727b5132daSValentin Clement /// Inlined complex negation 18737b5132daSValentin Clement struct NegcOpConversion : public FIROpConversion<fir::NegcOp> { 18747b5132daSValentin Clement using FIROpConversion::FIROpConversion; 18757b5132daSValentin Clement 18767b5132daSValentin Clement mlir::LogicalResult 18777b5132daSValentin Clement matchAndRewrite(fir::NegcOp neg, OpAdaptor adaptor, 18787b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 18797b5132daSValentin Clement // given: -(x + iy) 18807b5132daSValentin Clement // result: -x - iy 18817b5132daSValentin Clement auto *ctxt = neg.getContext(); 18827b5132daSValentin Clement auto eleTy = convertType(getComplexEleTy(neg.getType())); 18837b5132daSValentin Clement auto ty = convertType(neg.getType()); 18847b5132daSValentin Clement auto loc = neg.getLoc(); 18857b5132daSValentin Clement mlir::Value o0 = adaptor.getOperands()[0]; 18867b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0)); 18877b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1)); 18887b5132daSValentin Clement auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c0); 18897b5132daSValentin Clement auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c1); 18907b5132daSValentin Clement auto nrp = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, rp); 18917b5132daSValentin Clement auto nip = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, ip); 18927b5132daSValentin Clement auto r = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, o0, nrp, c0); 18937b5132daSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(neg, ty, r, nip, c1); 18947b5132daSValentin Clement return success(); 18957b5132daSValentin Clement } 18967b5132daSValentin Clement }; 18977b5132daSValentin Clement 18981ed5a90fSValentin Clement /// Conversion pattern for operation that must be dead. The information in these 18991ed5a90fSValentin Clement /// operations is used by other operation. At this point they should not have 19001ed5a90fSValentin Clement /// anymore uses. 19011ed5a90fSValentin Clement /// These operations are normally dead after the pre-codegen pass. 19021ed5a90fSValentin Clement template <typename FromOp> 19031ed5a90fSValentin Clement struct MustBeDeadConversion : public FIROpConversion<FromOp> { 19041ed5a90fSValentin Clement explicit MustBeDeadConversion(fir::LLVMTypeConverter &lowering) 19051ed5a90fSValentin Clement : FIROpConversion<FromOp>(lowering) {} 19061ed5a90fSValentin Clement using OpAdaptor = typename FromOp::Adaptor; 19071ed5a90fSValentin Clement 19081ed5a90fSValentin Clement mlir::LogicalResult 19091ed5a90fSValentin Clement matchAndRewrite(FromOp op, OpAdaptor adaptor, 19101ed5a90fSValentin Clement mlir::ConversionPatternRewriter &rewriter) const final { 19111ed5a90fSValentin Clement if (!op->getUses().empty()) 19121ed5a90fSValentin Clement return rewriter.notifyMatchFailure(op, "op must be dead"); 19131ed5a90fSValentin Clement rewriter.eraseOp(op); 19141ed5a90fSValentin Clement return success(); 19151ed5a90fSValentin Clement } 19161ed5a90fSValentin Clement }; 19171ed5a90fSValentin Clement 19181ed5a90fSValentin Clement struct ShapeOpConversion : public MustBeDeadConversion<fir::ShapeOp> { 19191ed5a90fSValentin Clement using MustBeDeadConversion::MustBeDeadConversion; 19201ed5a90fSValentin Clement }; 19211ed5a90fSValentin Clement 19221ed5a90fSValentin Clement struct ShapeShiftOpConversion : public MustBeDeadConversion<fir::ShapeShiftOp> { 19231ed5a90fSValentin Clement using MustBeDeadConversion::MustBeDeadConversion; 19241ed5a90fSValentin Clement }; 19251ed5a90fSValentin Clement 19261ed5a90fSValentin Clement struct ShiftOpConversion : public MustBeDeadConversion<fir::ShiftOp> { 19271ed5a90fSValentin Clement using MustBeDeadConversion::MustBeDeadConversion; 19281ed5a90fSValentin Clement }; 19291ed5a90fSValentin Clement 19301ed5a90fSValentin Clement struct SliceOpConversion : public MustBeDeadConversion<fir::SliceOp> { 19311ed5a90fSValentin Clement using MustBeDeadConversion::MustBeDeadConversion; 19321ed5a90fSValentin Clement }; 19331ed5a90fSValentin Clement 1934420ad7ceSAndrzej Warzynski /// `fir.is_present` --> 1935420ad7ceSAndrzej Warzynski /// ``` 1936420ad7ceSAndrzej Warzynski /// %0 = llvm.mlir.constant(0 : i64) 1937420ad7ceSAndrzej Warzynski /// %1 = llvm.ptrtoint %0 1938420ad7ceSAndrzej Warzynski /// %2 = llvm.icmp "ne" %1, %0 : i64 1939420ad7ceSAndrzej Warzynski /// ``` 1940420ad7ceSAndrzej Warzynski struct IsPresentOpConversion : public FIROpConversion<fir::IsPresentOp> { 1941420ad7ceSAndrzej Warzynski using FIROpConversion::FIROpConversion; 1942420ad7ceSAndrzej Warzynski 1943420ad7ceSAndrzej Warzynski mlir::LogicalResult 1944420ad7ceSAndrzej Warzynski matchAndRewrite(fir::IsPresentOp isPresent, OpAdaptor adaptor, 1945420ad7ceSAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 1946420ad7ceSAndrzej Warzynski mlir::Type idxTy = lowerTy().indexType(); 1947420ad7ceSAndrzej Warzynski mlir::Location loc = isPresent.getLoc(); 1948420ad7ceSAndrzej Warzynski auto ptr = adaptor.getOperands()[0]; 1949420ad7ceSAndrzej Warzynski 1950420ad7ceSAndrzej Warzynski if (isPresent.val().getType().isa<fir::BoxCharType>()) { 1951420ad7ceSAndrzej Warzynski auto structTy = ptr.getType().cast<mlir::LLVM::LLVMStructType>(); 1952420ad7ceSAndrzej Warzynski assert(!structTy.isOpaque() && !structTy.getBody().empty()); 1953420ad7ceSAndrzej Warzynski 1954420ad7ceSAndrzej Warzynski mlir::Type ty = structTy.getBody()[0]; 1955420ad7ceSAndrzej Warzynski mlir::MLIRContext *ctx = isPresent.getContext(); 1956420ad7ceSAndrzej Warzynski auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 1957420ad7ceSAndrzej Warzynski ptr = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, ptr, c0); 1958420ad7ceSAndrzej Warzynski } 1959420ad7ceSAndrzej Warzynski mlir::LLVM::ConstantOp c0 = 1960420ad7ceSAndrzej Warzynski genConstantIndex(isPresent.getLoc(), idxTy, rewriter, 0); 1961420ad7ceSAndrzej Warzynski auto addr = rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, ptr); 1962420ad7ceSAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>( 1963420ad7ceSAndrzej Warzynski isPresent, mlir::LLVM::ICmpPredicate::ne, addr, c0); 1964420ad7ceSAndrzej Warzynski 1965420ad7ceSAndrzej Warzynski return success(); 1966420ad7ceSAndrzej Warzynski } 1967420ad7ceSAndrzej Warzynski }; 19681e77b095SAndrzej Warzynski 19691e77b095SAndrzej Warzynski /// Convert `!fir.emboxchar<!fir.char<KIND, ?>, #n>` into a sequence of 19701e77b095SAndrzej Warzynski /// instructions that generate `!llvm.struct<(ptr<ik>, i64)>`. The 1st element 19711e77b095SAndrzej Warzynski /// in this struct is a pointer. Its type is determined from `KIND`. The 2nd 19721e77b095SAndrzej Warzynski /// element is the length of the character buffer (`#n`). 19731e77b095SAndrzej Warzynski struct EmboxCharOpConversion : public FIROpConversion<fir::EmboxCharOp> { 19741e77b095SAndrzej Warzynski using FIROpConversion::FIROpConversion; 19751e77b095SAndrzej Warzynski 19761e77b095SAndrzej Warzynski mlir::LogicalResult 19771e77b095SAndrzej Warzynski matchAndRewrite(fir::EmboxCharOp emboxChar, OpAdaptor adaptor, 19781e77b095SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 19791e77b095SAndrzej Warzynski mlir::ValueRange operands = adaptor.getOperands(); 19801e77b095SAndrzej Warzynski MLIRContext *ctx = emboxChar.getContext(); 19811e77b095SAndrzej Warzynski 19821e77b095SAndrzej Warzynski mlir::Value charBuffer = operands[0]; 19831e77b095SAndrzej Warzynski mlir::Value charBufferLen = operands[1]; 19841e77b095SAndrzej Warzynski 19851e77b095SAndrzej Warzynski mlir::Location loc = emboxChar.getLoc(); 19861e77b095SAndrzej Warzynski mlir::Type llvmStructTy = convertType(emboxChar.getType()); 19871e77b095SAndrzej Warzynski auto llvmStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, llvmStructTy); 19881e77b095SAndrzej Warzynski 19891e77b095SAndrzej Warzynski mlir::Type lenTy = 19901e77b095SAndrzej Warzynski llvmStructTy.cast<mlir::LLVM::LLVMStructType>().getBody()[1]; 19911e77b095SAndrzej Warzynski mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, charBufferLen); 19921e77b095SAndrzej Warzynski 19931e77b095SAndrzej Warzynski auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 19941e77b095SAndrzej Warzynski auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 19951e77b095SAndrzej Warzynski auto insertBufferOp = rewriter.create<mlir::LLVM::InsertValueOp>( 19961e77b095SAndrzej Warzynski loc, llvmStructTy, llvmStruct, charBuffer, c0); 19971e77b095SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 19981e77b095SAndrzej Warzynski emboxChar, llvmStructTy, insertBufferOp, lenAfterCast, c1); 19991e77b095SAndrzej Warzynski 20001e77b095SAndrzej Warzynski return success(); 20011e77b095SAndrzej Warzynski } 20021e77b095SAndrzej Warzynski }; 200314867ffcSAndrzej Warzynski 200414867ffcSAndrzej Warzynski /// Construct an `llvm.extractvalue` instruction. It will return value at 200514867ffcSAndrzej Warzynski /// element \p x from \p tuple. 200614867ffcSAndrzej Warzynski mlir::LLVM::ExtractValueOp 200714867ffcSAndrzej Warzynski genExtractValueWithIndex(mlir::Location loc, mlir::Value tuple, mlir::Type ty, 200814867ffcSAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter, 200914867ffcSAndrzej Warzynski mlir::MLIRContext *ctx, int x) { 201014867ffcSAndrzej Warzynski auto cx = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(x)); 201114867ffcSAndrzej Warzynski auto xty = ty.cast<mlir::LLVM::LLVMStructType>().getBody()[x]; 201214867ffcSAndrzej Warzynski return rewriter.create<mlir::LLVM::ExtractValueOp>(loc, xty, tuple, cx); 201314867ffcSAndrzej Warzynski } 201414867ffcSAndrzej Warzynski 20156c3d7fd4SAndrzej Warzynski /// Convert `!fir.boxchar_len` to `!llvm.extractvalue` for the 2nd part of the 20166c3d7fd4SAndrzej Warzynski /// boxchar. 20176c3d7fd4SAndrzej Warzynski struct BoxCharLenOpConversion : public FIROpConversion<fir::BoxCharLenOp> { 20186c3d7fd4SAndrzej Warzynski using FIROpConversion::FIROpConversion; 20196c3d7fd4SAndrzej Warzynski 20206c3d7fd4SAndrzej Warzynski mlir::LogicalResult 20216c3d7fd4SAndrzej Warzynski matchAndRewrite(fir::BoxCharLenOp boxCharLen, OpAdaptor adaptor, 20226c3d7fd4SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 20236c3d7fd4SAndrzej Warzynski mlir::Value boxChar = adaptor.getOperands()[0]; 20246c3d7fd4SAndrzej Warzynski mlir::Location loc = boxChar.getLoc(); 20256c3d7fd4SAndrzej Warzynski mlir::MLIRContext *ctx = boxChar.getContext(); 20266c3d7fd4SAndrzej Warzynski mlir::Type returnValTy = boxCharLen.getResult().getType(); 20276c3d7fd4SAndrzej Warzynski 20286c3d7fd4SAndrzej Warzynski constexpr int boxcharLenIdx = 1; 20296c3d7fd4SAndrzej Warzynski mlir::LLVM::ExtractValueOp len = genExtractValueWithIndex( 20306c3d7fd4SAndrzej Warzynski loc, boxChar, boxChar.getType(), rewriter, ctx, boxcharLenIdx); 20316c3d7fd4SAndrzej Warzynski mlir::Value lenAfterCast = integerCast(loc, rewriter, returnValTy, len); 20326c3d7fd4SAndrzej Warzynski rewriter.replaceOp(boxCharLen, lenAfterCast); 20336c3d7fd4SAndrzej Warzynski 20346c3d7fd4SAndrzej Warzynski return success(); 20356c3d7fd4SAndrzej Warzynski } 20366c3d7fd4SAndrzej Warzynski }; 20376c3d7fd4SAndrzej Warzynski 203814867ffcSAndrzej Warzynski /// Convert `fir.unboxchar` into two `llvm.extractvalue` instructions. One for 203914867ffcSAndrzej Warzynski /// the character buffer and one for the buffer length. 204014867ffcSAndrzej Warzynski struct UnboxCharOpConversion : public FIROpConversion<fir::UnboxCharOp> { 204114867ffcSAndrzej Warzynski using FIROpConversion::FIROpConversion; 204214867ffcSAndrzej Warzynski 204314867ffcSAndrzej Warzynski mlir::LogicalResult 204414867ffcSAndrzej Warzynski matchAndRewrite(fir::UnboxCharOp unboxchar, OpAdaptor adaptor, 204514867ffcSAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 204614867ffcSAndrzej Warzynski MLIRContext *ctx = unboxchar.getContext(); 204714867ffcSAndrzej Warzynski 204814867ffcSAndrzej Warzynski mlir::Type lenTy = convertType(unboxchar.getType(1)); 204914867ffcSAndrzej Warzynski mlir::Value tuple = adaptor.getOperands()[0]; 205014867ffcSAndrzej Warzynski mlir::Type tupleTy = tuple.getType(); 205114867ffcSAndrzej Warzynski 205214867ffcSAndrzej Warzynski mlir::Location loc = unboxchar.getLoc(); 205314867ffcSAndrzej Warzynski mlir::Value ptrToBuffer = 205414867ffcSAndrzej Warzynski genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 0); 205514867ffcSAndrzej Warzynski 205614867ffcSAndrzej Warzynski mlir::LLVM::ExtractValueOp len = 205714867ffcSAndrzej Warzynski genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 1); 205814867ffcSAndrzej Warzynski mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, len); 205914867ffcSAndrzej Warzynski 206014867ffcSAndrzej Warzynski rewriter.replaceOp(unboxchar, 206114867ffcSAndrzej Warzynski ArrayRef<mlir::Value>{ptrToBuffer, lenAfterCast}); 206214867ffcSAndrzej Warzynski return success(); 206314867ffcSAndrzej Warzynski } 206414867ffcSAndrzej Warzynski }; 206514867ffcSAndrzej Warzynski 2066*cc505c0bSKiran Chandramohan /// Lower `fir.unboxproc` operation. Unbox a procedure box value, yielding its 2067*cc505c0bSKiran Chandramohan /// components. 2068*cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers. 2069*cc505c0bSKiran Chandramohan struct UnboxProcOpConversion : public FIROpConversion<fir::UnboxProcOp> { 2070*cc505c0bSKiran Chandramohan using FIROpConversion::FIROpConversion; 2071*cc505c0bSKiran Chandramohan 2072*cc505c0bSKiran Chandramohan mlir::LogicalResult 2073*cc505c0bSKiran Chandramohan matchAndRewrite(fir::UnboxProcOp unboxproc, OpAdaptor adaptor, 2074*cc505c0bSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 2075*cc505c0bSKiran Chandramohan return rewriter.notifyMatchFailure( 2076*cc505c0bSKiran Chandramohan unboxproc, "fir.unboxproc codegen is not implemented yet"); 2077*cc505c0bSKiran Chandramohan } 2078*cc505c0bSKiran Chandramohan }; 2079*cc505c0bSKiran Chandramohan 2080044d5b5dSValentin Clement } // namespace 2081044d5b5dSValentin Clement 2082044d5b5dSValentin Clement namespace { 2083044d5b5dSValentin Clement /// Convert FIR dialect to LLVM dialect 2084044d5b5dSValentin Clement /// 2085044d5b5dSValentin Clement /// This pass lowers all FIR dialect operations to LLVM IR dialect. An 2086044d5b5dSValentin Clement /// MLIR pass is used to lower residual Std dialect to LLVM IR dialect. 2087044d5b5dSValentin Clement /// 2088044d5b5dSValentin Clement /// This pass is not complete yet. We are upstreaming it in small patches. 2089044d5b5dSValentin Clement class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> { 2090044d5b5dSValentin Clement public: 2091044d5b5dSValentin Clement mlir::ModuleOp getModule() { return getOperation(); } 2092044d5b5dSValentin Clement 2093044d5b5dSValentin Clement void runOnOperation() override final { 20947b5132daSValentin Clement auto mod = getModule(); 20957b5132daSValentin Clement if (!forcedTargetTriple.empty()) { 20967b5132daSValentin Clement fir::setTargetTriple(mod, forcedTargetTriple); 20977b5132daSValentin Clement } 20987b5132daSValentin Clement 2099044d5b5dSValentin Clement auto *context = getModule().getContext(); 2100044d5b5dSValentin Clement fir::LLVMTypeConverter typeConverter{getModule()}; 2101044d5b5dSValentin Clement mlir::OwningRewritePatternList pattern(context); 2102df3b9810SValentin Clement pattern.insert< 2103420ad7ceSAndrzej Warzynski AbsentOpConversion, AddcOpConversion, AddrOfOpConversion, 21041a2ec667SValentin Clement AllocaOpConversion, BoxAddrOpConversion, BoxCharLenOpConversion, 21051a2ec667SValentin Clement BoxDimsOpConversion, BoxEleSizeOpConversion, BoxIsAllocOpConversion, 2106*cc505c0bSKiran Chandramohan BoxIsArrayOpConversion, BoxIsPtrOpConversion, BoxProcHostOpConversion, 2107*cc505c0bSKiran Chandramohan BoxRankOpConversion, BoxTypeDescOpConversion, CallOpConversion, 2108*cc505c0bSKiran Chandramohan CmpcOpConversion, ConstcOpConversion, ConvertOpConversion, 2109*cc505c0bSKiran Chandramohan DispatchOpConversion, DispatchTableOpConversion, DTEntryOpConversion, 2110*cc505c0bSKiran Chandramohan DivcOpConversion, EmboxOpConversion, EmboxCharOpConversion, 2111*cc505c0bSKiran Chandramohan EmboxProcOpConversion, ExtractValueOpConversion, HasValueOpConversion, 2112*cc505c0bSKiran Chandramohan GenTypeDescOpConversion, GlobalLenOpConversion, GlobalOpConversion, 2113*cc505c0bSKiran Chandramohan InsertOnRangeOpConversion, InsertValueOpConversion, 2114e81d73edSDiana Picus IsPresentOpConversion, LoadOpConversion, NegcOpConversion, 2115e81d73edSDiana Picus MulcOpConversion, SelectCaseOpConversion, SelectOpConversion, 2116e81d73edSDiana Picus SelectRankOpConversion, SelectTypeOpConversion, ShapeOpConversion, 2117e81d73edSDiana Picus ShapeShiftOpConversion, ShiftOpConversion, SliceOpConversion, 2118e81d73edSDiana Picus StoreOpConversion, StringLitOpConversion, SubcOpConversion, 2119*cc505c0bSKiran Chandramohan UnboxCharOpConversion, UnboxProcOpConversion, UndefOpConversion, 2120*cc505c0bSKiran Chandramohan UnreachableOpConversion, ZeroOpConversion>(typeConverter); 2121044d5b5dSValentin Clement mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern); 2122044d5b5dSValentin Clement mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter, 2123044d5b5dSValentin Clement pattern); 2124044d5b5dSValentin Clement mlir::ConversionTarget target{*context}; 2125044d5b5dSValentin Clement target.addLegalDialect<mlir::LLVM::LLVMDialect>(); 2126044d5b5dSValentin Clement 2127044d5b5dSValentin Clement // required NOPs for applying a full conversion 2128044d5b5dSValentin Clement target.addLegalOp<mlir::ModuleOp>(); 2129044d5b5dSValentin Clement 2130044d5b5dSValentin Clement // apply the patterns 2131044d5b5dSValentin Clement if (mlir::failed(mlir::applyFullConversion(getModule(), target, 2132044d5b5dSValentin Clement std::move(pattern)))) { 2133044d5b5dSValentin Clement signalPassFailure(); 2134044d5b5dSValentin Clement } 2135044d5b5dSValentin Clement } 2136044d5b5dSValentin Clement }; 2137044d5b5dSValentin Clement } // namespace 2138044d5b5dSValentin Clement 2139044d5b5dSValentin Clement std::unique_ptr<mlir::Pass> fir::createFIRToLLVMPass() { 2140044d5b5dSValentin Clement return std::make_unique<FIRToLLVMLowering>(); 2141044d5b5dSValentin Clement } 2142