diff --git a/src/tint/reader/spirv/function.cc b/src/tint/reader/spirv/function.cc index e133e585cc..58941ebc45 100644 --- a/src/tint/reader/spirv/function.cc +++ b/src/tint/reader/spirv/function.cc @@ -327,6 +327,8 @@ std::string GetGlslStd450FuncName(uint32_t ext_opcode) { return "exp2"; case GLSLstd450FaceForward: return "faceForward"; + case GLSLstd450FindILsb: + return "firstTrailingBit"; case GLSLstd450Floor: return "floor"; case GLSLstd450Fma: @@ -427,7 +429,6 @@ std::string GetGlslStd450FuncName(uint32_t ext_opcode) { case GLSLstd450PackDouble2x32: case GLSLstd450UnpackDouble2x32: - case GLSLstd450FindILsb: case GLSLstd450FindSMsb: case GLSLstd450FindUMsb: diff --git a/src/tint/reader/spirv/function_glsl_std_450_test.cc b/src/tint/reader/spirv/function_glsl_std_450_test.cc index c5131e9ac2..7a4fd94394 100644 --- a/src/tint/reader/spirv/function_glsl_std_450_test.cc +++ b/src/tint/reader/spirv/function_glsl_std_450_test.cc @@ -179,6 +179,8 @@ using SpvParserTest_GlslStd450_Inting_IntingInting = SpvParserTestBase<::testing::TestWithParam>; using SpvParserTest_GlslStd450_Inting_IntingIntingInting = SpvParserTestBase<::testing::TestWithParam>; +using SpvParserTest_GlslStd450_Uinting_Uinting = + SpvParserTestBase<::testing::TestWithParam>; using SpvParserTest_GlslStd450_Uinting_UintingUinting = SpvParserTestBase<::testing::TestWithParam>; using SpvParserTest_GlslStd450_Uinting_UintingUintingUinting = @@ -580,7 +582,8 @@ TEST_P(SpvParserTest_GlslStd450_Inting_IntingIntingInting, Vector) { INSTANTIATE_TEST_SUITE_P(Samples, SpvParserTest_GlslStd450_Inting_Inting, - ::testing::Values(GlslStd450Case{"SAbs", "abs"})); + ::testing::Values(GlslStd450Case{"SAbs", "abs"}, + GlslStd450Case{"FindILsb", "firstTrailingBit"})); INSTANTIATE_TEST_SUITE_P(Samples, SpvParserTest_GlslStd450_Inting_IntingInting, @@ -591,6 +594,41 @@ INSTANTIATE_TEST_SUITE_P(Samples, SpvParserTest_GlslStd450_Inting_IntingIntingInting, ::testing::Values(GlslStd450Case{"SClamp", "clamp"})); +TEST_P(SpvParserTest_GlslStd450_Uinting_Uinting, Scalar) { + const auto assembly = Preamble() + R"( + %1 = OpExtInst %uint %glsl )" + + GetParam().opcode + + R"( %u1 + OpReturn + OpFunctionEnd + )"; + auto p = parser(test::Assemble(assembly)); + ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly; + auto fe = p->function_emitter(100); + EXPECT_TRUE(fe.EmitBody()) << p->error(); + auto ast_body = fe.ast_body(); + const auto body = test::ToString(p->program(), ast_body); + EXPECT_THAT(body, HasSubstr("let x_1 : u32 = " + GetParam().wgsl_func + "(u1);")) << body; +} + +TEST_P(SpvParserTest_GlslStd450_Uinting_Uinting, Vector) { + const auto assembly = Preamble() + R"( + %1 = OpExtInst %v2uint %glsl )" + + GetParam().opcode + + R"( %v2u1 + OpReturn + OpFunctionEnd + )"; + auto p = parser(test::Assemble(assembly)); + ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()); + auto fe = p->function_emitter(100); + EXPECT_TRUE(fe.EmitBody()) << p->error(); + auto ast_body = fe.ast_body(); + const auto body = test::ToString(p->program(), ast_body); + EXPECT_THAT(body, HasSubstr("let x_1 : vec2 = " + GetParam().wgsl_func + "(v2u1);")) + << body; +} + TEST_P(SpvParserTest_GlslStd450_Uinting_UintingUinting, Scalar) { const auto assembly = Preamble() + R"( %1 = OpExtInst %uint %glsl )" + @@ -661,6 +699,10 @@ TEST_P(SpvParserTest_GlslStd450_Uinting_UintingUintingUinting, Vector) { << body; } +INSTANTIATE_TEST_SUITE_P(Samples, + SpvParserTest_GlslStd450_Uinting_Uinting, + ::testing::Values(GlslStd450Case{"FindILsb", "firstTrailingBit"})); + INSTANTIATE_TEST_SUITE_P(Samples, SpvParserTest_GlslStd450_Uinting_UintingUinting, ::testing::Values(GlslStd450Case{"UMax", "max"}, @@ -907,6 +949,34 @@ TEST_F(SpvParserTest, RectifyOperandsAndResult_UClamp) { << body; } +TEST_F(SpvParserTest, RectifyOperandsAndResult_FindILsb) { + // Check conversion of: + // signed results to unsigned result to match first arg. + // unsigned results to signed result to match first arg. + // This is the first extended instruction we've supported which goes both + // ways. + const auto assembly = Preamble() + R"( + %1 = OpExtInst %uint %glsl FindILsb %i1 + %2 = OpExtInst %v2uint %glsl FindILsb %v2i1 + %3 = OpExtInst %int %glsl FindILsb %u1 + %4 = OpExtInst %v2int %glsl FindILsb %v2u1 + OpReturn + OpFunctionEnd + )"; + auto p = parser(test::Assemble(assembly)); + ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()); + auto fe = p->function_emitter(100); + EXPECT_TRUE(fe.EmitBody()) << p->error(); + auto ast_body = fe.ast_body(); + const auto body = test::ToString(p->program(), ast_body); + EXPECT_THAT(body, HasSubstr(R"( +let x_1 : u32 = bitcast(firstTrailingBit(i1)); +let x_2 : vec2 = bitcast>(firstTrailingBit(v2i1)); +let x_3 : i32 = bitcast(firstTrailingBit(u1)); +let x_4 : vec2 = bitcast>(firstTrailingBit(v2u1));)")) + << body; +} + struct DataPackingCase { std::string opcode; std::string wgsl_func; diff --git a/src/tint/reader/spirv/parser_impl.cc b/src/tint/reader/spirv/parser_impl.cc index b79c6634f1..38a3a05595 100644 --- a/src/tint/reader/spirv/parser_impl.cc +++ b/src/tint/reader/spirv/parser_impl.cc @@ -221,6 +221,7 @@ bool AssumesResultSignednessMatchesFirstOperand(GLSLstd450 extended_opcode) { case GLSLstd450UMin: case GLSLstd450UMax: case GLSLstd450UClamp: + case GLSLstd450FindILsb: // TODO(dneto): FindSMsb? // TODO(dneto): FindUMsb? return true;