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" 21*ace01605SRiver Riddle #include "mlir/Conversion/ControlFlowToLLVM/ControlFlowToLLVM.h" 22044d5b5dSValentin Clement #include "mlir/Conversion/LLVMCommon/Pattern.h" 23044d5b5dSValentin Clement #include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h" 24044d5b5dSValentin Clement #include "mlir/IR/BuiltinTypes.h" 253ae8e442SValentin Clement #include "mlir/IR/Matchers.h" 26044d5b5dSValentin Clement #include "mlir/Pass/Pass.h" 27853e79d8SValentin Clement #include "mlir/Target/LLVMIR/ModuleTranslation.h" 28044d5b5dSValentin Clement #include "llvm/ADT/ArrayRef.h" 29044d5b5dSValentin Clement 30044d5b5dSValentin Clement #define DEBUG_TYPE "flang-codegen" 31044d5b5dSValentin Clement 32044d5b5dSValentin Clement // fir::LLVMTypeConverter for converting to LLVM IR dialect types. 33044d5b5dSValentin Clement #include "TypeConverter.h" 34044d5b5dSValentin Clement 35af6ee580SValentin Clement // TODO: This should really be recovered from the specified target. 36af6ee580SValentin Clement static constexpr unsigned defaultAlign = 8; 37af6ee580SValentin Clement 38b6e44ecdSValentin Clement /// `fir.box` attribute values as defined for CFI_attribute_t in 39b6e44ecdSValentin Clement /// flang/ISO_Fortran_binding.h. 40b6e44ecdSValentin Clement static constexpr unsigned kAttrPointer = CFI_attribute_pointer; 41b6e44ecdSValentin Clement static constexpr unsigned kAttrAllocatable = CFI_attribute_allocatable; 42b6e44ecdSValentin Clement 43135d5d4aSKiran Chandramohan static inline mlir::Type getVoidPtrType(mlir::MLIRContext *context) { 44fa517555SKiran Chandramohan return mlir::LLVM::LLVMPointerType::get(mlir::IntegerType::get(context, 8)); 45fa517555SKiran Chandramohan } 46fa517555SKiran Chandramohan 471e6d9c06SDiana Picus static mlir::LLVM::ConstantOp 481e6d9c06SDiana Picus genConstantIndex(mlir::Location loc, mlir::Type ity, 491e6d9c06SDiana Picus mlir::ConversionPatternRewriter &rewriter, 501e6d9c06SDiana Picus std::int64_t offset) { 511e6d9c06SDiana Picus auto cattr = rewriter.getI64IntegerAttr(offset); 521e6d9c06SDiana Picus return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr); 531e6d9c06SDiana Picus } 541e6d9c06SDiana Picus 5539f4ef81SValentin Clement static Block *createBlock(mlir::ConversionPatternRewriter &rewriter, 5639f4ef81SValentin Clement mlir::Block *insertBefore) { 5739f4ef81SValentin Clement assert(insertBefore && "expected valid insertion block"); 5839f4ef81SValentin Clement return rewriter.createBlock(insertBefore->getParent(), 5939f4ef81SValentin Clement mlir::Region::iterator(insertBefore)); 6039f4ef81SValentin Clement } 6139f4ef81SValentin Clement 62044d5b5dSValentin Clement namespace { 63044d5b5dSValentin Clement /// FIR conversion pattern template 64044d5b5dSValentin Clement template <typename FromOp> 65044d5b5dSValentin Clement class FIROpConversion : public mlir::ConvertOpToLLVMPattern<FromOp> { 66044d5b5dSValentin Clement public: 67044d5b5dSValentin Clement explicit FIROpConversion(fir::LLVMTypeConverter &lowering) 68044d5b5dSValentin Clement : mlir::ConvertOpToLLVMPattern<FromOp>(lowering) {} 69044d5b5dSValentin Clement 70044d5b5dSValentin Clement protected: 71044d5b5dSValentin Clement mlir::Type convertType(mlir::Type ty) const { 72044d5b5dSValentin Clement return lowerTy().convertType(ty); 73044d5b5dSValentin Clement } 74c2acd453SAlexisPerry mlir::Type voidPtrTy() const { return getVoidPtrType(); } 75044d5b5dSValentin Clement 765d27abe6SValentin Clement mlir::Type getVoidPtrType() const { 775d27abe6SValentin Clement return mlir::LLVM::LLVMPointerType::get( 785d27abe6SValentin Clement mlir::IntegerType::get(&lowerTy().getContext(), 8)); 795d27abe6SValentin Clement } 805d27abe6SValentin Clement 81df3b9810SValentin Clement mlir::LLVM::ConstantOp 82af6ee580SValentin Clement genI32Constant(mlir::Location loc, mlir::ConversionPatternRewriter &rewriter, 83af6ee580SValentin Clement int value) const { 84af6ee580SValentin Clement mlir::Type i32Ty = rewriter.getI32Type(); 85af6ee580SValentin Clement mlir::IntegerAttr attr = rewriter.getI32IntegerAttr(value); 86af6ee580SValentin Clement return rewriter.create<mlir::LLVM::ConstantOp>(loc, i32Ty, attr); 87af6ee580SValentin Clement } 88af6ee580SValentin Clement 89af6ee580SValentin Clement mlir::LLVM::ConstantOp 90df3b9810SValentin Clement genConstantOffset(mlir::Location loc, 91df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter, 92df3b9810SValentin Clement int offset) const { 93af6ee580SValentin Clement mlir::Type ity = lowerTy().offsetType(); 94af6ee580SValentin Clement mlir::IntegerAttr cattr = rewriter.getI32IntegerAttr(offset); 95df3b9810SValentin Clement return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr); 96df3b9810SValentin Clement } 97df3b9810SValentin Clement 98b6e44ecdSValentin Clement /// Construct code sequence to extract the specifc value from a `fir.box`. 99b6e44ecdSValentin Clement mlir::Value getValueFromBox(mlir::Location loc, mlir::Value box, 100df3b9810SValentin Clement mlir::Type resultTy, 101b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter, 102b6e44ecdSValentin Clement unsigned boxValue) const { 103df3b9810SValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 104b6e44ecdSValentin Clement mlir::LLVM::ConstantOp cValuePos = 105b6e44ecdSValentin Clement genConstantOffset(loc, rewriter, boxValue); 106df3b9810SValentin Clement auto pty = mlir::LLVM::LLVMPointerType::get(resultTy); 107df3b9810SValentin Clement auto p = rewriter.create<mlir::LLVM::GEPOp>( 10830122656SAlex Zinenko loc, pty, box, mlir::ValueRange{c0, cValuePos}); 109df3b9810SValentin Clement return rewriter.create<mlir::LLVM::LoadOp>(loc, resultTy, p); 110df3b9810SValentin Clement } 111df3b9810SValentin Clement 112df3b9810SValentin Clement /// Method to construct code sequence to get the triple for dimension `dim` 113df3b9810SValentin Clement /// from a box. 114df3b9810SValentin Clement SmallVector<mlir::Value, 3> 115df3b9810SValentin Clement getDimsFromBox(mlir::Location loc, ArrayRef<mlir::Type> retTys, 116df3b9810SValentin Clement mlir::Value box, mlir::Value dim, 117df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 118df3b9810SValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 119df3b9810SValentin Clement mlir::LLVM::ConstantOp cDims = 120df3b9810SValentin Clement genConstantOffset(loc, rewriter, kDimsPosInBox); 121df3b9810SValentin Clement mlir::LLVM::LoadOp l0 = 122df3b9810SValentin Clement loadFromOffset(loc, box, c0, cDims, dim, 0, retTys[0], rewriter); 123df3b9810SValentin Clement mlir::LLVM::LoadOp l1 = 124df3b9810SValentin Clement loadFromOffset(loc, box, c0, cDims, dim, 1, retTys[1], rewriter); 125df3b9810SValentin Clement mlir::LLVM::LoadOp l2 = 126df3b9810SValentin Clement loadFromOffset(loc, box, c0, cDims, dim, 2, retTys[2], rewriter); 127df3b9810SValentin Clement return {l0.getResult(), l1.getResult(), l2.getResult()}; 128df3b9810SValentin Clement } 129df3b9810SValentin Clement 130df3b9810SValentin Clement mlir::LLVM::LoadOp 131df3b9810SValentin Clement loadFromOffset(mlir::Location loc, mlir::Value a, mlir::LLVM::ConstantOp c0, 132df3b9810SValentin Clement mlir::LLVM::ConstantOp cDims, mlir::Value dim, int off, 133df3b9810SValentin Clement mlir::Type ty, 134df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 135df3b9810SValentin Clement auto pty = mlir::LLVM::LLVMPointerType::get(ty); 136df3b9810SValentin Clement mlir::LLVM::ConstantOp c = genConstantOffset(loc, rewriter, off); 137df3b9810SValentin Clement mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, a, c0, cDims, dim, c); 138df3b9810SValentin Clement return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p); 139df3b9810SValentin Clement } 140df3b9810SValentin Clement 1415d27abe6SValentin Clement mlir::Value 1425d27abe6SValentin Clement loadStrideFromBox(mlir::Location loc, mlir::Value box, unsigned dim, 1435d27abe6SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 1445d27abe6SValentin Clement auto idxTy = lowerTy().indexType(); 1455d27abe6SValentin Clement auto c0 = genConstantOffset(loc, rewriter, 0); 1465d27abe6SValentin Clement auto cDims = genConstantOffset(loc, rewriter, kDimsPosInBox); 1475d27abe6SValentin Clement auto dimValue = genConstantIndex(loc, idxTy, rewriter, dim); 1485d27abe6SValentin Clement return loadFromOffset(loc, box, c0, cDims, dimValue, kDimStridePos, idxTy, 1495d27abe6SValentin Clement rewriter); 1505d27abe6SValentin Clement } 1515d27abe6SValentin Clement 152df3b9810SValentin Clement /// Read base address from a fir.box. Returned address has type ty. 153df3b9810SValentin Clement mlir::Value 154df3b9810SValentin Clement loadBaseAddrFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box, 155df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 156df3b9810SValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 157df3b9810SValentin Clement mlir::LLVM::ConstantOp cAddr = 158df3b9810SValentin Clement genConstantOffset(loc, rewriter, kAddrPosInBox); 159df3b9810SValentin Clement auto pty = mlir::LLVM::LLVMPointerType::get(ty); 160df3b9810SValentin Clement mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cAddr); 161df3b9810SValentin Clement return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p); 162df3b9810SValentin Clement } 163df3b9810SValentin Clement 164df3b9810SValentin Clement mlir::Value 165df3b9810SValentin Clement loadElementSizeFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box, 166df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 167df3b9810SValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 168df3b9810SValentin Clement mlir::LLVM::ConstantOp cElemLen = 169df3b9810SValentin Clement genConstantOffset(loc, rewriter, kElemLenPosInBox); 170df3b9810SValentin Clement auto pty = mlir::LLVM::LLVMPointerType::get(ty); 171df3b9810SValentin Clement mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cElemLen); 172df3b9810SValentin Clement return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p); 173df3b9810SValentin Clement } 174df3b9810SValentin Clement 175b6e44ecdSValentin Clement // Load the attribute from the \p box and perform a check against \p maskValue 176b6e44ecdSValentin Clement // The final comparison is implemented as `(attribute & maskValue) != 0`. 177b6e44ecdSValentin Clement mlir::Value genBoxAttributeCheck(mlir::Location loc, mlir::Value box, 178b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter, 179b6e44ecdSValentin Clement unsigned maskValue) const { 180b6e44ecdSValentin Clement mlir::Type attrTy = rewriter.getI32Type(); 181b6e44ecdSValentin Clement mlir::Value attribute = 182b6e44ecdSValentin Clement getValueFromBox(loc, box, attrTy, rewriter, kAttributePosInBox); 183b6e44ecdSValentin Clement mlir::LLVM::ConstantOp attrMask = 184b6e44ecdSValentin Clement genConstantOffset(loc, rewriter, maskValue); 185b6e44ecdSValentin Clement auto maskRes = 186b6e44ecdSValentin Clement rewriter.create<mlir::LLVM::AndOp>(loc, attrTy, attribute, attrMask); 187b6e44ecdSValentin Clement mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0); 188b6e44ecdSValentin Clement return rewriter.create<mlir::LLVM::ICmpOp>( 189b6e44ecdSValentin Clement loc, mlir::LLVM::ICmpPredicate::ne, maskRes, c0); 190b6e44ecdSValentin Clement } 191b6e44ecdSValentin Clement 192af6ee580SValentin Clement // Get the element type given an LLVM type that is of the form 193af6ee580SValentin Clement // [llvm.ptr](array|struct|vector)+ and the provided indexes. 194af6ee580SValentin Clement static mlir::Type getBoxEleTy(mlir::Type type, 195af6ee580SValentin Clement llvm::ArrayRef<unsigned> indexes) { 196af6ee580SValentin Clement if (auto t = type.dyn_cast<mlir::LLVM::LLVMPointerType>()) 197af6ee580SValentin Clement type = t.getElementType(); 198af6ee580SValentin Clement for (auto i : indexes) { 199af6ee580SValentin Clement if (auto t = type.dyn_cast<mlir::LLVM::LLVMStructType>()) { 200af6ee580SValentin Clement assert(!t.isOpaque() && i < t.getBody().size()); 201af6ee580SValentin Clement type = t.getBody()[i]; 202af6ee580SValentin Clement } else if (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) { 203af6ee580SValentin Clement type = t.getElementType(); 204af6ee580SValentin Clement } else if (auto t = type.dyn_cast<mlir::VectorType>()) { 205af6ee580SValentin Clement type = t.getElementType(); 206af6ee580SValentin Clement } else { 207af6ee580SValentin Clement fir::emitFatalError(mlir::UnknownLoc::get(type.getContext()), 208af6ee580SValentin Clement "request for invalid box element type"); 209af6ee580SValentin Clement } 210af6ee580SValentin Clement } 211af6ee580SValentin Clement return type; 212af6ee580SValentin Clement } 213af6ee580SValentin Clement 2145d27abe6SValentin Clement // Return LLVM type of the base address given the LLVM type 2155d27abe6SValentin Clement // of the related descriptor (lowered fir.box type). 2165d27abe6SValentin Clement static mlir::Type getBaseAddrTypeFromBox(mlir::Type type) { 2175d27abe6SValentin Clement return getBoxEleTy(type, {kAddrPosInBox}); 2185d27abe6SValentin Clement } 2195d27abe6SValentin Clement 220df3b9810SValentin Clement template <typename... ARGS> 221df3b9810SValentin Clement mlir::LLVM::GEPOp genGEP(mlir::Location loc, mlir::Type ty, 222df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter, 223df3b9810SValentin Clement mlir::Value base, ARGS... args) const { 224df3b9810SValentin Clement SmallVector<mlir::Value> cv{args...}; 225df3b9810SValentin Clement return rewriter.create<mlir::LLVM::GEPOp>(loc, ty, base, cv); 226df3b9810SValentin Clement } 227df3b9810SValentin Clement 2281e6d9c06SDiana Picus /// Perform an extension or truncation as needed on an integer value. Lowering 2291e6d9c06SDiana Picus /// to the specific target may involve some sign-extending or truncation of 2301e6d9c06SDiana Picus /// values, particularly to fit them from abstract box types to the 2311e6d9c06SDiana Picus /// appropriate reified structures. 2321e6d9c06SDiana Picus mlir::Value integerCast(mlir::Location loc, 2331e6d9c06SDiana Picus mlir::ConversionPatternRewriter &rewriter, 2341e6d9c06SDiana Picus mlir::Type ty, mlir::Value val) const { 2351e6d9c06SDiana Picus auto valTy = val.getType(); 2361e6d9c06SDiana Picus // If the value was not yet lowered, lower its type so that it can 2371e6d9c06SDiana Picus // be used in getPrimitiveTypeSizeInBits. 2381e6d9c06SDiana Picus if (!valTy.isa<mlir::IntegerType>()) 2391e6d9c06SDiana Picus valTy = convertType(valTy); 2401e6d9c06SDiana Picus auto toSize = mlir::LLVM::getPrimitiveTypeSizeInBits(ty); 2411e6d9c06SDiana Picus auto fromSize = mlir::LLVM::getPrimitiveTypeSizeInBits(valTy); 2421e6d9c06SDiana Picus if (toSize < fromSize) 2431e6d9c06SDiana Picus return rewriter.create<mlir::LLVM::TruncOp>(loc, ty, val); 2441e6d9c06SDiana Picus if (toSize > fromSize) 2451e6d9c06SDiana Picus return rewriter.create<mlir::LLVM::SExtOp>(loc, ty, val); 2461e6d9c06SDiana Picus return val; 2471e6d9c06SDiana Picus } 2481e6d9c06SDiana Picus 249044d5b5dSValentin Clement fir::LLVMTypeConverter &lowerTy() const { 250044d5b5dSValentin Clement return *static_cast<fir::LLVMTypeConverter *>(this->getTypeConverter()); 251044d5b5dSValentin Clement } 252044d5b5dSValentin Clement }; 253044d5b5dSValentin Clement 2543ae8e442SValentin Clement /// FIR conversion pattern template 2553ae8e442SValentin Clement template <typename FromOp> 2563ae8e442SValentin Clement class FIROpAndTypeConversion : public FIROpConversion<FromOp> { 2573ae8e442SValentin Clement public: 2583ae8e442SValentin Clement using FIROpConversion<FromOp>::FIROpConversion; 2593ae8e442SValentin Clement using OpAdaptor = typename FromOp::Adaptor; 2603ae8e442SValentin Clement 2613ae8e442SValentin Clement mlir::LogicalResult 2623ae8e442SValentin Clement matchAndRewrite(FromOp op, OpAdaptor adaptor, 2633ae8e442SValentin Clement mlir::ConversionPatternRewriter &rewriter) const final { 2643ae8e442SValentin Clement mlir::Type ty = this->convertType(op.getType()); 2653ae8e442SValentin Clement return doRewrite(op, ty, adaptor, rewriter); 2663ae8e442SValentin Clement } 2673ae8e442SValentin Clement 2683ae8e442SValentin Clement virtual mlir::LogicalResult 2693ae8e442SValentin Clement doRewrite(FromOp addr, mlir::Type ty, OpAdaptor adaptor, 2703ae8e442SValentin Clement mlir::ConversionPatternRewriter &rewriter) const = 0; 2713ae8e442SValentin Clement }; 2723ae8e442SValentin Clement 273420ad7ceSAndrzej Warzynski /// Create value signaling an absent optional argument in a call, e.g. 274420ad7ceSAndrzej Warzynski /// `fir.absent !fir.ref<i64>` --> `llvm.mlir.null : !llvm.ptr<i64>` 275420ad7ceSAndrzej Warzynski struct AbsentOpConversion : public FIROpConversion<fir::AbsentOp> { 276420ad7ceSAndrzej Warzynski using FIROpConversion::FIROpConversion; 277420ad7ceSAndrzej Warzynski 278420ad7ceSAndrzej Warzynski mlir::LogicalResult 279420ad7ceSAndrzej Warzynski matchAndRewrite(fir::AbsentOp absent, OpAdaptor, 280420ad7ceSAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 281420ad7ceSAndrzej Warzynski mlir::Type ty = convertType(absent.getType()); 282420ad7ceSAndrzej Warzynski mlir::Location loc = absent.getLoc(); 283420ad7ceSAndrzej Warzynski 284420ad7ceSAndrzej Warzynski if (absent.getType().isa<fir::BoxCharType>()) { 285420ad7ceSAndrzej Warzynski auto structTy = ty.cast<mlir::LLVM::LLVMStructType>(); 286420ad7ceSAndrzej Warzynski assert(!structTy.isOpaque() && !structTy.getBody().empty()); 287420ad7ceSAndrzej Warzynski auto undefStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 288420ad7ceSAndrzej Warzynski auto nullField = 289420ad7ceSAndrzej Warzynski rewriter.create<mlir::LLVM::NullOp>(loc, structTy.getBody()[0]); 290420ad7ceSAndrzej Warzynski mlir::MLIRContext *ctx = absent.getContext(); 291420ad7ceSAndrzej Warzynski auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 292420ad7ceSAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 293420ad7ceSAndrzej Warzynski absent, ty, undefStruct, nullField, c0); 294420ad7ceSAndrzej Warzynski } else { 295420ad7ceSAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(absent, ty); 296420ad7ceSAndrzej Warzynski } 297420ad7ceSAndrzej Warzynski return success(); 298420ad7ceSAndrzej Warzynski } 299420ad7ceSAndrzej Warzynski }; 300420ad7ceSAndrzej Warzynski 3010c4a7a52SValentin Clement // Lower `fir.address_of` operation to `llvm.address_of` operation. 302044d5b5dSValentin Clement struct AddrOfOpConversion : public FIROpConversion<fir::AddrOfOp> { 303044d5b5dSValentin Clement using FIROpConversion::FIROpConversion; 304044d5b5dSValentin Clement 305044d5b5dSValentin Clement mlir::LogicalResult 306044d5b5dSValentin Clement matchAndRewrite(fir::AddrOfOp addr, OpAdaptor adaptor, 307044d5b5dSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 308044d5b5dSValentin Clement auto ty = convertType(addr.getType()); 309044d5b5dSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::AddressOfOp>( 310044d5b5dSValentin Clement addr, ty, addr.symbol().getRootReference().getValue()); 311044d5b5dSValentin Clement return success(); 312044d5b5dSValentin Clement } 313044d5b5dSValentin Clement }; 3141e6d9c06SDiana Picus } // namespace 3151e6d9c06SDiana Picus 3161e6d9c06SDiana Picus /// Lookup the function to compute the memory size of this parametric derived 3171e6d9c06SDiana Picus /// type. The size of the object may depend on the LEN type parameters of the 3181e6d9c06SDiana Picus /// derived type. 3191e6d9c06SDiana Picus static mlir::LLVM::LLVMFuncOp 3201e6d9c06SDiana Picus getDependentTypeMemSizeFn(fir::RecordType recTy, fir::AllocaOp op, 3211e6d9c06SDiana Picus mlir::ConversionPatternRewriter &rewriter) { 3221e6d9c06SDiana Picus auto module = op->getParentOfType<mlir::ModuleOp>(); 3231e6d9c06SDiana Picus std::string name = recTy.getName().str() + "P.mem.size"; 3241e6d9c06SDiana Picus return module.lookupSymbol<mlir::LLVM::LLVMFuncOp>(name); 3251e6d9c06SDiana Picus } 3261e6d9c06SDiana Picus 3271e6d9c06SDiana Picus namespace { 3281e6d9c06SDiana Picus /// convert to LLVM IR dialect `alloca` 3291e6d9c06SDiana Picus struct AllocaOpConversion : public FIROpConversion<fir::AllocaOp> { 3301e6d9c06SDiana Picus using FIROpConversion::FIROpConversion; 3311e6d9c06SDiana Picus 3321e6d9c06SDiana Picus mlir::LogicalResult 3331e6d9c06SDiana Picus matchAndRewrite(fir::AllocaOp alloc, OpAdaptor adaptor, 3341e6d9c06SDiana Picus mlir::ConversionPatternRewriter &rewriter) const override { 3351e6d9c06SDiana Picus mlir::ValueRange operands = adaptor.getOperands(); 3361e6d9c06SDiana Picus auto loc = alloc.getLoc(); 3371e6d9c06SDiana Picus mlir::Type ity = lowerTy().indexType(); 3381e6d9c06SDiana Picus unsigned i = 0; 3391e6d9c06SDiana Picus mlir::Value size = genConstantIndex(loc, ity, rewriter, 1).getResult(); 3401e6d9c06SDiana Picus mlir::Type ty = convertType(alloc.getType()); 3411e6d9c06SDiana Picus mlir::Type resultTy = ty; 3421e6d9c06SDiana Picus if (alloc.hasLenParams()) { 3431e6d9c06SDiana Picus unsigned end = alloc.numLenParams(); 3441e6d9c06SDiana Picus llvm::SmallVector<mlir::Value> lenParams; 3451e6d9c06SDiana Picus for (; i < end; ++i) 3461e6d9c06SDiana Picus lenParams.push_back(operands[i]); 3471e6d9c06SDiana Picus mlir::Type scalarType = fir::unwrapSequenceType(alloc.getInType()); 3481e6d9c06SDiana Picus if (auto chrTy = scalarType.dyn_cast<fir::CharacterType>()) { 3491e6d9c06SDiana Picus fir::CharacterType rawCharTy = fir::CharacterType::getUnknownLen( 3501e6d9c06SDiana Picus chrTy.getContext(), chrTy.getFKind()); 3511e6d9c06SDiana Picus ty = mlir::LLVM::LLVMPointerType::get(convertType(rawCharTy)); 3521e6d9c06SDiana Picus assert(end == 1); 3531e6d9c06SDiana Picus size = integerCast(loc, rewriter, ity, lenParams[0]); 3541e6d9c06SDiana Picus } else if (auto recTy = scalarType.dyn_cast<fir::RecordType>()) { 3551e6d9c06SDiana Picus mlir::LLVM::LLVMFuncOp memSizeFn = 3561e6d9c06SDiana Picus getDependentTypeMemSizeFn(recTy, alloc, rewriter); 3571e6d9c06SDiana Picus if (!memSizeFn) 3581e6d9c06SDiana Picus emitError(loc, "did not find allocation function"); 3591e6d9c06SDiana Picus mlir::NamedAttribute attr = rewriter.getNamedAttr( 3601e6d9c06SDiana Picus "callee", mlir::SymbolRefAttr::get(memSizeFn)); 3611e6d9c06SDiana Picus auto call = rewriter.create<mlir::LLVM::CallOp>( 3621e6d9c06SDiana Picus loc, ity, lenParams, llvm::ArrayRef<mlir::NamedAttribute>{attr}); 3631e6d9c06SDiana Picus size = call.getResult(0); 3641e6d9c06SDiana Picus ty = mlir::LLVM::LLVMPointerType::get( 3651e6d9c06SDiana Picus mlir::IntegerType::get(alloc.getContext(), 8)); 3661e6d9c06SDiana Picus } else { 3671e6d9c06SDiana Picus return emitError(loc, "unexpected type ") 3681e6d9c06SDiana Picus << scalarType << " with type parameters"; 3691e6d9c06SDiana Picus } 3701e6d9c06SDiana Picus } 3711e6d9c06SDiana Picus if (alloc.hasShapeOperands()) { 3721e6d9c06SDiana Picus mlir::Type allocEleTy = fir::unwrapRefType(alloc.getType()); 3731e6d9c06SDiana Picus // Scale the size by constant factors encoded in the array type. 374776d0ed6SDiana Picus // We only do this for arrays that don't have a constant interior, since 375776d0ed6SDiana Picus // those are the only ones that get decayed to a pointer to the element 376776d0ed6SDiana Picus // type. 3771e6d9c06SDiana Picus if (auto seqTy = allocEleTy.dyn_cast<fir::SequenceType>()) { 378776d0ed6SDiana Picus if (!seqTy.hasConstantInterior()) { 3791e6d9c06SDiana Picus fir::SequenceType::Extent constSize = 1; 3801e6d9c06SDiana Picus for (auto extent : seqTy.getShape()) 3811e6d9c06SDiana Picus if (extent != fir::SequenceType::getUnknownExtent()) 3821e6d9c06SDiana Picus constSize *= extent; 3831e6d9c06SDiana Picus mlir::Value constVal{ 3841e6d9c06SDiana Picus genConstantIndex(loc, ity, rewriter, constSize).getResult()}; 3851e6d9c06SDiana Picus size = rewriter.create<mlir::LLVM::MulOp>(loc, ity, size, constVal); 3861e6d9c06SDiana Picus } 387776d0ed6SDiana Picus } 3881e6d9c06SDiana Picus unsigned end = operands.size(); 3891e6d9c06SDiana Picus for (; i < end; ++i) 3901e6d9c06SDiana Picus size = rewriter.create<mlir::LLVM::MulOp>( 3911e6d9c06SDiana Picus loc, ity, size, integerCast(loc, rewriter, ity, operands[i])); 3921e6d9c06SDiana Picus } 3931e6d9c06SDiana Picus if (ty == resultTy) { 3941e6d9c06SDiana Picus // Do not emit the bitcast if ty and resultTy are the same. 3951e6d9c06SDiana Picus rewriter.replaceOpWithNewOp<mlir::LLVM::AllocaOp>(alloc, ty, size, 3961e6d9c06SDiana Picus alloc->getAttrs()); 3971e6d9c06SDiana Picus } else { 3981e6d9c06SDiana Picus auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, ty, size, 3991e6d9c06SDiana Picus alloc->getAttrs()); 4001e6d9c06SDiana Picus rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(alloc, resultTy, al); 4011e6d9c06SDiana Picus } 4021e6d9c06SDiana Picus return success(); 4031e6d9c06SDiana Picus } 4041e6d9c06SDiana Picus }; 405044d5b5dSValentin Clement 406df3b9810SValentin Clement /// Lower `fir.box_addr` to the sequence of operations to extract the first 407df3b9810SValentin Clement /// element of the box. 408df3b9810SValentin Clement struct BoxAddrOpConversion : public FIROpConversion<fir::BoxAddrOp> { 409df3b9810SValentin Clement using FIROpConversion::FIROpConversion; 410df3b9810SValentin Clement 411df3b9810SValentin Clement mlir::LogicalResult 412df3b9810SValentin Clement matchAndRewrite(fir::BoxAddrOp boxaddr, OpAdaptor adaptor, 413df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 414df3b9810SValentin Clement mlir::Value a = adaptor.getOperands()[0]; 415df3b9810SValentin Clement auto loc = boxaddr.getLoc(); 416df3b9810SValentin Clement mlir::Type ty = convertType(boxaddr.getType()); 417df3b9810SValentin Clement if (auto argty = boxaddr.val().getType().dyn_cast<fir::BoxType>()) { 418df3b9810SValentin Clement rewriter.replaceOp(boxaddr, loadBaseAddrFromBox(loc, ty, a, rewriter)); 419df3b9810SValentin Clement } else { 420df3b9810SValentin Clement auto c0attr = rewriter.getI32IntegerAttr(0); 421df3b9810SValentin Clement auto c0 = mlir::ArrayAttr::get(boxaddr.getContext(), c0attr); 422df3b9810SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(boxaddr, ty, a, 423df3b9810SValentin Clement c0); 424df3b9810SValentin Clement } 425df3b9810SValentin Clement return success(); 426df3b9810SValentin Clement } 427df3b9810SValentin Clement }; 428df3b9810SValentin Clement 429df3b9810SValentin Clement /// Lower `fir.box_dims` to a sequence of operations to extract the requested 430df3b9810SValentin Clement /// dimension infomartion from the boxed value. 431df3b9810SValentin Clement /// Result in a triple set of GEPs and loads. 432df3b9810SValentin Clement struct BoxDimsOpConversion : public FIROpConversion<fir::BoxDimsOp> { 433df3b9810SValentin Clement using FIROpConversion::FIROpConversion; 434df3b9810SValentin Clement 435df3b9810SValentin Clement mlir::LogicalResult 436df3b9810SValentin Clement matchAndRewrite(fir::BoxDimsOp boxdims, OpAdaptor adaptor, 437df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 438df3b9810SValentin Clement SmallVector<mlir::Type, 3> resultTypes = { 439df3b9810SValentin Clement convertType(boxdims.getResult(0).getType()), 440df3b9810SValentin Clement convertType(boxdims.getResult(1).getType()), 441df3b9810SValentin Clement convertType(boxdims.getResult(2).getType()), 442df3b9810SValentin Clement }; 443df3b9810SValentin Clement auto results = 444df3b9810SValentin Clement getDimsFromBox(boxdims.getLoc(), resultTypes, adaptor.getOperands()[0], 445df3b9810SValentin Clement adaptor.getOperands()[1], rewriter); 446df3b9810SValentin Clement rewriter.replaceOp(boxdims, results); 447df3b9810SValentin Clement return success(); 448df3b9810SValentin Clement } 449df3b9810SValentin Clement }; 450df3b9810SValentin Clement 451df3b9810SValentin Clement /// Lower `fir.box_elesize` to a sequence of operations ro extract the size of 452df3b9810SValentin Clement /// an element in the boxed value. 453df3b9810SValentin Clement struct BoxEleSizeOpConversion : public FIROpConversion<fir::BoxEleSizeOp> { 454df3b9810SValentin Clement using FIROpConversion::FIROpConversion; 455df3b9810SValentin Clement 456df3b9810SValentin Clement mlir::LogicalResult 457df3b9810SValentin Clement matchAndRewrite(fir::BoxEleSizeOp boxelesz, OpAdaptor adaptor, 458df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 459df3b9810SValentin Clement mlir::Value a = adaptor.getOperands()[0]; 460df3b9810SValentin Clement auto loc = boxelesz.getLoc(); 461df3b9810SValentin Clement auto ty = convertType(boxelesz.getType()); 462b6e44ecdSValentin Clement auto elemSize = getValueFromBox(loc, a, ty, rewriter, kElemLenPosInBox); 463b6e44ecdSValentin Clement rewriter.replaceOp(boxelesz, elemSize); 464b6e44ecdSValentin Clement return success(); 465b6e44ecdSValentin Clement } 466b6e44ecdSValentin Clement }; 467b6e44ecdSValentin Clement 468b6e44ecdSValentin Clement /// Lower `fir.box_isalloc` to a sequence of operations to determine if the 469b6e44ecdSValentin Clement /// boxed value was from an ALLOCATABLE entity. 470b6e44ecdSValentin Clement struct BoxIsAllocOpConversion : public FIROpConversion<fir::BoxIsAllocOp> { 471b6e44ecdSValentin Clement using FIROpConversion::FIROpConversion; 472b6e44ecdSValentin Clement 473b6e44ecdSValentin Clement mlir::LogicalResult 474b6e44ecdSValentin Clement matchAndRewrite(fir::BoxIsAllocOp boxisalloc, OpAdaptor adaptor, 475b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 476b6e44ecdSValentin Clement mlir::Value box = adaptor.getOperands()[0]; 477b6e44ecdSValentin Clement auto loc = boxisalloc.getLoc(); 478b6e44ecdSValentin Clement mlir::Value check = 479b6e44ecdSValentin Clement genBoxAttributeCheck(loc, box, rewriter, kAttrAllocatable); 480b6e44ecdSValentin Clement rewriter.replaceOp(boxisalloc, check); 481b6e44ecdSValentin Clement return success(); 482b6e44ecdSValentin Clement } 483b6e44ecdSValentin Clement }; 484b6e44ecdSValentin Clement 485b6e44ecdSValentin Clement /// Lower `fir.box_isarray` to a sequence of operations to determine if the 486b6e44ecdSValentin Clement /// boxed is an array. 487b6e44ecdSValentin Clement struct BoxIsArrayOpConversion : public FIROpConversion<fir::BoxIsArrayOp> { 488b6e44ecdSValentin Clement using FIROpConversion::FIROpConversion; 489b6e44ecdSValentin Clement 490b6e44ecdSValentin Clement mlir::LogicalResult 491b6e44ecdSValentin Clement matchAndRewrite(fir::BoxIsArrayOp boxisarray, OpAdaptor adaptor, 492b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 493b6e44ecdSValentin Clement mlir::Value a = adaptor.getOperands()[0]; 494b6e44ecdSValentin Clement auto loc = boxisarray.getLoc(); 495b6e44ecdSValentin Clement auto rank = 496b6e44ecdSValentin Clement getValueFromBox(loc, a, rewriter.getI32Type(), rewriter, kRankPosInBox); 497b6e44ecdSValentin Clement auto c0 = genConstantOffset(loc, rewriter, 0); 498b6e44ecdSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>( 499b6e44ecdSValentin Clement boxisarray, mlir::LLVM::ICmpPredicate::ne, rank, c0); 500b6e44ecdSValentin Clement return success(); 501b6e44ecdSValentin Clement } 502b6e44ecdSValentin Clement }; 503b6e44ecdSValentin Clement 504b6e44ecdSValentin Clement /// Lower `fir.box_isptr` to a sequence of operations to determined if the 505b6e44ecdSValentin Clement /// boxed value was from a POINTER entity. 506b6e44ecdSValentin Clement struct BoxIsPtrOpConversion : public FIROpConversion<fir::BoxIsPtrOp> { 507b6e44ecdSValentin Clement using FIROpConversion::FIROpConversion; 508b6e44ecdSValentin Clement 509b6e44ecdSValentin Clement mlir::LogicalResult 510b6e44ecdSValentin Clement matchAndRewrite(fir::BoxIsPtrOp boxisptr, OpAdaptor adaptor, 511b6e44ecdSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 512b6e44ecdSValentin Clement mlir::Value box = adaptor.getOperands()[0]; 513b6e44ecdSValentin Clement auto loc = boxisptr.getLoc(); 514b6e44ecdSValentin Clement mlir::Value check = genBoxAttributeCheck(loc, box, rewriter, kAttrPointer); 515b6e44ecdSValentin Clement rewriter.replaceOp(boxisptr, check); 516df3b9810SValentin Clement return success(); 517df3b9810SValentin Clement } 518df3b9810SValentin Clement }; 519df3b9810SValentin Clement 520df3b9810SValentin Clement /// Lower `fir.box_rank` to the sequence of operation to extract the rank from 521df3b9810SValentin Clement /// the box. 522df3b9810SValentin Clement struct BoxRankOpConversion : public FIROpConversion<fir::BoxRankOp> { 523df3b9810SValentin Clement using FIROpConversion::FIROpConversion; 524df3b9810SValentin Clement 525df3b9810SValentin Clement mlir::LogicalResult 526df3b9810SValentin Clement matchAndRewrite(fir::BoxRankOp boxrank, OpAdaptor adaptor, 527df3b9810SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 528df3b9810SValentin Clement mlir::Value a = adaptor.getOperands()[0]; 529df3b9810SValentin Clement auto loc = boxrank.getLoc(); 530df3b9810SValentin Clement mlir::Type ty = convertType(boxrank.getType()); 531b6e44ecdSValentin Clement auto result = getValueFromBox(loc, a, ty, rewriter, kRankPosInBox); 532df3b9810SValentin Clement rewriter.replaceOp(boxrank, result); 533df3b9810SValentin Clement return success(); 534df3b9810SValentin Clement } 535df3b9810SValentin Clement }; 536df3b9810SValentin Clement 5371a2ec667SValentin Clement /// Lower `fir.string_lit` to LLVM IR dialect operation. 5381a2ec667SValentin Clement struct StringLitOpConversion : public FIROpConversion<fir::StringLitOp> { 5391a2ec667SValentin Clement using FIROpConversion::FIROpConversion; 5401a2ec667SValentin Clement 5411a2ec667SValentin Clement mlir::LogicalResult 5421a2ec667SValentin Clement matchAndRewrite(fir::StringLitOp constop, OpAdaptor adaptor, 5431a2ec667SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 5441a2ec667SValentin Clement auto ty = convertType(constop.getType()); 5451a2ec667SValentin Clement auto attr = constop.getValue(); 5461a2ec667SValentin Clement if (attr.isa<mlir::StringAttr>()) { 5471a2ec667SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(constop, ty, attr); 5481a2ec667SValentin Clement return success(); 5491a2ec667SValentin Clement } 5501a2ec667SValentin Clement 5511a2ec667SValentin Clement auto arr = attr.cast<mlir::ArrayAttr>(); 5521a2ec667SValentin Clement auto charTy = constop.getType().cast<fir::CharacterType>(); 5531a2ec667SValentin Clement unsigned bits = lowerTy().characterBitsize(charTy); 5541a2ec667SValentin Clement mlir::Type intTy = rewriter.getIntegerType(bits); 5551a2ec667SValentin Clement auto attrs = llvm::map_range( 5561a2ec667SValentin Clement arr.getValue(), [intTy, bits](mlir::Attribute attr) -> Attribute { 5571a2ec667SValentin Clement return mlir::IntegerAttr::get( 5581a2ec667SValentin Clement intTy, 5591a2ec667SValentin Clement attr.cast<mlir::IntegerAttr>().getValue().sextOrTrunc(bits)); 5601a2ec667SValentin Clement }); 5611a2ec667SValentin Clement mlir::Type vecType = mlir::VectorType::get(arr.size(), intTy); 5621a2ec667SValentin Clement auto denseAttr = mlir::DenseElementsAttr::get( 5631a2ec667SValentin Clement vecType.cast<mlir::ShapedType>(), llvm::to_vector<8>(attrs)); 5641a2ec667SValentin Clement rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(constop, ty, 5651a2ec667SValentin Clement denseAttr); 5661a2ec667SValentin Clement return success(); 5671a2ec667SValentin Clement } 5681a2ec667SValentin Clement }; 5691a2ec667SValentin Clement 570cc505c0bSKiran Chandramohan /// Lower `fir.boxproc_host` operation. Extracts the host pointer from the 571cc505c0bSKiran Chandramohan /// boxproc. 572cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers. 573cc505c0bSKiran Chandramohan struct BoxProcHostOpConversion : public FIROpConversion<fir::BoxProcHostOp> { 574cc505c0bSKiran Chandramohan using FIROpConversion::FIROpConversion; 575cc505c0bSKiran Chandramohan 576cc505c0bSKiran Chandramohan mlir::LogicalResult 577cc505c0bSKiran Chandramohan matchAndRewrite(fir::BoxProcHostOp boxprochost, OpAdaptor adaptor, 578cc505c0bSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 5797ce8c6fcSKiran Chandramohan TODO(boxprochost.getLoc(), "fir.boxproc_host codegen"); 5807ce8c6fcSKiran Chandramohan return failure(); 581cc505c0bSKiran Chandramohan } 582cc505c0bSKiran Chandramohan }; 583cc505c0bSKiran Chandramohan 584e38ef2ffSValentin Clement /// Lower `fir.box_tdesc` to the sequence of operations to extract the type 585e38ef2ffSValentin Clement /// descriptor from the box. 586e38ef2ffSValentin Clement struct BoxTypeDescOpConversion : public FIROpConversion<fir::BoxTypeDescOp> { 587e38ef2ffSValentin Clement using FIROpConversion::FIROpConversion; 588e38ef2ffSValentin Clement 589e38ef2ffSValentin Clement mlir::LogicalResult 590e38ef2ffSValentin Clement matchAndRewrite(fir::BoxTypeDescOp boxtypedesc, OpAdaptor adaptor, 591e38ef2ffSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 592e38ef2ffSValentin Clement mlir::Value box = adaptor.getOperands()[0]; 593e38ef2ffSValentin Clement auto loc = boxtypedesc.getLoc(); 594e38ef2ffSValentin Clement mlir::Type typeTy = 595e38ef2ffSValentin Clement fir::getDescFieldTypeModel<kTypePosInBox>()(boxtypedesc.getContext()); 596e38ef2ffSValentin Clement auto result = getValueFromBox(loc, box, typeTy, rewriter, kTypePosInBox); 597e38ef2ffSValentin Clement auto typePtrTy = mlir::LLVM::LLVMPointerType::get(typeTy); 598e38ef2ffSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(boxtypedesc, typePtrTy, 599e38ef2ffSValentin Clement result); 600e38ef2ffSValentin Clement return success(); 601e38ef2ffSValentin Clement } 602e38ef2ffSValentin Clement }; 603e38ef2ffSValentin Clement 604ddd11b9aSAndrzej Warzynski // `fir.call` -> `llvm.call` 605ddd11b9aSAndrzej Warzynski struct CallOpConversion : public FIROpConversion<fir::CallOp> { 606ddd11b9aSAndrzej Warzynski using FIROpConversion::FIROpConversion; 607ddd11b9aSAndrzej Warzynski 608ddd11b9aSAndrzej Warzynski mlir::LogicalResult 609ddd11b9aSAndrzej Warzynski matchAndRewrite(fir::CallOp call, OpAdaptor adaptor, 610ddd11b9aSAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 611ddd11b9aSAndrzej Warzynski SmallVector<mlir::Type> resultTys; 612ddd11b9aSAndrzej Warzynski for (auto r : call.getResults()) 613ddd11b9aSAndrzej Warzynski resultTys.push_back(convertType(r.getType())); 614ddd11b9aSAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>( 615ddd11b9aSAndrzej Warzynski call, resultTys, adaptor.getOperands(), call->getAttrs()); 616ddd11b9aSAndrzej Warzynski return success(); 617ddd11b9aSAndrzej Warzynski } 618ddd11b9aSAndrzej Warzynski }; 619c2acd453SAlexisPerry } // namespace 620ddd11b9aSAndrzej Warzynski 621092cee5fSValentin Clement static mlir::Type getComplexEleTy(mlir::Type complex) { 622092cee5fSValentin Clement if (auto cc = complex.dyn_cast<mlir::ComplexType>()) 623092cee5fSValentin Clement return cc.getElementType(); 624092cee5fSValentin Clement return complex.cast<fir::ComplexType>().getElementType(); 625092cee5fSValentin Clement } 626092cee5fSValentin Clement 627c2acd453SAlexisPerry namespace { 628f1dfc027SDiana Picus /// Compare complex values 629f1dfc027SDiana Picus /// 630f1dfc027SDiana Picus /// Per 10.1, the only comparisons available are .EQ. (oeq) and .NE. (une). 631f1dfc027SDiana Picus /// 632f1dfc027SDiana Picus /// For completeness, all other comparison are done on the real component only. 633f1dfc027SDiana Picus struct CmpcOpConversion : public FIROpConversion<fir::CmpcOp> { 634f1dfc027SDiana Picus using FIROpConversion::FIROpConversion; 635f1dfc027SDiana Picus 636f1dfc027SDiana Picus mlir::LogicalResult 637f1dfc027SDiana Picus matchAndRewrite(fir::CmpcOp cmp, OpAdaptor adaptor, 638f1dfc027SDiana Picus mlir::ConversionPatternRewriter &rewriter) const override { 639f1dfc027SDiana Picus mlir::ValueRange operands = adaptor.getOperands(); 640f1dfc027SDiana Picus mlir::MLIRContext *ctxt = cmp.getContext(); 641f1dfc027SDiana Picus mlir::Type eleTy = convertType(getComplexEleTy(cmp.lhs().getType())); 642f1dfc027SDiana Picus mlir::Type resTy = convertType(cmp.getType()); 643f1dfc027SDiana Picus mlir::Location loc = cmp.getLoc(); 644f1dfc027SDiana Picus auto pos0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0)); 645f1dfc027SDiana Picus SmallVector<mlir::Value, 2> rp{rewriter.create<mlir::LLVM::ExtractValueOp>( 646f1dfc027SDiana Picus loc, eleTy, operands[0], pos0), 647f1dfc027SDiana Picus rewriter.create<mlir::LLVM::ExtractValueOp>( 648f1dfc027SDiana Picus loc, eleTy, operands[1], pos0)}; 649f1dfc027SDiana Picus auto rcp = 650f1dfc027SDiana Picus rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, rp, cmp->getAttrs()); 651f1dfc027SDiana Picus auto pos1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1)); 652f1dfc027SDiana Picus SmallVector<mlir::Value, 2> ip{rewriter.create<mlir::LLVM::ExtractValueOp>( 653f1dfc027SDiana Picus loc, eleTy, operands[0], pos1), 654f1dfc027SDiana Picus rewriter.create<mlir::LLVM::ExtractValueOp>( 655f1dfc027SDiana Picus loc, eleTy, operands[1], pos1)}; 656f1dfc027SDiana Picus auto icp = 657f1dfc027SDiana Picus rewriter.create<mlir::LLVM::FCmpOp>(loc, resTy, ip, cmp->getAttrs()); 658f1dfc027SDiana Picus SmallVector<mlir::Value, 2> cp{rcp, icp}; 659f1dfc027SDiana Picus switch (cmp.getPredicate()) { 660f1dfc027SDiana Picus case mlir::arith::CmpFPredicate::OEQ: // .EQ. 661f1dfc027SDiana Picus rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(cmp, resTy, cp); 662f1dfc027SDiana Picus break; 663f1dfc027SDiana Picus case mlir::arith::CmpFPredicate::UNE: // .NE. 664f1dfc027SDiana Picus rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(cmp, resTy, cp); 665f1dfc027SDiana Picus break; 666f1dfc027SDiana Picus default: 667f1dfc027SDiana Picus rewriter.replaceOp(cmp, rcp.getResult()); 668f1dfc027SDiana Picus break; 669f1dfc027SDiana Picus } 670f1dfc027SDiana Picus return success(); 671f1dfc027SDiana Picus } 672f1dfc027SDiana Picus }; 673f1dfc027SDiana Picus 674e81d73edSDiana Picus /// Lower complex constants 675e81d73edSDiana Picus struct ConstcOpConversion : public FIROpConversion<fir::ConstcOp> { 676e81d73edSDiana Picus using FIROpConversion::FIROpConversion; 677e81d73edSDiana Picus 678e81d73edSDiana Picus mlir::LogicalResult 679e81d73edSDiana Picus matchAndRewrite(fir::ConstcOp conc, OpAdaptor, 680e81d73edSDiana Picus mlir::ConversionPatternRewriter &rewriter) const override { 681e81d73edSDiana Picus mlir::Location loc = conc.getLoc(); 682e81d73edSDiana Picus mlir::MLIRContext *ctx = conc.getContext(); 683e81d73edSDiana Picus mlir::Type ty = convertType(conc.getType()); 684e81d73edSDiana Picus mlir::Type ety = convertType(getComplexEleTy(conc.getType())); 685e81d73edSDiana Picus auto realFloatAttr = mlir::FloatAttr::get(ety, getValue(conc.getReal())); 686e81d73edSDiana Picus auto realPart = 687e81d73edSDiana Picus rewriter.create<mlir::LLVM::ConstantOp>(loc, ety, realFloatAttr); 688e81d73edSDiana Picus auto imFloatAttr = mlir::FloatAttr::get(ety, getValue(conc.getImaginary())); 689e81d73edSDiana Picus auto imPart = 690e81d73edSDiana Picus rewriter.create<mlir::LLVM::ConstantOp>(loc, ety, imFloatAttr); 691e81d73edSDiana Picus auto realIndex = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 692e81d73edSDiana Picus auto imIndex = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 693e81d73edSDiana Picus auto undef = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 694e81d73edSDiana Picus auto setReal = rewriter.create<mlir::LLVM::InsertValueOp>( 695e81d73edSDiana Picus loc, ty, undef, realPart, realIndex); 696e81d73edSDiana Picus rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(conc, ty, setReal, 697e81d73edSDiana Picus imPart, imIndex); 698e81d73edSDiana Picus return success(); 699e81d73edSDiana Picus } 700e81d73edSDiana Picus 701e81d73edSDiana Picus inline APFloat getValue(mlir::Attribute attr) const { 702e81d73edSDiana Picus return attr.cast<fir::RealAttr>().getValue(); 703e81d73edSDiana Picus } 704e81d73edSDiana Picus }; 705e81d73edSDiana Picus 706092cee5fSValentin Clement /// convert value of from-type to value of to-type 707092cee5fSValentin Clement struct ConvertOpConversion : public FIROpConversion<fir::ConvertOp> { 708092cee5fSValentin Clement using FIROpConversion::FIROpConversion; 709092cee5fSValentin Clement 710092cee5fSValentin Clement static bool isFloatingPointTy(mlir::Type ty) { 711092cee5fSValentin Clement return ty.isa<mlir::FloatType>(); 712092cee5fSValentin Clement } 713092cee5fSValentin Clement 714092cee5fSValentin Clement mlir::LogicalResult 715092cee5fSValentin Clement matchAndRewrite(fir::ConvertOp convert, OpAdaptor adaptor, 716092cee5fSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 717092cee5fSValentin Clement auto fromTy = convertType(convert.value().getType()); 718092cee5fSValentin Clement auto toTy = convertType(convert.res().getType()); 719092cee5fSValentin Clement mlir::Value op0 = adaptor.getOperands()[0]; 720092cee5fSValentin Clement if (fromTy == toTy) { 721092cee5fSValentin Clement rewriter.replaceOp(convert, op0); 722092cee5fSValentin Clement return success(); 723092cee5fSValentin Clement } 724092cee5fSValentin Clement auto loc = convert.getLoc(); 725092cee5fSValentin Clement auto convertFpToFp = [&](mlir::Value val, unsigned fromBits, 726092cee5fSValentin Clement unsigned toBits, mlir::Type toTy) -> mlir::Value { 727092cee5fSValentin Clement if (fromBits == toBits) { 728092cee5fSValentin Clement // TODO: Converting between two floating-point representations with the 729092cee5fSValentin Clement // same bitwidth is not allowed for now. 730092cee5fSValentin Clement mlir::emitError(loc, 731092cee5fSValentin Clement "cannot implicitly convert between two floating-point " 732092cee5fSValentin Clement "representations of the same bitwidth"); 733092cee5fSValentin Clement return {}; 734092cee5fSValentin Clement } 735092cee5fSValentin Clement if (fromBits > toBits) 736092cee5fSValentin Clement return rewriter.create<mlir::LLVM::FPTruncOp>(loc, toTy, val); 737092cee5fSValentin Clement return rewriter.create<mlir::LLVM::FPExtOp>(loc, toTy, val); 738092cee5fSValentin Clement }; 739092cee5fSValentin Clement // Complex to complex conversion. 740092cee5fSValentin Clement if (fir::isa_complex(convert.value().getType()) && 741092cee5fSValentin Clement fir::isa_complex(convert.res().getType())) { 742092cee5fSValentin Clement // Special case: handle the conversion of a complex such that both the 743092cee5fSValentin Clement // real and imaginary parts are converted together. 744092cee5fSValentin Clement auto zero = mlir::ArrayAttr::get(convert.getContext(), 745092cee5fSValentin Clement rewriter.getI32IntegerAttr(0)); 746092cee5fSValentin Clement auto one = mlir::ArrayAttr::get(convert.getContext(), 747092cee5fSValentin Clement rewriter.getI32IntegerAttr(1)); 748092cee5fSValentin Clement auto ty = convertType(getComplexEleTy(convert.value().getType())); 749092cee5fSValentin Clement auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, zero); 750092cee5fSValentin Clement auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, one); 751092cee5fSValentin Clement auto nt = convertType(getComplexEleTy(convert.res().getType())); 752092cee5fSValentin Clement auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(ty); 753092cee5fSValentin Clement auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(nt); 754092cee5fSValentin Clement auto rc = convertFpToFp(rp, fromBits, toBits, nt); 755092cee5fSValentin Clement auto ic = convertFpToFp(ip, fromBits, toBits, nt); 756092cee5fSValentin Clement auto un = rewriter.create<mlir::LLVM::UndefOp>(loc, toTy); 757092cee5fSValentin Clement auto i1 = 758092cee5fSValentin Clement rewriter.create<mlir::LLVM::InsertValueOp>(loc, toTy, un, rc, zero); 759092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(convert, toTy, i1, 760092cee5fSValentin Clement ic, one); 761092cee5fSValentin Clement return mlir::success(); 762092cee5fSValentin Clement } 763092cee5fSValentin Clement // Floating point to floating point conversion. 764092cee5fSValentin Clement if (isFloatingPointTy(fromTy)) { 765092cee5fSValentin Clement if (isFloatingPointTy(toTy)) { 766092cee5fSValentin Clement auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy); 767092cee5fSValentin Clement auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy); 768092cee5fSValentin Clement auto v = convertFpToFp(op0, fromBits, toBits, toTy); 769092cee5fSValentin Clement rewriter.replaceOp(convert, v); 770092cee5fSValentin Clement return mlir::success(); 771092cee5fSValentin Clement } 772092cee5fSValentin Clement if (toTy.isa<mlir::IntegerType>()) { 773092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::FPToSIOp>(convert, toTy, op0); 774092cee5fSValentin Clement return mlir::success(); 775092cee5fSValentin Clement } 776092cee5fSValentin Clement } else if (fromTy.isa<mlir::IntegerType>()) { 777092cee5fSValentin Clement // Integer to integer conversion. 778092cee5fSValentin Clement if (toTy.isa<mlir::IntegerType>()) { 779092cee5fSValentin Clement auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy); 780092cee5fSValentin Clement auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy); 781092cee5fSValentin Clement assert(fromBits != toBits); 782092cee5fSValentin Clement if (fromBits > toBits) { 783092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::TruncOp>(convert, toTy, op0); 784092cee5fSValentin Clement return mlir::success(); 785092cee5fSValentin Clement } 786092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::SExtOp>(convert, toTy, op0); 787092cee5fSValentin Clement return mlir::success(); 788092cee5fSValentin Clement } 789092cee5fSValentin Clement // Integer to floating point conversion. 790092cee5fSValentin Clement if (isFloatingPointTy(toTy)) { 791092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::SIToFPOp>(convert, toTy, op0); 792092cee5fSValentin Clement return mlir::success(); 793092cee5fSValentin Clement } 794092cee5fSValentin Clement // Integer to pointer conversion. 795092cee5fSValentin Clement if (toTy.isa<mlir::LLVM::LLVMPointerType>()) { 796092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(convert, toTy, op0); 797092cee5fSValentin Clement return mlir::success(); 798092cee5fSValentin Clement } 799092cee5fSValentin Clement } else if (fromTy.isa<mlir::LLVM::LLVMPointerType>()) { 800092cee5fSValentin Clement // Pointer to integer conversion. 801092cee5fSValentin Clement if (toTy.isa<mlir::IntegerType>()) { 802092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::PtrToIntOp>(convert, toTy, op0); 803092cee5fSValentin Clement return mlir::success(); 804092cee5fSValentin Clement } 805092cee5fSValentin Clement // Pointer to pointer conversion. 806092cee5fSValentin Clement if (toTy.isa<mlir::LLVM::LLVMPointerType>()) { 807092cee5fSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(convert, toTy, op0); 808092cee5fSValentin Clement return mlir::success(); 809092cee5fSValentin Clement } 810092cee5fSValentin Clement } 811092cee5fSValentin Clement return emitError(loc) << "cannot convert " << fromTy << " to " << toTy; 812092cee5fSValentin Clement } 813092cee5fSValentin Clement }; 814092cee5fSValentin Clement 8159534e361SValentin Clement /// Lower `fir.dispatch` operation. A virtual call to a method in a dispatch 8169534e361SValentin Clement /// table. 8179534e361SValentin Clement struct DispatchOpConversion : public FIROpConversion<fir::DispatchOp> { 8189534e361SValentin Clement using FIROpConversion::FIROpConversion; 8199534e361SValentin Clement 8209534e361SValentin Clement mlir::LogicalResult 8219534e361SValentin Clement matchAndRewrite(fir::DispatchOp dispatch, OpAdaptor adaptor, 8229534e361SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 8237ce8c6fcSKiran Chandramohan TODO(dispatch.getLoc(), "fir.dispatch codegen"); 8247ce8c6fcSKiran Chandramohan return failure(); 8259534e361SValentin Clement } 8269534e361SValentin Clement }; 8279534e361SValentin Clement 8289534e361SValentin Clement /// Lower `fir.dispatch_table` operation. The dispatch table for a Fortran 8299534e361SValentin Clement /// derived type. 8309534e361SValentin Clement struct DispatchTableOpConversion 8319534e361SValentin Clement : public FIROpConversion<fir::DispatchTableOp> { 8329534e361SValentin Clement using FIROpConversion::FIROpConversion; 8339534e361SValentin Clement 8349534e361SValentin Clement mlir::LogicalResult 8359534e361SValentin Clement matchAndRewrite(fir::DispatchTableOp dispTab, OpAdaptor adaptor, 8369534e361SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 8377ce8c6fcSKiran Chandramohan TODO(dispTab.getLoc(), "fir.dispatch_table codegen"); 8387ce8c6fcSKiran Chandramohan return failure(); 8399534e361SValentin Clement } 8409534e361SValentin Clement }; 8419534e361SValentin Clement 8429534e361SValentin Clement /// Lower `fir.dt_entry` operation. An entry in a dispatch table; binds a 8439534e361SValentin Clement /// method-name to a function. 8449534e361SValentin Clement struct DTEntryOpConversion : public FIROpConversion<fir::DTEntryOp> { 8459534e361SValentin Clement using FIROpConversion::FIROpConversion; 8469534e361SValentin Clement 8479534e361SValentin Clement mlir::LogicalResult 8489534e361SValentin Clement matchAndRewrite(fir::DTEntryOp dtEnt, OpAdaptor adaptor, 8499534e361SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 8507ce8c6fcSKiran Chandramohan TODO(dtEnt.getLoc(), "fir.dt_entry codegen"); 8517ce8c6fcSKiran Chandramohan return failure(); 8529534e361SValentin Clement } 8539534e361SValentin Clement }; 8549534e361SValentin Clement 855677df8c7SValentin Clement /// Lower `fir.global_len` operation. 856677df8c7SValentin Clement struct GlobalLenOpConversion : public FIROpConversion<fir::GlobalLenOp> { 857677df8c7SValentin Clement using FIROpConversion::FIROpConversion; 858677df8c7SValentin Clement 859677df8c7SValentin Clement mlir::LogicalResult 860677df8c7SValentin Clement matchAndRewrite(fir::GlobalLenOp globalLen, OpAdaptor adaptor, 861677df8c7SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 8627ce8c6fcSKiran Chandramohan TODO(globalLen.getLoc(), "fir.global_len codegen"); 8637ce8c6fcSKiran Chandramohan return failure(); 864677df8c7SValentin Clement } 865677df8c7SValentin Clement }; 866677df8c7SValentin Clement 867cdc476abSDiana Picus /// Lower fir.len_param_index 868cdc476abSDiana Picus struct LenParamIndexOpConversion 869cdc476abSDiana Picus : public FIROpConversion<fir::LenParamIndexOp> { 870cdc476abSDiana Picus using FIROpConversion::FIROpConversion; 871cdc476abSDiana Picus 872cdc476abSDiana Picus // FIXME: this should be specialized by the runtime target 873cdc476abSDiana Picus mlir::LogicalResult 874cdc476abSDiana Picus matchAndRewrite(fir::LenParamIndexOp lenp, OpAdaptor, 875cdc476abSDiana Picus mlir::ConversionPatternRewriter &rewriter) const override { 8767ce8c6fcSKiran Chandramohan TODO(lenp.getLoc(), "fir.len_param_index codegen"); 877cdc476abSDiana Picus } 878cdc476abSDiana Picus }; 879cdc476abSDiana Picus 88031246187SValentin Clement /// Lower `fir.gentypedesc` to a global constant. 88131246187SValentin Clement struct GenTypeDescOpConversion : public FIROpConversion<fir::GenTypeDescOp> { 88231246187SValentin Clement using FIROpConversion::FIROpConversion; 88331246187SValentin Clement 88431246187SValentin Clement mlir::LogicalResult 88531246187SValentin Clement matchAndRewrite(fir::GenTypeDescOp gentypedesc, OpAdaptor adaptor, 88631246187SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 8877ce8c6fcSKiran Chandramohan TODO(gentypedesc.getLoc(), "fir.gentypedesc codegen"); 8887ce8c6fcSKiran Chandramohan return failure(); 88931246187SValentin Clement } 89031246187SValentin Clement }; 891c2acd453SAlexisPerry } // namespace 892c2acd453SAlexisPerry 893c2acd453SAlexisPerry /// Return the LLVMFuncOp corresponding to the standard malloc call. 894c2acd453SAlexisPerry static mlir::LLVM::LLVMFuncOp 895c2acd453SAlexisPerry getMalloc(fir::AllocMemOp op, mlir::ConversionPatternRewriter &rewriter) { 896c2acd453SAlexisPerry auto module = op->getParentOfType<mlir::ModuleOp>(); 897c2acd453SAlexisPerry if (mlir::LLVM::LLVMFuncOp mallocFunc = 898c2acd453SAlexisPerry module.lookupSymbol<mlir::LLVM::LLVMFuncOp>("malloc")) 899c2acd453SAlexisPerry return mallocFunc; 900c2acd453SAlexisPerry mlir::OpBuilder moduleBuilder( 901c2acd453SAlexisPerry op->getParentOfType<mlir::ModuleOp>().getBodyRegion()); 902c2acd453SAlexisPerry auto indexType = mlir::IntegerType::get(op.getContext(), 64); 903c2acd453SAlexisPerry return moduleBuilder.create<mlir::LLVM::LLVMFuncOp>( 904c2acd453SAlexisPerry rewriter.getUnknownLoc(), "malloc", 905c2acd453SAlexisPerry mlir::LLVM::LLVMFunctionType::get(getVoidPtrType(op.getContext()), 906c2acd453SAlexisPerry indexType, 907c2acd453SAlexisPerry /*isVarArg=*/false)); 908c2acd453SAlexisPerry } 909c2acd453SAlexisPerry 910c2acd453SAlexisPerry /// Helper function for generating the LLVM IR that computes the size 911c2acd453SAlexisPerry /// in bytes for a derived type. 912c2acd453SAlexisPerry static mlir::Value 913c2acd453SAlexisPerry computeDerivedTypeSize(mlir::Location loc, mlir::Type ptrTy, mlir::Type idxTy, 914c2acd453SAlexisPerry mlir::ConversionPatternRewriter &rewriter) { 915c2acd453SAlexisPerry auto nullPtr = rewriter.create<mlir::LLVM::NullOp>(loc, ptrTy); 916c2acd453SAlexisPerry mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1); 91730122656SAlex Zinenko llvm::SmallVector<mlir::Value> args{one}; 91830122656SAlex Zinenko auto gep = rewriter.create<mlir::LLVM::GEPOp>(loc, ptrTy, nullPtr, args); 919c2acd453SAlexisPerry return rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, gep); 920c2acd453SAlexisPerry } 921c2acd453SAlexisPerry 922c2acd453SAlexisPerry namespace { 923c2acd453SAlexisPerry /// Lower a `fir.allocmem` instruction into `llvm.call @malloc` 924c2acd453SAlexisPerry struct AllocMemOpConversion : public FIROpConversion<fir::AllocMemOp> { 925c2acd453SAlexisPerry using FIROpConversion::FIROpConversion; 926c2acd453SAlexisPerry 927c2acd453SAlexisPerry mlir::LogicalResult 928c2acd453SAlexisPerry matchAndRewrite(fir::AllocMemOp heap, OpAdaptor adaptor, 929c2acd453SAlexisPerry mlir::ConversionPatternRewriter &rewriter) const override { 930c2acd453SAlexisPerry mlir::Type ty = convertType(heap.getType()); 931c2acd453SAlexisPerry mlir::LLVM::LLVMFuncOp mallocFunc = getMalloc(heap, rewriter); 932c2acd453SAlexisPerry mlir::Location loc = heap.getLoc(); 933c2acd453SAlexisPerry auto ity = lowerTy().indexType(); 934c2acd453SAlexisPerry if (auto recTy = fir::unwrapSequenceType(heap.getAllocatedType()) 935c2acd453SAlexisPerry .dyn_cast<fir::RecordType>()) 936c2acd453SAlexisPerry if (recTy.getNumLenParams() != 0) { 937c2acd453SAlexisPerry TODO(loc, 938c2acd453SAlexisPerry "fir.allocmem codegen of derived type with length parameters"); 939c2acd453SAlexisPerry return failure(); 940c2acd453SAlexisPerry } 941c2acd453SAlexisPerry mlir::Value size = genTypeSizeInBytes(loc, ity, rewriter, ty); 942c2acd453SAlexisPerry for (mlir::Value opnd : adaptor.getOperands()) 943c2acd453SAlexisPerry size = rewriter.create<mlir::LLVM::MulOp>( 944c2acd453SAlexisPerry loc, ity, size, integerCast(loc, rewriter, ity, opnd)); 945c2acd453SAlexisPerry heap->setAttr("callee", mlir::SymbolRefAttr::get(mallocFunc)); 946c2acd453SAlexisPerry auto malloc = rewriter.create<mlir::LLVM::CallOp>( 947c2acd453SAlexisPerry loc, ::getVoidPtrType(heap.getContext()), size, heap->getAttrs()); 948c2acd453SAlexisPerry rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(heap, ty, 949c2acd453SAlexisPerry malloc.getResult(0)); 950c2acd453SAlexisPerry return success(); 951c2acd453SAlexisPerry } 952c2acd453SAlexisPerry 953c2acd453SAlexisPerry // Compute the (allocation) size of the allocmem type in bytes. 954c2acd453SAlexisPerry mlir::Value genTypeSizeInBytes(mlir::Location loc, mlir::Type idxTy, 955c2acd453SAlexisPerry mlir::ConversionPatternRewriter &rewriter, 956c2acd453SAlexisPerry mlir::Type llTy) const { 957c2acd453SAlexisPerry // Use the primitive size, if available. 958c2acd453SAlexisPerry auto ptrTy = llTy.dyn_cast<mlir::LLVM::LLVMPointerType>(); 959c2acd453SAlexisPerry if (auto size = 960c2acd453SAlexisPerry mlir::LLVM::getPrimitiveTypeSizeInBits(ptrTy.getElementType())) 961c2acd453SAlexisPerry return genConstantIndex(loc, idxTy, rewriter, size / 8); 962c2acd453SAlexisPerry 963c2acd453SAlexisPerry // Otherwise, generate the GEP trick in LLVM IR to compute the size. 964c2acd453SAlexisPerry return computeDerivedTypeSize(loc, ptrTy, idxTy, rewriter); 965c2acd453SAlexisPerry } 966c2acd453SAlexisPerry }; 967c2acd453SAlexisPerry } // namespace 968c2acd453SAlexisPerry 969c2acd453SAlexisPerry /// Return the LLVMFuncOp corresponding to the standard free call. 970c2acd453SAlexisPerry static mlir::LLVM::LLVMFuncOp 971c2acd453SAlexisPerry getFree(fir::FreeMemOp op, mlir::ConversionPatternRewriter &rewriter) { 972c2acd453SAlexisPerry auto module = op->getParentOfType<mlir::ModuleOp>(); 973c2acd453SAlexisPerry if (mlir::LLVM::LLVMFuncOp freeFunc = 974c2acd453SAlexisPerry module.lookupSymbol<mlir::LLVM::LLVMFuncOp>("free")) 975c2acd453SAlexisPerry return freeFunc; 976c2acd453SAlexisPerry mlir::OpBuilder moduleBuilder(module.getBodyRegion()); 977c2acd453SAlexisPerry auto voidType = mlir::LLVM::LLVMVoidType::get(op.getContext()); 978c2acd453SAlexisPerry return moduleBuilder.create<mlir::LLVM::LLVMFuncOp>( 979c2acd453SAlexisPerry rewriter.getUnknownLoc(), "free", 980c2acd453SAlexisPerry mlir::LLVM::LLVMFunctionType::get(voidType, 981c2acd453SAlexisPerry getVoidPtrType(op.getContext()), 982c2acd453SAlexisPerry /*isVarArg=*/false)); 983c2acd453SAlexisPerry } 984c2acd453SAlexisPerry 985c2acd453SAlexisPerry namespace { 986c2acd453SAlexisPerry /// Lower a `fir.freemem` instruction into `llvm.call @free` 987c2acd453SAlexisPerry struct FreeMemOpConversion : public FIROpConversion<fir::FreeMemOp> { 988c2acd453SAlexisPerry using FIROpConversion::FIROpConversion; 989c2acd453SAlexisPerry 990c2acd453SAlexisPerry mlir::LogicalResult 991c2acd453SAlexisPerry matchAndRewrite(fir::FreeMemOp freemem, OpAdaptor adaptor, 992c2acd453SAlexisPerry mlir::ConversionPatternRewriter &rewriter) const override { 993c2acd453SAlexisPerry mlir::LLVM::LLVMFuncOp freeFunc = getFree(freemem, rewriter); 994c2acd453SAlexisPerry mlir::Location loc = freemem.getLoc(); 995c2acd453SAlexisPerry auto bitcast = rewriter.create<mlir::LLVM::BitcastOp>( 996c2acd453SAlexisPerry freemem.getLoc(), voidPtrTy(), adaptor.getOperands()[0]); 997c2acd453SAlexisPerry freemem->setAttr("callee", mlir::SymbolRefAttr::get(freeFunc)); 998c2acd453SAlexisPerry rewriter.create<mlir::LLVM::CallOp>( 999c2acd453SAlexisPerry loc, mlir::TypeRange{}, mlir::ValueRange{bitcast}, freemem->getAttrs()); 1000c2acd453SAlexisPerry rewriter.eraseOp(freemem); 1001c2acd453SAlexisPerry return success(); 1002c2acd453SAlexisPerry } 1003c2acd453SAlexisPerry }; 100431246187SValentin Clement 100522d332a0SAndrzej Warzynski /// Convert `fir.end` 100622d332a0SAndrzej Warzynski struct FirEndOpConversion : public FIROpConversion<fir::FirEndOp> { 100722d332a0SAndrzej Warzynski using FIROpConversion::FIROpConversion; 100822d332a0SAndrzej Warzynski 100922d332a0SAndrzej Warzynski mlir::LogicalResult 101022d332a0SAndrzej Warzynski matchAndRewrite(fir::FirEndOp firEnd, OpAdaptor, 101122d332a0SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 10127ce8c6fcSKiran Chandramohan TODO(firEnd.getLoc(), "fir.end codegen"); 10137ce8c6fcSKiran Chandramohan return failure(); 101422d332a0SAndrzej Warzynski } 101522d332a0SAndrzej Warzynski }; 101622d332a0SAndrzej Warzynski 10170c4a7a52SValentin Clement /// Lower `fir.has_value` operation to `llvm.return` operation. 1018044d5b5dSValentin Clement struct HasValueOpConversion : public FIROpConversion<fir::HasValueOp> { 1019044d5b5dSValentin Clement using FIROpConversion::FIROpConversion; 1020044d5b5dSValentin Clement 1021044d5b5dSValentin Clement mlir::LogicalResult 1022044d5b5dSValentin Clement matchAndRewrite(fir::HasValueOp op, OpAdaptor adaptor, 1023044d5b5dSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 1024044d5b5dSValentin Clement rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, adaptor.getOperands()); 1025044d5b5dSValentin Clement return success(); 1026044d5b5dSValentin Clement } 1027044d5b5dSValentin Clement }; 1028044d5b5dSValentin Clement 10290c4a7a52SValentin Clement /// Lower `fir.global` operation to `llvm.global` operation. 10300c4a7a52SValentin Clement /// `fir.insert_on_range` operations are replaced with constant dense attribute 10310c4a7a52SValentin Clement /// if they are applied on the full range. 1032044d5b5dSValentin Clement struct GlobalOpConversion : public FIROpConversion<fir::GlobalOp> { 1033044d5b5dSValentin Clement using FIROpConversion::FIROpConversion; 1034044d5b5dSValentin Clement 1035044d5b5dSValentin Clement mlir::LogicalResult 1036044d5b5dSValentin Clement matchAndRewrite(fir::GlobalOp global, OpAdaptor adaptor, 1037044d5b5dSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 1038044d5b5dSValentin Clement auto tyAttr = convertType(global.getType()); 1039044d5b5dSValentin Clement if (global.getType().isa<fir::BoxType>()) 1040044d5b5dSValentin Clement tyAttr = tyAttr.cast<mlir::LLVM::LLVMPointerType>().getElementType(); 1041044d5b5dSValentin Clement auto loc = global.getLoc(); 1042044d5b5dSValentin Clement mlir::Attribute initAttr{}; 1043044d5b5dSValentin Clement if (global.initVal()) 1044044d5b5dSValentin Clement initAttr = global.initVal().getValue(); 1045044d5b5dSValentin Clement auto linkage = convertLinkage(global.linkName()); 1046044d5b5dSValentin Clement auto isConst = global.constant().hasValue(); 1047044d5b5dSValentin Clement auto g = rewriter.create<mlir::LLVM::GlobalOp>( 1048feeee78aSJacques Pienaar loc, tyAttr, isConst, linkage, global.getSymName(), initAttr); 1049044d5b5dSValentin Clement auto &gr = g.getInitializerRegion(); 1050044d5b5dSValentin Clement rewriter.inlineRegionBefore(global.region(), gr, gr.end()); 1051044d5b5dSValentin Clement if (!gr.empty()) { 1052044d5b5dSValentin Clement // Replace insert_on_range with a constant dense attribute if the 1053044d5b5dSValentin Clement // initialization is on the full range. 1054044d5b5dSValentin Clement auto insertOnRangeOps = gr.front().getOps<fir::InsertOnRangeOp>(); 1055044d5b5dSValentin Clement for (auto insertOp : insertOnRangeOps) { 1056044d5b5dSValentin Clement if (isFullRange(insertOp.coor(), insertOp.getType())) { 1057044d5b5dSValentin Clement auto seqTyAttr = convertType(insertOp.getType()); 1058044d5b5dSValentin Clement auto *op = insertOp.val().getDefiningOp(); 1059044d5b5dSValentin Clement auto constant = mlir::dyn_cast<mlir::arith::ConstantOp>(op); 1060044d5b5dSValentin Clement if (!constant) { 1061044d5b5dSValentin Clement auto convertOp = mlir::dyn_cast<fir::ConvertOp>(op); 1062044d5b5dSValentin Clement if (!convertOp) 1063044d5b5dSValentin Clement continue; 1064044d5b5dSValentin Clement constant = cast<mlir::arith::ConstantOp>( 1065044d5b5dSValentin Clement convertOp.value().getDefiningOp()); 1066044d5b5dSValentin Clement } 1067044d5b5dSValentin Clement mlir::Type vecType = mlir::VectorType::get( 1068044d5b5dSValentin Clement insertOp.getType().getShape(), constant.getType()); 1069044d5b5dSValentin Clement auto denseAttr = mlir::DenseElementsAttr::get( 10703012f35fSJacques Pienaar vecType.cast<ShapedType>(), constant.getValue()); 1071044d5b5dSValentin Clement rewriter.setInsertionPointAfter(insertOp); 1072044d5b5dSValentin Clement rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>( 1073044d5b5dSValentin Clement insertOp, seqTyAttr, denseAttr); 1074044d5b5dSValentin Clement } 1075044d5b5dSValentin Clement } 1076044d5b5dSValentin Clement } 1077044d5b5dSValentin Clement rewriter.eraseOp(global); 1078044d5b5dSValentin Clement return success(); 1079044d5b5dSValentin Clement } 1080044d5b5dSValentin Clement 10818ec0f221SMehdi Amini bool isFullRange(mlir::DenseIntElementsAttr indexes, 10828ec0f221SMehdi Amini fir::SequenceType seqTy) const { 1083044d5b5dSValentin Clement auto extents = seqTy.getShape(); 10848ec0f221SMehdi Amini if (indexes.size() / 2 != static_cast<int64_t>(extents.size())) 1085044d5b5dSValentin Clement return false; 10868ec0f221SMehdi Amini auto cur_index = indexes.value_begin<int64_t>(); 1087044d5b5dSValentin Clement for (unsigned i = 0; i < indexes.size(); i += 2) { 10888ec0f221SMehdi Amini if (*(cur_index++) != 0) 1089044d5b5dSValentin Clement return false; 10908ec0f221SMehdi Amini if (*(cur_index++) != extents[i / 2] - 1) 1091044d5b5dSValentin Clement return false; 1092044d5b5dSValentin Clement } 1093044d5b5dSValentin Clement return true; 1094044d5b5dSValentin Clement } 1095044d5b5dSValentin Clement 10960c4a7a52SValentin Clement // TODO: String comparaison should be avoided. Replace linkName with an 10970c4a7a52SValentin Clement // enumeration. 1098044d5b5dSValentin Clement mlir::LLVM::Linkage convertLinkage(Optional<StringRef> optLinkage) const { 1099044d5b5dSValentin Clement if (optLinkage.hasValue()) { 1100044d5b5dSValentin Clement auto name = optLinkage.getValue(); 1101044d5b5dSValentin Clement if (name == "internal") 1102044d5b5dSValentin Clement return mlir::LLVM::Linkage::Internal; 1103044d5b5dSValentin Clement if (name == "linkonce") 1104044d5b5dSValentin Clement return mlir::LLVM::Linkage::Linkonce; 1105044d5b5dSValentin Clement if (name == "common") 1106044d5b5dSValentin Clement return mlir::LLVM::Linkage::Common; 1107044d5b5dSValentin Clement if (name == "weak") 1108044d5b5dSValentin Clement return mlir::LLVM::Linkage::Weak; 1109044d5b5dSValentin Clement } 1110044d5b5dSValentin Clement return mlir::LLVM::Linkage::External; 1111044d5b5dSValentin Clement } 1112044d5b5dSValentin Clement }; 1113c2acd453SAlexisPerry } // namespace 1114044d5b5dSValentin Clement 1115c2acd453SAlexisPerry static void genCondBrOp(mlir::Location loc, mlir::Value cmp, mlir::Block *dest, 111639f4ef81SValentin Clement Optional<mlir::ValueRange> destOps, 111739f4ef81SValentin Clement mlir::ConversionPatternRewriter &rewriter, 111839f4ef81SValentin Clement mlir::Block *newBlock) { 111939f4ef81SValentin Clement if (destOps.hasValue()) 112039f4ef81SValentin Clement rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, destOps.getValue(), 112139f4ef81SValentin Clement newBlock, mlir::ValueRange()); 112239f4ef81SValentin Clement else 112339f4ef81SValentin Clement rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, newBlock); 112439f4ef81SValentin Clement } 112539f4ef81SValentin Clement 112639f4ef81SValentin Clement template <typename A, typename B> 1127c2acd453SAlexisPerry static void genBrOp(A caseOp, mlir::Block *dest, Optional<B> destOps, 112839f4ef81SValentin Clement mlir::ConversionPatternRewriter &rewriter) { 112939f4ef81SValentin Clement if (destOps.hasValue()) 113039f4ef81SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, destOps.getValue(), 113139f4ef81SValentin Clement dest); 113239f4ef81SValentin Clement else 113339f4ef81SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, llvm::None, dest); 113439f4ef81SValentin Clement } 113539f4ef81SValentin Clement 1136c2acd453SAlexisPerry static void genCaseLadderStep(mlir::Location loc, mlir::Value cmp, 1137c2acd453SAlexisPerry mlir::Block *dest, 113839f4ef81SValentin Clement Optional<mlir::ValueRange> destOps, 113939f4ef81SValentin Clement mlir::ConversionPatternRewriter &rewriter) { 114039f4ef81SValentin Clement auto *thisBlock = rewriter.getInsertionBlock(); 114139f4ef81SValentin Clement auto *newBlock = createBlock(rewriter, dest); 114239f4ef81SValentin Clement rewriter.setInsertionPointToEnd(thisBlock); 114339f4ef81SValentin Clement genCondBrOp(loc, cmp, dest, destOps, rewriter, newBlock); 114439f4ef81SValentin Clement rewriter.setInsertionPointToEnd(newBlock); 114539f4ef81SValentin Clement } 114639f4ef81SValentin Clement 1147c2acd453SAlexisPerry namespace { 114839f4ef81SValentin Clement /// Conversion of `fir.select_case` 114939f4ef81SValentin Clement /// 115039f4ef81SValentin Clement /// The `fir.select_case` operation is converted to a if-then-else ladder. 115139f4ef81SValentin Clement /// Depending on the case condition type, one or several comparison and 115239f4ef81SValentin Clement /// conditional branching can be generated. 115339f4ef81SValentin Clement /// 115439f4ef81SValentin Clement /// A a point value case such as `case(4)`, a lower bound case such as 115539f4ef81SValentin Clement /// `case(5:)` or an upper bound case such as `case(:3)` are converted to a 115639f4ef81SValentin Clement /// simple comparison between the selector value and the constant value in the 115739f4ef81SValentin Clement /// case. The block associated with the case condition is then executed if 115839f4ef81SValentin Clement /// the comparison succeed otherwise it branch to the next block with the 115939f4ef81SValentin Clement /// comparison for the the next case conditon. 116039f4ef81SValentin Clement /// 116139f4ef81SValentin Clement /// A closed interval case condition such as `case(7:10)` is converted with a 116239f4ef81SValentin Clement /// first comparison and conditional branching for the lower bound. If 116339f4ef81SValentin Clement /// successful, it branch to a second block with the comparison for the 116439f4ef81SValentin Clement /// upper bound in the same case condition. 116539f4ef81SValentin Clement /// 116639f4ef81SValentin Clement /// TODO: lowering of CHARACTER type cases is not handled yet. 116739f4ef81SValentin Clement struct SelectCaseOpConversion : public FIROpConversion<fir::SelectCaseOp> { 116839f4ef81SValentin Clement using FIROpConversion::FIROpConversion; 116939f4ef81SValentin Clement 117039f4ef81SValentin Clement mlir::LogicalResult 117139f4ef81SValentin Clement matchAndRewrite(fir::SelectCaseOp caseOp, OpAdaptor adaptor, 117239f4ef81SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 117339f4ef81SValentin Clement unsigned conds = caseOp.getNumConditions(); 117439f4ef81SValentin Clement llvm::ArrayRef<mlir::Attribute> cases = caseOp.getCases().getValue(); 117539f4ef81SValentin Clement // Type can be CHARACTER, INTEGER, or LOGICAL (C1145) 11767ce8c6fcSKiran Chandramohan auto ty = caseOp.getSelector().getType(); 11777ce8c6fcSKiran Chandramohan if (ty.isa<fir::CharacterType>()) { 11787ce8c6fcSKiran Chandramohan TODO(caseOp.getLoc(), "fir.select_case codegen with character type"); 11797ce8c6fcSKiran Chandramohan return failure(); 11807ce8c6fcSKiran Chandramohan } 118139f4ef81SValentin Clement mlir::Value selector = caseOp.getSelector(adaptor.getOperands()); 118239f4ef81SValentin Clement auto loc = caseOp.getLoc(); 118339f4ef81SValentin Clement for (unsigned t = 0; t != conds; ++t) { 118439f4ef81SValentin Clement mlir::Block *dest = caseOp.getSuccessor(t); 118539f4ef81SValentin Clement llvm::Optional<mlir::ValueRange> destOps = 118639f4ef81SValentin Clement caseOp.getSuccessorOperands(adaptor.getOperands(), t); 118739f4ef81SValentin Clement llvm::Optional<mlir::ValueRange> cmpOps = 118839f4ef81SValentin Clement *caseOp.getCompareOperands(adaptor.getOperands(), t); 118939f4ef81SValentin Clement mlir::Value caseArg = *(cmpOps.getValue().begin()); 119039f4ef81SValentin Clement mlir::Attribute attr = cases[t]; 119139f4ef81SValentin Clement if (attr.isa<fir::PointIntervalAttr>()) { 119239f4ef81SValentin Clement auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 119339f4ef81SValentin Clement loc, mlir::LLVM::ICmpPredicate::eq, selector, caseArg); 119439f4ef81SValentin Clement genCaseLadderStep(loc, cmp, dest, destOps, rewriter); 119539f4ef81SValentin Clement continue; 119639f4ef81SValentin Clement } 119739f4ef81SValentin Clement if (attr.isa<fir::LowerBoundAttr>()) { 119839f4ef81SValentin Clement auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 119939f4ef81SValentin Clement loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector); 120039f4ef81SValentin Clement genCaseLadderStep(loc, cmp, dest, destOps, rewriter); 120139f4ef81SValentin Clement continue; 120239f4ef81SValentin Clement } 120339f4ef81SValentin Clement if (attr.isa<fir::UpperBoundAttr>()) { 120439f4ef81SValentin Clement auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 120539f4ef81SValentin Clement loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg); 120639f4ef81SValentin Clement genCaseLadderStep(loc, cmp, dest, destOps, rewriter); 120739f4ef81SValentin Clement continue; 120839f4ef81SValentin Clement } 120939f4ef81SValentin Clement if (attr.isa<fir::ClosedIntervalAttr>()) { 121039f4ef81SValentin Clement auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 121139f4ef81SValentin Clement loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector); 121239f4ef81SValentin Clement auto *thisBlock = rewriter.getInsertionBlock(); 121339f4ef81SValentin Clement auto *newBlock1 = createBlock(rewriter, dest); 121439f4ef81SValentin Clement auto *newBlock2 = createBlock(rewriter, dest); 121539f4ef81SValentin Clement rewriter.setInsertionPointToEnd(thisBlock); 121639f4ef81SValentin Clement rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, newBlock1, newBlock2); 121739f4ef81SValentin Clement rewriter.setInsertionPointToEnd(newBlock1); 121839f4ef81SValentin Clement mlir::Value caseArg0 = *(cmpOps.getValue().begin() + 1); 121939f4ef81SValentin Clement auto cmp0 = rewriter.create<mlir::LLVM::ICmpOp>( 122039f4ef81SValentin Clement loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg0); 122139f4ef81SValentin Clement genCondBrOp(loc, cmp0, dest, destOps, rewriter, newBlock2); 122239f4ef81SValentin Clement rewriter.setInsertionPointToEnd(newBlock2); 122339f4ef81SValentin Clement continue; 122439f4ef81SValentin Clement } 122539f4ef81SValentin Clement assert(attr.isa<mlir::UnitAttr>()); 122639f4ef81SValentin Clement assert((t + 1 == conds) && "unit must be last"); 122739f4ef81SValentin Clement genBrOp(caseOp, dest, destOps, rewriter); 122839f4ef81SValentin Clement } 122939f4ef81SValentin Clement return success(); 123039f4ef81SValentin Clement } 123139f4ef81SValentin Clement }; 1232c2acd453SAlexisPerry } // namespace 123339f4ef81SValentin Clement 12348c239909SValentin Clement template <typename OP> 1235c2acd453SAlexisPerry static void selectMatchAndRewrite(fir::LLVMTypeConverter &lowering, OP select, 12368c239909SValentin Clement typename OP::Adaptor adaptor, 12378c239909SValentin Clement mlir::ConversionPatternRewriter &rewriter) { 12388c239909SValentin Clement unsigned conds = select.getNumConditions(); 12398c239909SValentin Clement auto cases = select.getCases().getValue(); 12408c239909SValentin Clement mlir::Value selector = adaptor.selector(); 12418c239909SValentin Clement auto loc = select.getLoc(); 12428c239909SValentin Clement assert(conds > 0 && "select must have cases"); 12438c239909SValentin Clement 12448c239909SValentin Clement llvm::SmallVector<mlir::Block *> destinations; 12458c239909SValentin Clement llvm::SmallVector<mlir::ValueRange> destinationsOperands; 12468c239909SValentin Clement mlir::Block *defaultDestination; 12478c239909SValentin Clement mlir::ValueRange defaultOperands; 12488c239909SValentin Clement llvm::SmallVector<int32_t> caseValues; 12498c239909SValentin Clement 12508c239909SValentin Clement for (unsigned t = 0; t != conds; ++t) { 12518c239909SValentin Clement mlir::Block *dest = select.getSuccessor(t); 12528c239909SValentin Clement auto destOps = select.getSuccessorOperands(adaptor.getOperands(), t); 12538c239909SValentin Clement const mlir::Attribute &attr = cases[t]; 12548c239909SValentin Clement if (auto intAttr = attr.template dyn_cast<mlir::IntegerAttr>()) { 12558c239909SValentin Clement destinations.push_back(dest); 12568c239909SValentin Clement destinationsOperands.push_back(destOps.hasValue() ? *destOps 12578c239909SValentin Clement : ValueRange()); 12588c239909SValentin Clement caseValues.push_back(intAttr.getInt()); 12598c239909SValentin Clement continue; 12608c239909SValentin Clement } 12618c239909SValentin Clement assert(attr.template dyn_cast_or_null<mlir::UnitAttr>()); 12628c239909SValentin Clement assert((t + 1 == conds) && "unit must be last"); 12638c239909SValentin Clement defaultDestination = dest; 12648c239909SValentin Clement defaultOperands = destOps.hasValue() ? *destOps : ValueRange(); 12658c239909SValentin Clement } 12668c239909SValentin Clement 12678c239909SValentin Clement // LLVM::SwitchOp takes a i32 type for the selector. 12688c239909SValentin Clement if (select.getSelector().getType() != rewriter.getI32Type()) 12698c239909SValentin Clement selector = 12708c239909SValentin Clement rewriter.create<LLVM::TruncOp>(loc, rewriter.getI32Type(), selector); 12718c239909SValentin Clement 12728c239909SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>( 12738c239909SValentin Clement select, selector, 12748c239909SValentin Clement /*defaultDestination=*/defaultDestination, 12758c239909SValentin Clement /*defaultOperands=*/defaultOperands, 12768c239909SValentin Clement /*caseValues=*/caseValues, 12778c239909SValentin Clement /*caseDestinations=*/destinations, 12788c239909SValentin Clement /*caseOperands=*/destinationsOperands, 12798c239909SValentin Clement /*branchWeights=*/ArrayRef<int32_t>()); 12808c239909SValentin Clement } 12818c239909SValentin Clement 1282c2acd453SAlexisPerry namespace { 12838c239909SValentin Clement /// conversion of fir::SelectOp to an if-then-else ladder 12848c239909SValentin Clement struct SelectOpConversion : public FIROpConversion<fir::SelectOp> { 12858c239909SValentin Clement using FIROpConversion::FIROpConversion; 12868c239909SValentin Clement 12878c239909SValentin Clement mlir::LogicalResult 12888c239909SValentin Clement matchAndRewrite(fir::SelectOp op, OpAdaptor adaptor, 12898c239909SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 12908c239909SValentin Clement selectMatchAndRewrite<fir::SelectOp>(lowerTy(), op, adaptor, rewriter); 12918c239909SValentin Clement return success(); 12928c239909SValentin Clement } 12938c239909SValentin Clement }; 12948c239909SValentin Clement 1295e3349fa1SAndrzej Warzynski /// `fir.load` --> `llvm.load` 1296e3349fa1SAndrzej Warzynski struct LoadOpConversion : public FIROpConversion<fir::LoadOp> { 1297e3349fa1SAndrzej Warzynski using FIROpConversion::FIROpConversion; 1298e3349fa1SAndrzej Warzynski 1299e3349fa1SAndrzej Warzynski mlir::LogicalResult 1300e3349fa1SAndrzej Warzynski matchAndRewrite(fir::LoadOp load, OpAdaptor adaptor, 1301e3349fa1SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 1302e3349fa1SAndrzej Warzynski // fir.box is a special case because it is considered as an ssa values in 1303e3349fa1SAndrzej Warzynski // fir, but it is lowered as a pointer to a descriptor. So fir.ref<fir.box> 1304e3349fa1SAndrzej Warzynski // and fir.box end up being the same llvm types and loading a 1305e3349fa1SAndrzej Warzynski // fir.ref<fir.box> is actually a no op in LLVM. 1306e3349fa1SAndrzej Warzynski if (load.getType().isa<fir::BoxType>()) { 1307e3349fa1SAndrzej Warzynski rewriter.replaceOp(load, adaptor.getOperands()[0]); 1308e3349fa1SAndrzej Warzynski } else { 1309e3349fa1SAndrzej Warzynski mlir::Type ty = convertType(load.getType()); 1310e3349fa1SAndrzej Warzynski ArrayRef<NamedAttribute> at = load->getAttrs(); 1311e3349fa1SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::LoadOp>( 1312e3349fa1SAndrzej Warzynski load, ty, adaptor.getOperands(), at); 1313e3349fa1SAndrzej Warzynski } 1314e3349fa1SAndrzej Warzynski return success(); 1315e3349fa1SAndrzej Warzynski } 1316e3349fa1SAndrzej Warzynski }; 1317e3349fa1SAndrzej Warzynski 1318b8207db7SValentin Clement /// Lower `fir.no_reassoc` to LLVM IR dialect. 1319b8207db7SValentin Clement /// TODO: how do we want to enforce this in LLVM-IR? Can we manipulate the fast 1320b8207db7SValentin Clement /// math flags? 1321b8207db7SValentin Clement struct NoReassocOpConversion : public FIROpConversion<fir::NoReassocOp> { 1322b8207db7SValentin Clement using FIROpConversion::FIROpConversion; 1323b8207db7SValentin Clement 1324b8207db7SValentin Clement mlir::LogicalResult 1325b8207db7SValentin Clement matchAndRewrite(fir::NoReassocOp noreassoc, OpAdaptor adaptor, 1326b8207db7SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 1327b8207db7SValentin Clement rewriter.replaceOp(noreassoc, adaptor.getOperands()[0]); 1328b8207db7SValentin Clement return success(); 1329b8207db7SValentin Clement } 1330b8207db7SValentin Clement }; 1331b8207db7SValentin Clement 13322a299e4fSValentin Clement /// Lower `fir.select_type` to LLVM IR dialect. 13332a299e4fSValentin Clement struct SelectTypeOpConversion : public FIROpConversion<fir::SelectTypeOp> { 13342a299e4fSValentin Clement using FIROpConversion::FIROpConversion; 13352a299e4fSValentin Clement 13362a299e4fSValentin Clement mlir::LogicalResult 13372a299e4fSValentin Clement matchAndRewrite(fir::SelectTypeOp select, OpAdaptor adaptor, 13382a299e4fSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 13397ce8c6fcSKiran Chandramohan mlir::emitError(select.getLoc(), 13407ce8c6fcSKiran Chandramohan "fir.select_type should have already been converted"); 13417ce8c6fcSKiran Chandramohan return failure(); 13422a299e4fSValentin Clement } 13432a299e4fSValentin Clement }; 13442a299e4fSValentin Clement 13458c239909SValentin Clement /// conversion of fir::SelectRankOp to an if-then-else ladder 13468c239909SValentin Clement struct SelectRankOpConversion : public FIROpConversion<fir::SelectRankOp> { 13478c239909SValentin Clement using FIROpConversion::FIROpConversion; 13488c239909SValentin Clement 13498c239909SValentin Clement mlir::LogicalResult 13508c239909SValentin Clement matchAndRewrite(fir::SelectRankOp op, OpAdaptor adaptor, 13518c239909SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 13528c239909SValentin Clement selectMatchAndRewrite<fir::SelectRankOp>(lowerTy(), op, adaptor, rewriter); 13538c239909SValentin Clement return success(); 13548c239909SValentin Clement } 13558c239909SValentin Clement }; 13568c239909SValentin Clement 1357e3349fa1SAndrzej Warzynski /// `fir.store` --> `llvm.store` 1358e3349fa1SAndrzej Warzynski struct StoreOpConversion : public FIROpConversion<fir::StoreOp> { 1359e3349fa1SAndrzej Warzynski using FIROpConversion::FIROpConversion; 1360e3349fa1SAndrzej Warzynski 1361e3349fa1SAndrzej Warzynski mlir::LogicalResult 1362e3349fa1SAndrzej Warzynski matchAndRewrite(fir::StoreOp store, OpAdaptor adaptor, 1363e3349fa1SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 1364e3349fa1SAndrzej Warzynski if (store.value().getType().isa<fir::BoxType>()) { 1365e3349fa1SAndrzej Warzynski // fir.box value is actually in memory, load it first before storing it. 1366e3349fa1SAndrzej Warzynski mlir::Location loc = store.getLoc(); 1367e3349fa1SAndrzej Warzynski mlir::Type boxPtrTy = adaptor.getOperands()[0].getType(); 1368e3349fa1SAndrzej Warzynski auto val = rewriter.create<mlir::LLVM::LoadOp>( 1369e3349fa1SAndrzej Warzynski loc, boxPtrTy.cast<mlir::LLVM::LLVMPointerType>().getElementType(), 1370e3349fa1SAndrzej Warzynski adaptor.getOperands()[0]); 1371e3349fa1SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>( 1372e3349fa1SAndrzej Warzynski store, val, adaptor.getOperands()[1]); 1373e3349fa1SAndrzej Warzynski } else { 1374e3349fa1SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>( 1375e3349fa1SAndrzej Warzynski store, adaptor.getOperands()[0], adaptor.getOperands()[1]); 1376e3349fa1SAndrzej Warzynski } 1377e3349fa1SAndrzej Warzynski return success(); 1378e3349fa1SAndrzej Warzynski } 1379e3349fa1SAndrzej Warzynski }; 1380e3349fa1SAndrzej Warzynski 1381e3349fa1SAndrzej Warzynski /// convert to LLVM IR dialect `undef` 1382044d5b5dSValentin Clement struct UndefOpConversion : public FIROpConversion<fir::UndefOp> { 1383044d5b5dSValentin Clement using FIROpConversion::FIROpConversion; 1384044d5b5dSValentin Clement 1385044d5b5dSValentin Clement mlir::LogicalResult 1386044d5b5dSValentin Clement matchAndRewrite(fir::UndefOp undef, OpAdaptor, 1387044d5b5dSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 1388044d5b5dSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::UndefOp>( 1389044d5b5dSValentin Clement undef, convertType(undef.getType())); 1390044d5b5dSValentin Clement return success(); 1391044d5b5dSValentin Clement } 1392044d5b5dSValentin Clement }; 1393a7a61359SValentin Clement 1394e3349fa1SAndrzej Warzynski /// `fir.unreachable` --> `llvm.unreachable` 139532e08248SAndrzej Warzynski struct UnreachableOpConversion : public FIROpConversion<fir::UnreachableOp> { 139632e08248SAndrzej Warzynski using FIROpConversion::FIROpConversion; 139732e08248SAndrzej Warzynski 139832e08248SAndrzej Warzynski mlir::LogicalResult 139932e08248SAndrzej Warzynski matchAndRewrite(fir::UnreachableOp unreach, OpAdaptor adaptor, 140032e08248SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 140132e08248SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(unreach); 140232e08248SAndrzej Warzynski return success(); 140332e08248SAndrzej Warzynski } 140432e08248SAndrzej Warzynski }; 140532e08248SAndrzej Warzynski 1406a7a61359SValentin Clement struct ZeroOpConversion : public FIROpConversion<fir::ZeroOp> { 1407a7a61359SValentin Clement using FIROpConversion::FIROpConversion; 1408a7a61359SValentin Clement 1409a7a61359SValentin Clement mlir::LogicalResult 1410a7a61359SValentin Clement matchAndRewrite(fir::ZeroOp zero, OpAdaptor, 1411a7a61359SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 14127ce8c6fcSKiran Chandramohan mlir::Type ty = convertType(zero.getType()); 1413a7a61359SValentin Clement if (ty.isa<mlir::LLVM::LLVMPointerType>()) { 1414a7a61359SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(zero, ty); 1415a7a61359SValentin Clement } else if (ty.isa<mlir::IntegerType>()) { 1416a7a61359SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>( 1417a7a61359SValentin Clement zero, ty, mlir::IntegerAttr::get(zero.getType(), 0)); 1418a7a61359SValentin Clement } else if (mlir::LLVM::isCompatibleFloatingPointType(ty)) { 1419a7a61359SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>( 1420a7a61359SValentin Clement zero, ty, mlir::FloatAttr::get(zero.getType(), 0.0)); 1421a7a61359SValentin Clement } else { 1422a7a61359SValentin Clement // TODO: create ConstantAggregateZero for FIR aggregate/array types. 142352d813edSValentin Clement return rewriter.notifyMatchFailure( 142452d813edSValentin Clement zero, 1425a7a61359SValentin Clement "conversion of fir.zero with aggregate type not implemented yet"); 1426a7a61359SValentin Clement } 1427a7a61359SValentin Clement return success(); 1428a7a61359SValentin Clement } 1429a7a61359SValentin Clement }; 1430c2acd453SAlexisPerry } // namespace 143132e08248SAndrzej Warzynski 1432af6ee580SValentin Clement /// Common base class for embox to descriptor conversion. 1433af6ee580SValentin Clement template <typename OP> 1434af6ee580SValentin Clement struct EmboxCommonConversion : public FIROpConversion<OP> { 1435af6ee580SValentin Clement using FIROpConversion<OP>::FIROpConversion; 1436af6ee580SValentin Clement 1437af6ee580SValentin Clement // Find the LLVMFuncOp in whose entry block the alloca should be inserted. 1438af6ee580SValentin Clement // The order to find the LLVMFuncOp is as follows: 1439af6ee580SValentin Clement // 1. The parent operation of the current block if it is a LLVMFuncOp. 1440af6ee580SValentin Clement // 2. The first ancestor that is a LLVMFuncOp. 1441af6ee580SValentin Clement mlir::LLVM::LLVMFuncOp 1442af6ee580SValentin Clement getFuncForAllocaInsert(mlir::ConversionPatternRewriter &rewriter) const { 1443af6ee580SValentin Clement mlir::Operation *parentOp = rewriter.getInsertionBlock()->getParentOp(); 1444af6ee580SValentin Clement return mlir::isa<mlir::LLVM::LLVMFuncOp>(parentOp) 1445af6ee580SValentin Clement ? mlir::cast<mlir::LLVM::LLVMFuncOp>(parentOp) 1446af6ee580SValentin Clement : parentOp->getParentOfType<mlir::LLVM::LLVMFuncOp>(); 1447af6ee580SValentin Clement } 1448af6ee580SValentin Clement 1449af6ee580SValentin Clement // Generate an alloca of size 1 and type \p toTy. 1450af6ee580SValentin Clement mlir::LLVM::AllocaOp 1451af6ee580SValentin Clement genAllocaWithType(mlir::Location loc, mlir::Type toTy, unsigned alignment, 1452af6ee580SValentin Clement mlir::ConversionPatternRewriter &rewriter) const { 1453af6ee580SValentin Clement auto thisPt = rewriter.saveInsertionPoint(); 1454af6ee580SValentin Clement mlir::LLVM::LLVMFuncOp func = getFuncForAllocaInsert(rewriter); 1455af6ee580SValentin Clement rewriter.setInsertionPointToStart(&func.front()); 1456af6ee580SValentin Clement auto size = this->genI32Constant(loc, rewriter, 1); 1457af6ee580SValentin Clement auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, toTy, size, alignment); 1458af6ee580SValentin Clement rewriter.restoreInsertionPoint(thisPt); 1459af6ee580SValentin Clement return al; 1460af6ee580SValentin Clement } 1461af6ee580SValentin Clement 1462af6ee580SValentin Clement static int getCFIAttr(fir::BoxType boxTy) { 1463af6ee580SValentin Clement auto eleTy = boxTy.getEleTy(); 1464af6ee580SValentin Clement if (eleTy.isa<fir::PointerType>()) 1465af6ee580SValentin Clement return CFI_attribute_pointer; 1466af6ee580SValentin Clement if (eleTy.isa<fir::HeapType>()) 1467af6ee580SValentin Clement return CFI_attribute_allocatable; 1468af6ee580SValentin Clement return CFI_attribute_other; 1469af6ee580SValentin Clement } 1470af6ee580SValentin Clement 1471af6ee580SValentin Clement static fir::RecordType unwrapIfDerived(fir::BoxType boxTy) { 1472af6ee580SValentin Clement return fir::unwrapSequenceType(fir::dyn_cast_ptrOrBoxEleTy(boxTy)) 1473af6ee580SValentin Clement .template dyn_cast<fir::RecordType>(); 1474af6ee580SValentin Clement } 1475af6ee580SValentin Clement static bool isDerivedTypeWithLenParams(fir::BoxType boxTy) { 1476af6ee580SValentin Clement auto recTy = unwrapIfDerived(boxTy); 1477af6ee580SValentin Clement return recTy && recTy.getNumLenParams() > 0; 1478af6ee580SValentin Clement } 1479af6ee580SValentin Clement static bool isDerivedType(fir::BoxType boxTy) { 1480af6ee580SValentin Clement return unwrapIfDerived(boxTy) != nullptr; 1481af6ee580SValentin Clement } 1482af6ee580SValentin Clement 1483af6ee580SValentin Clement // Get the element size and CFI type code of the boxed value. 1484af6ee580SValentin Clement std::tuple<mlir::Value, mlir::Value> getSizeAndTypeCode( 1485af6ee580SValentin Clement mlir::Location loc, mlir::ConversionPatternRewriter &rewriter, 1486af6ee580SValentin Clement mlir::Type boxEleTy, mlir::ValueRange lenParams = {}) const { 1487af6ee580SValentin Clement auto doInteger = 1488af6ee580SValentin Clement [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> { 1489af6ee580SValentin Clement int typeCode = fir::integerBitsToTypeCode(width); 1490af6ee580SValentin Clement return {this->genConstantOffset(loc, rewriter, width / 8), 1491af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, typeCode)}; 1492af6ee580SValentin Clement }; 1493af6ee580SValentin Clement auto doLogical = 1494af6ee580SValentin Clement [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> { 1495af6ee580SValentin Clement int typeCode = fir::logicalBitsToTypeCode(width); 1496af6ee580SValentin Clement return {this->genConstantOffset(loc, rewriter, width / 8), 1497af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, typeCode)}; 1498af6ee580SValentin Clement }; 1499af6ee580SValentin Clement auto doFloat = [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> { 1500af6ee580SValentin Clement int typeCode = fir::realBitsToTypeCode(width); 1501af6ee580SValentin Clement return {this->genConstantOffset(loc, rewriter, width / 8), 1502af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, typeCode)}; 1503af6ee580SValentin Clement }; 1504af6ee580SValentin Clement auto doComplex = 1505af6ee580SValentin Clement [&](unsigned width) -> std::tuple<mlir::Value, mlir::Value> { 1506af6ee580SValentin Clement auto typeCode = fir::complexBitsToTypeCode(width); 1507af6ee580SValentin Clement return {this->genConstantOffset(loc, rewriter, width / 8 * 2), 1508af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, typeCode)}; 1509af6ee580SValentin Clement }; 1510af6ee580SValentin Clement auto doCharacter = 1511af6ee580SValentin Clement [&](unsigned width, 1512af6ee580SValentin Clement mlir::Value len) -> std::tuple<mlir::Value, mlir::Value> { 1513af6ee580SValentin Clement auto typeCode = fir::characterBitsToTypeCode(width); 1514af6ee580SValentin Clement auto typeCodeVal = this->genConstantOffset(loc, rewriter, typeCode); 1515af6ee580SValentin Clement if (width == 8) 1516af6ee580SValentin Clement return {len, typeCodeVal}; 1517af6ee580SValentin Clement auto byteWidth = this->genConstantOffset(loc, rewriter, width / 8); 1518af6ee580SValentin Clement auto i64Ty = mlir::IntegerType::get(&this->lowerTy().getContext(), 64); 1519af6ee580SValentin Clement auto size = 1520af6ee580SValentin Clement rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, byteWidth, len); 1521af6ee580SValentin Clement return {size, typeCodeVal}; 1522af6ee580SValentin Clement }; 1523af6ee580SValentin Clement auto getKindMap = [&]() -> fir::KindMapping & { 1524af6ee580SValentin Clement return this->lowerTy().getKindMap(); 1525af6ee580SValentin Clement }; 1526af6ee580SValentin Clement // Pointer-like types. 1527af6ee580SValentin Clement if (auto eleTy = fir::dyn_cast_ptrEleTy(boxEleTy)) 1528af6ee580SValentin Clement boxEleTy = eleTy; 1529af6ee580SValentin Clement // Integer types. 1530af6ee580SValentin Clement if (fir::isa_integer(boxEleTy)) { 1531af6ee580SValentin Clement if (auto ty = boxEleTy.dyn_cast<mlir::IntegerType>()) 1532af6ee580SValentin Clement return doInteger(ty.getWidth()); 1533af6ee580SValentin Clement auto ty = boxEleTy.cast<fir::IntegerType>(); 1534af6ee580SValentin Clement return doInteger(getKindMap().getIntegerBitsize(ty.getFKind())); 1535af6ee580SValentin Clement } 1536af6ee580SValentin Clement // Floating point types. 1537af6ee580SValentin Clement if (fir::isa_real(boxEleTy)) { 1538af6ee580SValentin Clement if (auto ty = boxEleTy.dyn_cast<mlir::FloatType>()) 1539af6ee580SValentin Clement return doFloat(ty.getWidth()); 1540af6ee580SValentin Clement auto ty = boxEleTy.cast<fir::RealType>(); 1541af6ee580SValentin Clement return doFloat(getKindMap().getRealBitsize(ty.getFKind())); 1542af6ee580SValentin Clement } 1543af6ee580SValentin Clement // Complex types. 1544af6ee580SValentin Clement if (fir::isa_complex(boxEleTy)) { 1545af6ee580SValentin Clement if (auto ty = boxEleTy.dyn_cast<mlir::ComplexType>()) 1546af6ee580SValentin Clement return doComplex( 1547af6ee580SValentin Clement ty.getElementType().cast<mlir::FloatType>().getWidth()); 1548af6ee580SValentin Clement auto ty = boxEleTy.cast<fir::ComplexType>(); 1549af6ee580SValentin Clement return doComplex(getKindMap().getRealBitsize(ty.getFKind())); 1550af6ee580SValentin Clement } 1551af6ee580SValentin Clement // Character types. 1552af6ee580SValentin Clement if (auto ty = boxEleTy.dyn_cast<fir::CharacterType>()) { 1553af6ee580SValentin Clement auto charWidth = getKindMap().getCharacterBitsize(ty.getFKind()); 1554af6ee580SValentin Clement if (ty.getLen() != fir::CharacterType::unknownLen()) { 1555af6ee580SValentin Clement auto len = this->genConstantOffset(loc, rewriter, ty.getLen()); 1556af6ee580SValentin Clement return doCharacter(charWidth, len); 1557af6ee580SValentin Clement } 1558af6ee580SValentin Clement assert(!lenParams.empty()); 1559af6ee580SValentin Clement return doCharacter(charWidth, lenParams.back()); 1560af6ee580SValentin Clement } 1561af6ee580SValentin Clement // Logical type. 1562af6ee580SValentin Clement if (auto ty = boxEleTy.dyn_cast<fir::LogicalType>()) 1563af6ee580SValentin Clement return doLogical(getKindMap().getLogicalBitsize(ty.getFKind())); 1564af6ee580SValentin Clement // Array types. 1565af6ee580SValentin Clement if (auto seqTy = boxEleTy.dyn_cast<fir::SequenceType>()) 1566af6ee580SValentin Clement return getSizeAndTypeCode(loc, rewriter, seqTy.getEleTy(), lenParams); 1567af6ee580SValentin Clement // Derived-type types. 1568af6ee580SValentin Clement if (boxEleTy.isa<fir::RecordType>()) { 1569af6ee580SValentin Clement auto ptrTy = mlir::LLVM::LLVMPointerType::get( 1570af6ee580SValentin Clement this->lowerTy().convertType(boxEleTy)); 1571af6ee580SValentin Clement auto nullPtr = rewriter.create<mlir::LLVM::NullOp>(loc, ptrTy); 1572af6ee580SValentin Clement auto one = 1573af6ee580SValentin Clement genConstantIndex(loc, this->lowerTy().offsetType(), rewriter, 1); 157430122656SAlex Zinenko auto gep = rewriter.create<mlir::LLVM::GEPOp>(loc, ptrTy, nullPtr, 157530122656SAlex Zinenko mlir::ValueRange{one}); 1576af6ee580SValentin Clement auto eleSize = rewriter.create<mlir::LLVM::PtrToIntOp>( 1577af6ee580SValentin Clement loc, this->lowerTy().indexType(), gep); 1578af6ee580SValentin Clement return {eleSize, 1579af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, fir::derivedToTypeCode())}; 1580af6ee580SValentin Clement } 1581af6ee580SValentin Clement // Reference type. 1582af6ee580SValentin Clement if (fir::isa_ref_type(boxEleTy)) { 1583af6ee580SValentin Clement // FIXME: use the target pointer size rather than sizeof(void*) 1584af6ee580SValentin Clement return {this->genConstantOffset(loc, rewriter, sizeof(void *)), 1585af6ee580SValentin Clement this->genConstantOffset(loc, rewriter, CFI_type_cptr)}; 1586af6ee580SValentin Clement } 1587af6ee580SValentin Clement fir::emitFatalError(loc, "unhandled type in fir.box code generation"); 1588af6ee580SValentin Clement } 1589af6ee580SValentin Clement 1590af6ee580SValentin Clement /// Basic pattern to write a field in the descriptor 1591af6ee580SValentin Clement mlir::Value insertField(mlir::ConversionPatternRewriter &rewriter, 1592af6ee580SValentin Clement mlir::Location loc, mlir::Value dest, 1593af6ee580SValentin Clement ArrayRef<unsigned> fldIndexes, mlir::Value value, 1594af6ee580SValentin Clement bool bitcast = false) const { 1595af6ee580SValentin Clement auto boxTy = dest.getType(); 1596af6ee580SValentin Clement auto fldTy = this->getBoxEleTy(boxTy, fldIndexes); 1597af6ee580SValentin Clement if (bitcast) 1598af6ee580SValentin Clement value = rewriter.create<mlir::LLVM::BitcastOp>(loc, fldTy, value); 1599af6ee580SValentin Clement else 1600af6ee580SValentin Clement value = this->integerCast(loc, rewriter, fldTy, value); 1601af6ee580SValentin Clement SmallVector<mlir::Attribute, 2> attrs; 1602af6ee580SValentin Clement for (auto i : fldIndexes) 1603af6ee580SValentin Clement attrs.push_back(rewriter.getI32IntegerAttr(i)); 1604af6ee580SValentin Clement auto indexesAttr = mlir::ArrayAttr::get(rewriter.getContext(), attrs); 1605af6ee580SValentin Clement return rewriter.create<mlir::LLVM::InsertValueOp>(loc, boxTy, dest, value, 1606af6ee580SValentin Clement indexesAttr); 1607af6ee580SValentin Clement } 1608af6ee580SValentin Clement 1609af6ee580SValentin Clement inline mlir::Value 1610af6ee580SValentin Clement insertBaseAddress(mlir::ConversionPatternRewriter &rewriter, 1611af6ee580SValentin Clement mlir::Location loc, mlir::Value dest, 1612af6ee580SValentin Clement mlir::Value base) const { 16131f551032SValentin Clement return insertField(rewriter, loc, dest, {kAddrPosInBox}, base, 16141f551032SValentin Clement /*bitCast=*/true); 16151f551032SValentin Clement } 16161f551032SValentin Clement 16171f551032SValentin Clement inline mlir::Value insertLowerBound(mlir::ConversionPatternRewriter &rewriter, 16181f551032SValentin Clement mlir::Location loc, mlir::Value dest, 16191f551032SValentin Clement unsigned dim, mlir::Value lb) const { 16201f551032SValentin Clement return insertField(rewriter, loc, dest, 16211f551032SValentin Clement {kDimsPosInBox, dim, kDimLowerBoundPos}, lb); 16221f551032SValentin Clement } 16231f551032SValentin Clement 16241f551032SValentin Clement inline mlir::Value insertExtent(mlir::ConversionPatternRewriter &rewriter, 16251f551032SValentin Clement mlir::Location loc, mlir::Value dest, 16261f551032SValentin Clement unsigned dim, mlir::Value extent) const { 16271f551032SValentin Clement return insertField(rewriter, loc, dest, {kDimsPosInBox, dim, kDimExtentPos}, 16281f551032SValentin Clement extent); 16291f551032SValentin Clement } 16301f551032SValentin Clement 16311f551032SValentin Clement inline mlir::Value insertStride(mlir::ConversionPatternRewriter &rewriter, 16321f551032SValentin Clement mlir::Location loc, mlir::Value dest, 16331f551032SValentin Clement unsigned dim, mlir::Value stride) const { 16341f551032SValentin Clement return insertField(rewriter, loc, dest, {kDimsPosInBox, dim, kDimStridePos}, 16351f551032SValentin Clement stride); 1636af6ee580SValentin Clement } 1637af6ee580SValentin Clement 1638af6ee580SValentin Clement /// Get the address of the type descriptor global variable that was created by 1639af6ee580SValentin Clement /// lowering for derived type \p recType. 1640af6ee580SValentin Clement template <typename BOX> 1641af6ee580SValentin Clement mlir::Value 1642af6ee580SValentin Clement getTypeDescriptor(BOX box, mlir::ConversionPatternRewriter &rewriter, 1643af6ee580SValentin Clement mlir::Location loc, fir::RecordType recType) const { 164474acd744SValentin Clement std::string name = recType.translateNameToFrontendMangledName(); 1645af6ee580SValentin Clement auto module = box->template getParentOfType<mlir::ModuleOp>(); 1646af6ee580SValentin Clement if (auto global = module.template lookupSymbol<fir::GlobalOp>(name)) { 1647af6ee580SValentin Clement auto ty = mlir::LLVM::LLVMPointerType::get( 1648af6ee580SValentin Clement this->lowerTy().convertType(global.getType())); 1649af6ee580SValentin Clement return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty, 1650feeee78aSJacques Pienaar global.getSymName()); 1651af6ee580SValentin Clement } 1652af6ee580SValentin Clement if (auto global = 1653af6ee580SValentin Clement module.template lookupSymbol<mlir::LLVM::GlobalOp>(name)) { 1654af6ee580SValentin Clement // The global may have already been translated to LLVM. 1655af6ee580SValentin Clement auto ty = mlir::LLVM::LLVMPointerType::get(global.getType()); 1656af6ee580SValentin Clement return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty, 1657feeee78aSJacques Pienaar global.getSymName()); 1658af6ee580SValentin Clement } 1659af6ee580SValentin Clement // The global does not exist in the current translation unit, but may be 1660af6ee580SValentin Clement // defined elsewhere (e.g., type defined in a module). 1661af6ee580SValentin Clement // For now, create a extern_weak symbol (will become nullptr if unresolved) 1662af6ee580SValentin Clement // to support generating code without the front-end generated symbols. 1663af6ee580SValentin Clement // These could be made available_externally to require the symbols to be 1664af6ee580SValentin Clement // defined elsewhere and to cause link-time failure otherwise. 1665af6ee580SValentin Clement auto i8Ty = rewriter.getIntegerType(8); 1666af6ee580SValentin Clement mlir::OpBuilder modBuilder(module.getBodyRegion()); 1667af6ee580SValentin Clement // TODO: The symbol should be lowered to constant in lowering, they are read 1668af6ee580SValentin Clement // only. 1669af6ee580SValentin Clement modBuilder.create<mlir::LLVM::GlobalOp>(loc, i8Ty, /*isConstant=*/false, 1670af6ee580SValentin Clement mlir::LLVM::Linkage::ExternWeak, 1671af6ee580SValentin Clement name, mlir::Attribute{}); 1672af6ee580SValentin Clement auto ty = mlir::LLVM::LLVMPointerType::get(i8Ty); 1673af6ee580SValentin Clement return rewriter.create<mlir::LLVM::AddressOfOp>(loc, ty, name); 1674af6ee580SValentin Clement } 1675af6ee580SValentin Clement 1676af6ee580SValentin Clement template <typename BOX> 1677af6ee580SValentin Clement std::tuple<fir::BoxType, mlir::Value, mlir::Value> 1678af6ee580SValentin Clement consDescriptorPrefix(BOX box, mlir::ConversionPatternRewriter &rewriter, 1679af6ee580SValentin Clement unsigned rank, mlir::ValueRange lenParams) const { 1680af6ee580SValentin Clement auto loc = box.getLoc(); 1681af6ee580SValentin Clement auto boxTy = box.getType().template dyn_cast<fir::BoxType>(); 1682af6ee580SValentin Clement auto convTy = this->lowerTy().convertBoxType(boxTy, rank); 1683af6ee580SValentin Clement auto llvmBoxPtrTy = convTy.template cast<mlir::LLVM::LLVMPointerType>(); 1684af6ee580SValentin Clement auto llvmBoxTy = llvmBoxPtrTy.getElementType(); 1685af6ee580SValentin Clement mlir::Value descriptor = 1686af6ee580SValentin Clement rewriter.create<mlir::LLVM::UndefOp>(loc, llvmBoxTy); 1687af6ee580SValentin Clement 1688af6ee580SValentin Clement llvm::SmallVector<mlir::Value> typeparams = lenParams; 1689af6ee580SValentin Clement if constexpr (!std::is_same_v<BOX, fir::EmboxOp>) { 1690af6ee580SValentin Clement if (!box.substr().empty() && fir::hasDynamicSize(boxTy.getEleTy())) 1691af6ee580SValentin Clement typeparams.push_back(box.substr()[1]); 1692af6ee580SValentin Clement } 1693af6ee580SValentin Clement 1694af6ee580SValentin Clement // Write each of the fields with the appropriate values 1695af6ee580SValentin Clement auto [eleSize, cfiTy] = 1696af6ee580SValentin Clement getSizeAndTypeCode(loc, rewriter, boxTy.getEleTy(), typeparams); 1697af6ee580SValentin Clement descriptor = 1698af6ee580SValentin Clement insertField(rewriter, loc, descriptor, {kElemLenPosInBox}, eleSize); 1699af6ee580SValentin Clement descriptor = insertField(rewriter, loc, descriptor, {kVersionPosInBox}, 1700af6ee580SValentin Clement this->genI32Constant(loc, rewriter, CFI_VERSION)); 1701af6ee580SValentin Clement descriptor = insertField(rewriter, loc, descriptor, {kRankPosInBox}, 1702af6ee580SValentin Clement this->genI32Constant(loc, rewriter, rank)); 1703af6ee580SValentin Clement descriptor = insertField(rewriter, loc, descriptor, {kTypePosInBox}, cfiTy); 1704af6ee580SValentin Clement descriptor = 1705af6ee580SValentin Clement insertField(rewriter, loc, descriptor, {kAttributePosInBox}, 1706af6ee580SValentin Clement this->genI32Constant(loc, rewriter, getCFIAttr(boxTy))); 1707af6ee580SValentin Clement const bool hasAddendum = isDerivedType(boxTy); 1708af6ee580SValentin Clement descriptor = 1709af6ee580SValentin Clement insertField(rewriter, loc, descriptor, {kF18AddendumPosInBox}, 1710af6ee580SValentin Clement this->genI32Constant(loc, rewriter, hasAddendum ? 1 : 0)); 1711af6ee580SValentin Clement 1712af6ee580SValentin Clement if (hasAddendum) { 1713af6ee580SValentin Clement auto isArray = 1714af6ee580SValentin Clement fir::dyn_cast_ptrOrBoxEleTy(boxTy).template isa<fir::SequenceType>(); 1715af6ee580SValentin Clement unsigned typeDescFieldId = isArray ? kOptTypePtrPosInBox : kDimsPosInBox; 1716af6ee580SValentin Clement auto typeDesc = 1717af6ee580SValentin Clement getTypeDescriptor(box, rewriter, loc, unwrapIfDerived(boxTy)); 1718af6ee580SValentin Clement descriptor = 1719af6ee580SValentin Clement insertField(rewriter, loc, descriptor, {typeDescFieldId}, typeDesc, 1720af6ee580SValentin Clement /*bitCast=*/true); 1721af6ee580SValentin Clement } 1722af6ee580SValentin Clement 1723af6ee580SValentin Clement return {boxTy, descriptor, eleSize}; 1724af6ee580SValentin Clement } 1725af6ee580SValentin Clement 17261f551032SValentin Clement /// Compute the base address of a substring given the base address of a scalar 17271f551032SValentin Clement /// string and the zero based string lower bound. 17281f551032SValentin Clement mlir::Value shiftSubstringBase(mlir::ConversionPatternRewriter &rewriter, 17291f551032SValentin Clement mlir::Location loc, mlir::Value base, 17301f551032SValentin Clement mlir::Value lowerBound) const { 17311f551032SValentin Clement llvm::SmallVector<mlir::Value> gepOperands; 17321f551032SValentin Clement auto baseType = 17331f551032SValentin Clement base.getType().cast<mlir::LLVM::LLVMPointerType>().getElementType(); 17341f551032SValentin Clement if (baseType.isa<mlir::LLVM::LLVMArrayType>()) { 17351f551032SValentin Clement auto idxTy = this->lowerTy().indexType(); 17361f551032SValentin Clement mlir::Value zero = genConstantIndex(loc, idxTy, rewriter, 0); 17371f551032SValentin Clement gepOperands.push_back(zero); 17381f551032SValentin Clement } 17391f551032SValentin Clement gepOperands.push_back(lowerBound); 17401f551032SValentin Clement return this->genGEP(loc, base.getType(), rewriter, base, gepOperands); 17411f551032SValentin Clement } 17421f551032SValentin Clement 1743af6ee580SValentin Clement /// If the embox is not in a globalOp body, allocate storage for the box; 1744af6ee580SValentin Clement /// store the value inside and return the generated alloca. Return the input 1745af6ee580SValentin Clement /// value otherwise. 1746af6ee580SValentin Clement mlir::Value 1747af6ee580SValentin Clement placeInMemoryIfNotGlobalInit(mlir::ConversionPatternRewriter &rewriter, 1748af6ee580SValentin Clement mlir::Location loc, mlir::Value boxValue) const { 1749af6ee580SValentin Clement auto *thisBlock = rewriter.getInsertionBlock(); 1750af6ee580SValentin Clement if (thisBlock && mlir::isa<mlir::LLVM::GlobalOp>(thisBlock->getParentOp())) 1751af6ee580SValentin Clement return boxValue; 1752af6ee580SValentin Clement auto boxPtrTy = mlir::LLVM::LLVMPointerType::get(boxValue.getType()); 1753af6ee580SValentin Clement auto alloca = genAllocaWithType(loc, boxPtrTy, defaultAlign, rewriter); 1754af6ee580SValentin Clement rewriter.create<mlir::LLVM::StoreOp>(loc, boxValue, alloca); 1755af6ee580SValentin Clement return alloca; 1756af6ee580SValentin Clement } 1757af6ee580SValentin Clement }; 1758af6ee580SValentin Clement 17591f551032SValentin Clement /// Compute the extent of a triplet slice (lb:ub:step). 17601f551032SValentin Clement static mlir::Value 17611f551032SValentin Clement computeTripletExtent(mlir::ConversionPatternRewriter &rewriter, 17621f551032SValentin Clement mlir::Location loc, mlir::Value lb, mlir::Value ub, 17631f551032SValentin Clement mlir::Value step, mlir::Value zero, mlir::Type type) { 17641f551032SValentin Clement mlir::Value extent = rewriter.create<mlir::LLVM::SubOp>(loc, type, ub, lb); 17651f551032SValentin Clement extent = rewriter.create<mlir::LLVM::AddOp>(loc, type, extent, step); 17661f551032SValentin Clement extent = rewriter.create<mlir::LLVM::SDivOp>(loc, type, extent, step); 17671f551032SValentin Clement // If the resulting extent is negative (`ub-lb` and `step` have different 17681f551032SValentin Clement // signs), zero must be returned instead. 17691f551032SValentin Clement auto cmp = rewriter.create<mlir::LLVM::ICmpOp>( 17701f551032SValentin Clement loc, mlir::LLVM::ICmpPredicate::sgt, extent, zero); 17711f551032SValentin Clement return rewriter.create<mlir::LLVM::SelectOp>(loc, cmp, extent, zero); 17721f551032SValentin Clement } 17731f551032SValentin Clement 1774af6ee580SValentin Clement /// Create a generic box on a memory reference. This conversions lowers the 1775af6ee580SValentin Clement /// abstract box to the appropriate, initialized descriptor. 1776af6ee580SValentin Clement struct EmboxOpConversion : public EmboxCommonConversion<fir::EmboxOp> { 1777af6ee580SValentin Clement using EmboxCommonConversion::EmboxCommonConversion; 1778af6ee580SValentin Clement 1779af6ee580SValentin Clement mlir::LogicalResult 1780af6ee580SValentin Clement matchAndRewrite(fir::EmboxOp embox, OpAdaptor adaptor, 1781af6ee580SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 1782af6ee580SValentin Clement assert(!embox.getShape() && "There should be no dims on this embox op"); 1783af6ee580SValentin Clement auto [boxTy, dest, eleSize] = 1784af6ee580SValentin Clement consDescriptorPrefix(embox, rewriter, /*rank=*/0, 1785af6ee580SValentin Clement /*lenParams=*/adaptor.getOperands().drop_front(1)); 1786af6ee580SValentin Clement dest = insertBaseAddress(rewriter, embox.getLoc(), dest, 1787af6ee580SValentin Clement adaptor.getOperands()[0]); 17887ce8c6fcSKiran Chandramohan if (isDerivedTypeWithLenParams(boxTy)) { 17897ce8c6fcSKiran Chandramohan TODO(embox.getLoc(), 17907ce8c6fcSKiran Chandramohan "fir.embox codegen of derived with length parameters"); 17917ce8c6fcSKiran Chandramohan return failure(); 17927ce8c6fcSKiran Chandramohan } 1793af6ee580SValentin Clement auto result = placeInMemoryIfNotGlobalInit(rewriter, embox.getLoc(), dest); 1794af6ee580SValentin Clement rewriter.replaceOp(embox, result); 1795af6ee580SValentin Clement return success(); 1796af6ee580SValentin Clement } 1797af6ee580SValentin Clement }; 1798af6ee580SValentin Clement 1799cc505c0bSKiran Chandramohan /// Lower `fir.emboxproc` operation. Creates a procedure box. 1800cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers. 1801cc505c0bSKiran Chandramohan struct EmboxProcOpConversion : public FIROpConversion<fir::EmboxProcOp> { 1802cc505c0bSKiran Chandramohan using FIROpConversion::FIROpConversion; 1803cc505c0bSKiran Chandramohan 1804cc505c0bSKiran Chandramohan mlir::LogicalResult 1805cc505c0bSKiran Chandramohan matchAndRewrite(fir::EmboxProcOp emboxproc, OpAdaptor adaptor, 1806cc505c0bSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 18077ce8c6fcSKiran Chandramohan TODO(emboxproc.getLoc(), "fir.emboxproc codegen"); 18087ce8c6fcSKiran Chandramohan return failure(); 1809cc505c0bSKiran Chandramohan } 1810cc505c0bSKiran Chandramohan }; 1811cc505c0bSKiran Chandramohan 18121f551032SValentin Clement /// Create a generic box on a memory reference. 18131f551032SValentin Clement struct XEmboxOpConversion : public EmboxCommonConversion<fir::cg::XEmboxOp> { 18141f551032SValentin Clement using EmboxCommonConversion::EmboxCommonConversion; 18151f551032SValentin Clement 18161f551032SValentin Clement mlir::LogicalResult 18171f551032SValentin Clement matchAndRewrite(fir::cg::XEmboxOp xbox, OpAdaptor adaptor, 18181f551032SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 18191f551032SValentin Clement auto [boxTy, dest, eleSize] = consDescriptorPrefix( 18201f551032SValentin Clement xbox, rewriter, xbox.getOutRank(), 18211f551032SValentin Clement adaptor.getOperands().drop_front(xbox.lenParamOffset())); 18221f551032SValentin Clement // Generate the triples in the dims field of the descriptor 18231f551032SValentin Clement mlir::ValueRange operands = adaptor.getOperands(); 18241f551032SValentin Clement auto i64Ty = mlir::IntegerType::get(xbox.getContext(), 64); 18251f551032SValentin Clement mlir::Value base = operands[0]; 18261f551032SValentin Clement assert(!xbox.shape().empty() && "must have a shape"); 18271f551032SValentin Clement unsigned shapeOffset = xbox.shapeOffset(); 18281f551032SValentin Clement bool hasShift = !xbox.shift().empty(); 18291f551032SValentin Clement unsigned shiftOffset = xbox.shiftOffset(); 18301f551032SValentin Clement bool hasSlice = !xbox.slice().empty(); 18311f551032SValentin Clement unsigned sliceOffset = xbox.sliceOffset(); 18321f551032SValentin Clement mlir::Location loc = xbox.getLoc(); 18331f551032SValentin Clement mlir::Value zero = genConstantIndex(loc, i64Ty, rewriter, 0); 18341f551032SValentin Clement mlir::Value one = genConstantIndex(loc, i64Ty, rewriter, 1); 18351f551032SValentin Clement mlir::Value prevDim = integerCast(loc, rewriter, i64Ty, eleSize); 18361f551032SValentin Clement mlir::Value prevPtrOff = one; 18371f551032SValentin Clement mlir::Type eleTy = boxTy.getEleTy(); 18381f551032SValentin Clement const unsigned rank = xbox.getRank(); 18391f551032SValentin Clement llvm::SmallVector<mlir::Value> gepArgs; 18401f551032SValentin Clement unsigned constRows = 0; 18411f551032SValentin Clement mlir::Value ptrOffset = zero; 18421f551032SValentin Clement if (auto memEleTy = fir::dyn_cast_ptrEleTy(xbox.memref().getType())) 18431f551032SValentin Clement if (auto seqTy = memEleTy.dyn_cast<fir::SequenceType>()) { 18441f551032SValentin Clement mlir::Type seqEleTy = seqTy.getEleTy(); 18451f551032SValentin Clement // Adjust the element scaling factor if the element is a dependent type. 18461f551032SValentin Clement if (fir::hasDynamicSize(seqEleTy)) { 18471f551032SValentin Clement if (fir::isa_char(seqEleTy)) { 18481f551032SValentin Clement assert(xbox.lenParams().size() == 1); 18491f551032SValentin Clement prevPtrOff = integerCast(loc, rewriter, i64Ty, 18501f551032SValentin Clement operands[xbox.lenParamOffset()]); 18511f551032SValentin Clement } else if (seqEleTy.isa<fir::RecordType>()) { 18521f551032SValentin Clement TODO(loc, "generate call to calculate size of PDT"); 18531f551032SValentin Clement } else { 18541f551032SValentin Clement return rewriter.notifyMatchFailure(xbox, "unexpected dynamic type"); 18551f551032SValentin Clement } 18561f551032SValentin Clement } else { 18571f551032SValentin Clement constRows = seqTy.getConstantRows(); 18581f551032SValentin Clement } 18591f551032SValentin Clement } 18601f551032SValentin Clement 18611f551032SValentin Clement bool hasSubcomp = !xbox.subcomponent().empty(); 18621f551032SValentin Clement mlir::Value stepExpr; 18631f551032SValentin Clement if (hasSubcomp) { 18641f551032SValentin Clement // We have a subcomponent. The step value needs to be the number of 18651f551032SValentin Clement // bytes per element (which is a derived type). 18661f551032SValentin Clement mlir::Type ty0 = base.getType(); 18671f551032SValentin Clement [[maybe_unused]] auto ptrTy = ty0.dyn_cast<mlir::LLVM::LLVMPointerType>(); 18681f551032SValentin Clement assert(ptrTy && "expected pointer type"); 18691f551032SValentin Clement mlir::Type memEleTy = fir::dyn_cast_ptrEleTy(xbox.memref().getType()); 18701f551032SValentin Clement assert(memEleTy && "expected fir pointer type"); 18711f551032SValentin Clement auto seqTy = memEleTy.dyn_cast<fir::SequenceType>(); 18721f551032SValentin Clement assert(seqTy && "expected sequence type"); 18731f551032SValentin Clement mlir::Type seqEleTy = seqTy.getEleTy(); 18741f551032SValentin Clement auto eleTy = mlir::LLVM::LLVMPointerType::get(convertType(seqEleTy)); 18751f551032SValentin Clement stepExpr = computeDerivedTypeSize(loc, eleTy, i64Ty, rewriter); 18761f551032SValentin Clement } 18771f551032SValentin Clement 18781f551032SValentin Clement // Process the array subspace arguments (shape, shift, etc.), if any, 18791f551032SValentin Clement // translating everything to values in the descriptor wherever the entity 18801f551032SValentin Clement // has a dynamic array dimension. 18811f551032SValentin Clement for (unsigned di = 0, descIdx = 0; di < rank; ++di) { 18821f551032SValentin Clement mlir::Value extent = operands[shapeOffset]; 18831f551032SValentin Clement mlir::Value outerExtent = extent; 18841f551032SValentin Clement bool skipNext = false; 18851f551032SValentin Clement if (hasSlice) { 18861f551032SValentin Clement mlir::Value off = operands[sliceOffset]; 18871f551032SValentin Clement mlir::Value adj = one; 18881f551032SValentin Clement if (hasShift) 18891f551032SValentin Clement adj = operands[shiftOffset]; 18901f551032SValentin Clement auto ao = rewriter.create<mlir::LLVM::SubOp>(loc, i64Ty, off, adj); 18911f551032SValentin Clement if (constRows > 0) { 18921f551032SValentin Clement gepArgs.push_back(ao); 18931f551032SValentin Clement --constRows; 18941f551032SValentin Clement } else { 18951f551032SValentin Clement auto dimOff = 18961f551032SValentin Clement rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, ao, prevPtrOff); 18971f551032SValentin Clement ptrOffset = 18981f551032SValentin Clement rewriter.create<mlir::LLVM::AddOp>(loc, i64Ty, dimOff, ptrOffset); 18991f551032SValentin Clement } 19001f551032SValentin Clement if (mlir::isa_and_nonnull<fir::UndefOp>( 19011f551032SValentin Clement xbox.slice()[3 * di + 1].getDefiningOp())) { 19021f551032SValentin Clement // This dimension contains a scalar expression in the array slice op. 19031f551032SValentin Clement // The dimension is loop invariant, will be dropped, and will not 19041f551032SValentin Clement // appear in the descriptor. 19051f551032SValentin Clement skipNext = true; 19061f551032SValentin Clement } 19071f551032SValentin Clement } 19081f551032SValentin Clement if (!skipNext) { 19091f551032SValentin Clement // store lower bound (normally 0) 19101f551032SValentin Clement mlir::Value lb = zero; 19111f551032SValentin Clement if (eleTy.isa<fir::PointerType>() || eleTy.isa<fir::HeapType>()) { 19121f551032SValentin Clement lb = one; 19131f551032SValentin Clement if (hasShift) 19141f551032SValentin Clement lb = operands[shiftOffset]; 19151f551032SValentin Clement } 19161f551032SValentin Clement dest = insertLowerBound(rewriter, loc, dest, descIdx, lb); 19171f551032SValentin Clement 19181f551032SValentin Clement // store extent 19191f551032SValentin Clement if (hasSlice) 19201f551032SValentin Clement extent = computeTripletExtent(rewriter, loc, operands[sliceOffset], 19211f551032SValentin Clement operands[sliceOffset + 1], 19221f551032SValentin Clement operands[sliceOffset + 2], zero, i64Ty); 19231f551032SValentin Clement dest = insertExtent(rewriter, loc, dest, descIdx, extent); 19241f551032SValentin Clement 19251f551032SValentin Clement // store step (scaled by shaped extent) 19261f551032SValentin Clement 19271f551032SValentin Clement mlir::Value step = hasSubcomp ? stepExpr : prevDim; 19281f551032SValentin Clement if (hasSlice) 19291f551032SValentin Clement step = rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, step, 19301f551032SValentin Clement operands[sliceOffset + 2]); 19311f551032SValentin Clement dest = insertStride(rewriter, loc, dest, descIdx, step); 19321f551032SValentin Clement ++descIdx; 19331f551032SValentin Clement } 19341f551032SValentin Clement 19351f551032SValentin Clement // compute the stride and offset for the next natural dimension 19361f551032SValentin Clement prevDim = 19371f551032SValentin Clement rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, prevDim, outerExtent); 19381f551032SValentin Clement if (constRows == 0) 19391f551032SValentin Clement prevPtrOff = rewriter.create<mlir::LLVM::MulOp>(loc, i64Ty, prevPtrOff, 19401f551032SValentin Clement outerExtent); 19411f551032SValentin Clement 19421f551032SValentin Clement // increment iterators 19431f551032SValentin Clement ++shapeOffset; 19441f551032SValentin Clement if (hasShift) 19451f551032SValentin Clement ++shiftOffset; 19461f551032SValentin Clement if (hasSlice) 19471f551032SValentin Clement sliceOffset += 3; 19481f551032SValentin Clement } 19491f551032SValentin Clement if (hasSlice || hasSubcomp || !xbox.substr().empty()) { 195030122656SAlex Zinenko llvm::SmallVector<mlir::Value> args = {ptrOffset}; 19511f551032SValentin Clement args.append(gepArgs.rbegin(), gepArgs.rend()); 19521f551032SValentin Clement if (hasSubcomp) { 19531f551032SValentin Clement // For each field in the path add the offset to base via the args list. 19541f551032SValentin Clement // In the most general case, some offsets must be computed since 19551f551032SValentin Clement // they are not be known until runtime. 19561f551032SValentin Clement if (fir::hasDynamicSize(fir::unwrapSequenceType( 19571f551032SValentin Clement fir::unwrapPassByRefType(xbox.memref().getType())))) 19581f551032SValentin Clement TODO(loc, "fir.embox codegen dynamic size component in derived type"); 19591f551032SValentin Clement args.append(operands.begin() + xbox.subcomponentOffset(), 19601f551032SValentin Clement operands.begin() + xbox.subcomponentOffset() + 19611f551032SValentin Clement xbox.subcomponent().size()); 19621f551032SValentin Clement } 196330122656SAlex Zinenko base = 196430122656SAlex Zinenko rewriter.create<mlir::LLVM::GEPOp>(loc, base.getType(), base, args); 19651f551032SValentin Clement if (!xbox.substr().empty()) 19661f551032SValentin Clement base = shiftSubstringBase(rewriter, loc, base, 19671f551032SValentin Clement operands[xbox.substrOffset()]); 19681f551032SValentin Clement } 19691f551032SValentin Clement dest = insertBaseAddress(rewriter, loc, dest, base); 19701f551032SValentin Clement if (isDerivedTypeWithLenParams(boxTy)) 19711f551032SValentin Clement TODO(loc, "fir.embox codegen of derived with length parameters"); 19721f551032SValentin Clement 19731f551032SValentin Clement mlir::Value result = placeInMemoryIfNotGlobalInit(rewriter, loc, dest); 19741f551032SValentin Clement rewriter.replaceOp(xbox, result); 19751f551032SValentin Clement return success(); 19761f551032SValentin Clement } 19771f551032SValentin Clement }; 19781f551032SValentin Clement 1979fa517555SKiran Chandramohan /// Create a new box given a box reference. 1980fa517555SKiran Chandramohan struct XReboxOpConversion : public EmboxCommonConversion<fir::cg::XReboxOp> { 1981fa517555SKiran Chandramohan using EmboxCommonConversion::EmboxCommonConversion; 1982fa517555SKiran Chandramohan 1983fa517555SKiran Chandramohan mlir::LogicalResult 1984fa517555SKiran Chandramohan matchAndRewrite(fir::cg::XReboxOp rebox, OpAdaptor adaptor, 1985fa517555SKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 1986fa517555SKiran Chandramohan mlir::Location loc = rebox.getLoc(); 1987fa517555SKiran Chandramohan mlir::Type idxTy = lowerTy().indexType(); 1988fa517555SKiran Chandramohan mlir::Value loweredBox = adaptor.getOperands()[0]; 1989fa517555SKiran Chandramohan mlir::ValueRange operands = adaptor.getOperands(); 1990fa517555SKiran Chandramohan 1991fa517555SKiran Chandramohan // Create new descriptor and fill its non-shape related data. 1992fa517555SKiran Chandramohan llvm::SmallVector<mlir::Value, 2> lenParams; 1993fa517555SKiran Chandramohan mlir::Type inputEleTy = getInputEleTy(rebox); 1994fa517555SKiran Chandramohan if (auto charTy = inputEleTy.dyn_cast<fir::CharacterType>()) { 1995fa517555SKiran Chandramohan mlir::Value len = 1996fa517555SKiran Chandramohan loadElementSizeFromBox(loc, idxTy, loweredBox, rewriter); 1997fa517555SKiran Chandramohan if (charTy.getFKind() != 1) { 1998fa517555SKiran Chandramohan mlir::Value width = 1999fa517555SKiran Chandramohan genConstantIndex(loc, idxTy, rewriter, charTy.getFKind()); 2000fa517555SKiran Chandramohan len = rewriter.create<mlir::LLVM::SDivOp>(loc, idxTy, len, width); 2001fa517555SKiran Chandramohan } 2002fa517555SKiran Chandramohan lenParams.emplace_back(len); 2003fa517555SKiran Chandramohan } else if (auto recTy = inputEleTy.dyn_cast<fir::RecordType>()) { 2004fa517555SKiran Chandramohan if (recTy.getNumLenParams() != 0) 2005fa517555SKiran Chandramohan TODO(loc, "reboxing descriptor of derived type with length parameters"); 2006fa517555SKiran Chandramohan } 2007fa517555SKiran Chandramohan auto [boxTy, dest, eleSize] = 2008fa517555SKiran Chandramohan consDescriptorPrefix(rebox, rewriter, rebox.getOutRank(), lenParams); 2009fa517555SKiran Chandramohan 2010fa517555SKiran Chandramohan // Read input extents, strides, and base address 2011fa517555SKiran Chandramohan llvm::SmallVector<mlir::Value> inputExtents; 2012fa517555SKiran Chandramohan llvm::SmallVector<mlir::Value> inputStrides; 2013fa517555SKiran Chandramohan const unsigned inputRank = rebox.getRank(); 2014fa517555SKiran Chandramohan for (unsigned i = 0; i < inputRank; ++i) { 2015fa517555SKiran Chandramohan mlir::Value dim = genConstantIndex(loc, idxTy, rewriter, i); 2016fa517555SKiran Chandramohan SmallVector<mlir::Value, 3> dimInfo = 2017fa517555SKiran Chandramohan getDimsFromBox(loc, {idxTy, idxTy, idxTy}, loweredBox, dim, rewriter); 2018fa517555SKiran Chandramohan inputExtents.emplace_back(dimInfo[1]); 2019fa517555SKiran Chandramohan inputStrides.emplace_back(dimInfo[2]); 2020fa517555SKiran Chandramohan } 2021fa517555SKiran Chandramohan 2022fa517555SKiran Chandramohan mlir::Type baseTy = getBaseAddrTypeFromBox(loweredBox.getType()); 2023fa517555SKiran Chandramohan mlir::Value baseAddr = 2024fa517555SKiran Chandramohan loadBaseAddrFromBox(loc, baseTy, loweredBox, rewriter); 2025fa517555SKiran Chandramohan 2026fa517555SKiran Chandramohan if (!rebox.slice().empty() || !rebox.subcomponent().empty()) 2027fa517555SKiran Chandramohan return sliceBox(rebox, dest, baseAddr, inputExtents, inputStrides, 2028fa517555SKiran Chandramohan operands, rewriter); 2029fa517555SKiran Chandramohan return reshapeBox(rebox, dest, baseAddr, inputExtents, inputStrides, 2030fa517555SKiran Chandramohan operands, rewriter); 2031fa517555SKiran Chandramohan } 2032fa517555SKiran Chandramohan 2033fa517555SKiran Chandramohan private: 2034fa517555SKiran Chandramohan /// Write resulting shape and base address in descriptor, and replace rebox 2035fa517555SKiran Chandramohan /// op. 2036fa517555SKiran Chandramohan mlir::LogicalResult 2037fa517555SKiran Chandramohan finalizeRebox(fir::cg::XReboxOp rebox, mlir::Value dest, mlir::Value base, 2038fa517555SKiran Chandramohan mlir::ValueRange lbounds, mlir::ValueRange extents, 2039fa517555SKiran Chandramohan mlir::ValueRange strides, 2040fa517555SKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const { 2041fa517555SKiran Chandramohan mlir::Location loc = rebox.getLoc(); 2042fa517555SKiran Chandramohan mlir::Value one = genConstantIndex(loc, lowerTy().indexType(), rewriter, 1); 2043fa517555SKiran Chandramohan for (auto iter : llvm::enumerate(llvm::zip(extents, strides))) { 2044fa517555SKiran Chandramohan unsigned dim = iter.index(); 2045fa517555SKiran Chandramohan mlir::Value lb = lbounds.empty() ? one : lbounds[dim]; 2046fa517555SKiran Chandramohan dest = insertLowerBound(rewriter, loc, dest, dim, lb); 2047fa517555SKiran Chandramohan dest = insertExtent(rewriter, loc, dest, dim, std::get<0>(iter.value())); 2048fa517555SKiran Chandramohan dest = insertStride(rewriter, loc, dest, dim, std::get<1>(iter.value())); 2049fa517555SKiran Chandramohan } 2050fa517555SKiran Chandramohan dest = insertBaseAddress(rewriter, loc, dest, base); 2051fa517555SKiran Chandramohan mlir::Value result = 2052fa517555SKiran Chandramohan placeInMemoryIfNotGlobalInit(rewriter, rebox.getLoc(), dest); 2053fa517555SKiran Chandramohan rewriter.replaceOp(rebox, result); 2054fa517555SKiran Chandramohan return success(); 2055fa517555SKiran Chandramohan } 2056fa517555SKiran Chandramohan 2057fa517555SKiran Chandramohan // Apply slice given the base address, extents and strides of the input box. 2058fa517555SKiran Chandramohan mlir::LogicalResult 2059fa517555SKiran Chandramohan sliceBox(fir::cg::XReboxOp rebox, mlir::Value dest, mlir::Value base, 2060fa517555SKiran Chandramohan mlir::ValueRange inputExtents, mlir::ValueRange inputStrides, 2061fa517555SKiran Chandramohan mlir::ValueRange operands, 2062fa517555SKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const { 2063fa517555SKiran Chandramohan mlir::Location loc = rebox.getLoc(); 2064fa517555SKiran Chandramohan mlir::Type voidPtrTy = ::getVoidPtrType(rebox.getContext()); 2065fa517555SKiran Chandramohan mlir::Type idxTy = lowerTy().indexType(); 2066fa517555SKiran Chandramohan mlir::Value zero = genConstantIndex(loc, idxTy, rewriter, 0); 2067fa517555SKiran Chandramohan // Apply subcomponent and substring shift on base address. 2068fa517555SKiran Chandramohan if (!rebox.subcomponent().empty() || !rebox.substr().empty()) { 2069fa517555SKiran Chandramohan // Cast to inputEleTy* so that a GEP can be used. 2070fa517555SKiran Chandramohan mlir::Type inputEleTy = getInputEleTy(rebox); 2071fa517555SKiran Chandramohan auto llvmElePtrTy = 2072fa517555SKiran Chandramohan mlir::LLVM::LLVMPointerType::get(convertType(inputEleTy)); 2073fa517555SKiran Chandramohan base = rewriter.create<mlir::LLVM::BitcastOp>(loc, llvmElePtrTy, base); 2074fa517555SKiran Chandramohan 2075fa517555SKiran Chandramohan if (!rebox.subcomponent().empty()) { 2076fa517555SKiran Chandramohan llvm::SmallVector<mlir::Value> gepOperands = {zero}; 2077fa517555SKiran Chandramohan for (unsigned i = 0; i < rebox.subcomponent().size(); ++i) 2078fa517555SKiran Chandramohan gepOperands.push_back(operands[rebox.subcomponentOffset() + i]); 2079fa517555SKiran Chandramohan base = genGEP(loc, llvmElePtrTy, rewriter, base, gepOperands); 2080fa517555SKiran Chandramohan } 2081fa517555SKiran Chandramohan if (!rebox.substr().empty()) 2082fa517555SKiran Chandramohan base = shiftSubstringBase(rewriter, loc, base, 2083fa517555SKiran Chandramohan operands[rebox.substrOffset()]); 2084fa517555SKiran Chandramohan } 2085fa517555SKiran Chandramohan 2086fa517555SKiran Chandramohan if (rebox.slice().empty()) 2087fa517555SKiran Chandramohan // The array section is of the form array[%component][substring], keep 2088fa517555SKiran Chandramohan // the input array extents and strides. 2089fa517555SKiran Chandramohan return finalizeRebox(rebox, dest, base, /*lbounds*/ llvm::None, 2090fa517555SKiran Chandramohan inputExtents, inputStrides, rewriter); 2091fa517555SKiran Chandramohan 2092fa517555SKiran Chandramohan // Strides from the fir.box are in bytes. 2093fa517555SKiran Chandramohan base = rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, base); 2094fa517555SKiran Chandramohan 2095fa517555SKiran Chandramohan // The slice is of the form array(i:j:k)[%component]. Compute new extents 2096fa517555SKiran Chandramohan // and strides. 2097fa517555SKiran Chandramohan llvm::SmallVector<mlir::Value> slicedExtents; 2098fa517555SKiran Chandramohan llvm::SmallVector<mlir::Value> slicedStrides; 2099fa517555SKiran Chandramohan mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1); 2100fa517555SKiran Chandramohan const bool sliceHasOrigins = !rebox.shift().empty(); 2101fa517555SKiran Chandramohan unsigned sliceOps = rebox.sliceOffset(); 2102fa517555SKiran Chandramohan unsigned shiftOps = rebox.shiftOffset(); 2103fa517555SKiran Chandramohan auto strideOps = inputStrides.begin(); 2104fa517555SKiran Chandramohan const unsigned inputRank = inputStrides.size(); 2105fa517555SKiran Chandramohan for (unsigned i = 0; i < inputRank; 2106fa517555SKiran Chandramohan ++i, ++strideOps, ++shiftOps, sliceOps += 3) { 2107fa517555SKiran Chandramohan mlir::Value sliceLb = 2108fa517555SKiran Chandramohan integerCast(loc, rewriter, idxTy, operands[sliceOps]); 2109fa517555SKiran Chandramohan mlir::Value inputStride = *strideOps; // already idxTy 2110fa517555SKiran Chandramohan // Apply origin shift: base += (lb-shift)*input_stride 2111fa517555SKiran Chandramohan mlir::Value sliceOrigin = 2112fa517555SKiran Chandramohan sliceHasOrigins 2113fa517555SKiran Chandramohan ? integerCast(loc, rewriter, idxTy, operands[shiftOps]) 2114fa517555SKiran Chandramohan : one; 2115fa517555SKiran Chandramohan mlir::Value diff = 2116fa517555SKiran Chandramohan rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, sliceLb, sliceOrigin); 2117fa517555SKiran Chandramohan mlir::Value offset = 2118fa517555SKiran Chandramohan rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, inputStride); 2119fa517555SKiran Chandramohan base = genGEP(loc, voidPtrTy, rewriter, base, offset); 2120fa517555SKiran Chandramohan // Apply upper bound and step if this is a triplet. Otherwise, the 2121fa517555SKiran Chandramohan // dimension is dropped and no extents/strides are computed. 2122fa517555SKiran Chandramohan mlir::Value upper = operands[sliceOps + 1]; 2123fa517555SKiran Chandramohan const bool isTripletSlice = 2124fa517555SKiran Chandramohan !mlir::isa_and_nonnull<mlir::LLVM::UndefOp>(upper.getDefiningOp()); 2125fa517555SKiran Chandramohan if (isTripletSlice) { 2126fa517555SKiran Chandramohan mlir::Value step = 2127fa517555SKiran Chandramohan integerCast(loc, rewriter, idxTy, operands[sliceOps + 2]); 2128fa517555SKiran Chandramohan // extent = ub-lb+step/step 2129fa517555SKiran Chandramohan mlir::Value sliceUb = integerCast(loc, rewriter, idxTy, upper); 2130fa517555SKiran Chandramohan mlir::Value extent = computeTripletExtent(rewriter, loc, sliceLb, 2131fa517555SKiran Chandramohan sliceUb, step, zero, idxTy); 2132fa517555SKiran Chandramohan slicedExtents.emplace_back(extent); 2133fa517555SKiran Chandramohan // stride = step*input_stride 2134fa517555SKiran Chandramohan mlir::Value stride = 2135fa517555SKiran Chandramohan rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, step, inputStride); 2136fa517555SKiran Chandramohan slicedStrides.emplace_back(stride); 2137fa517555SKiran Chandramohan } 2138fa517555SKiran Chandramohan } 2139fa517555SKiran Chandramohan return finalizeRebox(rebox, dest, base, /*lbounds*/ llvm::None, 2140fa517555SKiran Chandramohan slicedExtents, slicedStrides, rewriter); 2141fa517555SKiran Chandramohan } 2142fa517555SKiran Chandramohan 2143fa517555SKiran Chandramohan /// Apply a new shape to the data described by a box given the base address, 2144fa517555SKiran Chandramohan /// extents and strides of the box. 2145fa517555SKiran Chandramohan mlir::LogicalResult 2146fa517555SKiran Chandramohan reshapeBox(fir::cg::XReboxOp rebox, mlir::Value dest, mlir::Value base, 2147fa517555SKiran Chandramohan mlir::ValueRange inputExtents, mlir::ValueRange inputStrides, 2148fa517555SKiran Chandramohan mlir::ValueRange operands, 2149fa517555SKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const { 2150fa517555SKiran Chandramohan mlir::ValueRange reboxShifts{operands.begin() + rebox.shiftOffset(), 2151fa517555SKiran Chandramohan operands.begin() + rebox.shiftOffset() + 2152fa517555SKiran Chandramohan rebox.shift().size()}; 2153fa517555SKiran Chandramohan if (rebox.shape().empty()) { 2154fa517555SKiran Chandramohan // Only setting new lower bounds. 2155fa517555SKiran Chandramohan return finalizeRebox(rebox, dest, base, reboxShifts, inputExtents, 2156fa517555SKiran Chandramohan inputStrides, rewriter); 2157fa517555SKiran Chandramohan } 2158fa517555SKiran Chandramohan 2159fa517555SKiran Chandramohan mlir::Location loc = rebox.getLoc(); 2160fa517555SKiran Chandramohan // Strides from the fir.box are in bytes. 2161fa517555SKiran Chandramohan mlir::Type voidPtrTy = ::getVoidPtrType(rebox.getContext()); 2162fa517555SKiran Chandramohan base = rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, base); 2163fa517555SKiran Chandramohan 2164fa517555SKiran Chandramohan llvm::SmallVector<mlir::Value> newStrides; 2165fa517555SKiran Chandramohan llvm::SmallVector<mlir::Value> newExtents; 2166fa517555SKiran Chandramohan mlir::Type idxTy = lowerTy().indexType(); 2167fa517555SKiran Chandramohan // First stride from input box is kept. The rest is assumed contiguous 2168fa517555SKiran Chandramohan // (it is not possible to reshape otherwise). If the input is scalar, 2169fa517555SKiran Chandramohan // which may be OK if all new extents are ones, the stride does not 2170fa517555SKiran Chandramohan // matter, use one. 2171fa517555SKiran Chandramohan mlir::Value stride = inputStrides.empty() 2172fa517555SKiran Chandramohan ? genConstantIndex(loc, idxTy, rewriter, 1) 2173fa517555SKiran Chandramohan : inputStrides[0]; 2174fa517555SKiran Chandramohan for (unsigned i = 0; i < rebox.shape().size(); ++i) { 2175fa517555SKiran Chandramohan mlir::Value rawExtent = operands[rebox.shapeOffset() + i]; 2176fa517555SKiran Chandramohan mlir::Value extent = integerCast(loc, rewriter, idxTy, rawExtent); 2177fa517555SKiran Chandramohan newExtents.emplace_back(extent); 2178fa517555SKiran Chandramohan newStrides.emplace_back(stride); 2179fa517555SKiran Chandramohan // nextStride = extent * stride; 2180fa517555SKiran Chandramohan stride = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, extent, stride); 2181fa517555SKiran Chandramohan } 2182fa517555SKiran Chandramohan return finalizeRebox(rebox, dest, base, reboxShifts, newExtents, newStrides, 2183fa517555SKiran Chandramohan rewriter); 2184fa517555SKiran Chandramohan } 2185fa517555SKiran Chandramohan 2186fa517555SKiran Chandramohan /// Return scalar element type of the input box. 2187fa517555SKiran Chandramohan static mlir::Type getInputEleTy(fir::cg::XReboxOp rebox) { 2188fa517555SKiran Chandramohan auto ty = fir::dyn_cast_ptrOrBoxEleTy(rebox.box().getType()); 2189fa517555SKiran Chandramohan if (auto seqTy = ty.dyn_cast<fir::SequenceType>()) 2190fa517555SKiran Chandramohan return seqTy.getEleTy(); 2191fa517555SKiran Chandramohan return ty; 2192fa517555SKiran Chandramohan } 2193fa517555SKiran Chandramohan }; 2194fa517555SKiran Chandramohan 219554c56347SValentin Clement // Code shared between insert_value and extract_value Ops. 219654c56347SValentin Clement struct ValueOpCommon { 219754c56347SValentin Clement // Translate the arguments pertaining to any multidimensional array to 219854c56347SValentin Clement // row-major order for LLVM-IR. 219954c56347SValentin Clement static void toRowMajor(SmallVectorImpl<mlir::Attribute> &attrs, 220054c56347SValentin Clement mlir::Type ty) { 220154c56347SValentin Clement assert(ty && "type is null"); 220254c56347SValentin Clement const auto end = attrs.size(); 220354c56347SValentin Clement for (std::remove_const_t<decltype(end)> i = 0; i < end; ++i) { 220454c56347SValentin Clement if (auto seq = ty.dyn_cast<mlir::LLVM::LLVMArrayType>()) { 220554c56347SValentin Clement const auto dim = getDimension(seq); 220654c56347SValentin Clement if (dim > 1) { 220754c56347SValentin Clement auto ub = std::min(i + dim, end); 220854c56347SValentin Clement std::reverse(attrs.begin() + i, attrs.begin() + ub); 220954c56347SValentin Clement i += dim - 1; 221054c56347SValentin Clement } 221154c56347SValentin Clement ty = getArrayElementType(seq); 221254c56347SValentin Clement } else if (auto st = ty.dyn_cast<mlir::LLVM::LLVMStructType>()) { 221354c56347SValentin Clement ty = st.getBody()[attrs[i].cast<mlir::IntegerAttr>().getInt()]; 221454c56347SValentin Clement } else { 221554c56347SValentin Clement llvm_unreachable("index into invalid type"); 221654c56347SValentin Clement } 221754c56347SValentin Clement } 221854c56347SValentin Clement } 221954c56347SValentin Clement 222054c56347SValentin Clement static llvm::SmallVector<mlir::Attribute> 222154c56347SValentin Clement collectIndices(mlir::ConversionPatternRewriter &rewriter, 222254c56347SValentin Clement mlir::ArrayAttr arrAttr) { 222354c56347SValentin Clement llvm::SmallVector<mlir::Attribute> attrs; 222454c56347SValentin Clement for (auto i = arrAttr.begin(), e = arrAttr.end(); i != e; ++i) { 222554c56347SValentin Clement if (i->isa<mlir::IntegerAttr>()) { 222654c56347SValentin Clement attrs.push_back(*i); 222754c56347SValentin Clement } else { 222854c56347SValentin Clement auto fieldName = i->cast<mlir::StringAttr>().getValue(); 222954c56347SValentin Clement ++i; 223054c56347SValentin Clement auto ty = i->cast<mlir::TypeAttr>().getValue(); 223154c56347SValentin Clement auto index = ty.cast<fir::RecordType>().getFieldIndex(fieldName); 223254c56347SValentin Clement attrs.push_back(mlir::IntegerAttr::get(rewriter.getI32Type(), index)); 223354c56347SValentin Clement } 223454c56347SValentin Clement } 223554c56347SValentin Clement return attrs; 223654c56347SValentin Clement } 223754c56347SValentin Clement 223854c56347SValentin Clement private: 223954c56347SValentin Clement static unsigned getDimension(mlir::LLVM::LLVMArrayType ty) { 224054c56347SValentin Clement unsigned result = 1; 224154c56347SValentin Clement for (auto eleTy = ty.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>(); 224254c56347SValentin Clement eleTy; 224354c56347SValentin Clement eleTy = eleTy.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>()) 224454c56347SValentin Clement ++result; 224554c56347SValentin Clement return result; 224654c56347SValentin Clement } 224754c56347SValentin Clement 224854c56347SValentin Clement static mlir::Type getArrayElementType(mlir::LLVM::LLVMArrayType ty) { 224954c56347SValentin Clement auto eleTy = ty.getElementType(); 225054c56347SValentin Clement while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>()) 225154c56347SValentin Clement eleTy = arrTy.getElementType(); 225254c56347SValentin Clement return eleTy; 225354c56347SValentin Clement } 225454c56347SValentin Clement }; 225554c56347SValentin Clement 2256c2acd453SAlexisPerry namespace { 225754c56347SValentin Clement /// Extract a subobject value from an ssa-value of aggregate type 225854c56347SValentin Clement struct ExtractValueOpConversion 225954c56347SValentin Clement : public FIROpAndTypeConversion<fir::ExtractValueOp>, 226054c56347SValentin Clement public ValueOpCommon { 226154c56347SValentin Clement using FIROpAndTypeConversion::FIROpAndTypeConversion; 226254c56347SValentin Clement 226354c56347SValentin Clement mlir::LogicalResult 226454c56347SValentin Clement doRewrite(fir::ExtractValueOp extractVal, mlir::Type ty, OpAdaptor adaptor, 226554c56347SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 226654c56347SValentin Clement auto attrs = collectIndices(rewriter, extractVal.coor()); 226754c56347SValentin Clement toRowMajor(attrs, adaptor.getOperands()[0].getType()); 226854c56347SValentin Clement auto position = mlir::ArrayAttr::get(extractVal.getContext(), attrs); 226954c56347SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>( 227054c56347SValentin Clement extractVal, ty, adaptor.getOperands()[0], position); 227154c56347SValentin Clement return success(); 227254c56347SValentin Clement } 227354c56347SValentin Clement }; 227454c56347SValentin Clement 227554c56347SValentin Clement /// InsertValue is the generalized instruction for the composition of new 227654c56347SValentin Clement /// aggregate type values. 227754c56347SValentin Clement struct InsertValueOpConversion 227854c56347SValentin Clement : public FIROpAndTypeConversion<fir::InsertValueOp>, 227954c56347SValentin Clement public ValueOpCommon { 228054c56347SValentin Clement using FIROpAndTypeConversion::FIROpAndTypeConversion; 228154c56347SValentin Clement 228254c56347SValentin Clement mlir::LogicalResult 228354c56347SValentin Clement doRewrite(fir::InsertValueOp insertVal, mlir::Type ty, OpAdaptor adaptor, 228454c56347SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 228554c56347SValentin Clement auto attrs = collectIndices(rewriter, insertVal.coor()); 228654c56347SValentin Clement toRowMajor(attrs, adaptor.getOperands()[0].getType()); 228754c56347SValentin Clement auto position = mlir::ArrayAttr::get(insertVal.getContext(), attrs); 228854c56347SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 228954c56347SValentin Clement insertVal, ty, adaptor.getOperands()[0], adaptor.getOperands()[1], 229054c56347SValentin Clement position); 229154c56347SValentin Clement return success(); 229254c56347SValentin Clement } 229354c56347SValentin Clement }; 229454c56347SValentin Clement 22953ae8e442SValentin Clement /// InsertOnRange inserts a value into a sequence over a range of offsets. 22963ae8e442SValentin Clement struct InsertOnRangeOpConversion 22973ae8e442SValentin Clement : public FIROpAndTypeConversion<fir::InsertOnRangeOp> { 22983ae8e442SValentin Clement using FIROpAndTypeConversion::FIROpAndTypeConversion; 22993ae8e442SValentin Clement 23003ae8e442SValentin Clement // Increments an array of subscripts in a row major fasion. 23013ae8e442SValentin Clement void incrementSubscripts(const SmallVector<uint64_t> &dims, 23023ae8e442SValentin Clement SmallVector<uint64_t> &subscripts) const { 23033ae8e442SValentin Clement for (size_t i = dims.size(); i > 0; --i) { 23043ae8e442SValentin Clement if (++subscripts[i - 1] < dims[i - 1]) { 23053ae8e442SValentin Clement return; 23063ae8e442SValentin Clement } 23073ae8e442SValentin Clement subscripts[i - 1] = 0; 23083ae8e442SValentin Clement } 23093ae8e442SValentin Clement } 23103ae8e442SValentin Clement 23113ae8e442SValentin Clement mlir::LogicalResult 23123ae8e442SValentin Clement doRewrite(fir::InsertOnRangeOp range, mlir::Type ty, OpAdaptor adaptor, 23133ae8e442SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 23143ae8e442SValentin Clement 23153ae8e442SValentin Clement llvm::SmallVector<uint64_t> dims; 23163ae8e442SValentin Clement auto type = adaptor.getOperands()[0].getType(); 23173ae8e442SValentin Clement 23183ae8e442SValentin Clement // Iteratively extract the array dimensions from the type. 23193ae8e442SValentin Clement while (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) { 23203ae8e442SValentin Clement dims.push_back(t.getNumElements()); 23213ae8e442SValentin Clement type = t.getElementType(); 23223ae8e442SValentin Clement } 23233ae8e442SValentin Clement 23243ae8e442SValentin Clement SmallVector<uint64_t> lBounds; 23253ae8e442SValentin Clement SmallVector<uint64_t> uBounds; 23263ae8e442SValentin Clement 23273ae8e442SValentin Clement // Unzip the upper and lower bound and convert to a row major format. 23288ec0f221SMehdi Amini mlir::DenseIntElementsAttr coor = range.coor(); 23298ec0f221SMehdi Amini auto reversedCoor = llvm::reverse(coor.getValues<int64_t>()); 23308ec0f221SMehdi Amini for (auto i = reversedCoor.begin(), e = reversedCoor.end(); i != e; ++i) { 23313ae8e442SValentin Clement uBounds.push_back(*i++); 23323ae8e442SValentin Clement lBounds.push_back(*i); 23333ae8e442SValentin Clement } 23343ae8e442SValentin Clement 23353ae8e442SValentin Clement auto &subscripts = lBounds; 23363ae8e442SValentin Clement auto loc = range.getLoc(); 23373ae8e442SValentin Clement mlir::Value lastOp = adaptor.getOperands()[0]; 23383ae8e442SValentin Clement mlir::Value insertVal = adaptor.getOperands()[1]; 23393ae8e442SValentin Clement 23403ae8e442SValentin Clement auto i64Ty = rewriter.getI64Type(); 23413ae8e442SValentin Clement while (subscripts != uBounds) { 23423ae8e442SValentin Clement // Convert uint64_t's to Attribute's. 23433ae8e442SValentin Clement SmallVector<mlir::Attribute> subscriptAttrs; 23443ae8e442SValentin Clement for (const auto &subscript : subscripts) 23453ae8e442SValentin Clement subscriptAttrs.push_back(IntegerAttr::get(i64Ty, subscript)); 23463ae8e442SValentin Clement lastOp = rewriter.create<mlir::LLVM::InsertValueOp>( 23473ae8e442SValentin Clement loc, ty, lastOp, insertVal, 23483ae8e442SValentin Clement ArrayAttr::get(range.getContext(), subscriptAttrs)); 23493ae8e442SValentin Clement 23503ae8e442SValentin Clement incrementSubscripts(dims, subscripts); 23513ae8e442SValentin Clement } 23523ae8e442SValentin Clement 23533ae8e442SValentin Clement // Convert uint64_t's to Attribute's. 23543ae8e442SValentin Clement SmallVector<mlir::Attribute> subscriptAttrs; 23553ae8e442SValentin Clement for (const auto &subscript : subscripts) 23563ae8e442SValentin Clement subscriptAttrs.push_back( 23573ae8e442SValentin Clement IntegerAttr::get(rewriter.getI64Type(), subscript)); 23583ae8e442SValentin Clement mlir::ArrayRef<mlir::Attribute> arrayRef(subscriptAttrs); 23593ae8e442SValentin Clement 23603ae8e442SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 23613ae8e442SValentin Clement range, ty, lastOp, insertVal, 23623ae8e442SValentin Clement ArrayAttr::get(range.getContext(), arrayRef)); 23633ae8e442SValentin Clement 23643ae8e442SValentin Clement return success(); 23653ae8e442SValentin Clement } 23663ae8e442SValentin Clement }; 2367c2acd453SAlexisPerry } // namespace 23687b5132daSValentin Clement 23695d27abe6SValentin Clement /// XArrayCoor is the address arithmetic on a dynamically shaped, sliced, 23705d27abe6SValentin Clement /// shifted etc. array. 23715d27abe6SValentin Clement /// (See the static restriction on coordinate_of.) array_coor determines the 23725d27abe6SValentin Clement /// coordinate (location) of a specific element. 23735d27abe6SValentin Clement struct XArrayCoorOpConversion 23745d27abe6SValentin Clement : public FIROpAndTypeConversion<fir::cg::XArrayCoorOp> { 23755d27abe6SValentin Clement using FIROpAndTypeConversion::FIROpAndTypeConversion; 23765d27abe6SValentin Clement 23775d27abe6SValentin Clement mlir::LogicalResult 23785d27abe6SValentin Clement doRewrite(fir::cg::XArrayCoorOp coor, mlir::Type ty, OpAdaptor adaptor, 23795d27abe6SValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 23805d27abe6SValentin Clement auto loc = coor.getLoc(); 23815d27abe6SValentin Clement mlir::ValueRange operands = adaptor.getOperands(); 23825d27abe6SValentin Clement unsigned rank = coor.getRank(); 23835d27abe6SValentin Clement assert(coor.indices().size() == rank); 23845d27abe6SValentin Clement assert(coor.shape().empty() || coor.shape().size() == rank); 23855d27abe6SValentin Clement assert(coor.shift().empty() || coor.shift().size() == rank); 23865d27abe6SValentin Clement assert(coor.slice().empty() || coor.slice().size() == 3 * rank); 23875d27abe6SValentin Clement mlir::Type idxTy = lowerTy().indexType(); 23885d27abe6SValentin Clement mlir::Value one = genConstantIndex(loc, idxTy, rewriter, 1); 23895d27abe6SValentin Clement mlir::Value prevExt = one; 23905d27abe6SValentin Clement mlir::Value zero = genConstantIndex(loc, idxTy, rewriter, 0); 23915d27abe6SValentin Clement mlir::Value offset = zero; 23925d27abe6SValentin Clement const bool isShifted = !coor.shift().empty(); 23935d27abe6SValentin Clement const bool isSliced = !coor.slice().empty(); 23945d27abe6SValentin Clement const bool baseIsBoxed = coor.memref().getType().isa<fir::BoxType>(); 23955d27abe6SValentin Clement 23965d27abe6SValentin Clement auto indexOps = coor.indices().begin(); 23975d27abe6SValentin Clement auto shapeOps = coor.shape().begin(); 23985d27abe6SValentin Clement auto shiftOps = coor.shift().begin(); 23995d27abe6SValentin Clement auto sliceOps = coor.slice().begin(); 24005d27abe6SValentin Clement // For each dimension of the array, generate the offset calculation. 24015d27abe6SValentin Clement for (unsigned i = 0; i < rank; 24025d27abe6SValentin Clement ++i, ++indexOps, ++shapeOps, ++shiftOps, sliceOps += 3) { 24035d27abe6SValentin Clement mlir::Value index = 24045d27abe6SValentin Clement integerCast(loc, rewriter, idxTy, operands[coor.indicesOffset() + i]); 24055d27abe6SValentin Clement mlir::Value lb = isShifted ? integerCast(loc, rewriter, idxTy, 24065d27abe6SValentin Clement operands[coor.shiftOffset() + i]) 24075d27abe6SValentin Clement : one; 24085d27abe6SValentin Clement mlir::Value step = one; 24095d27abe6SValentin Clement bool normalSlice = isSliced; 24105d27abe6SValentin Clement // Compute zero based index in dimension i of the element, applying 24115d27abe6SValentin Clement // potential triplets and lower bounds. 24125d27abe6SValentin Clement if (isSliced) { 24135d27abe6SValentin Clement mlir::Value ub = *(sliceOps + 1); 24145d27abe6SValentin Clement normalSlice = !mlir::isa_and_nonnull<fir::UndefOp>(ub.getDefiningOp()); 24155d27abe6SValentin Clement if (normalSlice) 24165d27abe6SValentin Clement step = integerCast(loc, rewriter, idxTy, *(sliceOps + 2)); 24175d27abe6SValentin Clement } 24185d27abe6SValentin Clement auto idx = rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, index, lb); 24195d27abe6SValentin Clement mlir::Value diff = 24205d27abe6SValentin Clement rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, idx, step); 24215d27abe6SValentin Clement if (normalSlice) { 24225d27abe6SValentin Clement mlir::Value sliceLb = 24235d27abe6SValentin Clement integerCast(loc, rewriter, idxTy, operands[coor.sliceOffset() + i]); 24245d27abe6SValentin Clement auto adj = rewriter.create<mlir::LLVM::SubOp>(loc, idxTy, sliceLb, lb); 24255d27abe6SValentin Clement diff = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, diff, adj); 24265d27abe6SValentin Clement } 24275d27abe6SValentin Clement // Update the offset given the stride and the zero based index `diff` 24285d27abe6SValentin Clement // that was just computed. 24295d27abe6SValentin Clement if (baseIsBoxed) { 24305d27abe6SValentin Clement // Use stride in bytes from the descriptor. 24315d27abe6SValentin Clement mlir::Value stride = 24325d27abe6SValentin Clement loadStrideFromBox(loc, adaptor.getOperands()[0], i, rewriter); 24335d27abe6SValentin Clement auto sc = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, stride); 24345d27abe6SValentin Clement offset = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, offset); 24355d27abe6SValentin Clement } else { 24365d27abe6SValentin Clement // Use stride computed at last iteration. 24375d27abe6SValentin Clement auto sc = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, diff, prevExt); 24385d27abe6SValentin Clement offset = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, offset); 24395d27abe6SValentin Clement // Compute next stride assuming contiguity of the base array 24405d27abe6SValentin Clement // (in element number). 24415d27abe6SValentin Clement auto nextExt = 24425d27abe6SValentin Clement integerCast(loc, rewriter, idxTy, operands[coor.shapeOffset() + i]); 24435d27abe6SValentin Clement prevExt = 24445d27abe6SValentin Clement rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, prevExt, nextExt); 24455d27abe6SValentin Clement } 24465d27abe6SValentin Clement } 24475d27abe6SValentin Clement 24485d27abe6SValentin Clement // Add computed offset to the base address. 24495d27abe6SValentin Clement if (baseIsBoxed) { 24505d27abe6SValentin Clement // Working with byte offsets. The base address is read from the fir.box. 24515d27abe6SValentin Clement // and need to be casted to i8* to do the pointer arithmetic. 24525d27abe6SValentin Clement mlir::Type baseTy = 24535d27abe6SValentin Clement getBaseAddrTypeFromBox(adaptor.getOperands()[0].getType()); 24545d27abe6SValentin Clement mlir::Value base = 24555d27abe6SValentin Clement loadBaseAddrFromBox(loc, baseTy, adaptor.getOperands()[0], rewriter); 24565d27abe6SValentin Clement mlir::Type voidPtrTy = getVoidPtrType(); 24575d27abe6SValentin Clement base = rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, base); 245830122656SAlex Zinenko llvm::SmallVector<mlir::Value> args{offset}; 245930122656SAlex Zinenko auto addr = 246030122656SAlex Zinenko rewriter.create<mlir::LLVM::GEPOp>(loc, voidPtrTy, base, args); 24615d27abe6SValentin Clement if (coor.subcomponent().empty()) { 24625d27abe6SValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(coor, baseTy, addr); 24635d27abe6SValentin Clement return success(); 24645d27abe6SValentin Clement } 24655d27abe6SValentin Clement auto casted = rewriter.create<mlir::LLVM::BitcastOp>(loc, baseTy, addr); 24665d27abe6SValentin Clement args.clear(); 24675d27abe6SValentin Clement args.push_back(zero); 24685d27abe6SValentin Clement if (!coor.lenParams().empty()) { 24695d27abe6SValentin Clement // If type parameters are present, then we don't want to use a GEPOp 24705d27abe6SValentin Clement // as below, as the LLVM struct type cannot be statically defined. 24715d27abe6SValentin Clement TODO(loc, "derived type with type parameters"); 24725d27abe6SValentin Clement } 24735d27abe6SValentin Clement // TODO: array offset subcomponents must be converted to LLVM's 24745d27abe6SValentin Clement // row-major layout here. 24755d27abe6SValentin Clement for (auto i = coor.subcomponentOffset(); i != coor.indicesOffset(); ++i) 24765d27abe6SValentin Clement args.push_back(operands[i]); 247730122656SAlex Zinenko rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(coor, baseTy, casted, 247830122656SAlex Zinenko args); 24795d27abe6SValentin Clement return success(); 24805d27abe6SValentin Clement } 24815d27abe6SValentin Clement 24825d27abe6SValentin Clement // The array was not boxed, so it must be contiguous. offset is therefore an 24835d27abe6SValentin Clement // element offset and the base type is kept in the GEP unless the element 24845d27abe6SValentin Clement // type size is itself dynamic. 24855d27abe6SValentin Clement mlir::Value base; 24865d27abe6SValentin Clement if (coor.subcomponent().empty()) { 24875d27abe6SValentin Clement // No subcomponent. 24885d27abe6SValentin Clement if (!coor.lenParams().empty()) { 24895d27abe6SValentin Clement // Type parameters. Adjust element size explicitly. 24905d27abe6SValentin Clement auto eleTy = fir::dyn_cast_ptrEleTy(coor.getType()); 24915d27abe6SValentin Clement assert(eleTy && "result must be a reference-like type"); 24925d27abe6SValentin Clement if (fir::characterWithDynamicLen(eleTy)) { 24935d27abe6SValentin Clement assert(coor.lenParams().size() == 1); 24945d27abe6SValentin Clement auto bitsInChar = lowerTy().getKindMap().getCharacterBitsize( 24955d27abe6SValentin Clement eleTy.cast<fir::CharacterType>().getFKind()); 24965d27abe6SValentin Clement auto scaling = genConstantIndex(loc, idxTy, rewriter, bitsInChar / 8); 24975d27abe6SValentin Clement auto scaledBySize = 24985d27abe6SValentin Clement rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, offset, scaling); 24995d27abe6SValentin Clement auto length = 25005d27abe6SValentin Clement integerCast(loc, rewriter, idxTy, 25015d27abe6SValentin Clement adaptor.getOperands()[coor.lenParamsOffset()]); 25025d27abe6SValentin Clement offset = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, scaledBySize, 25035d27abe6SValentin Clement length); 25045d27abe6SValentin Clement } else { 25055d27abe6SValentin Clement TODO(loc, "compute size of derived type with type parameters"); 25065d27abe6SValentin Clement } 25075d27abe6SValentin Clement } 25085d27abe6SValentin Clement // Cast the base address to a pointer to T. 25095d27abe6SValentin Clement base = rewriter.create<mlir::LLVM::BitcastOp>(loc, ty, 25105d27abe6SValentin Clement adaptor.getOperands()[0]); 25115d27abe6SValentin Clement } else { 25125d27abe6SValentin Clement // Operand #0 must have a pointer type. For subcomponent slicing, we 25135d27abe6SValentin Clement // want to cast away the array type and have a plain struct type. 25145d27abe6SValentin Clement mlir::Type ty0 = adaptor.getOperands()[0].getType(); 25155d27abe6SValentin Clement auto ptrTy = ty0.dyn_cast<mlir::LLVM::LLVMPointerType>(); 25165d27abe6SValentin Clement assert(ptrTy && "expected pointer type"); 25175d27abe6SValentin Clement mlir::Type eleTy = ptrTy.getElementType(); 25185d27abe6SValentin Clement while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>()) 25195d27abe6SValentin Clement eleTy = arrTy.getElementType(); 25205d27abe6SValentin Clement auto newTy = mlir::LLVM::LLVMPointerType::get(eleTy); 25215d27abe6SValentin Clement base = rewriter.create<mlir::LLVM::BitcastOp>(loc, newTy, 25225d27abe6SValentin Clement adaptor.getOperands()[0]); 25235d27abe6SValentin Clement } 252430122656SAlex Zinenko SmallVector<mlir::Value> args = {offset}; 25255d27abe6SValentin Clement for (auto i = coor.subcomponentOffset(); i != coor.indicesOffset(); ++i) 25265d27abe6SValentin Clement args.push_back(operands[i]); 252730122656SAlex Zinenko rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(coor, ty, base, args); 25285d27abe6SValentin Clement return success(); 25295d27abe6SValentin Clement } 25305d27abe6SValentin Clement }; 25315d27abe6SValentin Clement 25327b5132daSValentin Clement // 25337b5132daSValentin Clement // Primitive operations on Complex types 25347b5132daSValentin Clement // 25357b5132daSValentin Clement 25367b5132daSValentin Clement /// Generate inline code for complex addition/subtraction 25377b5132daSValentin Clement template <typename LLVMOP, typename OPTY> 2538c2acd453SAlexisPerry static mlir::LLVM::InsertValueOp 2539c2acd453SAlexisPerry complexSum(OPTY sumop, mlir::ValueRange opnds, 25407b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter, 25417b5132daSValentin Clement fir::LLVMTypeConverter &lowering) { 25427b5132daSValentin Clement mlir::Value a = opnds[0]; 25437b5132daSValentin Clement mlir::Value b = opnds[1]; 25447b5132daSValentin Clement auto loc = sumop.getLoc(); 25457b5132daSValentin Clement auto ctx = sumop.getContext(); 25467b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 25477b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 25487b5132daSValentin Clement mlir::Type eleTy = lowering.convertType(getComplexEleTy(sumop.getType())); 25497b5132daSValentin Clement mlir::Type ty = lowering.convertType(sumop.getType()); 25507b5132daSValentin Clement auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0); 25517b5132daSValentin Clement auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1); 25527b5132daSValentin Clement auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0); 25537b5132daSValentin Clement auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1); 25547b5132daSValentin Clement auto rx = rewriter.create<LLVMOP>(loc, eleTy, x0, x1); 25557b5132daSValentin Clement auto ry = rewriter.create<LLVMOP>(loc, eleTy, y0, y1); 25567b5132daSValentin Clement auto r0 = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 25577b5132daSValentin Clement auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r0, rx, c0); 25587b5132daSValentin Clement return rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ry, c1); 25597b5132daSValentin Clement } 25607b5132daSValentin Clement 2561c2acd453SAlexisPerry namespace { 25627b5132daSValentin Clement struct AddcOpConversion : public FIROpConversion<fir::AddcOp> { 25637b5132daSValentin Clement using FIROpConversion::FIROpConversion; 25647b5132daSValentin Clement 25657b5132daSValentin Clement mlir::LogicalResult 25667b5132daSValentin Clement matchAndRewrite(fir::AddcOp addc, OpAdaptor adaptor, 25677b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 25687b5132daSValentin Clement // given: (x + iy) + (x' + iy') 25697b5132daSValentin Clement // result: (x + x') + i(y + y') 25707b5132daSValentin Clement auto r = complexSum<mlir::LLVM::FAddOp>(addc, adaptor.getOperands(), 25717b5132daSValentin Clement rewriter, lowerTy()); 25727b5132daSValentin Clement rewriter.replaceOp(addc, r.getResult()); 25737b5132daSValentin Clement return success(); 25747b5132daSValentin Clement } 25757b5132daSValentin Clement }; 25767b5132daSValentin Clement 25777b5132daSValentin Clement struct SubcOpConversion : public FIROpConversion<fir::SubcOp> { 25787b5132daSValentin Clement using FIROpConversion::FIROpConversion; 25797b5132daSValentin Clement 25807b5132daSValentin Clement mlir::LogicalResult 25817b5132daSValentin Clement matchAndRewrite(fir::SubcOp subc, OpAdaptor adaptor, 25827b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 25837b5132daSValentin Clement // given: (x + iy) - (x' + iy') 25847b5132daSValentin Clement // result: (x - x') + i(y - y') 25857b5132daSValentin Clement auto r = complexSum<mlir::LLVM::FSubOp>(subc, adaptor.getOperands(), 25867b5132daSValentin Clement rewriter, lowerTy()); 25877b5132daSValentin Clement rewriter.replaceOp(subc, r.getResult()); 25887b5132daSValentin Clement return success(); 25897b5132daSValentin Clement } 25907b5132daSValentin Clement }; 25917b5132daSValentin Clement 25927b5132daSValentin Clement /// Inlined complex multiply 25937b5132daSValentin Clement struct MulcOpConversion : public FIROpConversion<fir::MulcOp> { 25947b5132daSValentin Clement using FIROpConversion::FIROpConversion; 25957b5132daSValentin Clement 25967b5132daSValentin Clement mlir::LogicalResult 25977b5132daSValentin Clement matchAndRewrite(fir::MulcOp mulc, OpAdaptor adaptor, 25987b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 25997b5132daSValentin Clement // TODO: Can we use a call to __muldc3 ? 26007b5132daSValentin Clement // given: (x + iy) * (x' + iy') 26017b5132daSValentin Clement // result: (xx'-yy')+i(xy'+yx') 26027b5132daSValentin Clement mlir::Value a = adaptor.getOperands()[0]; 26037b5132daSValentin Clement mlir::Value b = adaptor.getOperands()[1]; 26047b5132daSValentin Clement auto loc = mulc.getLoc(); 26057b5132daSValentin Clement auto *ctx = mulc.getContext(); 26067b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 26077b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 26087b5132daSValentin Clement mlir::Type eleTy = convertType(getComplexEleTy(mulc.getType())); 26097b5132daSValentin Clement mlir::Type ty = convertType(mulc.getType()); 26107b5132daSValentin Clement auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0); 26117b5132daSValentin Clement auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1); 26127b5132daSValentin Clement auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0); 26137b5132daSValentin Clement auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1); 26147b5132daSValentin Clement auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1); 26157b5132daSValentin Clement auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1); 26167b5132daSValentin Clement auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1); 26177b5132daSValentin Clement auto ri = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xy, yx); 26187b5132daSValentin Clement auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1); 26197b5132daSValentin Clement auto rr = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, xx, yy); 26207b5132daSValentin Clement auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 26217b5132daSValentin Clement auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0); 26227b5132daSValentin Clement auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1); 26237b5132daSValentin Clement rewriter.replaceOp(mulc, r0.getResult()); 26247b5132daSValentin Clement return success(); 26257b5132daSValentin Clement } 26267b5132daSValentin Clement }; 26277b5132daSValentin Clement 26287b5132daSValentin Clement /// Inlined complex division 26297b5132daSValentin Clement struct DivcOpConversion : public FIROpConversion<fir::DivcOp> { 26307b5132daSValentin Clement using FIROpConversion::FIROpConversion; 26317b5132daSValentin Clement 26327b5132daSValentin Clement mlir::LogicalResult 26337b5132daSValentin Clement matchAndRewrite(fir::DivcOp divc, OpAdaptor adaptor, 26347b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 26357b5132daSValentin Clement // TODO: Can we use a call to __divdc3 instead? 26367b5132daSValentin Clement // Just generate inline code for now. 26377b5132daSValentin Clement // given: (x + iy) / (x' + iy') 26387b5132daSValentin Clement // result: ((xx'+yy')/d) + i((yx'-xy')/d) where d = x'x' + y'y' 26397b5132daSValentin Clement mlir::Value a = adaptor.getOperands()[0]; 26407b5132daSValentin Clement mlir::Value b = adaptor.getOperands()[1]; 26417b5132daSValentin Clement auto loc = divc.getLoc(); 26427b5132daSValentin Clement auto *ctx = divc.getContext(); 26437b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 26447b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 26457b5132daSValentin Clement mlir::Type eleTy = convertType(getComplexEleTy(divc.getType())); 26467b5132daSValentin Clement mlir::Type ty = convertType(divc.getType()); 26477b5132daSValentin Clement auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0); 26487b5132daSValentin Clement auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1); 26497b5132daSValentin Clement auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0); 26507b5132daSValentin Clement auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1); 26517b5132daSValentin Clement auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1); 26527b5132daSValentin Clement auto x1x1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x1, x1); 26537b5132daSValentin Clement auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1); 26547b5132daSValentin Clement auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1); 26557b5132daSValentin Clement auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1); 26567b5132daSValentin Clement auto y1y1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y1, y1); 26577b5132daSValentin Clement auto d = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, x1x1, y1y1); 26587b5132daSValentin Clement auto rrn = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xx, yy); 26597b5132daSValentin Clement auto rin = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, yx, xy); 26607b5132daSValentin Clement auto rr = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rrn, d); 26617b5132daSValentin Clement auto ri = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rin, d); 26627b5132daSValentin Clement auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty); 26637b5132daSValentin Clement auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0); 26647b5132daSValentin Clement auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1); 26657b5132daSValentin Clement rewriter.replaceOp(divc, r0.getResult()); 26667b5132daSValentin Clement return success(); 26677b5132daSValentin Clement } 26687b5132daSValentin Clement }; 26697b5132daSValentin Clement 26707b5132daSValentin Clement /// Inlined complex negation 26717b5132daSValentin Clement struct NegcOpConversion : public FIROpConversion<fir::NegcOp> { 26727b5132daSValentin Clement using FIROpConversion::FIROpConversion; 26737b5132daSValentin Clement 26747b5132daSValentin Clement mlir::LogicalResult 26757b5132daSValentin Clement matchAndRewrite(fir::NegcOp neg, OpAdaptor adaptor, 26767b5132daSValentin Clement mlir::ConversionPatternRewriter &rewriter) const override { 26777b5132daSValentin Clement // given: -(x + iy) 26787b5132daSValentin Clement // result: -x - iy 26797b5132daSValentin Clement auto *ctxt = neg.getContext(); 26807b5132daSValentin Clement auto eleTy = convertType(getComplexEleTy(neg.getType())); 26817b5132daSValentin Clement auto ty = convertType(neg.getType()); 26827b5132daSValentin Clement auto loc = neg.getLoc(); 26837b5132daSValentin Clement mlir::Value o0 = adaptor.getOperands()[0]; 26847b5132daSValentin Clement auto c0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0)); 26857b5132daSValentin Clement auto c1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1)); 26867b5132daSValentin Clement auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c0); 26877b5132daSValentin Clement auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c1); 26887b5132daSValentin Clement auto nrp = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, rp); 26897b5132daSValentin Clement auto nip = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, ip); 26907b5132daSValentin Clement auto r = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, o0, nrp, c0); 26917b5132daSValentin Clement rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(neg, ty, r, nip, c1); 26927b5132daSValentin Clement return success(); 26937b5132daSValentin Clement } 26947b5132daSValentin Clement }; 26957b5132daSValentin Clement 26961ed5a90fSValentin Clement /// Conversion pattern for operation that must be dead. The information in these 26971ed5a90fSValentin Clement /// operations is used by other operation. At this point they should not have 26981ed5a90fSValentin Clement /// anymore uses. 26991ed5a90fSValentin Clement /// These operations are normally dead after the pre-codegen pass. 27001ed5a90fSValentin Clement template <typename FromOp> 27011ed5a90fSValentin Clement struct MustBeDeadConversion : public FIROpConversion<FromOp> { 27021ed5a90fSValentin Clement explicit MustBeDeadConversion(fir::LLVMTypeConverter &lowering) 27031ed5a90fSValentin Clement : FIROpConversion<FromOp>(lowering) {} 27041ed5a90fSValentin Clement using OpAdaptor = typename FromOp::Adaptor; 27051ed5a90fSValentin Clement 27061ed5a90fSValentin Clement mlir::LogicalResult 27071ed5a90fSValentin Clement matchAndRewrite(FromOp op, OpAdaptor adaptor, 27081ed5a90fSValentin Clement mlir::ConversionPatternRewriter &rewriter) const final { 27091ed5a90fSValentin Clement if (!op->getUses().empty()) 27101ed5a90fSValentin Clement return rewriter.notifyMatchFailure(op, "op must be dead"); 27111ed5a90fSValentin Clement rewriter.eraseOp(op); 27121ed5a90fSValentin Clement return success(); 27131ed5a90fSValentin Clement } 27141ed5a90fSValentin Clement }; 27151ed5a90fSValentin Clement 27161ed5a90fSValentin Clement struct ShapeOpConversion : public MustBeDeadConversion<fir::ShapeOp> { 27171ed5a90fSValentin Clement using MustBeDeadConversion::MustBeDeadConversion; 27181ed5a90fSValentin Clement }; 27191ed5a90fSValentin Clement 27201ed5a90fSValentin Clement struct ShapeShiftOpConversion : public MustBeDeadConversion<fir::ShapeShiftOp> { 27211ed5a90fSValentin Clement using MustBeDeadConversion::MustBeDeadConversion; 27221ed5a90fSValentin Clement }; 27231ed5a90fSValentin Clement 27241ed5a90fSValentin Clement struct ShiftOpConversion : public MustBeDeadConversion<fir::ShiftOp> { 27251ed5a90fSValentin Clement using MustBeDeadConversion::MustBeDeadConversion; 27261ed5a90fSValentin Clement }; 27271ed5a90fSValentin Clement 27281ed5a90fSValentin Clement struct SliceOpConversion : public MustBeDeadConversion<fir::SliceOp> { 27291ed5a90fSValentin Clement using MustBeDeadConversion::MustBeDeadConversion; 27301ed5a90fSValentin Clement }; 27311ed5a90fSValentin Clement 2732420ad7ceSAndrzej Warzynski /// `fir.is_present` --> 2733420ad7ceSAndrzej Warzynski /// ``` 2734420ad7ceSAndrzej Warzynski /// %0 = llvm.mlir.constant(0 : i64) 2735420ad7ceSAndrzej Warzynski /// %1 = llvm.ptrtoint %0 2736420ad7ceSAndrzej Warzynski /// %2 = llvm.icmp "ne" %1, %0 : i64 2737420ad7ceSAndrzej Warzynski /// ``` 2738420ad7ceSAndrzej Warzynski struct IsPresentOpConversion : public FIROpConversion<fir::IsPresentOp> { 2739420ad7ceSAndrzej Warzynski using FIROpConversion::FIROpConversion; 2740420ad7ceSAndrzej Warzynski 2741420ad7ceSAndrzej Warzynski mlir::LogicalResult 2742420ad7ceSAndrzej Warzynski matchAndRewrite(fir::IsPresentOp isPresent, OpAdaptor adaptor, 2743420ad7ceSAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 2744420ad7ceSAndrzej Warzynski mlir::Type idxTy = lowerTy().indexType(); 2745420ad7ceSAndrzej Warzynski mlir::Location loc = isPresent.getLoc(); 2746420ad7ceSAndrzej Warzynski auto ptr = adaptor.getOperands()[0]; 2747420ad7ceSAndrzej Warzynski 2748420ad7ceSAndrzej Warzynski if (isPresent.val().getType().isa<fir::BoxCharType>()) { 2749420ad7ceSAndrzej Warzynski auto structTy = ptr.getType().cast<mlir::LLVM::LLVMStructType>(); 2750420ad7ceSAndrzej Warzynski assert(!structTy.isOpaque() && !structTy.getBody().empty()); 2751420ad7ceSAndrzej Warzynski 2752420ad7ceSAndrzej Warzynski mlir::Type ty = structTy.getBody()[0]; 2753420ad7ceSAndrzej Warzynski mlir::MLIRContext *ctx = isPresent.getContext(); 2754420ad7ceSAndrzej Warzynski auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 2755420ad7ceSAndrzej Warzynski ptr = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, ptr, c0); 2756420ad7ceSAndrzej Warzynski } 2757420ad7ceSAndrzej Warzynski mlir::LLVM::ConstantOp c0 = 2758420ad7ceSAndrzej Warzynski genConstantIndex(isPresent.getLoc(), idxTy, rewriter, 0); 2759420ad7ceSAndrzej Warzynski auto addr = rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, ptr); 2760420ad7ceSAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>( 2761420ad7ceSAndrzej Warzynski isPresent, mlir::LLVM::ICmpPredicate::ne, addr, c0); 2762420ad7ceSAndrzej Warzynski 2763420ad7ceSAndrzej Warzynski return success(); 2764420ad7ceSAndrzej Warzynski } 2765420ad7ceSAndrzej Warzynski }; 27661e77b095SAndrzej Warzynski 27671e77b095SAndrzej Warzynski /// Convert `!fir.emboxchar<!fir.char<KIND, ?>, #n>` into a sequence of 27681e77b095SAndrzej Warzynski /// instructions that generate `!llvm.struct<(ptr<ik>, i64)>`. The 1st element 27691e77b095SAndrzej Warzynski /// in this struct is a pointer. Its type is determined from `KIND`. The 2nd 27701e77b095SAndrzej Warzynski /// element is the length of the character buffer (`#n`). 27711e77b095SAndrzej Warzynski struct EmboxCharOpConversion : public FIROpConversion<fir::EmboxCharOp> { 27721e77b095SAndrzej Warzynski using FIROpConversion::FIROpConversion; 27731e77b095SAndrzej Warzynski 27741e77b095SAndrzej Warzynski mlir::LogicalResult 27751e77b095SAndrzej Warzynski matchAndRewrite(fir::EmboxCharOp emboxChar, OpAdaptor adaptor, 27761e77b095SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 27771e77b095SAndrzej Warzynski mlir::ValueRange operands = adaptor.getOperands(); 27781e77b095SAndrzej Warzynski MLIRContext *ctx = emboxChar.getContext(); 27791e77b095SAndrzej Warzynski 27801e77b095SAndrzej Warzynski mlir::Value charBuffer = operands[0]; 27811e77b095SAndrzej Warzynski mlir::Value charBufferLen = operands[1]; 27821e77b095SAndrzej Warzynski 27831e77b095SAndrzej Warzynski mlir::Location loc = emboxChar.getLoc(); 27841e77b095SAndrzej Warzynski mlir::Type llvmStructTy = convertType(emboxChar.getType()); 27851e77b095SAndrzej Warzynski auto llvmStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, llvmStructTy); 27861e77b095SAndrzej Warzynski 27871e77b095SAndrzej Warzynski mlir::Type lenTy = 27881e77b095SAndrzej Warzynski llvmStructTy.cast<mlir::LLVM::LLVMStructType>().getBody()[1]; 27891e77b095SAndrzej Warzynski mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, charBufferLen); 27901e77b095SAndrzej Warzynski 27911e77b095SAndrzej Warzynski auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); 27921e77b095SAndrzej Warzynski auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); 27931e77b095SAndrzej Warzynski auto insertBufferOp = rewriter.create<mlir::LLVM::InsertValueOp>( 27941e77b095SAndrzej Warzynski loc, llvmStructTy, llvmStruct, charBuffer, c0); 27951e77b095SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>( 27961e77b095SAndrzej Warzynski emboxChar, llvmStructTy, insertBufferOp, lenAfterCast, c1); 27971e77b095SAndrzej Warzynski 27981e77b095SAndrzej Warzynski return success(); 27991e77b095SAndrzej Warzynski } 28001e77b095SAndrzej Warzynski }; 2801c2acd453SAlexisPerry } // namespace 280214867ffcSAndrzej Warzynski 280314867ffcSAndrzej Warzynski /// Construct an `llvm.extractvalue` instruction. It will return value at 280414867ffcSAndrzej Warzynski /// element \p x from \p tuple. 2805c2acd453SAlexisPerry static mlir::LLVM::ExtractValueOp 280614867ffcSAndrzej Warzynski genExtractValueWithIndex(mlir::Location loc, mlir::Value tuple, mlir::Type ty, 280714867ffcSAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter, 280814867ffcSAndrzej Warzynski mlir::MLIRContext *ctx, int x) { 280914867ffcSAndrzej Warzynski auto cx = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(x)); 281014867ffcSAndrzej Warzynski auto xty = ty.cast<mlir::LLVM::LLVMStructType>().getBody()[x]; 281114867ffcSAndrzej Warzynski return rewriter.create<mlir::LLVM::ExtractValueOp>(loc, xty, tuple, cx); 281214867ffcSAndrzej Warzynski } 281314867ffcSAndrzej Warzynski 2814c2acd453SAlexisPerry namespace { 28156c3d7fd4SAndrzej Warzynski /// Convert `!fir.boxchar_len` to `!llvm.extractvalue` for the 2nd part of the 28166c3d7fd4SAndrzej Warzynski /// boxchar. 28176c3d7fd4SAndrzej Warzynski struct BoxCharLenOpConversion : public FIROpConversion<fir::BoxCharLenOp> { 28186c3d7fd4SAndrzej Warzynski using FIROpConversion::FIROpConversion; 28196c3d7fd4SAndrzej Warzynski 28206c3d7fd4SAndrzej Warzynski mlir::LogicalResult 28216c3d7fd4SAndrzej Warzynski matchAndRewrite(fir::BoxCharLenOp boxCharLen, OpAdaptor adaptor, 28226c3d7fd4SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 28236c3d7fd4SAndrzej Warzynski mlir::Value boxChar = adaptor.getOperands()[0]; 28246c3d7fd4SAndrzej Warzynski mlir::Location loc = boxChar.getLoc(); 28256c3d7fd4SAndrzej Warzynski mlir::MLIRContext *ctx = boxChar.getContext(); 28266c3d7fd4SAndrzej Warzynski mlir::Type returnValTy = boxCharLen.getResult().getType(); 28276c3d7fd4SAndrzej Warzynski 28286c3d7fd4SAndrzej Warzynski constexpr int boxcharLenIdx = 1; 28296c3d7fd4SAndrzej Warzynski mlir::LLVM::ExtractValueOp len = genExtractValueWithIndex( 28306c3d7fd4SAndrzej Warzynski loc, boxChar, boxChar.getType(), rewriter, ctx, boxcharLenIdx); 28316c3d7fd4SAndrzej Warzynski mlir::Value lenAfterCast = integerCast(loc, rewriter, returnValTy, len); 28326c3d7fd4SAndrzej Warzynski rewriter.replaceOp(boxCharLen, lenAfterCast); 28336c3d7fd4SAndrzej Warzynski 28346c3d7fd4SAndrzej Warzynski return success(); 28356c3d7fd4SAndrzej Warzynski } 28366c3d7fd4SAndrzej Warzynski }; 28376c3d7fd4SAndrzej Warzynski 283814867ffcSAndrzej Warzynski /// Convert `fir.unboxchar` into two `llvm.extractvalue` instructions. One for 283914867ffcSAndrzej Warzynski /// the character buffer and one for the buffer length. 284014867ffcSAndrzej Warzynski struct UnboxCharOpConversion : public FIROpConversion<fir::UnboxCharOp> { 284114867ffcSAndrzej Warzynski using FIROpConversion::FIROpConversion; 284214867ffcSAndrzej Warzynski 284314867ffcSAndrzej Warzynski mlir::LogicalResult 284414867ffcSAndrzej Warzynski matchAndRewrite(fir::UnboxCharOp unboxchar, OpAdaptor adaptor, 284514867ffcSAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 284614867ffcSAndrzej Warzynski MLIRContext *ctx = unboxchar.getContext(); 284714867ffcSAndrzej Warzynski 284814867ffcSAndrzej Warzynski mlir::Type lenTy = convertType(unboxchar.getType(1)); 284914867ffcSAndrzej Warzynski mlir::Value tuple = adaptor.getOperands()[0]; 285014867ffcSAndrzej Warzynski mlir::Type tupleTy = tuple.getType(); 285114867ffcSAndrzej Warzynski 285214867ffcSAndrzej Warzynski mlir::Location loc = unboxchar.getLoc(); 285314867ffcSAndrzej Warzynski mlir::Value ptrToBuffer = 285414867ffcSAndrzej Warzynski genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 0); 285514867ffcSAndrzej Warzynski 285614867ffcSAndrzej Warzynski mlir::LLVM::ExtractValueOp len = 285714867ffcSAndrzej Warzynski genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 1); 285814867ffcSAndrzej Warzynski mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, len); 285914867ffcSAndrzej Warzynski 286014867ffcSAndrzej Warzynski rewriter.replaceOp(unboxchar, 286114867ffcSAndrzej Warzynski ArrayRef<mlir::Value>{ptrToBuffer, lenAfterCast}); 286214867ffcSAndrzej Warzynski return success(); 286314867ffcSAndrzej Warzynski } 286414867ffcSAndrzej Warzynski }; 286514867ffcSAndrzej Warzynski 2866cc505c0bSKiran Chandramohan /// Lower `fir.unboxproc` operation. Unbox a procedure box value, yielding its 2867cc505c0bSKiran Chandramohan /// components. 2868cc505c0bSKiran Chandramohan /// TODO: Part of supporting Fortran 2003 procedure pointers. 2869cc505c0bSKiran Chandramohan struct UnboxProcOpConversion : public FIROpConversion<fir::UnboxProcOp> { 2870cc505c0bSKiran Chandramohan using FIROpConversion::FIROpConversion; 2871cc505c0bSKiran Chandramohan 2872cc505c0bSKiran Chandramohan mlir::LogicalResult 2873cc505c0bSKiran Chandramohan matchAndRewrite(fir::UnboxProcOp unboxproc, OpAdaptor adaptor, 2874cc505c0bSKiran Chandramohan mlir::ConversionPatternRewriter &rewriter) const override { 28757ce8c6fcSKiran Chandramohan TODO(unboxproc.getLoc(), "fir.unboxproc codegen"); 28767ce8c6fcSKiran Chandramohan return failure(); 2877cc505c0bSKiran Chandramohan } 2878cc505c0bSKiran Chandramohan }; 2879cc505c0bSKiran Chandramohan 2880e6c66ef5SAndrzej Warzynski /// Convert `fir.field_index`. The conversion depends on whether the size of 2881e6c66ef5SAndrzej Warzynski /// the record is static or dynamic. 2882e6c66ef5SAndrzej Warzynski struct FieldIndexOpConversion : public FIROpConversion<fir::FieldIndexOp> { 2883e6c66ef5SAndrzej Warzynski using FIROpConversion::FIROpConversion; 2884e6c66ef5SAndrzej Warzynski 2885e6c66ef5SAndrzej Warzynski // NB: most field references should be resolved by this point 2886e6c66ef5SAndrzej Warzynski mlir::LogicalResult 2887e6c66ef5SAndrzej Warzynski matchAndRewrite(fir::FieldIndexOp field, OpAdaptor adaptor, 2888e6c66ef5SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 2889e6c66ef5SAndrzej Warzynski auto recTy = field.on_type().cast<fir::RecordType>(); 2890e6c66ef5SAndrzej Warzynski unsigned index = recTy.getFieldIndex(field.field_id()); 2891e6c66ef5SAndrzej Warzynski 2892e6c66ef5SAndrzej Warzynski if (!fir::hasDynamicSize(recTy)) { 2893e6c66ef5SAndrzej Warzynski // Derived type has compile-time constant layout. Return index of the 2894e6c66ef5SAndrzej Warzynski // component type in the parent type (to be used in GEP). 2895e6c66ef5SAndrzej Warzynski rewriter.replaceOp(field, mlir::ValueRange{genConstantOffset( 2896e6c66ef5SAndrzej Warzynski field.getLoc(), rewriter, index)}); 2897e6c66ef5SAndrzej Warzynski return success(); 2898e6c66ef5SAndrzej Warzynski } 2899e6c66ef5SAndrzej Warzynski 2900e6c66ef5SAndrzej Warzynski // Derived type has compile-time constant layout. Call the compiler 2901e6c66ef5SAndrzej Warzynski // generated function to determine the byte offset of the field at runtime. 2902e6c66ef5SAndrzej Warzynski // This returns a non-constant. 2903e6c66ef5SAndrzej Warzynski FlatSymbolRefAttr symAttr = mlir::SymbolRefAttr::get( 2904e6c66ef5SAndrzej Warzynski field.getContext(), getOffsetMethodName(recTy, field.field_id())); 2905e6c66ef5SAndrzej Warzynski NamedAttribute callAttr = rewriter.getNamedAttr("callee", symAttr); 2906e6c66ef5SAndrzej Warzynski NamedAttribute fieldAttr = rewriter.getNamedAttr( 2907e6c66ef5SAndrzej Warzynski "field", mlir::IntegerAttr::get(lowerTy().indexType(), index)); 2908e6c66ef5SAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>( 2909e6c66ef5SAndrzej Warzynski field, lowerTy().offsetType(), adaptor.getOperands(), 2910e6c66ef5SAndrzej Warzynski llvm::ArrayRef<mlir::NamedAttribute>{callAttr, fieldAttr}); 2911e6c66ef5SAndrzej Warzynski return success(); 2912e6c66ef5SAndrzej Warzynski } 2913e6c66ef5SAndrzej Warzynski 2914e6c66ef5SAndrzej Warzynski // Re-Construct the name of the compiler generated method that calculates the 2915e6c66ef5SAndrzej Warzynski // offset 2916e6c66ef5SAndrzej Warzynski inline static std::string getOffsetMethodName(fir::RecordType recTy, 2917e6c66ef5SAndrzej Warzynski llvm::StringRef field) { 2918e6c66ef5SAndrzej Warzynski return recTy.getName().str() + "P." + field.str() + ".offset"; 2919e6c66ef5SAndrzej Warzynski } 2920e6c66ef5SAndrzej Warzynski }; 2921e6c66ef5SAndrzej Warzynski 292275db341dSAndrzej Warzynski /// Convert to (memory) reference to a reference to a subobject. 292375db341dSAndrzej Warzynski /// The coordinate_of op is a Swiss army knife operation that can be used on 292475db341dSAndrzej Warzynski /// (memory) references to records, arrays, complex, etc. as well as boxes. 292575db341dSAndrzej Warzynski /// With unboxed arrays, there is the restriction that the array have a static 292675db341dSAndrzej Warzynski /// shape in all but the last column. 292775db341dSAndrzej Warzynski struct CoordinateOpConversion 292875db341dSAndrzej Warzynski : public FIROpAndTypeConversion<fir::CoordinateOp> { 292975db341dSAndrzej Warzynski using FIROpAndTypeConversion::FIROpAndTypeConversion; 293075db341dSAndrzej Warzynski 293175db341dSAndrzej Warzynski mlir::LogicalResult 293275db341dSAndrzej Warzynski doRewrite(fir::CoordinateOp coor, mlir::Type ty, OpAdaptor adaptor, 293375db341dSAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const override { 293475db341dSAndrzej Warzynski mlir::ValueRange operands = adaptor.getOperands(); 293575db341dSAndrzej Warzynski 293675db341dSAndrzej Warzynski mlir::Location loc = coor.getLoc(); 293775db341dSAndrzej Warzynski mlir::Value base = operands[0]; 293875db341dSAndrzej Warzynski mlir::Type baseObjectTy = coor.getBaseType(); 293975db341dSAndrzej Warzynski mlir::Type objectTy = fir::dyn_cast_ptrOrBoxEleTy(baseObjectTy); 294075db341dSAndrzej Warzynski assert(objectTy && "fir.coordinate_of expects a reference type"); 294175db341dSAndrzej Warzynski 294275db341dSAndrzej Warzynski // Complex type - basically, extract the real or imaginary part 294375db341dSAndrzej Warzynski if (fir::isa_complex(objectTy)) { 294475db341dSAndrzej Warzynski mlir::LLVM::ConstantOp c0 = 294575db341dSAndrzej Warzynski genConstantIndex(loc, lowerTy().indexType(), rewriter, 0); 294675db341dSAndrzej Warzynski SmallVector<mlir::Value> offs = {c0, operands[1]}; 294775db341dSAndrzej Warzynski mlir::Value gep = genGEP(loc, ty, rewriter, base, offs); 294875db341dSAndrzej Warzynski rewriter.replaceOp(coor, gep); 294975db341dSAndrzej Warzynski return success(); 295075db341dSAndrzej Warzynski } 295175db341dSAndrzej Warzynski 29526d655ad0SAndrzej Warzynski // Boxed type - get the base pointer from the box 29536d655ad0SAndrzej Warzynski if (baseObjectTy.dyn_cast<fir::BoxType>()) 29546d655ad0SAndrzej Warzynski return doRewriteBox(coor, ty, operands, loc, rewriter); 295575db341dSAndrzej Warzynski 29566d655ad0SAndrzej Warzynski // Reference or pointer type 29576d655ad0SAndrzej Warzynski if (baseObjectTy.isa<fir::ReferenceType, fir::PointerType>()) 29586d655ad0SAndrzej Warzynski return doRewriteRefOrPtr(coor, ty, operands, loc, rewriter); 295975db341dSAndrzej Warzynski 296075db341dSAndrzej Warzynski return rewriter.notifyMatchFailure( 296175db341dSAndrzej Warzynski coor, "fir.coordinate_of base operand has unsupported type"); 296275db341dSAndrzej Warzynski } 296375db341dSAndrzej Warzynski 296475db341dSAndrzej Warzynski unsigned getFieldNumber(fir::RecordType ty, mlir::Value op) const { 296575db341dSAndrzej Warzynski return fir::hasDynamicSize(ty) 296675db341dSAndrzej Warzynski ? op.getDefiningOp() 296775db341dSAndrzej Warzynski ->getAttrOfType<mlir::IntegerAttr>("field") 296875db341dSAndrzej Warzynski .getInt() 296975db341dSAndrzej Warzynski : getIntValue(op); 297075db341dSAndrzej Warzynski } 297175db341dSAndrzej Warzynski 297275db341dSAndrzej Warzynski int64_t getIntValue(mlir::Value val) const { 297375db341dSAndrzej Warzynski assert(val && val.dyn_cast<mlir::OpResult>() && "must not be null value"); 297475db341dSAndrzej Warzynski mlir::Operation *defop = val.getDefiningOp(); 297575db341dSAndrzej Warzynski 297675db341dSAndrzej Warzynski if (auto constOp = dyn_cast<mlir::arith::ConstantIntOp>(defop)) 297775db341dSAndrzej Warzynski return constOp.value(); 297875db341dSAndrzej Warzynski if (auto llConstOp = dyn_cast<mlir::LLVM::ConstantOp>(defop)) 2979feeee78aSJacques Pienaar if (auto attr = llConstOp.getValue().dyn_cast<mlir::IntegerAttr>()) 298075db341dSAndrzej Warzynski return attr.getValue().getSExtValue(); 298175db341dSAndrzej Warzynski fir::emitFatalError(val.getLoc(), "must be a constant"); 298275db341dSAndrzej Warzynski } 298375db341dSAndrzej Warzynski 29846d655ad0SAndrzej Warzynski bool hasSubDimensions(mlir::Type type) const { 29856d655ad0SAndrzej Warzynski return type.isa<fir::SequenceType, fir::RecordType, mlir::TupleType>(); 29866d655ad0SAndrzej Warzynski } 29876d655ad0SAndrzej Warzynski 29886d655ad0SAndrzej Warzynski /// Check whether this form of `!fir.coordinate_of` is supported. These 29896d655ad0SAndrzej Warzynski /// additional checks are required, because we are not yet able to convert 29906d655ad0SAndrzej Warzynski /// all valid forms of `!fir.coordinate_of`. 29916d655ad0SAndrzej Warzynski /// TODO: Either implement the unsupported cases or extend the verifier 29926d655ad0SAndrzej Warzynski /// in FIROps.cpp instead. 29936d655ad0SAndrzej Warzynski bool supportedCoordinate(mlir::Type type, mlir::ValueRange coors) const { 29946d655ad0SAndrzej Warzynski const std::size_t numOfCoors = coors.size(); 29956d655ad0SAndrzej Warzynski std::size_t i = 0; 29966d655ad0SAndrzej Warzynski bool subEle = false; 29976d655ad0SAndrzej Warzynski bool ptrEle = false; 29986d655ad0SAndrzej Warzynski for (; i < numOfCoors; ++i) { 29996d655ad0SAndrzej Warzynski mlir::Value nxtOpnd = coors[i]; 30006d655ad0SAndrzej Warzynski if (auto arrTy = type.dyn_cast<fir::SequenceType>()) { 30016d655ad0SAndrzej Warzynski subEle = true; 30026d655ad0SAndrzej Warzynski i += arrTy.getDimension() - 1; 30036d655ad0SAndrzej Warzynski type = arrTy.getEleTy(); 30046d655ad0SAndrzej Warzynski } else if (auto recTy = type.dyn_cast<fir::RecordType>()) { 30056d655ad0SAndrzej Warzynski subEle = true; 30066d655ad0SAndrzej Warzynski type = recTy.getType(getFieldNumber(recTy, nxtOpnd)); 30076d655ad0SAndrzej Warzynski } else if (auto tupTy = type.dyn_cast<mlir::TupleType>()) { 30086d655ad0SAndrzej Warzynski subEle = true; 30096d655ad0SAndrzej Warzynski type = tupTy.getType(getIntValue(nxtOpnd)); 30106d655ad0SAndrzej Warzynski } else { 30116d655ad0SAndrzej Warzynski ptrEle = true; 30126d655ad0SAndrzej Warzynski } 30136d655ad0SAndrzej Warzynski } 30146d655ad0SAndrzej Warzynski if (ptrEle) 30156d655ad0SAndrzej Warzynski return (!subEle) && (numOfCoors == 1); 30166d655ad0SAndrzej Warzynski return subEle && (i >= numOfCoors); 30176d655ad0SAndrzej Warzynski } 30186d655ad0SAndrzej Warzynski 30196d655ad0SAndrzej Warzynski /// Walk the abstract memory layout and determine if the path traverses any 30206d655ad0SAndrzej Warzynski /// array types with unknown shape. Return true iff all the array types have a 30216d655ad0SAndrzej Warzynski /// constant shape along the path. 30226d655ad0SAndrzej Warzynski bool arraysHaveKnownShape(mlir::Type type, mlir::ValueRange coors) const { 30236d655ad0SAndrzej Warzynski const std::size_t sz = coors.size(); 30246d655ad0SAndrzej Warzynski std::size_t i = 0; 30256d655ad0SAndrzej Warzynski for (; i < sz; ++i) { 30266d655ad0SAndrzej Warzynski mlir::Value nxtOpnd = coors[i]; 30276d655ad0SAndrzej Warzynski if (auto arrTy = type.dyn_cast<fir::SequenceType>()) { 30286d655ad0SAndrzej Warzynski if (fir::sequenceWithNonConstantShape(arrTy)) 30296d655ad0SAndrzej Warzynski return false; 30306d655ad0SAndrzej Warzynski i += arrTy.getDimension() - 1; 30316d655ad0SAndrzej Warzynski type = arrTy.getEleTy(); 30326d655ad0SAndrzej Warzynski } else if (auto strTy = type.dyn_cast<fir::RecordType>()) { 30336d655ad0SAndrzej Warzynski type = strTy.getType(getFieldNumber(strTy, nxtOpnd)); 30346d655ad0SAndrzej Warzynski } else if (auto strTy = type.dyn_cast<mlir::TupleType>()) { 30356d655ad0SAndrzej Warzynski type = strTy.getType(getIntValue(nxtOpnd)); 30366d655ad0SAndrzej Warzynski } else { 30376d655ad0SAndrzej Warzynski return true; 30386d655ad0SAndrzej Warzynski } 30396d655ad0SAndrzej Warzynski } 30406d655ad0SAndrzej Warzynski return true; 30416d655ad0SAndrzej Warzynski } 30426d655ad0SAndrzej Warzynski 304375db341dSAndrzej Warzynski private: 30446d655ad0SAndrzej Warzynski mlir::LogicalResult 30456d655ad0SAndrzej Warzynski doRewriteBox(fir::CoordinateOp coor, mlir::Type ty, mlir::ValueRange operands, 30466d655ad0SAndrzej Warzynski mlir::Location loc, 304775db341dSAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const { 304875db341dSAndrzej Warzynski mlir::Type boxObjTy = coor.getBaseType(); 304975db341dSAndrzej Warzynski assert(boxObjTy.dyn_cast<fir::BoxType>() && "This is not a `fir.box`"); 305075db341dSAndrzej Warzynski 305175db341dSAndrzej Warzynski mlir::Value boxBaseAddr = operands[0]; 305275db341dSAndrzej Warzynski 305375db341dSAndrzej Warzynski // 1. SPECIAL CASE (uses `fir.len_param_index`): 305475db341dSAndrzej Warzynski // %box = ... : !fir.box<!fir.type<derived{len1:i32}>> 305575db341dSAndrzej Warzynski // %lenp = fir.len_param_index len1, !fir.type<derived{len1:i32}> 305675db341dSAndrzej Warzynski // %addr = coordinate_of %box, %lenp 305775db341dSAndrzej Warzynski if (coor.getNumOperands() == 2) { 305875db341dSAndrzej Warzynski mlir::Operation *coordinateDef = (*coor.coor().begin()).getDefiningOp(); 305975db341dSAndrzej Warzynski if (isa_and_nonnull<fir::LenParamIndexOp>(coordinateDef)) { 306075db341dSAndrzej Warzynski TODO(loc, 306175db341dSAndrzej Warzynski "fir.coordinate_of - fir.len_param_index is not supported yet"); 306275db341dSAndrzej Warzynski } 306375db341dSAndrzej Warzynski } 306475db341dSAndrzej Warzynski 306575db341dSAndrzej Warzynski // 2. GENERAL CASE: 306675db341dSAndrzej Warzynski // 2.1. (`fir.array`) 306775db341dSAndrzej Warzynski // %box = ... : !fix.box<!fir.array<?xU>> 306875db341dSAndrzej Warzynski // %idx = ... : index 306975db341dSAndrzej Warzynski // %resultAddr = coordinate_of %box, %idx : !fir.ref<U> 307075db341dSAndrzej Warzynski // 2.2 (`fir.derived`) 307175db341dSAndrzej Warzynski // %box = ... : !fix.box<!fir.type<derived_type{field_1:i32}>> 307275db341dSAndrzej Warzynski // %idx = ... : i32 307375db341dSAndrzej Warzynski // %resultAddr = coordinate_of %box, %idx : !fir.ref<i32> 307475db341dSAndrzej Warzynski // 2.3 (`fir.derived` inside `fir.array`) 307575db341dSAndrzej Warzynski // %box = ... : !fir.box<!fir.array<10 x !fir.type<derived_1{field_1:f32, field_2:f32}>>> 307675db341dSAndrzej Warzynski // %idx1 = ... : index 307775db341dSAndrzej Warzynski // %idx2 = ... : i32 307875db341dSAndrzej Warzynski // %resultAddr = coordinate_of %box, %idx1, %idx2 : !fir.ref<f32> 307975db341dSAndrzej Warzynski // 2.4. TODO: Either document or disable any other case that the following 308075db341dSAndrzej Warzynski // implementation might convert. 308175db341dSAndrzej Warzynski mlir::LLVM::ConstantOp c0 = 308275db341dSAndrzej Warzynski genConstantIndex(loc, lowerTy().indexType(), rewriter, 0); 308375db341dSAndrzej Warzynski mlir::Value resultAddr = 308475db341dSAndrzej Warzynski loadBaseAddrFromBox(loc, getBaseAddrTypeFromBox(boxBaseAddr.getType()), 308575db341dSAndrzej Warzynski boxBaseAddr, rewriter); 308675db341dSAndrzej Warzynski auto currentObjTy = fir::dyn_cast_ptrOrBoxEleTy(boxObjTy); 308775db341dSAndrzej Warzynski mlir::Type voidPtrTy = ::getVoidPtrType(coor.getContext()); 308875db341dSAndrzej Warzynski 308975db341dSAndrzej Warzynski for (unsigned i = 1, last = operands.size(); i < last; ++i) { 309075db341dSAndrzej Warzynski if (auto arrTy = currentObjTy.dyn_cast<fir::SequenceType>()) { 309175db341dSAndrzej Warzynski if (i != 1) 309275db341dSAndrzej Warzynski TODO(loc, "fir.array nested inside other array and/or derived type"); 309375db341dSAndrzej Warzynski // Applies byte strides from the box. Ignore lower bound from box 309475db341dSAndrzej Warzynski // since fir.coordinate_of indexes are zero based. Lowering takes care 309575db341dSAndrzej Warzynski // of lower bound aspects. This both accounts for dynamically sized 309675db341dSAndrzej Warzynski // types and non contiguous arrays. 309775db341dSAndrzej Warzynski auto idxTy = lowerTy().indexType(); 309875db341dSAndrzej Warzynski mlir::Value off = genConstantIndex(loc, idxTy, rewriter, 0); 309975db341dSAndrzej Warzynski for (unsigned index = i, lastIndex = i + arrTy.getDimension(); 310075db341dSAndrzej Warzynski index < lastIndex; ++index) { 310175db341dSAndrzej Warzynski mlir::Value stride = 310275db341dSAndrzej Warzynski loadStrideFromBox(loc, operands[0], index - i, rewriter); 310375db341dSAndrzej Warzynski auto sc = rewriter.create<mlir::LLVM::MulOp>(loc, idxTy, 310475db341dSAndrzej Warzynski operands[index], stride); 310575db341dSAndrzej Warzynski off = rewriter.create<mlir::LLVM::AddOp>(loc, idxTy, sc, off); 310675db341dSAndrzej Warzynski } 310775db341dSAndrzej Warzynski auto voidPtrBase = 310875db341dSAndrzej Warzynski rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, resultAddr); 310930122656SAlex Zinenko SmallVector<mlir::Value> args{off}; 311030122656SAlex Zinenko resultAddr = rewriter.create<mlir::LLVM::GEPOp>(loc, voidPtrTy, 311130122656SAlex Zinenko voidPtrBase, args); 311275db341dSAndrzej Warzynski i += arrTy.getDimension() - 1; 311375db341dSAndrzej Warzynski currentObjTy = arrTy.getEleTy(); 311475db341dSAndrzej Warzynski } else if (auto recTy = currentObjTy.dyn_cast<fir::RecordType>()) { 311575db341dSAndrzej Warzynski auto recRefTy = 311675db341dSAndrzej Warzynski mlir::LLVM::LLVMPointerType::get(lowerTy().convertType(recTy)); 311775db341dSAndrzej Warzynski mlir::Value nxtOpnd = operands[i]; 311875db341dSAndrzej Warzynski auto memObj = 311975db341dSAndrzej Warzynski rewriter.create<mlir::LLVM::BitcastOp>(loc, recRefTy, resultAddr); 312030122656SAlex Zinenko llvm::SmallVector<mlir::Value> args = {c0, nxtOpnd}; 312175db341dSAndrzej Warzynski currentObjTy = recTy.getType(getFieldNumber(recTy, nxtOpnd)); 312275db341dSAndrzej Warzynski auto llvmCurrentObjTy = lowerTy().convertType(currentObjTy); 312375db341dSAndrzej Warzynski auto gep = rewriter.create<mlir::LLVM::GEPOp>( 312430122656SAlex Zinenko loc, mlir::LLVM::LLVMPointerType::get(llvmCurrentObjTy), memObj, 312530122656SAlex Zinenko args); 312675db341dSAndrzej Warzynski resultAddr = 312775db341dSAndrzej Warzynski rewriter.create<mlir::LLVM::BitcastOp>(loc, voidPtrTy, gep); 312875db341dSAndrzej Warzynski } else { 312975db341dSAndrzej Warzynski fir::emitFatalError(loc, "unexpected type in coordinate_of"); 313075db341dSAndrzej Warzynski } 313175db341dSAndrzej Warzynski } 313275db341dSAndrzej Warzynski 313375db341dSAndrzej Warzynski rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(coor, ty, resultAddr); 31346d655ad0SAndrzej Warzynski return success(); 313575db341dSAndrzej Warzynski } 313675db341dSAndrzej Warzynski 31376d655ad0SAndrzej Warzynski mlir::LogicalResult 31386d655ad0SAndrzej Warzynski doRewriteRefOrPtr(fir::CoordinateOp coor, mlir::Type ty, 31396d655ad0SAndrzej Warzynski mlir::ValueRange operands, mlir::Location loc, 31406d655ad0SAndrzej Warzynski mlir::ConversionPatternRewriter &rewriter) const { 31416d655ad0SAndrzej Warzynski mlir::Type baseObjectTy = coor.getBaseType(); 31426d655ad0SAndrzej Warzynski 31436d655ad0SAndrzej Warzynski mlir::Type currentObjTy = fir::dyn_cast_ptrOrBoxEleTy(baseObjectTy); 31446d655ad0SAndrzej Warzynski bool hasSubdimension = hasSubDimensions(currentObjTy); 31456d655ad0SAndrzej Warzynski bool columnIsDeferred = !hasSubdimension; 31466d655ad0SAndrzej Warzynski 31476d655ad0SAndrzej Warzynski if (!supportedCoordinate(currentObjTy, operands.drop_front(1))) { 31486d655ad0SAndrzej Warzynski TODO(loc, "unsupported combination of coordinate operands"); 31496d655ad0SAndrzej Warzynski } 31506d655ad0SAndrzej Warzynski 31516d655ad0SAndrzej Warzynski const bool hasKnownShape = 31526d655ad0SAndrzej Warzynski arraysHaveKnownShape(currentObjTy, operands.drop_front(1)); 31536d655ad0SAndrzej Warzynski 31546d655ad0SAndrzej Warzynski // If only the column is `?`, then we can simply place the column value in 31556d655ad0SAndrzej Warzynski // the 0-th GEP position. 31566d655ad0SAndrzej Warzynski if (auto arrTy = currentObjTy.dyn_cast<fir::SequenceType>()) { 31576d655ad0SAndrzej Warzynski if (!hasKnownShape) { 31586d655ad0SAndrzej Warzynski const unsigned sz = arrTy.getDimension(); 31596d655ad0SAndrzej Warzynski if (arraysHaveKnownShape(arrTy.getEleTy(), 31606d655ad0SAndrzej Warzynski operands.drop_front(1 + sz))) { 31616d655ad0SAndrzej Warzynski llvm::ArrayRef<int64_t> shape = arrTy.getShape(); 31626d655ad0SAndrzej Warzynski bool allConst = true; 31636d655ad0SAndrzej Warzynski for (unsigned i = 0; i < sz - 1; ++i) { 31646d655ad0SAndrzej Warzynski if (shape[i] < 0) { 31656d655ad0SAndrzej Warzynski allConst = false; 31666d655ad0SAndrzej Warzynski break; 31676d655ad0SAndrzej Warzynski } 31686d655ad0SAndrzej Warzynski } 31696d655ad0SAndrzej Warzynski if (allConst) 31706d655ad0SAndrzej Warzynski columnIsDeferred = true; 31716d655ad0SAndrzej Warzynski } 31726d655ad0SAndrzej Warzynski } 31736d655ad0SAndrzej Warzynski } 31746d655ad0SAndrzej Warzynski 31756d655ad0SAndrzej Warzynski if (fir::hasDynamicSize(fir::unwrapSequenceType(currentObjTy))) { 31766d655ad0SAndrzej Warzynski mlir::emitError( 31776d655ad0SAndrzej Warzynski loc, "fir.coordinate_of with a dynamic element size is unsupported"); 31786d655ad0SAndrzej Warzynski return failure(); 31796d655ad0SAndrzej Warzynski } 31806d655ad0SAndrzej Warzynski 31816d655ad0SAndrzej Warzynski if (hasKnownShape || columnIsDeferred) { 31826d655ad0SAndrzej Warzynski SmallVector<mlir::Value> offs; 31836d655ad0SAndrzej Warzynski if (hasKnownShape && hasSubdimension) { 31846d655ad0SAndrzej Warzynski mlir::LLVM::ConstantOp c0 = 31856d655ad0SAndrzej Warzynski genConstantIndex(loc, lowerTy().indexType(), rewriter, 0); 31866d655ad0SAndrzej Warzynski offs.push_back(c0); 31876d655ad0SAndrzej Warzynski } 31886d655ad0SAndrzej Warzynski const std::size_t sz = operands.size(); 31896d655ad0SAndrzej Warzynski Optional<int> dims; 31906d655ad0SAndrzej Warzynski SmallVector<mlir::Value> arrIdx; 31916d655ad0SAndrzej Warzynski for (std::size_t i = 1; i < sz; ++i) { 31926d655ad0SAndrzej Warzynski mlir::Value nxtOpnd = operands[i]; 31936d655ad0SAndrzej Warzynski 31946d655ad0SAndrzej Warzynski if (!currentObjTy) { 31956d655ad0SAndrzej Warzynski mlir::emitError(loc, "invalid coordinate/check failed"); 31966d655ad0SAndrzej Warzynski return failure(); 31976d655ad0SAndrzej Warzynski } 31986d655ad0SAndrzej Warzynski 31996d655ad0SAndrzej Warzynski // check if the i-th coordinate relates to an array 32006d655ad0SAndrzej Warzynski if (dims.hasValue()) { 32016d655ad0SAndrzej Warzynski arrIdx.push_back(nxtOpnd); 32026d655ad0SAndrzej Warzynski int dimsLeft = *dims; 32036d655ad0SAndrzej Warzynski if (dimsLeft > 1) { 32046d655ad0SAndrzej Warzynski dims = dimsLeft - 1; 32056d655ad0SAndrzej Warzynski continue; 32066d655ad0SAndrzej Warzynski } 32076d655ad0SAndrzej Warzynski currentObjTy = currentObjTy.cast<fir::SequenceType>().getEleTy(); 32086d655ad0SAndrzej Warzynski // append array range in reverse (FIR arrays are column-major) 32096d655ad0SAndrzej Warzynski offs.append(arrIdx.rbegin(), arrIdx.rend()); 32106d655ad0SAndrzej Warzynski arrIdx.clear(); 32116d655ad0SAndrzej Warzynski dims.reset(); 32126d655ad0SAndrzej Warzynski continue; 32136d655ad0SAndrzej Warzynski } 32146d655ad0SAndrzej Warzynski if (auto arrTy = currentObjTy.dyn_cast<fir::SequenceType>()) { 32156d655ad0SAndrzej Warzynski int d = arrTy.getDimension() - 1; 32166d655ad0SAndrzej Warzynski if (d > 0) { 32176d655ad0SAndrzej Warzynski dims = d; 32186d655ad0SAndrzej Warzynski arrIdx.push_back(nxtOpnd); 32196d655ad0SAndrzej Warzynski continue; 32206d655ad0SAndrzej Warzynski } 32216d655ad0SAndrzej Warzynski currentObjTy = currentObjTy.cast<fir::SequenceType>().getEleTy(); 32226d655ad0SAndrzej Warzynski offs.push_back(nxtOpnd); 32236d655ad0SAndrzej Warzynski continue; 32246d655ad0SAndrzej Warzynski } 32256d655ad0SAndrzej Warzynski 32266d655ad0SAndrzej Warzynski // check if the i-th coordinate relates to a field 32276d655ad0SAndrzej Warzynski if (auto recTy = currentObjTy.dyn_cast<fir::RecordType>()) 32286d655ad0SAndrzej Warzynski currentObjTy = recTy.getType(getFieldNumber(recTy, nxtOpnd)); 32296d655ad0SAndrzej Warzynski else if (auto tupTy = currentObjTy.dyn_cast<mlir::TupleType>()) 32306d655ad0SAndrzej Warzynski currentObjTy = tupTy.getType(getIntValue(nxtOpnd)); 32316d655ad0SAndrzej Warzynski else 32326d655ad0SAndrzej Warzynski currentObjTy = nullptr; 32336d655ad0SAndrzej Warzynski 32346d655ad0SAndrzej Warzynski offs.push_back(nxtOpnd); 32356d655ad0SAndrzej Warzynski } 32366d655ad0SAndrzej Warzynski if (dims.hasValue()) 32376d655ad0SAndrzej Warzynski offs.append(arrIdx.rbegin(), arrIdx.rend()); 32386d655ad0SAndrzej Warzynski mlir::Value base = operands[0]; 32396d655ad0SAndrzej Warzynski mlir::Value retval = genGEP(loc, ty, rewriter, base, offs); 32406d655ad0SAndrzej Warzynski rewriter.replaceOp(coor, retval); 32416d655ad0SAndrzej Warzynski return success(); 32426d655ad0SAndrzej Warzynski } 32436d655ad0SAndrzej Warzynski 32446d655ad0SAndrzej Warzynski mlir::emitError(loc, "fir.coordinate_of base operand has unsupported type"); 32456d655ad0SAndrzej Warzynski return failure(); 324675db341dSAndrzej Warzynski } 324775db341dSAndrzej Warzynski }; 324875db341dSAndrzej Warzynski 3249044d5b5dSValentin Clement } // namespace 3250044d5b5dSValentin Clement 3251044d5b5dSValentin Clement namespace { 3252044d5b5dSValentin Clement /// Convert FIR dialect to LLVM dialect 3253044d5b5dSValentin Clement /// 3254044d5b5dSValentin Clement /// This pass lowers all FIR dialect operations to LLVM IR dialect. An 3255044d5b5dSValentin Clement /// MLIR pass is used to lower residual Std dialect to LLVM IR dialect. 3256044d5b5dSValentin Clement /// 3257044d5b5dSValentin Clement /// This pass is not complete yet. We are upstreaming it in small patches. 3258044d5b5dSValentin Clement class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> { 3259044d5b5dSValentin Clement public: 3260044d5b5dSValentin Clement mlir::ModuleOp getModule() { return getOperation(); } 3261044d5b5dSValentin Clement 3262044d5b5dSValentin Clement void runOnOperation() override final { 32637b5132daSValentin Clement auto mod = getModule(); 32647b5132daSValentin Clement if (!forcedTargetTriple.empty()) { 32657b5132daSValentin Clement fir::setTargetTriple(mod, forcedTargetTriple); 32667b5132daSValentin Clement } 32677b5132daSValentin Clement 3268044d5b5dSValentin Clement auto *context = getModule().getContext(); 3269044d5b5dSValentin Clement fir::LLVMTypeConverter typeConverter{getModule()}; 32709f85c198SRiver Riddle mlir::RewritePatternSet pattern(context); 3271df3b9810SValentin Clement pattern.insert< 3272420ad7ceSAndrzej Warzynski AbsentOpConversion, AddcOpConversion, AddrOfOpConversion, 3273c2acd453SAlexisPerry AllocaOpConversion, AllocMemOpConversion, BoxAddrOpConversion, 3274c2acd453SAlexisPerry BoxCharLenOpConversion, BoxDimsOpConversion, BoxEleSizeOpConversion, 3275c2acd453SAlexisPerry BoxIsAllocOpConversion, BoxIsArrayOpConversion, BoxIsPtrOpConversion, 3276c2acd453SAlexisPerry BoxProcHostOpConversion, BoxRankOpConversion, BoxTypeDescOpConversion, 3277c2acd453SAlexisPerry CallOpConversion, CmpcOpConversion, ConstcOpConversion, 3278e6e7da55SAndrzej Warzynski ConvertOpConversion, CoordinateOpConversion, DispatchOpConversion, 3279e6e7da55SAndrzej Warzynski DispatchTableOpConversion, DTEntryOpConversion, DivcOpConversion, 3280e6e7da55SAndrzej Warzynski EmboxOpConversion, EmboxCharOpConversion, EmboxProcOpConversion, 3281e6e7da55SAndrzej Warzynski ExtractValueOpConversion, FieldIndexOpConversion, FirEndOpConversion, 3282e6e7da55SAndrzej Warzynski FreeMemOpConversion, HasValueOpConversion, GenTypeDescOpConversion, 3283e6e7da55SAndrzej Warzynski GlobalLenOpConversion, GlobalOpConversion, InsertOnRangeOpConversion, 3284e6e7da55SAndrzej Warzynski InsertValueOpConversion, IsPresentOpConversion, 3285e6e7da55SAndrzej Warzynski LenParamIndexOpConversion, LoadOpConversion, NegcOpConversion, 3286e6e7da55SAndrzej Warzynski NoReassocOpConversion, MulcOpConversion, SelectCaseOpConversion, 3287e6e7da55SAndrzej Warzynski SelectOpConversion, SelectRankOpConversion, SelectTypeOpConversion, 3288e6e7da55SAndrzej Warzynski ShapeOpConversion, ShapeShiftOpConversion, ShiftOpConversion, 3289e6e7da55SAndrzej Warzynski SliceOpConversion, StoreOpConversion, StringLitOpConversion, 3290e6e7da55SAndrzej Warzynski SubcOpConversion, UnboxCharOpConversion, UnboxProcOpConversion, 3291e6e7da55SAndrzej Warzynski UndefOpConversion, UnreachableOpConversion, XArrayCoorOpConversion, 3292e6e7da55SAndrzej Warzynski XEmboxOpConversion, XReboxOpConversion, ZeroOpConversion>( 3293e6e7da55SAndrzej Warzynski typeConverter); 3294044d5b5dSValentin Clement mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern); 3295044d5b5dSValentin Clement mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter, 3296044d5b5dSValentin Clement pattern); 3297*ace01605SRiver Riddle mlir::cf::populateControlFlowToLLVMConversionPatterns(typeConverter, 3298*ace01605SRiver Riddle pattern); 3299044d5b5dSValentin Clement mlir::ConversionTarget target{*context}; 3300044d5b5dSValentin Clement target.addLegalDialect<mlir::LLVM::LLVMDialect>(); 3301044d5b5dSValentin Clement 3302044d5b5dSValentin Clement // required NOPs for applying a full conversion 3303044d5b5dSValentin Clement target.addLegalOp<mlir::ModuleOp>(); 3304044d5b5dSValentin Clement 3305044d5b5dSValentin Clement // apply the patterns 3306044d5b5dSValentin Clement if (mlir::failed(mlir::applyFullConversion(getModule(), target, 3307044d5b5dSValentin Clement std::move(pattern)))) { 3308044d5b5dSValentin Clement signalPassFailure(); 3309044d5b5dSValentin Clement } 3310044d5b5dSValentin Clement } 3311044d5b5dSValentin Clement }; 3312853e79d8SValentin Clement 3313853e79d8SValentin Clement /// Lower from LLVM IR dialect to proper LLVM-IR and dump the module 3314853e79d8SValentin Clement struct LLVMIRLoweringPass 3315853e79d8SValentin Clement : public mlir::PassWrapper<LLVMIRLoweringPass, 3316853e79d8SValentin Clement mlir::OperationPass<mlir::ModuleOp>> { 3317853e79d8SValentin Clement using Printer = fir::LLVMIRLoweringPrinter; 3318853e79d8SValentin Clement LLVMIRLoweringPass(raw_ostream &output, Printer p) 3319853e79d8SValentin Clement : output{output}, printer{p} {} 3320853e79d8SValentin Clement 3321853e79d8SValentin Clement mlir::ModuleOp getModule() { return getOperation(); } 3322853e79d8SValentin Clement 3323853e79d8SValentin Clement void runOnOperation() override final { 3324853e79d8SValentin Clement auto *ctx = getModule().getContext(); 3325853e79d8SValentin Clement auto optName = getModule().getName(); 3326853e79d8SValentin Clement llvm::LLVMContext llvmCtx; 3327853e79d8SValentin Clement if (auto llvmModule = mlir::translateModuleToLLVMIR( 3328853e79d8SValentin Clement getModule(), llvmCtx, optName ? *optName : "FIRModule")) { 3329853e79d8SValentin Clement printer(*llvmModule, output); 3330853e79d8SValentin Clement return; 3331853e79d8SValentin Clement } 3332853e79d8SValentin Clement 3333853e79d8SValentin Clement mlir::emitError(mlir::UnknownLoc::get(ctx), "could not emit LLVM-IR\n"); 3334853e79d8SValentin Clement signalPassFailure(); 3335853e79d8SValentin Clement } 3336853e79d8SValentin Clement 3337853e79d8SValentin Clement private: 3338853e79d8SValentin Clement raw_ostream &output; 3339853e79d8SValentin Clement Printer printer; 3340853e79d8SValentin Clement }; 3341853e79d8SValentin Clement 3342044d5b5dSValentin Clement } // namespace 3343044d5b5dSValentin Clement 3344044d5b5dSValentin Clement std::unique_ptr<mlir::Pass> fir::createFIRToLLVMPass() { 3345044d5b5dSValentin Clement return std::make_unique<FIRToLLVMLowering>(); 3346044d5b5dSValentin Clement } 3347853e79d8SValentin Clement 3348853e79d8SValentin Clement std::unique_ptr<mlir::Pass> 3349853e79d8SValentin Clement fir::createLLVMDialectToLLVMPass(raw_ostream &output, 3350853e79d8SValentin Clement fir::LLVMIRLoweringPrinter printer) { 3351853e79d8SValentin Clement return std::make_unique<LLVMIRLoweringPass>(output, printer); 3352853e79d8SValentin Clement } 3353