[spirv-reader] Support OpAny, OpAll, OpIsInf, OpIsNan
Bug: tint:3, tint:121
Change-Id: I1a6a2d45684c28a0e03ad4b208dc6b2f737da694
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/25422
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index 66f5c1c..3e547f9 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -191,6 +191,25 @@
return false;
}
+/// Converts a SPIR-V opcode for a WGSL builtin function, if there is a
+/// direct translation. Returns nullptr otherwise.
+/// @returns the WGSL builtin function name for the given opcode, or nullptr.
+const char* GetUnaryBuiltInFunctionName(SpvOp opcode) {
+ switch (opcode) {
+ case SpvOpAny:
+ return "any";
+ case SpvOpAll:
+ return "all";
+ case SpvOpIsNan:
+ return "is_nan";
+ case SpvOpIsInf:
+ return "is_inf";
+ default:
+ break;
+ }
+ return nullptr;
+}
+
// Converts a SPIR-V opcode to its corresponding AST binary opcode, if any
// @param opcode SPIR-V opcode
// @returns the AST binary op for the given opcode, or kNone
@@ -2649,6 +2668,16 @@
arg0.type);
}
+ const char* unary_builtin_name = GetUnaryBuiltInFunctionName(opcode);
+ if (unary_builtin_name != nullptr) {
+ ast::ExpressionList params;
+ params.emplace_back(MakeOperand(inst, 0).expr);
+ return {ast_type,
+ std::make_unique<ast::CallExpression>(
+ std::make_unique<ast::IdentifierExpression>(unary_builtin_name),
+ std::move(params))};
+ }
+
if (opcode == SpvOpAccessChain || opcode == SpvOpInBoundsAccessChain) {
return MakeAccessChain(inst);
}
diff --git a/src/reader/spirv/function_logical_test.cc b/src/reader/spirv/function_logical_test.cc
index 8f4272c..24793d1 100644
--- a/src/reader/spirv/function_logical_test.cc
+++ b/src/reader/spirv/function_logical_test.cc
@@ -1279,10 +1279,198 @@
})")) << ToString(fe.ast_body());
}
-// TODO(dneto): OpAny - likely builtin function TBD
-// TODO(dneto): OpAll - likely builtin function TBD
-// TODO(dneto): OpIsNan - likely builtin function TBD
-// TODO(dneto): OpIsInf - likely builtin function TBD
+using SpvLogicalTest = SpvParserTestBase<::testing::Test>;
+
+TEST_F(SpvLogicalTest, Any) {
+ const auto assembly = CommonTypes() + R"(
+ %100 = OpFunction %void None %voidfn
+ %entry = OpLabel
+ %1 = OpAny %bool %v2bool_t_f
+ OpReturn
+ OpFunctionEnd
+ )";
+ auto* p = parser(test::Assemble(assembly));
+ ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+ FunctionEmitter fe(p, *spirv_function(100));
+ EXPECT_TRUE(fe.EmitBody()) << p->error();
+ EXPECT_THAT(ToString(fe.ast_body()), HasSubstr(R"(VariableDeclStatement{
+ Variable{
+ x_1
+ none
+ __bool
+ {
+ Call{
+ Identifier{any}
+ (
+ TypeConstructor{
+ __vec_2__bool
+ ScalarConstructor{true}
+ ScalarConstructor{false}
+ }
+ )
+ }
+ }
+ }
+})")) << ToString(fe.ast_body());
+}
+
+TEST_F(SpvLogicalTest, All) {
+ const auto assembly = CommonTypes() + R"(
+ %100 = OpFunction %void None %voidfn
+ %entry = OpLabel
+ %1 = OpAll %bool %v2bool_t_f
+ OpReturn
+ OpFunctionEnd
+ )";
+ auto* p = parser(test::Assemble(assembly));
+ ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+ FunctionEmitter fe(p, *spirv_function(100));
+ EXPECT_TRUE(fe.EmitBody()) << p->error();
+ EXPECT_THAT(ToString(fe.ast_body()), HasSubstr(R"(VariableDeclStatement{
+ Variable{
+ x_1
+ none
+ __bool
+ {
+ Call{
+ Identifier{all}
+ (
+ TypeConstructor{
+ __vec_2__bool
+ ScalarConstructor{true}
+ ScalarConstructor{false}
+ }
+ )
+ }
+ }
+ }
+})")) << ToString(fe.ast_body());
+}
+
+TEST_F(SpvLogicalTest, IsNan_Scalar) {
+ const auto assembly = CommonTypes() + R"(
+ %100 = OpFunction %void None %voidfn
+ %entry = OpLabel
+ %1 = OpIsNan %bool %float_50
+ OpReturn
+ OpFunctionEnd
+ )";
+ auto* p = parser(test::Assemble(assembly));
+ ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+ FunctionEmitter fe(p, *spirv_function(100));
+ EXPECT_TRUE(fe.EmitBody()) << p->error();
+ EXPECT_THAT(ToString(fe.ast_body()), HasSubstr(R"(VariableDeclStatement{
+ Variable{
+ x_1
+ none
+ __bool
+ {
+ Call{
+ Identifier{is_nan}
+ (
+ ScalarConstructor{50.000000}
+ )
+ }
+ }
+ }
+})")) << ToString(fe.ast_body());
+}
+
+TEST_F(SpvLogicalTest, IsNan_Vector) {
+ const auto assembly = CommonTypes() + R"(
+ %100 = OpFunction %void None %voidfn
+ %entry = OpLabel
+ %1 = OpIsNan %v2bool %v2float_50_60
+ OpReturn
+ OpFunctionEnd
+ )";
+ auto* p = parser(test::Assemble(assembly));
+ ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+ FunctionEmitter fe(p, *spirv_function(100));
+ EXPECT_TRUE(fe.EmitBody()) << p->error();
+ EXPECT_THAT(ToString(fe.ast_body()), HasSubstr(R"(VariableDeclStatement{
+ Variable{
+ x_1
+ none
+ __vec_2__bool
+ {
+ Call{
+ Identifier{is_nan}
+ (
+ TypeConstructor{
+ __vec_2__f32
+ ScalarConstructor{50.000000}
+ ScalarConstructor{60.000000}
+ }
+ )
+ }
+ }
+ }
+})")) << ToString(fe.ast_body());
+}
+
+TEST_F(SpvLogicalTest, IsInf_Scalar) {
+ const auto assembly = CommonTypes() + R"(
+ %100 = OpFunction %void None %voidfn
+ %entry = OpLabel
+ %1 = OpIsInf %bool %float_50
+ OpReturn
+ OpFunctionEnd
+ )";
+ auto* p = parser(test::Assemble(assembly));
+ ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+ FunctionEmitter fe(p, *spirv_function(100));
+ EXPECT_TRUE(fe.EmitBody()) << p->error();
+ EXPECT_THAT(ToString(fe.ast_body()), HasSubstr(R"(VariableDeclStatement{
+ Variable{
+ x_1
+ none
+ __bool
+ {
+ Call{
+ Identifier{is_inf}
+ (
+ ScalarConstructor{50.000000}
+ )
+ }
+ }
+ }
+})")) << ToString(fe.ast_body());
+}
+
+TEST_F(SpvLogicalTest, IsInf_Vector) {
+ const auto assembly = CommonTypes() + R"(
+ %100 = OpFunction %void None %voidfn
+ %entry = OpLabel
+ %1 = OpIsInf %v2bool %v2float_50_60
+ OpReturn
+ OpFunctionEnd
+ )";
+ auto* p = parser(test::Assemble(assembly));
+ ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+ FunctionEmitter fe(p, *spirv_function(100));
+ EXPECT_TRUE(fe.EmitBody()) << p->error();
+ EXPECT_THAT(ToString(fe.ast_body()), HasSubstr(R"(VariableDeclStatement{
+ Variable{
+ x_1
+ none
+ __vec_2__bool
+ {
+ Call{
+ Identifier{is_inf}
+ (
+ TypeConstructor{
+ __vec_2__f32
+ ScalarConstructor{50.000000}
+ ScalarConstructor{60.000000}
+ }
+ )
+ }
+ }
+ }
+})")) << ToString(fe.ast_body());
+}
+
// TODO(dneto): Kernel-guarded instructions.
// TODO(dneto): OpSelect over more general types, as in SPIR-V 1.4