spirv-reader: Substitute 1.0 for scalar normalize

WGSL only has vector normalize, not scalar.
Scalar normalize is always 1.0, so return that directly.

Bug: tint:765
Change-Id: I08332c20922f5834f65284b9aaeb22995423171d
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/50603
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: David Neto <dneto@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
This commit is contained in:
David Neto 2021-05-12 04:35:01 +00:00 committed by Commit Bot service account
parent 32b5018c5d
commit 6344d4c2f5
2 changed files with 127 additions and 3 deletions

View File

@ -3444,6 +3444,17 @@ TypedExpression FunctionEmitter::MaybeEmitCombinatorialValue(
TypedExpression FunctionEmitter::EmitGlslStd450ExtInst( TypedExpression FunctionEmitter::EmitGlslStd450ExtInst(
const spvtools::opt::Instruction& inst) { const spvtools::opt::Instruction& inst) {
const auto ext_opcode = inst.GetSingleWordInOperand(1); const auto ext_opcode = inst.GetSingleWordInOperand(1);
auto* result_type = parser_impl_.ConvertType(inst.type_id());
if ((ext_opcode == GLSLstd450Normalize) && result_type->IsScalar()) {
// WGSL does not have scalar form of the normalize builtin.
// The answer would be 1 anyway, so return that directly.
return {ty_.F32(),
create<ast::ScalarConstructorExpression>(
Source{}, create<ast::FloatLiteral>(Source{}, 1.0f))};
}
const auto name = GetGlslStd450FuncName(ext_opcode); const auto name = GetGlslStd450FuncName(ext_opcode);
if (name.empty()) { if (name.empty()) {
Fail() << "unhandled GLSL.std.450 instruction " << ext_opcode; Fail() << "unhandled GLSL.std.450 instruction " << ext_opcode;
@ -3462,9 +3473,8 @@ TypedExpression FunctionEmitter::EmitGlslStd450ExtInst(
} }
operands.emplace_back(operand.expr); operands.emplace_back(operand.expr);
} }
auto* ast_type = parser_impl_.ConvertType(inst.type_id());
auto* call = create<ast::CallExpression>(Source{}, func, std::move(operands)); auto* call = create<ast::CallExpression>(Source{}, func, std::move(operands));
TypedExpression call_expr{ast_type, call}; TypedExpression call_expr{result_type, call};
return parser_impl_.RectifyForcedResultType(call_expr, inst, return parser_impl_.RectifyForcedResultType(call_expr, inst,
first_operand_type); first_operand_type);
} }

View File

@ -681,7 +681,6 @@ INSTANTIATE_TEST_SUITE_P(Samples,
{"InverseSqrt", "inverseSqrt"}, {"InverseSqrt", "inverseSqrt"},
{"Log", "log"}, {"Log", "log"},
{"Log2", "log2"}, {"Log2", "log2"},
{"Normalize", "normalize"},
{"Round", "round"}, {"Round", "round"},
{"RoundEven", "round"}, {"RoundEven", "round"},
{"Sin", "sin"}, {"Sin", "sin"},
@ -1080,6 +1079,121 @@ INSTANTIATE_TEST_SUITE_P(Samples,
SpvParserTest_GlslStd450_Uinting_UintingUintingUinting, SpvParserTest_GlslStd450_Uinting_UintingUintingUinting,
::testing::Values(GlslStd450Case{"UClamp", "clamp"})); ::testing::Values(GlslStd450Case{"UClamp", "clamp"}));
// Test Normalize. WGSL does not have a scalar form of the normalize builtin.
// So we have to test it separately, as it does not fit the patterns tested
// above.
TEST_F(SpvParserTest, Normalize_Scalar) {
// Scalar normalize always results in 1.0
const auto assembly = Preamble() + R"(
%1 = OpExtInst %float %glsl Normalize %f1
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();
const auto body = ToString(p->builder(), fe.ast_body());
EXPECT_THAT(body, HasSubstr(R"(
VariableConst{
x_1
none
__f32
{
ScalarConstructor[not set]{1.000000}
}
})"))
<< body;
}
TEST_F(SpvParserTest, Normalize_Vector2) {
// Scalar normalize always results in 1.0
const auto assembly = Preamble() + R"(
%1 = OpExtInst %v2float %glsl Normalize %v2f1
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();
const auto body = ToString(p->builder(), fe.ast_body());
EXPECT_THAT(body, HasSubstr(R"(
VariableConst{
x_1
none
__vec_2__f32
{
Call[not set]{
Identifier[not set]{normalize}
(
Identifier[not set]{v2f1}
)
}
}
})"))
<< body;
}
TEST_F(SpvParserTest, Normalize_Vector3) {
// Scalar normalize always results in 1.0
const auto assembly = Preamble() + R"(
%1 = OpExtInst %v3float %glsl Normalize %v3f1
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();
const auto body = ToString(p->builder(), fe.ast_body());
EXPECT_THAT(body, HasSubstr(R"(
VariableConst{
x_1
none
__vec_3__f32
{
Call[not set]{
Identifier[not set]{normalize}
(
Identifier[not set]{v3f1}
)
}
}
})"))
<< body;
}
TEST_F(SpvParserTest, Normalize_Vector4) {
// Scalar normalize always results in 1.0
const auto assembly = Preamble() + R"(
%1 = OpExtInst %v4float %glsl Normalize %v4f1
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();
const auto body = ToString(p->builder(), fe.ast_body());
EXPECT_THAT(body, HasSubstr(R"(
VariableConst{
x_1
none
__vec_4__f32
{
Call[not set]{
Identifier[not set]{normalize}
(
Identifier[not set]{v4f1}
)
}
}
})"))
<< body;
}
// Check that we convert signedness of operands and result type. // Check that we convert signedness of operands and result type.
// This is needed for each of the integer-based extended instructions. // This is needed for each of the integer-based extended instructions.