470 lines
14 KiB
TableGen
470 lines
14 KiB
TableGen
//===-- SPIRVBitOps.td - MLIR SPIR-V Bit Ops -*- 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 file contains bit ops for the SPIR-V dialect. It corresponds
|
|
// to "3.32.13. Bit Instructions" of the SPIR-V specification.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef MLIR_DIALECT_SPIRV_IR_BIT_OPS
|
|
#define MLIR_DIALECT_SPIRV_IR_BIT_OPS
|
|
|
|
include "mlir/Dialect/SPIRV/IR/SPIRVBase.td"
|
|
include "mlir/Interfaces/SideEffectInterfaces.td"
|
|
|
|
class SPIRV_BitBinaryOp<string mnemonic, list<Trait> traits = []> :
|
|
// All the operands type used in bit instructions are SPIRV_Integer.
|
|
SPIRV_BinaryOp<mnemonic, SPIRV_Integer, SPIRV_Integer,
|
|
!listconcat(traits,
|
|
[Pure, SameOperandsAndResultType])> {
|
|
let assemblyFormat = "operands attr-dict `:` type($result)";
|
|
}
|
|
|
|
class SPIRV_BitFieldExtractOp<string mnemonic, list<Trait> traits = []> :
|
|
SPIRV_Op<mnemonic, !listconcat(traits,
|
|
[Pure, AllTypesMatch<["base", "result"]>])> {
|
|
let arguments = (ins
|
|
SPIRV_ScalarOrVectorOf<SPIRV_Integer>:$base,
|
|
SPIRV_Integer:$offset,
|
|
SPIRV_Integer:$count
|
|
);
|
|
|
|
let results = (outs
|
|
SPIRV_ScalarOrVectorOf<SPIRV_Integer>:$result
|
|
);
|
|
|
|
let hasVerifier = 0;
|
|
|
|
let assemblyFormat = [{
|
|
operands attr-dict `:` type($base) `,` type($offset) `,` type($count)
|
|
}];
|
|
}
|
|
|
|
class SPIRV_BitUnaryOp<string mnemonic, list<Trait> traits = []> :
|
|
SPIRV_UnaryOp<mnemonic, SPIRV_Integer, SPIRV_Integer,
|
|
!listconcat(traits,
|
|
[Pure, SameOperandsAndResultType])>;
|
|
|
|
class SPIRV_ShiftOp<string mnemonic, list<Trait> traits = []> :
|
|
SPIRV_BinaryOp<mnemonic, SPIRV_Integer, SPIRV_Integer,
|
|
!listconcat(traits,
|
|
[Pure, SameOperandsAndResultShape,
|
|
AllTypesMatch<["operand1", "result"]>])> {
|
|
let assemblyFormat = [{
|
|
operands attr-dict `:` type($operand1) `,` type($operand2)
|
|
}];
|
|
let hasVerifier = 1;
|
|
}
|
|
|
|
// -----
|
|
|
|
def SPIRV_BitCountOp : SPIRV_BitUnaryOp<"BitCount", []> {
|
|
let summary = "Count the number of set bits in an object.";
|
|
|
|
let description = [{
|
|
Results are computed per component.
|
|
|
|
Result Type must be a scalar or vector of integer type. The components
|
|
must be wide enough to hold the unsigned Width of Base as an unsigned
|
|
value. That is, no sign bit is needed or counted when checking for a
|
|
wide enough result width.
|
|
|
|
Base must be a scalar or vector of integer type. It must have the same
|
|
number of components as Result Type.
|
|
|
|
The result is the unsigned value that is the number of bits in Base that
|
|
are 1.
|
|
|
|
#### Example:
|
|
|
|
```mlir
|
|
%2 = spirv.BitCount %0: i32
|
|
%3 = spirv.BitCount %1: vector<4xi32>
|
|
```
|
|
}];
|
|
}
|
|
|
|
// -----
|
|
|
|
def SPIRV_BitFieldInsertOp : SPIRV_Op<"BitFieldInsert",
|
|
[Pure, AllTypesMatch<["base", "insert", "result"]>]> {
|
|
let summary = [{
|
|
Make a copy of an object, with a modified bit field that comes from
|
|
another object.
|
|
}];
|
|
|
|
let description = [{
|
|
Results are computed per component.
|
|
|
|
Result Type must be a scalar or vector of integer type.
|
|
|
|
The type of Base and Insert must be the same as Result Type.
|
|
|
|
Any result bits numbered outside [Offset, Offset + Count - 1]
|
|
(inclusive) will come from the corresponding bits in Base.
|
|
|
|
Any result bits numbered in [Offset, Offset + Count - 1] come, in
|
|
order, from the bits numbered [0, Count - 1] of Insert.
|
|
|
|
Count must be an integer type scalar. Count is the number of bits taken
|
|
from Insert. It will be consumed as an unsigned value. Count can be 0,
|
|
in which case the result will be Base.
|
|
|
|
Offset must be an integer type scalar. Offset is the lowest-order bit
|
|
of the bit field. It will be consumed as an unsigned value.
|
|
|
|
The resulting value is undefined if Count or Offset or their sum is
|
|
greater than the number of bits in the result.
|
|
|
|
#### Example:
|
|
|
|
```mlir
|
|
%0 = spirv.BitFieldInsert %base, %insert, %offset, %count : vector<3xi32>, i8, i8
|
|
```
|
|
}];
|
|
|
|
let availability = [
|
|
MinVersion<SPIRV_V_1_0>,
|
|
MaxVersion<SPIRV_V_1_6>,
|
|
Extension<[]>,
|
|
Capability<[SPIRV_C_BitInstructions, SPIRV_C_Shader]>
|
|
];
|
|
|
|
let arguments = (ins
|
|
SPIRV_ScalarOrVectorOf<SPIRV_Integer>:$base,
|
|
SPIRV_ScalarOrVectorOf<SPIRV_Integer>:$insert,
|
|
SPIRV_Integer:$offset,
|
|
SPIRV_Integer:$count
|
|
);
|
|
|
|
let results = (outs
|
|
SPIRV_ScalarOrVectorOf<SPIRV_Integer>:$result
|
|
);
|
|
|
|
let hasVerifier = 0;
|
|
|
|
let assemblyFormat = [{
|
|
operands attr-dict `:` type($base) `,` type($offset) `,` type($count)
|
|
}];
|
|
}
|
|
|
|
// -----
|
|
|
|
def SPIRV_BitFieldSExtractOp : SPIRV_BitFieldExtractOp<"BitFieldSExtract",
|
|
[SignedOp]> {
|
|
let summary = "Extract a bit field from an object, with sign extension.";
|
|
|
|
let description = [{
|
|
Results are computed per component.
|
|
|
|
Result Type must be a scalar or vector of integer type.
|
|
|
|
The type of Base must be the same as Result Type.
|
|
|
|
If Count is greater than 0: The bits of Base numbered in [Offset, Offset
|
|
+ Count - 1] (inclusive) become the bits numbered [0, Count - 1] of the
|
|
result. The remaining bits of the result will all be the same as bit
|
|
Offset + Count - 1 of Base.
|
|
|
|
Count must be an integer type scalar. Count is the number of bits
|
|
extracted from Base. It will be consumed as an unsigned value. Count can
|
|
be 0, in which case the result will be 0.
|
|
|
|
Offset must be an integer type scalar. Offset is the lowest-order bit
|
|
of the bit field to extract from Base. It will be consumed as an
|
|
unsigned value.
|
|
|
|
The resulting value is undefined if Count or Offset or their sum is
|
|
greater than the number of bits in the result.
|
|
|
|
#### Example:
|
|
|
|
```mlir
|
|
%0 = spirv.BitFieldSExtract %base, %offset, %count : vector<3xi32>, i8, i8
|
|
```
|
|
}];
|
|
|
|
let availability = [
|
|
MinVersion<SPIRV_V_1_0>,
|
|
MaxVersion<SPIRV_V_1_6>,
|
|
Extension<[]>,
|
|
Capability<[SPIRV_C_BitInstructions, SPIRV_C_Shader]>
|
|
];
|
|
}
|
|
|
|
// -----
|
|
|
|
def SPIRV_BitFieldUExtractOp : SPIRV_BitFieldExtractOp<"BitFieldUExtract",
|
|
[UnsignedOp]> {
|
|
let summary = "Extract a bit field from an object, without sign extension.";
|
|
|
|
let description = [{
|
|
The semantics are the same as with OpBitFieldSExtract with the exception
|
|
that there is no sign extension. The remaining bits of the result will
|
|
all be 0.
|
|
|
|
#### Example:
|
|
|
|
```mlir
|
|
%0 = spirv.BitFieldUExtract %base, %offset, %count : vector<3xi32>, i8, i8
|
|
```
|
|
}];
|
|
|
|
let availability = [
|
|
MinVersion<SPIRV_V_1_0>,
|
|
MaxVersion<SPIRV_V_1_6>,
|
|
Extension<[]>,
|
|
Capability<[SPIRV_C_BitInstructions, SPIRV_C_Shader]>
|
|
];
|
|
}
|
|
|
|
// -----
|
|
|
|
def SPIRV_BitReverseOp : SPIRV_BitUnaryOp<"BitReverse", []> {
|
|
let summary = "Reverse the bits in an object.";
|
|
|
|
let description = [{
|
|
Results are computed per component.
|
|
|
|
Result Type must be a scalar or vector of integer type.
|
|
|
|
The type of Base must be the same as Result Type.
|
|
|
|
The bit-number n of the result will be taken from bit-number Width - 1 -
|
|
n of Base, where Width is the OpTypeInt operand of the Result Type.
|
|
|
|
#### Example:
|
|
|
|
```mlir
|
|
%2 = spirv.BitReverse %0 : i32
|
|
%3 = spirv.BitReverse %1 : vector<4xi32>
|
|
```
|
|
}];
|
|
|
|
let availability = [
|
|
MinVersion<SPIRV_V_1_0>,
|
|
MaxVersion<SPIRV_V_1_6>,
|
|
Extension<[]>,
|
|
Capability<[SPIRV_C_BitInstructions, SPIRV_C_Shader]>
|
|
];
|
|
}
|
|
|
|
// -----
|
|
|
|
def SPIRV_BitwiseAndOp : SPIRV_BitBinaryOp<"BitwiseAnd",
|
|
[Commutative, UsableInSpecConstantOp]> {
|
|
let summary = [{
|
|
Result is 1 if both Operand 1 and Operand 2 are 1. Result is 0 if either
|
|
Operand 1 or Operand 2 are 0.
|
|
}];
|
|
|
|
let description = [{
|
|
Results are computed per component, and within each component, per bit.
|
|
|
|
Result Type must be a scalar or vector of integer type. The type of
|
|
Operand 1 and Operand 2 must be a scalar or vector of integer type.
|
|
They must have the same number of components as Result Type. They must
|
|
have the same component width as Result Type.
|
|
|
|
#### Example:
|
|
|
|
```mlir
|
|
%2 = spirv.BitwiseAnd %0, %1 : i32
|
|
%2 = spirv.BitwiseAnd %0, %1 : vector<4xi32>
|
|
```
|
|
}];
|
|
|
|
let hasFolder = 1;
|
|
}
|
|
|
|
// -----
|
|
|
|
def SPIRV_BitwiseOrOp : SPIRV_BitBinaryOp<"BitwiseOr",
|
|
[Commutative, UsableInSpecConstantOp]> {
|
|
let summary = [{
|
|
Result is 1 if either Operand 1 or Operand 2 is 1. Result is 0 if both
|
|
Operand 1 and Operand 2 are 0.
|
|
}];
|
|
|
|
let description = [{
|
|
Results are computed per component, and within each component, per bit.
|
|
|
|
Result Type must be a scalar or vector of integer type. The type of
|
|
Operand 1 and Operand 2 must be a scalar or vector of integer type.
|
|
They must have the same number of components as Result Type. They must
|
|
have the same component width as Result Type.
|
|
|
|
#### Example:
|
|
|
|
```mlir
|
|
%2 = spirv.BitwiseOr %0, %1 : i32
|
|
%2 = spirv.BitwiseOr %0, %1 : vector<4xi32>
|
|
```
|
|
}];
|
|
|
|
let hasFolder = 1;
|
|
}
|
|
|
|
// -----
|
|
|
|
def SPIRV_BitwiseXorOp : SPIRV_BitBinaryOp<"BitwiseXor",
|
|
[Commutative, UsableInSpecConstantOp]> {
|
|
let summary = [{
|
|
Result is 1 if exactly one of Operand 1 or Operand 2 is 1. Result is 0
|
|
if Operand 1 and Operand 2 have the same value.
|
|
}];
|
|
|
|
let description = [{
|
|
Results are computed per component, and within each component, per bit.
|
|
|
|
Result Type must be a scalar or vector of integer type. The type of
|
|
Operand 1 and Operand 2 must be a scalar or vector of integer type.
|
|
They must have the same number of components as Result Type. They must
|
|
have the same component width as Result Type.
|
|
|
|
#### Example:
|
|
|
|
```mlir
|
|
%2 = spirv.BitwiseXor %0, %1 : i32
|
|
%2 = spirv.BitwiseXor %0, %1 : vector<4xi32>
|
|
```
|
|
}];
|
|
|
|
let hasFolder = 1;
|
|
}
|
|
|
|
// -----
|
|
|
|
def SPIRV_ShiftLeftLogicalOp : SPIRV_ShiftOp<"ShiftLeftLogical",
|
|
[UsableInSpecConstantOp]> {
|
|
let summary = [{
|
|
Shift the bits in Base left by the number of bits specified in Shift.
|
|
The least-significant bits are zero filled.
|
|
}];
|
|
|
|
let description = [{
|
|
Result Type must be a scalar or vector of integer type.
|
|
|
|
The type of each Base and Shift must be a scalar or vector of integer
|
|
type. Base and Shift must have the same number of components. The
|
|
number of components and bit width of the type of Base must be the same
|
|
as in Result Type.
|
|
|
|
Shift is treated as unsigned. The result is undefined if Shift is
|
|
greater than or equal to the bit width of the components of Base.
|
|
|
|
The number of components and bit width of Result Type must match those
|
|
Base type. All types must be integer types.
|
|
|
|
Results are computed per component.
|
|
|
|
#### Example:
|
|
|
|
```mlir
|
|
%2 = spirv.ShiftLeftLogical %0, %1 : i32, i16
|
|
%5 = spirv.ShiftLeftLogical %3, %4 : vector<3xi32>, vector<3xi16>
|
|
```
|
|
}];
|
|
|
|
let hasFolder = 1;
|
|
}
|
|
|
|
// -----
|
|
|
|
def SPIRV_ShiftRightArithmeticOp : SPIRV_ShiftOp<"ShiftRightArithmetic",
|
|
[UsableInSpecConstantOp]> {
|
|
let summary = [{
|
|
Shift the bits in Base right by the number of bits specified in Shift.
|
|
The most-significant bits are filled with the sign bit from Base.
|
|
}];
|
|
|
|
let description = [{
|
|
Result Type must be a scalar or vector of integer type.
|
|
|
|
The type of each Base and Shift must be a scalar or vector of integer
|
|
type. Base and Shift must have the same number of components. The
|
|
number of components and bit width of the type of Base must be the same
|
|
as in Result Type.
|
|
|
|
Shift is treated as unsigned. The result is undefined if Shift is
|
|
greater than or equal to the bit width of the components of Base.
|
|
|
|
Results are computed per component.
|
|
|
|
#### Example:
|
|
|
|
```mlir
|
|
%2 = spirv.ShiftRightArithmetic %0, %1 : i32, i16
|
|
%5 = spirv.ShiftRightArithmetic %3, %4 : vector<3xi32>, vector<3xi16>
|
|
```
|
|
}];
|
|
|
|
let hasFolder = 1;
|
|
}
|
|
|
|
// -----
|
|
|
|
def SPIRV_ShiftRightLogicalOp : SPIRV_ShiftOp<"ShiftRightLogical",
|
|
[UsableInSpecConstantOp]> {
|
|
let summary = [{
|
|
Shift the bits in Base right by the number of bits specified in Shift.
|
|
The most-significant bits are zero filled.
|
|
}];
|
|
|
|
let description = [{
|
|
Result Type must be a scalar or vector of integer type.
|
|
|
|
The type of each Base and Shift must be a scalar or vector of integer
|
|
type. Base and Shift must have the same number of components. The
|
|
number of components and bit width of the type of Base must be the same
|
|
as in Result Type.
|
|
|
|
Shift is consumed as an unsigned integer. The result is undefined if
|
|
Shift is greater than or equal to the bit width of the components of
|
|
Base.
|
|
|
|
Results are computed per component.
|
|
|
|
#### Example:
|
|
|
|
```mlir
|
|
%2 = spirv.ShiftRightLogical %0, %1 : i32, i16
|
|
%5 = spirv.ShiftRightLogical %3, %4 : vector<3xi32>, vector<3xi16>
|
|
```
|
|
}];
|
|
|
|
let hasFolder = 1;
|
|
}
|
|
|
|
// -----
|
|
|
|
def SPIRV_NotOp : SPIRV_BitUnaryOp<"Not", [UsableInSpecConstantOp]> {
|
|
let summary = "Complement the bits of Operand.";
|
|
|
|
let description = [{
|
|
Results are computed per component, and within each component, per bit.
|
|
|
|
Result Type must be a scalar or vector of integer type.
|
|
|
|
Operand's type must be a scalar or vector of integer type. It must
|
|
have the same number of components as Result Type. The component width
|
|
must equal the component width in Result Type.
|
|
|
|
#### Example:
|
|
|
|
```mlir
|
|
%2 = spirv.Not %0 : i32
|
|
%3 = spirv.Not %1 : vector<4xi32>
|
|
```
|
|
}];
|
|
|
|
let hasFolder = 1;
|
|
}
|
|
|
|
#endif // MLIR_DIALECT_SPIRV_IR_BIT_OPS
|