blob: 0ca0f9e22191e9b8eee520874ab56ca5e6cd3c3e [file] [log] [blame]
//===- DataLayoutInterfaces.td - Data layout interfaces ----*- tablegen -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// Defines the interfaces for the data layout specification, operations to which
// they can be attached, and types that are subject to data layout.
//
//===----------------------------------------------------------------------===//
#ifndef MLIR_DATALAYOUTINTERFACES
#define MLIR_DATALAYOUTINTERFACES
include "mlir/IR/OpBase.td"
//===----------------------------------------------------------------------===//
// Attribute interfaces
//===----------------------------------------------------------------------===//
def DataLayoutEntryInterface : AttrInterface<"DataLayoutEntryInterface"> {
let cppNamespace = "::mlir";
let description = [{
Attribute interface describing an entry in a data layout specification.
A data layout specification entry is a key-value pair. Its key is either a
type, when the entry is related to a type or a class of types, or an
identifier, when it is not. `DataLayoutEntryKey` is an alias allowing one
to use both key types. Its value is an arbitrary attribute that is
interpreted either by the type for type keys or by the dialect containing
the identifier for identifier keys. The interface provides a hook that
can be used by specific implementations to delegate the verification of
attribute fitness for a particular key to the relevant type or dialect.
}];
let methods = [
InterfaceMethod<
/*description=*/"Returns the key of the this layout entry.",
/*retTy=*/"::mlir::DataLayoutEntryKey",
/*methodName=*/"getKey",
/*args=*/(ins)
>,
InterfaceMethod<
/*description=*/"Returns the value of this layout entry.",
/*retTy=*/"::mlir::Attribute",
/*methodName=*/"getValue",
/*args=*/(ins)
>,
InterfaceMethod<
/*description=*/"Checks that the entry is well-formed, reports errors "
"at the provided location.",
/*retTy=*/"::mlir::LogicalResult",
/*methodName=*/"verifyEntry",
/*args=*/(ins "::mlir::Location":$loc),
/*methodBody=*/"",
/*defaultImplementation=*/[{ return ::mlir::success(); }]
>
];
let extraClassDeclaration = [{
/// Returns `true` if the key of this entry is a type.
bool isTypeEntry() {
return getKey().is<::mlir::Type>();
}
}];
}
def DataLayoutSpecInterface : AttrInterface<"DataLayoutSpecInterface"> {
let cppNamespace = "::mlir";
let description = [{
Attribute interface describing a data layout specification.
A data layout specification is seen as a sequence of entries, each of which
is an attribute implementing the data layout entry interface. It assumes
a contiguous underlying storage for entries. The interface provides a hook
for implementations to verify the well-formedness of the specification,
with a default implementation that verifies the absence of entries with
duplicate keys and the well-formedness of each individual entry before
dispatching to the type or dialect the entry is associated with.
Data layout specifications may need to be combined in case they appear on
nested operations subject to layout, or to ensure the validity of layout
modification. Concrete specification attributes must implement the
corresponding hook.
}];
// The underlying storage being contiguous may be revised in the future, but
// care must be taken to avoid materializing or copying the entire list of
// entries.
let methods = [
InterfaceMethod<
/*description=*/"Combines the current layout with the given list of "
"layouts, provided from the outermost (oldest) to the "
"innermost (newest). Returns null on failure.",
/*retTy=*/"::mlir::DataLayoutSpecInterface",
/*methodName=*/"combineWith",
/*args=*/(ins "::llvm::ArrayRef<::mlir::DataLayoutSpecInterface>":$specs)
>,
InterfaceMethod<
/*description=*/"Returns the list of layout entries.",
/*retTy=*/"::mlir::DataLayoutEntryListRef",
/*methodName=*/"getEntries",
/*args=*/(ins)
>,
// Implementations may override this if they have an efficient lookup
// mechanism.
InterfaceMethod<
/*description=*/"Returns a copy of the entries related to a specific "
"type class regardles of type parameters. ",
/*retTy=*/"::mlir::DataLayoutEntryList",
/*methodName=*/"getSpecForType",
/*args=*/(ins "::mlir::TypeID":$type),
/*methodBody=*/"",
/*defaultImplementation=*/[{
return ::mlir::detail::filterEntriesForType($_attr.getEntries(), type);
}]
>,
// Implementations may override this if they have an efficient lookup
// mechanism.
InterfaceMethod<
/*description=*/"Returns the entry related to the given identifier, if "
"present.",
/*retTy=*/"::mlir::DataLayoutEntryInterface",
/*methodName=*/"getSpecForIdentifier",
/*args=*/(ins "::mlir::StringAttr":$identifier),
/*methodBody=*/"",
/*defaultImplementation=*/[{
return ::mlir::detail::filterEntryForIdentifier($_attr.getEntries(),
identifier);
}]
>,
InterfaceMethod<
/*description=*/"Verifies the validity of the specification and reports "
"any errors at the given location.",
/*retTy=*/"::mlir::LogicalResult",
/*methodName=*/"verifySpec",
/*args=*/(ins "::mlir::Location":$loc),
/*methodBody=*/"",
/*defaultImplementation=*/[{
return ::mlir::detail::verifyDataLayoutSpec($_attr, loc);
}]
>,
];
let extraClassDeclaration = [{
/// Returns a copy of the entries related to the type specified as template
/// parameter.
template <typename Ty>
DataLayoutEntryList getSpecForType() {
return getSpecForType(TypeID::get<Ty>());
}
/// Populates the given maps with lists of entries grouped by the type or
/// identifier they are associated with. Users are not expected to call this
/// method directly.
void bucketEntriesByType(
::llvm::DenseMap<::mlir::TypeID, ::mlir::DataLayoutEntryList> &types,
::llvm::DenseMap<::mlir::StringAttr,
::mlir::DataLayoutEntryInterface> &ids);
}];
}
//===----------------------------------------------------------------------===//
// Operation interface
//===----------------------------------------------------------------------===//
def DataLayoutOpInterface : OpInterface<"DataLayoutOpInterface"> {
let cppNamespace = "::mlir";
let description = [{
Interface for operations that can have a data layout specification attached.
The `DataLayout` object, which can be used for data layout queries, can be
constructed for such operations. The absence of a data layout specification
must be handled without failing.
Concrete operations must implement the hook returning the data layout
specification. They may optionally override the methods used in data layout
queries, default implementations of which provide predefined answers for
built-in types and dispatch to the type interface for all other types. These
methods must be idempotent, that is return the same result on repeated
queries with the same parameters. They are declared static and therefore
have no access to the operation or its attributes. Instead, they receive a
list of data layout entries relevant to the request. The entries are known
to have passed the spec and entry verifier.
}];
let methods = [
InterfaceMethod<
/*description=*/"Returns the data layout specification for this op, or "
"null if it does not exist.",
/*retTy=*/"::mlir::DataLayoutSpecInterface",
/*methodName=*/"getDataLayoutSpec",
/*args=*/(ins)
>,
StaticInterfaceMethod<
/*description=*/"Returns the size of the given type computed using the "
"relevant entries. The data layout object can be used "
"for recursive queries.",
/*retTy=*/"unsigned",
/*methodName=*/"getTypeSize",
/*args=*/(ins "::mlir::Type":$type,
"const ::mlir::DataLayout &":$dataLayout,
"::mlir::DataLayoutEntryListRef":$params),
/*methodBody=*/"",
/*defaultImplementation=*/[{
unsigned bits = ConcreteOp::getTypeSizeInBits(type, dataLayout, params);
return ::llvm::divideCeil(bits, 8);
}]
>,
StaticInterfaceMethod<
/*description=*/"Returns the size of the given type in bits computed "
"using the relevant entries. The data layout object can "
"be used for recursive queries.",
/*retTy=*/"unsigned",
/*methodName=*/"getTypeSizeInBits",
/*args=*/(ins "::mlir::Type":$type,
"const ::mlir::DataLayout &":$dataLayout,
"::mlir::DataLayoutEntryListRef":$params),
/*methodBody=*/"",
/*defaultImplementation=*/[{
return ::mlir::detail::getDefaultTypeSizeInBits(type, dataLayout,
params);
}]
>,
StaticInterfaceMethod<
/*description=*/"Returns the alignment required by the ABI for the given "
"type computed using the relevant entries. The data "
"layout object can be used for recursive queries.",
/*retTy=*/"unsigned",
/*methodName=*/"getTypeABIAlignment",
/*args=*/(ins "::mlir::Type":$type,
"const ::mlir::DataLayout &":$dataLayout,
"::mlir::DataLayoutEntryListRef":$params),
/*methodBody=*/"",
/*defaultImplementation=*/[{
return ::mlir::detail::getDefaultABIAlignment(type, dataLayout, params);
}]
>,
StaticInterfaceMethod<
/*description=*/"Returns the alignment preferred by the given type "
"computed using the relevant entries. The data layout"
"object can be used for recursive queries.",
/*retTy=*/"unsigned",
/*methodName=*/"getTypePreferredAlignment",
/*args=*/(ins "::mlir::Type":$type,
"const ::mlir::DataLayout &":$dataLayout,
"::mlir::DataLayoutEntryListRef":$params),
/*methodBody=*/"",
/*defaultImplementation=*/[{
return ::mlir::detail::getDefaultPreferredAlignment(type, dataLayout,
params);
}]
>,
];
let verify = [{ return ::mlir::detail::verifyDataLayoutOp($_op); }];
}
//===----------------------------------------------------------------------===//
// Type interface
//===----------------------------------------------------------------------===//
def DataLayoutTypeInterface : TypeInterface<"DataLayoutTypeInterface"> {
let cppNamespace = "::mlir";
let description = [{
Interface for types subject to data layout.
Types willing to be supported by the data layout subsystem should implement
this interface by providing implementations of functions querying their
size, required and preferred alignment. Each of these functions accepts as
arguments a data layout object that can be used to perform recursive queries
in the same scope, and a list of data layout entries relevant to this type.
Specifically, the entries are those that have as key _any instance_ of the
same type class as the current type. For example, if IntegerType had
implemented this interface, it would have received the entries with keys i1,
i2, i8, etc. regardless of the bitwidth of this type. This mechanism allows
types to "interpolate" the results in a type-specific way instead of listing
all possible types in the specification.
The list of entries may be empty, in which case the type must provide a
reasonable default value. The entries in the list are known to have passed
the spec and the entry verifiers, as well as the type-specified verifier if
provided.
In case of nested layout specs or spec changes, the type can override a hook
indicating whether the outer (old) and the inner (new) spec are compatible.
}];
let methods = [
InterfaceMethod<
/*description=*/"Returns the size of this type in bytes.",
/*retTy=*/"unsigned",
/*methodName=*/"getTypeSize",
/*args=*/(ins "const ::mlir::DataLayout &":$dataLayout,
"::mlir::DataLayoutEntryListRef":$params),
/*methodBody=*/"",
/*defaultImplementation=*/[{
unsigned bits = $_type.getTypeSizeInBits(dataLayout, params);
return ::llvm::divideCeil(bits, 8);
}]
>,
InterfaceMethod<
/*description=*/"Returns the size of this type in bits.",
/*retTy=*/"unsigned",
/*methodName=*/"getTypeSizeInBits",
/*args=*/(ins "const ::mlir::DataLayout &":$dataLayout,
"::mlir::DataLayoutEntryListRef":$params)
>,
InterfaceMethod<
/*description=*/"Returns the ABI-required alignment for this type, "
"in bytes",
/*retTy=*/"unsigned",
/*methodName=*/"getABIAlignment",
/*args=*/(ins "const ::mlir::DataLayout &":$dataLayout,
"::mlir::DataLayoutEntryListRef":$params)
>,
InterfaceMethod<
/*description=*/"Returns the preferred alignment for this type, "
"in bytes.",
/*retTy=*/"unsigned",
/*methodName=*/"getPreferredAlignment",
/*args=*/(ins "const ::mlir::DataLayout &":$dataLayout,
"::mlir::DataLayoutEntryListRef":$params)
>,
InterfaceMethod<
/*desc=*/"Returns true if the two lists of entries are compatible, that "
"is, that `newLayout` spec entries can be nested in an op with "
"`oldLayout` spec entries.",
/*retTy=*/"bool",
/*methodName=*/"areCompatible",
/*args=*/(ins "::mlir::DataLayoutEntryListRef":$oldLayout,
"::mlir::DataLayoutEntryListRef":$newLayout),
/*methodBody=*/"",
/*defaultImplementation=*/[{ return true; }]
>,
InterfaceMethod<
/*description=*/"Verifies that the given list of entries is valid for "
"this type.",
/*retTy=*/"::mlir::LogicalResult",
/*methodName=*/"verifyEntries",
/*args=*/(ins "::mlir::DataLayoutEntryListRef":$entries,
"::mlir::Location":$loc),
/*methodBody=*/"",
/*defaultImplementation=*/[{ return ::mlir::success(); }]
>,
];
}
#endif // MLIR_DATALAYOUTINTERFACES