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 <jrprice@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
This commit is contained in:
James Price 2023-05-04 18:50:49 +00:00 committed by Dawn LUCI CQ
parent b169165633
commit 02b5b224e3
7 changed files with 190 additions and 12 deletions

View File

@ -1858,7 +1858,10 @@ if (tint_build_unittests) {
] ]
if (tint_build_ir) { 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" ] deps += [ ":libtint_ir_src" ]
} }
} }

View File

@ -1228,6 +1228,8 @@ if(TINT_BUILD_TESTS)
if(${TINT_BUILD_IR}) if(${TINT_BUILD_IR})
list(APPEND TINT_TEST_SRCS list(APPEND TINT_TEST_SRCS
writer/spirv/generator_impl_ir_test.cc writer/spirv/generator_impl_ir_test.cc
writer/spirv/generator_impl_type_test.cc
writer/spirv/test_helper_ir.h
) )
endif() endif()
endif() endif()

View File

@ -16,6 +16,14 @@
#include "spirv/unified1/spirv.h" #include "spirv/unified1/spirv.h"
#include "src/tint/ir/module.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" #include "src/tint/writer/spirv/module.h"
namespace tint::writer::spirv { namespace tint::writer::spirv {
@ -45,4 +53,30 @@ bool GeneratorImplIr::Generate() {
return true; 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 } // namespace tint::writer::spirv

View File

@ -18,6 +18,7 @@
#include <vector> #include <vector>
#include "src/tint/diagnostic/diagnostic.h" #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/binary_writer.h"
#include "src/tint/writer/spirv/module.h" #include "src/tint/writer/spirv/module.h"
@ -25,6 +26,9 @@
namespace tint::ir { namespace tint::ir {
class Module; class Module;
} // namespace tint::ir } // namespace tint::ir
namespace tint::type {
class Type;
} // namespace tint::type
namespace tint::writer::spirv { namespace tint::writer::spirv {
@ -49,12 +53,20 @@ class GeneratorImplIr {
/// @returns the list of diagnostics raised by the generator /// @returns the list of diagnostics raised by the generator
diag::List Diagnostics() const { return diagnostics_; } 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: private:
const ir::Module* ir_; const ir::Module* ir_;
spirv::Module module_; spirv::Module module_;
BinaryWriter writer_; BinaryWriter writer_;
diag::List diagnostics_; diag::List diagnostics_;
/// The map of types to their result IDs.
utils::Hashmap<const type::Type*, uint32_t, 8> types_;
bool zero_init_workgroup_memory_ = false; bool zero_init_workgroup_memory_ = false;
}; };

View File

@ -12,22 +12,14 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "gtest/gtest.h" #include "src/tint/writer/spirv/test_helper_ir.h"
#include "src/tint/ir/module.h"
#include "src/tint/writer/spirv/generator_impl_ir.h"
#include "src/tint/writer/spirv/spv_dump.h"
namespace tint::writer::spirv { namespace tint::writer::spirv {
namespace { namespace {
using SpvGeneratorImplTest = testing::Test;
TEST_F(SpvGeneratorImplTest, ModuleHeader) { TEST_F(SpvGeneratorImplTest, ModuleHeader) {
ir::Module module; ASSERT_TRUE(generator_.Generate()) << generator_.Diagnostics().str();
GeneratorImplIr generator(&module, false); auto got = Disassemble(generator_.Result());
ASSERT_TRUE(generator.Generate()) << generator.Diagnostics().str();
auto got = Disassemble(generator.Result());
EXPECT_EQ(got, R"(OpCapability Shader EXPECT_EQ(got, R"(OpCapability Shader
OpMemoryModel Logical GLSL450 OpMemoryModel Logical GLSL450
)"); )");

View File

@ -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<type::Void>());
EXPECT_EQ(id, 1u);
EXPECT_EQ(DumpTypes(), "%1 = OpTypeVoid\n");
}
TEST_F(SpvGeneratorImplTest, Type_Bool) {
auto id = generator_.Type(ir.types.Get<type::Bool>());
EXPECT_EQ(id, 1u);
EXPECT_EQ(DumpTypes(), "%1 = OpTypeBool\n");
}
TEST_F(SpvGeneratorImplTest, Type_I32) {
auto id = generator_.Type(ir.types.Get<type::I32>());
EXPECT_EQ(id, 1u);
EXPECT_EQ(DumpTypes(), "%1 = OpTypeInt 32 1\n");
}
TEST_F(SpvGeneratorImplTest, Type_U32) {
auto id = generator_.Type(ir.types.Get<type::U32>());
EXPECT_EQ(id, 1u);
EXPECT_EQ(DumpTypes(), "%1 = OpTypeInt 32 0\n");
}
TEST_F(SpvGeneratorImplTest, Type_F32) {
auto id = generator_.Type(ir.types.Get<type::F32>());
EXPECT_EQ(id, 1u);
EXPECT_EQ(DumpTypes(), "%1 = OpTypeFloat 32\n");
}
TEST_F(SpvGeneratorImplTest, Type_F16) {
auto id = generator_.Type(ir.types.Get<type::F16>());
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<type::I32>()), 1u);
EXPECT_EQ(generator_.Type(ir.types.Get<type::U32>()), 2u);
EXPECT_EQ(generator_.Type(ir.types.Get<type::F32>()), 3u);
EXPECT_EQ(generator_.Type(ir.types.Get<type::F16>()), 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<type::I32>();
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

View File

@ -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 <string>
#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 <typename BASE>
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<testing::Test>;
template <typename T>
using SpvGeneratorImplTestWithParam = SpvGeneratorTestHelperBase<testing::TestWithParam<T>>;
} // namespace tint::writer::spirv
#endif // SRC_TINT_WRITER_SPIRV_TEST_HELPER_IR_H_