spirv-reader: handle OpUndef at module scope

Fixed: tint:523
Change-Id: I47639c8f701ca049c7215874cdea27f86d8a415b
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/43760
Auto-Submit: David Neto <dneto@google.com>
Commit-Queue: David Neto <dneto@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
This commit is contained in:
David Neto 2021-03-03 19:58:04 +00:00 committed by Commit Bot service account
parent 5a13258981
commit ec44eef965
4 changed files with 161 additions and 1 deletions

View File

@ -2091,6 +2091,13 @@ TypedExpression FunctionEmitter::MakeExpression(uint32_t id) {
create<ast::IdentifierExpression>( create<ast::IdentifierExpression>(
Source{}, builder_.Symbols().Register(name))}; Source{}, builder_.Symbols().Register(name))};
} }
case SpvOpUndef:
// Substitute a null value for undef.
// This case occurs when OpUndef appears at module scope, as if it were
// a constant.
return parser_impl_.MakeNullExpression(
parser_impl_.ConvertType(inst->type_id()));
default: default:
break; break;
} }
@ -3294,7 +3301,7 @@ TypedExpression FunctionEmitter::MaybeEmitCombinatorialValue(
if (opcode == SpvOpUndef) { if (opcode == SpvOpUndef) {
// Replace undef with the null value. // Replace undef with the null value.
return {ast_type, parser_impl_.MakeNullValue(ast_type)}; return parser_impl_.MakeNullExpression(ast_type);
} }
if (opcode == SpvOpSelect) { if (opcode == SpvOpSelect) {

View File

@ -40,6 +40,7 @@ std::string CommonTypes() {
%int = OpTypeInt 32 1 %int = OpTypeInt 32 1
%float = OpTypeFloat 32 %float = OpTypeFloat 32
%v2bool = OpTypeVector %bool 2
%v2uint = OpTypeVector %uint 2 %v2uint = OpTypeVector %uint 2
%v2int = OpTypeVector %int 2 %v2int = OpTypeVector %int 2
%v2float = OpTypeVector %float 2 %v2float = OpTypeVector %float 2
@ -48,6 +49,149 @@ std::string CommonTypes() {
using SpvParserTestMiscInstruction = SpvParserTest; using SpvParserTestMiscInstruction = SpvParserTest;
TEST_F(SpvParserTestMiscInstruction, OpUndef_BeforeFunction_Scalar) {
const auto assembly = CommonTypes() + R"(
%1 = OpUndef %bool
%2 = OpUndef %uint
%3 = OpUndef %int
%4 = OpUndef %float
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%11 = OpCopyObject %bool %1
%12 = OpCopyObject %uint %2
%13 = OpCopyObject %int %3
%14 = OpCopyObject %float %4
OpReturn
OpFunctionEnd
)";
auto p = parser(test::Assemble(assembly));
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
FunctionEmitter fe(p.get(), *spirv_function(p.get(), 100));
EXPECT_TRUE(fe.EmitBody()) << p->error();
EXPECT_THAT(ToString(p->builder(), fe.ast_body()),
HasSubstr(R"(VariableDeclStatement{
VariableConst{
x_11
none
__bool
{
ScalarConstructor[not set]{false}
}
}
}
VariableDeclStatement{
VariableConst{
x_12
none
__u32
{
ScalarConstructor[not set]{0}
}
}
}
VariableDeclStatement{
VariableConst{
x_13
none
__i32
{
ScalarConstructor[not set]{0}
}
}
}
VariableDeclStatement{
VariableConst{
x_14
none
__f32
{
ScalarConstructor[not set]{0.000000}
}
}
})")) << ToString(p->builder(), fe.ast_body());
}
TEST_F(SpvParserTestMiscInstruction, OpUndef_BeforeFunction_Vector) {
const auto assembly = CommonTypes() + R"(
%4 = OpUndef %v2bool
%1 = OpUndef %v2uint
%2 = OpUndef %v2int
%3 = OpUndef %v2float
%100 = OpFunction %void None %voidfn
%entry = OpLabel
%14 = OpCopyObject %v2uint %4
%11 = OpCopyObject %v2uint %1
%12 = OpCopyObject %v2int %2
%13 = OpCopyObject %v2float %3
OpReturn
OpFunctionEnd
)";
auto p = parser(test::Assemble(assembly));
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
FunctionEmitter fe(p.get(), *spirv_function(p.get(), 100));
EXPECT_TRUE(fe.EmitBody()) << p->error();
EXPECT_THAT(ToString(p->builder(), fe.ast_body()),
HasSubstr(R"(VariableDeclStatement{
VariableConst{
x_14
none
__vec_2__bool
{
TypeConstructor[not set]{
__vec_2__bool
ScalarConstructor[not set]{false}
ScalarConstructor[not set]{false}
}
}
}
}
VariableDeclStatement{
VariableConst{
x_11
none
__vec_2__u32
{
TypeConstructor[not set]{
__vec_2__u32
ScalarConstructor[not set]{0}
ScalarConstructor[not set]{0}
}
}
}
}
VariableDeclStatement{
VariableConst{
x_12
none
__vec_2__i32
{
TypeConstructor[not set]{
__vec_2__i32
ScalarConstructor[not set]{0}
ScalarConstructor[not set]{0}
}
}
}
}
VariableDeclStatement{
VariableConst{
x_13
none
__vec_2__f32
{
TypeConstructor[not set]{
__vec_2__f32
ScalarConstructor[not set]{0.000000}
ScalarConstructor[not set]{0.000000}
}
}
}
})")) << ToString(p->builder(), fe.ast_body());
}
TEST_F(SpvParserTestMiscInstruction, OpUndef_InFunction_Scalar) { TEST_F(SpvParserTestMiscInstruction, OpUndef_InFunction_Scalar) {
const auto assembly = CommonTypes() + R"( const auto assembly = CommonTypes() + R"(
%100 = OpFunction %void None %voidfn %100 = OpFunction %void None %voidfn

View File

@ -1538,6 +1538,10 @@ ast::Expression* ParserImpl::MakeNullValue(type::Type* type) {
return nullptr; return nullptr;
} }
TypedExpression ParserImpl::MakeNullExpression(type::Type* type) {
return {type, MakeNullValue(type)};
}
TypedExpression ParserImpl::RectifyOperandSignedness( TypedExpression ParserImpl::RectifyOperandSignedness(
const spvtools::opt::Instruction& inst, const spvtools::opt::Instruction& inst,
TypedExpression&& expr) { TypedExpression&& expr) {

View File

@ -326,6 +326,11 @@ class ParserImpl : Reader {
/// @returns a new expression /// @returns a new expression
ast::Expression* MakeNullValue(type::Type* type); ast::Expression* MakeNullValue(type::Type* type);
/// Make a typed expression for the null value for the given type.
/// @param type the AST type
/// @returns a new typed expression
TypedExpression MakeNullExpression(type::Type* type);
/// Converts a given expression to the signedness demanded for an operand /// Converts a given expression to the signedness demanded for an operand
/// of the given SPIR-V instruction, if required. If the instruction assumes /// of the given SPIR-V instruction, if required. If the instruction assumes
/// signed integer operands, and `expr` is unsigned, then return an /// signed integer operands, and `expr` is unsigned, then return an