Files
gps/tools/local/circt/include/mlir/Dialect/SPIRV/IR/SPIRVIntelExtOps.td
T
2026-07-12 11:01:51 +03:00

390 lines
12 KiB
TableGen

//===- SPIRVIntelExtOps.td - Intel SPIR-V extensions ---------------*- 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
//
//===----------------------------------------------------------------------===//
//
// This is the op definition spec of Intel-specific SPIR-V extensions
// These extensions are not part of Khronos specification but publicly available
// at (https://github.com/intel/llvm)
// Supported extensions
// * SPV_INTEL_bfloat16_conversion
// * SPV_INTEL_tensor_float32_conversion
//===----------------------------------------------------------------------===//
#ifndef MLIR_DIALECT_SPIRV_IR_INTEL_EXT_OPS
#define MLIR_DIALECT_SPIRV_IR_INTEL_EXT_OPS
// -----
def SPIRV_INTELConvertFToBF16Op : SPIRV_IntelVendorOp<"ConvertFToBF16", [SameOperandsAndResultShape]> {
let summary = "See extension SPV_INTEL_bfloat16_conversion";
let description = [{
Convert value numerically from 32-bit floating point to bfloat16,
which is represented as a 16-bit unsigned integer.
Result Type must be a scalar or vector of integer type.
The component width must be 16 bits. Bit pattern in the Result represents a bfloat16 value.
Float Value must be a scalar or vector of floating-point type.
It must have the same number of components as Result Type. The component width must be 32 bits.
Results are computed per component.
#### Example:
```mlir
%1 = spirv.ConvertFToBF16 %0 : f32 to i16
%3 = spirv.ConvertFToBF16 %2 : vector<3xf32> to vector<3xi16>
```
}];
let availability = [
MinVersion<SPIRV_V_1_0>,
MaxVersion<SPIRV_V_1_6>,
Extension<[SPV_INTEL_bfloat16_conversion]>,
Capability<[SPIRV_C_Bfloat16ConversionINTEL]>
];
let arguments = (ins
SPIRV_ScalarOrVectorOf<SPIRV_Float32>:$operand
);
let results = (outs
SPIRV_ScalarOrVectorOf<SPIRV_Int16>:$result
);
let assemblyFormat = [{
$operand attr-dict `:` type($operand) `to` type($result)
}];
let hasVerifier = 0;
}
// -----
def SPIRV_INTELConvertBF16ToFOp : SPIRV_IntelVendorOp<"ConvertBF16ToF", [SameOperandsAndResultShape]> {
let summary = "See extension SPV_INTEL_bfloat16_conversion";
let description = [{
Interpret a 16-bit integer as bfloat16 and convert the value numerically to 32-bit floating point type.
Result Type must be a scalar or vector of floating-point. The component width must be 32 bits.
Bfloat16 Value must be a scalar or vector of integer type, which is interpreted as a bfloat16 type.
The type must have the same number of components as the Result Type. The component width must be 16 bits.
Results are computed per component.
#### Example:
```mlir
%1 = spirv.ConvertBF16ToF %0 : i16 to f32
%3 = spirv.ConvertBF16ToF %2 : vector<3xi16> to vector<3xf32>
```
}];
let availability = [
MinVersion<SPIRV_V_1_0>,
MaxVersion<SPIRV_V_1_6>,
Extension<[SPV_INTEL_bfloat16_conversion]>,
Capability<[SPIRV_C_Bfloat16ConversionINTEL]>
];
let arguments = (ins
SPIRV_ScalarOrVectorOf<SPIRV_Int16>:$operand
);
let results = (outs
SPIRV_ScalarOrVectorOf<SPIRV_Float32>:$result
);
let assemblyFormat = [{
$operand attr-dict `:` type($operand) `to` type($result)
}];
let hasVerifier = 0;
}
// -----
def SPIRV_INTELRoundFToTF32Op : SPIRV_IntelVendorOp<"RoundFToTF32", [SameOperandsAndResultShape]> {
let summary = "See extension SPV_INTEL_tensor_float32_conversion";
let description = [{
Convert value numerically from a 32-bit floating point type to tensor float32,
with rounding to the nearest even.
Result Type must be a scalar or vector of 32-bit floating-point type.
The component width must be 32 bits. Bit pattern in the Result represents a tensor float32 value.
Float Value must be a scalar or vector of floating-point type.
It must have the same number of components as Result Type. The component width must be 32 bits.
Results are computed per component.
#### Example:
```mlir
%1 = spirv.RoundFToTF32 %0 : f32 to f32
%3 = spirv.RoundFToTF32 %2 : vector<3xf32> to vector<3xf32>
```
}];
let availability = [
MinVersion<SPIRV_V_1_0>,
MaxVersion<SPIRV_V_1_6>,
Extension<[SPV_INTEL_tensor_float32_conversion]>,
Capability<[SPIRV_C_TensorFloat32RoundingINTEL]>
];
let arguments = (ins
SPIRV_ScalarOrVectorOf<SPIRV_Float32>:$operand
);
let results = (outs
SPIRV_ScalarOrVectorOf<SPIRV_Float32>:$result
);
let assemblyFormat = [{
$operand attr-dict `:` type($operand) `to` type($result)
}];
let hasVerifier = 0;
}
// -----
class SPIRV_IntelSplitBarrierOp<string mnemonic>
: SPIRV_IntelVendorOp<mnemonic, []> {
let availability = [
MinVersion<SPIRV_V_1_0>,
MaxVersion<SPIRV_V_1_6>,
Extension<[SPV_INTEL_split_barrier]>,
Capability<[SPIRV_C_SplitBarrierINTEL]>
];
let arguments = (ins
SPIRV_ScopeAttr:$execution_scope,
SPIRV_ScopeAttr:$memory_scope,
SPIRV_MemorySemanticsAttr:$memory_semantics
);
let results = (outs);
let assemblyFormat = [{
$execution_scope $memory_scope $memory_semantics attr-dict
}];
let hasVerifier = 0;
}
def SPIRV_INTELControlBarrierArriveOp
: SPIRV_IntelSplitBarrierOp<"ControlBarrierArrive"> {
let summary = "See extension SPV_INTEL_split_barrier";
let description = [{
Indicates that an invocation has arrived at a split control barrier. This
may allow other invocations waiting on the split control barrier to continue
executing.
When `Execution` is `Workgroup` or larger, behavior is undefined unless all
invocations within `Execution` execute the same dynamic instance of this
instruction. When `Execution` is `Subgroup` or `Invocation`, the behavior of
this instruction in non-uniform control flow is defined by the client API.
If `Semantics` is not `None`, this instruction also serves as the start of a
memory barrier similar to an `OpMemoryBarrier` instruction with the same
`Memory` and `Semantics` operands. This allows atomically specifying both a
control barrier and a memory barrier (that is, without needing two
instructions). If `Semantics` is `None`, `Memory` is ignored.
#### Example:
```mlir
spirv.ControlBarrierArrive <Workgroup> <Device> <Acquire|UniformMemory>
```
}];
}
// -----
def SPIRV_INTELControlBarrierWaitOp
: SPIRV_IntelSplitBarrierOp<"ControlBarrierWait"> {
let summary = "See extension SPV_INTEL_split_barrier";
let description = [{
Waits for other invocations of this module to arrive at a split control
barrier.
When `Execution` is `Workgroup` or larger, behavior is undefined unless all
invocations within `Execution` execute the same dynamic instance of this
instruction. When `Execution` is `Subgroup` or `Invocation`, the behavior of
this instruction in non-uniform control flow is defined by the client API.
If `Semantics` is not `None`, this instruction also serves as the end of a
memory barrier similar to an `OpMemoryBarrier` instruction with the same
`Memory` and `Semantics` operands. This ensures that memory accesses issued
before arriving at the split barrier are observed before memory accesses
issued after this instruction. This control is ensured only for memory
accesses issued by this invocation and observed by another invocation
executing within `Memory` scope. This allows atomically specifying both a
control barrier and a memory barrier (that is, without needing two
instructions). If `Semantics` is `None`, `Memory` is ignored.
#### Example:
```mlir
spirv.ControlBarrierWait <Workgroup> <Device> <Acquire|UniformMemory>
```
}];
}
// -----
def SPIRV_INTELMaskedGatherOp : SPIRV_IntelVendorOp<"MaskedGather",
[AllTypesMatch<["fill_empty", "result"]>,
TypesMatchWith<"pointee type of ptr_vector must match result element type",
"ptr_vector", "result",
"VectorType::get("
"::llvm::cast<VectorType>($_self).getShape(), "
"::llvm::cast<spirv::PointerType>("
"::llvm::cast<VectorType>($_self).getElementType())"
".getPointeeType())">,
TypesMatchWith<"mask must be a vector of i1 matching result shape",
"result", "mask",
"getMatchingBoolType($_self)">]> {
let summary = "Gather values from memory using a vector of pointers and a mask";
let description = [{
Reads values from a vector of pointers gathering them into a result
vector. Lanes where the mask is false receive the corresponding
FillEmpty value.
Result Type must be a vector of numerical type.
PtrVector must be a vector of pointers to the scalar element type of
Result Type. It must have the same number of components as Result Type.
Alignment is the known minimum alignment in bytes of each pointer in
PtrVector.
Mask must be a vector of boolean type with the same number of components
as Result Type.
FillEmpty must have the same type as Result Type.
#### Example:
```mlir
%result = spirv.INTEL.MaskedGather %ptrs, %alignment, %mask, %fill
: vector<4x!spirv.ptr<f32, CrossWorkgroup>>, i32,
vector<4xi1>, vector<4xf32> -> vector<4xf32>
```
}];
let availability = [
MinVersion<SPIRV_V_1_0>,
MaxVersion<SPIRV_V_1_6>,
Extension<[SPV_INTEL_masked_gather_scatter]>,
Capability<[SPIRV_C_MaskedGatherScatterINTEL]>
];
let arguments = (ins
SPIRV_VectorOf<SPIRV_AnyPtr>:$ptr_vector,
SPIRV_Int32:$alignment,
SPIRV_VectorOf<SPIRV_Bool>:$mask,
SPIRV_VectorOf<SPIRV_Numerical>:$fill_empty
);
let results = (outs
SPIRV_VectorOf<SPIRV_Numerical>:$result
);
let assemblyFormat = [{
$ptr_vector `,` $alignment `,` $mask `,` $fill_empty attr-dict `:`
type($ptr_vector) `,` type($alignment) `,`
type($mask) `,` type($fill_empty) `->` type($result)
}];
let hasVerifier = 0;
}
// -----
def SPIRV_INTELMaskedScatterOp : SPIRV_IntelVendorOp<"MaskedScatter",
[TypesMatchWith<"pointee type of ptr_vector must match input element type",
"ptr_vector", "input_vector",
"VectorType::get("
"::llvm::cast<VectorType>($_self).getShape(), "
"::llvm::cast<spirv::PointerType>("
"::llvm::cast<VectorType>($_self).getElementType())"
".getPointeeType())">,
TypesMatchWith<"mask must be a vector of i1 matching input shape",
"input_vector", "mask",
"getMatchingBoolType($_self)">]> {
let summary = "Scatter values to memory using a vector of pointers and a mask";
let description = [{
Writes values from a vector into memory locations pointed to by a
vector of pointers. Only lanes where the mask is true are written.
PtrVector must be a vector of pointers to the scalar element type of
InputVector. It must have the same number of components as InputVector.
Alignment is the known minimum alignment in bytes of each pointer in
PtrVector.
Mask must be a vector of boolean type with the same number of components
as InputVector.
InputVector is the vector of values to scatter into memory.
#### Example:
```mlir
spirv.INTEL.MaskedScatter %ptrs, %alignment, %mask, %values
: vector<4x!spirv.ptr<f32, CrossWorkgroup>>, i32,
vector<4xi1>, vector<4xf32>
```
}];
let availability = [
MinVersion<SPIRV_V_1_0>,
MaxVersion<SPIRV_V_1_6>,
Extension<[SPV_INTEL_masked_gather_scatter]>,
Capability<[SPIRV_C_MaskedGatherScatterINTEL]>
];
let arguments = (ins
SPIRV_VectorOf<SPIRV_AnyPtr>:$ptr_vector,
SPIRV_Int32:$alignment,
SPIRV_VectorOf<SPIRV_Bool>:$mask,
SPIRV_VectorOf<SPIRV_Numerical>:$input_vector
);
let results = (outs);
let assemblyFormat = [{
$ptr_vector `,` $alignment `,` $mask `,` $input_vector attr-dict `:`
type($ptr_vector) `,` type($alignment) `,`
type($mask) `,` type($input_vector)
}];
let hasVerifier = 0;
}
// -----
#endif // MLIR_DIALECT_SPIRV_IR_INTEL_EXT_OPS