spirv-reader: support more integer builtins
Support:
- SAbs
- UMax, SMax
- UMin, SMin
Add tests for operand and result conversion for UClamp.
SClamp was already tested.
Bug: tint:3
Change-Id: I9b9278843ca5243991b330b27764756137da4ee4
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/35302
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Commit-Queue: David Neto <dneto@google.com>
Auto-Submit: David Neto <dneto@google.com>
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index 6a0c855..484fbba 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -326,6 +326,7 @@
std::string GetGlslStd450FuncName(uint32_t ext_opcode) {
switch (ext_opcode) {
case GLSLstd450FAbs:
+ case GLSLstd450SAbs:
return "abs";
case GLSLstd450Acos:
return "acos";
@@ -374,9 +375,13 @@
return "log2";
case GLSLstd450NMax:
case GLSLstd450FMax: // FMax is less prescriptive about NaN operands
+ case GLSLstd450UMax:
+ case GLSLstd450SMax:
return "max";
case GLSLstd450NMin:
case GLSLstd450FMin: // FMin is less prescriptive about NaN operands
+ case GLSLstd450UMin:
+ case GLSLstd450SMin:
return "min";
case GLSLstd450FMix:
return "mix";
@@ -411,7 +416,6 @@
// TODO(dneto) - The following are not implemented.
// They are grouped semantically, as in GLSL.std.450.h.
case GLSLstd450RoundEven:
- case GLSLstd450SAbs:
case GLSLstd450SSign:
case GLSLstd450Radians:
@@ -425,10 +429,6 @@
case GLSLstd450Modf:
case GLSLstd450ModfStruct:
- case GLSLstd450UMin:
- case GLSLstd450SMin:
- case GLSLstd450UMax:
- case GLSLstd450SMax:
case GLSLstd450IMix:
case GLSLstd450Frexp:
diff --git a/src/reader/spirv/function_glsl_std_450_test.cc b/src/reader/spirv/function_glsl_std_450_test.cc
index 203d357..4333cee 100644
--- a/src/reader/spirv/function_glsl_std_450_test.cc
+++ b/src/reader/spirv/function_glsl_std_450_test.cc
@@ -161,8 +161,14 @@
using SpvParserTest_GlslStd450_Float3_Float3Float3 =
SpvParserTestBase<::testing::TestWithParam<GlslStd450Case>>;
+using SpvParserTest_GlslStd450_Inting_Inting =
+ SpvParserTestBase<::testing::TestWithParam<GlslStd450Case>>;
+using SpvParserTest_GlslStd450_Inting_IntingInting =
+ SpvParserTestBase<::testing::TestWithParam<GlslStd450Case>>;
using SpvParserTest_GlslStd450_Inting_IntingIntingInting =
SpvParserTestBase<::testing::TestWithParam<GlslStd450Case>>;
+using SpvParserTest_GlslStd450_Uinting_UintingUinting =
+ SpvParserTestBase<::testing::TestWithParam<GlslStd450Case>>;
using SpvParserTest_GlslStd450_Uinting_UintingUintingUinting =
SpvParserTestBase<::testing::TestWithParam<GlslStd450Case>>;
@@ -691,6 +697,128 @@
{"FMix", "mix"},
{"SmoothStep", "smoothStep"}}));
+TEST_P(SpvParserTest_GlslStd450_Inting_Inting, Scalar) {
+ const auto assembly = Preamble() + R"(
+ %1 = OpExtInst %int %glsl )" +
+ GetParam().opcode +
+ R"( %i1
+ OpReturn
+ OpFunctionEnd
+ )";
+ auto p = parser(test::Assemble(assembly));
+ ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+ FunctionEmitter fe(p.get(), *spirv_function(p.get(), 100));
+ EXPECT_TRUE(fe.EmitBody()) << p->error();
+ EXPECT_THAT(ToString(fe.ast_body()), HasSubstr(R"(
+ VariableConst{
+ x_1
+ none
+ __i32
+ {
+ Call[not set]{
+ Identifier[not set]{)" + GetParam().wgsl_func +
+ R"(}
+ (
+ Identifier[not set]{i1}
+ )
+ }
+ }
+ })"))
+ << ToString(fe.ast_body());
+}
+
+TEST_P(SpvParserTest_GlslStd450_Inting_Inting, Vector) {
+ const auto assembly = Preamble() + R"(
+ %1 = OpExtInst %v2int %glsl )" +
+ GetParam().opcode +
+ R"( %v2i1
+ OpReturn
+ OpFunctionEnd
+ )";
+ auto p = parser(test::Assemble(assembly));
+ ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+ FunctionEmitter fe(p.get(), *spirv_function(p.get(), 100));
+ EXPECT_TRUE(fe.EmitBody()) << p->error();
+ EXPECT_THAT(ToString(fe.ast_body()), HasSubstr(R"(
+ VariableConst{
+ x_1
+ none
+ __vec_2__i32
+ {
+ Call[not set]{
+ Identifier[not set]{)" + GetParam().wgsl_func +
+ R"(}
+ (
+ Identifier[not set]{v2i1}
+ )
+ }
+ }
+ })"))
+ << ToString(fe.ast_body());
+}
+
+TEST_P(SpvParserTest_GlslStd450_Inting_IntingInting, Scalar) {
+ const auto assembly = Preamble() + R"(
+ %1 = OpExtInst %int %glsl )" +
+ GetParam().opcode +
+ R"( %i1 %i2
+ OpReturn
+ OpFunctionEnd
+ )";
+ auto p = parser(test::Assemble(assembly));
+ ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+ FunctionEmitter fe(p.get(), *spirv_function(p.get(), 100));
+ EXPECT_TRUE(fe.EmitBody()) << p->error();
+ EXPECT_THAT(ToString(fe.ast_body()), HasSubstr(R"(
+ VariableConst{
+ x_1
+ none
+ __i32
+ {
+ Call[not set]{
+ Identifier[not set]{)" + GetParam().wgsl_func +
+ R"(}
+ (
+ Identifier[not set]{i1}
+ Identifier[not set]{i2}
+ )
+ }
+ }
+ })"))
+ << ToString(fe.ast_body());
+}
+
+TEST_P(SpvParserTest_GlslStd450_Inting_IntingInting, Vector) {
+ const auto assembly = Preamble() + R"(
+ %1 = OpExtInst %v2int %glsl )" +
+ GetParam().opcode +
+ R"( %v2i1 %v2i2
+ OpReturn
+ OpFunctionEnd
+ )";
+ auto p = parser(test::Assemble(assembly));
+ ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+ FunctionEmitter fe(p.get(), *spirv_function(p.get(), 100));
+ EXPECT_TRUE(fe.EmitBody()) << p->error();
+ EXPECT_THAT(ToString(fe.ast_body()), HasSubstr(R"(
+ VariableConst{
+ x_1
+ none
+ __vec_2__i32
+ {
+ Call[not set]{
+ Identifier[not set]{)" + GetParam().wgsl_func +
+ R"(}
+ (
+ Identifier[not set]{v2i1}
+ Identifier[not set]{v2i2}
+ )
+ }
+ }
+ })"))
+ << ToString(fe.ast_body());
+}
+
TEST_P(SpvParserTest_GlslStd450_Inting_IntingIntingInting, Scalar) {
const auto assembly = Preamble() + R"(
%1 = OpExtInst %int %glsl )" +
@@ -756,9 +884,79 @@
}
INSTANTIATE_TEST_SUITE_P(Samples,
+ SpvParserTest_GlslStd450_Inting_Inting,
+ ::testing::Values(GlslStd450Case{"SAbs", "abs"}));
+
+INSTANTIATE_TEST_SUITE_P(Samples,
+ SpvParserTest_GlslStd450_Inting_IntingInting,
+ ::testing::Values(GlslStd450Case{"SMax", "max"},
+ GlslStd450Case{"SMin", "min"}));
+
+INSTANTIATE_TEST_SUITE_P(Samples,
SpvParserTest_GlslStd450_Inting_IntingIntingInting,
::testing::Values(GlslStd450Case{"SClamp", "clamp"}));
+TEST_P(SpvParserTest_GlslStd450_Uinting_UintingUinting, Scalar) {
+ const auto assembly = Preamble() + R"(
+ %1 = OpExtInst %uint %glsl )" +
+ GetParam().opcode + R"( %u1 %u2
+ OpReturn
+ OpFunctionEnd
+ )";
+ auto p = parser(test::Assemble(assembly));
+ ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+ FunctionEmitter fe(p.get(), *spirv_function(p.get(), 100));
+ EXPECT_TRUE(fe.EmitBody()) << p->error();
+ EXPECT_THAT(ToString(fe.ast_body()), HasSubstr(R"(
+ VariableConst{
+ x_1
+ none
+ __u32
+ {
+ Call[not set]{
+ Identifier[not set]{)" + GetParam().wgsl_func +
+ R"(}
+ (
+ Identifier[not set]{u1}
+ Identifier[not set]{u2}
+ )
+ }
+ }
+ })"))
+ << ToString(fe.ast_body());
+}
+
+TEST_P(SpvParserTest_GlslStd450_Uinting_UintingUinting, Vector) {
+ const auto assembly = Preamble() + R"(
+ %1 = OpExtInst %v2uint %glsl )" +
+ GetParam().opcode +
+ R"( %v2u1 %v2u2
+ OpReturn
+ OpFunctionEnd
+ )";
+ auto p = parser(test::Assemble(assembly));
+ ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+ FunctionEmitter fe(p.get(), *spirv_function(p.get(), 100));
+ EXPECT_TRUE(fe.EmitBody()) << p->error();
+ EXPECT_THAT(ToString(fe.ast_body()), HasSubstr(R"(
+ VariableConst{
+ x_1
+ none
+ __vec_2__u32
+ {
+ Call[not set]{
+ Identifier[not set]{)" + GetParam().wgsl_func +
+ R"(}
+ (
+ Identifier[not set]{v2u1}
+ Identifier[not set]{v2u2}
+ )
+ }
+ }
+ })"))
+ << ToString(fe.ast_body());
+}
+
TEST_P(SpvParserTest_GlslStd450_Uinting_UintingUintingUinting, Scalar) {
const auto assembly = Preamble() + R"(
%1 = OpExtInst %uint %glsl )" +
@@ -823,10 +1021,186 @@
}
INSTANTIATE_TEST_SUITE_P(Samples,
+ SpvParserTest_GlslStd450_Uinting_UintingUinting,
+ ::testing::Values(GlslStd450Case{"UMax", "max"},
+ GlslStd450Case{"UMin", "min"}));
+
+INSTANTIATE_TEST_SUITE_P(Samples,
SpvParserTest_GlslStd450_Uinting_UintingUintingUinting,
::testing::Values(GlslStd450Case{"UClamp", "clamp"}));
-TEST_F(SpvParserTest, RectifyOperandsAndResult_GLSLstd450SClamp) {
+// Check that we convert signedness of operands and result type.
+// This is needed for each of the integer-based extended instructions.
+
+TEST_F(SpvParserTest, RectifyOperandsAndResult_SAbs) {
+ const auto assembly = Preamble() + R"(
+ %1 = OpExtInst %uint %glsl SAbs %u1
+ %2 = OpExtInst %v2uint %glsl SAbs %v2u1
+ OpReturn
+ OpFunctionEnd
+ )";
+ auto p = parser(test::Assemble(assembly));
+ ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+ FunctionEmitter fe(p.get(), *spirv_function(p.get(), 100));
+ EXPECT_TRUE(fe.EmitBody()) << p->error();
+ auto body = ToString(fe.ast_body());
+ EXPECT_THAT(body, HasSubstr(R"(
+ VariableConst{
+ x_1
+ none
+ __u32
+ {
+ Bitcast[not set]<__u32>{
+ Call[not set]{
+ Identifier[not set]{abs}
+ (
+ Bitcast[not set]<__i32>{
+ Identifier[not set]{u1}
+ }
+ )
+ }
+ }
+ }
+ })"))
+ << body;
+ EXPECT_THAT(body, HasSubstr(R"(
+ VariableConst{
+ x_2
+ none
+ __vec_2__u32
+ {
+ Bitcast[not set]<__vec_2__u32>{
+ Call[not set]{
+ Identifier[not set]{abs}
+ (
+ Bitcast[not set]<__vec_2__i32>{
+ Identifier[not set]{v2u1}
+ }
+ )
+ }
+ }
+ }
+ })"))
+ << body;
+}
+
+TEST_F(SpvParserTest, RectifyOperandsAndResult_SMax) {
+ const auto assembly = Preamble() + R"(
+ %1 = OpExtInst %uint %glsl SMax %u1 %u2
+ %2 = OpExtInst %v2uint %glsl SMax %v2u1 %v2u2
+ OpReturn
+ OpFunctionEnd
+ )";
+ auto p = parser(test::Assemble(assembly));
+ ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+ FunctionEmitter fe(p.get(), *spirv_function(p.get(), 100));
+ EXPECT_TRUE(fe.EmitBody()) << p->error();
+ auto body = ToString(fe.ast_body());
+ EXPECT_THAT(body, HasSubstr(R"(
+ VariableConst{
+ x_1
+ none
+ __u32
+ {
+ Bitcast[not set]<__u32>{
+ Call[not set]{
+ Identifier[not set]{max}
+ (
+ Bitcast[not set]<__i32>{
+ Identifier[not set]{u1}
+ }
+ Bitcast[not set]<__i32>{
+ Identifier[not set]{u2}
+ }
+ )
+ }
+ }
+ }
+ })"))
+ << body;
+ EXPECT_THAT(body, HasSubstr(R"(
+ VariableConst{
+ x_2
+ none
+ __vec_2__u32
+ {
+ Bitcast[not set]<__vec_2__u32>{
+ Call[not set]{
+ Identifier[not set]{max}
+ (
+ Bitcast[not set]<__vec_2__i32>{
+ Identifier[not set]{v2u1}
+ }
+ Bitcast[not set]<__vec_2__i32>{
+ Identifier[not set]{v2u2}
+ }
+ )
+ }
+ }
+ }
+ })"))
+ << body;
+}
+
+TEST_F(SpvParserTest, RectifyOperandsAndResult_SMin) {
+ const auto assembly = Preamble() + R"(
+ %1 = OpExtInst %uint %glsl SMin %u1 %u2
+ %2 = OpExtInst %v2uint %glsl SMin %v2u1 %v2u2
+ OpReturn
+ OpFunctionEnd
+ )";
+ auto p = parser(test::Assemble(assembly));
+ ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+ FunctionEmitter fe(p.get(), *spirv_function(p.get(), 100));
+ EXPECT_TRUE(fe.EmitBody()) << p->error();
+ auto body = ToString(fe.ast_body());
+ EXPECT_THAT(body, HasSubstr(R"(
+ VariableConst{
+ x_1
+ none
+ __u32
+ {
+ Bitcast[not set]<__u32>{
+ Call[not set]{
+ Identifier[not set]{min}
+ (
+ Bitcast[not set]<__i32>{
+ Identifier[not set]{u1}
+ }
+ Bitcast[not set]<__i32>{
+ Identifier[not set]{u2}
+ }
+ )
+ }
+ }
+ }
+ })"))
+ << body;
+ EXPECT_THAT(body, HasSubstr(R"(
+ VariableConst{
+ x_2
+ none
+ __vec_2__u32
+ {
+ Bitcast[not set]<__vec_2__u32>{
+ Call[not set]{
+ Identifier[not set]{min}
+ (
+ Bitcast[not set]<__vec_2__i32>{
+ Identifier[not set]{v2u1}
+ }
+ Bitcast[not set]<__vec_2__i32>{
+ Identifier[not set]{v2u2}
+ }
+ )
+ }
+ }
+ }
+ })"))
+ << body;
+}
+
+TEST_F(SpvParserTest, RectifyOperandsAndResult_SClamp) {
const auto assembly = Preamble() + R"(
%1 = OpExtInst %uint %glsl SClamp %u1 %i2 %u3
%2 = OpExtInst %v2uint %glsl SClamp %v2u1 %v2i2 %v2u3
@@ -886,6 +1260,182 @@
<< body;
}
+TEST_F(SpvParserTest, RectifyOperandsAndResult_UMax) {
+ const auto assembly = Preamble() + R"(
+ %1 = OpExtInst %int %glsl UMax %i1 %i2
+ %2 = OpExtInst %v2int %glsl UMax %v2i1 %v2i2
+ OpReturn
+ OpFunctionEnd
+ )";
+ auto p = parser(test::Assemble(assembly));
+ ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+ FunctionEmitter fe(p.get(), *spirv_function(p.get(), 100));
+ EXPECT_TRUE(fe.EmitBody()) << p->error();
+ auto body = ToString(fe.ast_body());
+ EXPECT_THAT(body, HasSubstr(R"(
+ VariableConst{
+ x_1
+ none
+ __i32
+ {
+ Bitcast[not set]<__i32>{
+ Call[not set]{
+ Identifier[not set]{max}
+ (
+ Bitcast[not set]<__u32>{
+ Identifier[not set]{i1}
+ }
+ Bitcast[not set]<__u32>{
+ Identifier[not set]{i2}
+ }
+ )
+ }
+ }
+ }
+ })"))
+ << body;
+ EXPECT_THAT(body, HasSubstr(R"(
+ VariableConst{
+ x_2
+ none
+ __vec_2__i32
+ {
+ Bitcast[not set]<__vec_2__i32>{
+ Call[not set]{
+ Identifier[not set]{max}
+ (
+ Bitcast[not set]<__vec_2__u32>{
+ Identifier[not set]{v2i1}
+ }
+ Bitcast[not set]<__vec_2__u32>{
+ Identifier[not set]{v2i2}
+ }
+ )
+ }
+ }
+ }
+ })"))
+ << body;
+}
+
+TEST_F(SpvParserTest, RectifyOperandsAndResult_UMin) {
+ const auto assembly = Preamble() + R"(
+ %1 = OpExtInst %int %glsl UMin %i1 %i2
+ %2 = OpExtInst %v2int %glsl UMin %v2i1 %v2i2
+ OpReturn
+ OpFunctionEnd
+ )";
+ auto p = parser(test::Assemble(assembly));
+ ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+ FunctionEmitter fe(p.get(), *spirv_function(p.get(), 100));
+ EXPECT_TRUE(fe.EmitBody()) << p->error();
+ auto body = ToString(fe.ast_body());
+ EXPECT_THAT(body, HasSubstr(R"(
+ VariableConst{
+ x_1
+ none
+ __i32
+ {
+ Bitcast[not set]<__i32>{
+ Call[not set]{
+ Identifier[not set]{min}
+ (
+ Bitcast[not set]<__u32>{
+ Identifier[not set]{i1}
+ }
+ Bitcast[not set]<__u32>{
+ Identifier[not set]{i2}
+ }
+ )
+ }
+ }
+ }
+ })"))
+ << body;
+ EXPECT_THAT(body, HasSubstr(R"(
+ VariableConst{
+ x_2
+ none
+ __vec_2__i32
+ {
+ Bitcast[not set]<__vec_2__i32>{
+ Call[not set]{
+ Identifier[not set]{min}
+ (
+ Bitcast[not set]<__vec_2__u32>{
+ Identifier[not set]{v2i1}
+ }
+ Bitcast[not set]<__vec_2__u32>{
+ Identifier[not set]{v2i2}
+ }
+ )
+ }
+ }
+ }
+ })"))
+ << body;
+}
+
+TEST_F(SpvParserTest, RectifyOperandsAndResult_UClamp) {
+ const auto assembly = Preamble() + R"(
+ %1 = OpExtInst %int %glsl UClamp %i1 %u2 %i3
+ %2 = OpExtInst %v2int %glsl UClamp %v2i1 %v2u2 %v2i3
+ OpReturn
+ OpFunctionEnd
+ )";
+ auto p = parser(test::Assemble(assembly));
+ ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+ FunctionEmitter fe(p.get(), *spirv_function(p.get(), 100));
+ EXPECT_TRUE(fe.EmitBody()) << p->error();
+ auto body = ToString(fe.ast_body());
+ EXPECT_THAT(body, HasSubstr(R"(
+ VariableConst{
+ x_1
+ none
+ __i32
+ {
+ Bitcast[not set]<__i32>{
+ Call[not set]{
+ Identifier[not set]{clamp}
+ (
+ Bitcast[not set]<__u32>{
+ Identifier[not set]{i1}
+ }
+ Identifier[not set]{u2}
+ Bitcast[not set]<__u32>{
+ Identifier[not set]{i3}
+ }
+ )
+ }
+ }
+ }
+ })"))
+ << body;
+ EXPECT_THAT(body, HasSubstr(R"(
+ VariableConst{
+ x_2
+ none
+ __vec_2__i32
+ {
+ Bitcast[not set]<__vec_2__i32>{
+ Call[not set]{
+ Identifier[not set]{clamp}
+ (
+ Bitcast[not set]<__vec_2__u32>{
+ Identifier[not set]{v2i1}
+ }
+ Identifier[not set]{v2u2}
+ Bitcast[not set]<__vec_2__u32>{
+ Identifier[not set]{v2i3}
+ }
+ )
+ }
+ }
+ }
+ })"))
+ << body;
+}
+
} // namespace
} // namespace spirv
} // namespace reader