//===- TypeConverter.cpp - Convert builtin to LLVM dialect types ----------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "mlir/Conversion/LLVMCommon/TypeConverter.h" #include "MemRefDescriptor.h" #include "mlir/Conversion/LLVMCommon/MemRefBuilder.h" #include "mlir/Dialect/LLVMIR/LLVMDialect.h" #include "mlir/Dialect/LLVMIR/LLVMTypes.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/Support/Threading.h" #include <memory> #include <mutex> #include <optional> usingnamespacemlir; SmallVector<Type> &LLVMTypeConverter::getCurrentThreadRecursiveStack() { … } /// Create an LLVMTypeConverter using default LowerToLLVMOptions. LLVMTypeConverter::LLVMTypeConverter(MLIRContext *ctx, const DataLayoutAnalysis *analysis) : … { … } /// Create an LLVMTypeConverter using custom LowerToLLVMOptions. LLVMTypeConverter::LLVMTypeConverter(MLIRContext *ctx, const LowerToLLVMOptions &options, const DataLayoutAnalysis *analysis) : … { … } /// Returns the MLIR context. MLIRContext &LLVMTypeConverter::getContext() const { … } Type LLVMTypeConverter::getIndexType() const { … } unsigned LLVMTypeConverter::getPointerBitwidth(unsigned addressSpace) const { … } Type LLVMTypeConverter::convertIndexType(IndexType type) const { … } Type LLVMTypeConverter::convertIntegerType(IntegerType type) const { … } Type LLVMTypeConverter::convertFloatType(FloatType type) const { … } // Convert a `ComplexType` to an LLVM type. The result is a complex number // struct with entries for the // 1. real part and for the // 2. imaginary part. Type LLVMTypeConverter::convertComplexType(ComplexType type) const { … } // Except for signatures, MLIR function types are converted into LLVM // pointer-to-function types. Type LLVMTypeConverter::convertFunctionType(FunctionType type) const { … } /// Returns the `llvm.byval` or `llvm.byref` attributes that are present in the /// function arguments. Returns an empty container if none of these attributes /// are found in any of the arguments. static void filterByValRefArgAttrs(FunctionOpInterface funcOp, SmallVectorImpl<std::optional<NamedAttribute>> &result) { … } // Function types are converted to LLVM Function types by recursively converting // argument and result types. If MLIR Function has zero results, the LLVM // Function has one VoidType result. If MLIR Function has more than one result, // they are into an LLVM StructType in their order of appearance. // If `byValRefNonPtrAttrs` is provided, converted types of `llvm.byval` and // `llvm.byref` function arguments which are not LLVM pointers are overridden // with LLVM pointers. `llvm.byval` and `llvm.byref` arguments that were already // converted to LLVM pointer types are removed from 'byValRefNonPtrAttrs`. Type LLVMTypeConverter::convertFunctionSignatureImpl( FunctionType funcTy, bool isVariadic, bool useBarePtrCallConv, LLVMTypeConverter::SignatureConversion &result, SmallVectorImpl<std::optional<NamedAttribute>> *byValRefNonPtrAttrs) const { … } Type LLVMTypeConverter::convertFunctionSignature( FunctionType funcTy, bool isVariadic, bool useBarePtrCallConv, LLVMTypeConverter::SignatureConversion &result) const { … } Type LLVMTypeConverter::convertFunctionSignature( FunctionOpInterface funcOp, bool isVariadic, bool useBarePtrCallConv, LLVMTypeConverter::SignatureConversion &result, SmallVectorImpl<std::optional<NamedAttribute>> &byValRefNonPtrAttrs) const { … } /// Converts the function type to a C-compatible format, in particular using /// pointers to memref descriptors for arguments. std::pair<LLVM::LLVMFunctionType, LLVM::LLVMStructType> LLVMTypeConverter::convertFunctionTypeCWrapper(FunctionType type) const { … } /// Convert a memref type into a list of LLVM IR types that will form the /// memref descriptor. The result contains the following types: /// 1. The pointer to the allocated data buffer, followed by /// 2. The pointer to the aligned data buffer, followed by /// 3. A lowered `index`-type integer containing the distance between the /// beginning of the buffer and the first element to be accessed through the /// view, followed by /// 4. An array containing as many `index`-type integers as the rank of the /// MemRef: the array represents the size, in number of elements, of the memref /// along the given dimension. For constant MemRef dimensions, the /// corresponding size entry is a constant whose runtime value must match the /// static value, followed by /// 5. A second array containing as many `index`-type integers as the rank of /// the MemRef: the second array represents the "stride" (in tensor abstraction /// sense), i.e. the number of consecutive elements of the underlying buffer. /// TODO: add assertions for the static cases. /// /// If `unpackAggregates` is set to true, the arrays described in (4) and (5) /// are expanded into individual index-type elements. /// /// template <typename Elem, typename Index, size_t Rank> /// struct { /// Elem *allocatedPtr; /// Elem *alignedPtr; /// Index offset; /// Index sizes[Rank]; // omitted when rank == 0 /// Index strides[Rank]; // omitted when rank == 0 /// }; SmallVector<Type, 5> LLVMTypeConverter::getMemRefDescriptorFields(MemRefType type, bool unpackAggregates) const { … } unsigned LLVMTypeConverter::getMemRefDescriptorSize(MemRefType type, const DataLayout &layout) const { … } /// Converts MemRefType to LLVMType. A MemRefType is converted to a struct that /// packs the descriptor fields as defined by `getMemRefDescriptorFields`. Type LLVMTypeConverter::convertMemRefType(MemRefType type) const { … } /// Convert an unranked memref type into a list of non-aggregate LLVM IR types /// that will form the unranked memref descriptor. In particular, the fields /// for an unranked memref descriptor are: /// 1. index-typed rank, the dynamic rank of this MemRef /// 2. void* ptr, pointer to the static ranked MemRef descriptor. This will be /// stack allocated (alloca) copy of a MemRef descriptor that got casted to /// be unranked. SmallVector<Type, 2> LLVMTypeConverter::getUnrankedMemRefDescriptorFields() const { … } unsigned LLVMTypeConverter::getUnrankedMemRefDescriptorSize( UnrankedMemRefType type, const DataLayout &layout) const { … } Type LLVMTypeConverter::convertUnrankedMemRefType( UnrankedMemRefType type) const { … } FailureOr<unsigned> LLVMTypeConverter::getMemRefAddressSpace(BaseMemRefType type) const { … } // Check if a memref type can be converted to a bare pointer. bool LLVMTypeConverter::canConvertToBarePtr(BaseMemRefType type) { … } /// Convert a memref type to a bare pointer to the memref element type. Type LLVMTypeConverter::convertMemRefToBarePtr(BaseMemRefType type) const { … } /// Convert an n-D vector type to an LLVM vector type: /// * 0-D `vector<T>` are converted to vector<1xT> /// * 1-D `vector<axT>` remains as is while, /// * n>1 `vector<ax...xkxT>` convert via an (n-1)-D array type to /// `!llvm.array<ax...array<jxvector<kxT>>>`. /// As LLVM supports arrays of scalable vectors, this method will also convert /// n-D scalable vectors provided that only the trailing dim is scalable. FailureOr<Type> LLVMTypeConverter::convertVectorType(VectorType type) const { … } /// Convert a type in the context of the default or bare pointer calling /// convention. Calling convention sensitive types, such as MemRefType and /// UnrankedMemRefType, are converted following the specific rules for the /// calling convention. Calling convention independent types are converted /// following the default LLVM type conversions. Type LLVMTypeConverter::convertCallingConventionType( Type type, bool useBarePtrCallConv) const { … } /// Promote the bare pointers in 'values' that resulted from memrefs to /// descriptors. 'stdTypes' holds they types of 'values' before the conversion /// to the LLVM-IR dialect (i.e., MemRefType, or any other builtin type). void LLVMTypeConverter::promoteBarePtrsToDescriptors( ConversionPatternRewriter &rewriter, Location loc, ArrayRef<Type> stdTypes, SmallVectorImpl<Value> &values) const { … } /// Convert a non-empty list of types of values produced by an operation into an /// LLVM-compatible type. In particular, if more than one value is /// produced, create a literal structure with elements that correspond to each /// of the types converted with `convertType`. Type LLVMTypeConverter::packOperationResults(TypeRange types) const { … } /// Convert a non-empty list of types to be returned from a function into an /// LLVM-compatible type. In particular, if more than one value is returned, /// create an LLVM dialect structure type with elements that correspond to each /// of the types converted with `convertCallingConventionType`. Type LLVMTypeConverter::packFunctionResults(TypeRange types, bool useBarePtrCallConv) const { … } Value LLVMTypeConverter::promoteOneMemRefDescriptor(Location loc, Value operand, OpBuilder &builder) const { … } SmallVector<Value, 4> LLVMTypeConverter::promoteOperands(Location loc, ValueRange opOperands, ValueRange operands, OpBuilder &builder, bool useBarePtrCallConv) const { … } /// Callback to convert function argument types. It converts a MemRef function /// argument to a list of non-aggregate types containing descriptor /// information, and an UnrankedmemRef function argument to a list containing /// the rank and a pointer to a descriptor struct. LogicalResult mlir::structFuncArgTypeConverter(const LLVMTypeConverter &converter, Type type, SmallVectorImpl<Type> &result) { … } /// Callback to convert function argument types. It converts MemRef function /// arguments to bare pointers to the MemRef element type. LogicalResult mlir::barePtrFuncArgTypeConverter(const LLVMTypeConverter &converter, Type type, SmallVectorImpl<Type> &result) { … }