blob: d61387d2b107855c0467801c5d1e3f1efff146df [file]
// Copyright 2019 The IREE Authors
//
// Licensed 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
#ifndef IREE_DIALECT_HAL_BASE
#define IREE_DIALECT_HAL_BASE
include "iree/compiler/Dialect/HAL/IR/HALDialect.td"
include "iree/compiler/Dialect/HAL/IR/HALInterfaces.td"
//===----------------------------------------------------------------------===//
// HAL enums
//===----------------------------------------------------------------------===//
def HAL_MemoryModel_Unified : I32EnumAttrCase<"Unified", 0>;
def HAL_MemoryModel_Discrete : I32EnumAttrCase<"Discrete", 1>;
def HAL_MemoryModelAttr :
I32EnumAttr<"MemoryModel", "IREE HAL MemoryModel", [
HAL_MemoryModel_Unified,
HAL_MemoryModel_Discrete,
]> {
let cppNamespace = "::mlir::iree_compiler::IREE::HAL";
}
def HAL_MemoryType_None : BitEnumAttrCase<"None", 0x0000>; // ?
def HAL_MemoryType_Transient : BitEnumAttrCase<"Transient", 0x0001>; // T
def HAL_MemoryType_HostVisible : BitEnumAttrCase<"HostVisible", 0x0002>; // h
def HAL_MemoryType_HostCoherent : BitEnumAttrCase<"HostCoherent", 0x0004>; // c
def HAL_MemoryType_HostCached : BitEnumAttrCase<"HostCached", 0x0008>; // C
def HAL_MemoryType_HostLocal : BitEnumAttrCase<"HostLocal", 0x0006>; // H
def HAL_MemoryType_DeviceVisible : BitEnumAttrCase<"DeviceVisible", 0x0010>; // d
def HAL_MemoryType_DeviceLocal : BitEnumAttrCase<"DeviceLocal", 0x0030>; // D
def HAL_MemoryTypeBitfieldAttr :
BitEnumAttr<"MemoryTypeBitfield", "valid MemoryType", [
HAL_MemoryType_None,
HAL_MemoryType_Transient,
HAL_MemoryType_HostVisible,
HAL_MemoryType_HostCoherent,
HAL_MemoryType_HostCached,
HAL_MemoryType_HostLocal,
HAL_MemoryType_DeviceVisible,
HAL_MemoryType_DeviceLocal,
]> {
let cppNamespace = "mlir::iree_compiler::IREE::HAL";
}
def HAL_MemoryAccess_None : BitEnumAttrCase<"None", 0x0000>; // ?
def HAL_MemoryAccess_Read : BitEnumAttrCase<"Read", 0x0001>; // R
def HAL_MemoryAccess_Write : BitEnumAttrCase<"Write", 0x0002>; // W
def HAL_MemoryAccess_Discard : BitEnumAttrCase<"Discard", 0x0004>; // D
def HAL_MemoryAccess_DiscardWrite : BitEnumAttrCase<"DiscardWrite", 0x0006>;
def HAL_MemoryAccess_MayAlias : BitEnumAttrCase<"MayAlias", 0x0008>; // A
def HAL_MemoryAccess_All : BitEnumAttrCase<"All", 0x0007>;
def HAL_MemoryAccessBitfieldAttr :
BitEnumAttr<"MemoryAccessBitfield", "valid MemoryAccess", [
HAL_MemoryAccess_None,
HAL_MemoryAccess_Read,
HAL_MemoryAccess_Write,
HAL_MemoryAccess_Discard,
HAL_MemoryAccess_DiscardWrite,
HAL_MemoryAccess_MayAlias,
HAL_MemoryAccess_All,
]> {
let cppNamespace = "mlir::iree_compiler::IREE::HAL";
}
def HAL_BufferUsage_None : BitEnumAttrCase<"None", 0x0000>; // ?
def HAL_BufferUsage_Constant : BitEnumAttrCase<"Constant", 0x0001>; // C
def HAL_BufferUsage_Transfer : BitEnumAttrCase<"Transfer", 0x0002>; // T
def HAL_BufferUsage_Mapping : BitEnumAttrCase<"Mapping", 0x0004>; // M
def HAL_BufferUsage_Dispatch : BitEnumAttrCase<"Dispatch", 0x0008>; // D
def HAL_BufferUsage_All : BitEnumAttrCase<"All", 0x000E>;
def HAL_BufferUsageBitfieldAttr :
BitEnumAttr<"BufferUsageBitfield", "valid BufferUsage", [
HAL_BufferUsage_None,
HAL_BufferUsage_Constant,
HAL_BufferUsage_Transfer,
HAL_BufferUsage_Mapping,
HAL_BufferUsage_Dispatch,
HAL_BufferUsage_All,
]> {
let cppNamespace = "mlir::iree_compiler::IREE::HAL";
}
def HAL_CommandBufferMode_None : BitEnumAttrCase<"None", 0x0000>;
def HAL_CommandBufferMode_OneShot : BitEnumAttrCase<"OneShot", 0x0001>;
def HAL_CommandBufferMode_AllowInlineExecution : BitEnumAttrCase<"AllowInlineExecution", 0x0010>;
def HAL_CommandBufferModeBitfieldAttr :
BitEnumAttr<"CommandBufferModeBitfield", "valid CommandBufferMode", [
HAL_CommandBufferMode_None,
HAL_CommandBufferMode_OneShot,
HAL_CommandBufferMode_AllowInlineExecution,
]> {
let cppNamespace = "mlir::iree_compiler::IREE::HAL";
}
def HAL_CommandCategory_None : BitEnumAttrCase<"None", 0x0000>;
def HAL_CommandCategory_Transfer : BitEnumAttrCase<"Transfer", 0x0001>;
def HAL_CommandCategory_Dispatch : BitEnumAttrCase<"Dispatch", 0x0002>;
def HAL_CommandCategoryBitfieldAttr :
BitEnumAttr<"CommandCategoryBitfield", "valid CommandCategory", [
HAL_CommandCategory_None,
HAL_CommandCategory_Transfer,
HAL_CommandCategory_Dispatch,
]> {
let cppNamespace = "mlir::iree_compiler::IREE::HAL";
}
def HAL_DescriptorType_UniformBuffer : I32EnumAttrCase<"UniformBuffer", 6>;
def HAL_DescriptorType_StorageBuffer : I32EnumAttrCase<"StorageBuffer", 7>;
def HAL_DescriptorType_UniformBufferDynamic : I32EnumAttrCase<"UniformBufferDynamic", 8>;
def HAL_DescriptorType_StorageBufferDynamic : I32EnumAttrCase<"StorageBufferDynamic", 9>;
def HAL_DescriptorTypeAttr :
I32EnumAttr<"DescriptorType", "IREE HAL DescriptorType", [
HAL_DescriptorType_UniformBuffer,
HAL_DescriptorType_StorageBuffer,
HAL_DescriptorType_UniformBufferDynamic,
HAL_DescriptorType_StorageBufferDynamic,
]> {
let cppNamespace = "::mlir::iree_compiler::IREE::HAL";
}
def HAL_DescriptorSetLayoutUsageType_Immutable : I32EnumAttrCase<"Immutable", 0>;
def HAL_DescriptorSetLayoutUsageType_PushOnly : I32EnumAttrCase<"PushOnly", 1>;
def HAL_DescriptorSetLayoutUsageTypeAttr :
I32EnumAttr<"DescriptorSetLayoutUsageType", "IREE HAL DescriptorSetLayoutType", [
HAL_DescriptorSetLayoutUsageType_Immutable,
HAL_DescriptorSetLayoutUsageType_PushOnly,
]> {
let cppNamespace = "::mlir::iree_compiler::IREE::HAL";
}
def HAL_ExecutionStage_None : BitEnumAttrCase<"None", 0x0000>;
def HAL_ExecutionStage_CommandIssue : BitEnumAttrCase<"CommandIssue", 0x0001>;
def HAL_ExecutionStage_CommandProcess : BitEnumAttrCase<"CommandProcess", 0x0002>;
def HAL_ExecutionStage_Dispatch : BitEnumAttrCase<"Dispatch", 0x0004>;
def HAL_ExecutionStage_Transfer : BitEnumAttrCase<"Transfer", 0x0008>;
def HAL_ExecutionStage_CommandRetire : BitEnumAttrCase<"CommandRetire", 0x0010>;
def HAL_ExecutionStage_Host : BitEnumAttrCase<"Host", 0x0020>;
def HAL_ExecutionStageBitfieldAttr :
BitEnumAttr<"ExecutionStageBitfield", "valid ExecutionStage", [
HAL_ExecutionStage_None,
HAL_ExecutionStage_CommandIssue,
HAL_ExecutionStage_CommandProcess,
HAL_ExecutionStage_Dispatch,
HAL_ExecutionStage_Transfer,
HAL_ExecutionStage_CommandRetire,
HAL_ExecutionStage_Host
]> {
let cppNamespace = "mlir::iree_compiler::IREE::HAL";
}
def HAL_ExecutionBarrierFlag_None : BitEnumAttrCase<"None", 0x0000>;
def HAL_ExecutionBarrierFlag_Reserved : BitEnumAttrCase<"Reserved", 0x0001>;
def HAL_ExecutionBarrierFlagBitfieldAttr :
BitEnumAttr<"ExecutionBarrierFlagBitfield", "valid ExecutionBarrierFlag", [
HAL_ExecutionBarrierFlag_None,
HAL_ExecutionBarrierFlag_Reserved,
]> {
let cppNamespace = "mlir::iree_compiler::IREE::HAL";
}
def HAL_AccessScope_None : BitEnumAttrCase<"None", 0x0000>;
def HAL_AccessScope_IndirectCommandRead : BitEnumAttrCase<"IndirectCommandRead", 0x0001>;
def HAL_AccessScope_ConstantRead : BitEnumAttrCase<"ConstantRead", 0x0002>;
def HAL_AccessScope_DispatchRead : BitEnumAttrCase<"DispatchRead", 0x0004>;
def HAL_AccessScope_DispatchWrite : BitEnumAttrCase<"DispatchWrite", 0x0008>;
def HAL_AccessScope_TransferRead : BitEnumAttrCase<"TransferRead", 0x0010>;
def HAL_AccessScope_TransferWrite : BitEnumAttrCase<"TransferWrite", 0x0020>;
def HAL_AccessScope_HostRead : BitEnumAttrCase<"HostRead", 0x0040>;
def HAL_AccessScope_HostWrite : BitEnumAttrCase<"HostWrite", 0x0080>;
def HAL_AccessScope_MemoryRead : BitEnumAttrCase<"MemoryRead", 0x0100>;
def HAL_AccessScope_MemoryWrite : BitEnumAttrCase<"MemoryWrite", 0x0200>;
def HAL_AccessScopeBitfieldAttr :
BitEnumAttr<"AccessScopeBitfield", "valid AccessScope", [
HAL_AccessScope_None,
HAL_AccessScope_IndirectCommandRead,
HAL_AccessScope_ConstantRead,
HAL_AccessScope_DispatchRead,
HAL_AccessScope_DispatchWrite,
HAL_AccessScope_TransferRead,
HAL_AccessScope_TransferWrite,
HAL_AccessScope_HostRead,
HAL_AccessScope_HostWrite,
HAL_AccessScope_MemoryRead,
HAL_AccessScope_MemoryWrite
]> {
let cppNamespace = "mlir::iree_compiler::IREE::HAL";
}
//===----------------------------------------------------------------------===//
// HAL types
//===----------------------------------------------------------------------===//
def HAL_Allocator : DialectType<
HAL_Dialect,
CPred<"$_self.isa<IREE::HAL::AllocatorType>()">,
"allocator"> {
let description = [{
Allocates buffers for a particular device memory space.
}];
let builderCall = "$_builder.getType<IREE::HAL::AllocatorType>()";
}
def HAL_Buffer : DialectType<
HAL_Dialect,
CPred<"$_self.isa<IREE::HAL::BufferType>()">,
"buffer"> {
let description = [{
A memory buffer with a specific memory_type that is used to describe the
capabilities and behavior of the backing memory of the buffer. Buffers may
be any mix of host-accessible, host-coherent, or device-accessible for
various usages. Depending on these memory types the buffers may be mapped
for access on the host as memory though certain restrictions may be imposed.
}];
let builderCall = "$_builder.getType<IREE::HAL::BufferType>()";
}
def HAL_BufferView : DialectType<
HAL_Dialect,
CPred<"$_self.isa<IREE::HAL::BufferViewType>()">,
"buffer_view"> {
let description = [{
A shaped and typed buffer reference. This just wraps an existing hal.buffer
with its associated metadata to make it easier to pass across ABI
boundaries. In most cases buffer views can be elided entirely by the
compiler and they'll only be seen when calling external functions.
}];
let builderCall = "$_builder.getType<IREE::HAL::BufferViewType>()";
}
def HAL_CommandBuffer : DialectType<
HAL_Dialect,
CPred<"$_self.isa<IREE::HAL::CommandBufferType>()">,
"command_buffer"> {
let description = [{
Asynchronous command buffer recording interface. Commands are recorded by
the implementation for later submission to command queues.
}];
let builderCall = "$_builder.getType<IREE::HAL::CommandBufferType>()";
}
def HAL_DescriptorSet : DialectType<
HAL_Dialect,
CPred<"$_self.isa<IREE::HAL::DescriptorSetType>()">,
"descriptor_set"> {
let description = [{
Descriptor set.
}];
let builderCall = "$_builder.getType<IREE::HAL::DescriptorSetType>()";
}
def HAL_DescriptorSetLayout : DialectType<
HAL_Dialect,
CPred<"$_self.isa<IREE::HAL::DescriptorSetLayoutType>()">,
"descriptor_set_layout"> {
let description = [{
Descriptor set layout.
}];
let builderCall = "$_builder.getType<IREE::HAL::DescriptorSetLayoutType>()";
}
def HAL_Device : DialectType<
HAL_Dialect,
CPred<"$_self.isa<IREE::HAL::DeviceType>()">,
"device"> {
let description = [{
Logical device instance.
}];
let builderCall = "$_builder.getType<IREE::HAL::DeviceType>()";
}
def HAL_Event : DialectType<
HAL_Dialect,
CPred<"$_self.isa<IREE::HAL::EventType>()">,
"event"> {
let description = [{
Events are used for defining synchronization scopes within CommandBuffers.
An event only exists within a single CommandBuffer and must not be used
across CommandBuffers from the same device or others.
}];
}
def HAL_Executable : DialectType<
HAL_Dialect,
CPred<"$_self.isa<IREE::HAL::ExecutableType>()">,
"executable"> {
let description = [{
A prepared and ready-to-dispatch executable.
}];
let builderCall = "$_builder.getType<IREE::HAL::ExecutableType>()";
}
def HAL_ExecutableLayout : DialectType<
HAL_Dialect,
CPred<"$_self.isa<IREE::HAL::ExecutableLayoutType>()">,
"executable_layout"> {
let description = [{
An executable layout describing the descriptor sets and push constants used.
}];
let builderCall = "$_builder.getType<IREE::HAL::ExecutableLayoutType>()";
}
def HAL_RingBuffer : DialectType<
HAL_Dialect,
CPred<"$_self.isa<IREE::HAL::RingBufferType>()">,
"ring_buffer"> {
let description = [{
Ringbuffer used for transient buffer allocation.
}];
let builderCall = "$_builder.getType<IREE::HAL::RingBufferType>()";
}
def HAL_Semaphore : DialectType<
HAL_Dialect,
CPred<"$_self.isa<IREE::HAL::SemaphoreType>()">,
"semaphore"> {
let description = [{
Synchronization mechanism for host->device, device->host, host->host,
and device->device notification. Semaphores behave like Vulkan timeline
semaphores (or D3D12 fences) and contain a monotonically increasing
uint64_t payload. They may be waited on any number of times even if they
have already been signaled for a particular value. They may also be waited
on for a particular value prior to the signal for that value.
}];
let builderCall = "$_builder.getType<IREE::HAL::SemaphoreType>()";
}
def HAL_ObjectType : AnyTypeOf<[
HAL_Allocator,
HAL_Buffer,
HAL_BufferView,
HAL_CommandBuffer,
HAL_DescriptorSet,
HAL_DescriptorSetLayout,
HAL_Device,
HAL_Event,
HAL_Executable,
HAL_ExecutableLayout,
HAL_RingBuffer,
HAL_Semaphore,
]>;
def HAL_BufferType : AnyTypeOf<[
HAL_Buffer,
]>;
def HAL_OrdinalAttr : Util_IndexAttrBase<"size_t">;
def HAL_ExecutableDataAttr : SignlessIntElementsAttr<8>;
def HAL_ElementType : TypeAlias<I32>;
def HAL_ElementTypeAttr : SignlessIntegerAttrBase<
I32, "element type attribute">;
def HAL_DeviceSize : TypeAlias<Index>;
def HAL_DeviceSizeAttr : Util_IndexAttrBase<"iree_device_size_t">;
def HAL_DeviceSizes : Variadic<HAL_DeviceSize>;
def HAL_HostSize : TypeAlias<Index>;
def HAL_HostSizeAttr : Util_IndexAttrBase<"size_t">;
def HAL_TimelineValue : TypeAlias<Index>;
def HAL_PrimitiveType : AnyTypeOf<[Index, AnySignlessInteger, AnyFloat]>;
def HAL_VariableRefAttr : AliasedSymbolRefAttr;
def HAL_VariableType : AnyTypeOf<[HAL_PrimitiveType, AnyVector, HAL_ObjectType]>;
def HAL_VariablePtr : PtrOf<HAL_VariableType>;
def HAL_IndexAttr : Util_IndexAttrBase<"index">;
def HAL_IndexArrayAttr : TypedArrayAttrBase<HAL_IndexAttr,
"index array attribute"> {
let constBuilderCall = "$_builder.getIndexArrayAttr($0)";
}
def HAL_Dim : TypeAlias<Index>;
def HAL_Dims : Variadic<HAL_Dim>;
def HAL_Shape : Variadic<HAL_Dim>;
def HAL_ShapeDynamicDims : Variadic<HAL_Dim>;
// TODO(benvanik): assert rank 3
def HAL_WorkgroupSizeAttr : TypedArrayAttrBase<
Util_IndexAttrBase<"size_t">,
"index array attribute"> {
let constBuilderCall = "$_builder.getIndexArrayAttr($0)";
}
def HAL_CommandQueueAffinityAttr : SignlessIntElementsAttr<32> {
// TODO(b/143184519): add typeDescription support to other things.
// let description = [{
// A bitmask defining which queues an operation is allowed to execute on.
// The selection is wrapped to the total number of available queues, so 0b0101
// would enable queues 0 and 2 if there were four queues or queue 0 if there
// were two queues.
// }];
}
def HAL_DurationMillisAttr : SignlessIntElementsAttr<32> {
// TODO(b/143184519): add typeDescription support to other things.
// let description = [{
// A duration to wait in milliseconds. 0 indicates that the operation should
// return immediately without waiting and can be used as a way to poll handles.
// INT32_MAX will wait forever until the handle is signaled.
// }];
}
//===----------------------------------------------------------------------===//
// HAL structs
//===----------------------------------------------------------------------===//
def HAL_BufferConstraintsAttr :
Util_StructAttr<"buffer_constraints", "BufferConstraintsAttr", HAL_Dialect, [
// The maximum size of a memory allocation that can be created, even if
// there is more space available in the heap.
Util_StructFieldAttr<"max_allocation_size", HAL_DeviceSizeAttr>,
// The minimum required alignment, in bytes, for offsets used in runtime
// buffer bindings for target backends. Offset values (both dynamic and
// static) must be an integer multiple of this limit.
Util_StructFieldAttr<"min_buffer_offset_alignment", HAL_DeviceSizeAttr>,
// The maximum value that can be specified for size ranges of buffer
// bindings. The underlying allocation may be larger than this but only
// up to this amount will be visible to kernels.
Util_StructFieldAttr<"max_buffer_range", HAL_DeviceSizeAttr>,
// The minimum required alignment, in bytes, for size ranges of buffer
// bindings.
Util_StructFieldAttr<"min_buffer_range_alignment", HAL_DeviceSizeAttr>,
]> {
let cppNamespace = "mlir::iree_compiler::IREE::HAL";
}
def HAL_ByteRangeAttr :
Util_StructAttr<"byte_range", "ByteRangeAttr", HAL_Dialect, [
Util_StructFieldAttr<"offset", HAL_DeviceSizeAttr>,
Util_StructFieldAttr<"length", HAL_DeviceSizeAttr>,
]> {
let cppNamespace = "mlir::iree_compiler::IREE::HAL";
}
def HAL_DescriptorSetLayoutBindingAttr :
Util_StructAttr<"descriptor_set_layout_binding",
"DescriptorSetLayoutBindingAttr",
HAL_Dialect, [
Util_StructFieldAttr<"binding", I32Attr>,
Util_StructFieldAttr<"type", HAL_DescriptorTypeAttr>,
Util_StructFieldAttr<"access", HAL_MemoryAccessBitfieldAttr>,
]> {
let cppNamespace = "mlir::iree_compiler::IREE::HAL";
}
def HAL_DescriptorSetLayoutBindingArrayAttr : TypedArrayAttrBase<
HAL_DescriptorSetLayoutBindingAttr,
"HAL descriptor set layout binding array attribute">;
//===----------------------------------------------------------------------===//
// Device and executable target specification
//===----------------------------------------------------------------------===//
def HAL_DeviceTargetAttr :
AttrDef<HAL_Dialect, "DeviceTarget", []> {
let mnemonic = "device.target";
let summary = [{generic device target specification}];
let description = [{
Specifies the properties of a target runtime device.
Target devices are specified with a canonical identifier matching those used
by the runtime (such as `cpu`, `vulkan`, etc). Target devices may support
several target executable formats specified with `#hal.executable.target`.
An optional configuration dictionary allows for overriding backend defaults.
Example:
```mlir
#hal.device.target<"cpu", {
executable_targets = [
#hal.executable.target<"llvm", "embedded-elf-arm_32">,
#hal.executable.target<"llvm", "embedded-elf-arm_64">,
]
}>
```
}];
let parameters = (ins
AttrParameter<"StringAttr", "">:$deviceID,
AttrParameter<"DictionaryAttr", "">:$configuration
);
let builders = [
AttrBuilder<(ins "StringRef":$deviceID)>,
];
let extraClassDeclaration = [{
// Returns a symbol-compatible name that pseudo-uniquely identifies this
// target. Callers must perform deduplication when required.
std::string getSymbolNameFragment();
// Returns a hal.match.* expression tree that specifically matches this
// target device.
Attribute getMatchExpression();
// Returns the constraints defining buffer allocation and usage allowed on
// the device or the host defaults if none are defined.
BufferConstraintsAttr getBufferConstraints();
// Returns zero or more executable targets that this device supports.
SmallVector<ExecutableTargetAttr, 4> getExecutableTargets();
// Returns a list of target devices that may be active for the given
// operation. This will recursively walk parent operations until one with
// the `hal.device.targets` attribute is found.
static SmallVector<DeviceTargetAttr, 4> lookup(Operation *op);
// Returns a set of buffer constraints compatible with the host.
// These must only be used with device buffers when it is known that the
// device is local.
static BufferConstraintsAttr
getDefaultHostBufferConstraints(MLIRContext *context);
// Tries to find the min/max constraints on buffers across all target
// devices applicable to the given operation. If no target device specifies
// constraints then a generally acceptable default set with minimums will be
// returned.
//
// This can result in non-optimal constraints when multi-targeting wildly
// different device types and should only be used as a fallback.
static BufferConstraintsAttr
lookupConservativeBufferConstraints(Operation *op);
// Returns a list of all target executable configurations that may be
// required for the given operation.
static SmallVector<ExecutableTargetAttr, 4>
lookupExecutableTargets(Operation *op);
}];
}
def HAL_ExecutableTargetAttr :
AttrDef<HAL_Dialect, "ExecutableTarget", []> {
let mnemonic = "executable.target";
let summary = [{generic executable target specification}];
let description = [{
Specifies how to compile an executable for a specific target backend.
A backend is used to translate and serialize the executable into the final
form passed to the runtime. The format of the executable is a
target-specific value indicating the required runtime support to load the
deployed artifact. An optionally provided configuration dictionary overrides
backend-specific defaults.
Example:
```mlir
// Produce a system-native ELF for x86-64 systems using the LLVM backend:
#hal.executable.target<"llvm", "system-elf-x86_64", {
triple = "x86_64-unknown-linux-elf",
cpu = "host",
cpu_features = "host",
abi = "lp32",
...
}>
```
The same compilation backend may be used to translate executables for
several different runtime devices. Likewise the same runtime device may use
one of many different executable targets. Assume an N:M mapping between the
two in all cases.
}];
let parameters = (ins
AttrParameter<"StringAttr", "">:$backend,
AttrParameter<"StringAttr", "">:$format,
AttrParameter<"DictionaryAttr", "">:$configuration
);
let builders = [
AttrBuilder<(ins "StringRef":$backend, "StringRef":$format)>,
];
let extraClassDeclaration = [{
// Returns a symbol-compatible name that pseudo-uniquely identifies this
// target. Callers must perform deduplication when required.
std::string getSymbolNameFragment();
// Returns a hal.match.* expression tree that specifically matches a
// device that can load an executable of this target.
Attribute getMatchExpression();
}];
}
//===----------------------------------------------------------------------===//
// Experimental binding metadata
//===----------------------------------------------------------------------===//
// TODO(benvanik): drop this when we have a HAL dispatch abstraction.
def HAL_ExConstantStorageAttr :
Util_StructAttr<"ex.constant_storage",
"ExConstantStorageAttr",
HAL_Dialect, [
Util_StructFieldAttr<"binding", StrAttr>,
Util_StructFieldAttr<"storage", StrAttr>,
Util_StructFieldAttr<"offset", IndexAttr>,
Util_StructFieldAttr<"length", IndexAttr>,
]> {
let cppNamespace = "mlir::iree_compiler::IREE::HAL";
}
def HAL_ExPushConstantAttr :
Util_StructAttr<"ex.push_constant",
"ExPushConstantAttr",
HAL_Dialect, [
Util_StructFieldAttr<"ordinal", IndexAttr>,
Util_StructFieldAttr<"operand", IndexAttr>,
]> {
let cppNamespace = "mlir::iree_compiler::IREE::HAL";
}
def HAL_ExOperandBufferAttr :
Util_StructAttr<"ex.operand_buffer",
"ExOperandBufferAttr",
HAL_Dialect, [
Util_StructFieldAttr<"binding", StrAttr>,
Util_StructFieldAttr<"operand", IndexAttr>,
]> {
let cppNamespace = "mlir::iree_compiler::IREE::HAL";
}
def HAL_ExResultBufferAttr :
Util_StructAttr<"ex.result_buffer",
"ExResultBufferAttr",
HAL_Dialect, [
Util_StructFieldAttr<"binding", StrAttr>,
Util_StructFieldAttr<"result", IndexAttr>,
]> {
let cppNamespace = "mlir::iree_compiler::IREE::HAL";
}
//===----------------------------------------------------------------------===//
// Expression matching attributes
//===----------------------------------------------------------------------===//
def HAL_DeviceQuery : NativeOpTrait<"IREE::HAL::DeviceQuery">;
def HAL_MatchAlwaysAttr :
AttrDef<HAL_Dialect, "MatchAlways", [
DeclareAttrInterfaceMethods<HAL_MatchAttrInterface>,
]> {
let mnemonic = "match.always";
let summary = [{always matches}];
let description = [{
Returns true (constant true).
}];
}
def HAL_MatchAnyAttr :
AttrDef<HAL_Dialect, "MatchAny", [
DeclareAttrInterfaceMethods<HAL_MatchAttrInterface>,
]> {
let mnemonic = "match.any";
let summary = [{matches if any subexpression matches}];
let description = [{
Returns true if any subexpression matches (logical OR) and not empty.
}];
let parameters = (ins
AttrParameter<"ArrayAttr", "">:$conditions
);
let builders = [
AttrBuilder<(ins "ArrayRef<Attribute>":$conditions), [{
return $_get(context, ArrayAttr::get(context, conditions));
}]>,
];
}
def HAL_MatchAllAttr :
AttrDef<HAL_Dialect, "MatchAll", [
DeclareAttrInterfaceMethods<HAL_MatchAttrInterface>,
]> {
let mnemonic = "match.all";
let summary = [{matches if all subexpressions match}];
let description = [{
Returns true only if all subexpressions return true (logical AND) or empty.
}];
let parameters = (ins
AttrParameter<"ArrayAttr", "">:$conditions
);
let builders = [
AttrBuilder<(ins "ArrayRef<Attribute>":$conditions), [{
return $_get(context, ArrayAttr::get(context, conditions));
}]>,
];
}
def HAL_DeviceMatchIDAttr :
AttrDef<HAL_Dialect, "DeviceMatchID", [
DeclareAttrInterfaceMethods<HAL_MatchAttrInterface>,
]> {
let mnemonic = "device.match.id";
let summary = [{matches against a device ID pattern}];
let description = [{
Matches a device by its canonical compiler/runtime ID.
}];
let parameters = (ins
AttrParameter<"StringAttr", "">:$pattern
);
let builders = [
AttrBuilder<(ins "StringRef":$pattern), [{
return $_get(context, StringAttr::get(context, pattern));
}]>,
AttrBuilderWithInferredContext<(ins "StringAttr":$pattern), [{
return $_get(pattern.getContext(), pattern);
}]>,
AttrBuilderWithInferredContext<(ins "IREE::HAL::DeviceTargetAttr":$target), [{
return $_get(target.getContext(), target.getDeviceID());
}]>,
];
}
def HAL_DeviceMatchFeatureAttr :
AttrDef<HAL_Dialect, "DeviceMatchFeature", [
DeclareAttrInterfaceMethods<HAL_MatchAttrInterface>,
]> {
let mnemonic = "device.match.feature";
let summary = [{matches against a supported device feature pattern}];
let description = [{
Matches a device that supports the given feature. The format of the feature
pattern is device-dependent.
}];
let parameters = (ins
AttrParameter<"StringAttr", "">:$pattern
);
let builders = [
AttrBuilder<(ins "StringRef":$pattern), [{
return $_get(context, StringAttr::get(context, pattern));
}]>,
AttrBuilderWithInferredContext<(ins "StringAttr":$pattern), [{
return $_get(pattern.getContext(), pattern);
}]>,
];
}
def HAL_DeviceMatchArchitectureAttr :
AttrDef<HAL_Dialect, "DeviceMatchArchitecture", [
DeclareAttrInterfaceMethods<HAL_MatchAttrInterface>,
]> {
let mnemonic = "device.match.architecture";
let summary = [{matches against a device architecture pattern}];
let description = [{
Matches a device by its runtime architecture. The format of the architecture
pattern is device-dependent.
}];
let parameters = (ins
AttrParameter<"StringAttr", "">:$pattern
);
let builders = [
AttrBuilder<(ins "StringRef":$pattern), [{
return $_get(context, StringAttr::get(context, pattern));
}]>,
AttrBuilderWithInferredContext<(ins "StringAttr":$pattern), [{
return $_get(pattern.getContext(), pattern);
}]>,
];
}
def HAL_DeviceMatchExecutableFormatAttr :
AttrDef<HAL_Dialect, "DeviceMatchExecutableFormat", [
DeclareAttrInterfaceMethods<HAL_MatchAttrInterface>,
]> {
let mnemonic = "device.match.executable.format";
let summary = [{matches when a device supports the given executable format}];
let description = [{
Matches a device only if it claims to support the given executable format
pattern. It's still possible that the executable cannot be loaded such as if
it uses unavailable device features. This is used for queries such as
"can you load ELF libraries?" to quickly get to a set of executables to
attempt without needing to try dozens that definitely cannot be loaded.
Note that different devices may share the same executable formats: for
example a local synchronous CPU executor and a remote asynchronous CPU
executor can both load ELF libraries. It's also possible for the same device
to support multiple formats such as being able to load both
platform-agnostic ELF libraries and platform-specific DLL/MachO/etc
libraries.
}];
let parameters = (ins
AttrParameter<"StringAttr", "">:$pattern
);
let builders = [
AttrBuilder<(ins "StringRef":$pattern), [{
return $_get(context, StringAttr::get(context, pattern));
}]>,
AttrBuilderWithInferredContext<(ins "StringAttr":$pattern), [{
return $_get(pattern.getContext(), pattern);
}]>,
AttrBuilderWithInferredContext<(ins "IREE::HAL::ExecutableTargetAttr":$target), [{
return $_get(target.getContext(), target.getFormat());
}]>,
];
}
//===----------------------------------------------------------------------===//
// Base HAL op classes
//===----------------------------------------------------------------------===//
class HAL_Op<string mnemonic, list<OpTrait> traits = []> :
Op<HAL_Dialect, mnemonic, traits> {
let parser = [{ return parse$cppClass(parser, &result); }];
let printer = [{ return print$cppClass(p, *this); }];
}
#endif // IREE_DIALECT_HAL_BASE