From 02b5b224e3d1591f9b9f7d53ec46779c90ecba7d Mon Sep 17 00:00:00 2001 From: James Price Date: Thu, 4 May 2023 18:50:49 +0000 Subject: [PATCH] ir/spirv-writer: Add support for scalar types Also add a test helper header with some base classes that derive from the IR builder. Bug: tint:1906 Change-Id: If642bc64a50b6cae10363018a8dea8547ab9f542 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/131441 Commit-Queue: James Price Kokoro: Kokoro Reviewed-by: Dan Sinclair --- src/tint/BUILD.gn | 5 +- src/tint/CMakeLists.txt | 2 + src/tint/writer/spirv/generator_impl_ir.cc | 34 ++++++++ src/tint/writer/spirv/generator_impl_ir.h | 12 +++ .../writer/spirv/generator_impl_ir_test.cc | 14 +-- .../writer/spirv/generator_impl_type_test.cc | 87 +++++++++++++++++++ src/tint/writer/spirv/test_helper_ir.h | 48 ++++++++++ 7 files changed, 190 insertions(+), 12 deletions(-) create mode 100644 src/tint/writer/spirv/generator_impl_type_test.cc create mode 100644 src/tint/writer/spirv/test_helper_ir.h diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn index e3fed4d568..a866575e56 100644 --- a/src/tint/BUILD.gn +++ b/src/tint/BUILD.gn @@ -1858,7 +1858,10 @@ if (tint_build_unittests) { ] if (tint_build_ir) { - sources += [ "writer/spirv/generator_impl_ir_test.cc" ] + sources += [ + "writer/spirv/generator_impl_ir_test.cc", + "writer/spirv/generator_impl_type_test.cc", + ] deps += [ ":libtint_ir_src" ] } } diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt index d0cf092e0d..daafbb45c4 100644 --- a/src/tint/CMakeLists.txt +++ b/src/tint/CMakeLists.txt @@ -1228,6 +1228,8 @@ if(TINT_BUILD_TESTS) if(${TINT_BUILD_IR}) list(APPEND TINT_TEST_SRCS writer/spirv/generator_impl_ir_test.cc + writer/spirv/generator_impl_type_test.cc + writer/spirv/test_helper_ir.h ) endif() endif() diff --git a/src/tint/writer/spirv/generator_impl_ir.cc b/src/tint/writer/spirv/generator_impl_ir.cc index 23842b6c33..fabb3a9164 100644 --- a/src/tint/writer/spirv/generator_impl_ir.cc +++ b/src/tint/writer/spirv/generator_impl_ir.cc @@ -16,6 +16,14 @@ #include "spirv/unified1/spirv.h" #include "src/tint/ir/module.h" +#include "src/tint/switch.h" +#include "src/tint/type/bool.h" +#include "src/tint/type/f16.h" +#include "src/tint/type/f32.h" +#include "src/tint/type/i32.h" +#include "src/tint/type/type.h" +#include "src/tint/type/u32.h" +#include "src/tint/type/void.h" #include "src/tint/writer/spirv/module.h" namespace tint::writer::spirv { @@ -45,4 +53,30 @@ bool GeneratorImplIr::Generate() { return true; } +uint32_t GeneratorImplIr::Type(const type::Type* ty) { + return types_.GetOrCreate(ty, [&]() { + auto id = module_.NextId(); + Switch( + ty, // + [&](const type::Void*) { module_.PushType(spv::Op::OpTypeVoid, {id}); }, + [&](const type::Bool*) { module_.PushType(spv::Op::OpTypeBool, {id}); }, + [&](const type::I32*) { + module_.PushType(spv::Op::OpTypeInt, {id, 32u, 1u}); + }, + [&](const type::U32*) { + module_.PushType(spv::Op::OpTypeInt, {id, 32u, 0u}); + }, + [&](const type::F32*) { + module_.PushType(spv::Op::OpTypeFloat, {id, 32u}); + }, + [&](const type::F16*) { + module_.PushType(spv::Op::OpTypeFloat, {id, 16u}); + }, + [&](Default) { + TINT_ICE(Writer, diagnostics_) << "unhandled type: " << ty->FriendlyName(); + }); + return id; + }); +} + } // namespace tint::writer::spirv diff --git a/src/tint/writer/spirv/generator_impl_ir.h b/src/tint/writer/spirv/generator_impl_ir.h index 7da1184fb4..44fefb5d53 100644 --- a/src/tint/writer/spirv/generator_impl_ir.h +++ b/src/tint/writer/spirv/generator_impl_ir.h @@ -18,6 +18,7 @@ #include #include "src/tint/diagnostic/diagnostic.h" +#include "src/tint/utils/hashmap.h" #include "src/tint/writer/spirv/binary_writer.h" #include "src/tint/writer/spirv/module.h" @@ -25,6 +26,9 @@ namespace tint::ir { class Module; } // namespace tint::ir +namespace tint::type { +class Type; +} // namespace tint::type namespace tint::writer::spirv { @@ -49,12 +53,20 @@ class GeneratorImplIr { /// @returns the list of diagnostics raised by the generator diag::List Diagnostics() const { return diagnostics_; } + /// Get the result ID of the type `ty`, emitting a type declaration instruction if necessary. + /// @param ty the type to get the ID for + /// @returns the result ID of the type + uint32_t Type(const type::Type* ty); + private: const ir::Module* ir_; spirv::Module module_; BinaryWriter writer_; diag::List diagnostics_; + /// The map of types to their result IDs. + utils::Hashmap types_; + bool zero_init_workgroup_memory_ = false; }; diff --git a/src/tint/writer/spirv/generator_impl_ir_test.cc b/src/tint/writer/spirv/generator_impl_ir_test.cc index 8e8f8e76c4..a202eeae91 100644 --- a/src/tint/writer/spirv/generator_impl_ir_test.cc +++ b/src/tint/writer/spirv/generator_impl_ir_test.cc @@ -12,22 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "gtest/gtest.h" - -#include "src/tint/ir/module.h" -#include "src/tint/writer/spirv/generator_impl_ir.h" -#include "src/tint/writer/spirv/spv_dump.h" +#include "src/tint/writer/spirv/test_helper_ir.h" namespace tint::writer::spirv { namespace { -using SpvGeneratorImplTest = testing::Test; - TEST_F(SpvGeneratorImplTest, ModuleHeader) { - ir::Module module; - GeneratorImplIr generator(&module, false); - ASSERT_TRUE(generator.Generate()) << generator.Diagnostics().str(); - auto got = Disassemble(generator.Result()); + ASSERT_TRUE(generator_.Generate()) << generator_.Diagnostics().str(); + auto got = Disassemble(generator_.Result()); EXPECT_EQ(got, R"(OpCapability Shader OpMemoryModel Logical GLSL450 )"); diff --git a/src/tint/writer/spirv/generator_impl_type_test.cc b/src/tint/writer/spirv/generator_impl_type_test.cc new file mode 100644 index 0000000000..c8a2e8e6b2 --- /dev/null +++ b/src/tint/writer/spirv/generator_impl_type_test.cc @@ -0,0 +1,87 @@ +// Copyright 2023 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 "src/tint/type/bool.h" +#include "src/tint/type/f16.h" +#include "src/tint/type/f32.h" +#include "src/tint/type/i32.h" +#include "src/tint/type/type.h" +#include "src/tint/type/u32.h" +#include "src/tint/type/void.h" +#include "src/tint/writer/spirv/test_helper_ir.h" + +namespace tint::writer::spirv { +namespace { + +TEST_F(SpvGeneratorImplTest, Type_Void) { + auto id = generator_.Type(ir.types.Get()); + EXPECT_EQ(id, 1u); + EXPECT_EQ(DumpTypes(), "%1 = OpTypeVoid\n"); +} + +TEST_F(SpvGeneratorImplTest, Type_Bool) { + auto id = generator_.Type(ir.types.Get()); + EXPECT_EQ(id, 1u); + EXPECT_EQ(DumpTypes(), "%1 = OpTypeBool\n"); +} + +TEST_F(SpvGeneratorImplTest, Type_I32) { + auto id = generator_.Type(ir.types.Get()); + EXPECT_EQ(id, 1u); + EXPECT_EQ(DumpTypes(), "%1 = OpTypeInt 32 1\n"); +} + +TEST_F(SpvGeneratorImplTest, Type_U32) { + auto id = generator_.Type(ir.types.Get()); + EXPECT_EQ(id, 1u); + EXPECT_EQ(DumpTypes(), "%1 = OpTypeInt 32 0\n"); +} + +TEST_F(SpvGeneratorImplTest, Type_F32) { + auto id = generator_.Type(ir.types.Get()); + EXPECT_EQ(id, 1u); + EXPECT_EQ(DumpTypes(), "%1 = OpTypeFloat 32\n"); +} + +TEST_F(SpvGeneratorImplTest, Type_F16) { + auto id = generator_.Type(ir.types.Get()); + EXPECT_EQ(id, 1u); + EXPECT_EQ(DumpTypes(), "%1 = OpTypeFloat 16\n"); +} + +// Test that we do can emit multiple types. +// Includes types with the same opcode but different parameters. +TEST_F(SpvGeneratorImplTest, Type_Multiple) { + EXPECT_EQ(generator_.Type(ir.types.Get()), 1u); + EXPECT_EQ(generator_.Type(ir.types.Get()), 2u); + EXPECT_EQ(generator_.Type(ir.types.Get()), 3u); + EXPECT_EQ(generator_.Type(ir.types.Get()), 4u); + EXPECT_EQ(DumpTypes(), R"(%1 = OpTypeInt 32 1 +%2 = OpTypeInt 32 0 +%3 = OpTypeFloat 32 +%4 = OpTypeFloat 16 +)"); +} + +// Test that we do not emit the same type more than once. +TEST_F(SpvGeneratorImplTest, Type_Deduplicate) { + auto* i32 = ir.types.Get(); + EXPECT_EQ(generator_.Type(i32), 1u); + EXPECT_EQ(generator_.Type(i32), 1u); + EXPECT_EQ(generator_.Type(i32), 1u); + EXPECT_EQ(DumpTypes(), "%1 = OpTypeInt 32 1\n"); +} + +} // namespace +} // namespace tint::writer::spirv diff --git a/src/tint/writer/spirv/test_helper_ir.h b/src/tint/writer/spirv/test_helper_ir.h new file mode 100644 index 0000000000..6de6f48ce6 --- /dev/null +++ b/src/tint/writer/spirv/test_helper_ir.h @@ -0,0 +1,48 @@ +// Copyright 2023 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. + +#ifndef SRC_TINT_WRITER_SPIRV_TEST_HELPER_IR_H_ +#define SRC_TINT_WRITER_SPIRV_TEST_HELPER_IR_H_ + +#include + +#include "gtest/gtest.h" +#include "src/tint/ir/builder.h" +#include "src/tint/writer/spirv/generator_impl_ir.h" +#include "src/tint/writer/spirv/spv_dump.h" + +namespace tint::writer::spirv { + +/// Base helper class for testing the SPIR-V generator implementation. +template +class SpvGeneratorTestHelperBase : public ir::Builder, public BASE { + public: + SpvGeneratorTestHelperBase() : generator_(&ir, false) {} + + protected: + /// The SPIR-V generator. + GeneratorImplIr generator_; + + /// @returns the disassembled types from the generated module. + std::string DumpTypes() { return DumpInstructions(generator_.Module().Types()); } +}; + +using SpvGeneratorImplTest = SpvGeneratorTestHelperBase; + +template +using SpvGeneratorImplTestWithParam = SpvGeneratorTestHelperBase>; + +} // namespace tint::writer::spirv + +#endif // SRC_TINT_WRITER_SPIRV_TEST_HELPER_IR_H_