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" 141f551032SValentin Clement #include "CGOps.h" 15044d5b5dSValentin Clement #include "PassDetail.h" 16b6e44ecdSValentin Clement #include "flang/ISO_Fortran_binding.h" 1739f4ef81SValentin Clement #include "flang/Optimizer/Dialect/FIRAttr.h" 18044d5b5dSValentin Clement #include "flang/Optimizer/Dialect/FIROps.h" 19af6ee580SValentin Clement #include "flang/Optimizer/Support/TypeCode.h" 20044d5b5dSValentin Clement #include "mlir/Conversion/ArithmeticToLLVM/ArithmeticToLLVM.h" 21044d5b5dSValentin Clement #include "mlir/Conversion/LLVMCommon/Pattern.h" 22044d5b5dSValentin Clement #include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h" 23044d5b5dSValentin Clement #include "mlir/IR/BuiltinTypes.h" 243ae8e442SValentin Clement #include "mlir/IR/Matchers.h" 25044d5b5dSValentin Clement #include "mlir/Pass/Pass.h" 26044d5b5dSValentin Clement #include "llvm/ADT/ArrayRef.h" 27044d5b5dSValentin Clement 28044d5b5dSValentin Clement #define DEBUG_TYPE "flang-codegen" 29044d5b5dSValentin Clement 30044d5b5dSValentin Clement // fir::LLVMTypeConverter for converting to LLVM IR dialect types. 31044d5b5dSValentin Clement #include "TypeConverter.h" 32044d5b5dSValentin Clement 33af6ee580SValentin Clement // TODO: This should really be recovered from the specified target. 34af6ee580SValentin Clement static constexpr unsigned defaultAlign = 8; 35af6ee580SValentin Clement 36b6e44ecdSValentin Clement /// `fir.box` attribute values as defined for CFI_attribute_t in 37b6e44ecdSValentin Clement /// flang/ISO_Fortran_binding.h. 38b6e44ecdSValentin Clement static constexpr unsigned kAttrPointer = CFI_attribute_pointer; 39b6e44ecdSValentin Clement static constexpr unsigned kAttrAllocatable = CFI_attribute_allocatable; 40b6e44ecdSValentin Clement 41fa517555SKiran Chandramohan static mlir::Type getVoidPtrType(mlir::MLIRContext *context) { 42fa517555SKiran Chandramohan return mlir::LLVM::LLVMPointerType::get(mlir::IntegerType::get(context, 8)); 43fa517555SKiran Chandramohan } 44fa517555SKiran Chandramohan 451e6d9c06SDiana Picus static mlir::LLVM::ConstantOp 461e6d9c06SDiana Picus genConstantIndex(mlir::Location loc, mlir::Type ity, 471e6d9c06SDiana Picus mlir::ConversionPatternRewriter &rewriter, 481e6d9c06SDiana Picus std::int64_t offset) { 491e6d9c06SDiana Picus auto cattr = rewriter.getI64IntegerAttr(offset); 501e6d9c06SDiana Picus return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr); 511e6d9c06SDiana Picus } 521e6d9c06SDiana Picus 5339f4ef81SValentin Clement static Block *createBlock(mlir::ConversionPatternRewriter &rewriter, 5439f4ef81SValentin Clement mlir::Block *insertBefore) { 5539f4ef81SValentin Clement assert(insertBefore && "expected valid insertion block"); 5639f4ef81SValentin Clement return rewriter.createBlock(insertBefore->getParent(), 5739f4ef81SValentin Clement mlir::Region::iterator(insertBefore)); 5839f4ef81SValentin Clement } 5939f4ef81SValentin Clement 60044d5b5dSValentin Clement namespace { 61044d5b5dSValentin Clement /// FIR conversion pattern template 62044d5b5dSValentin Clement template <typename FromOp> 63044d5b5dSValentin Clement class FIROpConversion : public mlir::ConvertOpToLLVMPattern<FromOp> { 64044d5b5dSValentin Clement public: 65044d5b5dSValentin Clement explicit FIROpConversion(fir::LLVMTypeConverter &lowering) 66044d5b5dSValentin Clement : mlir::ConvertOpToLLVMPattern<FromOp>(lowering) {} 67044d5b5dSValentin Clement 68044d5b5dSValentin Clement protected: 69044d5b5dSValentin Clement mlir::Type convertType(mlir::Type ty) const { 70044d5b5dSValentin Clement return lowerTy().convertType(ty); 71044d5b5dSValentin Clement } 72*c2acd453SAlexisPerry mlir::Type voidPtrTy() const { return getVoidPtrType(); } 73044d5b5dSValentin Clement 745d27abe6SValentin Clement mlir::Type getVoidPtrType() const { 755d27abe6SValentin Clement return mlir::LLVM::LLVMPointerType::get( 765d27abe6SValentin Clement mlir::IntegerType::get(&lowerTy().getContext(), 8)); 775d27abe6SValentin Clement } 785d27abe6SValentin Clement 79df3b9810SValentin Clement mlir::LLVM::ConstantOp 80af6ee580SValentin Clement genI32Constant(mlir::Location loc, mlir::ConversionPatternRewriter &rewriter, 81af6ee580SValentin Clement int value) const { 82af6ee580SValentin Clement mlir::Type i32Ty = rewriter.getI32Type(); 83af6ee580SValentin Clement mlir::IntegerAttr attr = rewriter.getI32IntegerAttr(value); 84af6ee580SValentin Clement return rewriter.create<mlir::LLVM::ConstantOp>(loc, i32Ty, attr); 85af6ee580SValentin Clement } 86af6ee580SValentin Clement 87af6ee580SValentin Clement mlir::LLVM::ConstantOp 88df3b9810SValentin Clement genConstantOffset(mlir::Location loc, 89df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter, 90df3b9810SValentin Clement int offset) const { 91af6ee580SValentin Clement mlir::Type ity = lowerTy().offsetType(); 92af6ee580SValentin Clement mlir::IntegerAttr cattr = rewriter.getI32IntegerAttr(offset); 93df3b9810SValentin Clement return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr); 94df3b9810SValentin Clement } 95df3b9810SValentin Clement 96b6e44ecdSValentin Clement /// Construct code sequence to extract the specifc value from a `fir.box`. 97b6e44ecdSValentin Clement mlir::Value getValueFromBox(mlir::Location loc, mlir::Value box, 98df3b9810SValentin Clement mlir::Type resultTy, 99b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter, 100b6e44ecdSValentin Clement unsigned boxValue) const { 101df3b9810SValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 102b6e44ecdSValentin Clement mlir::LLVM::ConstantOp cValuePos = 103b6e44ecdSValentin Clement genConstantOffset(loc, rewriter, boxValue); 104df3b9810SValentin Clement auto pty = mlir::LLVM::LLVMPointerType::get(resultTy); 105df3b9810SValentin Clement auto p = rewriter.create<mlir::LLVM::GEPOp>( 106b6e44ecdSValentin Clement loc, pty, mlir::ValueRange{box, c0, cValuePos}); 107df3b9810SValentin Clement return rewriter.create<mlir::LLVM::LoadOp>(loc, resultTy, p); 108df3b9810SValentin Clement } 109df3b9810SValentin Clement 110df3b9810SValentin Clement /// Method to construct code sequence to get the triple for dimension `dim` 111df3b9810SValentin Clement /// from a box. 112df3b9810SValentin Clement SmallVector<mlir::Value, 3> 113df3b9810SValentin Clement getDimsFromBox(mlir::Location loc, ArrayRef<mlir::Type> retTys, 114df3b9810SValentin Clement mlir::Value box, mlir::Value dim, 115df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 116df3b9810SValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 117df3b9810SValentin Clement mlir::LLVM::ConstantOp cDims = 118df3b9810SValentin Clement genConstantOffset(loc, rewriter, kDimsPosInBox); 119df3b9810SValentin Clement mlir::LLVM::LoadOp l0 = 120df3b9810SValentin Clement loadFromOffset(loc, box, c0, cDims, dim, 0, retTys[0], rewriter); 121df3b9810SValentin Clement mlir::LLVM::LoadOp l1 = 122df3b9810SValentin Clement loadFromOffset(loc, box, c0, cDims, dim, 1, retTys[1], rewriter); 123df3b9810SValentin Clement mlir::LLVM::LoadOp l2 = 124df3b9810SValentin Clement loadFromOffset(loc, box, c0, cDims, dim, 2, retTys[2], rewriter); 125df3b9810SValentin Clement return {l0.getResult(), l1.getResult(), l2.getResult()}; 126df3b9810SValentin Clement } 127df3b9810SValentin Clement 128df3b9810SValentin Clement mlir::LLVM::LoadOp 129df3b9810SValentin Clement loadFromOffset(mlir::Location loc, mlir::Value a, mlir::LLVM::ConstantOp c0, 130df3b9810SValentin Clement mlir::LLVM::ConstantOp cDims, mlir::Value dim, int off, 131df3b9810SValentin Clement mlir::Type ty, 132df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 133df3b9810SValentin Clement auto pty = mlir::LLVM::LLVMPointerType::get(ty); 134df3b9810SValentin Clement mlir::LLVM::ConstantOp c = genConstantOffset(loc, rewriter, off); 135df3b9810SValentin Clement mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, a, c0, cDims, dim, c); 136df3b9810SValentin Clement return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p); 137df3b9810SValentin Clement } 138df3b9810SValentin Clement 1395d27abe6SValentin Clement mlir::Value 1405d27abe6SValentin Clement loadStrideFromBox(mlir::Location loc, mlir::Value box, unsigned dim, 1415d27abe6SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 1425d27abe6SValentin Clement auto idxTy = lowerTy().indexType(); 1435d27abe6SValentin Clement auto c0 = genConstantOffset(loc, rewriter, 0); 1445d27abe6SValentin Clement auto cDims = genConstantOffset(loc, rewriter, kDimsPosInBox); 1455d27abe6SValentin Clement auto dimValue = genConstantIndex(loc, idxTy, rewriter, dim); 1465d27abe6SValentin Clement return loadFromOffset(loc, box, c0, cDims, dimValue, kDimStridePos, idxTy, 1475d27abe6SValentin Clement rewriter); 1485d27abe6SValentin Clement } 1495d27abe6SValentin Clement 150df3b9810SValentin Clement /// Read base address from a fir.box. Returned address has type ty. 151df3b9810SValentin Clement mlir::Value 152df3b9810SValentin Clement loadBaseAddrFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box, 153df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 154df3b9810SValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 155df3b9810SValentin Clement mlir::LLVM::ConstantOp cAddr = 156df3b9810SValentin Clement genConstantOffset(loc, rewriter, kAddrPosInBox); 157df3b9810SValentin Clement auto pty = mlir::LLVM::LLVMPointerType::get(ty); 158df3b9810SValentin Clement mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cAddr); 159df3b9810SValentin Clement return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p); 160df3b9810SValentin Clement } 161df3b9810SValentin Clement 162df3b9810SValentin Clement mlir::Value 163df3b9810SValentin Clement loadElementSizeFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box, 164df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 165df3b9810SValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 166df3b9810SValentin Clement mlir::LLVM::ConstantOp cElemLen = 167df3b9810SValentin Clement genConstantOffset(loc, rewriter, kElemLenPosInBox); 168df3b9810SValentin Clement auto pty = mlir::LLVM::LLVMPointerType::get(ty); 169df3b9810SValentin Clement mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cElemLen); 170df3b9810SValentin Clement return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p); 171df3b9810SValentin Clement } 172df3b9810SValentin Clement 173b6e44ecdSValentin Clement // Load the attribute from the \p box and perform a check against \p maskValue 174b6e44ecdSValentin Clement // The final comparison is implemented as `(attribute & maskValue) != 0`. 175b6e44ecdSValentin Clement mlir::Value genBoxAttributeCheck(mlir::Location loc, mlir::Value box, 176b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter, 177b6e44ecdSValentin Clement unsigned maskValue) const { 178b6e44ecdSValentin Clement mlir::Type attrTy = rewriter.getI32Type(); 179b6e44ecdSValentin Clement mlir::Value attribute = 180b6e44ecdSValentin Clement getValueFromBox(loc, box, attrTy, rewriter, kAttributePosInBox); 181b6e44ecdSValentin Clement mlir::LLVM::ConstantOp attrMask = 182b6e44ecdSValentin Clement genConstantOffset(loc, rewriter, maskValue); 183b6e44ecdSValentin Clement auto maskRes = 184b6e44ecdSValentin Clement rewriter.create<mlir::LLVM::AndOp>(loc, attrTy, attribute, attrMask); 185b6e44ecdSValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 186b6e44ecdSValentin Clement return rewriter.create<mlir::LLVM::ICmpOp>( 187b6e44ecdSValentin Clement loc, mlir::LLVM::ICmpPredicate::ne, maskRes, c0); 188b6e44ecdSValentin Clement } 189b6e44ecdSValentin Clement 190af6ee580SValentin Clement // Get the element type given an LLVM type that is of the form 191af6ee580SValentin Clement // [llvm.ptr](array|struct|vector)+ and the provided indexes. 192af6ee580SValentin Clement static mlir::Type getBoxEleTy(mlir::Type type, 193af6ee580SValentin Clement llvm::ArrayRef<unsigned> indexes) { 194af6ee580SValentin Clement if (auto t = type.dyn_cast<mlir::LLVM::LLVMPointerType>()) 195af6ee580SValentin Clement type = t.getElementType(); 196af6ee580SValentin Clement for (auto i : indexes) { 197af6ee580SValentin Clement if (auto t = type.dyn_cast<mlir::LLVM::LLVMStructType>()) { 198af6ee580SValentin Clement assert(!t.isOpaque() && i < t.getBody().size()); 199af6ee580SValentin Clement type = t.getBody()[i]; 200af6ee580SValentin Clement } else if (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) { 201af6ee580SValentin Clement type = t.getElementType(); 202af6ee580SValentin Clement } else if (auto t = type.dyn_cast<mlir::VectorType>()) { 203af6ee580SValentin Clement type = t.getElementType(); 204af6ee580SValentin Clement } else { 205af6ee580SValentin Clement fir::emitFatalError(mlir::UnknownLoc::get(type.getContext()), 206af6ee580SValentin Clement "request for invalid box element type"); 207af6ee580SValentin Clement } 208af6ee580SValentin Clement } 209af6ee580SValentin Clement return type; 210af6ee580SValentin Clement } 211af6ee580SValentin Clement 2125d27abe6SValentin Clement // Return LLVM type of the base address given the LLVM type 2135d27abe6SValentin Clement // of the related descriptor (lowered fir.box type). 2145d27abe6SValentin Clement static mlir::Type getBaseAddrTypeFromBox(mlir::Type type) { 2155d27abe6SValentin Clement return getBoxEleTy(type, {kAddrPosInBox}); 2165d27abe6SValentin Clement } 2175d27abe6SValentin Clement 218df3b9810SValentin Clement template <typename... ARGS> 219df3b9810SValentin Clement mlir::LLVM::GEPOp genGEP(mlir::Location loc, mlir::Type ty, 220df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter, 221df3b9810SValentin Clement mlir::Value base, ARGS... args) const { 222df3b9810SValentin Clement SmallVector<mlir::Value> cv{args...}; 223df3b9810SValentin Clement return rewriter.create<mlir::LLVM::GEPOp>(loc, ty, base, cv); 224df3b9810SValentin Clement } 225df3b9810SValentin Clement 2261e6d9c06SDiana Picus /// Perform an extension or truncation as needed on an integer value. Lowering 2271e6d9c06SDiana Picus /// to the specific target may involve some sign-extending or truncation of 2281e6d9c06SDiana Picus /// values, particularly to fit them from abstract box types to the 2291e6d9c06SDiana Picus /// appropriate reified structures. 2301e6d9c06SDiana Picus mlir::Value integerCast(mlir::Location loc, 2311e6d9c06SDiana Picus mlir::ConversionPatternRewriter &rewriter, 2321e6d9c06SDiana Picus mlir::Type ty, mlir::Value val) const { 2331e6d9c06SDiana Picus auto valTy = val.getType(); 2341e6d9c06SDiana Picus // If the value was not yet lowered, lower its type so that it can 2351e6d9c06SDiana Picus // be used in getPrimitiveTypeSizeInBits. 2361e6d9c06SDiana Picus if (!valTy.isa<mlir::IntegerType>()) 2371e6d9c06SDiana Picus valTy = convertType(valTy); 2381e6d9c06SDiana Picus auto toSize = mlir::LLVM::getPrimitiveTypeSizeInBits(ty); 2391e6d9c06SDiana Picus auto fromSize = mlir::LLVM::getPrimitiveTypeSizeInBits(valTy); 2401e6d9c06SDiana Picus if (toSize < fromSize) 2411e6d9c06SDiana Picus return rewriter.create<mlir::LLVM::TruncOp>(loc, ty, val); 2421e6d9c06SDiana Picus if (toSize > fromSize) 2431e6d9c06SDiana Picus return rewriter.create<mlir::LLVM::SExtOp>(loc, ty, val); 2441e6d9c06SDiana Picus return val; 2451e6d9c06SDiana Picus } 2461e6d9c06SDiana Picus 247044d5b5dSValentin Clement fir::LLVMTypeConverter &lowerTy() const { 248044d5b5dSValentin Clement return *static_cast<fir::LLVMTypeConverter *>(this->getTypeConverter()); 249044d5b5dSValentin Clement } 250044d5b5dSValentin Clement }; 251044d5b5dSValentin Clement 2523ae8e442SValentin Clement /// FIR conversion pattern template 2533ae8e442SValentin Clement template <typename FromOp> 2543ae8e442SValentin Clement class FIROpAndTypeConversion : public FIROpConversion<FromOp> { 2553ae8e442SValentin Clement public: 2563ae8e442SValentin Clement using FIROpConversion<FromOp>::FIROpConversion; 2573ae8e442SValentin Clement using OpAdaptor = typename FromOp::Adaptor; 2583ae8e442SValentin Clement 2593ae8e442SValentin Clement mlir::LogicalResult 2603ae8e442SValentin Clement matchAndRewrite(FromOp op, OpAdaptor adaptor, 2613ae8e442SValentin Clement mlir::ConversionPatternRewriter &rewriter) const final { 2623ae8e442SValentin Clement mlir::Type ty = this->convertType(op.getType()); 2633ae8e442SValentin Clement return doRewrite(op, ty, adaptor, rewriter); 2643ae8e442SValentin Clement } 2653ae8e442SValentin Clement 2663ae8e442SValentin Clement virtual mlir::LogicalResult 2673ae8e442SValentin Clement doRewrite(FromOp addr, mlir::Type ty, OpAdaptor adaptor, 2683ae8e442SValentin Clement mlir::ConversionPatternRewriter &rewriter) const = 0; 2693ae8e442SValentin Clement }; 2703ae8e442SValentin Clement 271420ad7ceSAndrzej Warzynski /// Create value signaling an absent optional argument in a call, e.g. 272420ad7ceSAndrzej Warzynski /// `fir.absent !fir.ref<i64>` --> `llvm.mlir.null : !llvm.ptr<i64>` 273420ad7ceSAndrzej Warzynski struct AbsentOpConversion : public FIROpConversion<fir::AbsentOp> { 274420ad7ceSAndrzej Warzynski using FIROpConversion::FIROpConversion; 275420ad7ceSAndrzej Warzynski 276420ad7ceSAndrzej Warzynski mlir::LogicalResult 277420ad7ceSAndrzej Warzynski matchAndRewrite(fir::AbsentOp absent, OpAdaptor, 278420ad7ceSAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 279420ad7ceSAndrzej Warzynski mlir::Type ty = convertType(absent.getType()); 280420ad7ceSAndrzej Warzynski mlir::Location loc = absent.getLoc(); 281420ad7ceSAndrzej Warzynski 282420ad7ceSAndrzej Warzynski if (absent.getType().isa<fir::BoxCharType>()) { 283420ad7ceSAndrzej Warzynski auto structTy = ty.cast<mlir::LLVM::LLVMStructType>(); 284420ad7ceSAndrzej Warzynski assert(!structTy.isOpaque() && !structTy.getBody().empty()); 285420ad7ceSAndrzej Warzynski auto undefStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 286420ad7ceSAndrzej Warzynski auto nullField = 287420ad7ceSAndrzej Warzynski rewriter.create<mlir::LLVM::NullOp>(loc, structTy.getBody()[0]); 288420ad7ceSAndrzej Warzynski mlir::MLIRContext *ctx = absent.getContext(); 289420ad7ceSAndrzej Warzynski auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 290420ad7ceSAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 291420ad7ceSAndrzej Warzynski absent, ty, undefStruct, nullField, c0); 292420ad7ceSAndrzej Warzynski } else { 293420ad7ceSAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(absent, ty); 294420ad7ceSAndrzej Warzynski } 295420ad7ceSAndrzej Warzynski return success(); 296420ad7ceSAndrzej Warzynski } 297420ad7ceSAndrzej Warzynski }; 298420ad7ceSAndrzej Warzynski 2990c4a7a52SValentin Clement // Lower `fir.address_of` operation to `llvm.address_of` operation. 300044d5b5dSValentin Clement struct AddrOfOpConversion : public FIROpConversion<fir::AddrOfOp> { 301044d5b5dSValentin Clement using FIROpConversion::FIROpConversion; 302044d5b5dSValentin Clement 303044d5b5dSValentin Clement mlir::LogicalResult 304044d5b5dSValentin Clement matchAndRewrite(fir::AddrOfOp addr, OpAdaptor adaptor, 305044d5b5dSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 306044d5b5dSValentin Clement auto ty = convertType(addr.getType()); 307044d5b5dSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::AddressOfOp>( 308044d5b5dSValentin Clement addr, ty, addr.symbol().getRootReference().getValue()); 309044d5b5dSValentin Clement return success(); 310044d5b5dSValentin Clement } 311044d5b5dSValentin Clement }; 3121e6d9c06SDiana Picus } // namespace 3131e6d9c06SDiana Picus 3141e6d9c06SDiana Picus /// Lookup the function to compute the memory size of this parametric derived 3151e6d9c06SDiana Picus /// type. The size of the object may depend on the LEN type parameters of the 3161e6d9c06SDiana Picus /// derived type. 3171e6d9c06SDiana Picus static mlir::LLVM::LLVMFuncOp 3181e6d9c06SDiana Picus getDependentTypeMemSizeFn(fir::RecordType recTy, fir::AllocaOp op, 3191e6d9c06SDiana Picus mlir::ConversionPatternRewriter &rewriter) { 3201e6d9c06SDiana Picus auto module = op->getParentOfType<mlir::ModuleOp>(); 3211e6d9c06SDiana Picus std::string name = recTy.getName().str() + "P.mem.size"; 3221e6d9c06SDiana Picus return module.lookupSymbol<mlir::LLVM::LLVMFuncOp>(name); 3231e6d9c06SDiana Picus } 3241e6d9c06SDiana Picus 3251e6d9c06SDiana Picus namespace { 3261e6d9c06SDiana Picus /// convert to LLVM IR dialect `alloca` 3271e6d9c06SDiana Picus struct AllocaOpConversion : public FIROpConversion<fir::AllocaOp> { 3281e6d9c06SDiana Picus using FIROpConversion::FIROpConversion; 3291e6d9c06SDiana Picus 3301e6d9c06SDiana Picus mlir::LogicalResult 3311e6d9c06SDiana Picus matchAndRewrite(fir::AllocaOp alloc, OpAdaptor adaptor, 3321e6d9c06SDiana Picus mlir::ConversionPatternRewriter &rewriter) const override { 3331e6d9c06SDiana Picus mlir::ValueRange operands = adaptor.getOperands(); 3341e6d9c06SDiana Picus auto loc = alloc.getLoc(); 3351e6d9c06SDiana Picus mlir::Type ity = lowerTy().indexType(); 3361e6d9c06SDiana Picus unsigned i = 0; 3371e6d9c06SDiana Picus mlir::Value size = genConstantIndex(loc, ity, rewriter, 1).getResult(); 3381e6d9c06SDiana Picus mlir::Type ty = convertType(alloc.getType()); 3391e6d9c06SDiana Picus mlir::Type resultTy = ty; 3401e6d9c06SDiana Picus if (alloc.hasLenParams()) { 3411e6d9c06SDiana Picus unsigned end = alloc.numLenParams(); 3421e6d9c06SDiana Picus llvm::SmallVector<mlir::Value> lenParams; 3431e6d9c06SDiana Picus for (; i < end; ++i) 3441e6d9c06SDiana Picus lenParams.push_back(operands[i]); 3451e6d9c06SDiana Picus mlir::Type scalarType = fir::unwrapSequenceType(alloc.getInType()); 3461e6d9c06SDiana Picus if (auto chrTy = scalarType.dyn_cast<fir::CharacterType>()) { 3471e6d9c06SDiana Picus fir::CharacterType rawCharTy = fir::CharacterType::getUnknownLen( 3481e6d9c06SDiana Picus chrTy.getContext(), chrTy.getFKind()); 3491e6d9c06SDiana Picus ty = mlir::LLVM::LLVMPointerType::get(convertType(rawCharTy)); 3501e6d9c06SDiana Picus assert(end == 1); 3511e6d9c06SDiana Picus size = integerCast(loc, rewriter, ity, lenParams[0]); 3521e6d9c06SDiana Picus } else if (auto recTy = scalarType.dyn_cast<fir::RecordType>()) { 3531e6d9c06SDiana Picus mlir::LLVM::LLVMFuncOp memSizeFn = 3541e6d9c06SDiana Picus getDependentTypeMemSizeFn(recTy, alloc, rewriter); 3551e6d9c06SDiana Picus if (!memSizeFn) 3561e6d9c06SDiana Picus emitError(loc, "did not find allocation function"); 3571e6d9c06SDiana Picus mlir::NamedAttribute attr = rewriter.getNamedAttr( 3581e6d9c06SDiana Picus "callee", mlir::SymbolRefAttr::get(memSizeFn)); 3591e6d9c06SDiana Picus auto call = rewriter.create<mlir::LLVM::CallOp>( 3601e6d9c06SDiana Picus loc, ity, lenParams, llvm::ArrayRef<mlir::NamedAttribute>{attr}); 3611e6d9c06SDiana Picus size = call.getResult(0); 3621e6d9c06SDiana Picus ty = mlir::LLVM::LLVMPointerType::get( 3631e6d9c06SDiana Picus mlir::IntegerType::get(alloc.getContext(), 8)); 3641e6d9c06SDiana Picus } else { 3651e6d9c06SDiana Picus return emitError(loc, "unexpected type ") 3661e6d9c06SDiana Picus << scalarType << " with type parameters"; 3671e6d9c06SDiana Picus } 3681e6d9c06SDiana Picus } 3691e6d9c06SDiana Picus if (alloc.hasShapeOperands()) { 3701e6d9c06SDiana Picus mlir::Type allocEleTy = fir::unwrapRefType(alloc.getType()); 3711e6d9c06SDiana Picus // Scale the size by constant factors encoded in the array type. 3721e6d9c06SDiana Picus if (auto seqTy = allocEleTy.dyn_cast<fir::SequenceType>()) { 3731e6d9c06SDiana Picus fir::SequenceType::Extent constSize = 1; 3741e6d9c06SDiana Picus for (auto extent : seqTy.getShape()) 3751e6d9c06SDiana Picus if (extent != fir::SequenceType::getUnknownExtent()) 3761e6d9c06SDiana Picus constSize *= extent; 3771e6d9c06SDiana Picus mlir::Value constVal{ 3781e6d9c06SDiana Picus genConstantIndex(loc, ity, rewriter, constSize).getResult()}; 3791e6d9c06SDiana Picus size = rewriter.create<mlir::LLVM::MulOp>(loc, ity, size, constVal); 3801e6d9c06SDiana Picus } 3811e6d9c06SDiana Picus unsigned end = operands.size(); 3821e6d9c06SDiana Picus for (; i < end; ++i) 3831e6d9c06SDiana Picus size = rewriter.create<mlir::LLVM::MulOp>( 3841e6d9c06SDiana Picus loc, ity, size, integerCast(loc, rewriter, ity, operands[i])); 3851e6d9c06SDiana Picus } 3861e6d9c06SDiana Picus if (ty == resultTy) { 3871e6d9c06SDiana Picus // Do not emit the bitcast if ty and resultTy are the same. 3881e6d9c06SDiana Picus rewriter.replaceOpWithNewOp<mlir::LLVM::AllocaOp>(alloc, ty, size, 3891e6d9c06SDiana Picus alloc->getAttrs()); 3901e6d9c06SDiana Picus } else { 3911e6d9c06SDiana Picus auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, ty, size, 3921e6d9c06SDiana Picus alloc->getAttrs()); 3931e6d9c06SDiana Picus rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(alloc, resultTy, al); 3941e6d9c06SDiana Picus } 3951e6d9c06SDiana Picus return success(); 3961e6d9c06SDiana Picus } 3971e6d9c06SDiana Picus }; 398044d5b5dSValentin Clement 399df3b9810SValentin Clement /// Lower `fir.box_addr` to the sequence of operations to extract the first 400df3b9810SValentin Clement /// element of the box. 401df3b9810SValentin Clement struct BoxAddrOpConversion : public FIROpConversion<fir::BoxAddrOp> { 402df3b9810SValentin Clement using FIROpConversion::FIROpConversion; 403df3b9810SValentin Clement 404df3b9810SValentin Clement mlir::LogicalResult 405df3b9810SValentin Clement matchAndRewrite(fir::BoxAddrOp boxaddr, OpAdaptor adaptor, 406df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 407df3b9810SValentin Clement mlir::Value a = adaptor.getOperands()[0]; 408df3b9810SValentin Clement auto loc = boxaddr.getLoc(); 409df3b9810SValentin Clement mlir::Type ty = convertType(boxaddr.getType()); 410df3b9810SValentin Clement if (auto argty = boxaddr.val().getType().dyn_cast<fir::BoxType>()) { 411df3b9810SValentin Clement rewriter.replaceOp(boxaddr, loadBaseAddrFromBox(loc, ty, a, rewriter)); 412df3b9810SValentin Clement } else { 413df3b9810SValentin Clement auto c0attr = rewriter.getI32IntegerAttr(0); 414df3b9810SValentin Clement auto c0 = mlir::ArrayAttr::get(boxaddr.getContext(), c0attr); 415df3b9810SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(boxaddr, ty, a, 416df3b9810SValentin Clement c0); 417df3b9810SValentin Clement } 418df3b9810SValentin Clement return success(); 419df3b9810SValentin Clement } 420df3b9810SValentin Clement }; 421df3b9810SValentin Clement 422df3b9810SValentin Clement /// Lower `fir.box_dims` to a sequence of operations to extract the requested 423df3b9810SValentin Clement /// dimension infomartion from the boxed value. 424df3b9810SValentin Clement /// Result in a triple set of GEPs and loads. 425df3b9810SValentin Clement struct BoxDimsOpConversion : public FIROpConversion<fir::BoxDimsOp> { 426df3b9810SValentin Clement using FIROpConversion::FIROpConversion; 427df3b9810SValentin Clement 428df3b9810SValentin Clement mlir::LogicalResult 429df3b9810SValentin Clement matchAndRewrite(fir::BoxDimsOp boxdims, OpAdaptor adaptor, 430df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 431df3b9810SValentin Clement SmallVector<mlir::Type, 3> resultTypes = { 432df3b9810SValentin Clement convertType(boxdims.getResult(0).getType()), 433df3b9810SValentin Clement convertType(boxdims.getResult(1).getType()), 434df3b9810SValentin Clement convertType(boxdims.getResult(2).getType()), 435df3b9810SValentin Clement }; 436df3b9810SValentin Clement auto results = 437df3b9810SValentin Clement getDimsFromBox(boxdims.getLoc(), resultTypes, adaptor.getOperands()[0], 438df3b9810SValentin Clement adaptor.getOperands()[1], rewriter); 439df3b9810SValentin Clement rewriter.replaceOp(boxdims, results); 440df3b9810SValentin Clement return success(); 441df3b9810SValentin Clement } 442df3b9810SValentin Clement }; 443df3b9810SValentin Clement 444df3b9810SValentin Clement /// Lower `fir.box_elesize` to a sequence of operations ro extract the size of 445df3b9810SValentin Clement /// an element in the boxed value. 446df3b9810SValentin Clement struct BoxEleSizeOpConversion : public FIROpConversion<fir::BoxEleSizeOp> { 447df3b9810SValentin Clement using FIROpConversion::FIROpConversion; 448df3b9810SValentin Clement 449df3b9810SValentin Clement mlir::LogicalResult 450df3b9810SValentin Clement matchAndRewrite(fir::BoxEleSizeOp boxelesz, OpAdaptor adaptor, 451df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 452df3b9810SValentin Clement mlir::Value a = adaptor.getOperands()[0]; 453df3b9810SValentin Clement auto loc = boxelesz.getLoc(); 454df3b9810SValentin Clement auto ty = convertType(boxelesz.getType()); 455b6e44ecdSValentin Clement auto elemSize = getValueFromBox(loc, a, ty, rewriter, kElemLenPosInBox); 456b6e44ecdSValentin Clement rewriter.replaceOp(boxelesz, elemSize); 457b6e44ecdSValentin Clement return success(); 458b6e44ecdSValentin Clement } 459b6e44ecdSValentin Clement }; 460b6e44ecdSValentin Clement 461b6e44ecdSValentin Clement /// Lower `fir.box_isalloc` to a sequence of operations to determine if the 462b6e44ecdSValentin Clement /// boxed value was from an ALLOCATABLE entity. 463b6e44ecdSValentin Clement struct BoxIsAllocOpConversion : public FIROpConversion<fir::BoxIsAllocOp> { 464b6e44ecdSValentin Clement using FIROpConversion::FIROpConversion; 465b6e44ecdSValentin Clement 466b6e44ecdSValentin Clement mlir::LogicalResult 467b6e44ecdSValentin Clement matchAndRewrite(fir::BoxIsAllocOp boxisalloc, OpAdaptor adaptor, 468b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 469b6e44ecdSValentin Clement mlir::Value box = adaptor.getOperands()[0]; 470b6e44ecdSValentin Clement auto loc = boxisalloc.getLoc(); 471b6e44ecdSValentin Clement mlir::Value check = 472b6e44ecdSValentin Clement genBoxAttributeCheck(loc, box, rewriter, kAttrAllocatable); 473b6e44ecdSValentin Clement rewriter.replaceOp(boxisalloc, check); 474b6e44ecdSValentin Clement return success(); 475b6e44ecdSValentin Clement } 476b6e44ecdSValentin Clement }; 477b6e44ecdSValentin Clement 478b6e44ecdSValentin Clement /// Lower `fir.box_isarray` to a sequence of operations to determine if the 479b6e44ecdSValentin Clement /// boxed is an array. 480b6e44ecdSValentin Clement struct BoxIsArrayOpConversion : public FIROpConversion<fir::BoxIsArrayOp> { 481b6e44ecdSValentin Clement using FIROpConversion::FIROpConversion; 482b6e44ecdSValentin Clement 483b6e44ecdSValentin Clement mlir::LogicalResult 484b6e44ecdSValentin Clement matchAndRewrite(fir::BoxIsArrayOp boxisarray, OpAdaptor adaptor, 485b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 486b6e44ecdSValentin Clement mlir::Value a = adaptor.getOperands()[0]; 487b6e44ecdSValentin Clement auto loc = boxisarray.getLoc(); 488b6e44ecdSValentin Clement auto rank = 489b6e44ecdSValentin Clement getValueFromBox(loc, a, rewriter.getI32Type(), rewriter, kRankPosInBox); 490b6e44ecdSValentin Clement auto c0 = genConstantOffset(loc, rewriter, 0); 491b6e44ecdSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>( 492b6e44ecdSValentin Clement boxisarray, mlir::LLVM::ICmpPredicate::ne, rank, c0); 493b6e44ecdSValentin Clement return success(); 494b6e44ecdSValentin Clement } 495b6e44ecdSValentin Clement }; 496b6e44ecdSValentin Clement 497b6e44ecdSValentin Clement /// Lower `fir.box_isptr` to a sequence of operations to determined if the 498b6e44ecdSValentin Clement /// boxed value was from a POINTER entity. 499b6e44ecdSValentin Clement struct BoxIsPtrOpConversion : public FIROpConversion<fir::BoxIsPtrOp> { 500b6e44ecdSValentin Clement using FIROpConversion::FIROpConversion; 501b6e44ecdSValentin Clement 502b6e44ecdSValentin Clement mlir::LogicalResult 503b6e44ecdSValentin Clement matchAndRewrite(fir::BoxIsPtrOp boxisptr, OpAdaptor adaptor, 504b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 505b6e44ecdSValentin Clement mlir::Value box = adaptor.getOperands()[0]; 506b6e44ecdSValentin Clement auto loc = boxisptr.getLoc(); 507b6e44ecdSValentin Clement mlir::Value check = genBoxAttributeCheck(loc, box, rewriter, kAttrPointer); 508b6e44ecdSValentin Clement rewriter.replaceOp(boxisptr, check); 509df3b9810SValentin Clement return success(); 510df3b9810SValentin Clement } 511df3b9810SValentin Clement }; 512df3b9810SValentin Clement 513df3b9810SValentin Clement /// Lower `fir.box_rank` to the sequence of operation to extract the rank from 514df3b9810SValentin Clement /// the box. 515df3b9810SValentin Clement struct BoxRankOpConversion : public FIROpConversion<fir::BoxRankOp> { 516df3b9810SValentin Clement using FIROpConversion::FIROpConversion; 517df3b9810SValentin Clement 518df3b9810SValentin Clement mlir::LogicalResult 519df3b9810SValentin Clement matchAndRewrite(fir::BoxRankOp boxrank, OpAdaptor adaptor, 520df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 521df3b9810SValentin Clement mlir::Value a = adaptor.getOperands()[0]; 522df3b9810SValentin Clement auto loc = boxrank.getLoc(); 523df3b9810SValentin Clement mlir::Type ty = convertType(boxrank.getType()); 524b6e44ecdSValentin Clement auto result = getValueFromBox(loc, a, ty, rewriter, kRankPosInBox); 525df3b9810SValentin Clement rewriter.replaceOp(boxrank, result); 526df3b9810SValentin Clement return success(); 527df3b9810SValentin Clement } 528df3b9810SValentin Clement }; 529df3b9810SValentin Clement 5301a2ec667SValentin Clement /// Lower `fir.string_lit` to LLVM IR dialect operation. 5311a2ec667SValentin Clement struct StringLitOpConversion : public FIROpConversion<fir::StringLitOp> { 5321a2ec667SValentin Clement using FIROpConversion::FIROpConversion; 5331a2ec667SValentin Clement 5341a2ec667SValentin Clement mlir::LogicalResult 5351a2ec667SValentin Clement matchAndRewrite(fir::StringLitOp constop, OpAdaptor adaptor, 5361a2ec667SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 5371a2ec667SValentin Clement auto ty = convertType(constop.getType()); 5381a2ec667SValentin Clement auto attr = constop.getValue(); 5391a2ec667SValentin Clement if (attr.isa<mlir::StringAttr>()) { 5401a2ec667SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(constop, ty, attr); 5411a2ec667SValentin Clement return success(); 5421a2ec667SValentin Clement } 5431a2ec667SValentin Clement 5441a2ec667SValentin Clement auto arr = attr.cast<mlir::ArrayAttr>(); 5451a2ec667SValentin Clement auto charTy = constop.getType().cast<fir::CharacterType>(); 5461a2ec667SValentin Clement unsigned bits = lowerTy().characterBitsize(charTy); 5471a2ec667SValentin Clement mlir::Type intTy = rewriter.getIntegerType(bits); 5481a2ec667SValentin Clement auto attrs = llvm::map_range( 5491a2ec667SValentin Clement arr.getValue(), [intTy, bits](mlir::Attribute attr) -> Attribute { 5501a2ec667SValentin Clement return mlir::IntegerAttr::get( 5511a2ec667SValentin Clement intTy, 5521a2ec667SValentin Clement attr.cast<mlir::IntegerAttr>().getValue().sextOrTrunc(bits)); 5531a2ec667SValentin Clement }); 5541a2ec667SValentin Clement mlir::Type vecType = mlir::VectorType::get(arr.size(), intTy); 5551a2ec667SValentin Clement auto denseAttr = mlir::DenseElementsAttr::get( 5561a2ec667SValentin Clement vecType.cast<mlir::ShapedType>(), llvm::to_vector<8>(attrs)); 5571a2ec667SValentin Clement rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(constop, ty, 5581a2ec667SValentin Clement denseAttr); 5591a2ec667SValentin Clement return success(); 5601a2ec667SValentin Clement } 5611a2ec667SValentin Clement }; 5621a2ec667SValentin Clement 563cc505c0bSKiran Chandramohan /// Lower `fir.boxproc_host` operation. Extracts the host pointer from the 564cc505c0bSKiran Chandramohan /// boxproc. 565cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers. 566cc505c0bSKiran Chandramohan struct BoxProcHostOpConversion : public FIROpConversion<fir::BoxProcHostOp> { 567cc505c0bSKiran Chandramohan using FIROpConversion::FIROpConversion; 568cc505c0bSKiran Chandramohan 569cc505c0bSKiran Chandramohan mlir::LogicalResult 570cc505c0bSKiran Chandramohan matchAndRewrite(fir::BoxProcHostOp boxprochost, OpAdaptor adaptor, 571cc505c0bSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 5727ce8c6fcSKiran Chandramohan TODO(boxprochost.getLoc(), "fir.boxproc_host codegen"); 5737ce8c6fcSKiran Chandramohan return failure(); 574cc505c0bSKiran Chandramohan } 575cc505c0bSKiran Chandramohan }; 576cc505c0bSKiran Chandramohan 577e38ef2ffSValentin Clement /// Lower `fir.box_tdesc` to the sequence of operations to extract the type 578e38ef2ffSValentin Clement /// descriptor from the box. 579e38ef2ffSValentin Clement struct BoxTypeDescOpConversion : public FIROpConversion<fir::BoxTypeDescOp> { 580e38ef2ffSValentin Clement using FIROpConversion::FIROpConversion; 581e38ef2ffSValentin Clement 582e38ef2ffSValentin Clement mlir::LogicalResult 583e38ef2ffSValentin Clement matchAndRewrite(fir::BoxTypeDescOp boxtypedesc, OpAdaptor adaptor, 584e38ef2ffSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 585e38ef2ffSValentin Clement mlir::Value box = adaptor.getOperands()[0]; 586e38ef2ffSValentin Clement auto loc = boxtypedesc.getLoc(); 587e38ef2ffSValentin Clement mlir::Type typeTy = 588e38ef2ffSValentin Clement fir::getDescFieldTypeModel<kTypePosInBox>()(boxtypedesc.getContext()); 589e38ef2ffSValentin Clement auto result = getValueFromBox(loc, box, typeTy, rewriter, kTypePosInBox); 590e38ef2ffSValentin Clement auto typePtrTy = mlir::LLVM::LLVMPointerType::get(typeTy); 591e38ef2ffSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(boxtypedesc, typePtrTy, 592e38ef2ffSValentin Clement result); 593e38ef2ffSValentin Clement return success(); 594e38ef2ffSValentin Clement } 595e38ef2ffSValentin Clement }; 596e38ef2ffSValentin Clement 597ddd11b9aSAndrzej Warzynski // `fir.call` -> `llvm.call` 598ddd11b9aSAndrzej Warzynski struct CallOpConversion : public FIROpConversion<fir::CallOp> { 599ddd11b9aSAndrzej Warzynski using FIROpConversion::FIROpConversion; 600ddd11b9aSAndrzej Warzynski 601ddd11b9aSAndrzej Warzynski mlir::LogicalResult 602ddd11b9aSAndrzej Warzynski matchAndRewrite(fir::CallOp call, OpAdaptor adaptor, 603ddd11b9aSAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 604ddd11b9aSAndrzej Warzynski SmallVector<mlir::Type> resultTys; 605ddd11b9aSAndrzej Warzynski for (auto r : call.getResults()) 606ddd11b9aSAndrzej Warzynski resultTys.push_back(convertType(r.getType())); 607ddd11b9aSAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>( 608ddd11b9aSAndrzej Warzynski call, resultTys, adaptor.getOperands(), call->getAttrs()); 609ddd11b9aSAndrzej Warzynski return success(); 610ddd11b9aSAndrzej Warzynski } 611ddd11b9aSAndrzej Warzynski }; 612*c2acd453SAlexisPerry } // namespace 613ddd11b9aSAndrzej Warzynski 614092cee5fSValentin Clement static mlir::Type getComplexEleTy(mlir::Type complex) { 615092cee5fSValentin Clement if (auto cc = complex.dyn_cast<mlir::ComplexType>()) 616092cee5fSValentin Clement return cc.getElementType(); 617092cee5fSValentin Clement return complex.cast<fir::ComplexType>().getElementType(); 618092cee5fSValentin Clement } 619092cee5fSValentin Clement 620*c2acd453SAlexisPerry namespace { 621f1dfc027SDiana Picus /// Compare complex values 622f1dfc027SDiana Picus /// 623f1dfc027SDiana Picus /// Per 10.1, the only comparisons available are .EQ. (oeq) and .NE. (une). 624f1dfc027SDiana Picus /// 625f1dfc027SDiana Picus /// For completeness, all other comparison are done on the real component only. 626f1dfc027SDiana Picus struct CmpcOpConversion : public FIROpConversion<fir::CmpcOp> { 627f1dfc027SDiana Picus using FIROpConversion::FIROpConversion; 628f1dfc027SDiana Picus 629f1dfc027SDiana Picus mlir::LogicalResult 630f1dfc027SDiana Picus matchAndRewrite(fir::CmpcOp cmp, OpAdaptor adaptor, 631f1dfc027SDiana Picus mlir::ConversionPatternRewriter &rewriter) const override { 632f1dfc027SDiana Picus mlir::ValueRange operands = adaptor.getOperands(); 633f1dfc027SDiana Picus mlir::MLIRContext *ctxt = cmp.getContext(); 634f1dfc027SDiana Picus mlir::Type eleTy = convertType(getComplexEleTy(cmp.lhs().getType())); 635f1dfc027SDiana Picus mlir::Type resTy = convertType(cmp.getType()); 636f1dfc027SDiana Picus mlir::Location loc = cmp.getLoc(); 637f1dfc027SDiana Picus auto pos0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0)); 638f1dfc027SDiana Picus SmallVector<mlir::Value, 2> rp{rewriter.create<mlir::LLVM::ExtractValueOp>( 639f1dfc027SDiana Picus loc, eleTy, operands[0], pos0), 640f1dfc027SDiana Picus rewriter.create<mlir::LLVM::ExtractValueOp>( 641f1dfc027SDiana Picus loc, eleTy, operands[1], pos0)}; 642f1dfc027SDiana Picus auto rcp = 643f1dfc027SDiana Picus rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, rp, cmp->getAttrs()); 644f1dfc027SDiana Picus auto pos1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1)); 645f1dfc027SDiana Picus SmallVector<mlir::Value, 2> ip{rewriter.create<mlir::LLVM::ExtractValueOp>( 646f1dfc027SDiana Picus loc, eleTy, operands[0], pos1), 647f1dfc027SDiana Picus rewriter.create<mlir::LLVM::ExtractValueOp>( 648f1dfc027SDiana Picus loc, eleTy, operands[1], pos1)}; 649f1dfc027SDiana Picus auto icp = 650f1dfc027SDiana Picus rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, ip, cmp->getAttrs()); 651f1dfc027SDiana Picus SmallVector<mlir::Value, 2> cp{rcp, icp}; 652f1dfc027SDiana Picus switch (cmp.getPredicate()) { 653f1dfc027SDiana Picus case mlir::arith::CmpFPredicate::OEQ: // .EQ. 654f1dfc027SDiana Picus rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(cmp, resTy, cp); 655f1dfc027SDiana Picus break; 656f1dfc027SDiana Picus case mlir::arith::CmpFPredicate::UNE: // .NE. 657f1dfc027SDiana Picus rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(cmp, resTy, cp); 658f1dfc027SDiana Picus break; 659f1dfc027SDiana Picus default: 660f1dfc027SDiana Picus rewriter.replaceOp(cmp, rcp.getResult()); 661f1dfc027SDiana Picus break; 662f1dfc027SDiana Picus } 663f1dfc027SDiana Picus return success(); 664f1dfc027SDiana Picus } 665f1dfc027SDiana Picus }; 666f1dfc027SDiana Picus 667e81d73edSDiana Picus /// Lower complex constants 668e81d73edSDiana Picus struct ConstcOpConversion : public FIROpConversion<fir::ConstcOp> { 669e81d73edSDiana Picus using FIROpConversion::FIROpConversion; 670e81d73edSDiana Picus 671e81d73edSDiana Picus mlir::LogicalResult 672e81d73edSDiana Picus matchAndRewrite(fir::ConstcOp conc, OpAdaptor, 673e81d73edSDiana Picus mlir::ConversionPatternRewriter &rewriter) const override { 674e81d73edSDiana Picus mlir::Location loc = conc.getLoc(); 675e81d73edSDiana Picus mlir::MLIRContext *ctx = conc.getContext(); 676e81d73edSDiana Picus mlir::Type ty = convertType(conc.getType()); 677e81d73edSDiana Picus mlir::Type ety = convertType(getComplexEleTy(conc.getType())); 678e81d73edSDiana Picus auto realFloatAttr = mlir::FloatAttr::get(ety, getValue(conc.getReal())); 679e81d73edSDiana Picus auto realPart = 680e81d73edSDiana Picus rewriter.create<mlir::LLVM::ConstantOp>(loc, ety, realFloatAttr); 681e81d73edSDiana Picus auto imFloatAttr = mlir::FloatAttr::get(ety, getValue(conc.getImaginary())); 682e81d73edSDiana Picus auto imPart = 683e81d73edSDiana Picus rewriter.create<mlir::LLVM::ConstantOp>(loc, ety, imFloatAttr); 684e81d73edSDiana Picus auto realIndex = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 685e81d73edSDiana Picus auto imIndex = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 686e81d73edSDiana Picus auto undef = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 687e81d73edSDiana Picus auto setReal = rewriter.create<mlir::LLVM::InsertValueOp>( 688e81d73edSDiana Picus loc, ty, undef, realPart, realIndex); 689e81d73edSDiana Picus rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(conc, ty, setReal, 690e81d73edSDiana Picus imPart, imIndex); 691e81d73edSDiana Picus return success(); 692e81d73edSDiana Picus } 693e81d73edSDiana Picus 694e81d73edSDiana Picus inline APFloat getValue(mlir::Attribute attr) const { 695e81d73edSDiana Picus return attr.cast<fir::RealAttr>().getValue(); 696e81d73edSDiana Picus } 697e81d73edSDiana Picus }; 698e81d73edSDiana Picus 699092cee5fSValentin Clement /// convert value of from-type to value of to-type 700092cee5fSValentin Clement struct ConvertOpConversion : public FIROpConversion<fir::ConvertOp> { 701092cee5fSValentin Clement using FIROpConversion::FIROpConversion; 702092cee5fSValentin Clement 703092cee5fSValentin Clement static bool isFloatingPointTy(mlir::Type ty) { 704092cee5fSValentin Clement return ty.isa<mlir::FloatType>(); 705092cee5fSValentin Clement } 706092cee5fSValentin Clement 707092cee5fSValentin Clement mlir::LogicalResult 708092cee5fSValentin Clement matchAndRewrite(fir::ConvertOp convert, OpAdaptor adaptor, 709092cee5fSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 710092cee5fSValentin Clement auto fromTy = convertType(convert.value().getType()); 711092cee5fSValentin Clement auto toTy = convertType(convert.res().getType()); 712092cee5fSValentin Clement mlir::Value op0 = adaptor.getOperands()[0]; 713092cee5fSValentin Clement if (fromTy == toTy) { 714092cee5fSValentin Clement rewriter.replaceOp(convert, op0); 715092cee5fSValentin Clement return success(); 716092cee5fSValentin Clement } 717092cee5fSValentin Clement auto loc = convert.getLoc(); 718092cee5fSValentin Clement auto convertFpToFp = [&](mlir::Value val, unsigned fromBits, 719092cee5fSValentin Clement unsigned toBits, mlir::Type toTy) -> mlir::Value { 720092cee5fSValentin Clement if (fromBits == toBits) { 721092cee5fSValentin Clement // TODO: Converting between two floating-point representations with the 722092cee5fSValentin Clement // same bitwidth is not allowed for now. 723092cee5fSValentin Clement mlir::emitError(loc, 724092cee5fSValentin Clement "cannot implicitly convert between two floating-point " 725092cee5fSValentin Clement "representations of the same bitwidth"); 726092cee5fSValentin Clement return {}; 727092cee5fSValentin Clement } 728092cee5fSValentin Clement if (fromBits > toBits) 729092cee5fSValentin Clement return rewriter.create<mlir::LLVM::FPTruncOp>(loc, toTy, val); 730092cee5fSValentin Clement return rewriter.create<mlir::LLVM::FPExtOp>(loc, toTy, val); 731092cee5fSValentin Clement }; 732092cee5fSValentin Clement // Complex to complex conversion. 733092cee5fSValentin Clement if (fir::isa_complex(convert.value().getType()) && 734092cee5fSValentin Clement fir::isa_complex(convert.res().getType())) { 735092cee5fSValentin Clement // Special case: handle the conversion of a complex such that both the 736092cee5fSValentin Clement // real and imaginary parts are converted together. 737092cee5fSValentin Clement auto zero = mlir::ArrayAttr::get(convert.getContext(), 738092cee5fSValentin Clement rewriter.getI32IntegerAttr(0)); 739092cee5fSValentin Clement auto one = mlir::ArrayAttr::get(convert.getContext(), 740092cee5fSValentin Clement rewriter.getI32IntegerAttr(1)); 741092cee5fSValentin Clement auto ty = convertType(getComplexEleTy(convert.value().getType())); 742092cee5fSValentin Clement auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, zero); 743092cee5fSValentin Clement auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, one); 744092cee5fSValentin Clement auto nt = convertType(getComplexEleTy(convert.res().getType())); 745092cee5fSValentin Clement auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(ty); 746092cee5fSValentin Clement auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(nt); 747092cee5fSValentin Clement auto rc = convertFpToFp(rp, fromBits, toBits, nt); 748092cee5fSValentin Clement auto ic = convertFpToFp(ip, fromBits, toBits, nt); 749092cee5fSValentin Clement auto un = rewriter.create<mlir::LLVM::UndefOp>(loc, toTy); 750092cee5fSValentin Clement auto i1 = 751092cee5fSValentin Clement rewriter.create<mlir::LLVM::InsertValueOp>(loc, toTy, un, rc, zero); 752092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(convert, toTy, i1, 753092cee5fSValentin Clement ic, one); 754092cee5fSValentin Clement return mlir::success(); 755092cee5fSValentin Clement } 756092cee5fSValentin Clement // Floating point to floating point conversion. 757092cee5fSValentin Clement if (isFloatingPointTy(fromTy)) { 758092cee5fSValentin Clement if (isFloatingPointTy(toTy)) { 759092cee5fSValentin Clement auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy); 760092cee5fSValentin Clement auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy); 761092cee5fSValentin Clement auto v = convertFpToFp(op0, fromBits, toBits, toTy); 762092cee5fSValentin Clement rewriter.replaceOp(convert, v); 763092cee5fSValentin Clement return mlir::success(); 764092cee5fSValentin Clement } 765092cee5fSValentin Clement if (toTy.isa<mlir::IntegerType>()) { 766092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::FPToSIOp>(convert, toTy, op0); 767092cee5fSValentin Clement return mlir::success(); 768092cee5fSValentin Clement } 769092cee5fSValentin Clement } else if (fromTy.isa<mlir::IntegerType>()) { 770092cee5fSValentin Clement // Integer to integer conversion. 771092cee5fSValentin Clement if (toTy.isa<mlir::IntegerType>()) { 772092cee5fSValentin Clement auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy); 773092cee5fSValentin Clement auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy); 774092cee5fSValentin Clement assert(fromBits != toBits); 775092cee5fSValentin Clement if (fromBits > toBits) { 776092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::TruncOp>(convert, toTy, op0); 777092cee5fSValentin Clement return mlir::success(); 778092cee5fSValentin Clement } 779092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::SExtOp>(convert, toTy, op0); 780092cee5fSValentin Clement return mlir::success(); 781092cee5fSValentin Clement } 782092cee5fSValentin Clement // Integer to floating point conversion. 783092cee5fSValentin Clement if (isFloatingPointTy(toTy)) { 784092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::SIToFPOp>(convert, toTy, op0); 785092cee5fSValentin Clement return mlir::success(); 786092cee5fSValentin Clement } 787092cee5fSValentin Clement // Integer to pointer conversion. 788092cee5fSValentin Clement if (toTy.isa<mlir::LLVM::LLVMPointerType>()) { 789092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(convert, toTy, op0); 790092cee5fSValentin Clement return mlir::success(); 791092cee5fSValentin Clement } 792092cee5fSValentin Clement } else if (fromTy.isa<mlir::LLVM::LLVMPointerType>()) { 793092cee5fSValentin Clement // Pointer to integer conversion. 794092cee5fSValentin Clement if (toTy.isa<mlir::IntegerType>()) { 795092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::PtrToIntOp>(convert, toTy, op0); 796092cee5fSValentin Clement return mlir::success(); 797092cee5fSValentin Clement } 798092cee5fSValentin Clement // Pointer to pointer conversion. 799092cee5fSValentin Clement if (toTy.isa<mlir::LLVM::LLVMPointerType>()) { 800092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(convert, toTy, op0); 801092cee5fSValentin Clement return mlir::success(); 802092cee5fSValentin Clement } 803092cee5fSValentin Clement } 804092cee5fSValentin Clement return emitError(loc) << "cannot convert " << fromTy << " to " << toTy; 805092cee5fSValentin Clement } 806092cee5fSValentin Clement }; 807092cee5fSValentin Clement 8089534e361SValentin Clement /// Lower `fir.dispatch` operation. A virtual call to a method in a dispatch 8099534e361SValentin Clement /// table. 8109534e361SValentin Clement struct DispatchOpConversion : public FIROpConversion<fir::DispatchOp> { 8119534e361SValentin Clement using FIROpConversion::FIROpConversion; 8129534e361SValentin Clement 8139534e361SValentin Clement mlir::LogicalResult 8149534e361SValentin Clement matchAndRewrite(fir::DispatchOp dispatch, OpAdaptor adaptor, 8159534e361SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 8167ce8c6fcSKiran Chandramohan TODO(dispatch.getLoc(), "fir.dispatch codegen"); 8177ce8c6fcSKiran Chandramohan return failure(); 8189534e361SValentin Clement } 8199534e361SValentin Clement }; 8209534e361SValentin Clement 8219534e361SValentin Clement /// Lower `fir.dispatch_table` operation. The dispatch table for a Fortran 8229534e361SValentin Clement /// derived type. 8239534e361SValentin Clement struct DispatchTableOpConversion 8249534e361SValentin Clement : public FIROpConversion<fir::DispatchTableOp> { 8259534e361SValentin Clement using FIROpConversion::FIROpConversion; 8269534e361SValentin Clement 8279534e361SValentin Clement mlir::LogicalResult 8289534e361SValentin Clement matchAndRewrite(fir::DispatchTableOp dispTab, OpAdaptor adaptor, 8299534e361SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 8307ce8c6fcSKiran Chandramohan TODO(dispTab.getLoc(), "fir.dispatch_table codegen"); 8317ce8c6fcSKiran Chandramohan return failure(); 8329534e361SValentin Clement } 8339534e361SValentin Clement }; 8349534e361SValentin Clement 8359534e361SValentin Clement /// Lower `fir.dt_entry` operation. An entry in a dispatch table; binds a 8369534e361SValentin Clement /// method-name to a function. 8379534e361SValentin Clement struct DTEntryOpConversion : public FIROpConversion<fir::DTEntryOp> { 8389534e361SValentin Clement using FIROpConversion::FIROpConversion; 8399534e361SValentin Clement 8409534e361SValentin Clement mlir::LogicalResult 8419534e361SValentin Clement matchAndRewrite(fir::DTEntryOp dtEnt, OpAdaptor adaptor, 8429534e361SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 8437ce8c6fcSKiran Chandramohan TODO(dtEnt.getLoc(), "fir.dt_entry codegen"); 8447ce8c6fcSKiran Chandramohan return failure(); 8459534e361SValentin Clement } 8469534e361SValentin Clement }; 8479534e361SValentin Clement 848677df8c7SValentin Clement /// Lower `fir.global_len` operation. 849677df8c7SValentin Clement struct GlobalLenOpConversion : public FIROpConversion<fir::GlobalLenOp> { 850677df8c7SValentin Clement using FIROpConversion::FIROpConversion; 851677df8c7SValentin Clement 852677df8c7SValentin Clement mlir::LogicalResult 853677df8c7SValentin Clement matchAndRewrite(fir::GlobalLenOp globalLen, OpAdaptor adaptor, 854677df8c7SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 8557ce8c6fcSKiran Chandramohan TODO(globalLen.getLoc(), "fir.global_len codegen"); 8567ce8c6fcSKiran Chandramohan return failure(); 857677df8c7SValentin Clement } 858677df8c7SValentin Clement }; 859677df8c7SValentin Clement 860cdc476abSDiana Picus /// Lower fir.len_param_index 861cdc476abSDiana Picus struct LenParamIndexOpConversion 862cdc476abSDiana Picus : public FIROpConversion<fir::LenParamIndexOp> { 863cdc476abSDiana Picus using FIROpConversion::FIROpConversion; 864cdc476abSDiana Picus 865cdc476abSDiana Picus // FIXME: this should be specialized by the runtime target 866cdc476abSDiana Picus mlir::LogicalResult 867cdc476abSDiana Picus matchAndRewrite(fir::LenParamIndexOp lenp, OpAdaptor, 868cdc476abSDiana Picus mlir::ConversionPatternRewriter &rewriter) const override { 8697ce8c6fcSKiran Chandramohan TODO(lenp.getLoc(), "fir.len_param_index codegen"); 870cdc476abSDiana Picus } 871cdc476abSDiana Picus }; 872cdc476abSDiana Picus 87331246187SValentin Clement /// Lower `fir.gentypedesc` to a global constant. 87431246187SValentin Clement struct GenTypeDescOpConversion : public FIROpConversion<fir::GenTypeDescOp> { 87531246187SValentin Clement using FIROpConversion::FIROpConversion; 87631246187SValentin Clement 87731246187SValentin Clement mlir::LogicalResult 87831246187SValentin Clement matchAndRewrite(fir::GenTypeDescOp gentypedesc, OpAdaptor adaptor, 87931246187SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 8807ce8c6fcSKiran Chandramohan TODO(gentypedesc.getLoc(), "fir.gentypedesc codegen"); 8817ce8c6fcSKiran Chandramohan return failure(); 88231246187SValentin Clement } 88331246187SValentin Clement }; 884*c2acd453SAlexisPerry } // namespace 885*c2acd453SAlexisPerry 886*c2acd453SAlexisPerry /// Return the LLVMFuncOp corresponding to the standard malloc call. 887*c2acd453SAlexisPerry static mlir::LLVM::LLVMFuncOp 888*c2acd453SAlexisPerry getMalloc(fir::AllocMemOp op, mlir::ConversionPatternRewriter &rewriter) { 889*c2acd453SAlexisPerry auto module = op->getParentOfType<mlir::ModuleOp>(); 890*c2acd453SAlexisPerry if (mlir::LLVM::LLVMFuncOp mallocFunc = 891*c2acd453SAlexisPerry module.lookupSymbol<mlir::LLVM::LLVMFuncOp>("malloc")) 892*c2acd453SAlexisPerry return mallocFunc; 893*c2acd453SAlexisPerry mlir::OpBuilder moduleBuilder( 894*c2acd453SAlexisPerry op->getParentOfType<mlir::ModuleOp>().getBodyRegion()); 895*c2acd453SAlexisPerry auto indexType = mlir::IntegerType::get(op.getContext(), 64); 896*c2acd453SAlexisPerry return moduleBuilder.create<mlir::LLVM::LLVMFuncOp>( 897*c2acd453SAlexisPerry rewriter.getUnknownLoc(), "malloc", 898*c2acd453SAlexisPerry mlir::LLVM::LLVMFunctionType::get(getVoidPtrType(op.getContext()), 899*c2acd453SAlexisPerry indexType, 900*c2acd453SAlexisPerry /*isVarArg=*/false)); 901*c2acd453SAlexisPerry } 902*c2acd453SAlexisPerry 903*c2acd453SAlexisPerry /// Helper function for generating the LLVM IR that computes the size 904*c2acd453SAlexisPerry /// in bytes for a derived type. 905*c2acd453SAlexisPerry static mlir::Value 906*c2acd453SAlexisPerry computeDerivedTypeSize(mlir::Location loc, mlir::Type ptrTy, mlir::Type idxTy, 907*c2acd453SAlexisPerry mlir::ConversionPatternRewriter &rewriter) { 908*c2acd453SAlexisPerry auto nullPtr = rewriter.create<mlir::LLVM::NullOp>(loc, ptrTy); 909*c2acd453SAlexisPerry mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1); 910*c2acd453SAlexisPerry llvm::SmallVector<mlir::Value> args{nullPtr, one}; 911*c2acd453SAlexisPerry auto gep = rewriter.create<mlir::LLVM::GEPOp>(loc, ptrTy, args); 912*c2acd453SAlexisPerry return rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, gep); 913*c2acd453SAlexisPerry } 914*c2acd453SAlexisPerry 915*c2acd453SAlexisPerry namespace { 916*c2acd453SAlexisPerry /// Lower a `fir.allocmem` instruction into `llvm.call @malloc` 917*c2acd453SAlexisPerry struct AllocMemOpConversion : public FIROpConversion<fir::AllocMemOp> { 918*c2acd453SAlexisPerry using FIROpConversion::FIROpConversion; 919*c2acd453SAlexisPerry 920*c2acd453SAlexisPerry mlir::LogicalResult 921*c2acd453SAlexisPerry matchAndRewrite(fir::AllocMemOp heap, OpAdaptor adaptor, 922*c2acd453SAlexisPerry mlir::ConversionPatternRewriter &rewriter) const override { 923*c2acd453SAlexisPerry mlir::Type ty = convertType(heap.getType()); 924*c2acd453SAlexisPerry mlir::LLVM::LLVMFuncOp mallocFunc = getMalloc(heap, rewriter); 925*c2acd453SAlexisPerry mlir::Location loc = heap.getLoc(); 926*c2acd453SAlexisPerry auto ity = lowerTy().indexType(); 927*c2acd453SAlexisPerry if (auto recTy = fir::unwrapSequenceType(heap.getAllocatedType()) 928*c2acd453SAlexisPerry .dyn_cast<fir::RecordType>()) 929*c2acd453SAlexisPerry if (recTy.getNumLenParams() != 0) { 930*c2acd453SAlexisPerry TODO(loc, 931*c2acd453SAlexisPerry "fir.allocmem codegen of derived type with length parameters"); 932*c2acd453SAlexisPerry return failure(); 933*c2acd453SAlexisPerry } 934*c2acd453SAlexisPerry mlir::Value size = genTypeSizeInBytes(loc, ity, rewriter, ty); 935*c2acd453SAlexisPerry for (mlir::Value opnd : adaptor.getOperands()) 936*c2acd453SAlexisPerry size = rewriter.create<mlir::LLVM::MulOp>( 937*c2acd453SAlexisPerry loc, ity, size, integerCast(loc, rewriter, ity, opnd)); 938*c2acd453SAlexisPerry heap->setAttr("callee", mlir::SymbolRefAttr::get(mallocFunc)); 939*c2acd453SAlexisPerry auto malloc = rewriter.create<mlir::LLVM::CallOp>( 940*c2acd453SAlexisPerry loc, ::getVoidPtrType(heap.getContext()), size, heap->getAttrs()); 941*c2acd453SAlexisPerry rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(heap, ty, 942*c2acd453SAlexisPerry malloc.getResult(0)); 943*c2acd453SAlexisPerry return success(); 944*c2acd453SAlexisPerry } 945*c2acd453SAlexisPerry 946*c2acd453SAlexisPerry // Compute the (allocation) size of the allocmem type in bytes. 947*c2acd453SAlexisPerry mlir::Value genTypeSizeInBytes(mlir::Location loc, mlir::Type idxTy, 948*c2acd453SAlexisPerry mlir::ConversionPatternRewriter &rewriter, 949*c2acd453SAlexisPerry mlir::Type llTy) const { 950*c2acd453SAlexisPerry // Use the primitive size, if available. 951*c2acd453SAlexisPerry auto ptrTy = llTy.dyn_cast<mlir::LLVM::LLVMPointerType>(); 952*c2acd453SAlexisPerry if (auto size = 953*c2acd453SAlexisPerry mlir::LLVM::getPrimitiveTypeSizeInBits(ptrTy.getElementType())) 954*c2acd453SAlexisPerry return genConstantIndex(loc, idxTy, rewriter, size / 8); 955*c2acd453SAlexisPerry 956*c2acd453SAlexisPerry // Otherwise, generate the GEP trick in LLVM IR to compute the size. 957*c2acd453SAlexisPerry return computeDerivedTypeSize(loc, ptrTy, idxTy, rewriter); 958*c2acd453SAlexisPerry } 959*c2acd453SAlexisPerry }; 960*c2acd453SAlexisPerry } // namespace 961*c2acd453SAlexisPerry 962*c2acd453SAlexisPerry /// Return the LLVMFuncOp corresponding to the standard free call. 963*c2acd453SAlexisPerry static mlir::LLVM::LLVMFuncOp 964*c2acd453SAlexisPerry getFree(fir::FreeMemOp op, mlir::ConversionPatternRewriter &rewriter) { 965*c2acd453SAlexisPerry auto module = op->getParentOfType<mlir::ModuleOp>(); 966*c2acd453SAlexisPerry if (mlir::LLVM::LLVMFuncOp freeFunc = 967*c2acd453SAlexisPerry module.lookupSymbol<mlir::LLVM::LLVMFuncOp>("free")) 968*c2acd453SAlexisPerry return freeFunc; 969*c2acd453SAlexisPerry mlir::OpBuilder moduleBuilder(module.getBodyRegion()); 970*c2acd453SAlexisPerry auto voidType = mlir::LLVM::LLVMVoidType::get(op.getContext()); 971*c2acd453SAlexisPerry return moduleBuilder.create<mlir::LLVM::LLVMFuncOp>( 972*c2acd453SAlexisPerry rewriter.getUnknownLoc(), "free", 973*c2acd453SAlexisPerry mlir::LLVM::LLVMFunctionType::get(voidType, 974*c2acd453SAlexisPerry getVoidPtrType(op.getContext()), 975*c2acd453SAlexisPerry /*isVarArg=*/false)); 976*c2acd453SAlexisPerry } 977*c2acd453SAlexisPerry 978*c2acd453SAlexisPerry namespace { 979*c2acd453SAlexisPerry /// Lower a `fir.freemem` instruction into `llvm.call @free` 980*c2acd453SAlexisPerry struct FreeMemOpConversion : public FIROpConversion<fir::FreeMemOp> { 981*c2acd453SAlexisPerry using FIROpConversion::FIROpConversion; 982*c2acd453SAlexisPerry 983*c2acd453SAlexisPerry mlir::LogicalResult 984*c2acd453SAlexisPerry matchAndRewrite(fir::FreeMemOp freemem, OpAdaptor adaptor, 985*c2acd453SAlexisPerry mlir::ConversionPatternRewriter &rewriter) const override { 986*c2acd453SAlexisPerry mlir::LLVM::LLVMFuncOp freeFunc = getFree(freemem, rewriter); 987*c2acd453SAlexisPerry mlir::Location loc = freemem.getLoc(); 988*c2acd453SAlexisPerry auto bitcast = rewriter.create<mlir::LLVM::BitcastOp>( 989*c2acd453SAlexisPerry freemem.getLoc(), voidPtrTy(), adaptor.getOperands()[0]); 990*c2acd453SAlexisPerry freemem->setAttr("callee", mlir::SymbolRefAttr::get(freeFunc)); 991*c2acd453SAlexisPerry rewriter.create<mlir::LLVM::CallOp>( 992*c2acd453SAlexisPerry loc, mlir::TypeRange{}, mlir::ValueRange{bitcast}, freemem->getAttrs()); 993*c2acd453SAlexisPerry rewriter.eraseOp(freemem); 994*c2acd453SAlexisPerry return success(); 995*c2acd453SAlexisPerry } 996*c2acd453SAlexisPerry }; 99731246187SValentin Clement 99822d332a0SAndrzej Warzynski /// Convert `fir.end` 99922d332a0SAndrzej Warzynski struct FirEndOpConversion : public FIROpConversion<fir::FirEndOp> { 100022d332a0SAndrzej Warzynski using FIROpConversion::FIROpConversion; 100122d332a0SAndrzej Warzynski 100222d332a0SAndrzej Warzynski mlir::LogicalResult 100322d332a0SAndrzej Warzynski matchAndRewrite(fir::FirEndOp firEnd, OpAdaptor, 100422d332a0SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 10057ce8c6fcSKiran Chandramohan TODO(firEnd.getLoc(), "fir.end codegen"); 10067ce8c6fcSKiran Chandramohan return failure(); 100722d332a0SAndrzej Warzynski } 100822d332a0SAndrzej Warzynski }; 100922d332a0SAndrzej Warzynski 10100c4a7a52SValentin Clement /// Lower `fir.has_value` operation to `llvm.return` operation. 1011044d5b5dSValentin Clement struct HasValueOpConversion : public FIROpConversion<fir::HasValueOp> { 1012044d5b5dSValentin Clement using FIROpConversion::FIROpConversion; 1013044d5b5dSValentin Clement 1014044d5b5dSValentin Clement mlir::LogicalResult 1015044d5b5dSValentin Clement matchAndRewrite(fir::HasValueOp op, OpAdaptor adaptor, 1016044d5b5dSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 1017044d5b5dSValentin Clement rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, adaptor.getOperands()); 1018044d5b5dSValentin Clement return success(); 1019044d5b5dSValentin Clement } 1020044d5b5dSValentin Clement }; 1021044d5b5dSValentin Clement 10220c4a7a52SValentin Clement /// Lower `fir.global` operation to `llvm.global` operation. 10230c4a7a52SValentin Clement /// `fir.insert_on_range` operations are replaced with constant dense attribute 10240c4a7a52SValentin Clement /// if they are applied on the full range. 1025044d5b5dSValentin Clement struct GlobalOpConversion : public FIROpConversion<fir::GlobalOp> { 1026044d5b5dSValentin Clement using FIROpConversion::FIROpConversion; 1027044d5b5dSValentin Clement 1028044d5b5dSValentin Clement mlir::LogicalResult 1029044d5b5dSValentin Clement matchAndRewrite(fir::GlobalOp global, OpAdaptor adaptor, 1030044d5b5dSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 1031044d5b5dSValentin Clement auto tyAttr = convertType(global.getType()); 1032044d5b5dSValentin Clement if (global.getType().isa<fir::BoxType>()) 1033044d5b5dSValentin Clement tyAttr = tyAttr.cast<mlir::LLVM::LLVMPointerType>().getElementType(); 1034044d5b5dSValentin Clement auto loc = global.getLoc(); 1035044d5b5dSValentin Clement mlir::Attribute initAttr{}; 1036044d5b5dSValentin Clement if (global.initVal()) 1037044d5b5dSValentin Clement initAttr = global.initVal().getValue(); 1038044d5b5dSValentin Clement auto linkage = convertLinkage(global.linkName()); 1039044d5b5dSValentin Clement auto isConst = global.constant().hasValue(); 1040044d5b5dSValentin Clement auto g = rewriter.create<mlir::LLVM::GlobalOp>( 1041044d5b5dSValentin Clement loc, tyAttr, isConst, linkage, global.sym_name(), initAttr); 1042044d5b5dSValentin Clement auto &gr = g.getInitializerRegion(); 1043044d5b5dSValentin Clement rewriter.inlineRegionBefore(global.region(), gr, gr.end()); 1044044d5b5dSValentin Clement if (!gr.empty()) { 1045044d5b5dSValentin Clement // Replace insert_on_range with a constant dense attribute if the 1046044d5b5dSValentin Clement // initialization is on the full range. 1047044d5b5dSValentin Clement auto insertOnRangeOps = gr.front().getOps<fir::InsertOnRangeOp>(); 1048044d5b5dSValentin Clement for (auto insertOp : insertOnRangeOps) { 1049044d5b5dSValentin Clement if (isFullRange(insertOp.coor(), insertOp.getType())) { 1050044d5b5dSValentin Clement auto seqTyAttr = convertType(insertOp.getType()); 1051044d5b5dSValentin Clement auto *op = insertOp.val().getDefiningOp(); 1052044d5b5dSValentin Clement auto constant = mlir::dyn_cast<mlir::arith::ConstantOp>(op); 1053044d5b5dSValentin Clement if (!constant) { 1054044d5b5dSValentin Clement auto convertOp = mlir::dyn_cast<fir::ConvertOp>(op); 1055044d5b5dSValentin Clement if (!convertOp) 1056044d5b5dSValentin Clement continue; 1057044d5b5dSValentin Clement constant = cast<mlir::arith::ConstantOp>( 1058044d5b5dSValentin Clement convertOp.value().getDefiningOp()); 1059044d5b5dSValentin Clement } 1060044d5b5dSValentin Clement mlir::Type vecType = mlir::VectorType::get( 1061044d5b5dSValentin Clement insertOp.getType().getShape(), constant.getType()); 1062044d5b5dSValentin Clement auto denseAttr = mlir::DenseElementsAttr::get( 1063044d5b5dSValentin Clement vecType.cast<ShapedType>(), constant.value()); 1064044d5b5dSValentin Clement rewriter.setInsertionPointAfter(insertOp); 1065044d5b5dSValentin Clement rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>( 1066044d5b5dSValentin Clement insertOp, seqTyAttr, denseAttr); 1067044d5b5dSValentin Clement } 1068044d5b5dSValentin Clement } 1069044d5b5dSValentin Clement } 1070044d5b5dSValentin Clement rewriter.eraseOp(global); 1071044d5b5dSValentin Clement return success(); 1072044d5b5dSValentin Clement } 1073044d5b5dSValentin Clement 10748ec0f221SMehdi Amini bool isFullRange(mlir::DenseIntElementsAttr indexes, 10758ec0f221SMehdi Amini fir::SequenceType seqTy) const { 1076044d5b5dSValentin Clement auto extents = seqTy.getShape(); 10778ec0f221SMehdi Amini if (indexes.size() / 2 != static_cast<int64_t>(extents.size())) 1078044d5b5dSValentin Clement return false; 10798ec0f221SMehdi Amini auto cur_index = indexes.value_begin<int64_t>(); 1080044d5b5dSValentin Clement for (unsigned i = 0; i < indexes.size(); i += 2) { 10818ec0f221SMehdi Amini if (*(cur_index++) != 0) 1082044d5b5dSValentin Clement return false; 10838ec0f221SMehdi Amini if (*(cur_index++) != extents[i / 2] - 1) 1084044d5b5dSValentin Clement return false; 1085044d5b5dSValentin Clement } 1086044d5b5dSValentin Clement return true; 1087044d5b5dSValentin Clement } 1088044d5b5dSValentin Clement 10890c4a7a52SValentin Clement // TODO: String comparaison should be avoided. Replace linkName with an 10900c4a7a52SValentin Clement // enumeration. 1091044d5b5dSValentin Clement mlir::LLVM::Linkage convertLinkage(Optional<StringRef> optLinkage) const { 1092044d5b5dSValentin Clement if (optLinkage.hasValue()) { 1093044d5b5dSValentin Clement auto name = optLinkage.getValue(); 1094044d5b5dSValentin Clement if (name == "internal") 1095044d5b5dSValentin Clement return mlir::LLVM::Linkage::Internal; 1096044d5b5dSValentin Clement if (name == "linkonce") 1097044d5b5dSValentin Clement return mlir::LLVM::Linkage::Linkonce; 1098044d5b5dSValentin Clement if (name == "common") 1099044d5b5dSValentin Clement return mlir::LLVM::Linkage::Common; 1100044d5b5dSValentin Clement if (name == "weak") 1101044d5b5dSValentin Clement return mlir::LLVM::Linkage::Weak; 1102044d5b5dSValentin Clement } 1103044d5b5dSValentin Clement return mlir::LLVM::Linkage::External; 1104044d5b5dSValentin Clement } 1105044d5b5dSValentin Clement }; 1106*c2acd453SAlexisPerry } // namespace 1107044d5b5dSValentin Clement 1108*c2acd453SAlexisPerry static void genCondBrOp(mlir::Location loc, mlir::Value cmp, mlir::Block *dest, 110939f4ef81SValentin Clement Optional<mlir::ValueRange> destOps, 111039f4ef81SValentin Clement mlir::ConversionPatternRewriter &rewriter, 111139f4ef81SValentin Clement mlir::Block *newBlock) { 111239f4ef81SValentin Clement if (destOps.hasValue()) 111339f4ef81SValentin Clement rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, destOps.getValue(), 111439f4ef81SValentin Clement newBlock, mlir::ValueRange()); 111539f4ef81SValentin Clement else 111639f4ef81SValentin Clement rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, newBlock); 111739f4ef81SValentin Clement } 111839f4ef81SValentin Clement 111939f4ef81SValentin Clement template <typename A, typename B> 1120*c2acd453SAlexisPerry static void genBrOp(A caseOp, mlir::Block *dest, Optional<B> destOps, 112139f4ef81SValentin Clement mlir::ConversionPatternRewriter &rewriter) { 112239f4ef81SValentin Clement if (destOps.hasValue()) 112339f4ef81SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, destOps.getValue(), 112439f4ef81SValentin Clement dest); 112539f4ef81SValentin Clement else 112639f4ef81SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, llvm::None, dest); 112739f4ef81SValentin Clement } 112839f4ef81SValentin Clement 1129*c2acd453SAlexisPerry static void genCaseLadderStep(mlir::Location loc, mlir::Value cmp, 1130*c2acd453SAlexisPerry mlir::Block *dest, 113139f4ef81SValentin Clement Optional<mlir::ValueRange> destOps, 113239f4ef81SValentin Clement mlir::ConversionPatternRewriter &rewriter) { 113339f4ef81SValentin Clement auto *thisBlock = rewriter.getInsertionBlock(); 113439f4ef81SValentin Clement auto *newBlock = createBlock(rewriter, dest); 113539f4ef81SValentin Clement rewriter.setInsertionPointToEnd(thisBlock); 113639f4ef81SValentin Clement genCondBrOp(loc, cmp, dest, destOps, rewriter, newBlock); 113739f4ef81SValentin Clement rewriter.setInsertionPointToEnd(newBlock); 113839f4ef81SValentin Clement } 113939f4ef81SValentin Clement 1140*c2acd453SAlexisPerry namespace { 114139f4ef81SValentin Clement /// Conversion of `fir.select_case` 114239f4ef81SValentin Clement /// 114339f4ef81SValentin Clement /// The `fir.select_case` operation is converted to a if-then-else ladder. 114439f4ef81SValentin Clement /// Depending on the case condition type, one or several comparison and 114539f4ef81SValentin Clement /// conditional branching can be generated. 114639f4ef81SValentin Clement /// 114739f4ef81SValentin Clement /// A a point value case such as `case(4)`, a lower bound case such as 114839f4ef81SValentin Clement /// `case(5:)` or an upper bound case such as `case(:3)` are converted to a 114939f4ef81SValentin Clement /// simple comparison between the selector value and the constant value in the 115039f4ef81SValentin Clement /// case. The block associated with the case condition is then executed if 115139f4ef81SValentin Clement /// the comparison succeed otherwise it branch to the next block with the 115239f4ef81SValentin Clement /// comparison for the the next case conditon. 115339f4ef81SValentin Clement /// 115439f4ef81SValentin Clement /// A closed interval case condition such as `case(7:10)` is converted with a 115539f4ef81SValentin Clement /// first comparison and conditional branching for the lower bound. If 115639f4ef81SValentin Clement /// successful, it branch to a second block with the comparison for the 115739f4ef81SValentin Clement /// upper bound in the same case condition. 115839f4ef81SValentin Clement /// 115939f4ef81SValentin Clement /// TODO: lowering of CHARACTER type cases is not handled yet. 116039f4ef81SValentin Clement struct SelectCaseOpConversion : public FIROpConversion<fir::SelectCaseOp> { 116139f4ef81SValentin Clement using FIROpConversion::FIROpConversion; 116239f4ef81SValentin Clement 116339f4ef81SValentin Clement mlir::LogicalResult 116439f4ef81SValentin Clement matchAndRewrite(fir::SelectCaseOp caseOp, OpAdaptor adaptor, 116539f4ef81SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 116639f4ef81SValentin Clement unsigned conds = caseOp.getNumConditions(); 116739f4ef81SValentin Clement llvm::ArrayRef<mlir::Attribute> cases = caseOp.getCases().getValue(); 116839f4ef81SValentin Clement // Type can be CHARACTER, INTEGER, or LOGICAL (C1145) 11697ce8c6fcSKiran Chandramohan auto ty = caseOp.getSelector().getType(); 11707ce8c6fcSKiran Chandramohan if (ty.isa<fir::CharacterType>()) { 11717ce8c6fcSKiran Chandramohan TODO(caseOp.getLoc(), "fir.select_case codegen with character type"); 11727ce8c6fcSKiran Chandramohan return failure(); 11737ce8c6fcSKiran Chandramohan } 117439f4ef81SValentin Clement mlir::Value selector = caseOp.getSelector(adaptor.getOperands()); 117539f4ef81SValentin Clement auto loc = caseOp.getLoc(); 117639f4ef81SValentin Clement for (unsigned t = 0; t != conds; ++t) { 117739f4ef81SValentin Clement mlir::Block *dest = caseOp.getSuccessor(t); 117839f4ef81SValentin Clement llvm::Optional<mlir::ValueRange> destOps = 117939f4ef81SValentin Clement caseOp.getSuccessorOperands(adaptor.getOperands(), t); 118039f4ef81SValentin Clement llvm::Optional<mlir::ValueRange> cmpOps = 118139f4ef81SValentin Clement *caseOp.getCompareOperands(adaptor.getOperands(), t); 118239f4ef81SValentin Clement mlir::Value caseArg = *(cmpOps.getValue().begin()); 118339f4ef81SValentin Clement mlir::Attribute attr = cases[t]; 118439f4ef81SValentin Clement if (attr.isa<fir::PointIntervalAttr>()) { 118539f4ef81SValentin Clement auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 118639f4ef81SValentin Clement loc, mlir::LLVM::ICmpPredicate::eq, selector, caseArg); 118739f4ef81SValentin Clement genCaseLadderStep(loc, cmp, dest, destOps, rewriter); 118839f4ef81SValentin Clement continue; 118939f4ef81SValentin Clement } 119039f4ef81SValentin Clement if (attr.isa<fir::LowerBoundAttr>()) { 119139f4ef81SValentin Clement auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 119239f4ef81SValentin Clement loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector); 119339f4ef81SValentin Clement genCaseLadderStep(loc, cmp, dest, destOps, rewriter); 119439f4ef81SValentin Clement continue; 119539f4ef81SValentin Clement } 119639f4ef81SValentin Clement if (attr.isa<fir::UpperBoundAttr>()) { 119739f4ef81SValentin Clement auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 119839f4ef81SValentin Clement loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg); 119939f4ef81SValentin Clement genCaseLadderStep(loc, cmp, dest, destOps, rewriter); 120039f4ef81SValentin Clement continue; 120139f4ef81SValentin Clement } 120239f4ef81SValentin Clement if (attr.isa<fir::ClosedIntervalAttr>()) { 120339f4ef81SValentin Clement auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 120439f4ef81SValentin Clement loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector); 120539f4ef81SValentin Clement auto *thisBlock = rewriter.getInsertionBlock(); 120639f4ef81SValentin Clement auto *newBlock1 = createBlock(rewriter, dest); 120739f4ef81SValentin Clement auto *newBlock2 = createBlock(rewriter, dest); 120839f4ef81SValentin Clement rewriter.setInsertionPointToEnd(thisBlock); 120939f4ef81SValentin Clement rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, newBlock1, newBlock2); 121039f4ef81SValentin Clement rewriter.setInsertionPointToEnd(newBlock1); 121139f4ef81SValentin Clement mlir::Value caseArg0 = *(cmpOps.getValue().begin() + 1); 121239f4ef81SValentin Clement auto cmp0 = rewriter.create<mlir::LLVM::ICmpOp>( 121339f4ef81SValentin Clement loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg0); 121439f4ef81SValentin Clement genCondBrOp(loc, cmp0, dest, destOps, rewriter, newBlock2); 121539f4ef81SValentin Clement rewriter.setInsertionPointToEnd(newBlock2); 121639f4ef81SValentin Clement continue; 121739f4ef81SValentin Clement } 121839f4ef81SValentin Clement assert(attr.isa<mlir::UnitAttr>()); 121939f4ef81SValentin Clement assert((t + 1 == conds) && "unit must be last"); 122039f4ef81SValentin Clement genBrOp(caseOp, dest, destOps, rewriter); 122139f4ef81SValentin Clement } 122239f4ef81SValentin Clement return success(); 122339f4ef81SValentin Clement } 122439f4ef81SValentin Clement }; 1225*c2acd453SAlexisPerry } // namespace 122639f4ef81SValentin Clement 12278c239909SValentin Clement template <typename OP> 1228*c2acd453SAlexisPerry static void selectMatchAndRewrite(fir::LLVMTypeConverter &lowering, OP select, 12298c239909SValentin Clement typename OP::Adaptor adaptor, 12308c239909SValentin Clement mlir::ConversionPatternRewriter &rewriter) { 12318c239909SValentin Clement unsigned conds = select.getNumConditions(); 12328c239909SValentin Clement auto cases = select.getCases().getValue(); 12338c239909SValentin Clement mlir::Value selector = adaptor.selector(); 12348c239909SValentin Clement auto loc = select.getLoc(); 12358c239909SValentin Clement assert(conds > 0 && "select must have cases"); 12368c239909SValentin Clement 12378c239909SValentin Clement llvm::SmallVector<mlir::Block *> destinations; 12388c239909SValentin Clement llvm::SmallVector<mlir::ValueRange> destinationsOperands; 12398c239909SValentin Clement mlir::Block *defaultDestination; 12408c239909SValentin Clement mlir::ValueRange defaultOperands; 12418c239909SValentin Clement llvm::SmallVector<int32_t> caseValues; 12428c239909SValentin Clement 12438c239909SValentin Clement for (unsigned t = 0; t != conds; ++t) { 12448c239909SValentin Clement mlir::Block *dest = select.getSuccessor(t); 12458c239909SValentin Clement auto destOps = select.getSuccessorOperands(adaptor.getOperands(), t); 12468c239909SValentin Clement const mlir::Attribute &attr = cases[t]; 12478c239909SValentin Clement if (auto intAttr = attr.template dyn_cast<mlir::IntegerAttr>()) { 12488c239909SValentin Clement destinations.push_back(dest); 12498c239909SValentin Clement destinationsOperands.push_back(destOps.hasValue() ? *destOps 12508c239909SValentin Clement : ValueRange()); 12518c239909SValentin Clement caseValues.push_back(intAttr.getInt()); 12528c239909SValentin Clement continue; 12538c239909SValentin Clement } 12548c239909SValentin Clement assert(attr.template dyn_cast_or_null<mlir::UnitAttr>()); 12558c239909SValentin Clement assert((t + 1 == conds) && "unit must be last"); 12568c239909SValentin Clement defaultDestination = dest; 12578c239909SValentin Clement defaultOperands = destOps.hasValue() ? *destOps : ValueRange(); 12588c239909SValentin Clement } 12598c239909SValentin Clement 12608c239909SValentin Clement // LLVM::SwitchOp takes a i32 type for the selector. 12618c239909SValentin Clement if (select.getSelector().getType() != rewriter.getI32Type()) 12628c239909SValentin Clement selector = 12638c239909SValentin Clement rewriter.create<LLVM::TruncOp>(loc, rewriter.getI32Type(), selector); 12648c239909SValentin Clement 12658c239909SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>( 12668c239909SValentin Clement select, selector, 12678c239909SValentin Clement /*defaultDestination=*/defaultDestination, 12688c239909SValentin Clement /*defaultOperands=*/defaultOperands, 12698c239909SValentin Clement /*caseValues=*/caseValues, 12708c239909SValentin Clement /*caseDestinations=*/destinations, 12718c239909SValentin Clement /*caseOperands=*/destinationsOperands, 12728c239909SValentin Clement /*branchWeights=*/ArrayRef<int32_t>()); 12738c239909SValentin Clement } 12748c239909SValentin Clement 1275*c2acd453SAlexisPerry namespace { 12768c239909SValentin Clement /// conversion of fir::SelectOp to an if-then-else ladder 12778c239909SValentin Clement struct SelectOpConversion : public FIROpConversion<fir::SelectOp> { 12788c239909SValentin Clement using FIROpConversion::FIROpConversion; 12798c239909SValentin Clement 12808c239909SValentin Clement mlir::LogicalResult 12818c239909SValentin Clement matchAndRewrite(fir::SelectOp op, OpAdaptor adaptor, 12828c239909SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 12838c239909SValentin Clement selectMatchAndRewrite<fir::SelectOp>(lowerTy(), op, adaptor, rewriter); 12848c239909SValentin Clement return success(); 12858c239909SValentin Clement } 12868c239909SValentin Clement }; 12878c239909SValentin Clement 1288e3349fa1SAndrzej Warzynski /// `fir.load` --> `llvm.load` 1289e3349fa1SAndrzej Warzynski struct LoadOpConversion : public FIROpConversion<fir::LoadOp> { 1290e3349fa1SAndrzej Warzynski using FIROpConversion::FIROpConversion; 1291e3349fa1SAndrzej Warzynski 1292e3349fa1SAndrzej Warzynski mlir::LogicalResult 1293e3349fa1SAndrzej Warzynski matchAndRewrite(fir::LoadOp load, OpAdaptor adaptor, 1294e3349fa1SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 1295e3349fa1SAndrzej Warzynski // fir.box is a special case because it is considered as an ssa values in 1296e3349fa1SAndrzej Warzynski // fir, but it is lowered as a pointer to a descriptor. So fir.ref<fir.box> 1297e3349fa1SAndrzej Warzynski // and fir.box end up being the same llvm types and loading a 1298e3349fa1SAndrzej Warzynski // fir.ref<fir.box> is actually a no op in LLVM. 1299e3349fa1SAndrzej Warzynski if (load.getType().isa<fir::BoxType>()) { 1300e3349fa1SAndrzej Warzynski rewriter.replaceOp(load, adaptor.getOperands()[0]); 1301e3349fa1SAndrzej Warzynski } else { 1302e3349fa1SAndrzej Warzynski mlir::Type ty = convertType(load.getType()); 1303e3349fa1SAndrzej Warzynski ArrayRef<NamedAttribute> at = load->getAttrs(); 1304e3349fa1SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::LoadOp>( 1305e3349fa1SAndrzej Warzynski load, ty, adaptor.getOperands(), at); 1306e3349fa1SAndrzej Warzynski } 1307e3349fa1SAndrzej Warzynski return success(); 1308e3349fa1SAndrzej Warzynski } 1309e3349fa1SAndrzej Warzynski }; 1310e3349fa1SAndrzej Warzynski 1311b8207db7SValentin Clement /// Lower `fir.no_reassoc` to LLVM IR dialect. 1312b8207db7SValentin Clement /// TODO: how do we want to enforce this in LLVM-IR? Can we manipulate the fast 1313b8207db7SValentin Clement /// math flags? 1314b8207db7SValentin Clement struct NoReassocOpConversion : public FIROpConversion<fir::NoReassocOp> { 1315b8207db7SValentin Clement using FIROpConversion::FIROpConversion; 1316b8207db7SValentin Clement 1317b8207db7SValentin Clement mlir::LogicalResult 1318b8207db7SValentin Clement matchAndRewrite(fir::NoReassocOp noreassoc, OpAdaptor adaptor, 1319b8207db7SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 1320b8207db7SValentin Clement rewriter.replaceOp(noreassoc, adaptor.getOperands()[0]); 1321b8207db7SValentin Clement return success(); 1322b8207db7SValentin Clement } 1323b8207db7SValentin Clement }; 1324b8207db7SValentin Clement 13252a299e4fSValentin Clement /// Lower `fir.select_type` to LLVM IR dialect. 13262a299e4fSValentin Clement struct SelectTypeOpConversion : public FIROpConversion<fir::SelectTypeOp> { 13272a299e4fSValentin Clement using FIROpConversion::FIROpConversion; 13282a299e4fSValentin Clement 13292a299e4fSValentin Clement mlir::LogicalResult 13302a299e4fSValentin Clement matchAndRewrite(fir::SelectTypeOp select, OpAdaptor adaptor, 13312a299e4fSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 13327ce8c6fcSKiran Chandramohan mlir::emitError(select.getLoc(), 13337ce8c6fcSKiran Chandramohan "fir.select_type should have already been converted"); 13347ce8c6fcSKiran Chandramohan return failure(); 13352a299e4fSValentin Clement } 13362a299e4fSValentin Clement }; 13372a299e4fSValentin Clement 13388c239909SValentin Clement /// conversion of fir::SelectRankOp to an if-then-else ladder 13398c239909SValentin Clement struct SelectRankOpConversion : public FIROpConversion<fir::SelectRankOp> { 13408c239909SValentin Clement using FIROpConversion::FIROpConversion; 13418c239909SValentin Clement 13428c239909SValentin Clement mlir::LogicalResult 13438c239909SValentin Clement matchAndRewrite(fir::SelectRankOp op, OpAdaptor adaptor, 13448c239909SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 13458c239909SValentin Clement selectMatchAndRewrite<fir::SelectRankOp>(lowerTy(), op, adaptor, rewriter); 13468c239909SValentin Clement return success(); 13478c239909SValentin Clement } 13488c239909SValentin Clement }; 13498c239909SValentin Clement 1350e3349fa1SAndrzej Warzynski /// `fir.store` --> `llvm.store` 1351e3349fa1SAndrzej Warzynski struct StoreOpConversion : public FIROpConversion<fir::StoreOp> { 1352e3349fa1SAndrzej Warzynski using FIROpConversion::FIROpConversion; 1353e3349fa1SAndrzej Warzynski 1354e3349fa1SAndrzej Warzynski mlir::LogicalResult 1355e3349fa1SAndrzej Warzynski matchAndRewrite(fir::StoreOp store, OpAdaptor adaptor, 1356e3349fa1SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 1357e3349fa1SAndrzej Warzynski if (store.value().getType().isa<fir::BoxType>()) { 1358e3349fa1SAndrzej Warzynski // fir.box value is actually in memory, load it first before storing it. 1359e3349fa1SAndrzej Warzynski mlir::Location loc = store.getLoc(); 1360e3349fa1SAndrzej Warzynski mlir::Type boxPtrTy = adaptor.getOperands()[0].getType(); 1361e3349fa1SAndrzej Warzynski auto val = rewriter.create<mlir::LLVM::LoadOp>( 1362e3349fa1SAndrzej Warzynski loc, boxPtrTy.cast<mlir::LLVM::LLVMPointerType>().getElementType(), 1363e3349fa1SAndrzej Warzynski adaptor.getOperands()[0]); 1364e3349fa1SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>( 1365e3349fa1SAndrzej Warzynski store, val, adaptor.getOperands()[1]); 1366e3349fa1SAndrzej Warzynski } else { 1367e3349fa1SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>( 1368e3349fa1SAndrzej Warzynski store, adaptor.getOperands()[0], adaptor.getOperands()[1]); 1369e3349fa1SAndrzej Warzynski } 1370e3349fa1SAndrzej Warzynski return success(); 1371e3349fa1SAndrzej Warzynski } 1372e3349fa1SAndrzej Warzynski }; 1373e3349fa1SAndrzej Warzynski 1374e3349fa1SAndrzej Warzynski /// convert to LLVM IR dialect `undef` 1375044d5b5dSValentin Clement struct UndefOpConversion : public FIROpConversion<fir::UndefOp> { 1376044d5b5dSValentin Clement using FIROpConversion::FIROpConversion; 1377044d5b5dSValentin Clement 1378044d5b5dSValentin Clement mlir::LogicalResult 1379044d5b5dSValentin Clement matchAndRewrite(fir::UndefOp undef, OpAdaptor, 1380044d5b5dSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 1381044d5b5dSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::UndefOp>( 1382044d5b5dSValentin Clement undef, convertType(undef.getType())); 1383044d5b5dSValentin Clement return success(); 1384044d5b5dSValentin Clement } 1385044d5b5dSValentin Clement }; 1386a7a61359SValentin Clement 1387e3349fa1SAndrzej Warzynski /// `fir.unreachable` --> `llvm.unreachable` 138832e08248SAndrzej Warzynski struct UnreachableOpConversion : public FIROpConversion<fir::UnreachableOp> { 138932e08248SAndrzej Warzynski using FIROpConversion::FIROpConversion; 139032e08248SAndrzej Warzynski 139132e08248SAndrzej Warzynski mlir::LogicalResult 139232e08248SAndrzej Warzynski matchAndRewrite(fir::UnreachableOp unreach, OpAdaptor adaptor, 139332e08248SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 139432e08248SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(unreach); 139532e08248SAndrzej Warzynski return success(); 139632e08248SAndrzej Warzynski } 139732e08248SAndrzej Warzynski }; 139832e08248SAndrzej Warzynski 1399a7a61359SValentin Clement struct ZeroOpConversion : public FIROpConversion<fir::ZeroOp> { 1400a7a61359SValentin Clement using FIROpConversion::FIROpConversion; 1401a7a61359SValentin Clement 1402a7a61359SValentin Clement mlir::LogicalResult 1403a7a61359SValentin Clement matchAndRewrite(fir::ZeroOp zero, OpAdaptor, 1404a7a61359SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 14057ce8c6fcSKiran Chandramohan mlir::Type ty = convertType(zero.getType()); 1406a7a61359SValentin Clement if (ty.isa<mlir::LLVM::LLVMPointerType>()) { 1407a7a61359SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(zero, ty); 1408a7a61359SValentin Clement } else if (ty.isa<mlir::IntegerType>()) { 1409a7a61359SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>( 1410a7a61359SValentin Clement zero, ty, mlir::IntegerAttr::get(zero.getType(), 0)); 1411a7a61359SValentin Clement } else if (mlir::LLVM::isCompatibleFloatingPointType(ty)) { 1412a7a61359SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>( 1413a7a61359SValentin Clement zero, ty, mlir::FloatAttr::get(zero.getType(), 0.0)); 1414a7a61359SValentin Clement } else { 1415a7a61359SValentin Clement // TODO: create ConstantAggregateZero for FIR aggregate/array types. 141652d813edSValentin Clement return rewriter.notifyMatchFailure( 141752d813edSValentin Clement zero, 1418a7a61359SValentin Clement "conversion of fir.zero with aggregate type not implemented yet"); 1419a7a61359SValentin Clement } 1420a7a61359SValentin Clement return success(); 1421a7a61359SValentin Clement } 1422a7a61359SValentin Clement }; 1423*c2acd453SAlexisPerry } // namespace 142432e08248SAndrzej Warzynski 1425af6ee580SValentin Clement /// Common base class for embox to descriptor conversion. 1426af6ee580SValentin Clement template <typename OP> 1427af6ee580SValentin Clement struct EmboxCommonConversion : public FIROpConversion<OP> { 1428af6ee580SValentin Clement using FIROpConversion<OP>::FIROpConversion; 1429af6ee580SValentin Clement 1430af6ee580SValentin Clement // Find the LLVMFuncOp in whose entry block the alloca should be inserted. 1431af6ee580SValentin Clement // The order to find the LLVMFuncOp is as follows: 1432af6ee580SValentin Clement // 1. The parent operation of the current block if it is a LLVMFuncOp. 1433af6ee580SValentin Clement // 2. The first ancestor that is a LLVMFuncOp. 1434af6ee580SValentin Clement mlir::LLVM::LLVMFuncOp 1435af6ee580SValentin Clement getFuncForAllocaInsert(mlir::ConversionPatternRewriter &rewriter) const { 1436af6ee580SValentin Clement mlir::Operation *parentOp = rewriter.getInsertionBlock()->getParentOp(); 1437af6ee580SValentin Clement return mlir::isa<mlir::LLVM::LLVMFuncOp>(parentOp) 1438af6ee580SValentin Clement ? mlir::cast<mlir::LLVM::LLVMFuncOp>(parentOp) 1439af6ee580SValentin Clement : parentOp->getParentOfType<mlir::LLVM::LLVMFuncOp>(); 1440af6ee580SValentin Clement } 1441af6ee580SValentin Clement 1442af6ee580SValentin Clement // Generate an alloca of size 1 and type \p toTy. 1443af6ee580SValentin Clement mlir::LLVM::AllocaOp 1444af6ee580SValentin Clement genAllocaWithType(mlir::Location loc, mlir::Type toTy, unsigned alignment, 1445af6ee580SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 1446af6ee580SValentin Clement auto thisPt = rewriter.saveInsertionPoint(); 1447af6ee580SValentin Clement mlir::LLVM::LLVMFuncOp func = getFuncForAllocaInsert(rewriter); 1448af6ee580SValentin Clement rewriter.setInsertionPointToStart(&func.front()); 1449af6ee580SValentin Clement auto size = this->genI32Constant(loc, rewriter, 1); 1450af6ee580SValentin Clement auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, toTy, size, alignment); 1451af6ee580SValentin Clement rewriter.restoreInsertionPoint(thisPt); 1452af6ee580SValentin Clement return al; 1453af6ee580SValentin Clement } 1454af6ee580SValentin Clement 1455af6ee580SValentin Clement static int getCFIAttr(fir::BoxType boxTy) { 1456af6ee580SValentin Clement auto eleTy = boxTy.getEleTy(); 1457af6ee580SValentin Clement if (eleTy.isa<fir::PointerType>()) 1458af6ee580SValentin Clement return CFI_attribute_pointer; 1459af6ee580SValentin Clement if (eleTy.isa<fir::HeapType>()) 1460af6ee580SValentin Clement return CFI_attribute_allocatable; 1461af6ee580SValentin Clement return CFI_attribute_other; 1462af6ee580SValentin Clement } 1463af6ee580SValentin Clement 1464af6ee580SValentin Clement static fir::RecordType unwrapIfDerived(fir::BoxType boxTy) { 1465af6ee580SValentin Clement return fir::unwrapSequenceType(fir::dyn_cast_ptrOrBoxEleTy(boxTy)) 1466af6ee580SValentin Clement .template dyn_cast<fir::RecordType>(); 1467af6ee580SValentin Clement } 1468af6ee580SValentin Clement static bool isDerivedTypeWithLenParams(fir::BoxType boxTy) { 1469af6ee580SValentin Clement auto recTy = unwrapIfDerived(boxTy); 1470af6ee580SValentin Clement return recTy && recTy.getNumLenParams() > 0; 1471af6ee580SValentin Clement } 1472af6ee580SValentin Clement static bool isDerivedType(fir::BoxType boxTy) { 1473af6ee580SValentin Clement return unwrapIfDerived(boxTy) != nullptr; 1474af6ee580SValentin Clement } 1475af6ee580SValentin Clement 1476af6ee580SValentin Clement // Get the element size and CFI type code of the boxed value. 1477af6ee580SValentin Clement std::tuple<mlir::Value, mlir::Value> getSizeAndTypeCode( 1478af6ee580SValentin Clement mlir::Location loc, mlir::ConversionPatternRewriter &rewriter, 1479af6ee580SValentin Clement mlir::Type boxEleTy, mlir::ValueRange lenParams = {}) const { 1480af6ee580SValentin Clement auto doInteger = 1481af6ee580SValentin Clement [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> { 1482af6ee580SValentin Clement int typeCode = fir::integerBitsToTypeCode(width); 1483af6ee580SValentin Clement return {this->genConstantOffset(loc, rewriter, width / 8), 1484af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, typeCode)}; 1485af6ee580SValentin Clement }; 1486af6ee580SValentin Clement auto doLogical = 1487af6ee580SValentin Clement [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> { 1488af6ee580SValentin Clement int typeCode = fir::logicalBitsToTypeCode(width); 1489af6ee580SValentin Clement return {this->genConstantOffset(loc, rewriter, width / 8), 1490af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, typeCode)}; 1491af6ee580SValentin Clement }; 1492af6ee580SValentin Clement auto doFloat = [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> { 1493af6ee580SValentin Clement int typeCode = fir::realBitsToTypeCode(width); 1494af6ee580SValentin Clement return {this->genConstantOffset(loc, rewriter, width / 8), 1495af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, typeCode)}; 1496af6ee580SValentin Clement }; 1497af6ee580SValentin Clement auto doComplex = 1498af6ee580SValentin Clement [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> { 1499af6ee580SValentin Clement auto typeCode = fir::complexBitsToTypeCode(width); 1500af6ee580SValentin Clement return {this->genConstantOffset(loc, rewriter, width / 8 * 2), 1501af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, typeCode)}; 1502af6ee580SValentin Clement }; 1503af6ee580SValentin Clement auto doCharacter = 1504af6ee580SValentin Clement [&](unsigned width, 1505af6ee580SValentin Clement mlir::Value len) -> std::tuple<mlir::Value, mlir::Value> { 1506af6ee580SValentin Clement auto typeCode = fir::characterBitsToTypeCode(width); 1507af6ee580SValentin Clement auto typeCodeVal = this->genConstantOffset(loc, rewriter, typeCode); 1508af6ee580SValentin Clement if (width == 8) 1509af6ee580SValentin Clement return {len, typeCodeVal}; 1510af6ee580SValentin Clement auto byteWidth = this->genConstantOffset(loc, rewriter, width / 8); 1511af6ee580SValentin Clement auto i64Ty = mlir::IntegerType::get(&this->lowerTy().getContext(), 64); 1512af6ee580SValentin Clement auto size = 1513af6ee580SValentin Clement rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, byteWidth, len); 1514af6ee580SValentin Clement return {size, typeCodeVal}; 1515af6ee580SValentin Clement }; 1516af6ee580SValentin Clement auto getKindMap = [&]() -> fir::KindMapping & { 1517af6ee580SValentin Clement return this->lowerTy().getKindMap(); 1518af6ee580SValentin Clement }; 1519af6ee580SValentin Clement // Pointer-like types. 1520af6ee580SValentin Clement if (auto eleTy = fir::dyn_cast_ptrEleTy(boxEleTy)) 1521af6ee580SValentin Clement boxEleTy = eleTy; 1522af6ee580SValentin Clement // Integer types. 1523af6ee580SValentin Clement if (fir::isa_integer(boxEleTy)) { 1524af6ee580SValentin Clement if (auto ty = boxEleTy.dyn_cast<mlir::IntegerType>()) 1525af6ee580SValentin Clement return doInteger(ty.getWidth()); 1526af6ee580SValentin Clement auto ty = boxEleTy.cast<fir::IntegerType>(); 1527af6ee580SValentin Clement return doInteger(getKindMap().getIntegerBitsize(ty.getFKind())); 1528af6ee580SValentin Clement } 1529af6ee580SValentin Clement // Floating point types. 1530af6ee580SValentin Clement if (fir::isa_real(boxEleTy)) { 1531af6ee580SValentin Clement if (auto ty = boxEleTy.dyn_cast<mlir::FloatType>()) 1532af6ee580SValentin Clement return doFloat(ty.getWidth()); 1533af6ee580SValentin Clement auto ty = boxEleTy.cast<fir::RealType>(); 1534af6ee580SValentin Clement return doFloat(getKindMap().getRealBitsize(ty.getFKind())); 1535af6ee580SValentin Clement } 1536af6ee580SValentin Clement // Complex types. 1537af6ee580SValentin Clement if (fir::isa_complex(boxEleTy)) { 1538af6ee580SValentin Clement if (auto ty = boxEleTy.dyn_cast<mlir::ComplexType>()) 1539af6ee580SValentin Clement return doComplex( 1540af6ee580SValentin Clement ty.getElementType().cast<mlir::FloatType>().getWidth()); 1541af6ee580SValentin Clement auto ty = boxEleTy.cast<fir::ComplexType>(); 1542af6ee580SValentin Clement return doComplex(getKindMap().getRealBitsize(ty.getFKind())); 1543af6ee580SValentin Clement } 1544af6ee580SValentin Clement // Character types. 1545af6ee580SValentin Clement if (auto ty = boxEleTy.dyn_cast<fir::CharacterType>()) { 1546af6ee580SValentin Clement auto charWidth = getKindMap().getCharacterBitsize(ty.getFKind()); 1547af6ee580SValentin Clement if (ty.getLen() != fir::CharacterType::unknownLen()) { 1548af6ee580SValentin Clement auto len = this->genConstantOffset(loc, rewriter, ty.getLen()); 1549af6ee580SValentin Clement return doCharacter(charWidth, len); 1550af6ee580SValentin Clement } 1551af6ee580SValentin Clement assert(!lenParams.empty()); 1552af6ee580SValentin Clement return doCharacter(charWidth, lenParams.back()); 1553af6ee580SValentin Clement } 1554af6ee580SValentin Clement // Logical type. 1555af6ee580SValentin Clement if (auto ty = boxEleTy.dyn_cast<fir::LogicalType>()) 1556af6ee580SValentin Clement return doLogical(getKindMap().getLogicalBitsize(ty.getFKind())); 1557af6ee580SValentin Clement // Array types. 1558af6ee580SValentin Clement if (auto seqTy = boxEleTy.dyn_cast<fir::SequenceType>()) 1559af6ee580SValentin Clement return getSizeAndTypeCode(loc, rewriter, seqTy.getEleTy(), lenParams); 1560af6ee580SValentin Clement // Derived-type types. 1561af6ee580SValentin Clement if (boxEleTy.isa<fir::RecordType>()) { 1562af6ee580SValentin Clement auto ptrTy = mlir::LLVM::LLVMPointerType::get( 1563af6ee580SValentin Clement this->lowerTy().convertType(boxEleTy)); 1564af6ee580SValentin Clement auto nullPtr = rewriter.create<mlir::LLVM::NullOp>(loc, ptrTy); 1565af6ee580SValentin Clement auto one = 1566af6ee580SValentin Clement genConstantIndex(loc, this->lowerTy().offsetType(), rewriter, 1); 1567af6ee580SValentin Clement auto gep = rewriter.create<mlir::LLVM::GEPOp>( 1568af6ee580SValentin Clement loc, ptrTy, mlir::ValueRange{nullPtr, one}); 1569af6ee580SValentin Clement auto eleSize = rewriter.create<mlir::LLVM::PtrToIntOp>( 1570af6ee580SValentin Clement loc, this->lowerTy().indexType(), gep); 1571af6ee580SValentin Clement return {eleSize, 1572af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, fir::derivedToTypeCode())}; 1573af6ee580SValentin Clement } 1574af6ee580SValentin Clement // Reference type. 1575af6ee580SValentin Clement if (fir::isa_ref_type(boxEleTy)) { 1576af6ee580SValentin Clement // FIXME: use the target pointer size rather than sizeof(void*) 1577af6ee580SValentin Clement return {this->genConstantOffset(loc, rewriter, sizeof(void *)), 1578af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, CFI_type_cptr)}; 1579af6ee580SValentin Clement } 1580af6ee580SValentin Clement fir::emitFatalError(loc, "unhandled type in fir.box code generation"); 1581af6ee580SValentin Clement } 1582af6ee580SValentin Clement 1583af6ee580SValentin Clement /// Basic pattern to write a field in the descriptor 1584af6ee580SValentin Clement mlir::Value insertField(mlir::ConversionPatternRewriter &rewriter, 1585af6ee580SValentin Clement mlir::Location loc, mlir::Value dest, 1586af6ee580SValentin Clement ArrayRef<unsigned> fldIndexes, mlir::Value value, 1587af6ee580SValentin Clement bool bitcast = false) const { 1588af6ee580SValentin Clement auto boxTy = dest.getType(); 1589af6ee580SValentin Clement auto fldTy = this->getBoxEleTy(boxTy, fldIndexes); 1590af6ee580SValentin Clement if (bitcast) 1591af6ee580SValentin Clement value = rewriter.create<mlir::LLVM::BitcastOp>(loc, fldTy, value); 1592af6ee580SValentin Clement else 1593af6ee580SValentin Clement value = this->integerCast(loc, rewriter, fldTy, value); 1594af6ee580SValentin Clement SmallVector<mlir::Attribute, 2> attrs; 1595af6ee580SValentin Clement for (auto i : fldIndexes) 1596af6ee580SValentin Clement attrs.push_back(rewriter.getI32IntegerAttr(i)); 1597af6ee580SValentin Clement auto indexesAttr = mlir::ArrayAttr::get(rewriter.getContext(), attrs); 1598af6ee580SValentin Clement return rewriter.create<mlir::LLVM::InsertValueOp>(loc, boxTy, dest, value, 1599af6ee580SValentin Clement indexesAttr); 1600af6ee580SValentin Clement } 1601af6ee580SValentin Clement 1602af6ee580SValentin Clement inline mlir::Value 1603af6ee580SValentin Clement insertBaseAddress(mlir::ConversionPatternRewriter &rewriter, 1604af6ee580SValentin Clement mlir::Location loc, mlir::Value dest, 1605af6ee580SValentin Clement mlir::Value base) const { 16061f551032SValentin Clement return insertField(rewriter, loc, dest, {kAddrPosInBox}, base, 16071f551032SValentin Clement /*bitCast=*/true); 16081f551032SValentin Clement } 16091f551032SValentin Clement 16101f551032SValentin Clement inline mlir::Value insertLowerBound(mlir::ConversionPatternRewriter &rewriter, 16111f551032SValentin Clement mlir::Location loc, mlir::Value dest, 16121f551032SValentin Clement unsigned dim, mlir::Value lb) const { 16131f551032SValentin Clement return insertField(rewriter, loc, dest, 16141f551032SValentin Clement {kDimsPosInBox, dim, kDimLowerBoundPos}, lb); 16151f551032SValentin Clement } 16161f551032SValentin Clement 16171f551032SValentin Clement inline mlir::Value insertExtent(mlir::ConversionPatternRewriter &rewriter, 16181f551032SValentin Clement mlir::Location loc, mlir::Value dest, 16191f551032SValentin Clement unsigned dim, mlir::Value extent) const { 16201f551032SValentin Clement return insertField(rewriter, loc, dest, {kDimsPosInBox, dim, kDimExtentPos}, 16211f551032SValentin Clement extent); 16221f551032SValentin Clement } 16231f551032SValentin Clement 16241f551032SValentin Clement inline mlir::Value insertStride(mlir::ConversionPatternRewriter &rewriter, 16251f551032SValentin Clement mlir::Location loc, mlir::Value dest, 16261f551032SValentin Clement unsigned dim, mlir::Value stride) const { 16271f551032SValentin Clement return insertField(rewriter, loc, dest, {kDimsPosInBox, dim, kDimStridePos}, 16281f551032SValentin Clement stride); 1629af6ee580SValentin Clement } 1630af6ee580SValentin Clement 1631af6ee580SValentin Clement /// Get the address of the type descriptor global variable that was created by 1632af6ee580SValentin Clement /// lowering for derived type \p recType. 1633af6ee580SValentin Clement template <typename BOX> 1634af6ee580SValentin Clement mlir::Value 1635af6ee580SValentin Clement getTypeDescriptor(BOX box, mlir::ConversionPatternRewriter &rewriter, 1636af6ee580SValentin Clement mlir::Location loc, fir::RecordType recType) const { 1637af6ee580SValentin Clement std::string name = recType.getLoweredName(); 1638af6ee580SValentin Clement auto module = box->template getParentOfType<mlir::ModuleOp>(); 1639af6ee580SValentin Clement if (auto global = module.template lookupSymbol<fir::GlobalOp>(name)) { 1640af6ee580SValentin Clement auto ty = mlir::LLVM::LLVMPointerType::get( 1641af6ee580SValentin Clement this->lowerTy().convertType(global.getType())); 1642af6ee580SValentin Clement return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty, 1643af6ee580SValentin Clement global.sym_name()); 1644af6ee580SValentin Clement } 1645af6ee580SValentin Clement if (auto global = 1646af6ee580SValentin Clement module.template lookupSymbol<mlir::LLVM::GlobalOp>(name)) { 1647af6ee580SValentin Clement // The global may have already been translated to LLVM. 1648af6ee580SValentin Clement auto ty = mlir::LLVM::LLVMPointerType::get(global.getType()); 1649af6ee580SValentin Clement return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty, 1650af6ee580SValentin Clement global.sym_name()); 1651af6ee580SValentin Clement } 1652af6ee580SValentin Clement // The global does not exist in the current translation unit, but may be 1653af6ee580SValentin Clement // defined elsewhere (e.g., type defined in a module). 1654af6ee580SValentin Clement // For now, create a extern_weak symbol (will become nullptr if unresolved) 1655af6ee580SValentin Clement // to support generating code without the front-end generated symbols. 1656af6ee580SValentin Clement // These could be made available_externally to require the symbols to be 1657af6ee580SValentin Clement // defined elsewhere and to cause link-time failure otherwise. 1658af6ee580SValentin Clement auto i8Ty = rewriter.getIntegerType(8); 1659af6ee580SValentin Clement mlir::OpBuilder modBuilder(module.getBodyRegion()); 1660af6ee580SValentin Clement // TODO: The symbol should be lowered to constant in lowering, they are read 1661af6ee580SValentin Clement // only. 1662af6ee580SValentin Clement modBuilder.create<mlir::LLVM::GlobalOp>(loc, i8Ty, /*isConstant=*/false, 1663af6ee580SValentin Clement mlir::LLVM::Linkage::ExternWeak, 1664af6ee580SValentin Clement name, mlir::Attribute{}); 1665af6ee580SValentin Clement auto ty = mlir::LLVM::LLVMPointerType::get(i8Ty); 1666af6ee580SValentin Clement return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty, name); 1667af6ee580SValentin Clement } 1668af6ee580SValentin Clement 1669af6ee580SValentin Clement template <typename BOX> 1670af6ee580SValentin Clement std::tuple<fir::BoxType, mlir::Value, mlir::Value> 1671af6ee580SValentin Clement consDescriptorPrefix(BOX box, mlir::ConversionPatternRewriter &rewriter, 1672af6ee580SValentin Clement unsigned rank, mlir::ValueRange lenParams) const { 1673af6ee580SValentin Clement auto loc = box.getLoc(); 1674af6ee580SValentin Clement auto boxTy = box.getType().template dyn_cast<fir::BoxType>(); 1675af6ee580SValentin Clement auto convTy = this->lowerTy().convertBoxType(boxTy, rank); 1676af6ee580SValentin Clement auto llvmBoxPtrTy = convTy.template cast<mlir::LLVM::LLVMPointerType>(); 1677af6ee580SValentin Clement auto llvmBoxTy = llvmBoxPtrTy.getElementType(); 1678af6ee580SValentin Clement mlir::Value descriptor = 1679af6ee580SValentin Clement rewriter.create<mlir::LLVM::UndefOp>(loc, llvmBoxTy); 1680af6ee580SValentin Clement 1681af6ee580SValentin Clement llvm::SmallVector<mlir::Value> typeparams = lenParams; 1682af6ee580SValentin Clement if constexpr (!std::is_same_v<BOX, fir::EmboxOp>) { 1683af6ee580SValentin Clement if (!box.substr().empty() && fir::hasDynamicSize(boxTy.getEleTy())) 1684af6ee580SValentin Clement typeparams.push_back(box.substr()[1]); 1685af6ee580SValentin Clement } 1686af6ee580SValentin Clement 1687af6ee580SValentin Clement // Write each of the fields with the appropriate values 1688af6ee580SValentin Clement auto [eleSize, cfiTy] = 1689af6ee580SValentin Clement getSizeAndTypeCode(loc, rewriter, boxTy.getEleTy(), typeparams); 1690af6ee580SValentin Clement descriptor = 1691af6ee580SValentin Clement insertField(rewriter, loc, descriptor, {kElemLenPosInBox}, eleSize); 1692af6ee580SValentin Clement descriptor = insertField(rewriter, loc, descriptor, {kVersionPosInBox}, 1693af6ee580SValentin Clement this->genI32Constant(loc, rewriter, CFI_VERSION)); 1694af6ee580SValentin Clement descriptor = insertField(rewriter, loc, descriptor, {kRankPosInBox}, 1695af6ee580SValentin Clement this->genI32Constant(loc, rewriter, rank)); 1696af6ee580SValentin Clement descriptor = insertField(rewriter, loc, descriptor, {kTypePosInBox}, cfiTy); 1697af6ee580SValentin Clement descriptor = 1698af6ee580SValentin Clement insertField(rewriter, loc, descriptor, {kAttributePosInBox}, 1699af6ee580SValentin Clement this->genI32Constant(loc, rewriter, getCFIAttr(boxTy))); 1700af6ee580SValentin Clement const bool hasAddendum = isDerivedType(boxTy); 1701af6ee580SValentin Clement descriptor = 1702af6ee580SValentin Clement insertField(rewriter, loc, descriptor, {kF18AddendumPosInBox}, 1703af6ee580SValentin Clement this->genI32Constant(loc, rewriter, hasAddendum ? 1 : 0)); 1704af6ee580SValentin Clement 1705af6ee580SValentin Clement if (hasAddendum) { 1706af6ee580SValentin Clement auto isArray = 1707af6ee580SValentin Clement fir::dyn_cast_ptrOrBoxEleTy(boxTy).template isa<fir::SequenceType>(); 1708af6ee580SValentin Clement unsigned typeDescFieldId = isArray ? kOptTypePtrPosInBox : kDimsPosInBox; 1709af6ee580SValentin Clement auto typeDesc = 1710af6ee580SValentin Clement getTypeDescriptor(box, rewriter, loc, unwrapIfDerived(boxTy)); 1711af6ee580SValentin Clement descriptor = 1712af6ee580SValentin Clement insertField(rewriter, loc, descriptor, {typeDescFieldId}, typeDesc, 1713af6ee580SValentin Clement /*bitCast=*/true); 1714af6ee580SValentin Clement } 1715af6ee580SValentin Clement 1716af6ee580SValentin Clement return {boxTy, descriptor, eleSize}; 1717af6ee580SValentin Clement } 1718af6ee580SValentin Clement 17191f551032SValentin Clement /// Compute the base address of a substring given the base address of a scalar 17201f551032SValentin Clement /// string and the zero based string lower bound. 17211f551032SValentin Clement mlir::Value shiftSubstringBase(mlir::ConversionPatternRewriter &rewriter, 17221f551032SValentin Clement mlir::Location loc, mlir::Value base, 17231f551032SValentin Clement mlir::Value lowerBound) const { 17241f551032SValentin Clement llvm::SmallVector<mlir::Value> gepOperands; 17251f551032SValentin Clement auto baseType = 17261f551032SValentin Clement base.getType().cast<mlir::LLVM::LLVMPointerType>().getElementType(); 17271f551032SValentin Clement if (baseType.isa<mlir::LLVM::LLVMArrayType>()) { 17281f551032SValentin Clement auto idxTy = this->lowerTy().indexType(); 17291f551032SValentin Clement mlir::Value zero = genConstantIndex(loc, idxTy, rewriter, 0); 17301f551032SValentin Clement gepOperands.push_back(zero); 17311f551032SValentin Clement } 17321f551032SValentin Clement gepOperands.push_back(lowerBound); 17331f551032SValentin Clement return this->genGEP(loc, base.getType(), rewriter, base, gepOperands); 17341f551032SValentin Clement } 17351f551032SValentin Clement 1736af6ee580SValentin Clement /// If the embox is not in a globalOp body, allocate storage for the box; 1737af6ee580SValentin Clement /// store the value inside and return the generated alloca. Return the input 1738af6ee580SValentin Clement /// value otherwise. 1739af6ee580SValentin Clement mlir::Value 1740af6ee580SValentin Clement placeInMemoryIfNotGlobalInit(mlir::ConversionPatternRewriter &rewriter, 1741af6ee580SValentin Clement mlir::Location loc, mlir::Value boxValue) const { 1742af6ee580SValentin Clement auto *thisBlock = rewriter.getInsertionBlock(); 1743af6ee580SValentin Clement if (thisBlock && mlir::isa<mlir::LLVM::GlobalOp>(thisBlock->getParentOp())) 1744af6ee580SValentin Clement return boxValue; 1745af6ee580SValentin Clement auto boxPtrTy = mlir::LLVM::LLVMPointerType::get(boxValue.getType()); 1746af6ee580SValentin Clement auto alloca = genAllocaWithType(loc, boxPtrTy, defaultAlign, rewriter); 1747af6ee580SValentin Clement rewriter.create<mlir::LLVM::StoreOp>(loc, boxValue, alloca); 1748af6ee580SValentin Clement return alloca; 1749af6ee580SValentin Clement } 1750af6ee580SValentin Clement }; 1751af6ee580SValentin Clement 17521f551032SValentin Clement /// Compute the extent of a triplet slice (lb:ub:step). 17531f551032SValentin Clement static mlir::Value 17541f551032SValentin Clement computeTripletExtent(mlir::ConversionPatternRewriter &rewriter, 17551f551032SValentin Clement mlir::Location loc, mlir::Value lb, mlir::Value ub, 17561f551032SValentin Clement mlir::Value step, mlir::Value zero, mlir::Type type) { 17571f551032SValentin Clement mlir::Value extent = rewriter.create<mlir::LLVM::SubOp>(loc, type, ub, lb); 17581f551032SValentin Clement extent = rewriter.create<mlir::LLVM::AddOp>(loc, type, extent, step); 17591f551032SValentin Clement extent = rewriter.create<mlir::LLVM::SDivOp>(loc, type, extent, step); 17601f551032SValentin Clement // If the resulting extent is negative (`ub-lb` and `step` have different 17611f551032SValentin Clement // signs), zero must be returned instead. 17621f551032SValentin Clement auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 17631f551032SValentin Clement loc, mlir::LLVM::ICmpPredicate::sgt, extent, zero); 17641f551032SValentin Clement return rewriter.create<mlir::LLVM::SelectOp>(loc, cmp, extent, zero); 17651f551032SValentin Clement } 17661f551032SValentin Clement 1767af6ee580SValentin Clement /// Create a generic box on a memory reference. This conversions lowers the 1768af6ee580SValentin Clement /// abstract box to the appropriate, initialized descriptor. 1769af6ee580SValentin Clement struct EmboxOpConversion : public EmboxCommonConversion<fir::EmboxOp> { 1770af6ee580SValentin Clement using EmboxCommonConversion::EmboxCommonConversion; 1771af6ee580SValentin Clement 1772af6ee580SValentin Clement mlir::LogicalResult 1773af6ee580SValentin Clement matchAndRewrite(fir::EmboxOp embox, OpAdaptor adaptor, 1774af6ee580SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 1775af6ee580SValentin Clement assert(!embox.getShape() && "There should be no dims on this embox op"); 1776af6ee580SValentin Clement auto [boxTy, dest, eleSize] = 1777af6ee580SValentin Clement consDescriptorPrefix(embox, rewriter, /*rank=*/0, 1778af6ee580SValentin Clement /*lenParams=*/adaptor.getOperands().drop_front(1)); 1779af6ee580SValentin Clement dest = insertBaseAddress(rewriter, embox.getLoc(), dest, 1780af6ee580SValentin Clement adaptor.getOperands()[0]); 17817ce8c6fcSKiran Chandramohan if (isDerivedTypeWithLenParams(boxTy)) { 17827ce8c6fcSKiran Chandramohan TODO(embox.getLoc(), 17837ce8c6fcSKiran Chandramohan "fir.embox codegen of derived with length parameters"); 17847ce8c6fcSKiran Chandramohan return failure(); 17857ce8c6fcSKiran Chandramohan } 1786af6ee580SValentin Clement auto result = placeInMemoryIfNotGlobalInit(rewriter, embox.getLoc(), dest); 1787af6ee580SValentin Clement rewriter.replaceOp(embox, result); 1788af6ee580SValentin Clement return success(); 1789af6ee580SValentin Clement } 1790af6ee580SValentin Clement }; 1791af6ee580SValentin Clement 1792cc505c0bSKiran Chandramohan /// Lower `fir.emboxproc` operation. Creates a procedure box. 1793cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers. 1794cc505c0bSKiran Chandramohan struct EmboxProcOpConversion : public FIROpConversion<fir::EmboxProcOp> { 1795cc505c0bSKiran Chandramohan using FIROpConversion::FIROpConversion; 1796cc505c0bSKiran Chandramohan 1797cc505c0bSKiran Chandramohan mlir::LogicalResult 1798cc505c0bSKiran Chandramohan matchAndRewrite(fir::EmboxProcOp emboxproc, OpAdaptor adaptor, 1799cc505c0bSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 18007ce8c6fcSKiran Chandramohan TODO(emboxproc.getLoc(), "fir.emboxproc codegen"); 18017ce8c6fcSKiran Chandramohan return failure(); 1802cc505c0bSKiran Chandramohan } 1803cc505c0bSKiran Chandramohan }; 1804cc505c0bSKiran Chandramohan 18051f551032SValentin Clement /// Create a generic box on a memory reference. 18061f551032SValentin Clement struct XEmboxOpConversion : public EmboxCommonConversion<fir::cg::XEmboxOp> { 18071f551032SValentin Clement using EmboxCommonConversion::EmboxCommonConversion; 18081f551032SValentin Clement 18091f551032SValentin Clement mlir::LogicalResult 18101f551032SValentin Clement matchAndRewrite(fir::cg::XEmboxOp xbox, OpAdaptor adaptor, 18111f551032SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 18121f551032SValentin Clement auto [boxTy, dest, eleSize] = consDescriptorPrefix( 18131f551032SValentin Clement xbox, rewriter, xbox.getOutRank(), 18141f551032SValentin Clement adaptor.getOperands().drop_front(xbox.lenParamOffset())); 18151f551032SValentin Clement // Generate the triples in the dims field of the descriptor 18161f551032SValentin Clement mlir::ValueRange operands = adaptor.getOperands(); 18171f551032SValentin Clement auto i64Ty = mlir::IntegerType::get(xbox.getContext(), 64); 18181f551032SValentin Clement mlir::Value base = operands[0]; 18191f551032SValentin Clement assert(!xbox.shape().empty() && "must have a shape"); 18201f551032SValentin Clement unsigned shapeOffset = xbox.shapeOffset(); 18211f551032SValentin Clement bool hasShift = !xbox.shift().empty(); 18221f551032SValentin Clement unsigned shiftOffset = xbox.shiftOffset(); 18231f551032SValentin Clement bool hasSlice = !xbox.slice().empty(); 18241f551032SValentin Clement unsigned sliceOffset = xbox.sliceOffset(); 18251f551032SValentin Clement mlir::Location loc = xbox.getLoc(); 18261f551032SValentin Clement mlir::Value zero = genConstantIndex(loc, i64Ty, rewriter, 0); 18271f551032SValentin Clement mlir::Value one = genConstantIndex(loc, i64Ty, rewriter, 1); 18281f551032SValentin Clement mlir::Value prevDim = integerCast(loc, rewriter, i64Ty, eleSize); 18291f551032SValentin Clement mlir::Value prevPtrOff = one; 18301f551032SValentin Clement mlir::Type eleTy = boxTy.getEleTy(); 18311f551032SValentin Clement const unsigned rank = xbox.getRank(); 18321f551032SValentin Clement llvm::SmallVector<mlir::Value> gepArgs; 18331f551032SValentin Clement unsigned constRows = 0; 18341f551032SValentin Clement mlir::Value ptrOffset = zero; 18351f551032SValentin Clement if (auto memEleTy = fir::dyn_cast_ptrEleTy(xbox.memref().getType())) 18361f551032SValentin Clement if (auto seqTy = memEleTy.dyn_cast<fir::SequenceType>()) { 18371f551032SValentin Clement mlir::Type seqEleTy = seqTy.getEleTy(); 18381f551032SValentin Clement // Adjust the element scaling factor if the element is a dependent type. 18391f551032SValentin Clement if (fir::hasDynamicSize(seqEleTy)) { 18401f551032SValentin Clement if (fir::isa_char(seqEleTy)) { 18411f551032SValentin Clement assert(xbox.lenParams().size() == 1); 18421f551032SValentin Clement prevPtrOff = integerCast(loc, rewriter, i64Ty, 18431f551032SValentin Clement operands[xbox.lenParamOffset()]); 18441f551032SValentin Clement } else if (seqEleTy.isa<fir::RecordType>()) { 18451f551032SValentin Clement TODO(loc, "generate call to calculate size of PDT"); 18461f551032SValentin Clement } else { 18471f551032SValentin Clement return rewriter.notifyMatchFailure(xbox, "unexpected dynamic type"); 18481f551032SValentin Clement } 18491f551032SValentin Clement } else { 18501f551032SValentin Clement constRows = seqTy.getConstantRows(); 18511f551032SValentin Clement } 18521f551032SValentin Clement } 18531f551032SValentin Clement 18541f551032SValentin Clement bool hasSubcomp = !xbox.subcomponent().empty(); 18551f551032SValentin Clement mlir::Value stepExpr; 18561f551032SValentin Clement if (hasSubcomp) { 18571f551032SValentin Clement // We have a subcomponent. The step value needs to be the number of 18581f551032SValentin Clement // bytes per element (which is a derived type). 18591f551032SValentin Clement mlir::Type ty0 = base.getType(); 18601f551032SValentin Clement [[maybe_unused]] auto ptrTy = ty0.dyn_cast<mlir::LLVM::LLVMPointerType>(); 18611f551032SValentin Clement assert(ptrTy && "expected pointer type"); 18621f551032SValentin Clement mlir::Type memEleTy = fir::dyn_cast_ptrEleTy(xbox.memref().getType()); 18631f551032SValentin Clement assert(memEleTy && "expected fir pointer type"); 18641f551032SValentin Clement auto seqTy = memEleTy.dyn_cast<fir::SequenceType>(); 18651f551032SValentin Clement assert(seqTy && "expected sequence type"); 18661f551032SValentin Clement mlir::Type seqEleTy = seqTy.getEleTy(); 18671f551032SValentin Clement auto eleTy = mlir::LLVM::LLVMPointerType::get(convertType(seqEleTy)); 18681f551032SValentin Clement stepExpr = computeDerivedTypeSize(loc, eleTy, i64Ty, rewriter); 18691f551032SValentin Clement } 18701f551032SValentin Clement 18711f551032SValentin Clement // Process the array subspace arguments (shape, shift, etc.), if any, 18721f551032SValentin Clement // translating everything to values in the descriptor wherever the entity 18731f551032SValentin Clement // has a dynamic array dimension. 18741f551032SValentin Clement for (unsigned di = 0, descIdx = 0; di < rank; ++di) { 18751f551032SValentin Clement mlir::Value extent = operands[shapeOffset]; 18761f551032SValentin Clement mlir::Value outerExtent = extent; 18771f551032SValentin Clement bool skipNext = false; 18781f551032SValentin Clement if (hasSlice) { 18791f551032SValentin Clement mlir::Value off = operands[sliceOffset]; 18801f551032SValentin Clement mlir::Value adj = one; 18811f551032SValentin Clement if (hasShift) 18821f551032SValentin Clement adj = operands[shiftOffset]; 18831f551032SValentin Clement auto ao = rewriter.create<mlir::LLVM::SubOp>(loc, i64Ty, off, adj); 18841f551032SValentin Clement if (constRows > 0) { 18851f551032SValentin Clement gepArgs.push_back(ao); 18861f551032SValentin Clement --constRows; 18871f551032SValentin Clement } else { 18881f551032SValentin Clement auto dimOff = 18891f551032SValentin Clement rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, ao, prevPtrOff); 18901f551032SValentin Clement ptrOffset = 18911f551032SValentin Clement rewriter.create<mlir::LLVM::AddOp>(loc, i64Ty, dimOff, ptrOffset); 18921f551032SValentin Clement } 18931f551032SValentin Clement if (mlir::isa_and_nonnull<fir::UndefOp>( 18941f551032SValentin Clement xbox.slice()[3 * di + 1].getDefiningOp())) { 18951f551032SValentin Clement // This dimension contains a scalar expression in the array slice op. 18961f551032SValentin Clement // The dimension is loop invariant, will be dropped, and will not 18971f551032SValentin Clement // appear in the descriptor. 18981f551032SValentin Clement skipNext = true; 18991f551032SValentin Clement } 19001f551032SValentin Clement } 19011f551032SValentin Clement if (!skipNext) { 19021f551032SValentin Clement // store lower bound (normally 0) 19031f551032SValentin Clement mlir::Value lb = zero; 19041f551032SValentin Clement if (eleTy.isa<fir::PointerType>() || eleTy.isa<fir::HeapType>()) { 19051f551032SValentin Clement lb = one; 19061f551032SValentin Clement if (hasShift) 19071f551032SValentin Clement lb = operands[shiftOffset]; 19081f551032SValentin Clement } 19091f551032SValentin Clement dest = insertLowerBound(rewriter, loc, dest, descIdx, lb); 19101f551032SValentin Clement 19111f551032SValentin Clement // store extent 19121f551032SValentin Clement if (hasSlice) 19131f551032SValentin Clement extent = computeTripletExtent(rewriter, loc, operands[sliceOffset], 19141f551032SValentin Clement operands[sliceOffset + 1], 19151f551032SValentin Clement operands[sliceOffset + 2], zero, i64Ty); 19161f551032SValentin Clement dest = insertExtent(rewriter, loc, dest, descIdx, extent); 19171f551032SValentin Clement 19181f551032SValentin Clement // store step (scaled by shaped extent) 19191f551032SValentin Clement 19201f551032SValentin Clement mlir::Value step = hasSubcomp ? stepExpr : prevDim; 19211f551032SValentin Clement if (hasSlice) 19221f551032SValentin Clement step = rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, step, 19231f551032SValentin Clement operands[sliceOffset + 2]); 19241f551032SValentin Clement dest = insertStride(rewriter, loc, dest, descIdx, step); 19251f551032SValentin Clement ++descIdx; 19261f551032SValentin Clement } 19271f551032SValentin Clement 19281f551032SValentin Clement // compute the stride and offset for the next natural dimension 19291f551032SValentin Clement prevDim = 19301f551032SValentin Clement rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, prevDim, outerExtent); 19311f551032SValentin Clement if (constRows == 0) 19321f551032SValentin Clement prevPtrOff = rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, prevPtrOff, 19331f551032SValentin Clement outerExtent); 19341f551032SValentin Clement 19351f551032SValentin Clement // increment iterators 19361f551032SValentin Clement ++shapeOffset; 19371f551032SValentin Clement if (hasShift) 19381f551032SValentin Clement ++shiftOffset; 19391f551032SValentin Clement if (hasSlice) 19401f551032SValentin Clement sliceOffset += 3; 19411f551032SValentin Clement } 19421f551032SValentin Clement if (hasSlice || hasSubcomp || !xbox.substr().empty()) { 19431f551032SValentin Clement llvm::SmallVector<mlir::Value> args = {base, ptrOffset}; 19441f551032SValentin Clement args.append(gepArgs.rbegin(), gepArgs.rend()); 19451f551032SValentin Clement if (hasSubcomp) { 19461f551032SValentin Clement // For each field in the path add the offset to base via the args list. 19471f551032SValentin Clement // In the most general case, some offsets must be computed since 19481f551032SValentin Clement // they are not be known until runtime. 19491f551032SValentin Clement if (fir::hasDynamicSize(fir::unwrapSequenceType( 19501f551032SValentin Clement fir::unwrapPassByRefType(xbox.memref().getType())))) 19511f551032SValentin Clement TODO(loc, "fir.embox codegen dynamic size component in derived type"); 19521f551032SValentin Clement args.append(operands.begin() + xbox.subcomponentOffset(), 19531f551032SValentin Clement operands.begin() + xbox.subcomponentOffset() + 19541f551032SValentin Clement xbox.subcomponent().size()); 19551f551032SValentin Clement } 19561f551032SValentin Clement base = rewriter.create<mlir::LLVM::GEPOp>(loc, base.getType(), args); 19571f551032SValentin Clement if (!xbox.substr().empty()) 19581f551032SValentin Clement base = shiftSubstringBase(rewriter, loc, base, 19591f551032SValentin Clement operands[xbox.substrOffset()]); 19601f551032SValentin Clement } 19611f551032SValentin Clement dest = insertBaseAddress(rewriter, loc, dest, base); 19621f551032SValentin Clement if (isDerivedTypeWithLenParams(boxTy)) 19631f551032SValentin Clement TODO(loc, "fir.embox codegen of derived with length parameters"); 19641f551032SValentin Clement 19651f551032SValentin Clement mlir::Value result = placeInMemoryIfNotGlobalInit(rewriter, loc, dest); 19661f551032SValentin Clement rewriter.replaceOp(xbox, result); 19671f551032SValentin Clement return success(); 19681f551032SValentin Clement } 19691f551032SValentin Clement }; 19701f551032SValentin Clement 1971fa517555SKiran Chandramohan /// Create a new box given a box reference. 1972fa517555SKiran Chandramohan struct XReboxOpConversion : public EmboxCommonConversion<fir::cg::XReboxOp> { 1973fa517555SKiran Chandramohan using EmboxCommonConversion::EmboxCommonConversion; 1974fa517555SKiran Chandramohan 1975fa517555SKiran Chandramohan mlir::LogicalResult 1976fa517555SKiran Chandramohan matchAndRewrite(fir::cg::XReboxOp rebox, OpAdaptor adaptor, 1977fa517555SKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 1978fa517555SKiran Chandramohan mlir::Location loc = rebox.getLoc(); 1979fa517555SKiran Chandramohan mlir::Type idxTy = lowerTy().indexType(); 1980fa517555SKiran Chandramohan mlir::Value loweredBox = adaptor.getOperands()[0]; 1981fa517555SKiran Chandramohan mlir::ValueRange operands = adaptor.getOperands(); 1982fa517555SKiran Chandramohan 1983fa517555SKiran Chandramohan // Create new descriptor and fill its non-shape related data. 1984fa517555SKiran Chandramohan llvm::SmallVector<mlir::Value, 2> lenParams; 1985fa517555SKiran Chandramohan mlir::Type inputEleTy = getInputEleTy(rebox); 1986fa517555SKiran Chandramohan if (auto charTy = inputEleTy.dyn_cast<fir::CharacterType>()) { 1987fa517555SKiran Chandramohan mlir::Value len = 1988fa517555SKiran Chandramohan loadElementSizeFromBox(loc, idxTy, loweredBox, rewriter); 1989fa517555SKiran Chandramohan if (charTy.getFKind() != 1) { 1990fa517555SKiran Chandramohan mlir::Value width = 1991fa517555SKiran Chandramohan genConstantIndex(loc, idxTy, rewriter, charTy.getFKind()); 1992fa517555SKiran Chandramohan len = rewriter.create<mlir::LLVM::SDivOp>(loc, idxTy, len, width); 1993fa517555SKiran Chandramohan } 1994fa517555SKiran Chandramohan lenParams.emplace_back(len); 1995fa517555SKiran Chandramohan } else if (auto recTy = inputEleTy.dyn_cast<fir::RecordType>()) { 1996fa517555SKiran Chandramohan if (recTy.getNumLenParams() != 0) 1997fa517555SKiran Chandramohan TODO(loc, "reboxing descriptor of derived type with length parameters"); 1998fa517555SKiran Chandramohan } 1999fa517555SKiran Chandramohan auto [boxTy, dest, eleSize] = 2000fa517555SKiran Chandramohan consDescriptorPrefix(rebox, rewriter, rebox.getOutRank(), lenParams); 2001fa517555SKiran Chandramohan 2002fa517555SKiran Chandramohan // Read input extents, strides, and base address 2003fa517555SKiran Chandramohan llvm::SmallVector<mlir::Value> inputExtents; 2004fa517555SKiran Chandramohan llvm::SmallVector<mlir::Value> inputStrides; 2005fa517555SKiran Chandramohan const unsigned inputRank = rebox.getRank(); 2006fa517555SKiran Chandramohan for (unsigned i = 0; i < inputRank; ++i) { 2007fa517555SKiran Chandramohan mlir::Value dim = genConstantIndex(loc, idxTy, rewriter, i); 2008fa517555SKiran Chandramohan SmallVector<mlir::Value, 3> dimInfo = 2009fa517555SKiran Chandramohan getDimsFromBox(loc, {idxTy, idxTy, idxTy}, loweredBox, dim, rewriter); 2010fa517555SKiran Chandramohan inputExtents.emplace_back(dimInfo[1]); 2011fa517555SKiran Chandramohan inputStrides.emplace_back(dimInfo[2]); 2012fa517555SKiran Chandramohan } 2013fa517555SKiran Chandramohan 2014fa517555SKiran Chandramohan mlir::Type baseTy = getBaseAddrTypeFromBox(loweredBox.getType()); 2015fa517555SKiran Chandramohan mlir::Value baseAddr = 2016fa517555SKiran Chandramohan loadBaseAddrFromBox(loc, baseTy, loweredBox, rewriter); 2017fa517555SKiran Chandramohan 2018fa517555SKiran Chandramohan if (!rebox.slice().empty() || !rebox.subcomponent().empty()) 2019fa517555SKiran Chandramohan return sliceBox(rebox, dest, baseAddr, inputExtents, inputStrides, 2020fa517555SKiran Chandramohan operands, rewriter); 2021fa517555SKiran Chandramohan return reshapeBox(rebox, dest, baseAddr, inputExtents, inputStrides, 2022fa517555SKiran Chandramohan operands, rewriter); 2023fa517555SKiran Chandramohan } 2024fa517555SKiran Chandramohan 2025fa517555SKiran Chandramohan private: 2026fa517555SKiran Chandramohan /// Write resulting shape and base address in descriptor, and replace rebox 2027fa517555SKiran Chandramohan /// op. 2028fa517555SKiran Chandramohan mlir::LogicalResult 2029fa517555SKiran Chandramohan finalizeRebox(fir::cg::XReboxOp rebox, mlir::Value dest, mlir::Value base, 2030fa517555SKiran Chandramohan mlir::ValueRange lbounds, mlir::ValueRange extents, 2031fa517555SKiran Chandramohan mlir::ValueRange strides, 2032fa517555SKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const { 2033fa517555SKiran Chandramohan mlir::Location loc = rebox.getLoc(); 2034fa517555SKiran Chandramohan mlir::Value one = genConstantIndex(loc, lowerTy().indexType(), rewriter, 1); 2035fa517555SKiran Chandramohan for (auto iter : llvm::enumerate(llvm::zip(extents, strides))) { 2036fa517555SKiran Chandramohan unsigned dim = iter.index(); 2037fa517555SKiran Chandramohan mlir::Value lb = lbounds.empty() ? one : lbounds[dim]; 2038fa517555SKiran Chandramohan dest = insertLowerBound(rewriter, loc, dest, dim, lb); 2039fa517555SKiran Chandramohan dest = insertExtent(rewriter, loc, dest, dim, std::get<0>(iter.value())); 2040fa517555SKiran Chandramohan dest = insertStride(rewriter, loc, dest, dim, std::get<1>(iter.value())); 2041fa517555SKiran Chandramohan } 2042fa517555SKiran Chandramohan dest = insertBaseAddress(rewriter, loc, dest, base); 2043fa517555SKiran Chandramohan mlir::Value result = 2044fa517555SKiran Chandramohan placeInMemoryIfNotGlobalInit(rewriter, rebox.getLoc(), dest); 2045fa517555SKiran Chandramohan rewriter.replaceOp(rebox, result); 2046fa517555SKiran Chandramohan return success(); 2047fa517555SKiran Chandramohan } 2048fa517555SKiran Chandramohan 2049fa517555SKiran Chandramohan // Apply slice given the base address, extents and strides of the input box. 2050fa517555SKiran Chandramohan mlir::LogicalResult 2051fa517555SKiran Chandramohan sliceBox(fir::cg::XReboxOp rebox, mlir::Value dest, mlir::Value base, 2052fa517555SKiran Chandramohan mlir::ValueRange inputExtents, mlir::ValueRange inputStrides, 2053fa517555SKiran Chandramohan mlir::ValueRange operands, 2054fa517555SKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const { 2055fa517555SKiran Chandramohan mlir::Location loc = rebox.getLoc(); 2056fa517555SKiran Chandramohan mlir::Type voidPtrTy = ::getVoidPtrType(rebox.getContext()); 2057fa517555SKiran Chandramohan mlir::Type idxTy = lowerTy().indexType(); 2058fa517555SKiran Chandramohan mlir::Value zero = genConstantIndex(loc, idxTy, rewriter, 0); 2059fa517555SKiran Chandramohan // Apply subcomponent and substring shift on base address. 2060fa517555SKiran Chandramohan if (!rebox.subcomponent().empty() || !rebox.substr().empty()) { 2061fa517555SKiran Chandramohan // Cast to inputEleTy* so that a GEP can be used. 2062fa517555SKiran Chandramohan mlir::Type inputEleTy = getInputEleTy(rebox); 2063fa517555SKiran Chandramohan auto llvmElePtrTy = 2064fa517555SKiran Chandramohan mlir::LLVM::LLVMPointerType::get(convertType(inputEleTy)); 2065fa517555SKiran Chandramohan base = rewriter.create<mlir::LLVM::BitcastOp>(loc, llvmElePtrTy, base); 2066fa517555SKiran Chandramohan 2067fa517555SKiran Chandramohan if (!rebox.subcomponent().empty()) { 2068fa517555SKiran Chandramohan llvm::SmallVector<mlir::Value> gepOperands = {zero}; 2069fa517555SKiran Chandramohan for (unsigned i = 0; i < rebox.subcomponent().size(); ++i) 2070fa517555SKiran Chandramohan gepOperands.push_back(operands[rebox.subcomponentOffset() + i]); 2071fa517555SKiran Chandramohan base = genGEP(loc, llvmElePtrTy, rewriter, base, gepOperands); 2072fa517555SKiran Chandramohan } 2073fa517555SKiran Chandramohan if (!rebox.substr().empty()) 2074fa517555SKiran Chandramohan base = shiftSubstringBase(rewriter, loc, base, 2075fa517555SKiran Chandramohan operands[rebox.substrOffset()]); 2076fa517555SKiran Chandramohan } 2077fa517555SKiran Chandramohan 2078fa517555SKiran Chandramohan if (rebox.slice().empty()) 2079fa517555SKiran Chandramohan // The array section is of the form array[%component][substring], keep 2080fa517555SKiran Chandramohan // the input array extents and strides. 2081fa517555SKiran Chandramohan return finalizeRebox(rebox, dest, base, /*lbounds*/ llvm::None, 2082fa517555SKiran Chandramohan inputExtents, inputStrides, rewriter); 2083fa517555SKiran Chandramohan 2084fa517555SKiran Chandramohan // Strides from the fir.box are in bytes. 2085fa517555SKiran Chandramohan base = rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, base); 2086fa517555SKiran Chandramohan 2087fa517555SKiran Chandramohan // The slice is of the form array(i:j:k)[%component]. Compute new extents 2088fa517555SKiran Chandramohan // and strides. 2089fa517555SKiran Chandramohan llvm::SmallVector<mlir::Value> slicedExtents; 2090fa517555SKiran Chandramohan llvm::SmallVector<mlir::Value> slicedStrides; 2091fa517555SKiran Chandramohan mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1); 2092fa517555SKiran Chandramohan const bool sliceHasOrigins = !rebox.shift().empty(); 2093fa517555SKiran Chandramohan unsigned sliceOps = rebox.sliceOffset(); 2094fa517555SKiran Chandramohan unsigned shiftOps = rebox.shiftOffset(); 2095fa517555SKiran Chandramohan auto strideOps = inputStrides.begin(); 2096fa517555SKiran Chandramohan const unsigned inputRank = inputStrides.size(); 2097fa517555SKiran Chandramohan for (unsigned i = 0; i < inputRank; 2098fa517555SKiran Chandramohan ++i, ++strideOps, ++shiftOps, sliceOps += 3) { 2099fa517555SKiran Chandramohan mlir::Value sliceLb = 2100fa517555SKiran Chandramohan integerCast(loc, rewriter, idxTy, operands[sliceOps]); 2101fa517555SKiran Chandramohan mlir::Value inputStride = *strideOps; // already idxTy 2102fa517555SKiran Chandramohan // Apply origin shift: base += (lb-shift)*input_stride 2103fa517555SKiran Chandramohan mlir::Value sliceOrigin = 2104fa517555SKiran Chandramohan sliceHasOrigins 2105fa517555SKiran Chandramohan ? integerCast(loc, rewriter, idxTy, operands[shiftOps]) 2106fa517555SKiran Chandramohan : one; 2107fa517555SKiran Chandramohan mlir::Value diff = 2108fa517555SKiran Chandramohan rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, sliceLb, sliceOrigin); 2109fa517555SKiran Chandramohan mlir::Value offset = 2110fa517555SKiran Chandramohan rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, inputStride); 2111fa517555SKiran Chandramohan base = genGEP(loc, voidPtrTy, rewriter, base, offset); 2112fa517555SKiran Chandramohan // Apply upper bound and step if this is a triplet. Otherwise, the 2113fa517555SKiran Chandramohan // dimension is dropped and no extents/strides are computed. 2114fa517555SKiran Chandramohan mlir::Value upper = operands[sliceOps + 1]; 2115fa517555SKiran Chandramohan const bool isTripletSlice = 2116fa517555SKiran Chandramohan !mlir::isa_and_nonnull<mlir::LLVM::UndefOp>(upper.getDefiningOp()); 2117fa517555SKiran Chandramohan if (isTripletSlice) { 2118fa517555SKiran Chandramohan mlir::Value step = 2119fa517555SKiran Chandramohan integerCast(loc, rewriter, idxTy, operands[sliceOps + 2]); 2120fa517555SKiran Chandramohan // extent = ub-lb+step/step 2121fa517555SKiran Chandramohan mlir::Value sliceUb = integerCast(loc, rewriter, idxTy, upper); 2122fa517555SKiran Chandramohan mlir::Value extent = computeTripletExtent(rewriter, loc, sliceLb, 2123fa517555SKiran Chandramohan sliceUb, step, zero, idxTy); 2124fa517555SKiran Chandramohan slicedExtents.emplace_back(extent); 2125fa517555SKiran Chandramohan // stride = step*input_stride 2126fa517555SKiran Chandramohan mlir::Value stride = 2127fa517555SKiran Chandramohan rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, step, inputStride); 2128fa517555SKiran Chandramohan slicedStrides.emplace_back(stride); 2129fa517555SKiran Chandramohan } 2130fa517555SKiran Chandramohan } 2131fa517555SKiran Chandramohan return finalizeRebox(rebox, dest, base, /*lbounds*/ llvm::None, 2132fa517555SKiran Chandramohan slicedExtents, slicedStrides, rewriter); 2133fa517555SKiran Chandramohan } 2134fa517555SKiran Chandramohan 2135fa517555SKiran Chandramohan /// Apply a new shape to the data described by a box given the base address, 2136fa517555SKiran Chandramohan /// extents and strides of the box. 2137fa517555SKiran Chandramohan mlir::LogicalResult 2138fa517555SKiran Chandramohan reshapeBox(fir::cg::XReboxOp rebox, mlir::Value dest, mlir::Value base, 2139fa517555SKiran Chandramohan mlir::ValueRange inputExtents, mlir::ValueRange inputStrides, 2140fa517555SKiran Chandramohan mlir::ValueRange operands, 2141fa517555SKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const { 2142fa517555SKiran Chandramohan mlir::ValueRange reboxShifts{operands.begin() + rebox.shiftOffset(), 2143fa517555SKiran Chandramohan operands.begin() + rebox.shiftOffset() + 2144fa517555SKiran Chandramohan rebox.shift().size()}; 2145fa517555SKiran Chandramohan if (rebox.shape().empty()) { 2146fa517555SKiran Chandramohan // Only setting new lower bounds. 2147fa517555SKiran Chandramohan return finalizeRebox(rebox, dest, base, reboxShifts, inputExtents, 2148fa517555SKiran Chandramohan inputStrides, rewriter); 2149fa517555SKiran Chandramohan } 2150fa517555SKiran Chandramohan 2151fa517555SKiran Chandramohan mlir::Location loc = rebox.getLoc(); 2152fa517555SKiran Chandramohan // Strides from the fir.box are in bytes. 2153fa517555SKiran Chandramohan mlir::Type voidPtrTy = ::getVoidPtrType(rebox.getContext()); 2154fa517555SKiran Chandramohan base = rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, base); 2155fa517555SKiran Chandramohan 2156fa517555SKiran Chandramohan llvm::SmallVector<mlir::Value> newStrides; 2157fa517555SKiran Chandramohan llvm::SmallVector<mlir::Value> newExtents; 2158fa517555SKiran Chandramohan mlir::Type idxTy = lowerTy().indexType(); 2159fa517555SKiran Chandramohan // First stride from input box is kept. The rest is assumed contiguous 2160fa517555SKiran Chandramohan // (it is not possible to reshape otherwise). If the input is scalar, 2161fa517555SKiran Chandramohan // which may be OK if all new extents are ones, the stride does not 2162fa517555SKiran Chandramohan // matter, use one. 2163fa517555SKiran Chandramohan mlir::Value stride = inputStrides.empty() 2164fa517555SKiran Chandramohan ? genConstantIndex(loc, idxTy, rewriter, 1) 2165fa517555SKiran Chandramohan : inputStrides[0]; 2166fa517555SKiran Chandramohan for (unsigned i = 0; i < rebox.shape().size(); ++i) { 2167fa517555SKiran Chandramohan mlir::Value rawExtent = operands[rebox.shapeOffset() + i]; 2168fa517555SKiran Chandramohan mlir::Value extent = integerCast(loc, rewriter, idxTy, rawExtent); 2169fa517555SKiran Chandramohan newExtents.emplace_back(extent); 2170fa517555SKiran Chandramohan newStrides.emplace_back(stride); 2171fa517555SKiran Chandramohan // nextStride = extent * stride; 2172fa517555SKiran Chandramohan stride = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, extent, stride); 2173fa517555SKiran Chandramohan } 2174fa517555SKiran Chandramohan return finalizeRebox(rebox, dest, base, reboxShifts, newExtents, newStrides, 2175fa517555SKiran Chandramohan rewriter); 2176fa517555SKiran Chandramohan } 2177fa517555SKiran Chandramohan 2178fa517555SKiran Chandramohan /// Return scalar element type of the input box. 2179fa517555SKiran Chandramohan static mlir::Type getInputEleTy(fir::cg::XReboxOp rebox) { 2180fa517555SKiran Chandramohan auto ty = fir::dyn_cast_ptrOrBoxEleTy(rebox.box().getType()); 2181fa517555SKiran Chandramohan if (auto seqTy = ty.dyn_cast<fir::SequenceType>()) 2182fa517555SKiran Chandramohan return seqTy.getEleTy(); 2183fa517555SKiran Chandramohan return ty; 2184fa517555SKiran Chandramohan } 2185fa517555SKiran Chandramohan }; 2186fa517555SKiran Chandramohan 218754c56347SValentin Clement // Code shared between insert_value and extract_value Ops. 218854c56347SValentin Clement struct ValueOpCommon { 218954c56347SValentin Clement // Translate the arguments pertaining to any multidimensional array to 219054c56347SValentin Clement // row-major order for LLVM-IR. 219154c56347SValentin Clement static void toRowMajor(SmallVectorImpl<mlir::Attribute> &attrs, 219254c56347SValentin Clement mlir::Type ty) { 219354c56347SValentin Clement assert(ty && "type is null"); 219454c56347SValentin Clement const auto end = attrs.size(); 219554c56347SValentin Clement for (std::remove_const_t<decltype(end)> i = 0; i < end; ++i) { 219654c56347SValentin Clement if (auto seq = ty.dyn_cast<mlir::LLVM::LLVMArrayType>()) { 219754c56347SValentin Clement const auto dim = getDimension(seq); 219854c56347SValentin Clement if (dim > 1) { 219954c56347SValentin Clement auto ub = std::min(i + dim, end); 220054c56347SValentin Clement std::reverse(attrs.begin() + i, attrs.begin() + ub); 220154c56347SValentin Clement i += dim - 1; 220254c56347SValentin Clement } 220354c56347SValentin Clement ty = getArrayElementType(seq); 220454c56347SValentin Clement } else if (auto st = ty.dyn_cast<mlir::LLVM::LLVMStructType>()) { 220554c56347SValentin Clement ty = st.getBody()[attrs[i].cast<mlir::IntegerAttr>().getInt()]; 220654c56347SValentin Clement } else { 220754c56347SValentin Clement llvm_unreachable("index into invalid type"); 220854c56347SValentin Clement } 220954c56347SValentin Clement } 221054c56347SValentin Clement } 221154c56347SValentin Clement 221254c56347SValentin Clement static llvm::SmallVector<mlir::Attribute> 221354c56347SValentin Clement collectIndices(mlir::ConversionPatternRewriter &rewriter, 221454c56347SValentin Clement mlir::ArrayAttr arrAttr) { 221554c56347SValentin Clement llvm::SmallVector<mlir::Attribute> attrs; 221654c56347SValentin Clement for (auto i = arrAttr.begin(), e = arrAttr.end(); i != e; ++i) { 221754c56347SValentin Clement if (i->isa<mlir::IntegerAttr>()) { 221854c56347SValentin Clement attrs.push_back(*i); 221954c56347SValentin Clement } else { 222054c56347SValentin Clement auto fieldName = i->cast<mlir::StringAttr>().getValue(); 222154c56347SValentin Clement ++i; 222254c56347SValentin Clement auto ty = i->cast<mlir::TypeAttr>().getValue(); 222354c56347SValentin Clement auto index = ty.cast<fir::RecordType>().getFieldIndex(fieldName); 222454c56347SValentin Clement attrs.push_back(mlir::IntegerAttr::get(rewriter.getI32Type(), index)); 222554c56347SValentin Clement } 222654c56347SValentin Clement } 222754c56347SValentin Clement return attrs; 222854c56347SValentin Clement } 222954c56347SValentin Clement 223054c56347SValentin Clement private: 223154c56347SValentin Clement static unsigned getDimension(mlir::LLVM::LLVMArrayType ty) { 223254c56347SValentin Clement unsigned result = 1; 223354c56347SValentin Clement for (auto eleTy = ty.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>(); 223454c56347SValentin Clement eleTy; 223554c56347SValentin Clement eleTy = eleTy.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>()) 223654c56347SValentin Clement ++result; 223754c56347SValentin Clement return result; 223854c56347SValentin Clement } 223954c56347SValentin Clement 224054c56347SValentin Clement static mlir::Type getArrayElementType(mlir::LLVM::LLVMArrayType ty) { 224154c56347SValentin Clement auto eleTy = ty.getElementType(); 224254c56347SValentin Clement while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>()) 224354c56347SValentin Clement eleTy = arrTy.getElementType(); 224454c56347SValentin Clement return eleTy; 224554c56347SValentin Clement } 224654c56347SValentin Clement }; 224754c56347SValentin Clement 2248*c2acd453SAlexisPerry namespace { 224954c56347SValentin Clement /// Extract a subobject value from an ssa-value of aggregate type 225054c56347SValentin Clement struct ExtractValueOpConversion 225154c56347SValentin Clement : public FIROpAndTypeConversion<fir::ExtractValueOp>, 225254c56347SValentin Clement public ValueOpCommon { 225354c56347SValentin Clement using FIROpAndTypeConversion::FIROpAndTypeConversion; 225454c56347SValentin Clement 225554c56347SValentin Clement mlir::LogicalResult 225654c56347SValentin Clement doRewrite(fir::ExtractValueOp extractVal, mlir::Type ty, OpAdaptor adaptor, 225754c56347SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 225854c56347SValentin Clement auto attrs = collectIndices(rewriter, extractVal.coor()); 225954c56347SValentin Clement toRowMajor(attrs, adaptor.getOperands()[0].getType()); 226054c56347SValentin Clement auto position = mlir::ArrayAttr::get(extractVal.getContext(), attrs); 226154c56347SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>( 226254c56347SValentin Clement extractVal, ty, adaptor.getOperands()[0], position); 226354c56347SValentin Clement return success(); 226454c56347SValentin Clement } 226554c56347SValentin Clement }; 226654c56347SValentin Clement 226754c56347SValentin Clement /// InsertValue is the generalized instruction for the composition of new 226854c56347SValentin Clement /// aggregate type values. 226954c56347SValentin Clement struct InsertValueOpConversion 227054c56347SValentin Clement : public FIROpAndTypeConversion<fir::InsertValueOp>, 227154c56347SValentin Clement public ValueOpCommon { 227254c56347SValentin Clement using FIROpAndTypeConversion::FIROpAndTypeConversion; 227354c56347SValentin Clement 227454c56347SValentin Clement mlir::LogicalResult 227554c56347SValentin Clement doRewrite(fir::InsertValueOp insertVal, mlir::Type ty, OpAdaptor adaptor, 227654c56347SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 227754c56347SValentin Clement auto attrs = collectIndices(rewriter, insertVal.coor()); 227854c56347SValentin Clement toRowMajor(attrs, adaptor.getOperands()[0].getType()); 227954c56347SValentin Clement auto position = mlir::ArrayAttr::get(insertVal.getContext(), attrs); 228054c56347SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 228154c56347SValentin Clement insertVal, ty, adaptor.getOperands()[0], adaptor.getOperands()[1], 228254c56347SValentin Clement position); 228354c56347SValentin Clement return success(); 228454c56347SValentin Clement } 228554c56347SValentin Clement }; 228654c56347SValentin Clement 22873ae8e442SValentin Clement /// InsertOnRange inserts a value into a sequence over a range of offsets. 22883ae8e442SValentin Clement struct InsertOnRangeOpConversion 22893ae8e442SValentin Clement : public FIROpAndTypeConversion<fir::InsertOnRangeOp> { 22903ae8e442SValentin Clement using FIROpAndTypeConversion::FIROpAndTypeConversion; 22913ae8e442SValentin Clement 22923ae8e442SValentin Clement // Increments an array of subscripts in a row major fasion. 22933ae8e442SValentin Clement void incrementSubscripts(const SmallVector<uint64_t> &dims, 22943ae8e442SValentin Clement SmallVector<uint64_t> &subscripts) const { 22953ae8e442SValentin Clement for (size_t i = dims.size(); i > 0; --i) { 22963ae8e442SValentin Clement if (++subscripts[i - 1] < dims[i - 1]) { 22973ae8e442SValentin Clement return; 22983ae8e442SValentin Clement } 22993ae8e442SValentin Clement subscripts[i - 1] = 0; 23003ae8e442SValentin Clement } 23013ae8e442SValentin Clement } 23023ae8e442SValentin Clement 23033ae8e442SValentin Clement mlir::LogicalResult 23043ae8e442SValentin Clement doRewrite(fir::InsertOnRangeOp range, mlir::Type ty, OpAdaptor adaptor, 23053ae8e442SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 23063ae8e442SValentin Clement 23073ae8e442SValentin Clement llvm::SmallVector<uint64_t> dims; 23083ae8e442SValentin Clement auto type = adaptor.getOperands()[0].getType(); 23093ae8e442SValentin Clement 23103ae8e442SValentin Clement // Iteratively extract the array dimensions from the type. 23113ae8e442SValentin Clement while (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) { 23123ae8e442SValentin Clement dims.push_back(t.getNumElements()); 23133ae8e442SValentin Clement type = t.getElementType(); 23143ae8e442SValentin Clement } 23153ae8e442SValentin Clement 23163ae8e442SValentin Clement SmallVector<uint64_t> lBounds; 23173ae8e442SValentin Clement SmallVector<uint64_t> uBounds; 23183ae8e442SValentin Clement 23193ae8e442SValentin Clement // Unzip the upper and lower bound and convert to a row major format. 23208ec0f221SMehdi Amini mlir::DenseIntElementsAttr coor = range.coor(); 23218ec0f221SMehdi Amini auto reversedCoor = llvm::reverse(coor.getValues<int64_t>()); 23228ec0f221SMehdi Amini for (auto i = reversedCoor.begin(), e = reversedCoor.end(); i != e; ++i) { 23233ae8e442SValentin Clement uBounds.push_back(*i++); 23243ae8e442SValentin Clement lBounds.push_back(*i); 23253ae8e442SValentin Clement } 23263ae8e442SValentin Clement 23273ae8e442SValentin Clement auto &subscripts = lBounds; 23283ae8e442SValentin Clement auto loc = range.getLoc(); 23293ae8e442SValentin Clement mlir::Value lastOp = adaptor.getOperands()[0]; 23303ae8e442SValentin Clement mlir::Value insertVal = adaptor.getOperands()[1]; 23313ae8e442SValentin Clement 23323ae8e442SValentin Clement auto i64Ty = rewriter.getI64Type(); 23333ae8e442SValentin Clement while (subscripts != uBounds) { 23343ae8e442SValentin Clement // Convert uint64_t's to Attribute's. 23353ae8e442SValentin Clement SmallVector<mlir::Attribute> subscriptAttrs; 23363ae8e442SValentin Clement for (const auto &subscript : subscripts) 23373ae8e442SValentin Clement subscriptAttrs.push_back(IntegerAttr::get(i64Ty, subscript)); 23383ae8e442SValentin Clement lastOp = rewriter.create<mlir::LLVM::InsertValueOp>( 23393ae8e442SValentin Clement loc, ty, lastOp, insertVal, 23403ae8e442SValentin Clement ArrayAttr::get(range.getContext(), subscriptAttrs)); 23413ae8e442SValentin Clement 23423ae8e442SValentin Clement incrementSubscripts(dims, subscripts); 23433ae8e442SValentin Clement } 23443ae8e442SValentin Clement 23453ae8e442SValentin Clement // Convert uint64_t's to Attribute's. 23463ae8e442SValentin Clement SmallVector<mlir::Attribute> subscriptAttrs; 23473ae8e442SValentin Clement for (const auto &subscript : subscripts) 23483ae8e442SValentin Clement subscriptAttrs.push_back( 23493ae8e442SValentin Clement IntegerAttr::get(rewriter.getI64Type(), subscript)); 23503ae8e442SValentin Clement mlir::ArrayRef<mlir::Attribute> arrayRef(subscriptAttrs); 23513ae8e442SValentin Clement 23523ae8e442SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 23533ae8e442SValentin Clement range, ty, lastOp, insertVal, 23543ae8e442SValentin Clement ArrayAttr::get(range.getContext(), arrayRef)); 23553ae8e442SValentin Clement 23563ae8e442SValentin Clement return success(); 23573ae8e442SValentin Clement } 23583ae8e442SValentin Clement }; 2359*c2acd453SAlexisPerry } // namespace 23607b5132daSValentin Clement 23615d27abe6SValentin Clement /// XArrayCoor is the address arithmetic on a dynamically shaped, sliced, 23625d27abe6SValentin Clement /// shifted etc. array. 23635d27abe6SValentin Clement /// (See the static restriction on coordinate_of.) array_coor determines the 23645d27abe6SValentin Clement /// coordinate (location) of a specific element. 23655d27abe6SValentin Clement struct XArrayCoorOpConversion 23665d27abe6SValentin Clement : public FIROpAndTypeConversion<fir::cg::XArrayCoorOp> { 23675d27abe6SValentin Clement using FIROpAndTypeConversion::FIROpAndTypeConversion; 23685d27abe6SValentin Clement 23695d27abe6SValentin Clement mlir::LogicalResult 23705d27abe6SValentin Clement doRewrite(fir::cg::XArrayCoorOp coor, mlir::Type ty, OpAdaptor adaptor, 23715d27abe6SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 23725d27abe6SValentin Clement auto loc = coor.getLoc(); 23735d27abe6SValentin Clement mlir::ValueRange operands = adaptor.getOperands(); 23745d27abe6SValentin Clement unsigned rank = coor.getRank(); 23755d27abe6SValentin Clement assert(coor.indices().size() == rank); 23765d27abe6SValentin Clement assert(coor.shape().empty() || coor.shape().size() == rank); 23775d27abe6SValentin Clement assert(coor.shift().empty() || coor.shift().size() == rank); 23785d27abe6SValentin Clement assert(coor.slice().empty() || coor.slice().size() == 3 * rank); 23795d27abe6SValentin Clement mlir::Type idxTy = lowerTy().indexType(); 23805d27abe6SValentin Clement mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1); 23815d27abe6SValentin Clement mlir::Value prevExt = one; 23825d27abe6SValentin Clement mlir::Value zero = genConstantIndex(loc, idxTy, rewriter, 0); 23835d27abe6SValentin Clement mlir::Value offset = zero; 23845d27abe6SValentin Clement const bool isShifted = !coor.shift().empty(); 23855d27abe6SValentin Clement const bool isSliced = !coor.slice().empty(); 23865d27abe6SValentin Clement const bool baseIsBoxed = coor.memref().getType().isa<fir::BoxType>(); 23875d27abe6SValentin Clement 23885d27abe6SValentin Clement auto indexOps = coor.indices().begin(); 23895d27abe6SValentin Clement auto shapeOps = coor.shape().begin(); 23905d27abe6SValentin Clement auto shiftOps = coor.shift().begin(); 23915d27abe6SValentin Clement auto sliceOps = coor.slice().begin(); 23925d27abe6SValentin Clement // For each dimension of the array, generate the offset calculation. 23935d27abe6SValentin Clement for (unsigned i = 0; i < rank; 23945d27abe6SValentin Clement ++i, ++indexOps, ++shapeOps, ++shiftOps, sliceOps += 3) { 23955d27abe6SValentin Clement mlir::Value index = 23965d27abe6SValentin Clement integerCast(loc, rewriter, idxTy, operands[coor.indicesOffset() + i]); 23975d27abe6SValentin Clement mlir::Value lb = isShifted ? integerCast(loc, rewriter, idxTy, 23985d27abe6SValentin Clement operands[coor.shiftOffset() + i]) 23995d27abe6SValentin Clement : one; 24005d27abe6SValentin Clement mlir::Value step = one; 24015d27abe6SValentin Clement bool normalSlice = isSliced; 24025d27abe6SValentin Clement // Compute zero based index in dimension i of the element, applying 24035d27abe6SValentin Clement // potential triplets and lower bounds. 24045d27abe6SValentin Clement if (isSliced) { 24055d27abe6SValentin Clement mlir::Value ub = *(sliceOps + 1); 24065d27abe6SValentin Clement normalSlice = !mlir::isa_and_nonnull<fir::UndefOp>(ub.getDefiningOp()); 24075d27abe6SValentin Clement if (normalSlice) 24085d27abe6SValentin Clement step = integerCast(loc, rewriter, idxTy, *(sliceOps + 2)); 24095d27abe6SValentin Clement } 24105d27abe6SValentin Clement auto idx = rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, index, lb); 24115d27abe6SValentin Clement mlir::Value diff = 24125d27abe6SValentin Clement rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, idx, step); 24135d27abe6SValentin Clement if (normalSlice) { 24145d27abe6SValentin Clement mlir::Value sliceLb = 24155d27abe6SValentin Clement integerCast(loc, rewriter, idxTy, operands[coor.sliceOffset() + i]); 24165d27abe6SValentin Clement auto adj = rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, sliceLb, lb); 24175d27abe6SValentin Clement diff = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, diff, adj); 24185d27abe6SValentin Clement } 24195d27abe6SValentin Clement // Update the offset given the stride and the zero based index `diff` 24205d27abe6SValentin Clement // that was just computed. 24215d27abe6SValentin Clement if (baseIsBoxed) { 24225d27abe6SValentin Clement // Use stride in bytes from the descriptor. 24235d27abe6SValentin Clement mlir::Value stride = 24245d27abe6SValentin Clement loadStrideFromBox(loc, adaptor.getOperands()[0], i, rewriter); 24255d27abe6SValentin Clement auto sc = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, stride); 24265d27abe6SValentin Clement offset = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, offset); 24275d27abe6SValentin Clement } else { 24285d27abe6SValentin Clement // Use stride computed at last iteration. 24295d27abe6SValentin Clement auto sc = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, prevExt); 24305d27abe6SValentin Clement offset = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, offset); 24315d27abe6SValentin Clement // Compute next stride assuming contiguity of the base array 24325d27abe6SValentin Clement // (in element number). 24335d27abe6SValentin Clement auto nextExt = 24345d27abe6SValentin Clement integerCast(loc, rewriter, idxTy, operands[coor.shapeOffset() + i]); 24355d27abe6SValentin Clement prevExt = 24365d27abe6SValentin Clement rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, prevExt, nextExt); 24375d27abe6SValentin Clement } 24385d27abe6SValentin Clement } 24395d27abe6SValentin Clement 24405d27abe6SValentin Clement // Add computed offset to the base address. 24415d27abe6SValentin Clement if (baseIsBoxed) { 24425d27abe6SValentin Clement // Working with byte offsets. The base address is read from the fir.box. 24435d27abe6SValentin Clement // and need to be casted to i8* to do the pointer arithmetic. 24445d27abe6SValentin Clement mlir::Type baseTy = 24455d27abe6SValentin Clement getBaseAddrTypeFromBox(adaptor.getOperands()[0].getType()); 24465d27abe6SValentin Clement mlir::Value base = 24475d27abe6SValentin Clement loadBaseAddrFromBox(loc, baseTy, adaptor.getOperands()[0], rewriter); 24485d27abe6SValentin Clement mlir::Type voidPtrTy = getVoidPtrType(); 24495d27abe6SValentin Clement base = rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, base); 24505d27abe6SValentin Clement llvm::SmallVector<mlir::Value> args{base, offset}; 24515d27abe6SValentin Clement auto addr = rewriter.create<mlir::LLVM::GEPOp>(loc, voidPtrTy, args); 24525d27abe6SValentin Clement if (coor.subcomponent().empty()) { 24535d27abe6SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(coor, baseTy, addr); 24545d27abe6SValentin Clement return success(); 24555d27abe6SValentin Clement } 24565d27abe6SValentin Clement auto casted = rewriter.create<mlir::LLVM::BitcastOp>(loc, baseTy, addr); 24575d27abe6SValentin Clement args.clear(); 24585d27abe6SValentin Clement args.push_back(casted); 24595d27abe6SValentin Clement args.push_back(zero); 24605d27abe6SValentin Clement if (!coor.lenParams().empty()) { 24615d27abe6SValentin Clement // If type parameters are present, then we don't want to use a GEPOp 24625d27abe6SValentin Clement // as below, as the LLVM struct type cannot be statically defined. 24635d27abe6SValentin Clement TODO(loc, "derived type with type parameters"); 24645d27abe6SValentin Clement } 24655d27abe6SValentin Clement // TODO: array offset subcomponents must be converted to LLVM's 24665d27abe6SValentin Clement // row-major layout here. 24675d27abe6SValentin Clement for (auto i = coor.subcomponentOffset(); i != coor.indicesOffset(); ++i) 24685d27abe6SValentin Clement args.push_back(operands[i]); 24695d27abe6SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(coor, baseTy, args); 24705d27abe6SValentin Clement return success(); 24715d27abe6SValentin Clement } 24725d27abe6SValentin Clement 24735d27abe6SValentin Clement // The array was not boxed, so it must be contiguous. offset is therefore an 24745d27abe6SValentin Clement // element offset and the base type is kept in the GEP unless the element 24755d27abe6SValentin Clement // type size is itself dynamic. 24765d27abe6SValentin Clement mlir::Value base; 24775d27abe6SValentin Clement if (coor.subcomponent().empty()) { 24785d27abe6SValentin Clement // No subcomponent. 24795d27abe6SValentin Clement if (!coor.lenParams().empty()) { 24805d27abe6SValentin Clement // Type parameters. Adjust element size explicitly. 24815d27abe6SValentin Clement auto eleTy = fir::dyn_cast_ptrEleTy(coor.getType()); 24825d27abe6SValentin Clement assert(eleTy && "result must be a reference-like type"); 24835d27abe6SValentin Clement if (fir::characterWithDynamicLen(eleTy)) { 24845d27abe6SValentin Clement assert(coor.lenParams().size() == 1); 24855d27abe6SValentin Clement auto bitsInChar = lowerTy().getKindMap().getCharacterBitsize( 24865d27abe6SValentin Clement eleTy.cast<fir::CharacterType>().getFKind()); 24875d27abe6SValentin Clement auto scaling = genConstantIndex(loc, idxTy, rewriter, bitsInChar / 8); 24885d27abe6SValentin Clement auto scaledBySize = 24895d27abe6SValentin Clement rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, offset, scaling); 24905d27abe6SValentin Clement auto length = 24915d27abe6SValentin Clement integerCast(loc, rewriter, idxTy, 24925d27abe6SValentin Clement adaptor.getOperands()[coor.lenParamsOffset()]); 24935d27abe6SValentin Clement offset = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, scaledBySize, 24945d27abe6SValentin Clement length); 24955d27abe6SValentin Clement } else { 24965d27abe6SValentin Clement TODO(loc, "compute size of derived type with type parameters"); 24975d27abe6SValentin Clement } 24985d27abe6SValentin Clement } 24995d27abe6SValentin Clement // Cast the base address to a pointer to T. 25005d27abe6SValentin Clement base = rewriter.create<mlir::LLVM::BitcastOp>(loc, ty, 25015d27abe6SValentin Clement adaptor.getOperands()[0]); 25025d27abe6SValentin Clement } else { 25035d27abe6SValentin Clement // Operand #0 must have a pointer type. For subcomponent slicing, we 25045d27abe6SValentin Clement // want to cast away the array type and have a plain struct type. 25055d27abe6SValentin Clement mlir::Type ty0 = adaptor.getOperands()[0].getType(); 25065d27abe6SValentin Clement auto ptrTy = ty0.dyn_cast<mlir::LLVM::LLVMPointerType>(); 25075d27abe6SValentin Clement assert(ptrTy && "expected pointer type"); 25085d27abe6SValentin Clement mlir::Type eleTy = ptrTy.getElementType(); 25095d27abe6SValentin Clement while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>()) 25105d27abe6SValentin Clement eleTy = arrTy.getElementType(); 25115d27abe6SValentin Clement auto newTy = mlir::LLVM::LLVMPointerType::get(eleTy); 25125d27abe6SValentin Clement base = rewriter.create<mlir::LLVM::BitcastOp>(loc, newTy, 25135d27abe6SValentin Clement adaptor.getOperands()[0]); 25145d27abe6SValentin Clement } 25155d27abe6SValentin Clement SmallVector<mlir::Value> args = {base, offset}; 25165d27abe6SValentin Clement for (auto i = coor.subcomponentOffset(); i != coor.indicesOffset(); ++i) 25175d27abe6SValentin Clement args.push_back(operands[i]); 25185d27abe6SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(coor, ty, args); 25195d27abe6SValentin Clement return success(); 25205d27abe6SValentin Clement } 25215d27abe6SValentin Clement }; 25225d27abe6SValentin Clement 25237b5132daSValentin Clement // 25247b5132daSValentin Clement // Primitive operations on Complex types 25257b5132daSValentin Clement // 25267b5132daSValentin Clement 25277b5132daSValentin Clement /// Generate inline code for complex addition/subtraction 25287b5132daSValentin Clement template <typename LLVMOP, typename OPTY> 2529*c2acd453SAlexisPerry static mlir::LLVM::InsertValueOp 2530*c2acd453SAlexisPerry complexSum(OPTY sumop, mlir::ValueRange opnds, 25317b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter, 25327b5132daSValentin Clement fir::LLVMTypeConverter &lowering) { 25337b5132daSValentin Clement mlir::Value a = opnds[0]; 25347b5132daSValentin Clement mlir::Value b = opnds[1]; 25357b5132daSValentin Clement auto loc = sumop.getLoc(); 25367b5132daSValentin Clement auto ctx = sumop.getContext(); 25377b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 25387b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 25397b5132daSValentin Clement mlir::Type eleTy = lowering.convertType(getComplexEleTy(sumop.getType())); 25407b5132daSValentin Clement mlir::Type ty = lowering.convertType(sumop.getType()); 25417b5132daSValentin Clement auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0); 25427b5132daSValentin Clement auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1); 25437b5132daSValentin Clement auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0); 25447b5132daSValentin Clement auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1); 25457b5132daSValentin Clement auto rx = rewriter.create<LLVMOP>(loc, eleTy, x0, x1); 25467b5132daSValentin Clement auto ry = rewriter.create<LLVMOP>(loc, eleTy, y0, y1); 25477b5132daSValentin Clement auto r0 = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 25487b5132daSValentin Clement auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r0, rx, c0); 25497b5132daSValentin Clement return rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ry, c1); 25507b5132daSValentin Clement } 25517b5132daSValentin Clement 2552*c2acd453SAlexisPerry namespace { 25537b5132daSValentin Clement struct AddcOpConversion : public FIROpConversion<fir::AddcOp> { 25547b5132daSValentin Clement using FIROpConversion::FIROpConversion; 25557b5132daSValentin Clement 25567b5132daSValentin Clement mlir::LogicalResult 25577b5132daSValentin Clement matchAndRewrite(fir::AddcOp addc, OpAdaptor adaptor, 25587b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 25597b5132daSValentin Clement // given: (x + iy) + (x' + iy') 25607b5132daSValentin Clement // result: (x + x') + i(y + y') 25617b5132daSValentin Clement auto r = complexSum<mlir::LLVM::FAddOp>(addc, adaptor.getOperands(), 25627b5132daSValentin Clement rewriter, lowerTy()); 25637b5132daSValentin Clement rewriter.replaceOp(addc, r.getResult()); 25647b5132daSValentin Clement return success(); 25657b5132daSValentin Clement } 25667b5132daSValentin Clement }; 25677b5132daSValentin Clement 25687b5132daSValentin Clement struct SubcOpConversion : public FIROpConversion<fir::SubcOp> { 25697b5132daSValentin Clement using FIROpConversion::FIROpConversion; 25707b5132daSValentin Clement 25717b5132daSValentin Clement mlir::LogicalResult 25727b5132daSValentin Clement matchAndRewrite(fir::SubcOp subc, OpAdaptor adaptor, 25737b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 25747b5132daSValentin Clement // given: (x + iy) - (x' + iy') 25757b5132daSValentin Clement // result: (x - x') + i(y - y') 25767b5132daSValentin Clement auto r = complexSum<mlir::LLVM::FSubOp>(subc, adaptor.getOperands(), 25777b5132daSValentin Clement rewriter, lowerTy()); 25787b5132daSValentin Clement rewriter.replaceOp(subc, r.getResult()); 25797b5132daSValentin Clement return success(); 25807b5132daSValentin Clement } 25817b5132daSValentin Clement }; 25827b5132daSValentin Clement 25837b5132daSValentin Clement /// Inlined complex multiply 25847b5132daSValentin Clement struct MulcOpConversion : public FIROpConversion<fir::MulcOp> { 25857b5132daSValentin Clement using FIROpConversion::FIROpConversion; 25867b5132daSValentin Clement 25877b5132daSValentin Clement mlir::LogicalResult 25887b5132daSValentin Clement matchAndRewrite(fir::MulcOp mulc, OpAdaptor adaptor, 25897b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 25907b5132daSValentin Clement // TODO: Can we use a call to __muldc3 ? 25917b5132daSValentin Clement // given: (x + iy) * (x' + iy') 25927b5132daSValentin Clement // result: (xx'-yy')+i(xy'+yx') 25937b5132daSValentin Clement mlir::Value a = adaptor.getOperands()[0]; 25947b5132daSValentin Clement mlir::Value b = adaptor.getOperands()[1]; 25957b5132daSValentin Clement auto loc = mulc.getLoc(); 25967b5132daSValentin Clement auto *ctx = mulc.getContext(); 25977b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 25987b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 25997b5132daSValentin Clement mlir::Type eleTy = convertType(getComplexEleTy(mulc.getType())); 26007b5132daSValentin Clement mlir::Type ty = convertType(mulc.getType()); 26017b5132daSValentin Clement auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0); 26027b5132daSValentin Clement auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1); 26037b5132daSValentin Clement auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0); 26047b5132daSValentin Clement auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1); 26057b5132daSValentin Clement auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1); 26067b5132daSValentin Clement auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1); 26077b5132daSValentin Clement auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1); 26087b5132daSValentin Clement auto ri = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xy, yx); 26097b5132daSValentin Clement auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1); 26107b5132daSValentin Clement auto rr = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, xx, yy); 26117b5132daSValentin Clement auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 26127b5132daSValentin Clement auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0); 26137b5132daSValentin Clement auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1); 26147b5132daSValentin Clement rewriter.replaceOp(mulc, r0.getResult()); 26157b5132daSValentin Clement return success(); 26167b5132daSValentin Clement } 26177b5132daSValentin Clement }; 26187b5132daSValentin Clement 26197b5132daSValentin Clement /// Inlined complex division 26207b5132daSValentin Clement struct DivcOpConversion : public FIROpConversion<fir::DivcOp> { 26217b5132daSValentin Clement using FIROpConversion::FIROpConversion; 26227b5132daSValentin Clement 26237b5132daSValentin Clement mlir::LogicalResult 26247b5132daSValentin Clement matchAndRewrite(fir::DivcOp divc, OpAdaptor adaptor, 26257b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 26267b5132daSValentin Clement // TODO: Can we use a call to __divdc3 instead? 26277b5132daSValentin Clement // Just generate inline code for now. 26287b5132daSValentin Clement // given: (x + iy) / (x' + iy') 26297b5132daSValentin Clement // result: ((xx'+yy')/d) + i((yx'-xy')/d) where d = x'x' + y'y' 26307b5132daSValentin Clement mlir::Value a = adaptor.getOperands()[0]; 26317b5132daSValentin Clement mlir::Value b = adaptor.getOperands()[1]; 26327b5132daSValentin Clement auto loc = divc.getLoc(); 26337b5132daSValentin Clement auto *ctx = divc.getContext(); 26347b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 26357b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 26367b5132daSValentin Clement mlir::Type eleTy = convertType(getComplexEleTy(divc.getType())); 26377b5132daSValentin Clement mlir::Type ty = convertType(divc.getType()); 26387b5132daSValentin Clement auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0); 26397b5132daSValentin Clement auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1); 26407b5132daSValentin Clement auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0); 26417b5132daSValentin Clement auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1); 26427b5132daSValentin Clement auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1); 26437b5132daSValentin Clement auto x1x1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x1, x1); 26447b5132daSValentin Clement auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1); 26457b5132daSValentin Clement auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1); 26467b5132daSValentin Clement auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1); 26477b5132daSValentin Clement auto y1y1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y1, y1); 26487b5132daSValentin Clement auto d = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, x1x1, y1y1); 26497b5132daSValentin Clement auto rrn = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xx, yy); 26507b5132daSValentin Clement auto rin = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, yx, xy); 26517b5132daSValentin Clement auto rr = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rrn, d); 26527b5132daSValentin Clement auto ri = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rin, d); 26537b5132daSValentin Clement auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 26547b5132daSValentin Clement auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0); 26557b5132daSValentin Clement auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1); 26567b5132daSValentin Clement rewriter.replaceOp(divc, r0.getResult()); 26577b5132daSValentin Clement return success(); 26587b5132daSValentin Clement } 26597b5132daSValentin Clement }; 26607b5132daSValentin Clement 26617b5132daSValentin Clement /// Inlined complex negation 26627b5132daSValentin Clement struct NegcOpConversion : public FIROpConversion<fir::NegcOp> { 26637b5132daSValentin Clement using FIROpConversion::FIROpConversion; 26647b5132daSValentin Clement 26657b5132daSValentin Clement mlir::LogicalResult 26667b5132daSValentin Clement matchAndRewrite(fir::NegcOp neg, OpAdaptor adaptor, 26677b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 26687b5132daSValentin Clement // given: -(x + iy) 26697b5132daSValentin Clement // result: -x - iy 26707b5132daSValentin Clement auto *ctxt = neg.getContext(); 26717b5132daSValentin Clement auto eleTy = convertType(getComplexEleTy(neg.getType())); 26727b5132daSValentin Clement auto ty = convertType(neg.getType()); 26737b5132daSValentin Clement auto loc = neg.getLoc(); 26747b5132daSValentin Clement mlir::Value o0 = adaptor.getOperands()[0]; 26757b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0)); 26767b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1)); 26777b5132daSValentin Clement auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c0); 26787b5132daSValentin Clement auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c1); 26797b5132daSValentin Clement auto nrp = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, rp); 26807b5132daSValentin Clement auto nip = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, ip); 26817b5132daSValentin Clement auto r = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, o0, nrp, c0); 26827b5132daSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(neg, ty, r, nip, c1); 26837b5132daSValentin Clement return success(); 26847b5132daSValentin Clement } 26857b5132daSValentin Clement }; 26867b5132daSValentin Clement 26871ed5a90fSValentin Clement /// Conversion pattern for operation that must be dead. The information in these 26881ed5a90fSValentin Clement /// operations is used by other operation. At this point they should not have 26891ed5a90fSValentin Clement /// anymore uses. 26901ed5a90fSValentin Clement /// These operations are normally dead after the pre-codegen pass. 26911ed5a90fSValentin Clement template <typename FromOp> 26921ed5a90fSValentin Clement struct MustBeDeadConversion : public FIROpConversion<FromOp> { 26931ed5a90fSValentin Clement explicit MustBeDeadConversion(fir::LLVMTypeConverter &lowering) 26941ed5a90fSValentin Clement : FIROpConversion<FromOp>(lowering) {} 26951ed5a90fSValentin Clement using OpAdaptor = typename FromOp::Adaptor; 26961ed5a90fSValentin Clement 26971ed5a90fSValentin Clement mlir::LogicalResult 26981ed5a90fSValentin Clement matchAndRewrite(FromOp op, OpAdaptor adaptor, 26991ed5a90fSValentin Clement mlir::ConversionPatternRewriter &rewriter) const final { 27001ed5a90fSValentin Clement if (!op->getUses().empty()) 27011ed5a90fSValentin Clement return rewriter.notifyMatchFailure(op, "op must be dead"); 27021ed5a90fSValentin Clement rewriter.eraseOp(op); 27031ed5a90fSValentin Clement return success(); 27041ed5a90fSValentin Clement } 27051ed5a90fSValentin Clement }; 27061ed5a90fSValentin Clement 27071ed5a90fSValentin Clement struct ShapeOpConversion : public MustBeDeadConversion<fir::ShapeOp> { 27081ed5a90fSValentin Clement using MustBeDeadConversion::MustBeDeadConversion; 27091ed5a90fSValentin Clement }; 27101ed5a90fSValentin Clement 27111ed5a90fSValentin Clement struct ShapeShiftOpConversion : public MustBeDeadConversion<fir::ShapeShiftOp> { 27121ed5a90fSValentin Clement using MustBeDeadConversion::MustBeDeadConversion; 27131ed5a90fSValentin Clement }; 27141ed5a90fSValentin Clement 27151ed5a90fSValentin Clement struct ShiftOpConversion : public MustBeDeadConversion<fir::ShiftOp> { 27161ed5a90fSValentin Clement using MustBeDeadConversion::MustBeDeadConversion; 27171ed5a90fSValentin Clement }; 27181ed5a90fSValentin Clement 27191ed5a90fSValentin Clement struct SliceOpConversion : public MustBeDeadConversion<fir::SliceOp> { 27201ed5a90fSValentin Clement using MustBeDeadConversion::MustBeDeadConversion; 27211ed5a90fSValentin Clement }; 27221ed5a90fSValentin Clement 2723420ad7ceSAndrzej Warzynski /// `fir.is_present` --> 2724420ad7ceSAndrzej Warzynski /// ``` 2725420ad7ceSAndrzej Warzynski /// %0 = llvm.mlir.constant(0 : i64) 2726420ad7ceSAndrzej Warzynski /// %1 = llvm.ptrtoint %0 2727420ad7ceSAndrzej Warzynski /// %2 = llvm.icmp "ne" %1, %0 : i64 2728420ad7ceSAndrzej Warzynski /// ``` 2729420ad7ceSAndrzej Warzynski struct IsPresentOpConversion : public FIROpConversion<fir::IsPresentOp> { 2730420ad7ceSAndrzej Warzynski using FIROpConversion::FIROpConversion; 2731420ad7ceSAndrzej Warzynski 2732420ad7ceSAndrzej Warzynski mlir::LogicalResult 2733420ad7ceSAndrzej Warzynski matchAndRewrite(fir::IsPresentOp isPresent, OpAdaptor adaptor, 2734420ad7ceSAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 2735420ad7ceSAndrzej Warzynski mlir::Type idxTy = lowerTy().indexType(); 2736420ad7ceSAndrzej Warzynski mlir::Location loc = isPresent.getLoc(); 2737420ad7ceSAndrzej Warzynski auto ptr = adaptor.getOperands()[0]; 2738420ad7ceSAndrzej Warzynski 2739420ad7ceSAndrzej Warzynski if (isPresent.val().getType().isa<fir::BoxCharType>()) { 2740420ad7ceSAndrzej Warzynski auto structTy = ptr.getType().cast<mlir::LLVM::LLVMStructType>(); 2741420ad7ceSAndrzej Warzynski assert(!structTy.isOpaque() && !structTy.getBody().empty()); 2742420ad7ceSAndrzej Warzynski 2743420ad7ceSAndrzej Warzynski mlir::Type ty = structTy.getBody()[0]; 2744420ad7ceSAndrzej Warzynski mlir::MLIRContext *ctx = isPresent.getContext(); 2745420ad7ceSAndrzej Warzynski auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 2746420ad7ceSAndrzej Warzynski ptr = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, ptr, c0); 2747420ad7ceSAndrzej Warzynski } 2748420ad7ceSAndrzej Warzynski mlir::LLVM::ConstantOp c0 = 2749420ad7ceSAndrzej Warzynski genConstantIndex(isPresent.getLoc(), idxTy, rewriter, 0); 2750420ad7ceSAndrzej Warzynski auto addr = rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, ptr); 2751420ad7ceSAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>( 2752420ad7ceSAndrzej Warzynski isPresent, mlir::LLVM::ICmpPredicate::ne, addr, c0); 2753420ad7ceSAndrzej Warzynski 2754420ad7ceSAndrzej Warzynski return success(); 2755420ad7ceSAndrzej Warzynski } 2756420ad7ceSAndrzej Warzynski }; 27571e77b095SAndrzej Warzynski 27581e77b095SAndrzej Warzynski /// Convert `!fir.emboxchar<!fir.char<KIND, ?>, #n>` into a sequence of 27591e77b095SAndrzej Warzynski /// instructions that generate `!llvm.struct<(ptr<ik>, i64)>`. The 1st element 27601e77b095SAndrzej Warzynski /// in this struct is a pointer. Its type is determined from `KIND`. The 2nd 27611e77b095SAndrzej Warzynski /// element is the length of the character buffer (`#n`). 27621e77b095SAndrzej Warzynski struct EmboxCharOpConversion : public FIROpConversion<fir::EmboxCharOp> { 27631e77b095SAndrzej Warzynski using FIROpConversion::FIROpConversion; 27641e77b095SAndrzej Warzynski 27651e77b095SAndrzej Warzynski mlir::LogicalResult 27661e77b095SAndrzej Warzynski matchAndRewrite(fir::EmboxCharOp emboxChar, OpAdaptor adaptor, 27671e77b095SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 27681e77b095SAndrzej Warzynski mlir::ValueRange operands = adaptor.getOperands(); 27691e77b095SAndrzej Warzynski MLIRContext *ctx = emboxChar.getContext(); 27701e77b095SAndrzej Warzynski 27711e77b095SAndrzej Warzynski mlir::Value charBuffer = operands[0]; 27721e77b095SAndrzej Warzynski mlir::Value charBufferLen = operands[1]; 27731e77b095SAndrzej Warzynski 27741e77b095SAndrzej Warzynski mlir::Location loc = emboxChar.getLoc(); 27751e77b095SAndrzej Warzynski mlir::Type llvmStructTy = convertType(emboxChar.getType()); 27761e77b095SAndrzej Warzynski auto llvmStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, llvmStructTy); 27771e77b095SAndrzej Warzynski 27781e77b095SAndrzej Warzynski mlir::Type lenTy = 27791e77b095SAndrzej Warzynski llvmStructTy.cast<mlir::LLVM::LLVMStructType>().getBody()[1]; 27801e77b095SAndrzej Warzynski mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, charBufferLen); 27811e77b095SAndrzej Warzynski 27821e77b095SAndrzej Warzynski auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 27831e77b095SAndrzej Warzynski auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 27841e77b095SAndrzej Warzynski auto insertBufferOp = rewriter.create<mlir::LLVM::InsertValueOp>( 27851e77b095SAndrzej Warzynski loc, llvmStructTy, llvmStruct, charBuffer, c0); 27861e77b095SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 27871e77b095SAndrzej Warzynski emboxChar, llvmStructTy, insertBufferOp, lenAfterCast, c1); 27881e77b095SAndrzej Warzynski 27891e77b095SAndrzej Warzynski return success(); 27901e77b095SAndrzej Warzynski } 27911e77b095SAndrzej Warzynski }; 2792*c2acd453SAlexisPerry } // namespace 279314867ffcSAndrzej Warzynski 279414867ffcSAndrzej Warzynski /// Construct an `llvm.extractvalue` instruction. It will return value at 279514867ffcSAndrzej Warzynski /// element \p x from \p tuple. 2796*c2acd453SAlexisPerry static mlir::LLVM::ExtractValueOp 279714867ffcSAndrzej Warzynski genExtractValueWithIndex(mlir::Location loc, mlir::Value tuple, mlir::Type ty, 279814867ffcSAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter, 279914867ffcSAndrzej Warzynski mlir::MLIRContext *ctx, int x) { 280014867ffcSAndrzej Warzynski auto cx = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(x)); 280114867ffcSAndrzej Warzynski auto xty = ty.cast<mlir::LLVM::LLVMStructType>().getBody()[x]; 280214867ffcSAndrzej Warzynski return rewriter.create<mlir::LLVM::ExtractValueOp>(loc, xty, tuple, cx); 280314867ffcSAndrzej Warzynski } 280414867ffcSAndrzej Warzynski 2805*c2acd453SAlexisPerry namespace { 28066c3d7fd4SAndrzej Warzynski /// Convert `!fir.boxchar_len` to `!llvm.extractvalue` for the 2nd part of the 28076c3d7fd4SAndrzej Warzynski /// boxchar. 28086c3d7fd4SAndrzej Warzynski struct BoxCharLenOpConversion : public FIROpConversion<fir::BoxCharLenOp> { 28096c3d7fd4SAndrzej Warzynski using FIROpConversion::FIROpConversion; 28106c3d7fd4SAndrzej Warzynski 28116c3d7fd4SAndrzej Warzynski mlir::LogicalResult 28126c3d7fd4SAndrzej Warzynski matchAndRewrite(fir::BoxCharLenOp boxCharLen, OpAdaptor adaptor, 28136c3d7fd4SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 28146c3d7fd4SAndrzej Warzynski mlir::Value boxChar = adaptor.getOperands()[0]; 28156c3d7fd4SAndrzej Warzynski mlir::Location loc = boxChar.getLoc(); 28166c3d7fd4SAndrzej Warzynski mlir::MLIRContext *ctx = boxChar.getContext(); 28176c3d7fd4SAndrzej Warzynski mlir::Type returnValTy = boxCharLen.getResult().getType(); 28186c3d7fd4SAndrzej Warzynski 28196c3d7fd4SAndrzej Warzynski constexpr int boxcharLenIdx = 1; 28206c3d7fd4SAndrzej Warzynski mlir::LLVM::ExtractValueOp len = genExtractValueWithIndex( 28216c3d7fd4SAndrzej Warzynski loc, boxChar, boxChar.getType(), rewriter, ctx, boxcharLenIdx); 28226c3d7fd4SAndrzej Warzynski mlir::Value lenAfterCast = integerCast(loc, rewriter, returnValTy, len); 28236c3d7fd4SAndrzej Warzynski rewriter.replaceOp(boxCharLen, lenAfterCast); 28246c3d7fd4SAndrzej Warzynski 28256c3d7fd4SAndrzej Warzynski return success(); 28266c3d7fd4SAndrzej Warzynski } 28276c3d7fd4SAndrzej Warzynski }; 28286c3d7fd4SAndrzej Warzynski 282914867ffcSAndrzej Warzynski /// Convert `fir.unboxchar` into two `llvm.extractvalue` instructions. One for 283014867ffcSAndrzej Warzynski /// the character buffer and one for the buffer length. 283114867ffcSAndrzej Warzynski struct UnboxCharOpConversion : public FIROpConversion<fir::UnboxCharOp> { 283214867ffcSAndrzej Warzynski using FIROpConversion::FIROpConversion; 283314867ffcSAndrzej Warzynski 283414867ffcSAndrzej Warzynski mlir::LogicalResult 283514867ffcSAndrzej Warzynski matchAndRewrite(fir::UnboxCharOp unboxchar, OpAdaptor adaptor, 283614867ffcSAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 283714867ffcSAndrzej Warzynski MLIRContext *ctx = unboxchar.getContext(); 283814867ffcSAndrzej Warzynski 283914867ffcSAndrzej Warzynski mlir::Type lenTy = convertType(unboxchar.getType(1)); 284014867ffcSAndrzej Warzynski mlir::Value tuple = adaptor.getOperands()[0]; 284114867ffcSAndrzej Warzynski mlir::Type tupleTy = tuple.getType(); 284214867ffcSAndrzej Warzynski 284314867ffcSAndrzej Warzynski mlir::Location loc = unboxchar.getLoc(); 284414867ffcSAndrzej Warzynski mlir::Value ptrToBuffer = 284514867ffcSAndrzej Warzynski genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 0); 284614867ffcSAndrzej Warzynski 284714867ffcSAndrzej Warzynski mlir::LLVM::ExtractValueOp len = 284814867ffcSAndrzej Warzynski genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 1); 284914867ffcSAndrzej Warzynski mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, len); 285014867ffcSAndrzej Warzynski 285114867ffcSAndrzej Warzynski rewriter.replaceOp(unboxchar, 285214867ffcSAndrzej Warzynski ArrayRef<mlir::Value>{ptrToBuffer, lenAfterCast}); 285314867ffcSAndrzej Warzynski return success(); 285414867ffcSAndrzej Warzynski } 285514867ffcSAndrzej Warzynski }; 285614867ffcSAndrzej Warzynski 2857cc505c0bSKiran Chandramohan /// Lower `fir.unboxproc` operation. Unbox a procedure box value, yielding its 2858cc505c0bSKiran Chandramohan /// components. 2859cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers. 2860cc505c0bSKiran Chandramohan struct UnboxProcOpConversion : public FIROpConversion<fir::UnboxProcOp> { 2861cc505c0bSKiran Chandramohan using FIROpConversion::FIROpConversion; 2862cc505c0bSKiran Chandramohan 2863cc505c0bSKiran Chandramohan mlir::LogicalResult 2864cc505c0bSKiran Chandramohan matchAndRewrite(fir::UnboxProcOp unboxproc, OpAdaptor adaptor, 2865cc505c0bSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 28667ce8c6fcSKiran Chandramohan TODO(unboxproc.getLoc(), "fir.unboxproc codegen"); 28677ce8c6fcSKiran Chandramohan return failure(); 2868cc505c0bSKiran Chandramohan } 2869cc505c0bSKiran Chandramohan }; 2870cc505c0bSKiran Chandramohan 2871e6c66ef5SAndrzej Warzynski /// Convert `fir.field_index`. The conversion depends on whether the size of 2872e6c66ef5SAndrzej Warzynski /// the record is static or dynamic. 2873e6c66ef5SAndrzej Warzynski struct FieldIndexOpConversion : public FIROpConversion<fir::FieldIndexOp> { 2874e6c66ef5SAndrzej Warzynski using FIROpConversion::FIROpConversion; 2875e6c66ef5SAndrzej Warzynski 2876e6c66ef5SAndrzej Warzynski // NB: most field references should be resolved by this point 2877e6c66ef5SAndrzej Warzynski mlir::LogicalResult 2878e6c66ef5SAndrzej Warzynski matchAndRewrite(fir::FieldIndexOp field, OpAdaptor adaptor, 2879e6c66ef5SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 2880e6c66ef5SAndrzej Warzynski auto recTy = field.on_type().cast<fir::RecordType>(); 2881e6c66ef5SAndrzej Warzynski unsigned index = recTy.getFieldIndex(field.field_id()); 2882e6c66ef5SAndrzej Warzynski 2883e6c66ef5SAndrzej Warzynski if (!fir::hasDynamicSize(recTy)) { 2884e6c66ef5SAndrzej Warzynski // Derived type has compile-time constant layout. Return index of the 2885e6c66ef5SAndrzej Warzynski // component type in the parent type (to be used in GEP). 2886e6c66ef5SAndrzej Warzynski rewriter.replaceOp(field, mlir::ValueRange{genConstantOffset( 2887e6c66ef5SAndrzej Warzynski field.getLoc(), rewriter, index)}); 2888e6c66ef5SAndrzej Warzynski return success(); 2889e6c66ef5SAndrzej Warzynski } 2890e6c66ef5SAndrzej Warzynski 2891e6c66ef5SAndrzej Warzynski // Derived type has compile-time constant layout. Call the compiler 2892e6c66ef5SAndrzej Warzynski // generated function to determine the byte offset of the field at runtime. 2893e6c66ef5SAndrzej Warzynski // This returns a non-constant. 2894e6c66ef5SAndrzej Warzynski FlatSymbolRefAttr symAttr = mlir::SymbolRefAttr::get( 2895e6c66ef5SAndrzej Warzynski field.getContext(), getOffsetMethodName(recTy, field.field_id())); 2896e6c66ef5SAndrzej Warzynski NamedAttribute callAttr = rewriter.getNamedAttr("callee", symAttr); 2897e6c66ef5SAndrzej Warzynski NamedAttribute fieldAttr = rewriter.getNamedAttr( 2898e6c66ef5SAndrzej Warzynski "field", mlir::IntegerAttr::get(lowerTy().indexType(), index)); 2899e6c66ef5SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>( 2900e6c66ef5SAndrzej Warzynski field, lowerTy().offsetType(), adaptor.getOperands(), 2901e6c66ef5SAndrzej Warzynski llvm::ArrayRef<mlir::NamedAttribute>{callAttr, fieldAttr}); 2902e6c66ef5SAndrzej Warzynski return success(); 2903e6c66ef5SAndrzej Warzynski } 2904e6c66ef5SAndrzej Warzynski 2905e6c66ef5SAndrzej Warzynski // Re-Construct the name of the compiler generated method that calculates the 2906e6c66ef5SAndrzej Warzynski // offset 2907e6c66ef5SAndrzej Warzynski inline static std::string getOffsetMethodName(fir::RecordType recTy, 2908e6c66ef5SAndrzej Warzynski llvm::StringRef field) { 2909e6c66ef5SAndrzej Warzynski return recTy.getName().str() + "P." + field.str() + ".offset"; 2910e6c66ef5SAndrzej Warzynski } 2911e6c66ef5SAndrzej Warzynski }; 2912e6c66ef5SAndrzej Warzynski 2913044d5b5dSValentin Clement } // namespace 2914044d5b5dSValentin Clement 2915044d5b5dSValentin Clement namespace { 2916044d5b5dSValentin Clement /// Convert FIR dialect to LLVM dialect 2917044d5b5dSValentin Clement /// 2918044d5b5dSValentin Clement /// This pass lowers all FIR dialect operations to LLVM IR dialect. An 2919044d5b5dSValentin Clement /// MLIR pass is used to lower residual Std dialect to LLVM IR dialect. 2920044d5b5dSValentin Clement /// 2921044d5b5dSValentin Clement /// This pass is not complete yet. We are upstreaming it in small patches. 2922044d5b5dSValentin Clement class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> { 2923044d5b5dSValentin Clement public: 2924044d5b5dSValentin Clement mlir::ModuleOp getModule() { return getOperation(); } 2925044d5b5dSValentin Clement 2926044d5b5dSValentin Clement void runOnOperation() override final { 29277b5132daSValentin Clement auto mod = getModule(); 29287b5132daSValentin Clement if (!forcedTargetTriple.empty()) { 29297b5132daSValentin Clement fir::setTargetTriple(mod, forcedTargetTriple); 29307b5132daSValentin Clement } 29317b5132daSValentin Clement 2932044d5b5dSValentin Clement auto *context = getModule().getContext(); 2933044d5b5dSValentin Clement fir::LLVMTypeConverter typeConverter{getModule()}; 2934044d5b5dSValentin Clement mlir::OwningRewritePatternList pattern(context); 2935df3b9810SValentin Clement pattern.insert< 2936420ad7ceSAndrzej Warzynski AbsentOpConversion, AddcOpConversion, AddrOfOpConversion, 2937*c2acd453SAlexisPerry AllocaOpConversion, AllocMemOpConversion, BoxAddrOpConversion, 2938*c2acd453SAlexisPerry BoxCharLenOpConversion, BoxDimsOpConversion, BoxEleSizeOpConversion, 2939*c2acd453SAlexisPerry BoxIsAllocOpConversion, BoxIsArrayOpConversion, BoxIsPtrOpConversion, 2940*c2acd453SAlexisPerry BoxProcHostOpConversion, BoxRankOpConversion, BoxTypeDescOpConversion, 2941*c2acd453SAlexisPerry CallOpConversion, CmpcOpConversion, ConstcOpConversion, 2942*c2acd453SAlexisPerry ConvertOpConversion, DispatchOpConversion, DispatchTableOpConversion, 2943*c2acd453SAlexisPerry DTEntryOpConversion, DivcOpConversion, EmboxOpConversion, 2944*c2acd453SAlexisPerry EmboxCharOpConversion, EmboxProcOpConversion, ExtractValueOpConversion, 2945*c2acd453SAlexisPerry FieldIndexOpConversion, FirEndOpConversion, FreeMemOpConversion, 2946*c2acd453SAlexisPerry HasValueOpConversion, GenTypeDescOpConversion, GlobalLenOpConversion, 2947*c2acd453SAlexisPerry GlobalOpConversion, InsertOnRangeOpConversion, InsertValueOpConversion, 2948*c2acd453SAlexisPerry IsPresentOpConversion, LenParamIndexOpConversion, LoadOpConversion, 2949*c2acd453SAlexisPerry NegcOpConversion, NoReassocOpConversion, MulcOpConversion, 2950*c2acd453SAlexisPerry SelectCaseOpConversion, SelectOpConversion, SelectRankOpConversion, 2951*c2acd453SAlexisPerry SelectTypeOpConversion, ShapeOpConversion, ShapeShiftOpConversion, 2952*c2acd453SAlexisPerry ShiftOpConversion, SliceOpConversion, StoreOpConversion, 2953*c2acd453SAlexisPerry StringLitOpConversion, SubcOpConversion, UnboxCharOpConversion, 2954*c2acd453SAlexisPerry UnboxProcOpConversion, UndefOpConversion, UnreachableOpConversion, 2955*c2acd453SAlexisPerry XArrayCoorOpConversion, XEmboxOpConversion, XReboxOpConversion, 2956*c2acd453SAlexisPerry ZeroOpConversion>(typeConverter); 2957044d5b5dSValentin Clement mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern); 2958044d5b5dSValentin Clement mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter, 2959044d5b5dSValentin Clement pattern); 2960044d5b5dSValentin Clement mlir::ConversionTarget target{*context}; 2961044d5b5dSValentin Clement target.addLegalDialect<mlir::LLVM::LLVMDialect>(); 2962044d5b5dSValentin Clement 2963044d5b5dSValentin Clement // required NOPs for applying a full conversion 2964044d5b5dSValentin Clement target.addLegalOp<mlir::ModuleOp>(); 2965044d5b5dSValentin Clement 2966044d5b5dSValentin Clement // apply the patterns 2967044d5b5dSValentin Clement if (mlir::failed(mlir::applyFullConversion(getModule(), target, 2968044d5b5dSValentin Clement std::move(pattern)))) { 2969044d5b5dSValentin Clement signalPassFailure(); 2970044d5b5dSValentin Clement } 2971044d5b5dSValentin Clement } 2972044d5b5dSValentin Clement }; 2973044d5b5dSValentin Clement } // namespace 2974044d5b5dSValentin Clement 2975044d5b5dSValentin Clement std::unique_ptr<mlir::Pass> fir::createFIRToLLVMPass() { 2976044d5b5dSValentin Clement return std::make_unique<FIRToLLVMLowering>(); 2977044d5b5dSValentin Clement } 2978