From fd3700c0a71bad3239850874893b7e3fa519aa06 Mon Sep 17 00:00:00 2001 From: David Neto Date: Mon, 22 Jun 2020 20:48:59 +0000 Subject: [PATCH] [spirv-reader] Support Undef, mapping to null Bug: tint:3 Change-Id: I1549f0445c92312b0d20292ff9d60736300d5378 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/23600 Reviewed-by: dan sinclair --- BUILD.gn | 1 + src/CMakeLists.txt | 3 +- src/reader/spirv/function.cc | 8 +- src/reader/spirv/function_misc_test.cc | 286 ++++++++++++++++++ src/reader/spirv/parser_impl.cc | 6 + .../spirv/parser_impl_module_var_test.cc | 229 ++++++++++++++ 6 files changed, 530 insertions(+), 3 deletions(-) create mode 100644 src/reader/spirv/function_misc_test.cc diff --git a/BUILD.gn b/BUILD.gn index bc65b11327..39d66df3d7 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -656,6 +656,7 @@ source_set("tint_unittests_spv_reader_src") { "src/reader/spirv/function_glsl_std_450_test.cc", "src/reader/spirv/function_logical_test.cc", "src/reader/spirv/function_memory_test.cc", + "src/reader/spirv/function_misc_test.cc", "src/reader/spirv/function_var_test.cc", "src/reader/spirv/namer_test.cc", "src/reader/spirv/parser_impl_convert_member_decoration_test.cc", diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e046cda472..6c1138bb00 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -325,8 +325,9 @@ if(${TINT_BUILD_SPV_READER}) reader/spirv/function_decl_test.cc reader/spirv/function_glsl_std_450_test.cc reader/spirv/function_logical_test.cc - reader/spirv/function_var_test.cc reader/spirv/function_memory_test.cc + reader/spirv/function_misc_test.cc + reader/spirv/function_var_test.cc reader/spirv/namer_test.cc reader/spirv/parser_impl_convert_member_decoration_test.cc reader/spirv/parser_impl_convert_type_test.cc diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc index 9d3d5266db..d92862caab 100644 --- a/src/reader/spirv/function.cc +++ b/src/reader/spirv/function.cc @@ -2533,16 +2533,21 @@ TypedExpression FunctionEmitter::MaybeEmitCombinatorialValue( if (opcode == SpvOpVectorShuffle) { return MakeVectorShuffle(inst); } + if (opcode == SpvOpConvertSToF || opcode == SpvOpConvertUToF || opcode == SpvOpConvertFToS || opcode == SpvOpConvertFToU) { return MakeNumericConversion(inst); } + if (opcode == SpvOpUndef) { + // Replace undef with the null value. + return {ast_type, parser_impl_.MakeNullValue(ast_type)}; + } + // builtin readonly function // glsl.std.450 readonly function // Instructions: - // OpUndef // OpSatConvertSToU // Only in Kernel (OpenCL), not in WebGPU // OpSatConvertUToS // Only in Kernel (OpenCL), not in WebGPU // OpUConvert // Only needed when multiple widths supported @@ -2557,7 +2562,6 @@ TypedExpression FunctionEmitter::MaybeEmitCombinatorialValue( // OpArrayLength // OpVectorExtractDynamic // OpVectorInsertDynamic - // OpCompositeExtract // OpCompositeInsert return {}; diff --git a/src/reader/spirv/function_misc_test.cc b/src/reader/spirv/function_misc_test.cc new file mode 100644 index 0000000000..7e1e5f89dd --- /dev/null +++ b/src/reader/spirv/function_misc_test.cc @@ -0,0 +1,286 @@ +// Copyright 2020 The Tint Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include "gmock/gmock.h" +#include "src/reader/spirv/function.h" +#include "src/reader/spirv/parser_impl.h" +#include "src/reader/spirv/parser_impl_test_helper.h" +#include "src/reader/spirv/spirv_tools_helpers_test.h" + +namespace tint { +namespace reader { +namespace spirv { +namespace { + +using ::testing::HasSubstr; + +std::string CommonTypes() { + return R"( + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + + %bool = OpTypeBool + %uint = OpTypeInt 32 0 + %int = OpTypeInt 32 1 + %float = OpTypeFloat 32 + + %v2uint = OpTypeVector %uint 2 + %v2int = OpTypeVector %int 2 + %v2float = OpTypeVector %float 2 +)"; +} + +using SpvParserTestMiscInstruction = SpvParserTest; + +TEST_F(SpvParserTestMiscInstruction, OpUndef_InFunction_Scalar) { + const auto assembly = CommonTypes() + R"( + %100 = OpFunction %void None %voidfn + %entry = OpLabel + %1 = OpUndef %bool + %2 = OpUndef %uint + %3 = OpUndef %int + %4 = OpUndef %float + + %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, *spirv_function(100)); + EXPECT_TRUE(fe.EmitBody()) << p->error(); + EXPECT_THAT(ToString(fe.ast_body()), HasSubstr(R"(VariableDeclStatement{ + Variable{ + x_11 + none + __bool + { + ScalarConstructor{false} + } + } +} +VariableDeclStatement{ + Variable{ + x_12 + none + __u32 + { + ScalarConstructor{0} + } + } +} +VariableDeclStatement{ + Variable{ + x_13 + none + __i32 + { + ScalarConstructor{0} + } + } +} +VariableDeclStatement{ + Variable{ + x_14 + none + __f32 + { + ScalarConstructor{0.000000} + } + } +})")) << ToString(fe.ast_body()); +} + +TEST_F(SpvParserTestMiscInstruction, OpUndef_InFunction_Vector) { + const auto assembly = CommonTypes() + R"( + %100 = OpFunction %void None %voidfn + %entry = OpLabel + %1 = OpUndef %v2uint + %2 = OpUndef %v2int + %3 = OpUndef %v2float + + %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, *spirv_function(100)); + EXPECT_TRUE(fe.EmitBody()) << p->error(); + EXPECT_THAT(ToString(fe.ast_body()), HasSubstr(R"(VariableDeclStatement{ + Variable{ + x_11 + none + __vec_2__u32 + { + TypeConstructor{ + __vec_2__u32 + ScalarConstructor{0} + ScalarConstructor{0} + } + } + } +} +VariableDeclStatement{ + Variable{ + x_12 + none + __vec_2__i32 + { + TypeConstructor{ + __vec_2__i32 + ScalarConstructor{0} + ScalarConstructor{0} + } + } + } +} +VariableDeclStatement{ + Variable{ + x_13 + none + __vec_2__f32 + { + TypeConstructor{ + __vec_2__f32 + ScalarConstructor{0.000000} + ScalarConstructor{0.000000} + } + } + } +})")) << ToString(fe.ast_body()); +} + +TEST_F(SpvParserTestMiscInstruction, OpUndef_InFunction_Matrix) { + const auto assembly = CommonTypes() + R"( + %mat = OpTypeMatrix %v2float 2 + + %100 = OpFunction %void None %voidfn + %entry = OpLabel + %1 = OpUndef %mat + + %11 = OpCopyObject %mat %1 + OpReturn + OpFunctionEnd +)"; + auto* p = parser(test::Assemble(assembly)); + ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly; + FunctionEmitter fe(p, *spirv_function(100)); + EXPECT_TRUE(fe.EmitBody()) << p->error(); + EXPECT_THAT(ToString(fe.ast_body()), HasSubstr(R"(VariableDeclStatement{ + Variable{ + x_11 + none + __mat_2_2__f32 + { + TypeConstructor{ + __mat_2_2__f32 + TypeConstructor{ + __vec_2__f32 + ScalarConstructor{0.000000} + ScalarConstructor{0.000000} + } + TypeConstructor{ + __vec_2__f32 + ScalarConstructor{0.000000} + ScalarConstructor{0.000000} + } + } + } + } +})")) << ToString(fe.ast_body()); +} + +TEST_F(SpvParserTestMiscInstruction, OpUndef_InFunction_Array) { + const auto assembly = CommonTypes() + R"( + %uint_2 = OpConstant %uint 2 + %arr = OpTypeArray %uint %uint_2 + + %100 = OpFunction %void None %voidfn + %entry = OpLabel + %1 = OpUndef %arr + + %11 = OpCopyObject %arr %1 + OpReturn + OpFunctionEnd +)"; + auto* p = parser(test::Assemble(assembly)); + ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly; + FunctionEmitter fe(p, *spirv_function(100)); + EXPECT_TRUE(fe.EmitBody()) << p->error(); + EXPECT_THAT(ToString(fe.ast_body()), HasSubstr(R"(VariableDeclStatement{ + Variable{ + x_11 + none + __array__u32_2 + { + TypeConstructor{ + __array__u32_2 + ScalarConstructor{0} + ScalarConstructor{0} + } + } + } +})")) << ToString(fe.ast_body()); +} + +TEST_F(SpvParserTestMiscInstruction, OpUndef_InFunction_Struct) { + const auto assembly = CommonTypes() + R"( + %strct = OpTypeStruct %bool %uint %int %float + + %100 = OpFunction %void None %voidfn + %entry = OpLabel + %1 = OpUndef %strct + + %11 = OpCopyObject %strct %1 + OpReturn + OpFunctionEnd +)"; + auto* p = parser(test::Assemble(assembly)); + ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly; + FunctionEmitter fe(p, *spirv_function(100)); + EXPECT_TRUE(fe.EmitBody()) << p->error(); + EXPECT_THAT(ToString(fe.ast_body()), HasSubstr(R"(VariableDeclStatement{ + Variable{ + x_11 + none + __alias_S__struct_S + { + TypeConstructor{ + __alias_S__struct_S + ScalarConstructor{false} + ScalarConstructor{0} + ScalarConstructor{0} + ScalarConstructor{0.000000} + } + } + } +})")) << ToString(fe.ast_body()); +} + +// TODO(dneto): OpNop +// TODO(dneto): OpSizeof : requires Kernel (OpenCL) + +} // namespace +} // namespace spirv +} // namespace reader +} // namespace tint diff --git a/src/reader/spirv/parser_impl.cc b/src/reader/spirv/parser_impl.cc index 5d53d6d160..4ad72eeb19 100644 --- a/src/reader/spirv/parser_impl.cc +++ b/src/reader/spirv/parser_impl.cc @@ -890,6 +890,12 @@ TypedExpression ParserImpl::MakeConstantExpression(uint32_t id) { if (original_ast_type == nullptr) { return {}; } + + if (inst->opcode() == SpvOpUndef) { + // Remap undef to null. + return {original_ast_type, MakeNullValue(original_ast_type)}; + } + // TODO(dneto): Handle spec constants too? const auto* spirv_const = constant_mgr_->FindDeclaredConstant(id); if (spirv_const == nullptr) { diff --git a/src/reader/spirv/parser_impl_module_var_test.cc b/src/reader/spirv/parser_impl_module_var_test.cc index ffbe3ccdc6..b0c9d00348 100644 --- a/src/reader/spirv/parser_impl_module_var_test.cc +++ b/src/reader/spirv/parser_impl_module_var_test.cc @@ -293,6 +293,55 @@ TEST_F(SpvParserTest, ModuleScopeVar_ScalarNullInitializers) { })")); } +TEST_F(SpvParserTest, ModuleScopeVar_ScalarUndefInitializers) { + auto* p = parser(test::Assemble(CommonTypes() + R"( + %undef_bool = OpUndef %bool + %undef_int = OpUndef %int + %undef_uint = OpUndef %uint + %undef_float = OpUndef %float + + %1 = OpVariable %ptr_bool Private %undef_bool + %2 = OpVariable %ptr_int Private %undef_int + %3 = OpVariable %ptr_uint Private %undef_uint + %4 = OpVariable %ptr_float Private %undef_float + )")); + ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error(); + EXPECT_TRUE(p->error().empty()); + const auto module_str = p->module().to_str(); + EXPECT_THAT(module_str, HasSubstr(R"(Variable{ + x_1 + private + __bool + { + ScalarConstructor{false} + } + } + Variable{ + x_2 + private + __i32 + { + ScalarConstructor{0} + } + } + Variable{ + x_3 + private + __u32 + { + ScalarConstructor{0} + } + } + Variable{ + x_4 + private + __f32 + { + ScalarConstructor{0.000000} + } + })")); +} + TEST_F(SpvParserTest, ModuleScopeVar_VectorInitializer) { auto* p = parser(test::Assemble(CommonTypes() + R"( %ptr = OpTypePointer Private %v2float @@ -340,6 +389,29 @@ TEST_F(SpvParserTest, ModuleScopeVar_VectorBoolNullInitializer) { })")); } +TEST_F(SpvParserTest, ModuleScopeVar_VectorBoolUndefInitializer) { + auto* p = parser(test::Assemble(CommonTypes() + R"( + %ptr = OpTypePointer Private %v2bool + %const = OpUndef %v2bool + %200 = OpVariable %ptr Private %const + )")); + ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()); + EXPECT_TRUE(p->error().empty()); + const auto module_str = p->module().to_str(); + EXPECT_THAT(module_str, HasSubstr(R"(Variable{ + x_200 + private + __vec_2__bool + { + TypeConstructor{ + __vec_2__bool + ScalarConstructor{false} + ScalarConstructor{false} + } + } + })")); +} + TEST_F(SpvParserTest, ModuleScopeVar_VectorUintNullInitializer) { auto* p = parser(test::Assemble(CommonTypes() + R"( %ptr = OpTypePointer Private %v2uint @@ -363,6 +435,29 @@ TEST_F(SpvParserTest, ModuleScopeVar_VectorUintNullInitializer) { })")); } +TEST_F(SpvParserTest, ModuleScopeVar_VectorUintUndefInitializer) { + auto* p = parser(test::Assemble(CommonTypes() + R"( + %ptr = OpTypePointer Private %v2uint + %const = OpUndef %v2uint + %200 = OpVariable %ptr Private %const + )")); + ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()); + EXPECT_TRUE(p->error().empty()); + const auto module_str = p->module().to_str(); + EXPECT_THAT(module_str, HasSubstr(R"(Variable{ + x_200 + private + __vec_2__u32 + { + TypeConstructor{ + __vec_2__u32 + ScalarConstructor{0} + ScalarConstructor{0} + } + } + })")); +} + TEST_F(SpvParserTest, ModuleScopeVar_VectorIntNullInitializer) { auto* p = parser(test::Assemble(CommonTypes() + R"( %ptr = OpTypePointer Private %v2int @@ -386,6 +481,29 @@ TEST_F(SpvParserTest, ModuleScopeVar_VectorIntNullInitializer) { })")); } +TEST_F(SpvParserTest, ModuleScopeVar_VectorIntUndefInitializer) { + auto* p = parser(test::Assemble(CommonTypes() + R"( + %ptr = OpTypePointer Private %v2int + %const = OpUndef %v2int + %200 = OpVariable %ptr Private %const + )")); + ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()); + EXPECT_TRUE(p->error().empty()); + const auto module_str = p->module().to_str(); + EXPECT_THAT(module_str, HasSubstr(R"(Variable{ + x_200 + private + __vec_2__i32 + { + TypeConstructor{ + __vec_2__i32 + ScalarConstructor{0} + ScalarConstructor{0} + } + } + })")); +} + TEST_F(SpvParserTest, ModuleScopeVar_VectorFloatNullInitializer) { auto* p = parser(test::Assemble(CommonTypes() + R"( %ptr = OpTypePointer Private %v2float @@ -409,6 +527,29 @@ TEST_F(SpvParserTest, ModuleScopeVar_VectorFloatNullInitializer) { })")); } +TEST_F(SpvParserTest, ModuleScopeVar_VectorFloatUndefInitializer) { + auto* p = parser(test::Assemble(CommonTypes() + R"( + %ptr = OpTypePointer Private %v2float + %const = OpUndef %v2float + %200 = OpVariable %ptr Private %const + )")); + ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()); + EXPECT_TRUE(p->error().empty()); + const auto module_str = p->module().to_str(); + EXPECT_THAT(module_str, HasSubstr(R"(Variable{ + x_200 + private + __vec_2__f32 + { + TypeConstructor{ + __vec_2__f32 + ScalarConstructor{0.000000} + ScalarConstructor{0.000000} + } + } + })")); +} + TEST_F(SpvParserTest, ModuleScopeVar_MatrixInitializer) { auto* p = parser(test::Assemble(CommonTypes() + R"( %ptr = OpTypePointer Private %m3v2float @@ -487,6 +628,42 @@ TEST_F(SpvParserTest, ModuleScopeVar_MatrixNullInitializer) { })")); } +TEST_F(SpvParserTest, ModuleScopeVar_MatrixUndefInitializer) { + auto* p = parser(test::Assemble(CommonTypes() + R"( + %ptr = OpTypePointer Private %m3v2float + %const = OpUndef %m3v2float + %200 = OpVariable %ptr Private %const + )")); + ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()); + EXPECT_TRUE(p->error().empty()); + const auto module_str = p->module().to_str(); + EXPECT_THAT(module_str, HasSubstr(R"(Variable{ + x_200 + private + __mat_2_3__f32 + { + TypeConstructor{ + __mat_2_3__f32 + TypeConstructor{ + __vec_2__f32 + ScalarConstructor{0.000000} + ScalarConstructor{0.000000} + } + TypeConstructor{ + __vec_2__f32 + ScalarConstructor{0.000000} + ScalarConstructor{0.000000} + } + TypeConstructor{ + __vec_2__f32 + ScalarConstructor{0.000000} + ScalarConstructor{0.000000} + } + } + } + })")); +} + TEST_F(SpvParserTest, ModuleScopeVar_ArrayInitializer) { auto* p = parser(test::Assemble(CommonTypes() + R"( %ptr = OpTypePointer Private %arr2uint @@ -534,6 +711,29 @@ TEST_F(SpvParserTest, ModuleScopeVar_ArrayNullInitializer) { })")); } +TEST_F(SpvParserTest, ModuleScopeVar_ArrayUndefInitializer) { + auto* p = parser(test::Assemble(CommonTypes() + R"( + %ptr = OpTypePointer Private %arr2uint + %const = OpUndef %arr2uint + %200 = OpVariable %ptr Private %const + )")); + ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()); + EXPECT_TRUE(p->error().empty()); + const auto module_str = p->module().to_str(); + EXPECT_THAT(module_str, HasSubstr(R"(Variable{ + x_200 + private + __array__u32_2 + { + TypeConstructor{ + __array__u32_2 + ScalarConstructor{0} + ScalarConstructor{0} + } + } + })")); +} + TEST_F(SpvParserTest, ModuleScopeVar_StructInitializer) { auto* p = parser(test::Assemble(CommonTypes() + R"( %ptr = OpTypePointer Private %strct @@ -594,6 +794,35 @@ TEST_F(SpvParserTest, ModuleScopeVar_StructNullInitializer) { << module_str; } +TEST_F(SpvParserTest, ModuleScopeVar_StructUndefInitializer) { + auto* p = parser(test::Assemble(CommonTypes() + R"( + %ptr = OpTypePointer Private %strct + %const = OpUndef %strct + %200 = OpVariable %ptr Private %const + )")); + ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error(); + EXPECT_TRUE(p->error().empty()); + const auto module_str = p->module().to_str(); + EXPECT_THAT(module_str, HasSubstr(R"(Variable{ + x_200 + private + __alias_S__struct_S + { + TypeConstructor{ + __alias_S__struct_S + ScalarConstructor{0} + ScalarConstructor{0.000000} + TypeConstructor{ + __array__u32_2 + ScalarConstructor{0} + ScalarConstructor{0} + } + } + } + })")) + << module_str; +} + } // namespace } // namespace spirv } // namespace reader