tint/writer/spirv: Add path for generating from IR

This adds a GeneratorImplIr class and an option to the SPIR-V writer
to use it instead of the AST-based GeneratorImpl class.

The Tint exe now has a --use-ir flag which will use this path.

Bug: tint:1906
Change-Id: I34cc5c7468c8faf4a808669da8c44551ad01da8f
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/131341
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: James Price <jrprice@google.com>
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
This commit is contained in:
James Price 2023-05-04 01:31:36 +00:00 committed by Dawn LUCI CQ
parent 1164fe7475
commit 8f9ea96c20
10 changed files with 231 additions and 18 deletions

View File

@ -974,6 +974,17 @@ libtint_source_set("libtint_spv_writer_src") {
":libtint_utils_src",
":libtint_writer_src",
]
if (tint_build_ir) {
sources += [
"writer/spirv/generator_impl_ir.cc",
"writer/spirv/generator_impl_ir.h",
]
deps += [
":libtint_ir_builder_src",
":libtint_ir_src",
]
}
}
libtint_source_set("libtint_wgsl_reader_src") {
@ -1845,6 +1856,11 @@ if (tint_build_unittests) {
":tint_unittests_ast_src",
"${tint_spirv_tools_dir}/:spvtools",
]
if (tint_build_ir) {
sources += [ "writer/spirv/generator_impl_ir_test.cc" ]
deps += [ ":libtint_ir_src" ]
}
}
tint_unittests_source_set("tint_unittests_wgsl_reader_src") {

View File

@ -650,6 +650,13 @@ if(${TINT_BUILD_SPV_WRITER})
writer/spirv/operand.h
writer/spirv/scalar_constant.h
)
if(${TINT_BUILD_IR})
list(APPEND TINT_LIB_SRCS
writer/spirv/generator_impl_ir.cc
writer/spirv/generator_impl_ir.h
)
endif()
endif()
if(${TINT_BUILD_WGSL_WRITER})
@ -1217,6 +1224,12 @@ if(TINT_BUILD_TESTS)
writer/spirv/spv_dump.h
writer/spirv/test_helper.h
)
if(${TINT_BUILD_IR})
list(APPEND TINT_TEST_SRCS
writer/spirv/generator_impl_ir_test.cc
)
endif()
endif()
if(${TINT_BUILD_WGSL_WRITER})

View File

