blob: 93733ccd4929ae9048392278740ff26134ce4e88 [file] [log] [blame]
//===- LLVMTypes.h - MLIR LLVM dialect types --------------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// This file defines the types for the LLVM dialect in MLIR. These MLIR types
// correspond to the LLVM IR type system.
//
//===----------------------------------------------------------------------===//
#ifndef MLIR_DIALECT_LLVMIR_LLVMTYPES_H_
#define MLIR_DIALECT_LLVMIR_LLVMTYPES_H_
#include "mlir/IR/Types.h"
#include "mlir/Interfaces/DataLayoutInterfaces.h"
#include "mlir/Interfaces/MemorySlotInterfaces.h"
#include <optional>
namespace llvm {
class ElementCount;
class TypeSize;
} // namespace llvm
namespace mlir {
class AsmParser;
class AsmPrinter;
namespace LLVM {
class LLVMDialect;
namespace detail {
struct LLVMFunctionTypeStorage;
struct LLVMPointerTypeStorage;
struct LLVMStructTypeStorage;
struct LLVMTypeAndSizeStorage;
} // namespace detail
} // namespace LLVM
} // namespace mlir
//===----------------------------------------------------------------------===//
// ODS-Generated Declarations
//===----------------------------------------------------------------------===//
#include "mlir/Dialect/LLVMIR/LLVMTypeInterfaces.h.inc"
#define GET_TYPEDEF_CLASSES
#include "mlir/Dialect/LLVMIR/LLVMTypes.h.inc"
namespace mlir {
namespace LLVM {
//===----------------------------------------------------------------------===//
// Trivial types.
//===----------------------------------------------------------------------===//
// Batch-define trivial types.
#define DEFINE_TRIVIAL_LLVM_TYPE(ClassName, TypeName) \
class ClassName : public Type::TypeBase<ClassName, Type, TypeStorage> { \
public: \
using Base::Base; \
static constexpr StringLiteral name = TypeName; \
}
DEFINE_TRIVIAL_LLVM_TYPE(LLVMVoidType, "llvm.void");
DEFINE_TRIVIAL_LLVM_TYPE(LLVMPPCFP128Type, "llvm.ppc_fp128");
DEFINE_TRIVIAL_LLVM_TYPE(LLVMX86MMXType, "llvm.x86_mmx");
DEFINE_TRIVIAL_LLVM_TYPE(LLVMTokenType, "llvm.token");
DEFINE_TRIVIAL_LLVM_TYPE(LLVMLabelType, "llvm.label");
DEFINE_TRIVIAL_LLVM_TYPE(LLVMMetadataType, "llvm.metadata");
#undef DEFINE_TRIVIAL_LLVM_TYPE
//===----------------------------------------------------------------------===//
// LLVMStructType.
//===----------------------------------------------------------------------===//
/// LLVM dialect structure type representing a collection of different-typed
/// elements manipulated together. Structured can optionally be packed, meaning
/// that their elements immediately follow each other in memory without
/// accounting for potential alignment.
///
/// Structure types can be identified (named) or literal. Literal structures
/// are uniquely represented by the list of types they contain and packedness.
/// Literal structure types are immutable after construction.
///
/// Identified structures are uniquely represented by their name, a string. They
/// have a mutable component, consisting of the list of types they contain,
/// the packedness and the opacity bits. Identified structs can be created
/// without providing the lists of element types, making them suitable to
/// represent recursive, i.e. self-referring, structures. Identified structs
/// without body are considered opaque. For such structs, one can set the body.
/// Identified structs can be created as intentionally-opaque, implying that the
/// caller does not intend to ever set the body (e.g. forward-declarations of
/// structs from another module) and wants to disallow further modification of
/// the body. For intentionally-opaque structs or non-opaque structs with the
/// body, one is not allowed to set another body (however, one can set exactly
/// the same body).
///
/// Note that the packedness of the struct takes place in uniquing of literal
/// structs, but does not in uniquing of identified structs.
class LLVMStructType
: public Type::TypeBase<LLVMStructType, Type, detail::LLVMStructTypeStorage,
DataLayoutTypeInterface::Trait,
DestructurableTypeInterface::Trait,
TypeTrait::IsMutable> {
public:
/// Inherit base constructors.
using Base::Base;
static constexpr StringLiteral name = "llvm.struct";
/// Checks if the given type can be contained in a structure type.
static bool isValidElementType(Type type);
/// Gets or creates an identified struct with the given name in the provided
/// context. Note that unlike llvm::StructType::create, this function will
/// _NOT_ rename a struct in case a struct with the same name already exists
/// in the context. Instead, it will just return the existing struct,
/// similarly to the rest of MLIR type ::get methods.
static LLVMStructType getIdentified(MLIRContext *context, StringRef name);
static LLVMStructType
getIdentifiedChecked(function_ref<InFlightDiagnostic()> emitError,
MLIRContext *context, StringRef name);
/// Gets a new identified struct with the given body. The body _cannot_ be
/// changed later. If a struct with the given name already exists, renames
/// the struct by appending a `.` followed by a number to the name. Renaming
/// happens even if the existing struct has the same body.
static LLVMStructType getNewIdentified(MLIRContext *context, StringRef name,
ArrayRef<Type> elements,
bool isPacked = false);
/// Gets or creates a literal struct with the given body in the provided
/// context.
static LLVMStructType getLiteral(MLIRContext *context, ArrayRef<Type> types,
bool isPacked = false);
static LLVMStructType
getLiteralChecked(function_ref<InFlightDiagnostic()> emitError,
MLIRContext *context, ArrayRef<Type> types,
bool isPacked = false);
/// Gets or creates an intentionally-opaque identified struct. Such a struct
/// cannot have its body set. To create an opaque struct with a mutable body,
/// use `getIdentified`. Note that unlike llvm::StructType::create, this
/// function will _NOT_ rename a struct in case a struct with the same name
/// already exists in the context. Instead, it will just return the existing
/// struct, similarly to the rest of MLIR type ::get methods.
static LLVMStructType getOpaque(StringRef name, MLIRContext *context);
static LLVMStructType
getOpaqueChecked(function_ref<InFlightDiagnostic()> emitError,
MLIRContext *context, StringRef name);
/// Set the body of an identified struct. Returns failure if the body could
/// not be set, e.g. if the struct already has a body or if it was marked as
/// intentionally opaque. This might happen in a multi-threaded context when a
/// different thread modified the struct after it was created. Most callers
/// are likely to assert this always succeeds, but it is possible to implement
/// a local renaming scheme based on the result of this call.
LogicalResult setBody(ArrayRef<Type> types, bool isPacked);
/// Checks if a struct is packed.
bool isPacked() const;
/// Checks if a struct is identified.
bool isIdentified() const;
/// Checks if a struct is opaque.
bool isOpaque();
/// Checks if a struct is initialized.
bool isInitialized();
/// Returns the name of an identified struct.
StringRef getName();
/// Returns the list of element types contained in a non-opaque struct.
ArrayRef<Type> getBody() const;
/// Verifies that the type about to be constructed is well-formed.
static LogicalResult verify(function_ref<InFlightDiagnostic()> emitError,
StringRef, bool);
static LogicalResult verify(function_ref<InFlightDiagnostic()> emitError,
ArrayRef<Type> types, bool);
using Base::verify;
/// Hooks for DataLayoutTypeInterface. Should not be called directly. Obtain a
/// DataLayout instance and query it instead.
llvm::TypeSize getTypeSizeInBits(const DataLayout &dataLayout,
DataLayoutEntryListRef params) const;
uint64_t getABIAlignment(const DataLayout &dataLayout,
DataLayoutEntryListRef params) const;
uint64_t getPreferredAlignment(const DataLayout &dataLayout,
DataLayoutEntryListRef params) const;
bool areCompatible(DataLayoutEntryListRef oldLayout,
DataLayoutEntryListRef newLayout) const;
LogicalResult verifyEntries(DataLayoutEntryListRef entries,
Location loc) const;
/// Destructs the struct into its indexed field types.
std::optional<DenseMap<Attribute, Type>> getSubelementIndexMap();
/// Returns which type is stored at a given integer index within the struct.
Type getTypeAtIndex(Attribute index);
};
//===----------------------------------------------------------------------===//
// Printing and parsing.
//===----------------------------------------------------------------------===//
namespace detail {
/// Parses an LLVM dialect type.
Type parseType(DialectAsmParser &parser);
/// Prints an LLVM Dialect type.
void printType(Type type, AsmPrinter &printer);
} // namespace detail
/// Parse any MLIR type or a concise syntax for LLVM types.
ParseResult parsePrettyLLVMType(AsmParser &p, Type &type);
/// Print any MLIR type or a concise syntax for LLVM types.
void printPrettyLLVMType(AsmPrinter &p, Type type);
//===----------------------------------------------------------------------===//
// Utility functions.
//===----------------------------------------------------------------------===//
/// Returns `true` if the given type is compatible with the LLVM dialect. This
/// is an alias to `LLVMDialect::isCompatibleType`.
bool isCompatibleType(Type type);
/// Returns `true` if the given outer type is compatible with the LLVM dialect
/// without checking its potential nested types such as struct elements.
bool isCompatibleOuterType(Type type);
/// Returns `true` if the given type is a floating-point type compatible with
/// the LLVM dialect.
bool isCompatibleFloatingPointType(Type type);
/// Returns `true` if the given type is a vector type compatible with the LLVM
/// dialect. Compatible types include 1D built-in vector types of built-in
/// integers and floating-point values, LLVM dialect fixed vector types of LLVM
/// dialect pointers and LLVM dialect scalable vector types.
bool isCompatibleVectorType(Type type);
/// Returns the element type of any vector type compatible with the LLVM
/// dialect.
Type getVectorElementType(Type type);
/// Returns the element count of any LLVM-compatible vector type.
llvm::ElementCount getVectorNumElements(Type type);
/// Returns whether a vector type is scalable or not.
bool isScalableVectorType(Type vectorType);
/// Creates an LLVM dialect-compatible vector type with the given element type
/// and length.
Type getVectorType(Type elementType, unsigned numElements,
bool isScalable = false);
/// Creates an LLVM dialect-compatible vector type with the given element type
/// and length.
Type getVectorType(Type elementType, const llvm::ElementCount &numElements);
/// Creates an LLVM dialect-compatible type with the given element type and
/// length.
Type getFixedVectorType(Type elementType, unsigned numElements);
/// Creates an LLVM dialect-compatible type with the given element type and
/// length.
Type getScalableVectorType(Type elementType, unsigned numElements);
/// Returns the size of the given primitive LLVM dialect-compatible type
/// (including vectors) in bits, for example, the size of i16 is 16 and
/// the size of vector<4xi16> is 64. Returns 0 for non-primitive
/// (aggregates such as struct) or types that don't have a size (such as void).
llvm::TypeSize getPrimitiveTypeSizeInBits(Type type);
/// The positions of different values in the data layout entry for pointers.
enum class PtrDLEntryPos { Size = 0, Abi = 1, Preferred = 2, Index = 3 };
/// Returns the value that corresponds to named position `pos` from the
/// data layout entry `attr` assuming it's a dense integer elements attribute.
/// Returns `std::nullopt` if `pos` is not present in the entry.
/// Currently only `PtrDLEntryPos::Index` is optional, and all other positions
/// may be assumed to be present.
std::optional<uint64_t> extractPointerSpecValue(Attribute attr,
PtrDLEntryPos pos);
} // namespace LLVM
} // namespace mlir
#endif // MLIR_DIALECT_LLVMIR_LLVMTYPES_H_