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 535cc505c0bSKiran Chandramohan /// Lower `fir.boxproc_host` operation. Extracts the host pointer from the 536cc505c0bSKiran Chandramohan /// boxproc. 537cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers. 538cc505c0bSKiran Chandramohan struct BoxProcHostOpConversion : public FIROpConversion<fir::BoxProcHostOp> { 539cc505c0bSKiran Chandramohan using FIROpConversion::FIROpConversion; 540cc505c0bSKiran Chandramohan 541cc505c0bSKiran Chandramohan mlir::LogicalResult 542cc505c0bSKiran Chandramohan matchAndRewrite(fir::BoxProcHostOp boxprochost, OpAdaptor adaptor, 543cc505c0bSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 544cc505c0bSKiran Chandramohan return rewriter.notifyMatchFailure( 545cc505c0bSKiran Chandramohan boxprochost, "fir.boxproc_host codegen is not implemented yet"); 546cc505c0bSKiran Chandramohan } 547cc505c0bSKiran Chandramohan }; 548cc505c0bSKiran 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 84222d332a0SAndrzej Warzynski /// Convert `fir.end` 84322d332a0SAndrzej Warzynski struct FirEndOpConversion : public FIROpConversion<fir::FirEndOp> { 84422d332a0SAndrzej Warzynski using FIROpConversion::FIROpConversion; 84522d332a0SAndrzej Warzynski 84622d332a0SAndrzej Warzynski mlir::LogicalResult 84722d332a0SAndrzej Warzynski matchAndRewrite(fir::FirEndOp firEnd, OpAdaptor, 84822d332a0SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 84922d332a0SAndrzej Warzynski return rewriter.notifyMatchFailure( 85022d332a0SAndrzej Warzynski firEnd, "fir.end codegen is not implemented yet"); 85122d332a0SAndrzej Warzynski } 85222d332a0SAndrzej Warzynski }; 85322d332a0SAndrzej Warzynski 8540c4a7a52SValentin Clement /// Lower `fir.has_value` operation to `llvm.return` operation. 855044d5b5dSValentin Clement struct HasValueOpConversion : public FIROpConversion<fir::HasValueOp> { 856044d5b5dSValentin Clement using FIROpConversion::FIROpConversion; 857044d5b5dSValentin Clement 858044d5b5dSValentin Clement mlir::LogicalResult 859044d5b5dSValentin Clement matchAndRewrite(fir::HasValueOp op, OpAdaptor adaptor, 860044d5b5dSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 861044d5b5dSValentin Clement rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, adaptor.getOperands()); 862044d5b5dSValentin Clement return success(); 863044d5b5dSValentin Clement } 864044d5b5dSValentin Clement }; 865044d5b5dSValentin Clement 8660c4a7a52SValentin Clement /// Lower `fir.global` operation to `llvm.global` operation. 8670c4a7a52SValentin Clement /// `fir.insert_on_range` operations are replaced with constant dense attribute 8680c4a7a52SValentin Clement /// if they are applied on the full range. 869044d5b5dSValentin Clement struct GlobalOpConversion : public FIROpConversion<fir::GlobalOp> { 870044d5b5dSValentin Clement using FIROpConversion::FIROpConversion; 871044d5b5dSValentin Clement 872044d5b5dSValentin Clement mlir::LogicalResult 873044d5b5dSValentin Clement matchAndRewrite(fir::GlobalOp global, OpAdaptor adaptor, 874044d5b5dSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 875044d5b5dSValentin Clement auto tyAttr = convertType(global.getType()); 876044d5b5dSValentin Clement if (global.getType().isa<fir::BoxType>()) 877044d5b5dSValentin Clement tyAttr = tyAttr.cast<mlir::LLVM::LLVMPointerType>().getElementType(); 878044d5b5dSValentin Clement auto loc = global.getLoc(); 879044d5b5dSValentin Clement mlir::Attribute initAttr{}; 880044d5b5dSValentin Clement if (global.initVal()) 881044d5b5dSValentin Clement initAttr = global.initVal().getValue(); 882044d5b5dSValentin Clement auto linkage = convertLinkage(global.linkName()); 883044d5b5dSValentin Clement auto isConst = global.constant().hasValue(); 884044d5b5dSValentin Clement auto g = rewriter.create<mlir::LLVM::GlobalOp>( 885044d5b5dSValentin Clement loc, tyAttr, isConst, linkage, global.sym_name(), initAttr); 886044d5b5dSValentin Clement auto &gr = g.getInitializerRegion(); 887044d5b5dSValentin Clement rewriter.inlineRegionBefore(global.region(), gr, gr.end()); 888044d5b5dSValentin Clement if (!gr.empty()) { 889044d5b5dSValentin Clement // Replace insert_on_range with a constant dense attribute if the 890044d5b5dSValentin Clement // initialization is on the full range. 891044d5b5dSValentin Clement auto insertOnRangeOps = gr.front().getOps<fir::InsertOnRangeOp>(); 892044d5b5dSValentin Clement for (auto insertOp : insertOnRangeOps) { 893044d5b5dSValentin Clement if (isFullRange(insertOp.coor(), insertOp.getType())) { 894044d5b5dSValentin Clement auto seqTyAttr = convertType(insertOp.getType()); 895044d5b5dSValentin Clement auto *op = insertOp.val().getDefiningOp(); 896044d5b5dSValentin Clement auto constant = mlir::dyn_cast<mlir::arith::ConstantOp>(op); 897044d5b5dSValentin Clement if (!constant) { 898044d5b5dSValentin Clement auto convertOp = mlir::dyn_cast<fir::ConvertOp>(op); 899044d5b5dSValentin Clement if (!convertOp) 900044d5b5dSValentin Clement continue; 901044d5b5dSValentin Clement constant = cast<mlir::arith::ConstantOp>( 902044d5b5dSValentin Clement convertOp.value().getDefiningOp()); 903044d5b5dSValentin Clement } 904044d5b5dSValentin Clement mlir::Type vecType = mlir::VectorType::get( 905044d5b5dSValentin Clement insertOp.getType().getShape(), constant.getType()); 906044d5b5dSValentin Clement auto denseAttr = mlir::DenseElementsAttr::get( 907044d5b5dSValentin Clement vecType.cast<ShapedType>(), constant.value()); 908044d5b5dSValentin Clement rewriter.setInsertionPointAfter(insertOp); 909044d5b5dSValentin Clement rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>( 910044d5b5dSValentin Clement insertOp, seqTyAttr, denseAttr); 911044d5b5dSValentin Clement } 912044d5b5dSValentin Clement } 913044d5b5dSValentin Clement } 914044d5b5dSValentin Clement rewriter.eraseOp(global); 915044d5b5dSValentin Clement return success(); 916044d5b5dSValentin Clement } 917044d5b5dSValentin Clement 918044d5b5dSValentin Clement bool isFullRange(mlir::ArrayAttr indexes, fir::SequenceType seqTy) const { 919044d5b5dSValentin Clement auto extents = seqTy.getShape(); 920044d5b5dSValentin Clement if (indexes.size() / 2 != extents.size()) 921044d5b5dSValentin Clement return false; 922044d5b5dSValentin Clement for (unsigned i = 0; i < indexes.size(); i += 2) { 923044d5b5dSValentin Clement if (indexes[i].cast<IntegerAttr>().getInt() != 0) 924044d5b5dSValentin Clement return false; 925044d5b5dSValentin Clement if (indexes[i + 1].cast<IntegerAttr>().getInt() != extents[i / 2] - 1) 926044d5b5dSValentin Clement return false; 927044d5b5dSValentin Clement } 928044d5b5dSValentin Clement return true; 929044d5b5dSValentin Clement } 930044d5b5dSValentin Clement 9310c4a7a52SValentin Clement // TODO: String comparaison should be avoided. Replace linkName with an 9320c4a7a52SValentin Clement // enumeration. 933044d5b5dSValentin Clement mlir::LLVM::Linkage convertLinkage(Optional<StringRef> optLinkage) const { 934044d5b5dSValentin Clement if (optLinkage.hasValue()) { 935044d5b5dSValentin Clement auto name = optLinkage.getValue(); 936044d5b5dSValentin Clement if (name == "internal") 937044d5b5dSValentin Clement return mlir::LLVM::Linkage::Internal; 938044d5b5dSValentin Clement if (name == "linkonce") 939044d5b5dSValentin Clement return mlir::LLVM::Linkage::Linkonce; 940044d5b5dSValentin Clement if (name == "common") 941044d5b5dSValentin Clement return mlir::LLVM::Linkage::Common; 942044d5b5dSValentin Clement if (name == "weak") 943044d5b5dSValentin Clement return mlir::LLVM::Linkage::Weak; 944044d5b5dSValentin Clement } 945044d5b5dSValentin Clement return mlir::LLVM::Linkage::External; 946044d5b5dSValentin Clement } 947044d5b5dSValentin Clement }; 948044d5b5dSValentin Clement 94939f4ef81SValentin Clement void genCondBrOp(mlir::Location loc, mlir::Value cmp, mlir::Block *dest, 95039f4ef81SValentin Clement Optional<mlir::ValueRange> destOps, 95139f4ef81SValentin Clement mlir::ConversionPatternRewriter &rewriter, 95239f4ef81SValentin Clement mlir::Block *newBlock) { 95339f4ef81SValentin Clement if (destOps.hasValue()) 95439f4ef81SValentin Clement rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, destOps.getValue(), 95539f4ef81SValentin Clement newBlock, mlir::ValueRange()); 95639f4ef81SValentin Clement else 95739f4ef81SValentin Clement rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, newBlock); 95839f4ef81SValentin Clement } 95939f4ef81SValentin Clement 96039f4ef81SValentin Clement template <typename A, typename B> 96139f4ef81SValentin Clement void genBrOp(A caseOp, mlir::Block *dest, Optional<B> destOps, 96239f4ef81SValentin Clement mlir::ConversionPatternRewriter &rewriter) { 96339f4ef81SValentin Clement if (destOps.hasValue()) 96439f4ef81SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, destOps.getValue(), 96539f4ef81SValentin Clement dest); 96639f4ef81SValentin Clement else 96739f4ef81SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, llvm::None, dest); 96839f4ef81SValentin Clement } 96939f4ef81SValentin Clement 97039f4ef81SValentin Clement void genCaseLadderStep(mlir::Location loc, mlir::Value cmp, mlir::Block *dest, 97139f4ef81SValentin Clement Optional<mlir::ValueRange> destOps, 97239f4ef81SValentin Clement mlir::ConversionPatternRewriter &rewriter) { 97339f4ef81SValentin Clement auto *thisBlock = rewriter.getInsertionBlock(); 97439f4ef81SValentin Clement auto *newBlock = createBlock(rewriter, dest); 97539f4ef81SValentin Clement rewriter.setInsertionPointToEnd(thisBlock); 97639f4ef81SValentin Clement genCondBrOp(loc, cmp, dest, destOps, rewriter, newBlock); 97739f4ef81SValentin Clement rewriter.setInsertionPointToEnd(newBlock); 97839f4ef81SValentin Clement } 97939f4ef81SValentin Clement 98039f4ef81SValentin Clement /// Conversion of `fir.select_case` 98139f4ef81SValentin Clement /// 98239f4ef81SValentin Clement /// The `fir.select_case` operation is converted to a if-then-else ladder. 98339f4ef81SValentin Clement /// Depending on the case condition type, one or several comparison and 98439f4ef81SValentin Clement /// conditional branching can be generated. 98539f4ef81SValentin Clement /// 98639f4ef81SValentin Clement /// A a point value case such as `case(4)`, a lower bound case such as 98739f4ef81SValentin Clement /// `case(5:)` or an upper bound case such as `case(:3)` are converted to a 98839f4ef81SValentin Clement /// simple comparison between the selector value and the constant value in the 98939f4ef81SValentin Clement /// case. The block associated with the case condition is then executed if 99039f4ef81SValentin Clement /// the comparison succeed otherwise it branch to the next block with the 99139f4ef81SValentin Clement /// comparison for the the next case conditon. 99239f4ef81SValentin Clement /// 99339f4ef81SValentin Clement /// A closed interval case condition such as `case(7:10)` is converted with a 99439f4ef81SValentin Clement /// first comparison and conditional branching for the lower bound. If 99539f4ef81SValentin Clement /// successful, it branch to a second block with the comparison for the 99639f4ef81SValentin Clement /// upper bound in the same case condition. 99739f4ef81SValentin Clement /// 99839f4ef81SValentin Clement /// TODO: lowering of CHARACTER type cases is not handled yet. 99939f4ef81SValentin Clement struct SelectCaseOpConversion : public FIROpConversion<fir::SelectCaseOp> { 100039f4ef81SValentin Clement using FIROpConversion::FIROpConversion; 100139f4ef81SValentin Clement 100239f4ef81SValentin Clement mlir::LogicalResult 100339f4ef81SValentin Clement matchAndRewrite(fir::SelectCaseOp caseOp, OpAdaptor adaptor, 100439f4ef81SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 100539f4ef81SValentin Clement unsigned conds = caseOp.getNumConditions(); 100639f4ef81SValentin Clement llvm::ArrayRef<mlir::Attribute> cases = caseOp.getCases().getValue(); 100739f4ef81SValentin Clement // Type can be CHARACTER, INTEGER, or LOGICAL (C1145) 100839f4ef81SValentin Clement LLVM_ATTRIBUTE_UNUSED auto ty = caseOp.getSelector().getType(); 100939f4ef81SValentin Clement if (ty.isa<fir::CharacterType>()) 101039f4ef81SValentin Clement return rewriter.notifyMatchFailure(caseOp, 101139f4ef81SValentin Clement "conversion of fir.select_case with " 101239f4ef81SValentin Clement "character type not implemented yet"); 101339f4ef81SValentin Clement mlir::Value selector = caseOp.getSelector(adaptor.getOperands()); 101439f4ef81SValentin Clement auto loc = caseOp.getLoc(); 101539f4ef81SValentin Clement for (unsigned t = 0; t != conds; ++t) { 101639f4ef81SValentin Clement mlir::Block *dest = caseOp.getSuccessor(t); 101739f4ef81SValentin Clement llvm::Optional<mlir::ValueRange> destOps = 101839f4ef81SValentin Clement caseOp.getSuccessorOperands(adaptor.getOperands(), t); 101939f4ef81SValentin Clement llvm::Optional<mlir::ValueRange> cmpOps = 102039f4ef81SValentin Clement *caseOp.getCompareOperands(adaptor.getOperands(), t); 102139f4ef81SValentin Clement mlir::Value caseArg = *(cmpOps.getValue().begin()); 102239f4ef81SValentin Clement mlir::Attribute attr = cases[t]; 102339f4ef81SValentin Clement if (attr.isa<fir::PointIntervalAttr>()) { 102439f4ef81SValentin Clement auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 102539f4ef81SValentin Clement loc, mlir::LLVM::ICmpPredicate::eq, selector, caseArg); 102639f4ef81SValentin Clement genCaseLadderStep(loc, cmp, dest, destOps, rewriter); 102739f4ef81SValentin Clement continue; 102839f4ef81SValentin Clement } 102939f4ef81SValentin Clement if (attr.isa<fir::LowerBoundAttr>()) { 103039f4ef81SValentin Clement auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 103139f4ef81SValentin Clement loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector); 103239f4ef81SValentin Clement genCaseLadderStep(loc, cmp, dest, destOps, rewriter); 103339f4ef81SValentin Clement continue; 103439f4ef81SValentin Clement } 103539f4ef81SValentin Clement if (attr.isa<fir::UpperBoundAttr>()) { 103639f4ef81SValentin Clement auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 103739f4ef81SValentin Clement loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg); 103839f4ef81SValentin Clement genCaseLadderStep(loc, cmp, dest, destOps, rewriter); 103939f4ef81SValentin Clement continue; 104039f4ef81SValentin Clement } 104139f4ef81SValentin Clement if (attr.isa<fir::ClosedIntervalAttr>()) { 104239f4ef81SValentin Clement auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 104339f4ef81SValentin Clement loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector); 104439f4ef81SValentin Clement auto *thisBlock = rewriter.getInsertionBlock(); 104539f4ef81SValentin Clement auto *newBlock1 = createBlock(rewriter, dest); 104639f4ef81SValentin Clement auto *newBlock2 = createBlock(rewriter, dest); 104739f4ef81SValentin Clement rewriter.setInsertionPointToEnd(thisBlock); 104839f4ef81SValentin Clement rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, newBlock1, newBlock2); 104939f4ef81SValentin Clement rewriter.setInsertionPointToEnd(newBlock1); 105039f4ef81SValentin Clement mlir::Value caseArg0 = *(cmpOps.getValue().begin() + 1); 105139f4ef81SValentin Clement auto cmp0 = rewriter.create<mlir::LLVM::ICmpOp>( 105239f4ef81SValentin Clement loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg0); 105339f4ef81SValentin Clement genCondBrOp(loc, cmp0, dest, destOps, rewriter, newBlock2); 105439f4ef81SValentin Clement rewriter.setInsertionPointToEnd(newBlock2); 105539f4ef81SValentin Clement continue; 105639f4ef81SValentin Clement } 105739f4ef81SValentin Clement assert(attr.isa<mlir::UnitAttr>()); 105839f4ef81SValentin Clement assert((t + 1 == conds) && "unit must be last"); 105939f4ef81SValentin Clement genBrOp(caseOp, dest, destOps, rewriter); 106039f4ef81SValentin Clement } 106139f4ef81SValentin Clement return success(); 106239f4ef81SValentin Clement } 106339f4ef81SValentin Clement }; 106439f4ef81SValentin Clement 10658c239909SValentin Clement template <typename OP> 10668c239909SValentin Clement void selectMatchAndRewrite(fir::LLVMTypeConverter &lowering, OP select, 10678c239909SValentin Clement typename OP::Adaptor adaptor, 10688c239909SValentin Clement mlir::ConversionPatternRewriter &rewriter) { 10698c239909SValentin Clement unsigned conds = select.getNumConditions(); 10708c239909SValentin Clement auto cases = select.getCases().getValue(); 10718c239909SValentin Clement mlir::Value selector = adaptor.selector(); 10728c239909SValentin Clement auto loc = select.getLoc(); 10738c239909SValentin Clement assert(conds > 0 && "select must have cases"); 10748c239909SValentin Clement 10758c239909SValentin Clement llvm::SmallVector<mlir::Block *> destinations; 10768c239909SValentin Clement llvm::SmallVector<mlir::ValueRange> destinationsOperands; 10778c239909SValentin Clement mlir::Block *defaultDestination; 10788c239909SValentin Clement mlir::ValueRange defaultOperands; 10798c239909SValentin Clement llvm::SmallVector<int32_t> caseValues; 10808c239909SValentin Clement 10818c239909SValentin Clement for (unsigned t = 0; t != conds; ++t) { 10828c239909SValentin Clement mlir::Block *dest = select.getSuccessor(t); 10838c239909SValentin Clement auto destOps = select.getSuccessorOperands(adaptor.getOperands(), t); 10848c239909SValentin Clement const mlir::Attribute &attr = cases[t]; 10858c239909SValentin Clement if (auto intAttr = attr.template dyn_cast<mlir::IntegerAttr>()) { 10868c239909SValentin Clement destinations.push_back(dest); 10878c239909SValentin Clement destinationsOperands.push_back(destOps.hasValue() ? *destOps 10888c239909SValentin Clement : ValueRange()); 10898c239909SValentin Clement caseValues.push_back(intAttr.getInt()); 10908c239909SValentin Clement continue; 10918c239909SValentin Clement } 10928c239909SValentin Clement assert(attr.template dyn_cast_or_null<mlir::UnitAttr>()); 10938c239909SValentin Clement assert((t + 1 == conds) && "unit must be last"); 10948c239909SValentin Clement defaultDestination = dest; 10958c239909SValentin Clement defaultOperands = destOps.hasValue() ? *destOps : ValueRange(); 10968c239909SValentin Clement } 10978c239909SValentin Clement 10988c239909SValentin Clement // LLVM::SwitchOp takes a i32 type for the selector. 10998c239909SValentin Clement if (select.getSelector().getType() != rewriter.getI32Type()) 11008c239909SValentin Clement selector = 11018c239909SValentin Clement rewriter.create<LLVM::TruncOp>(loc, rewriter.getI32Type(), selector); 11028c239909SValentin Clement 11038c239909SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>( 11048c239909SValentin Clement select, selector, 11058c239909SValentin Clement /*defaultDestination=*/defaultDestination, 11068c239909SValentin Clement /*defaultOperands=*/defaultOperands, 11078c239909SValentin Clement /*caseValues=*/caseValues, 11088c239909SValentin Clement /*caseDestinations=*/destinations, 11098c239909SValentin Clement /*caseOperands=*/destinationsOperands, 11108c239909SValentin Clement /*branchWeights=*/ArrayRef<int32_t>()); 11118c239909SValentin Clement } 11128c239909SValentin Clement 11138c239909SValentin Clement /// conversion of fir::SelectOp to an if-then-else ladder 11148c239909SValentin Clement struct SelectOpConversion : public FIROpConversion<fir::SelectOp> { 11158c239909SValentin Clement using FIROpConversion::FIROpConversion; 11168c239909SValentin Clement 11178c239909SValentin Clement mlir::LogicalResult 11188c239909SValentin Clement matchAndRewrite(fir::SelectOp op, OpAdaptor adaptor, 11198c239909SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 11208c239909SValentin Clement selectMatchAndRewrite<fir::SelectOp>(lowerTy(), op, adaptor, rewriter); 11218c239909SValentin Clement return success(); 11228c239909SValentin Clement } 11238c239909SValentin Clement }; 11248c239909SValentin Clement 1125e3349fa1SAndrzej Warzynski /// `fir.load` --> `llvm.load` 1126e3349fa1SAndrzej Warzynski struct LoadOpConversion : public FIROpConversion<fir::LoadOp> { 1127e3349fa1SAndrzej Warzynski using FIROpConversion::FIROpConversion; 1128e3349fa1SAndrzej Warzynski 1129e3349fa1SAndrzej Warzynski mlir::LogicalResult 1130e3349fa1SAndrzej Warzynski matchAndRewrite(fir::LoadOp load, OpAdaptor adaptor, 1131e3349fa1SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 1132e3349fa1SAndrzej Warzynski // fir.box is a special case because it is considered as an ssa values in 1133e3349fa1SAndrzej Warzynski // fir, but it is lowered as a pointer to a descriptor. So fir.ref<fir.box> 1134e3349fa1SAndrzej Warzynski // and fir.box end up being the same llvm types and loading a 1135e3349fa1SAndrzej Warzynski // fir.ref<fir.box> is actually a no op in LLVM. 1136e3349fa1SAndrzej Warzynski if (load.getType().isa<fir::BoxType>()) { 1137e3349fa1SAndrzej Warzynski rewriter.replaceOp(load, adaptor.getOperands()[0]); 1138e3349fa1SAndrzej Warzynski } else { 1139e3349fa1SAndrzej Warzynski mlir::Type ty = convertType(load.getType()); 1140e3349fa1SAndrzej Warzynski ArrayRef<NamedAttribute> at = load->getAttrs(); 1141e3349fa1SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::LoadOp>( 1142e3349fa1SAndrzej Warzynski load, ty, adaptor.getOperands(), at); 1143e3349fa1SAndrzej Warzynski } 1144e3349fa1SAndrzej Warzynski return success(); 1145e3349fa1SAndrzej Warzynski } 1146e3349fa1SAndrzej Warzynski }; 1147e3349fa1SAndrzej Warzynski 11482a299e4fSValentin Clement /// Lower `fir.select_type` to LLVM IR dialect. 11492a299e4fSValentin Clement struct SelectTypeOpConversion : public FIROpConversion<fir::SelectTypeOp> { 11502a299e4fSValentin Clement using FIROpConversion::FIROpConversion; 11512a299e4fSValentin Clement 11522a299e4fSValentin Clement mlir::LogicalResult 11532a299e4fSValentin Clement matchAndRewrite(fir::SelectTypeOp select, OpAdaptor adaptor, 11542a299e4fSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 11552a299e4fSValentin Clement return rewriter.notifyMatchFailure( 11562a299e4fSValentin Clement select, "fir.select_type codegen is not implemented yet"); 11572a299e4fSValentin Clement } 11582a299e4fSValentin Clement }; 11592a299e4fSValentin Clement 11608c239909SValentin Clement /// conversion of fir::SelectRankOp to an if-then-else ladder 11618c239909SValentin Clement struct SelectRankOpConversion : public FIROpConversion<fir::SelectRankOp> { 11628c239909SValentin Clement using FIROpConversion::FIROpConversion; 11638c239909SValentin Clement 11648c239909SValentin Clement mlir::LogicalResult 11658c239909SValentin Clement matchAndRewrite(fir::SelectRankOp op, OpAdaptor adaptor, 11668c239909SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 11678c239909SValentin Clement selectMatchAndRewrite<fir::SelectRankOp>(lowerTy(), op, adaptor, rewriter); 11688c239909SValentin Clement return success(); 11698c239909SValentin Clement } 11708c239909SValentin Clement }; 11718c239909SValentin Clement 1172e3349fa1SAndrzej Warzynski /// `fir.store` --> `llvm.store` 1173e3349fa1SAndrzej Warzynski struct StoreOpConversion : public FIROpConversion<fir::StoreOp> { 1174e3349fa1SAndrzej Warzynski using FIROpConversion::FIROpConversion; 1175e3349fa1SAndrzej Warzynski 1176e3349fa1SAndrzej Warzynski mlir::LogicalResult 1177e3349fa1SAndrzej Warzynski matchAndRewrite(fir::StoreOp store, OpAdaptor adaptor, 1178e3349fa1SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 1179e3349fa1SAndrzej Warzynski if (store.value().getType().isa<fir::BoxType>()) { 1180e3349fa1SAndrzej Warzynski // fir.box value is actually in memory, load it first before storing it. 1181e3349fa1SAndrzej Warzynski mlir::Location loc = store.getLoc(); 1182e3349fa1SAndrzej Warzynski mlir::Type boxPtrTy = adaptor.getOperands()[0].getType(); 1183e3349fa1SAndrzej Warzynski auto val = rewriter.create<mlir::LLVM::LoadOp>( 1184e3349fa1SAndrzej Warzynski loc, boxPtrTy.cast<mlir::LLVM::LLVMPointerType>().getElementType(), 1185e3349fa1SAndrzej Warzynski adaptor.getOperands()[0]); 1186e3349fa1SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>( 1187e3349fa1SAndrzej Warzynski store, val, adaptor.getOperands()[1]); 1188e3349fa1SAndrzej Warzynski } else { 1189e3349fa1SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>( 1190e3349fa1SAndrzej Warzynski store, adaptor.getOperands()[0], adaptor.getOperands()[1]); 1191e3349fa1SAndrzej Warzynski } 1192e3349fa1SAndrzej Warzynski return success(); 1193e3349fa1SAndrzej Warzynski } 1194e3349fa1SAndrzej Warzynski }; 1195e3349fa1SAndrzej Warzynski 1196e3349fa1SAndrzej Warzynski /// convert to LLVM IR dialect `undef` 1197044d5b5dSValentin Clement struct UndefOpConversion : public FIROpConversion<fir::UndefOp> { 1198044d5b5dSValentin Clement using FIROpConversion::FIROpConversion; 1199044d5b5dSValentin Clement 1200044d5b5dSValentin Clement mlir::LogicalResult 1201044d5b5dSValentin Clement matchAndRewrite(fir::UndefOp undef, OpAdaptor, 1202044d5b5dSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 1203044d5b5dSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::UndefOp>( 1204044d5b5dSValentin Clement undef, convertType(undef.getType())); 1205044d5b5dSValentin Clement return success(); 1206044d5b5dSValentin Clement } 1207044d5b5dSValentin Clement }; 1208a7a61359SValentin Clement 1209e3349fa1SAndrzej Warzynski /// `fir.unreachable` --> `llvm.unreachable` 121032e08248SAndrzej Warzynski struct UnreachableOpConversion : public FIROpConversion<fir::UnreachableOp> { 121132e08248SAndrzej Warzynski using FIROpConversion::FIROpConversion; 121232e08248SAndrzej Warzynski 121332e08248SAndrzej Warzynski mlir::LogicalResult 121432e08248SAndrzej Warzynski matchAndRewrite(fir::UnreachableOp unreach, OpAdaptor adaptor, 121532e08248SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 121632e08248SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(unreach); 121732e08248SAndrzej Warzynski return success(); 121832e08248SAndrzej Warzynski } 121932e08248SAndrzej Warzynski }; 122032e08248SAndrzej Warzynski 1221a7a61359SValentin Clement struct ZeroOpConversion : public FIROpConversion<fir::ZeroOp> { 1222a7a61359SValentin Clement using FIROpConversion::FIROpConversion; 1223a7a61359SValentin Clement 1224a7a61359SValentin Clement mlir::LogicalResult 1225a7a61359SValentin Clement matchAndRewrite(fir::ZeroOp zero, OpAdaptor, 1226a7a61359SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 1227a7a61359SValentin Clement auto ty = convertType(zero.getType()); 1228a7a61359SValentin Clement if (ty.isa<mlir::LLVM::LLVMPointerType>()) { 1229a7a61359SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(zero, ty); 1230a7a61359SValentin Clement } else if (ty.isa<mlir::IntegerType>()) { 1231a7a61359SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>( 1232a7a61359SValentin Clement zero, ty, mlir::IntegerAttr::get(zero.getType(), 0)); 1233a7a61359SValentin Clement } else if (mlir::LLVM::isCompatibleFloatingPointType(ty)) { 1234a7a61359SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>( 1235a7a61359SValentin Clement zero, ty, mlir::FloatAttr::get(zero.getType(), 0.0)); 1236a7a61359SValentin Clement } else { 1237a7a61359SValentin Clement // TODO: create ConstantAggregateZero for FIR aggregate/array types. 123852d813edSValentin Clement return rewriter.notifyMatchFailure( 123952d813edSValentin Clement zero, 1240a7a61359SValentin Clement "conversion of fir.zero with aggregate type not implemented yet"); 1241a7a61359SValentin Clement } 1242a7a61359SValentin Clement return success(); 1243a7a61359SValentin Clement } 1244a7a61359SValentin Clement }; 124532e08248SAndrzej Warzynski 1246af6ee580SValentin Clement /// Common base class for embox to descriptor conversion. 1247af6ee580SValentin Clement template <typename OP> 1248af6ee580SValentin Clement struct EmboxCommonConversion : public FIROpConversion<OP> { 1249af6ee580SValentin Clement using FIROpConversion<OP>::FIROpConversion; 1250af6ee580SValentin Clement 1251af6ee580SValentin Clement // Find the LLVMFuncOp in whose entry block the alloca should be inserted. 1252af6ee580SValentin Clement // The order to find the LLVMFuncOp is as follows: 1253af6ee580SValentin Clement // 1. The parent operation of the current block if it is a LLVMFuncOp. 1254af6ee580SValentin Clement // 2. The first ancestor that is a LLVMFuncOp. 1255af6ee580SValentin Clement mlir::LLVM::LLVMFuncOp 1256af6ee580SValentin Clement getFuncForAllocaInsert(mlir::ConversionPatternRewriter &rewriter) const { 1257af6ee580SValentin Clement mlir::Operation *parentOp = rewriter.getInsertionBlock()->getParentOp(); 1258af6ee580SValentin Clement return mlir::isa<mlir::LLVM::LLVMFuncOp>(parentOp) 1259af6ee580SValentin Clement ? mlir::cast<mlir::LLVM::LLVMFuncOp>(parentOp) 1260af6ee580SValentin Clement : parentOp->getParentOfType<mlir::LLVM::LLVMFuncOp>(); 1261af6ee580SValentin Clement } 1262af6ee580SValentin Clement 1263af6ee580SValentin Clement // Generate an alloca of size 1 and type \p toTy. 1264af6ee580SValentin Clement mlir::LLVM::AllocaOp 1265af6ee580SValentin Clement genAllocaWithType(mlir::Location loc, mlir::Type toTy, unsigned alignment, 1266af6ee580SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 1267af6ee580SValentin Clement auto thisPt = rewriter.saveInsertionPoint(); 1268af6ee580SValentin Clement mlir::LLVM::LLVMFuncOp func = getFuncForAllocaInsert(rewriter); 1269af6ee580SValentin Clement rewriter.setInsertionPointToStart(&func.front()); 1270af6ee580SValentin Clement auto size = this->genI32Constant(loc, rewriter, 1); 1271af6ee580SValentin Clement auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, toTy, size, alignment); 1272af6ee580SValentin Clement rewriter.restoreInsertionPoint(thisPt); 1273af6ee580SValentin Clement return al; 1274af6ee580SValentin Clement } 1275af6ee580SValentin Clement 1276af6ee580SValentin Clement static int getCFIAttr(fir::BoxType boxTy) { 1277af6ee580SValentin Clement auto eleTy = boxTy.getEleTy(); 1278af6ee580SValentin Clement if (eleTy.isa<fir::PointerType>()) 1279af6ee580SValentin Clement return CFI_attribute_pointer; 1280af6ee580SValentin Clement if (eleTy.isa<fir::HeapType>()) 1281af6ee580SValentin Clement return CFI_attribute_allocatable; 1282af6ee580SValentin Clement return CFI_attribute_other; 1283af6ee580SValentin Clement } 1284af6ee580SValentin Clement 1285af6ee580SValentin Clement static fir::RecordType unwrapIfDerived(fir::BoxType boxTy) { 1286af6ee580SValentin Clement return fir::unwrapSequenceType(fir::dyn_cast_ptrOrBoxEleTy(boxTy)) 1287af6ee580SValentin Clement .template dyn_cast<fir::RecordType>(); 1288af6ee580SValentin Clement } 1289af6ee580SValentin Clement static bool isDerivedTypeWithLenParams(fir::BoxType boxTy) { 1290af6ee580SValentin Clement auto recTy = unwrapIfDerived(boxTy); 1291af6ee580SValentin Clement return recTy && recTy.getNumLenParams() > 0; 1292af6ee580SValentin Clement } 1293af6ee580SValentin Clement static bool isDerivedType(fir::BoxType boxTy) { 1294af6ee580SValentin Clement return unwrapIfDerived(boxTy) != nullptr; 1295af6ee580SValentin Clement } 1296af6ee580SValentin Clement 1297af6ee580SValentin Clement // Get the element size and CFI type code of the boxed value. 1298af6ee580SValentin Clement std::tuple<mlir::Value, mlir::Value> getSizeAndTypeCode( 1299af6ee580SValentin Clement mlir::Location loc, mlir::ConversionPatternRewriter &rewriter, 1300af6ee580SValentin Clement mlir::Type boxEleTy, mlir::ValueRange lenParams = {}) const { 1301af6ee580SValentin Clement auto doInteger = 1302af6ee580SValentin Clement [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> { 1303af6ee580SValentin Clement int typeCode = fir::integerBitsToTypeCode(width); 1304af6ee580SValentin Clement return {this->genConstantOffset(loc, rewriter, width / 8), 1305af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, typeCode)}; 1306af6ee580SValentin Clement }; 1307af6ee580SValentin Clement auto doLogical = 1308af6ee580SValentin Clement [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> { 1309af6ee580SValentin Clement int typeCode = fir::logicalBitsToTypeCode(width); 1310af6ee580SValentin Clement return {this->genConstantOffset(loc, rewriter, width / 8), 1311af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, typeCode)}; 1312af6ee580SValentin Clement }; 1313af6ee580SValentin Clement auto doFloat = [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> { 1314af6ee580SValentin Clement int typeCode = fir::realBitsToTypeCode(width); 1315af6ee580SValentin Clement return {this->genConstantOffset(loc, rewriter, width / 8), 1316af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, typeCode)}; 1317af6ee580SValentin Clement }; 1318af6ee580SValentin Clement auto doComplex = 1319af6ee580SValentin Clement [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> { 1320af6ee580SValentin Clement auto typeCode = fir::complexBitsToTypeCode(width); 1321af6ee580SValentin Clement return {this->genConstantOffset(loc, rewriter, width / 8 * 2), 1322af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, typeCode)}; 1323af6ee580SValentin Clement }; 1324af6ee580SValentin Clement auto doCharacter = 1325af6ee580SValentin Clement [&](unsigned width, 1326af6ee580SValentin Clement mlir::Value len) -> std::tuple<mlir::Value, mlir::Value> { 1327af6ee580SValentin Clement auto typeCode = fir::characterBitsToTypeCode(width); 1328af6ee580SValentin Clement auto typeCodeVal = this->genConstantOffset(loc, rewriter, typeCode); 1329af6ee580SValentin Clement if (width == 8) 1330af6ee580SValentin Clement return {len, typeCodeVal}; 1331af6ee580SValentin Clement auto byteWidth = this->genConstantOffset(loc, rewriter, width / 8); 1332af6ee580SValentin Clement auto i64Ty = mlir::IntegerType::get(&this->lowerTy().getContext(), 64); 1333af6ee580SValentin Clement auto size = 1334af6ee580SValentin Clement rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, byteWidth, len); 1335af6ee580SValentin Clement return {size, typeCodeVal}; 1336af6ee580SValentin Clement }; 1337af6ee580SValentin Clement auto getKindMap = [&]() -> fir::KindMapping & { 1338af6ee580SValentin Clement return this->lowerTy().getKindMap(); 1339af6ee580SValentin Clement }; 1340af6ee580SValentin Clement // Pointer-like types. 1341af6ee580SValentin Clement if (auto eleTy = fir::dyn_cast_ptrEleTy(boxEleTy)) 1342af6ee580SValentin Clement boxEleTy = eleTy; 1343af6ee580SValentin Clement // Integer types. 1344af6ee580SValentin Clement if (fir::isa_integer(boxEleTy)) { 1345af6ee580SValentin Clement if (auto ty = boxEleTy.dyn_cast<mlir::IntegerType>()) 1346af6ee580SValentin Clement return doInteger(ty.getWidth()); 1347af6ee580SValentin Clement auto ty = boxEleTy.cast<fir::IntegerType>(); 1348af6ee580SValentin Clement return doInteger(getKindMap().getIntegerBitsize(ty.getFKind())); 1349af6ee580SValentin Clement } 1350af6ee580SValentin Clement // Floating point types. 1351af6ee580SValentin Clement if (fir::isa_real(boxEleTy)) { 1352af6ee580SValentin Clement if (auto ty = boxEleTy.dyn_cast<mlir::FloatType>()) 1353af6ee580SValentin Clement return doFloat(ty.getWidth()); 1354af6ee580SValentin Clement auto ty = boxEleTy.cast<fir::RealType>(); 1355af6ee580SValentin Clement return doFloat(getKindMap().getRealBitsize(ty.getFKind())); 1356af6ee580SValentin Clement } 1357af6ee580SValentin Clement // Complex types. 1358af6ee580SValentin Clement if (fir::isa_complex(boxEleTy)) { 1359af6ee580SValentin Clement if (auto ty = boxEleTy.dyn_cast<mlir::ComplexType>()) 1360af6ee580SValentin Clement return doComplex( 1361af6ee580SValentin Clement ty.getElementType().cast<mlir::FloatType>().getWidth()); 1362af6ee580SValentin Clement auto ty = boxEleTy.cast<fir::ComplexType>(); 1363af6ee580SValentin Clement return doComplex(getKindMap().getRealBitsize(ty.getFKind())); 1364af6ee580SValentin Clement } 1365af6ee580SValentin Clement // Character types. 1366af6ee580SValentin Clement if (auto ty = boxEleTy.dyn_cast<fir::CharacterType>()) { 1367af6ee580SValentin Clement auto charWidth = getKindMap().getCharacterBitsize(ty.getFKind()); 1368af6ee580SValentin Clement if (ty.getLen() != fir::CharacterType::unknownLen()) { 1369af6ee580SValentin Clement auto len = this->genConstantOffset(loc, rewriter, ty.getLen()); 1370af6ee580SValentin Clement return doCharacter(charWidth, len); 1371af6ee580SValentin Clement } 1372af6ee580SValentin Clement assert(!lenParams.empty()); 1373af6ee580SValentin Clement return doCharacter(charWidth, lenParams.back()); 1374af6ee580SValentin Clement } 1375af6ee580SValentin Clement // Logical type. 1376af6ee580SValentin Clement if (auto ty = boxEleTy.dyn_cast<fir::LogicalType>()) 1377af6ee580SValentin Clement return doLogical(getKindMap().getLogicalBitsize(ty.getFKind())); 1378af6ee580SValentin Clement // Array types. 1379af6ee580SValentin Clement if (auto seqTy = boxEleTy.dyn_cast<fir::SequenceType>()) 1380af6ee580SValentin Clement return getSizeAndTypeCode(loc, rewriter, seqTy.getEleTy(), lenParams); 1381af6ee580SValentin Clement // Derived-type types. 1382af6ee580SValentin Clement if (boxEleTy.isa<fir::RecordType>()) { 1383af6ee580SValentin Clement auto ptrTy = mlir::LLVM::LLVMPointerType::get( 1384af6ee580SValentin Clement this->lowerTy().convertType(boxEleTy)); 1385af6ee580SValentin Clement auto nullPtr = rewriter.create<mlir::LLVM::NullOp>(loc, ptrTy); 1386af6ee580SValentin Clement auto one = 1387af6ee580SValentin Clement genConstantIndex(loc, this->lowerTy().offsetType(), rewriter, 1); 1388af6ee580SValentin Clement auto gep = rewriter.create<mlir::LLVM::GEPOp>( 1389af6ee580SValentin Clement loc, ptrTy, mlir::ValueRange{nullPtr, one}); 1390af6ee580SValentin Clement auto eleSize = rewriter.create<mlir::LLVM::PtrToIntOp>( 1391af6ee580SValentin Clement loc, this->lowerTy().indexType(), gep); 1392af6ee580SValentin Clement return {eleSize, 1393af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, fir::derivedToTypeCode())}; 1394af6ee580SValentin Clement } 1395af6ee580SValentin Clement // Reference type. 1396af6ee580SValentin Clement if (fir::isa_ref_type(boxEleTy)) { 1397af6ee580SValentin Clement // FIXME: use the target pointer size rather than sizeof(void*) 1398af6ee580SValentin Clement return {this->genConstantOffset(loc, rewriter, sizeof(void *)), 1399af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, CFI_type_cptr)}; 1400af6ee580SValentin Clement } 1401af6ee580SValentin Clement fir::emitFatalError(loc, "unhandled type in fir.box code generation"); 1402af6ee580SValentin Clement } 1403af6ee580SValentin Clement 1404af6ee580SValentin Clement /// Basic pattern to write a field in the descriptor 1405af6ee580SValentin Clement mlir::Value insertField(mlir::ConversionPatternRewriter &rewriter, 1406af6ee580SValentin Clement mlir::Location loc, mlir::Value dest, 1407af6ee580SValentin Clement ArrayRef<unsigned> fldIndexes, mlir::Value value, 1408af6ee580SValentin Clement bool bitcast = false) const { 1409af6ee580SValentin Clement auto boxTy = dest.getType(); 1410af6ee580SValentin Clement auto fldTy = this->getBoxEleTy(boxTy, fldIndexes); 1411af6ee580SValentin Clement if (bitcast) 1412af6ee580SValentin Clement value = rewriter.create<mlir::LLVM::BitcastOp>(loc, fldTy, value); 1413af6ee580SValentin Clement else 1414af6ee580SValentin Clement value = this->integerCast(loc, rewriter, fldTy, value); 1415af6ee580SValentin Clement SmallVector<mlir::Attribute, 2> attrs; 1416af6ee580SValentin Clement for (auto i : fldIndexes) 1417af6ee580SValentin Clement attrs.push_back(rewriter.getI32IntegerAttr(i)); 1418af6ee580SValentin Clement auto indexesAttr = mlir::ArrayAttr::get(rewriter.getContext(), attrs); 1419af6ee580SValentin Clement return rewriter.create<mlir::LLVM::InsertValueOp>(loc, boxTy, dest, value, 1420af6ee580SValentin Clement indexesAttr); 1421af6ee580SValentin Clement } 1422af6ee580SValentin Clement 1423af6ee580SValentin Clement inline mlir::Value 1424af6ee580SValentin Clement insertBaseAddress(mlir::ConversionPatternRewriter &rewriter, 1425af6ee580SValentin Clement mlir::Location loc, mlir::Value dest, 1426af6ee580SValentin Clement mlir::Value base) const { 1427af6ee580SValentin Clement return insertField(rewriter, loc, dest, {0}, base, /*bitCast=*/true); 1428af6ee580SValentin Clement } 1429af6ee580SValentin Clement 1430af6ee580SValentin Clement /// Get the address of the type descriptor global variable that was created by 1431af6ee580SValentin Clement /// lowering for derived type \p recType. 1432af6ee580SValentin Clement template <typename BOX> 1433af6ee580SValentin Clement mlir::Value 1434af6ee580SValentin Clement getTypeDescriptor(BOX box, mlir::ConversionPatternRewriter &rewriter, 1435af6ee580SValentin Clement mlir::Location loc, fir::RecordType recType) const { 1436af6ee580SValentin Clement std::string name = recType.getLoweredName(); 1437af6ee580SValentin Clement auto module = box->template getParentOfType<mlir::ModuleOp>(); 1438af6ee580SValentin Clement if (auto global = module.template lookupSymbol<fir::GlobalOp>(name)) { 1439af6ee580SValentin Clement auto ty = mlir::LLVM::LLVMPointerType::get( 1440af6ee580SValentin Clement this->lowerTy().convertType(global.getType())); 1441af6ee580SValentin Clement return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty, 1442af6ee580SValentin Clement global.sym_name()); 1443af6ee580SValentin Clement } 1444af6ee580SValentin Clement if (auto global = 1445af6ee580SValentin Clement module.template lookupSymbol<mlir::LLVM::GlobalOp>(name)) { 1446af6ee580SValentin Clement // The global may have already been translated to LLVM. 1447af6ee580SValentin Clement auto ty = mlir::LLVM::LLVMPointerType::get(global.getType()); 1448af6ee580SValentin Clement return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty, 1449af6ee580SValentin Clement global.sym_name()); 1450af6ee580SValentin Clement } 1451af6ee580SValentin Clement // The global does not exist in the current translation unit, but may be 1452af6ee580SValentin Clement // defined elsewhere (e.g., type defined in a module). 1453af6ee580SValentin Clement // For now, create a extern_weak symbol (will become nullptr if unresolved) 1454af6ee580SValentin Clement // to support generating code without the front-end generated symbols. 1455af6ee580SValentin Clement // These could be made available_externally to require the symbols to be 1456af6ee580SValentin Clement // defined elsewhere and to cause link-time failure otherwise. 1457af6ee580SValentin Clement auto i8Ty = rewriter.getIntegerType(8); 1458af6ee580SValentin Clement mlir::OpBuilder modBuilder(module.getBodyRegion()); 1459af6ee580SValentin Clement // TODO: The symbol should be lowered to constant in lowering, they are read 1460af6ee580SValentin Clement // only. 1461af6ee580SValentin Clement modBuilder.create<mlir::LLVM::GlobalOp>(loc, i8Ty, /*isConstant=*/false, 1462af6ee580SValentin Clement mlir::LLVM::Linkage::ExternWeak, 1463af6ee580SValentin Clement name, mlir::Attribute{}); 1464af6ee580SValentin Clement auto ty = mlir::LLVM::LLVMPointerType::get(i8Ty); 1465af6ee580SValentin Clement return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty, name); 1466af6ee580SValentin Clement } 1467af6ee580SValentin Clement 1468af6ee580SValentin Clement template <typename BOX> 1469af6ee580SValentin Clement std::tuple<fir::BoxType, mlir::Value, mlir::Value> 1470af6ee580SValentin Clement consDescriptorPrefix(BOX box, mlir::ConversionPatternRewriter &rewriter, 1471af6ee580SValentin Clement unsigned rank, mlir::ValueRange lenParams) const { 1472af6ee580SValentin Clement auto loc = box.getLoc(); 1473af6ee580SValentin Clement auto boxTy = box.getType().template dyn_cast<fir::BoxType>(); 1474af6ee580SValentin Clement auto convTy = this->lowerTy().convertBoxType(boxTy, rank); 1475af6ee580SValentin Clement auto llvmBoxPtrTy = convTy.template cast<mlir::LLVM::LLVMPointerType>(); 1476af6ee580SValentin Clement auto llvmBoxTy = llvmBoxPtrTy.getElementType(); 1477af6ee580SValentin Clement mlir::Value descriptor = 1478af6ee580SValentin Clement rewriter.create<mlir::LLVM::UndefOp>(loc, llvmBoxTy); 1479af6ee580SValentin Clement 1480af6ee580SValentin Clement llvm::SmallVector<mlir::Value> typeparams = lenParams; 1481af6ee580SValentin Clement if constexpr (!std::is_same_v<BOX, fir::EmboxOp>) { 1482af6ee580SValentin Clement if (!box.substr().empty() && fir::hasDynamicSize(boxTy.getEleTy())) 1483af6ee580SValentin Clement typeparams.push_back(box.substr()[1]); 1484af6ee580SValentin Clement } 1485af6ee580SValentin Clement 1486af6ee580SValentin Clement // Write each of the fields with the appropriate values 1487af6ee580SValentin Clement auto [eleSize, cfiTy] = 1488af6ee580SValentin Clement getSizeAndTypeCode(loc, rewriter, boxTy.getEleTy(), typeparams); 1489af6ee580SValentin Clement descriptor = 1490af6ee580SValentin Clement insertField(rewriter, loc, descriptor, {kElemLenPosInBox}, eleSize); 1491af6ee580SValentin Clement descriptor = insertField(rewriter, loc, descriptor, {kVersionPosInBox}, 1492af6ee580SValentin Clement this->genI32Constant(loc, rewriter, CFI_VERSION)); 1493af6ee580SValentin Clement descriptor = insertField(rewriter, loc, descriptor, {kRankPosInBox}, 1494af6ee580SValentin Clement this->genI32Constant(loc, rewriter, rank)); 1495af6ee580SValentin Clement descriptor = insertField(rewriter, loc, descriptor, {kTypePosInBox}, cfiTy); 1496af6ee580SValentin Clement descriptor = 1497af6ee580SValentin Clement insertField(rewriter, loc, descriptor, {kAttributePosInBox}, 1498af6ee580SValentin Clement this->genI32Constant(loc, rewriter, getCFIAttr(boxTy))); 1499af6ee580SValentin Clement const bool hasAddendum = isDerivedType(boxTy); 1500af6ee580SValentin Clement descriptor = 1501af6ee580SValentin Clement insertField(rewriter, loc, descriptor, {kF18AddendumPosInBox}, 1502af6ee580SValentin Clement this->genI32Constant(loc, rewriter, hasAddendum ? 1 : 0)); 1503af6ee580SValentin Clement 1504af6ee580SValentin Clement if (hasAddendum) { 1505af6ee580SValentin Clement auto isArray = 1506af6ee580SValentin Clement fir::dyn_cast_ptrOrBoxEleTy(boxTy).template isa<fir::SequenceType>(); 1507af6ee580SValentin Clement unsigned typeDescFieldId = isArray ? kOptTypePtrPosInBox : kDimsPosInBox; 1508af6ee580SValentin Clement auto typeDesc = 1509af6ee580SValentin Clement getTypeDescriptor(box, rewriter, loc, unwrapIfDerived(boxTy)); 1510af6ee580SValentin Clement descriptor = 1511af6ee580SValentin Clement insertField(rewriter, loc, descriptor, {typeDescFieldId}, typeDesc, 1512af6ee580SValentin Clement /*bitCast=*/true); 1513af6ee580SValentin Clement } 1514af6ee580SValentin Clement 1515af6ee580SValentin Clement return {boxTy, descriptor, eleSize}; 1516af6ee580SValentin Clement } 1517af6ee580SValentin Clement 1518af6ee580SValentin Clement /// If the embox is not in a globalOp body, allocate storage for the box; 1519af6ee580SValentin Clement /// store the value inside and return the generated alloca. Return the input 1520af6ee580SValentin Clement /// value otherwise. 1521af6ee580SValentin Clement mlir::Value 1522af6ee580SValentin Clement placeInMemoryIfNotGlobalInit(mlir::ConversionPatternRewriter &rewriter, 1523af6ee580SValentin Clement mlir::Location loc, mlir::Value boxValue) const { 1524af6ee580SValentin Clement auto *thisBlock = rewriter.getInsertionBlock(); 1525af6ee580SValentin Clement if (thisBlock && mlir::isa<mlir::LLVM::GlobalOp>(thisBlock->getParentOp())) 1526af6ee580SValentin Clement return boxValue; 1527af6ee580SValentin Clement auto boxPtrTy = mlir::LLVM::LLVMPointerType::get(boxValue.getType()); 1528af6ee580SValentin Clement auto alloca = genAllocaWithType(loc, boxPtrTy, defaultAlign, rewriter); 1529af6ee580SValentin Clement rewriter.create<mlir::LLVM::StoreOp>(loc, boxValue, alloca); 1530af6ee580SValentin Clement return alloca; 1531af6ee580SValentin Clement } 1532af6ee580SValentin Clement }; 1533af6ee580SValentin Clement 1534af6ee580SValentin Clement /// Create a generic box on a memory reference. This conversions lowers the 1535af6ee580SValentin Clement /// abstract box to the appropriate, initialized descriptor. 1536af6ee580SValentin Clement struct EmboxOpConversion : public EmboxCommonConversion<fir::EmboxOp> { 1537af6ee580SValentin Clement using EmboxCommonConversion::EmboxCommonConversion; 1538af6ee580SValentin Clement 1539af6ee580SValentin Clement mlir::LogicalResult 1540af6ee580SValentin Clement matchAndRewrite(fir::EmboxOp embox, OpAdaptor adaptor, 1541af6ee580SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 1542af6ee580SValentin Clement assert(!embox.getShape() && "There should be no dims on this embox op"); 1543af6ee580SValentin Clement auto [boxTy, dest, eleSize] = 1544af6ee580SValentin Clement consDescriptorPrefix(embox, rewriter, /*rank=*/0, 1545af6ee580SValentin Clement /*lenParams=*/adaptor.getOperands().drop_front(1)); 1546af6ee580SValentin Clement dest = insertBaseAddress(rewriter, embox.getLoc(), dest, 1547af6ee580SValentin Clement adaptor.getOperands()[0]); 1548af6ee580SValentin Clement if (isDerivedTypeWithLenParams(boxTy)) 1549af6ee580SValentin Clement return rewriter.notifyMatchFailure( 1550af6ee580SValentin Clement embox, "fir.embox codegen of derived with length parameters not " 1551af6ee580SValentin Clement "implemented yet"); 1552af6ee580SValentin Clement auto result = placeInMemoryIfNotGlobalInit(rewriter, embox.getLoc(), dest); 1553af6ee580SValentin Clement rewriter.replaceOp(embox, result); 1554af6ee580SValentin Clement return success(); 1555af6ee580SValentin Clement } 1556af6ee580SValentin Clement }; 1557af6ee580SValentin Clement 1558cc505c0bSKiran Chandramohan /// Lower `fir.emboxproc` operation. Creates a procedure box. 1559cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers. 1560cc505c0bSKiran Chandramohan struct EmboxProcOpConversion : public FIROpConversion<fir::EmboxProcOp> { 1561cc505c0bSKiran Chandramohan using FIROpConversion::FIROpConversion; 1562cc505c0bSKiran Chandramohan 1563cc505c0bSKiran Chandramohan mlir::LogicalResult 1564cc505c0bSKiran Chandramohan matchAndRewrite(fir::EmboxProcOp emboxproc, OpAdaptor adaptor, 1565cc505c0bSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 1566cc505c0bSKiran Chandramohan return rewriter.notifyMatchFailure( 1567cc505c0bSKiran Chandramohan emboxproc, "fir.emboxproc codegen is not implemented yet"); 1568cc505c0bSKiran Chandramohan } 1569cc505c0bSKiran Chandramohan }; 1570cc505c0bSKiran Chandramohan 1571cc505c0bSKiran Chandramohan 157254c56347SValentin Clement // Code shared between insert_value and extract_value Ops. 157354c56347SValentin Clement struct ValueOpCommon { 157454c56347SValentin Clement // Translate the arguments pertaining to any multidimensional array to 157554c56347SValentin Clement // row-major order for LLVM-IR. 157654c56347SValentin Clement static void toRowMajor(SmallVectorImpl<mlir::Attribute> &attrs, 157754c56347SValentin Clement mlir::Type ty) { 157854c56347SValentin Clement assert(ty && "type is null"); 157954c56347SValentin Clement const auto end = attrs.size(); 158054c56347SValentin Clement for (std::remove_const_t<decltype(end)> i = 0; i < end; ++i) { 158154c56347SValentin Clement if (auto seq = ty.dyn_cast<mlir::LLVM::LLVMArrayType>()) { 158254c56347SValentin Clement const auto dim = getDimension(seq); 158354c56347SValentin Clement if (dim > 1) { 158454c56347SValentin Clement auto ub = std::min(i + dim, end); 158554c56347SValentin Clement std::reverse(attrs.begin() + i, attrs.begin() + ub); 158654c56347SValentin Clement i += dim - 1; 158754c56347SValentin Clement } 158854c56347SValentin Clement ty = getArrayElementType(seq); 158954c56347SValentin Clement } else if (auto st = ty.dyn_cast<mlir::LLVM::LLVMStructType>()) { 159054c56347SValentin Clement ty = st.getBody()[attrs[i].cast<mlir::IntegerAttr>().getInt()]; 159154c56347SValentin Clement } else { 159254c56347SValentin Clement llvm_unreachable("index into invalid type"); 159354c56347SValentin Clement } 159454c56347SValentin Clement } 159554c56347SValentin Clement } 159654c56347SValentin Clement 159754c56347SValentin Clement static llvm::SmallVector<mlir::Attribute> 159854c56347SValentin Clement collectIndices(mlir::ConversionPatternRewriter &rewriter, 159954c56347SValentin Clement mlir::ArrayAttr arrAttr) { 160054c56347SValentin Clement llvm::SmallVector<mlir::Attribute> attrs; 160154c56347SValentin Clement for (auto i = arrAttr.begin(), e = arrAttr.end(); i != e; ++i) { 160254c56347SValentin Clement if (i->isa<mlir::IntegerAttr>()) { 160354c56347SValentin Clement attrs.push_back(*i); 160454c56347SValentin Clement } else { 160554c56347SValentin Clement auto fieldName = i->cast<mlir::StringAttr>().getValue(); 160654c56347SValentin Clement ++i; 160754c56347SValentin Clement auto ty = i->cast<mlir::TypeAttr>().getValue(); 160854c56347SValentin Clement auto index = ty.cast<fir::RecordType>().getFieldIndex(fieldName); 160954c56347SValentin Clement attrs.push_back(mlir::IntegerAttr::get(rewriter.getI32Type(), index)); 161054c56347SValentin Clement } 161154c56347SValentin Clement } 161254c56347SValentin Clement return attrs; 161354c56347SValentin Clement } 161454c56347SValentin Clement 161554c56347SValentin Clement private: 161654c56347SValentin Clement static unsigned getDimension(mlir::LLVM::LLVMArrayType ty) { 161754c56347SValentin Clement unsigned result = 1; 161854c56347SValentin Clement for (auto eleTy = ty.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>(); 161954c56347SValentin Clement eleTy; 162054c56347SValentin Clement eleTy = eleTy.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>()) 162154c56347SValentin Clement ++result; 162254c56347SValentin Clement return result; 162354c56347SValentin Clement } 162454c56347SValentin Clement 162554c56347SValentin Clement static mlir::Type getArrayElementType(mlir::LLVM::LLVMArrayType ty) { 162654c56347SValentin Clement auto eleTy = ty.getElementType(); 162754c56347SValentin Clement while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>()) 162854c56347SValentin Clement eleTy = arrTy.getElementType(); 162954c56347SValentin Clement return eleTy; 163054c56347SValentin Clement } 163154c56347SValentin Clement }; 163254c56347SValentin Clement 163354c56347SValentin Clement /// Extract a subobject value from an ssa-value of aggregate type 163454c56347SValentin Clement struct ExtractValueOpConversion 163554c56347SValentin Clement : public FIROpAndTypeConversion<fir::ExtractValueOp>, 163654c56347SValentin Clement public ValueOpCommon { 163754c56347SValentin Clement using FIROpAndTypeConversion::FIROpAndTypeConversion; 163854c56347SValentin Clement 163954c56347SValentin Clement mlir::LogicalResult 164054c56347SValentin Clement doRewrite(fir::ExtractValueOp extractVal, mlir::Type ty, OpAdaptor adaptor, 164154c56347SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 164254c56347SValentin Clement auto attrs = collectIndices(rewriter, extractVal.coor()); 164354c56347SValentin Clement toRowMajor(attrs, adaptor.getOperands()[0].getType()); 164454c56347SValentin Clement auto position = mlir::ArrayAttr::get(extractVal.getContext(), attrs); 164554c56347SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>( 164654c56347SValentin Clement extractVal, ty, adaptor.getOperands()[0], position); 164754c56347SValentin Clement return success(); 164854c56347SValentin Clement } 164954c56347SValentin Clement }; 165054c56347SValentin Clement 165154c56347SValentin Clement /// InsertValue is the generalized instruction for the composition of new 165254c56347SValentin Clement /// aggregate type values. 165354c56347SValentin Clement struct InsertValueOpConversion 165454c56347SValentin Clement : public FIROpAndTypeConversion<fir::InsertValueOp>, 165554c56347SValentin Clement public ValueOpCommon { 165654c56347SValentin Clement using FIROpAndTypeConversion::FIROpAndTypeConversion; 165754c56347SValentin Clement 165854c56347SValentin Clement mlir::LogicalResult 165954c56347SValentin Clement doRewrite(fir::InsertValueOp insertVal, mlir::Type ty, OpAdaptor adaptor, 166054c56347SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 166154c56347SValentin Clement auto attrs = collectIndices(rewriter, insertVal.coor()); 166254c56347SValentin Clement toRowMajor(attrs, adaptor.getOperands()[0].getType()); 166354c56347SValentin Clement auto position = mlir::ArrayAttr::get(insertVal.getContext(), attrs); 166454c56347SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 166554c56347SValentin Clement insertVal, ty, adaptor.getOperands()[0], adaptor.getOperands()[1], 166654c56347SValentin Clement position); 166754c56347SValentin Clement return success(); 166854c56347SValentin Clement } 166954c56347SValentin Clement }; 167054c56347SValentin Clement 16713ae8e442SValentin Clement /// InsertOnRange inserts a value into a sequence over a range of offsets. 16723ae8e442SValentin Clement struct InsertOnRangeOpConversion 16733ae8e442SValentin Clement : public FIROpAndTypeConversion<fir::InsertOnRangeOp> { 16743ae8e442SValentin Clement using FIROpAndTypeConversion::FIROpAndTypeConversion; 16753ae8e442SValentin Clement 16763ae8e442SValentin Clement // Increments an array of subscripts in a row major fasion. 16773ae8e442SValentin Clement void incrementSubscripts(const SmallVector<uint64_t> &dims, 16783ae8e442SValentin Clement SmallVector<uint64_t> &subscripts) const { 16793ae8e442SValentin Clement for (size_t i = dims.size(); i > 0; --i) { 16803ae8e442SValentin Clement if (++subscripts[i - 1] < dims[i - 1]) { 16813ae8e442SValentin Clement return; 16823ae8e442SValentin Clement } 16833ae8e442SValentin Clement subscripts[i - 1] = 0; 16843ae8e442SValentin Clement } 16853ae8e442SValentin Clement } 16863ae8e442SValentin Clement 16873ae8e442SValentin Clement mlir::LogicalResult 16883ae8e442SValentin Clement doRewrite(fir::InsertOnRangeOp range, mlir::Type ty, OpAdaptor adaptor, 16893ae8e442SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 16903ae8e442SValentin Clement 16913ae8e442SValentin Clement llvm::SmallVector<uint64_t> dims; 16923ae8e442SValentin Clement auto type = adaptor.getOperands()[0].getType(); 16933ae8e442SValentin Clement 16943ae8e442SValentin Clement // Iteratively extract the array dimensions from the type. 16953ae8e442SValentin Clement while (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) { 16963ae8e442SValentin Clement dims.push_back(t.getNumElements()); 16973ae8e442SValentin Clement type = t.getElementType(); 16983ae8e442SValentin Clement } 16993ae8e442SValentin Clement 17003ae8e442SValentin Clement SmallVector<uint64_t> lBounds; 17013ae8e442SValentin Clement SmallVector<uint64_t> uBounds; 17023ae8e442SValentin Clement 17033ae8e442SValentin Clement // Extract integer value from the attribute 17043ae8e442SValentin Clement SmallVector<int64_t> coordinates = llvm::to_vector<4>( 17053ae8e442SValentin Clement llvm::map_range(range.coor(), [](Attribute a) -> int64_t { 17063ae8e442SValentin Clement return a.cast<IntegerAttr>().getInt(); 17073ae8e442SValentin Clement })); 17083ae8e442SValentin Clement 17093ae8e442SValentin Clement // Unzip the upper and lower bound and convert to a row major format. 17103ae8e442SValentin Clement for (auto i = coordinates.rbegin(), e = coordinates.rend(); i != e; ++i) { 17113ae8e442SValentin Clement uBounds.push_back(*i++); 17123ae8e442SValentin Clement lBounds.push_back(*i); 17133ae8e442SValentin Clement } 17143ae8e442SValentin Clement 17153ae8e442SValentin Clement auto &subscripts = lBounds; 17163ae8e442SValentin Clement auto loc = range.getLoc(); 17173ae8e442SValentin Clement mlir::Value lastOp = adaptor.getOperands()[0]; 17183ae8e442SValentin Clement mlir::Value insertVal = adaptor.getOperands()[1]; 17193ae8e442SValentin Clement 17203ae8e442SValentin Clement auto i64Ty = rewriter.getI64Type(); 17213ae8e442SValentin Clement while (subscripts != uBounds) { 17223ae8e442SValentin Clement // Convert uint64_t's to Attribute's. 17233ae8e442SValentin Clement SmallVector<mlir::Attribute> subscriptAttrs; 17243ae8e442SValentin Clement for (const auto &subscript : subscripts) 17253ae8e442SValentin Clement subscriptAttrs.push_back(IntegerAttr::get(i64Ty, subscript)); 17263ae8e442SValentin Clement lastOp = rewriter.create<mlir::LLVM::InsertValueOp>( 17273ae8e442SValentin Clement loc, ty, lastOp, insertVal, 17283ae8e442SValentin Clement ArrayAttr::get(range.getContext(), subscriptAttrs)); 17293ae8e442SValentin Clement 17303ae8e442SValentin Clement incrementSubscripts(dims, subscripts); 17313ae8e442SValentin Clement } 17323ae8e442SValentin Clement 17333ae8e442SValentin Clement // Convert uint64_t's to Attribute's. 17343ae8e442SValentin Clement SmallVector<mlir::Attribute> subscriptAttrs; 17353ae8e442SValentin Clement for (const auto &subscript : subscripts) 17363ae8e442SValentin Clement subscriptAttrs.push_back( 17373ae8e442SValentin Clement IntegerAttr::get(rewriter.getI64Type(), subscript)); 17383ae8e442SValentin Clement mlir::ArrayRef<mlir::Attribute> arrayRef(subscriptAttrs); 17393ae8e442SValentin Clement 17403ae8e442SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 17413ae8e442SValentin Clement range, ty, lastOp, insertVal, 17423ae8e442SValentin Clement ArrayAttr::get(range.getContext(), arrayRef)); 17433ae8e442SValentin Clement 17443ae8e442SValentin Clement return success(); 17453ae8e442SValentin Clement } 17463ae8e442SValentin Clement }; 17477b5132daSValentin Clement 17487b5132daSValentin Clement // 17497b5132daSValentin Clement // Primitive operations on Complex types 17507b5132daSValentin Clement // 17517b5132daSValentin Clement 17527b5132daSValentin Clement /// Generate inline code for complex addition/subtraction 17537b5132daSValentin Clement template <typename LLVMOP, typename OPTY> 17547b5132daSValentin Clement mlir::LLVM::InsertValueOp complexSum(OPTY sumop, mlir::ValueRange opnds, 17557b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter, 17567b5132daSValentin Clement fir::LLVMTypeConverter &lowering) { 17577b5132daSValentin Clement mlir::Value a = opnds[0]; 17587b5132daSValentin Clement mlir::Value b = opnds[1]; 17597b5132daSValentin Clement auto loc = sumop.getLoc(); 17607b5132daSValentin Clement auto ctx = sumop.getContext(); 17617b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 17627b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 17637b5132daSValentin Clement mlir::Type eleTy = lowering.convertType(getComplexEleTy(sumop.getType())); 17647b5132daSValentin Clement mlir::Type ty = lowering.convertType(sumop.getType()); 17657b5132daSValentin Clement auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0); 17667b5132daSValentin Clement auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1); 17677b5132daSValentin Clement auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0); 17687b5132daSValentin Clement auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1); 17697b5132daSValentin Clement auto rx = rewriter.create<LLVMOP>(loc, eleTy, x0, x1); 17707b5132daSValentin Clement auto ry = rewriter.create<LLVMOP>(loc, eleTy, y0, y1); 17717b5132daSValentin Clement auto r0 = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 17727b5132daSValentin Clement auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r0, rx, c0); 17737b5132daSValentin Clement return rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ry, c1); 17747b5132daSValentin Clement } 17757b5132daSValentin Clement 17767b5132daSValentin Clement struct AddcOpConversion : public FIROpConversion<fir::AddcOp> { 17777b5132daSValentin Clement using FIROpConversion::FIROpConversion; 17787b5132daSValentin Clement 17797b5132daSValentin Clement mlir::LogicalResult 17807b5132daSValentin Clement matchAndRewrite(fir::AddcOp addc, OpAdaptor adaptor, 17817b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 17827b5132daSValentin Clement // given: (x + iy) + (x' + iy') 17837b5132daSValentin Clement // result: (x + x') + i(y + y') 17847b5132daSValentin Clement auto r = complexSum<mlir::LLVM::FAddOp>(addc, adaptor.getOperands(), 17857b5132daSValentin Clement rewriter, lowerTy()); 17867b5132daSValentin Clement rewriter.replaceOp(addc, r.getResult()); 17877b5132daSValentin Clement return success(); 17887b5132daSValentin Clement } 17897b5132daSValentin Clement }; 17907b5132daSValentin Clement 17917b5132daSValentin Clement struct SubcOpConversion : public FIROpConversion<fir::SubcOp> { 17927b5132daSValentin Clement using FIROpConversion::FIROpConversion; 17937b5132daSValentin Clement 17947b5132daSValentin Clement mlir::LogicalResult 17957b5132daSValentin Clement matchAndRewrite(fir::SubcOp subc, OpAdaptor adaptor, 17967b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 17977b5132daSValentin Clement // given: (x + iy) - (x' + iy') 17987b5132daSValentin Clement // result: (x - x') + i(y - y') 17997b5132daSValentin Clement auto r = complexSum<mlir::LLVM::FSubOp>(subc, adaptor.getOperands(), 18007b5132daSValentin Clement rewriter, lowerTy()); 18017b5132daSValentin Clement rewriter.replaceOp(subc, r.getResult()); 18027b5132daSValentin Clement return success(); 18037b5132daSValentin Clement } 18047b5132daSValentin Clement }; 18057b5132daSValentin Clement 18067b5132daSValentin Clement /// Inlined complex multiply 18077b5132daSValentin Clement struct MulcOpConversion : public FIROpConversion<fir::MulcOp> { 18087b5132daSValentin Clement using FIROpConversion::FIROpConversion; 18097b5132daSValentin Clement 18107b5132daSValentin Clement mlir::LogicalResult 18117b5132daSValentin Clement matchAndRewrite(fir::MulcOp mulc, OpAdaptor adaptor, 18127b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 18137b5132daSValentin Clement // TODO: Can we use a call to __muldc3 ? 18147b5132daSValentin Clement // given: (x + iy) * (x' + iy') 18157b5132daSValentin Clement // result: (xx'-yy')+i(xy'+yx') 18167b5132daSValentin Clement mlir::Value a = adaptor.getOperands()[0]; 18177b5132daSValentin Clement mlir::Value b = adaptor.getOperands()[1]; 18187b5132daSValentin Clement auto loc = mulc.getLoc(); 18197b5132daSValentin Clement auto *ctx = mulc.getContext(); 18207b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 18217b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 18227b5132daSValentin Clement mlir::Type eleTy = convertType(getComplexEleTy(mulc.getType())); 18237b5132daSValentin Clement mlir::Type ty = convertType(mulc.getType()); 18247b5132daSValentin Clement auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0); 18257b5132daSValentin Clement auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1); 18267b5132daSValentin Clement auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0); 18277b5132daSValentin Clement auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1); 18287b5132daSValentin Clement auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1); 18297b5132daSValentin Clement auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1); 18307b5132daSValentin Clement auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1); 18317b5132daSValentin Clement auto ri = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xy, yx); 18327b5132daSValentin Clement auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1); 18337b5132daSValentin Clement auto rr = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, xx, yy); 18347b5132daSValentin Clement auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 18357b5132daSValentin Clement auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0); 18367b5132daSValentin Clement auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1); 18377b5132daSValentin Clement rewriter.replaceOp(mulc, r0.getResult()); 18387b5132daSValentin Clement return success(); 18397b5132daSValentin Clement } 18407b5132daSValentin Clement }; 18417b5132daSValentin Clement 18427b5132daSValentin Clement /// Inlined complex division 18437b5132daSValentin Clement struct DivcOpConversion : public FIROpConversion<fir::DivcOp> { 18447b5132daSValentin Clement using FIROpConversion::FIROpConversion; 18457b5132daSValentin Clement 18467b5132daSValentin Clement mlir::LogicalResult 18477b5132daSValentin Clement matchAndRewrite(fir::DivcOp divc, OpAdaptor adaptor, 18487b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 18497b5132daSValentin Clement // TODO: Can we use a call to __divdc3 instead? 18507b5132daSValentin Clement // Just generate inline code for now. 18517b5132daSValentin Clement // given: (x + iy) / (x' + iy') 18527b5132daSValentin Clement // result: ((xx'+yy')/d) + i((yx'-xy')/d) where d = x'x' + y'y' 18537b5132daSValentin Clement mlir::Value a = adaptor.getOperands()[0]; 18547b5132daSValentin Clement mlir::Value b = adaptor.getOperands()[1]; 18557b5132daSValentin Clement auto loc = divc.getLoc(); 18567b5132daSValentin Clement auto *ctx = divc.getContext(); 18577b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 18587b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 18597b5132daSValentin Clement mlir::Type eleTy = convertType(getComplexEleTy(divc.getType())); 18607b5132daSValentin Clement mlir::Type ty = convertType(divc.getType()); 18617b5132daSValentin Clement auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0); 18627b5132daSValentin Clement auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1); 18637b5132daSValentin Clement auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0); 18647b5132daSValentin Clement auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1); 18657b5132daSValentin Clement auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1); 18667b5132daSValentin Clement auto x1x1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x1, x1); 18677b5132daSValentin Clement auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1); 18687b5132daSValentin Clement auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1); 18697b5132daSValentin Clement auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1); 18707b5132daSValentin Clement auto y1y1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y1, y1); 18717b5132daSValentin Clement auto d = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, x1x1, y1y1); 18727b5132daSValentin Clement auto rrn = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xx, yy); 18737b5132daSValentin Clement auto rin = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, yx, xy); 18747b5132daSValentin Clement auto rr = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rrn, d); 18757b5132daSValentin Clement auto ri = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rin, d); 18767b5132daSValentin Clement auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 18777b5132daSValentin Clement auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0); 18787b5132daSValentin Clement auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1); 18797b5132daSValentin Clement rewriter.replaceOp(divc, r0.getResult()); 18807b5132daSValentin Clement return success(); 18817b5132daSValentin Clement } 18827b5132daSValentin Clement }; 18837b5132daSValentin Clement 18847b5132daSValentin Clement /// Inlined complex negation 18857b5132daSValentin Clement struct NegcOpConversion : public FIROpConversion<fir::NegcOp> { 18867b5132daSValentin Clement using FIROpConversion::FIROpConversion; 18877b5132daSValentin Clement 18887b5132daSValentin Clement mlir::LogicalResult 18897b5132daSValentin Clement matchAndRewrite(fir::NegcOp neg, OpAdaptor adaptor, 18907b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 18917b5132daSValentin Clement // given: -(x + iy) 18927b5132daSValentin Clement // result: -x - iy 18937b5132daSValentin Clement auto *ctxt = neg.getContext(); 18947b5132daSValentin Clement auto eleTy = convertType(getComplexEleTy(neg.getType())); 18957b5132daSValentin Clement auto ty = convertType(neg.getType()); 18967b5132daSValentin Clement auto loc = neg.getLoc(); 18977b5132daSValentin Clement mlir::Value o0 = adaptor.getOperands()[0]; 18987b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0)); 18997b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1)); 19007b5132daSValentin Clement auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c0); 19017b5132daSValentin Clement auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c1); 19027b5132daSValentin Clement auto nrp = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, rp); 19037b5132daSValentin Clement auto nip = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, ip); 19047b5132daSValentin Clement auto r = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, o0, nrp, c0); 19057b5132daSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(neg, ty, r, nip, c1); 19067b5132daSValentin Clement return success(); 19077b5132daSValentin Clement } 19087b5132daSValentin Clement }; 19097b5132daSValentin Clement 19101ed5a90fSValentin Clement /// Conversion pattern for operation that must be dead. The information in these 19111ed5a90fSValentin Clement /// operations is used by other operation. At this point they should not have 19121ed5a90fSValentin Clement /// anymore uses. 19131ed5a90fSValentin Clement /// These operations are normally dead after the pre-codegen pass. 19141ed5a90fSValentin Clement template <typename FromOp> 19151ed5a90fSValentin Clement struct MustBeDeadConversion : public FIROpConversion<FromOp> { 19161ed5a90fSValentin Clement explicit MustBeDeadConversion(fir::LLVMTypeConverter &lowering) 19171ed5a90fSValentin Clement : FIROpConversion<FromOp>(lowering) {} 19181ed5a90fSValentin Clement using OpAdaptor = typename FromOp::Adaptor; 19191ed5a90fSValentin Clement 19201ed5a90fSValentin Clement mlir::LogicalResult 19211ed5a90fSValentin Clement matchAndRewrite(FromOp op, OpAdaptor adaptor, 19221ed5a90fSValentin Clement mlir::ConversionPatternRewriter &rewriter) const final { 19231ed5a90fSValentin Clement if (!op->getUses().empty()) 19241ed5a90fSValentin Clement return rewriter.notifyMatchFailure(op, "op must be dead"); 19251ed5a90fSValentin Clement rewriter.eraseOp(op); 19261ed5a90fSValentin Clement return success(); 19271ed5a90fSValentin Clement } 19281ed5a90fSValentin Clement }; 19291ed5a90fSValentin Clement 19301ed5a90fSValentin Clement struct ShapeOpConversion : public MustBeDeadConversion<fir::ShapeOp> { 19311ed5a90fSValentin Clement using MustBeDeadConversion::MustBeDeadConversion; 19321ed5a90fSValentin Clement }; 19331ed5a90fSValentin Clement 19341ed5a90fSValentin Clement struct ShapeShiftOpConversion : public MustBeDeadConversion<fir::ShapeShiftOp> { 19351ed5a90fSValentin Clement using MustBeDeadConversion::MustBeDeadConversion; 19361ed5a90fSValentin Clement }; 19371ed5a90fSValentin Clement 19381ed5a90fSValentin Clement struct ShiftOpConversion : public MustBeDeadConversion<fir::ShiftOp> { 19391ed5a90fSValentin Clement using MustBeDeadConversion::MustBeDeadConversion; 19401ed5a90fSValentin Clement }; 19411ed5a90fSValentin Clement 19421ed5a90fSValentin Clement struct SliceOpConversion : public MustBeDeadConversion<fir::SliceOp> { 19431ed5a90fSValentin Clement using MustBeDeadConversion::MustBeDeadConversion; 19441ed5a90fSValentin Clement }; 19451ed5a90fSValentin Clement 1946420ad7ceSAndrzej Warzynski /// `fir.is_present` --> 1947420ad7ceSAndrzej Warzynski /// ``` 1948420ad7ceSAndrzej Warzynski /// %0 = llvm.mlir.constant(0 : i64) 1949420ad7ceSAndrzej Warzynski /// %1 = llvm.ptrtoint %0 1950420ad7ceSAndrzej Warzynski /// %2 = llvm.icmp "ne" %1, %0 : i64 1951420ad7ceSAndrzej Warzynski /// ``` 1952420ad7ceSAndrzej Warzynski struct IsPresentOpConversion : public FIROpConversion<fir::IsPresentOp> { 1953420ad7ceSAndrzej Warzynski using FIROpConversion::FIROpConversion; 1954420ad7ceSAndrzej Warzynski 1955420ad7ceSAndrzej Warzynski mlir::LogicalResult 1956420ad7ceSAndrzej Warzynski matchAndRewrite(fir::IsPresentOp isPresent, OpAdaptor adaptor, 1957420ad7ceSAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 1958420ad7ceSAndrzej Warzynski mlir::Type idxTy = lowerTy().indexType(); 1959420ad7ceSAndrzej Warzynski mlir::Location loc = isPresent.getLoc(); 1960420ad7ceSAndrzej Warzynski auto ptr = adaptor.getOperands()[0]; 1961420ad7ceSAndrzej Warzynski 1962420ad7ceSAndrzej Warzynski if (isPresent.val().getType().isa<fir::BoxCharType>()) { 1963420ad7ceSAndrzej Warzynski auto structTy = ptr.getType().cast<mlir::LLVM::LLVMStructType>(); 1964420ad7ceSAndrzej Warzynski assert(!structTy.isOpaque() && !structTy.getBody().empty()); 1965420ad7ceSAndrzej Warzynski 1966420ad7ceSAndrzej Warzynski mlir::Type ty = structTy.getBody()[0]; 1967420ad7ceSAndrzej Warzynski mlir::MLIRContext *ctx = isPresent.getContext(); 1968420ad7ceSAndrzej Warzynski auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 1969420ad7ceSAndrzej Warzynski ptr = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, ptr, c0); 1970420ad7ceSAndrzej Warzynski } 1971420ad7ceSAndrzej Warzynski mlir::LLVM::ConstantOp c0 = 1972420ad7ceSAndrzej Warzynski genConstantIndex(isPresent.getLoc(), idxTy, rewriter, 0); 1973420ad7ceSAndrzej Warzynski auto addr = rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, ptr); 1974420ad7ceSAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>( 1975420ad7ceSAndrzej Warzynski isPresent, mlir::LLVM::ICmpPredicate::ne, addr, c0); 1976420ad7ceSAndrzej Warzynski 1977420ad7ceSAndrzej Warzynski return success(); 1978420ad7ceSAndrzej Warzynski } 1979420ad7ceSAndrzej Warzynski }; 19801e77b095SAndrzej Warzynski 19811e77b095SAndrzej Warzynski /// Convert `!fir.emboxchar<!fir.char<KIND, ?>, #n>` into a sequence of 19821e77b095SAndrzej Warzynski /// instructions that generate `!llvm.struct<(ptr<ik>, i64)>`. The 1st element 19831e77b095SAndrzej Warzynski /// in this struct is a pointer. Its type is determined from `KIND`. The 2nd 19841e77b095SAndrzej Warzynski /// element is the length of the character buffer (`#n`). 19851e77b095SAndrzej Warzynski struct EmboxCharOpConversion : public FIROpConversion<fir::EmboxCharOp> { 19861e77b095SAndrzej Warzynski using FIROpConversion::FIROpConversion; 19871e77b095SAndrzej Warzynski 19881e77b095SAndrzej Warzynski mlir::LogicalResult 19891e77b095SAndrzej Warzynski matchAndRewrite(fir::EmboxCharOp emboxChar, OpAdaptor adaptor, 19901e77b095SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 19911e77b095SAndrzej Warzynski mlir::ValueRange operands = adaptor.getOperands(); 19921e77b095SAndrzej Warzynski MLIRContext *ctx = emboxChar.getContext(); 19931e77b095SAndrzej Warzynski 19941e77b095SAndrzej Warzynski mlir::Value charBuffer = operands[0]; 19951e77b095SAndrzej Warzynski mlir::Value charBufferLen = operands[1]; 19961e77b095SAndrzej Warzynski 19971e77b095SAndrzej Warzynski mlir::Location loc = emboxChar.getLoc(); 19981e77b095SAndrzej Warzynski mlir::Type llvmStructTy = convertType(emboxChar.getType()); 19991e77b095SAndrzej Warzynski auto llvmStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, llvmStructTy); 20001e77b095SAndrzej Warzynski 20011e77b095SAndrzej Warzynski mlir::Type lenTy = 20021e77b095SAndrzej Warzynski llvmStructTy.cast<mlir::LLVM::LLVMStructType>().getBody()[1]; 20031e77b095SAndrzej Warzynski mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, charBufferLen); 20041e77b095SAndrzej Warzynski 20051e77b095SAndrzej Warzynski auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 20061e77b095SAndrzej Warzynski auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 20071e77b095SAndrzej Warzynski auto insertBufferOp = rewriter.create<mlir::LLVM::InsertValueOp>( 20081e77b095SAndrzej Warzynski loc, llvmStructTy, llvmStruct, charBuffer, c0); 20091e77b095SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 20101e77b095SAndrzej Warzynski emboxChar, llvmStructTy, insertBufferOp, lenAfterCast, c1); 20111e77b095SAndrzej Warzynski 20121e77b095SAndrzej Warzynski return success(); 20131e77b095SAndrzej Warzynski } 20141e77b095SAndrzej Warzynski }; 201514867ffcSAndrzej Warzynski 201614867ffcSAndrzej Warzynski /// Construct an `llvm.extractvalue` instruction. It will return value at 201714867ffcSAndrzej Warzynski /// element \p x from \p tuple. 201814867ffcSAndrzej Warzynski mlir::LLVM::ExtractValueOp 201914867ffcSAndrzej Warzynski genExtractValueWithIndex(mlir::Location loc, mlir::Value tuple, mlir::Type ty, 202014867ffcSAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter, 202114867ffcSAndrzej Warzynski mlir::MLIRContext *ctx, int x) { 202214867ffcSAndrzej Warzynski auto cx = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(x)); 202314867ffcSAndrzej Warzynski auto xty = ty.cast<mlir::LLVM::LLVMStructType>().getBody()[x]; 202414867ffcSAndrzej Warzynski return rewriter.create<mlir::LLVM::ExtractValueOp>(loc, xty, tuple, cx); 202514867ffcSAndrzej Warzynski } 202614867ffcSAndrzej Warzynski 20276c3d7fd4SAndrzej Warzynski /// Convert `!fir.boxchar_len` to `!llvm.extractvalue` for the 2nd part of the 20286c3d7fd4SAndrzej Warzynski /// boxchar. 20296c3d7fd4SAndrzej Warzynski struct BoxCharLenOpConversion : public FIROpConversion<fir::BoxCharLenOp> { 20306c3d7fd4SAndrzej Warzynski using FIROpConversion::FIROpConversion; 20316c3d7fd4SAndrzej Warzynski 20326c3d7fd4SAndrzej Warzynski mlir::LogicalResult 20336c3d7fd4SAndrzej Warzynski matchAndRewrite(fir::BoxCharLenOp boxCharLen, OpAdaptor adaptor, 20346c3d7fd4SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 20356c3d7fd4SAndrzej Warzynski mlir::Value boxChar = adaptor.getOperands()[0]; 20366c3d7fd4SAndrzej Warzynski mlir::Location loc = boxChar.getLoc(); 20376c3d7fd4SAndrzej Warzynski mlir::MLIRContext *ctx = boxChar.getContext(); 20386c3d7fd4SAndrzej Warzynski mlir::Type returnValTy = boxCharLen.getResult().getType(); 20396c3d7fd4SAndrzej Warzynski 20406c3d7fd4SAndrzej Warzynski constexpr int boxcharLenIdx = 1; 20416c3d7fd4SAndrzej Warzynski mlir::LLVM::ExtractValueOp len = genExtractValueWithIndex( 20426c3d7fd4SAndrzej Warzynski loc, boxChar, boxChar.getType(), rewriter, ctx, boxcharLenIdx); 20436c3d7fd4SAndrzej Warzynski mlir::Value lenAfterCast = integerCast(loc, rewriter, returnValTy, len); 20446c3d7fd4SAndrzej Warzynski rewriter.replaceOp(boxCharLen, lenAfterCast); 20456c3d7fd4SAndrzej Warzynski 20466c3d7fd4SAndrzej Warzynski return success(); 20476c3d7fd4SAndrzej Warzynski } 20486c3d7fd4SAndrzej Warzynski }; 20496c3d7fd4SAndrzej Warzynski 205014867ffcSAndrzej Warzynski /// Convert `fir.unboxchar` into two `llvm.extractvalue` instructions. One for 205114867ffcSAndrzej Warzynski /// the character buffer and one for the buffer length. 205214867ffcSAndrzej Warzynski struct UnboxCharOpConversion : public FIROpConversion<fir::UnboxCharOp> { 205314867ffcSAndrzej Warzynski using FIROpConversion::FIROpConversion; 205414867ffcSAndrzej Warzynski 205514867ffcSAndrzej Warzynski mlir::LogicalResult 205614867ffcSAndrzej Warzynski matchAndRewrite(fir::UnboxCharOp unboxchar, OpAdaptor adaptor, 205714867ffcSAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 205814867ffcSAndrzej Warzynski MLIRContext *ctx = unboxchar.getContext(); 205914867ffcSAndrzej Warzynski 206014867ffcSAndrzej Warzynski mlir::Type lenTy = convertType(unboxchar.getType(1)); 206114867ffcSAndrzej Warzynski mlir::Value tuple = adaptor.getOperands()[0]; 206214867ffcSAndrzej Warzynski mlir::Type tupleTy = tuple.getType(); 206314867ffcSAndrzej Warzynski 206414867ffcSAndrzej Warzynski mlir::Location loc = unboxchar.getLoc(); 206514867ffcSAndrzej Warzynski mlir::Value ptrToBuffer = 206614867ffcSAndrzej Warzynski genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 0); 206714867ffcSAndrzej Warzynski 206814867ffcSAndrzej Warzynski mlir::LLVM::ExtractValueOp len = 206914867ffcSAndrzej Warzynski genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 1); 207014867ffcSAndrzej Warzynski mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, len); 207114867ffcSAndrzej Warzynski 207214867ffcSAndrzej Warzynski rewriter.replaceOp(unboxchar, 207314867ffcSAndrzej Warzynski ArrayRef<mlir::Value>{ptrToBuffer, lenAfterCast}); 207414867ffcSAndrzej Warzynski return success(); 207514867ffcSAndrzej Warzynski } 207614867ffcSAndrzej Warzynski }; 207714867ffcSAndrzej Warzynski 2078cc505c0bSKiran Chandramohan /// Lower `fir.unboxproc` operation. Unbox a procedure box value, yielding its 2079cc505c0bSKiran Chandramohan /// components. 2080cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers. 2081cc505c0bSKiran Chandramohan struct UnboxProcOpConversion : public FIROpConversion<fir::UnboxProcOp> { 2082cc505c0bSKiran Chandramohan using FIROpConversion::FIROpConversion; 2083cc505c0bSKiran Chandramohan 2084cc505c0bSKiran Chandramohan mlir::LogicalResult 2085cc505c0bSKiran Chandramohan matchAndRewrite(fir::UnboxProcOp unboxproc, OpAdaptor adaptor, 2086cc505c0bSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 2087cc505c0bSKiran Chandramohan return rewriter.notifyMatchFailure( 2088cc505c0bSKiran Chandramohan unboxproc, "fir.unboxproc codegen is not implemented yet"); 2089cc505c0bSKiran Chandramohan } 2090cc505c0bSKiran Chandramohan }; 2091cc505c0bSKiran Chandramohan 2092*e6c66ef5SAndrzej Warzynski /// Convert `fir.field_index`. The conversion depends on whether the size of 2093*e6c66ef5SAndrzej Warzynski /// the record is static or dynamic. 2094*e6c66ef5SAndrzej Warzynski struct FieldIndexOpConversion : public FIROpConversion<fir::FieldIndexOp> { 2095*e6c66ef5SAndrzej Warzynski using FIROpConversion::FIROpConversion; 2096*e6c66ef5SAndrzej Warzynski 2097*e6c66ef5SAndrzej Warzynski // NB: most field references should be resolved by this point 2098*e6c66ef5SAndrzej Warzynski mlir::LogicalResult 2099*e6c66ef5SAndrzej Warzynski matchAndRewrite(fir::FieldIndexOp field, OpAdaptor adaptor, 2100*e6c66ef5SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 2101*e6c66ef5SAndrzej Warzynski auto recTy = field.on_type().cast<fir::RecordType>(); 2102*e6c66ef5SAndrzej Warzynski unsigned index = recTy.getFieldIndex(field.field_id()); 2103*e6c66ef5SAndrzej Warzynski 2104*e6c66ef5SAndrzej Warzynski if (!fir::hasDynamicSize(recTy)) { 2105*e6c66ef5SAndrzej Warzynski // Derived type has compile-time constant layout. Return index of the 2106*e6c66ef5SAndrzej Warzynski // component type in the parent type (to be used in GEP). 2107*e6c66ef5SAndrzej Warzynski rewriter.replaceOp(field, mlir::ValueRange{genConstantOffset( 2108*e6c66ef5SAndrzej Warzynski field.getLoc(), rewriter, index)}); 2109*e6c66ef5SAndrzej Warzynski return success(); 2110*e6c66ef5SAndrzej Warzynski } 2111*e6c66ef5SAndrzej Warzynski 2112*e6c66ef5SAndrzej Warzynski // Derived type has compile-time constant layout. Call the compiler 2113*e6c66ef5SAndrzej Warzynski // generated function to determine the byte offset of the field at runtime. 2114*e6c66ef5SAndrzej Warzynski // This returns a non-constant. 2115*e6c66ef5SAndrzej Warzynski FlatSymbolRefAttr symAttr = mlir::SymbolRefAttr::get( 2116*e6c66ef5SAndrzej Warzynski field.getContext(), getOffsetMethodName(recTy, field.field_id())); 2117*e6c66ef5SAndrzej Warzynski NamedAttribute callAttr = rewriter.getNamedAttr("callee", symAttr); 2118*e6c66ef5SAndrzej Warzynski NamedAttribute fieldAttr = rewriter.getNamedAttr( 2119*e6c66ef5SAndrzej Warzynski "field", mlir::IntegerAttr::get(lowerTy().indexType(), index)); 2120*e6c66ef5SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>( 2121*e6c66ef5SAndrzej Warzynski field, lowerTy().offsetType(), adaptor.getOperands(), 2122*e6c66ef5SAndrzej Warzynski llvm::ArrayRef<mlir::NamedAttribute>{callAttr, fieldAttr}); 2123*e6c66ef5SAndrzej Warzynski return success(); 2124*e6c66ef5SAndrzej Warzynski } 2125*e6c66ef5SAndrzej Warzynski 2126*e6c66ef5SAndrzej Warzynski // Re-Construct the name of the compiler generated method that calculates the 2127*e6c66ef5SAndrzej Warzynski // offset 2128*e6c66ef5SAndrzej Warzynski inline static std::string getOffsetMethodName(fir::RecordType recTy, 2129*e6c66ef5SAndrzej Warzynski llvm::StringRef field) { 2130*e6c66ef5SAndrzej Warzynski return recTy.getName().str() + "P." + field.str() + ".offset"; 2131*e6c66ef5SAndrzej Warzynski } 2132*e6c66ef5SAndrzej Warzynski }; 2133*e6c66ef5SAndrzej Warzynski 2134044d5b5dSValentin Clement } // namespace 2135044d5b5dSValentin Clement 2136044d5b5dSValentin Clement namespace { 2137044d5b5dSValentin Clement /// Convert FIR dialect to LLVM dialect 2138044d5b5dSValentin Clement /// 2139044d5b5dSValentin Clement /// This pass lowers all FIR dialect operations to LLVM IR dialect. An 2140044d5b5dSValentin Clement /// MLIR pass is used to lower residual Std dialect to LLVM IR dialect. 2141044d5b5dSValentin Clement /// 2142044d5b5dSValentin Clement /// This pass is not complete yet. We are upstreaming it in small patches. 2143044d5b5dSValentin Clement class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> { 2144044d5b5dSValentin Clement public: 2145044d5b5dSValentin Clement mlir::ModuleOp getModule() { return getOperation(); } 2146044d5b5dSValentin Clement 2147044d5b5dSValentin Clement void runOnOperation() override final { 21487b5132daSValentin Clement auto mod = getModule(); 21497b5132daSValentin Clement if (!forcedTargetTriple.empty()) { 21507b5132daSValentin Clement fir::setTargetTriple(mod, forcedTargetTriple); 21517b5132daSValentin Clement } 21527b5132daSValentin Clement 2153044d5b5dSValentin Clement auto *context = getModule().getContext(); 2154044d5b5dSValentin Clement fir::LLVMTypeConverter typeConverter{getModule()}; 2155044d5b5dSValentin Clement mlir::OwningRewritePatternList pattern(context); 2156df3b9810SValentin Clement pattern.insert< 2157420ad7ceSAndrzej Warzynski AbsentOpConversion, AddcOpConversion, AddrOfOpConversion, 21581a2ec667SValentin Clement AllocaOpConversion, BoxAddrOpConversion, BoxCharLenOpConversion, 21591a2ec667SValentin Clement BoxDimsOpConversion, BoxEleSizeOpConversion, BoxIsAllocOpConversion, 2160cc505c0bSKiran Chandramohan BoxIsArrayOpConversion, BoxIsPtrOpConversion, BoxProcHostOpConversion, 2161cc505c0bSKiran Chandramohan BoxRankOpConversion, BoxTypeDescOpConversion, CallOpConversion, 2162cc505c0bSKiran Chandramohan CmpcOpConversion, ConstcOpConversion, ConvertOpConversion, 2163cc505c0bSKiran Chandramohan DispatchOpConversion, DispatchTableOpConversion, DTEntryOpConversion, 2164cc505c0bSKiran Chandramohan DivcOpConversion, EmboxOpConversion, EmboxCharOpConversion, 2165*e6c66ef5SAndrzej Warzynski EmboxProcOpConversion, ExtractValueOpConversion, FieldIndexOpConversion, 2166*e6c66ef5SAndrzej Warzynski FirEndOpConversion, HasValueOpConversion, GenTypeDescOpConversion, 2167*e6c66ef5SAndrzej Warzynski GlobalLenOpConversion, GlobalOpConversion, InsertOnRangeOpConversion, 2168*e6c66ef5SAndrzej Warzynski InsertValueOpConversion, IsPresentOpConversion, LoadOpConversion, 2169*e6c66ef5SAndrzej Warzynski NegcOpConversion, MulcOpConversion, SelectCaseOpConversion, 2170*e6c66ef5SAndrzej Warzynski SelectOpConversion, SelectRankOpConversion, SelectTypeOpConversion, 2171*e6c66ef5SAndrzej Warzynski ShapeOpConversion, ShapeShiftOpConversion, ShiftOpConversion, 2172*e6c66ef5SAndrzej Warzynski SliceOpConversion, StoreOpConversion, StringLitOpConversion, 2173*e6c66ef5SAndrzej Warzynski SubcOpConversion, UnboxCharOpConversion, UnboxProcOpConversion, 2174*e6c66ef5SAndrzej Warzynski UndefOpConversion, UnreachableOpConversion, ZeroOpConversion>( 2175*e6c66ef5SAndrzej Warzynski typeConverter); 2176044d5b5dSValentin Clement mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern); 2177044d5b5dSValentin Clement mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter, 2178044d5b5dSValentin Clement pattern); 2179044d5b5dSValentin Clement mlir::ConversionTarget target{*context}; 2180044d5b5dSValentin Clement target.addLegalDialect<mlir::LLVM::LLVMDialect>(); 2181044d5b5dSValentin Clement 2182044d5b5dSValentin Clement // required NOPs for applying a full conversion 2183044d5b5dSValentin Clement target.addLegalOp<mlir::ModuleOp>(); 2184044d5b5dSValentin Clement 2185044d5b5dSValentin Clement // apply the patterns 2186044d5b5dSValentin Clement if (mlir::failed(mlir::applyFullConversion(getModule(), target, 2187044d5b5dSValentin Clement std::move(pattern)))) { 2188044d5b5dSValentin Clement signalPassFailure(); 2189044d5b5dSValentin Clement } 2190044d5b5dSValentin Clement } 2191044d5b5dSValentin Clement }; 2192044d5b5dSValentin Clement } // namespace 2193044d5b5dSValentin Clement 2194044d5b5dSValentin Clement std::unique_ptr<mlir::Pass> fir::createFIRToLLVMPass() { 2195044d5b5dSValentin Clement return std::make_unique<FIRToLLVMLowering>(); 2196044d5b5dSValentin Clement } 2197