[spirv-reader][ir] Add Signed comparison operators.
Add conversions for the `OpSGreaterThan`, `OpSGreaterThanEqual`,
`OpSLessThan` and `OpSLessThanEqual` comparison operators.
Bug: 391486024, 391486212, 391486712, 391486323
Change-Id: Id51db4896448dacb01710264dcdf6a048d3b2cc5
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/227214
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/tint/lang/spirv/builtin_fn.cc b/src/tint/lang/spirv/builtin_fn.cc
index 44edd7f..12bb13e 100644
--- a/src/tint/lang/spirv/builtin_fn.cc
+++ b/src/tint/lang/spirv/builtin_fn.cc
@@ -164,6 +164,14 @@
return "s_div";
case BuiltinFn::kSMod:
return "s_mod";
+ case BuiltinFn::kSGreaterThan:
+ return "s_greater_than";
+ case BuiltinFn::kSGreaterThanEqual:
+ return "s_greater_than_equal";
+ case BuiltinFn::kSLessThan:
+ return "s_less_than";
+ case BuiltinFn::kSLessThanEqual:
+ return "s_less_than_equal";
case BuiltinFn::kConvertFToS:
return "convertFToS";
case BuiltinFn::kConvertSToF:
@@ -278,6 +286,10 @@
case BuiltinFn::kBitwiseXor:
case BuiltinFn::kEqual:
case BuiltinFn::kNotEqual:
+ case BuiltinFn::kSGreaterThan:
+ case BuiltinFn::kSGreaterThanEqual:
+ case BuiltinFn::kSLessThan:
+ case BuiltinFn::kSLessThanEqual:
break;
}
return core::ir::Instruction::Accesses{};
diff --git a/src/tint/lang/spirv/builtin_fn.cc.tmpl b/src/tint/lang/spirv/builtin_fn.cc.tmpl
index c99ba89..4e57ac1 100644
--- a/src/tint/lang/spirv/builtin_fn.cc.tmpl
+++ b/src/tint/lang/spirv/builtin_fn.cc.tmpl
@@ -111,6 +111,10 @@
case BuiltinFn::kBitwiseXor:
case BuiltinFn::kEqual:
case BuiltinFn::kNotEqual:
+ case BuiltinFn::kSGreaterThan:
+ case BuiltinFn::kSGreaterThanEqual:
+ case BuiltinFn::kSLessThan:
+ case BuiltinFn::kSLessThanEqual:
break;
}
return core::ir::Instruction::Accesses{};
diff --git a/src/tint/lang/spirv/builtin_fn.h b/src/tint/lang/spirv/builtin_fn.h
index 02778de..f643687 100644
--- a/src/tint/lang/spirv/builtin_fn.h
+++ b/src/tint/lang/spirv/builtin_fn.h
@@ -109,6 +109,10 @@
kMul,
kSDiv,
kSMod,
+ kSGreaterThan,
+ kSGreaterThanEqual,
+ kSLessThan,
+ kSLessThanEqual,
kConvertFToS,
kConvertSToF,
kConvertUToF,
diff --git a/src/tint/lang/spirv/intrinsic/data.cc b/src/tint/lang/spirv/intrinsic/data.cc
index 0b5486f..fe1a81a 100644
--- a/src/tint/lang/spirv/intrinsic/data.cc
+++ b/src/tint/lang/spirv/intrinsic/data.cc
@@ -5949,23 +5949,23 @@
{
/* [178] */
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* num_parameters */ 1,
- /* num_explicit_templates */ 1,
+ /* num_parameters */ 2,
+ /* num_explicit_templates */ 0,
/* num_templates */ 2,
- /* templates */ TemplateIndex(79),
- /* parameters */ ParameterIndex(1),
- /* return_matcher_indices */ MatcherIndicesIndex(4),
+ /* templates */ TemplateIndex(22),
+ /* parameters */ ParameterIndex(6),
+ /* return_matcher_indices */ MatcherIndicesIndex(17),
/* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
},
{
/* [179] */
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* num_parameters */ 1,
- /* num_explicit_templates */ 1,
+ /* num_parameters */ 2,
+ /* num_explicit_templates */ 0,
/* num_templates */ 3,
- /* templates */ TemplateIndex(79),
- /* parameters */ ParameterIndex(362),
- /* return_matcher_indices */ MatcherIndicesIndex(149),
+ /* templates */ TemplateIndex(52),
+ /* parameters */ ParameterIndex(361),
+ /* return_matcher_indices */ MatcherIndicesIndex(179),
/* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
},
{
@@ -5974,7 +5974,7 @@
/* num_parameters */ 1,
/* num_explicit_templates */ 1,
/* num_templates */ 2,
- /* templates */ TemplateIndex(82),
+ /* templates */ TemplateIndex(79),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(4),
/* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
@@ -5985,7 +5985,7 @@
/* num_parameters */ 1,
/* num_explicit_templates */ 1,
/* num_templates */ 3,
- /* templates */ TemplateIndex(82),
+ /* templates */ TemplateIndex(79),
/* parameters */ ParameterIndex(362),
/* return_matcher_indices */ MatcherIndicesIndex(149),
/* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
@@ -5993,23 +5993,23 @@
{
/* [182] */
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* num_parameters */ 2,
- /* num_explicit_templates */ 0,
+ /* num_parameters */ 1,
+ /* num_explicit_templates */ 1,
/* num_templates */ 2,
- /* templates */ TemplateIndex(22),
- /* parameters */ ParameterIndex(6),
- /* return_matcher_indices */ MatcherIndicesIndex(17),
+ /* templates */ TemplateIndex(82),
+ /* parameters */ ParameterIndex(1),
+ /* return_matcher_indices */ MatcherIndicesIndex(4),
/* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
},
{
/* [183] */
/* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
- /* num_parameters */ 2,
- /* num_explicit_templates */ 0,
+ /* num_parameters */ 1,
+ /* num_explicit_templates */ 1,
/* num_templates */ 3,
- /* templates */ TemplateIndex(52),
- /* parameters */ ParameterIndex(361),
- /* return_matcher_indices */ MatcherIndicesIndex(179),
+ /* templates */ TemplateIndex(82),
+ /* parameters */ ParameterIndex(362),
+ /* return_matcher_indices */ MatcherIndicesIndex(149),
/* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
},
{
@@ -6727,86 +6727,114 @@
},
{
/* [61] */
- /* fn convertFToS<R : iu32>[T : f32_f16](T) -> R */
- /* fn convertFToS<R : iu32>[T : f32_f16, N : num](vec<N, T>) -> vec<N, R> */
+ /* fn s_greater_than[A : iu32, B : iu32](A, B) -> bool */
+ /* fn s_greater_than[A : iu32, B : iu32, N : num](vec<N, A>, vec<N, B>) -> vec<N, bool> */
/* num overloads */ 2,
/* overloads */ OverloadIndex(178),
},
{
/* [62] */
- /* fn convertSToF<R : f32_f16>[T : iu32](T) -> R */
- /* fn convertSToF<R : f32_f16>[T : iu32, N : num](vec<N, T>) -> vec<N, R> */
+ /* fn s_greater_than_equal[A : iu32, B : iu32](A, B) -> bool */
+ /* fn s_greater_than_equal[A : iu32, B : iu32, N : num](vec<N, A>, vec<N, B>) -> vec<N, bool> */
/* num overloads */ 2,
- /* overloads */ OverloadIndex(180),
+ /* overloads */ OverloadIndex(178),
},
{
/* [63] */
- /* fn convertUToF<R : f32_f16>[T : iu32](T) -> R */
- /* fn convertUToF<R : f32_f16>[T : iu32, N : num](vec<N, T>) -> vec<N, R> */
+ /* fn s_less_than[A : iu32, B : iu32](A, B) -> bool */
+ /* fn s_less_than[A : iu32, B : iu32, N : num](vec<N, A>, vec<N, B>) -> vec<N, bool> */
+ /* num overloads */ 2,
+ /* overloads */ OverloadIndex(178),
+ },
+ {
+ /* [64] */
+ /* fn s_less_than_equal[A : iu32, B : iu32](A, B) -> bool */
+ /* fn s_less_than_equal[A : iu32, B : iu32, N : num](vec<N, A>, vec<N, B>) -> vec<N, bool> */
+ /* num overloads */ 2,
+ /* overloads */ OverloadIndex(178),
+ },
+ {
+ /* [65] */
+ /* fn convertFToS<R : iu32>[T : f32_f16](T) -> R */
+ /* fn convertFToS<R : iu32>[T : f32_f16, N : num](vec<N, T>) -> vec<N, R> */
/* num overloads */ 2,
/* overloads */ OverloadIndex(180),
},
{
- /* [64] */
+ /* [66] */
+ /* fn convertSToF<R : f32_f16>[T : iu32](T) -> R */
+ /* fn convertSToF<R : f32_f16>[T : iu32, N : num](vec<N, T>) -> vec<N, R> */
+ /* num overloads */ 2,
+ /* overloads */ OverloadIndex(182),
+ },
+ {
+ /* [67] */
+ /* fn convertUToF<R : f32_f16>[T : iu32](T) -> R */
+ /* fn convertUToF<R : f32_f16>[T : iu32, N : num](vec<N, T>) -> vec<N, R> */
+ /* num overloads */ 2,
+ /* overloads */ OverloadIndex(182),
+ },
+ {
+ /* [68] */
/* fn bitwiseAnd<R : iu32>[A : iu32, B : iu32](A, B) -> R */
/* fn bitwiseAnd<R : iu32>[A : iu32, B : iu32, N : num](vec<N, A>, vec<N, B>) -> vec<N, R> */
/* num overloads */ 2,
/* overloads */ OverloadIndex(176),
},
{
- /* [65] */
+ /* [69] */
/* fn bitwiseOr<R : iu32>[A : iu32, B : iu32](A, B) -> R */
/* fn bitwiseOr<R : iu32>[A : iu32, B : iu32, N : num](vec<N, A>, vec<N, B>) -> vec<N, R> */
/* num overloads */ 2,
/* overloads */ OverloadIndex(176),
},
{
- /* [66] */
+ /* [70] */
/* fn bitwiseXor<R : iu32>[A : iu32, B : iu32](A, B) -> R */
/* fn bitwiseXor<R : iu32>[A : iu32, B : iu32, N : num](vec<N, A>, vec<N, B>) -> vec<N, R> */
/* num overloads */ 2,
/* overloads */ OverloadIndex(176),
},
{
- /* [67] */
+ /* [71] */
/* fn equal[A : iu32, B : iu32](A, B) -> bool */
/* fn equal[A : iu32, B : iu32, N : num](vec<N, A>, vec<N, B>) -> vec<N, bool> */
/* num overloads */ 2,
- /* overloads */ OverloadIndex(182),
+ /* overloads */ OverloadIndex(178),
},
{
- /* [68] */
+ /* [72] */
/* fn not_equal[A : iu32, B : iu32](A, B) -> bool */
/* fn not_equal[A : iu32, B : iu32, N : num](vec<N, A>, vec<N, B>) -> vec<N, bool> */
/* num overloads */ 2,
- /* overloads */ OverloadIndex(182),
+ /* overloads */ OverloadIndex(178),
},
{
- /* [69] */
+ /* [73] */
/* fn sdot(u32, u32, u32) -> i32 */
/* num overloads */ 1,
/* overloads */ OverloadIndex(195),
},
{
- /* [70] */
+ /* [74] */
/* fn udot(u32, u32, u32) -> u32 */
/* num overloads */ 1,
/* overloads */ OverloadIndex(196),
},
{
- /* [71] */
+ /* [75] */
/* fn cooperative_matrix_load<T : subgroup_matrix<K, S, C, R>>[K : subgroup_matrix_kind, S : fiu32_f16, C : num, R : num](ptr<workgroup_or_storage, S, readable>, u32, u32, u32) -> T */
/* num overloads */ 1,
/* overloads */ OverloadIndex(197),
},
{
- /* [72] */
+ /* [76] */
/* fn cooperative_matrix_store[K : subgroup_matrix_kind, S : fiu32_f16, C : num, R : num](ptr<workgroup_or_storage, S, writable>, subgroup_matrix<K, S, C, R>, u32, u32, u32) */
/* num overloads */ 1,
/* overloads */ OverloadIndex(198),
},
{
- /* [73] */
+ /* [77] */
/* fn cooperative_matrix_mul_add[T : subgroup_matrix_elements, TR : subgroup_matrix_elements, C : num, R : num, K : num](subgroup_matrix<subgroup_matrix_kind_left, T, K, R>, subgroup_matrix<subgroup_matrix_kind_right, T, C, K>, subgroup_matrix<subgroup_matrix_kind_result, TR, C, R>, u32) -> subgroup_matrix<subgroup_matrix_kind_result, TR, C, R> */
/* num overloads */ 1,
/* overloads */ OverloadIndex(199),
diff --git a/src/tint/lang/spirv/reader/lower/builtins.cc b/src/tint/lang/spirv/reader/lower/builtins.cc
index 170385c..e4fee04 100644
--- a/src/tint/lang/spirv/reader/lower/builtins.cc
+++ b/src/tint/lang/spirv/reader/lower/builtins.cc
@@ -170,6 +170,18 @@
case spirv::BuiltinFn::kNotEqual:
NotEqual(builtin);
break;
+ case spirv::BuiltinFn::kSGreaterThan:
+ SGreaterThan(builtin);
+ break;
+ case spirv::BuiltinFn::kSGreaterThanEqual:
+ SGreaterThanEqual(builtin);
+ break;
+ case spirv::BuiltinFn::kSLessThan:
+ SLessThan(builtin);
+ break;
+ case spirv::BuiltinFn::kSLessThanEqual:
+ SLessThanEqual(builtin);
+ break;
default:
TINT_UNREACHABLE() << "unknown spirv builtin: " << builtin->Func();
}
@@ -313,6 +325,37 @@
EmitBinaryMatchedArgs(call, core::BinaryOp::kNotEqual);
}
+ void EmitBinaryWithSignedArgs(spirv::ir::BuiltinCall* call, core::BinaryOp op) {
+ const auto& args = call->Args();
+ auto* lhs = args[0];
+ auto* rhs = args[1];
+
+ auto* arg_ty = ty.MatchWidth(ty.i32(), call->Result(0)->Type());
+ b.InsertBefore(call, [&] {
+ if (lhs->Type() != arg_ty) {
+ lhs = b.Bitcast(arg_ty, lhs)->Result(0);
+ }
+ if (rhs->Type() != arg_ty) {
+ rhs = b.Bitcast(arg_ty, rhs)->Result(0);
+ }
+
+ b.BinaryWithResult(call->DetachResult(), op, lhs, rhs)->Result(0);
+ });
+ call->Destroy();
+ }
+ void SGreaterThan(spirv::ir::BuiltinCall* call) {
+ EmitBinaryWithSignedArgs(call, core::BinaryOp::kGreaterThan);
+ }
+ void SGreaterThanEqual(spirv::ir::BuiltinCall* call) {
+ EmitBinaryWithSignedArgs(call, core::BinaryOp::kGreaterThanEqual);
+ }
+ void SLessThan(spirv::ir::BuiltinCall* call) {
+ EmitBinaryWithSignedArgs(call, core::BinaryOp::kLessThan);
+ }
+ void SLessThanEqual(spirv::ir::BuiltinCall* call) {
+ EmitBinaryWithSignedArgs(call, core::BinaryOp::kLessThanEqual);
+ }
+
// The SPIR-V Signed methods all interpret their arguments as signed (regardless of the type of
// the argument). In order to satisfy this, we must bitcast any unsigned argument to a signed
// type before calling the WGSL equivalent method.
diff --git a/src/tint/lang/spirv/reader/lower/builtins_test.cc b/src/tint/lang/spirv/reader/lower/builtins_test.cc
index 139e5e4..8cf5cff 100644
--- a/src/tint/lang/spirv/reader/lower/builtins_test.cc
+++ b/src/tint/lang/spirv/reader/lower/builtins_test.cc
@@ -6305,5 +6305,291 @@
::testing::Values(SpirvReaderParams{spirv::BuiltinFn::kEqual, "equal", "eq"},
SpirvReaderParams{spirv::BuiltinFn::kNotEqual, "not_equal", "neq"}));
+using SpirvReader_SignedIntegerTest =
+ core::ir::transform::TransformTestWithParam<SpirvReaderParams>;
+TEST_P(SpirvReader_SignedIntegerTest, Scalar_SignedSigned) {
+ auto param = GetParam();
+ auto* ep = b.ComputeFunction("foo");
+
+ b.Append(ep->Block(), [&] { //
+ b.Call<spirv::ir::BuiltinCall>(ty.bool_(), param.fn, 1_i, 2_i);
+ b.Return(ep);
+ });
+
+ auto src = R"(
+%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
+ $B1: {
+ %2:bool = spirv.)" +
+ param.spv_name + R"( 1i, 2i
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+ Run(Builtins);
+
+ auto expect = R"(
+%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
+ $B1: {
+ %2:bool = )" + param.wgsl_name +
+ R"( 1i, 2i
+ ret
+ }
+}
+)";
+ EXPECT_EQ(expect, str());
+}
+
+TEST_P(SpirvReader_SignedIntegerTest, Scalar_SignedUnsigned) {
+ auto param = GetParam();
+ auto* ep = b.ComputeFunction("foo");
+
+ b.Append(ep->Block(), [&] { //
+ b.Call<spirv::ir::BuiltinCall>(ty.bool_(), param.fn, 1_i, 8_u);
+ b.Return(ep);
+ });
+
+ auto src = R"(
+%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
+ $B1: {
+ %2:bool = spirv.)" +
+ param.spv_name + R"( 1i, 8u
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+ Run(Builtins);
+
+ auto expect = R"(
+%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
+ $B1: {
+ %2:i32 = bitcast 8u
+ %3:bool = )" + param.wgsl_name +
+ R"( 1i, %2
+ ret
+ }
+}
+)";
+ EXPECT_EQ(expect, str());
+}
+
+TEST_P(SpirvReader_SignedIntegerTest, Scalar_UnsignedSigned) {
+ auto param = GetParam();
+ auto* ep = b.ComputeFunction("foo");
+
+ b.Append(ep->Block(), [&] { //
+ b.Call<spirv::ir::BuiltinCall>(ty.bool_(), param.fn, 8_u, 1_i);
+ b.Return(ep);
+ });
+
+ auto src = R"(
+%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
+ $B1: {
+ %2:bool = spirv.)" +
+ param.spv_name + R"( 8u, 1i
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+ Run(Builtins);
+
+ auto expect = R"(
+%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
+ $B1: {
+ %2:i32 = bitcast 8u
+ %3:bool = )" + param.wgsl_name +
+ R"( %2, 1i
+ ret
+ }
+}
+)";
+ EXPECT_EQ(expect, str());
+}
+
+TEST_P(SpirvReader_SignedIntegerTest, Scalar_UnsignedUnsigned) {
+ auto param = GetParam();
+ auto* ep = b.ComputeFunction("foo");
+
+ b.Append(ep->Block(), [&] { //
+ b.Call<spirv::ir::BuiltinCall>(ty.bool_(), param.fn, 8_u, 9_u);
+ b.Return(ep);
+ });
+
+ auto src = R"(
+%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
+ $B1: {
+ %2:bool = spirv.)" +
+ param.spv_name + R"( 8u, 9u
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+ Run(Builtins);
+
+ auto expect = R"(
+%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
+ $B1: {
+ %2:i32 = bitcast 8u
+ %3:i32 = bitcast 9u
+ %4:bool = )" + param.wgsl_name +
+ R"( %2, %3
+ ret
+ }
+}
+)";
+ EXPECT_EQ(expect, str());
+}
+
+TEST_P(SpirvReader_SignedIntegerTest, Vector_SignedSigned) {
+ auto param = GetParam();
+ auto* ep = b.ComputeFunction("foo");
+
+ b.Append(ep->Block(), [&] { //
+ b.Call<spirv::ir::BuiltinCall>(ty.vec2<bool>(), param.fn, b.Splat<vec2<i32>>(1_i),
+ b.Splat<vec2<i32>>(2_i));
+ b.Return(ep);
+ });
+
+ auto src = R"(
+%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
+ $B1: {
+ %2:vec2<bool> = spirv.)" +
+ param.spv_name + R"( vec2<i32>(1i), vec2<i32>(2i)
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+ Run(Builtins);
+
+ auto expect = R"(
+%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
+ $B1: {
+ %2:vec2<bool> = )" +
+ param.wgsl_name + R"( vec2<i32>(1i), vec2<i32>(2i)
+ ret
+ }
+}
+)";
+ EXPECT_EQ(expect, str());
+}
+
+TEST_P(SpirvReader_SignedIntegerTest, Vector_SignedUnsigned) {
+ auto param = GetParam();
+ auto* ep = b.ComputeFunction("foo");
+
+ b.Append(ep->Block(), [&] { //
+ b.Call<spirv::ir::BuiltinCall>(ty.vec2<bool>(), param.fn, b.Splat<vec2<i32>>(1_i),
+ b.Splat<vec2<u32>>(8_u));
+ b.Return(ep);
+ });
+
+ auto src = R"(
+%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
+ $B1: {
+ %2:vec2<bool> = spirv.)" +
+ param.spv_name + R"( vec2<i32>(1i), vec2<u32>(8u)
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+ Run(Builtins);
+
+ auto expect = R"(
+%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
+ $B1: {
+ %2:vec2<i32> = bitcast vec2<u32>(8u)
+ %3:vec2<bool> = )" +
+ param.wgsl_name + R"( vec2<i32>(1i), %2
+ ret
+ }
+}
+)";
+ EXPECT_EQ(expect, str());
+}
+
+TEST_P(SpirvReader_SignedIntegerTest, Vector_UnsignedSigned) {
+ auto param = GetParam();
+ auto* ep = b.ComputeFunction("foo");
+
+ b.Append(ep->Block(), [&] { //
+ b.Call<spirv::ir::BuiltinCall>(ty.vec2<bool>(), param.fn, b.Splat<vec2<u32>>(8_u),
+ b.Splat<vec2<i32>>(1_i));
+ b.Return(ep);
+ });
+
+ auto src = R"(
+%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
+ $B1: {
+ %2:vec2<bool> = spirv.)" +
+ param.spv_name + R"( vec2<u32>(8u), vec2<i32>(1i)
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+ Run(Builtins);
+
+ auto expect = R"(
+%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
+ $B1: {
+ %2:vec2<i32> = bitcast vec2<u32>(8u)
+ %3:vec2<bool> = )" +
+ param.wgsl_name + R"( %2, vec2<i32>(1i)
+ ret
+ }
+}
+)";
+ EXPECT_EQ(expect, str());
+}
+
+TEST_P(SpirvReader_SignedIntegerTest, Vector_UnsignedUnsigned) {
+ auto param = GetParam();
+ auto* ep = b.ComputeFunction("foo");
+
+ b.Append(ep->Block(), [&] { //
+ b.Call<spirv::ir::BuiltinCall>(ty.vec2<bool>(), param.fn, b.Splat<vec2<u32>>(8_u),
+ b.Splat<vec2<u32>>(9_u));
+ b.Return(ep);
+ });
+
+ auto src = R"(
+%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
+ $B1: {
+ %2:vec2<bool> = spirv.)" +
+ param.spv_name + R"( vec2<u32>(8u), vec2<u32>(9u)
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+ Run(Builtins);
+
+ auto expect = R"(
+%foo = @compute @workgroup_size(1u, 1u, 1u) func():void {
+ $B1: {
+ %2:vec2<i32> = bitcast vec2<u32>(8u)
+ %3:vec2<i32> = bitcast vec2<u32>(9u)
+ %4:vec2<bool> = )" +
+ param.wgsl_name + R"( %2, %3
+ ret
+ }
+}
+)";
+ EXPECT_EQ(expect, str());
+}
+INSTANTIATE_TEST_SUITE_P(
+ SpirvReader,
+ SpirvReader_SignedIntegerTest,
+ ::testing::Values(
+ SpirvReaderParams{spirv::BuiltinFn::kSGreaterThan, "s_greater_than", "gt"},
+ SpirvReaderParams{spirv::BuiltinFn::kSGreaterThanEqual, "s_greater_than_equal", "gte"},
+ SpirvReaderParams{spirv::BuiltinFn::kSLessThan, "s_less_than", "lt"},
+ SpirvReaderParams{spirv::BuiltinFn::kSLessThanEqual, "s_less_than_equal", "lte"}));
+
} // namespace
} // namespace tint::spirv::reader::lower
diff --git a/src/tint/lang/spirv/reader/parser/logical_test.cc b/src/tint/lang/spirv/reader/parser/logical_test.cc
index f00c282..a0becf7 100644
--- a/src/tint/lang/spirv/reader/parser/logical_test.cc
+++ b/src/tint/lang/spirv/reader/parser/logical_test.cc
@@ -232,7 +232,7 @@
%ep_type = OpTypeFunction %void
%main = OpFunction %void None %ep_type
%main_start = OpLabel
- %1 = OpI)" +
+ %1 = Op)" +
params.spv_name + R"( %bool %one %two
OpReturn
OpFunctionEnd
@@ -274,7 +274,7 @@
%ep_type = OpTypeFunction %void
%main = OpFunction %void None %ep_type
%main_start = OpLabel
- %1 = OpI)" +
+ %1 = Op)" +
params.spv_name + R"( %bool %one %eight
OpReturn
OpFunctionEnd
@@ -316,7 +316,7 @@
%ep_type = OpTypeFunction %void
%main = OpFunction %void None %ep_type
%main_start = OpLabel
- %1 = OpI)" +
+ %1 = Op)" +
params.spv_name + R"( %bool %eight %one
OpReturn
OpFunctionEnd
@@ -358,7 +358,7 @@
%ep_type = OpTypeFunction %void
%main = OpFunction %void None %ep_type
%main_start = OpLabel
- %1 = OpI)" +
+ %1 = Op)" +
params.spv_name + R"( %bool %eight %nine
OpReturn
OpFunctionEnd
@@ -400,7 +400,7 @@
%ep_type = OpTypeFunction %void
%main = OpFunction %void None %ep_type
%main_start = OpLabel
- %1 = OpI)" +
+ %1 = Op)" +
params.spv_name + R"( %v2bool %v2one %v2two
OpReturn
OpFunctionEnd
@@ -442,7 +442,7 @@
%ep_type = OpTypeFunction %void
%main = OpFunction %void None %ep_type
%main_start = OpLabel
- %1 = OpI)" +
+ %1 = Op)" +
params.spv_name + R"( %v2bool %v2one %v2eight
OpReturn
OpFunctionEnd
@@ -484,7 +484,7 @@
%ep_type = OpTypeFunction %void
%main = OpFunction %void None %ep_type
%main_start = OpLabel
- %1 = OpI)" +
+ %1 = Op)" +
params.spv_name + R"( %v2bool %v2eight %v2one
OpReturn
OpFunctionEnd
@@ -526,7 +526,7 @@
%ep_type = OpTypeFunction %void
%main = OpFunction %void None %ep_type
%main_start = OpLabel
- %1 = OpI)" +
+ %1 = Op)" +
params.spv_name + R"( %v2bool %v2eight %v2nine
OpReturn
OpFunctionEnd
@@ -544,8 +544,13 @@
INSTANTIATE_TEST_SUITE_P(SpirvParserTest,
SpirvParser_IntegerTest,
- testing::Values(SpirvLogicalParam{"Equal", "equal"},
- SpirvLogicalParam{"NotEqual", "not_equal"}));
+ testing::Values(SpirvLogicalParam{"IEqual", "equal"},
+ SpirvLogicalParam{"INotEqual", "not_equal"},
+ SpirvLogicalParam{"SGreaterThan", "s_greater_than"},
+ SpirvLogicalParam{"SGreaterThanEqual",
+ "s_greater_than_equal"},
+ SpirvLogicalParam{"SLessThan", "s_less_than"},
+ SpirvLogicalParam{"SLessThanEqual", "s_less_than_equal"}));
using SpirvParser_LogicalTest = SpirvParserTestWithParam<SpirvLogicalParam>;
TEST_P(SpirvParser_LogicalTest, Scalar) {
diff --git a/src/tint/lang/spirv/reader/parser/parser.cc b/src/tint/lang/spirv/reader/parser/parser.cc
index a9e2543..ed86efc 100644
--- a/src/tint/lang/spirv/reader/parser/parser.cc
+++ b/src/tint/lang/spirv/reader/parser/parser.cc
@@ -764,6 +764,18 @@
case spv::Op::OpINotEqual:
EmitSpirvBuiltinCall(inst, spirv::BuiltinFn::kNotEqual);
break;
+ case spv::Op::OpSGreaterThan:
+ EmitSpirvBuiltinCall(inst, spirv::BuiltinFn::kSGreaterThan);
+ break;
+ case spv::Op::OpSGreaterThanEqual:
+ EmitSpirvBuiltinCall(inst, spirv::BuiltinFn::kSGreaterThanEqual);
+ break;
+ case spv::Op::OpSLessThan:
+ EmitSpirvBuiltinCall(inst, spirv::BuiltinFn::kSLessThan);
+ break;
+ case spv::Op::OpSLessThanEqual:
+ EmitSpirvBuiltinCall(inst, spirv::BuiltinFn::kSLessThanEqual);
+ break;
case spv::Op::OpISub:
EmitSpirvExplicitBuiltinCall(inst, spirv::BuiltinFn::kSub);
break;
diff --git a/src/tint/lang/spirv/spirv.def b/src/tint/lang/spirv/spirv.def
index 2833eba..82ad82f 100644
--- a/src/tint/lang/spirv/spirv.def
+++ b/src/tint/lang/spirv/spirv.def
@@ -414,6 +414,15 @@
implicit(A: iu32, B: iu32, N: num) fn s_div<R: iu32>(vec<N, A>, vec<N, B>) -> vec<N, R>
implicit(A: iu32, B: iu32, N: num) fn s_mod<R: iu32>(vec<N, A>, vec<N, B>) -> vec<N, R>
+implicit(A: iu32, B: iu32) fn s_greater_than(A, B) -> bool
+implicit(A: iu32, B: iu32, N: num) fn s_greater_than(vec<N, A>, vec<N, B>) -> vec<N, bool>
+implicit(A: iu32, B: iu32) fn s_greater_than_equal(A, B) -> bool
+implicit(A: iu32, B: iu32, N: num) fn s_greater_than_equal(vec<N, A>, vec<N, B>) -> vec<N, bool>
+implicit(A: iu32, B: iu32) fn s_less_than(A, B) -> bool
+implicit(A: iu32, B: iu32, N: num) fn s_less_than(vec<N, A>, vec<N, B>) -> vec<N, bool>
+implicit(A: iu32, B: iu32) fn s_less_than_equal(A, B) -> bool
+implicit(A: iu32, B: iu32, N: num) fn s_less_than_equal(vec<N, A>, vec<N, B>) -> vec<N, bool>
+
implicit(T: f32_f16) fn convertFToS<R: iu32>(T) -> R
implicit(T: f32_f16, N: num) fn convertFToS<R: iu32>(vec<N, T>) -> vec<N, R>
implicit(T: iu32) fn convertSToF<R: f32_f16>(T) -> R
diff --git a/src/tint/lang/spirv/writer/printer/printer.cc b/src/tint/lang/spirv/writer/printer/printer.cc
index c76d552..c8d3f9e 100644
--- a/src/tint/lang/spirv/writer/printer/printer.cc
+++ b/src/tint/lang/spirv/writer/printer/printer.cc
@@ -1548,6 +1548,18 @@
case BuiltinFn::kNotEqual:
op = spv::Op::OpINotEqual;
break;
+ case BuiltinFn::kSGreaterThan:
+ op = spv::Op::OpSGreaterThan;
+ break;
+ case BuiltinFn::kSGreaterThanEqual:
+ op = spv::Op::OpSGreaterThanEqual;
+ break;
+ case BuiltinFn::kSLessThan:
+ op = spv::Op::OpSLessThan;
+ break;
+ case BuiltinFn::kSLessThanEqual:
+ op = spv::Op::OpSLessThanEqual;
+ break;
case spirv::BuiltinFn::kNone:
TINT_ICE() << "undefined spirv ir function";
}