-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[mlir][spirv] Add definition for GL Pack/UnpackHalf2x16 #143889
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-mlir-spirv @llvm/pr-subscribers-mlir Author: Igor Wodiany (IgWod-IMG) ChangesFull diff: https://github.com/llvm/llvm-project/pull/143889.diff 3 Files Affected:
diff --git a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVGLOps.td b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVGLOps.td
index f3f75240e5214..7ffe0c8da1cae 100644
--- a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVGLOps.td
+++ b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVGLOps.td
@@ -1317,4 +1317,88 @@ def SPIRV_GLFractOp : SPIRV_GLUnaryArithmeticOp<"Fract", 10, SPIRV_Float> {
}];
}
+// -----
+
+def SPIRV_GLPackHalf2x16Op : SPIRV_GLOp<"PackHalf2x16", 58, [Pure]> {
+ let summary = "Pack two-component vector of 32-bit floats into a 32-bit integer";
+
+ let description = [{
+ Result is the unsigned integer obtained by converting the components of a
+ two-component floating-point vector to the 16-bit OpTypeFloat, and then packing
+ these two 16-bit integers into a 32-bit unsigned integer. The first vector
+ component specifies the 16 least-significant bits of the result; the second
+ component specifies the 16 most-significant bits.
+
+ The RelaxedPrecision Decoration only affects the conversion step of the instruction.
+
+ The v operand must be a vector of 2 components whose type is a 32-bit floating-point.
+
+ Result Type must be a 32-bit integer type.
+
+ #### Example:
+
+ ```mlir
+ %1 = spirv.GL.PackHalf2x16 %0 : vector<2xf32> -> i32
+ ```
+ }];
+
+ let arguments = (ins
+ VectorOfLengthAndType<[2], [SPIRV_Float32]>:$operand
+ );
+
+ let results = (outs
+ SPIRV_Int32:$result
+ );
+
+ let assemblyFormat = [{
+ attr-dict $operand `:` type($operand) `->` type($result)
+ }];
+
+ let hasVerifier = 0;
+}
+
+// -----
+
+def SPIRV_GLUnpackHalf2x16Op : SPIRV_GLOp<"UnpackHalf2x16", 62, [Pure]> {
+ let summary = "Unpack 32-bit integer into two-component vector of 32-bit floats";
+
+ let description = [{
+ Result is the two-component floating-point vector with components obtained by
+ unpacking a 32-bit unsigned integer into a pair of 16-bit values, interpreting
+ those values as 16-bit floating-point numbers according to the OpenGL
+ Specification, and converting them to 32-bit floating-point values. Subnormal
+ numbers are either preserved or flushed to zero, consistently within an
+ implementation.
+
+ The first component of the vector is obtained from the 16 least-significant bits
+ of v; the second component is obtained from the 16 most-significant bits of v.
+
+ The RelaxedPrecision Decoration only affects the conversion step of the instruction.
+
+ The v operand must be a scalar with 32-bit integer type.
+
+ Result Type must be a vector of 2 components whose type is 32-bit floating point.
+
+ #### Example:
+
+ ```mlir
+ %1 = spirv.GL.UnpackHalf2x16 %0 : i32 -> vector<2xf32>
+ ```
+ }];
+
+ let arguments = (ins
+ SPIRV_Int32:$operand
+ );
+
+ let results = (outs
+ VectorOfLengthAndType<[2], [SPIRV_Float32]>:$result
+ );
+
+ let assemblyFormat = [{
+ attr-dict $operand `:` type($operand) `->` type($result)
+ }];
+
+ let hasVerifier = 0;
+}
+
#endif // MLIR_DIALECT_SPIRV_IR_GL_OPS
diff --git a/mlir/test/Dialect/SPIRV/IR/gl-ops.mlir b/mlir/test/Dialect/SPIRV/IR/gl-ops.mlir
index 29beee5aea93c..fbcf2095dc608 100644
--- a/mlir/test/Dialect/SPIRV/IR/gl-ops.mlir
+++ b/mlir/test/Dialect/SPIRV/IR/gl-ops.mlir
@@ -815,3 +815,107 @@ func.func @exp2_invalid_type(%arg0 : i32) -> () {
%0 = spirv.GL.Exp2 %arg0 : i32
return
}
+
+// -----
+
+//===----------------------------------------------------------------------===//
+// spirv.GL.PackHalf2x16
+//===----------------------------------------------------------------------===//
+
+func.func @pack_half_2x16(%arg0 : vector<2xf32>) -> () {
+ // CHECK: spirv.GL.PackHalf2x16 {{%.*}} : vector<2xf32> -> i32
+ %0 = spirv.GL.PackHalf2x16 %arg0 : vector<2xf32> -> i32
+ return
+}
+
+// -----
+
+func.func @pack_half_2x16_i16_output(%arg0 : vector<2xf32>) -> () {
+ // expected-error @+1 {{op result #0 must be Int32, but got 'i16'}}
+ %0 = spirv.GL.PackHalf2x16 %arg0 : vector<2xf32> -> i16
+ return
+}
+
+// -----
+
+func.func @pack_half_2x16_wrong_vec_size(%arg0 : vector<3xf32>) -> () {
+ // expected-error @+1 {{op operand #0 must be vector of Float32 values of length 2, but got 'vector<3xf32>'}}
+ %0 = spirv.GL.PackHalf2x16 %arg0 : vector<3xf32> -> i32
+ return
+}
+
+// -----
+
+func.func @pack_half_2x16_wrong_vec_type(%arg0 : vector<2xi32>) -> () {
+ // expected-error @+1 {{op operand #0 must be vector of Float32 values of length 2, but got 'vector<2xi32>'}}
+ %0 = spirv.GL.PackHalf2x16 %arg0 : vector<2xi32> -> i32
+ return
+}
+
+// -----
+
+func.func @pack_half_2x16_scalar_in(%arg0 : f32) -> () {
+ // expected-error @+1 {{invalid kind of type specified: expected builtin.vector, but found 'f32'}}
+ %0 = spirv.GL.PackHalf2x16 %arg0 : f32 -> i32
+ return
+}
+
+// -----
+
+func.func @unpack_half_2x16_vector_out(%arg0 : vector<2xf32>) -> () {
+ // expected-error @+1 {{invalid kind of type specified: expected builtin.integer, but found 'vector<2xf32>'}}
+ %0 = spirv.GL.UnpackHalf2x16 %arg0 : vector<2xf32> -> vector<2xi32>
+ return
+}
+
+// -----
+
+//===----------------------------------------------------------------------===//
+// spirv.GL.UnpackHalf2x16
+//===----------------------------------------------------------------------===//
+
+func.func @unpack_half_2x16(%arg0 : i32) -> () {
+ // CHECK: spirv.GL.UnpackHalf2x16 {{%.*}} : i32 -> vector<2xf32>
+ %0 = spirv.GL.UnpackHalf2x16 %arg0 : i32 -> vector<2xf32>
+ return
+}
+
+// -----
+
+func.func @unpack_half_2x16_i16_input(%arg0 : i16) -> () {
+ // expected-error @+1 {{op operand #0 must be Int32, but got 'i16'}}
+ %0 = spirv.GL.UnpackHalf2x16 %arg0 : i16 -> vector<2xf32>
+ return
+}
+
+// -----
+
+func.func @unpack_half_2x16_wrong_vec_size(%arg0 : i32) -> () {
+ // expected-error @+1 {{op result #0 must be vector of Float32 values of length 2, but got 'vector<3xf32>'}}
+ %0 = spirv.GL.UnpackHalf2x16 %arg0 : i32 -> vector<3xf32>
+ return
+}
+
+// -----
+
+func.func @unpack_half_2x16_wrong_vec_type(%arg0 : i32) -> () {
+ // expected-error @+1 {{op result #0 must be vector of Float32 values of length 2, but got 'vector<2xi32>'}}
+ %0 = spirv.GL.UnpackHalf2x16 %arg0 : i32 -> vector<2xi32>
+ return
+}
+
+// -----
+
+func.func @unpack_half_2x16_vec_in(%arg0 : vector<2xf32>) -> () {
+ // expected-error @+1 {{invalid kind of type specified: expected builtin.integer, but found 'vector<2xf32>'}}
+ %0 = spirv.GL.UnpackHalf2x16 %arg0 : vector<2xf32> -> vector<2xf32>
+ return
+}
+
+// -----
+
+func.func @unpack_half_2x16_scalar_out(%arg0 : i32) -> () {
+ // expected-error @+1 {{invalid kind of type specified: expected builtin.vector, but found 'f32'}}
+ %0 = spirv.GL.UnpackHalf2x16 %arg0 : i32 -> f32
+ return
+}
diff --git a/mlir/test/Target/SPIRV/gl-ops.mlir b/mlir/test/Target/SPIRV/gl-ops.mlir
index 3dee03345e9a1..e4a6c6fb5a34e 100644
--- a/mlir/test/Target/SPIRV/gl-ops.mlir
+++ b/mlir/test/Target/SPIRV/gl-ops.mlir
@@ -96,7 +96,7 @@ spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader], []> {
spirv.Return
}
-spirv.func @vector(%arg0 : f32, %arg1 : vector<3xf32>, %arg2 : vector<3xf32>) "None" {
+ spirv.func @vector(%arg0 : f32, %arg1 : vector<3xf32>, %arg2 : vector<3xf32>) "None" {
// CHECK: {{%.*}} = spirv.GL.Cross {{%.*}}, {{%.*}} : vector<3xf32>
%0 = spirv.GL.Cross %arg1, %arg2 : vector<3xf32>
// CHECK: {{%.*}} = spirv.GL.Normalize {{%.*}} : f32
@@ -114,5 +114,11 @@ spirv.func @vector(%arg0 : f32, %arg1 : vector<3xf32>, %arg2 : vector<3xf32>) "N
spirv.Return
}
-
+ spirv.func @pack_half_2x16(%arg0 : i32) "None" {
+ // CHECK: {{%.*}} = spirv.GL.UnpackHalf2x16 {{%.*}} : i32 -> vector<2xf32>
+ %0 = spirv.GL.UnpackHalf2x16 %arg0 : i32 -> vector<2xf32>
+ // CHECK: {{%.*}} = spirv.GL.PackHalf2x16 {{%.*}} : vector<2xf32> -> i32
+ %1 = spirv.GL.PackHalf2x16 %0 : vector<2xf32> -> i32
+ spirv.Return
+ }
}
|
Result is the unsigned integer obtained by converting the components of a | ||
two-component floating-point vector to the 16-bit OpTypeFloat, and then packing | ||
these two 16-bit integers into a 32-bit unsigned integer. The first vector |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sidenote: This seems like a very clumsy way to define an op -- they don't say how the initial f32 -> f16 conversion is done. I assume it's the same as OpFConvert
, but the language does not really specify.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, I did some digging, and it seems that at least with respect to the rounding mode its somehow intentional: KhronosGroup/Vulkan-Docs#1825. Looking at the Vulkan spec itself, it gives a bit more information: https://registry.khronos.org/vulkan/specs/latest/html/vkspec.html#spirvenv-op-prec:
packHalf2x16 | Correctly rounded with implementation defined rounding mode. |
---|
No description provided.