From b6f02999647db41f79e79fc61afe4f94f6f99239 Mon Sep 17 00:00:00 2001 From: David Neto Date: Wed, 22 Jul 2020 12:58:31 +0000 Subject: [PATCH] [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 --- src/reader/spirv/function.cc | 29 ++++ src/reader/spirv/function_logical_test.cc | 196 +++++++++++++++++++++- 2 files changed, 221 insertions(+), 4 deletions(-) diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc index 66f5c1c29a..3e547f9a2a 100644 --- a/src/reader/spirv/function.cc +++ b/src/reader/spirv/function.cc @@ -191,6 +191,25 @@ bool GetUnaryOp(SpvOp opcode, ast::UnaryOp* ast_unary_op) { 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 @@ TypedExpression FunctionEmitter::MaybeEmitCombinatorialValue( 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( + std::make_unique(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 8f4272c1f3..24793d1270 100644 --- a/src/reader/spirv/function_logical_test.cc +++ b/src/reader/spirv/function_logical_test.cc @@ -1279,10 +1279,198 @@ TEST_F(SpvFUnordTest, Select_VecBoolCond_VectorParams) { })")) << 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