@ -111,6 +111,7 @@ struct Options {
#if TINT_BUILD_IR
bool dump_ir = false;
bool dump_ir_graph = false;
bool use_ir = false;
#endif // TINT_BUILD_IR
#if TINT_BUILD_SYNTAX_TREE_WRITER
@ -388,6 +389,8 @@ bool ParseArgs(const std::vector<std::string>& args, Options* opts) {
opts->dump_ir = true;
} else if (arg == "--dump-ir-graph") {
opts->dump_ir_graph = true;
} else if (arg == "--use-ir") {
opts->use_ir = true;
#endif // TINT_BUILD_IR
#if TINT_BUILD_SYNTAX_TREE_WRITER
} else if (arg == "--dump-ast") {
@ -548,6 +551,9 @@ bool GenerateSpirv(const tint::Program* program, const Options& options) {
gen_options.disable_workgroup_init = options.disable_workgroup_init;
gen_options.external_texture_options.bindings_map =
tint::cmd::GenerateExternalTextureBindings(program);
#if TINT_BUILD_IR
gen_options.use_tint_ir = options.use_ir;
#endif
auto result = tint::writer::spirv::Generate(program, gen_options);
if (!result.success) {
tint::cmd::PrintWGSL(std::cerr, *program);
@ -1023,7 +1029,8 @@ int main(int argc, const char** argv) {
#if TINT_BUILD_IR
usage +=
" --dump-ir -- Writes the IR to stdout\n"
" --dump-ir-graph -- Writes the IR graph to 'tint.dot' as a dot graph\n";
" --dump-ir-graph -- Writes the IR graph to 'tint.dot' as a dot graph\n"
" --use-ir -- Use the IR for writers and transforms when possible\n";
#endif // TINT_BUILD_IR
#if TINT_BUILD_SYNTAX_TREE_WRITER
usage += " --dump-ast -- Writes the AST to stdout\n";

View File

@ -17,6 +17,10 @@
#include <utility>
#include "src/tint/writer/spirv/generator_impl.h"
#if TINT_BUILD_IR
#include "src/tint/ir/converter.h" // nogncheck
#include "src/tint/writer/spirv/generator_impl_ir.h" // nogncheck
#endif // TINT_BUILD_IR
namespace tint::writer::spirv {
@ -31,23 +35,41 @@ Result Generate(const Program* program, const Options& options) {
return result;
}
// Sanitize the program.
auto sanitized_result = Sanitize(program, options);
if (!sanitized_result.program.IsValid()) {
result.success = false;
result.error = sanitized_result.program.Diagnostics().str();
return result;
}
// Generate the SPIR-V code.
bool zero_initialize_workgroup_memory =
!options.disable_workgroup_init && options.use_zero_initialize_workgroup_memory_extension;
auto impl = std::make_unique<GeneratorImpl>(&sanitized_result.program,
zero_initialize_workgroup_memory);
result.success = impl->Generate();
result.error = impl->Diagnostics().str();
result.spirv = std::move(impl->Result());
#if TINT_BUILD_IR
if (options.use_tint_ir) {
// Convert the AST program to an IR module.
auto ir = ir::Converter::FromProgram(program);
if (!ir) {
result.error = "IR converter: " + ir.Failure();
return result;
}
// Generate the SPIR-V code.
auto impl = std::make_unique<GeneratorImplIr>(&ir.Get(), zero_initialize_workgroup_memory);
result.success = impl->Generate();
result.error = impl->Diagnostics().str();
result.spirv = std::move(impl->Result());
} else // NOLINT(readability/braces)
#endif
{
// Sanitize the program.
auto sanitized_result = Sanitize(program, options);
if (!sanitized_result.program.IsValid()) {
result.success = false;
result.error = sanitized_result.program.Diagnostics().str();
return result;
}
// Generate the SPIR-V code.
auto impl = std::make_unique<GeneratorImpl>(&sanitized_result.program,
zero_initialize_workgroup_memory);
result.success = impl->Generate();
result.error = impl->Diagnostics().str();
result.spirv = std::move(impl->Result());
}
return result;
}

View File

@ -60,6 +60,11 @@ struct Options {
/// VK_KHR_zero_initialize_workgroup_memory is enabled.
bool use_zero_initialize_workgroup_memory_extension = false;
#if TINT_BUILD_IR
/// Set to `true` to generate SPIR-V via the Tint IR instead of from the AST.
bool use_tint_ir = false;
#endif
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
TINT_REFLECT(disable_robustness,
emit_vertex_point_size,

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.
#include "src/tint/writer/spirv/generator_impl_ir.h"
#include "spirv/unified1/spirv.h"
#include "src/tint/ir/module.h"
#include "src/tint/writer/spirv/module.h"
namespace tint::writer::spirv {
GeneratorImplIr::GeneratorImplIr(const ir::Module* module, bool zero_init_workgroup_mem)
: ir_(module), zero_init_workgroup_memory_(zero_init_workgroup_mem) {}
bool GeneratorImplIr::Generate() {
// TODO(crbug.com/tint/1906): Check supported extensions.
module_.PushCapability(SpvCapabilityShader);
module_.PushMemoryModel(spv::Op::OpMemoryModel, {U32Operand(SpvAddressingModelLogical),
U32Operand(SpvMemoryModelGLSL450)});
// TODO(crbug.com/tint/1906): Emit extensions.
// TODO(crbug.com/tint/1906): Emit variables.
(void)zero_init_workgroup_memory_;
// TODO(crbug.com/tint/1906): Emit functions.
(void)ir_;
// Serialize the module into binary SPIR-V.
writer_.WriteHeader(module_.IdBound());
writer_.WriteModule(&module_);
return true;
}
} // namespace tint::writer::spirv

View File

@ -0,0 +1,63 @@
// 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_GENERATOR_IMPL_IR_H_
#define SRC_TINT_WRITER_SPIRV_GENERATOR_IMPL_IR_H_
#include <vector>
#include "src/tint/diagnostic/diagnostic.h"
#include "src/tint/writer/spirv/binary_writer.h"
#include "src/tint/writer/spirv/module.h"
// Forward declarations
namespace tint::ir {
class Module;
} // namespace tint::ir
namespace tint::writer::spirv {
/// Implementation class for SPIR-V generator
class GeneratorImplIr {
public:
/// Constructor
/// @param module the Tint IR module to generate
/// @param zero_init_workgroup_memory `true` to initialize all the variables in the Workgroup
/// storage class with OpConstantNull
GeneratorImplIr(const ir::Module* module, bool zero_init_workgroup_memory);
/// @returns true on successful generation; false otherwise
bool Generate();
/// @returns the module that this generator has produced
spirv::Module& Module() { return module_; }
/// @returns the generated SPIR-V binary data
const std::vector<uint32_t>& Result() const { return writer_.result(); }
/// @returns the list of diagnostics raised by the generator
diag::List Diagnostics() const { return diagnostics_; }
private:
const ir::Module* ir_;
spirv::Module module_;
BinaryWriter writer_;
diag::List diagnostics_;
bool zero_init_workgroup_memory_ = false;
};
} // namespace tint::writer::spirv
#endif // SRC_TINT_WRITER_SPIRV_GENERATOR_IMPL_IR_H_

View File

@ -0,0 +1,37 @@
// 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 "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"
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());
EXPECT_EQ(got, R"(OpCapability Shader
OpMemoryModel Logical GLSL450
)");
}
} // namespace
} // namespace tint::writer::spirv

View File

@ -18,7 +18,6 @@
#include "src/tint/writer/spirv/binary_writer.h"
namespace tint::writer::spirv {
namespace {
std::string Disassemble(const std::vector<uint32_t>& data) {
std::string spv_errors;
@ -56,8 +55,6 @@ std::string Disassemble(const std::vector<uint32_t>& data) {
return result;
}
} // namespace
std::string DumpBuilder(Builder& builder) {
BinaryWriter writer;
writer.WriteHeader(builder.Module().IdBound());

View File

@ -22,6 +22,11 @@
namespace tint::writer::spirv {
/// Disassembles SPIR-V binary data into its textual form.
/// @param data the SPIR-V binary data
/// @returns the disassembled SPIR-V string
std::string Disassemble(const std::vector<uint32_t>& data);
/// Dumps the given builder to a SPIR-V disassembly string
/// @param builder the builder to convert
/// @returns the builder as a SPIR-V disassembly string