[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>
This commit is contained in:
David Neto 2020-07-22 12:58:31 +00:00 committed by dan sinclair
parent e3de74fd2b
commit b6f0299964
2 changed files with 221 additions and 4 deletions

View File

@ -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<ast::CallExpression>(
std::make_unique<ast::IdentifierExpression>(unary_builtin_name),
std::move(params))};
}
if (opcode == SpvOpAccessChain || opcode == SpvOpInBoundsAccessChain) {
return MakeAccessChain(inst);
}

View File

@ -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