[ir][spirv-writer] Emit blocks

All instructions are unimplemented, and the only supported branch
target is the function terminator.

No new tests, as this only handles returning from an empty function.

Bug: tint:1906
Change-Id: I05cf5d252d96d37757c3ac1f84b79d0586c36b97
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/132283
Commit-Queue: James Price <jrprice@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
James Price 2023-05-09 22:20:16 +00:00 committed by Dawn LUCI CQ
parent 21703b9cb5
commit 5e7807f02b
3 changed files with 48 additions and 5 deletions

View File

@ -21,6 +21,7 @@ TEST_F(SpvGeneratorImplTest, Function_Empty) {
auto* func = CreateFunction(); auto* func = CreateFunction();
func->name = ir.symbols.Register("foo"); func->name = ir.symbols.Register("foo");
func->return_type = ir.types.Get<type::Void>(); func->return_type = ir.types.Get<type::Void>();
func->start_target->branch.target = func->end_target;
generator_.EmitFunction(func); generator_.EmitFunction(func);
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo" EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
@ -37,6 +38,7 @@ OpFunctionEnd
TEST_F(SpvGeneratorImplTest, Function_DeduplicateType) { TEST_F(SpvGeneratorImplTest, Function_DeduplicateType) {
auto* func = CreateFunction(); auto* func = CreateFunction();
func->return_type = ir.types.Get<type::Void>(); func->return_type = ir.types.Get<type::Void>();
func->start_target->branch.target = func->end_target;
generator_.EmitFunction(func); generator_.EmitFunction(func);
generator_.EmitFunction(func); generator_.EmitFunction(func);
@ -52,6 +54,7 @@ TEST_F(SpvGeneratorImplTest, Function_EntryPoint_Compute) {
func->return_type = ir.types.Get<type::Void>(); func->return_type = ir.types.Get<type::Void>();
func->pipeline_stage = ir::Function::PipelineStage::kCompute; func->pipeline_stage = ir::Function::PipelineStage::kCompute;
func->workgroup_size = {32, 4, 1}; func->workgroup_size = {32, 4, 1};
func->start_target->branch.target = func->end_target;
generator_.EmitFunction(func); generator_.EmitFunction(func);
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpEntryPoint GLCompute %1 "main" EXPECT_EQ(DumpModule(generator_.Module()), R"(OpEntryPoint GLCompute %1 "main"
@ -71,6 +74,7 @@ TEST_F(SpvGeneratorImplTest, Function_EntryPoint_Fragment) {
func->name = ir.symbols.Register("main"); func->name = ir.symbols.Register("main");
func->return_type = ir.types.Get<type::Void>(); func->return_type = ir.types.Get<type::Void>();
func->pipeline_stage = ir::Function::PipelineStage::kFragment; func->pipeline_stage = ir::Function::PipelineStage::kFragment;
func->start_target->branch.target = func->end_target;
generator_.EmitFunction(func); generator_.EmitFunction(func);
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpEntryPoint Fragment %1 "main" EXPECT_EQ(DumpModule(generator_.Module()), R"(OpEntryPoint Fragment %1 "main"
@ -90,6 +94,7 @@ TEST_F(SpvGeneratorImplTest, Function_EntryPoint_Vertex) {
func->name = ir.symbols.Register("main"); func->name = ir.symbols.Register("main");
func->return_type = ir.types.Get<type::Void>(); func->return_type = ir.types.Get<type::Void>();
func->pipeline_stage = ir::Function::PipelineStage::kVertex; func->pipeline_stage = ir::Function::PipelineStage::kVertex;
func->start_target->branch.target = func->end_target;
generator_.EmitFunction(func); generator_.EmitFunction(func);
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpEntryPoint Vertex %1 "main" EXPECT_EQ(DumpModule(generator_.Module()), R"(OpEntryPoint Vertex %1 "main"
@ -109,17 +114,20 @@ TEST_F(SpvGeneratorImplTest, Function_EntryPoint_Multiple) {
f1->return_type = ir.types.Get<type::Void>(); f1->return_type = ir.types.Get<type::Void>();
f1->pipeline_stage = ir::Function::PipelineStage::kCompute; f1->pipeline_stage = ir::Function::PipelineStage::kCompute;
f1->workgroup_size = {32, 4, 1}; f1->workgroup_size = {32, 4, 1};
f1->start_target->branch.target = f1->end_target;
auto* f2 = CreateFunction(); auto* f2 = CreateFunction();
f2->name = ir.symbols.Register("main2"); f2->name = ir.symbols.Register("main2");
f2->return_type = ir.types.Get<type::Void>(); f2->return_type = ir.types.Get<type::Void>();
f2->pipeline_stage = ir::Function::PipelineStage::kCompute; f2->pipeline_stage = ir::Function::PipelineStage::kCompute;
f2->workgroup_size = {8, 2, 16}; f2->workgroup_size = {8, 2, 16};
f2->start_target->branch.target = f2->end_target;
auto* f3 = CreateFunction(); auto* f3 = CreateFunction();
f3->name = ir.symbols.Register("main3"); f3->name = ir.symbols.Register("main3");
f3->return_type = ir.types.Get<type::Void>(); f3->return_type = ir.types.Get<type::Void>();
f3->pipeline_stage = ir::Function::PipelineStage::kFragment; f3->pipeline_stage = ir::Function::PipelineStage::kFragment;
f3->start_target->branch.target = f3->end_target;
generator_.EmitFunction(f1); generator_.EmitFunction(f1);
generator_.EmitFunction(f2); generator_.EmitFunction(f2);

View File

@ -15,6 +15,8 @@
#include "src/tint/writer/spirv/generator_impl_ir.h" #include "src/tint/writer/spirv/generator_impl_ir.h"
#include "spirv/unified1/spirv.h" #include "spirv/unified1/spirv.h"
#include "src/tint/ir/block.h"
#include "src/tint/ir/function_terminator.h"
#include "src/tint/ir/module.h" #include "src/tint/ir/module.h"
#include "src/tint/switch.h" #include "src/tint/switch.h"
#include "src/tint/type/bool.h" #include "src/tint/type/bool.h"
@ -150,12 +152,11 @@ void GeneratorImplIr::EmitFunction(const ir::Function* func) {
// Create a function that we will add instructions to. // Create a function that we will add instructions to.
// TODO(jrprice): Add the parameter declarations when they are supported in the IR. // TODO(jrprice): Add the parameter declarations when they are supported in the IR.
auto entry_block = module_.NextId(); auto entry_block = module_.NextId();
Function current_function_(decl, entry_block, {}); current_function_ = Function(decl, entry_block, {});
TINT_DEFER(current_function_ = Function());
// TODO(jrprice): Emit the body of the function. // Emit the body of the function.
EmitBlock(func->start_target);
// TODO(jrprice): Remove this when we start emitting OpReturn for branches to the terminator.
current_function_.push_inst(spv::Op::OpReturn, {});
// Add the function to the module. // Add the function to the module.
module_.PushFunction(current_function_); module_.PushFunction(current_function_);
@ -192,4 +193,26 @@ void GeneratorImplIr::EmitEntryPoint(const ir::Function* func, uint32_t id) {
module_.PushEntryPoint(spv::Op::OpEntryPoint, {U32Operand(stage), id, func->name.Name()}); module_.PushEntryPoint(spv::Op::OpEntryPoint, {U32Operand(stage), id, func->name.Name()});
} }
void GeneratorImplIr::EmitBlock(const ir::Block* block) {
// Emit the instructions.
for (auto* inst : block->instructions) {
auto result = Switch(inst, //
[&](Default) {
TINT_ICE(Writer, diagnostics_)
<< "unimplemented instruction: " << inst->TypeInfo().name;
return 0u;
});
instructions_.Add(inst, result);
}
// Handle the branch at the end of the block.
Switch(
block->branch.target,
[&](const ir::FunctionTerminator*) {
// TODO(jrprice): Handle the return value, which will be a branch argument.
current_function_.push_inst(spv::Op::OpReturn, {});
},
[&](Default) { TINT_ICE(Writer, diagnostics_) << "unimplemented branch target"; });
}
} // namespace tint::writer::spirv } // namespace tint::writer::spirv

View File

@ -23,10 +23,12 @@
#include "src/tint/utils/hashmap.h" #include "src/tint/utils/hashmap.h"
#include "src/tint/utils/vector.h" #include "src/tint/utils/vector.h"
#include "src/tint/writer/spirv/binary_writer.h" #include "src/tint/writer/spirv/binary_writer.h"
#include "src/tint/writer/spirv/function.h"
#include "src/tint/writer/spirv/module.h" #include "src/tint/writer/spirv/module.h"
// Forward declarations // Forward declarations
namespace tint::ir { namespace tint::ir {
class Block;
class Function; class Function;
class Module; class Module;
} // namespace tint::ir } // namespace tint::ir
@ -76,6 +78,10 @@ class GeneratorImplIr {
/// @param id the result ID of the function declaration /// @param id the result ID of the function declaration
void EmitEntryPoint(const ir::Function* func, uint32_t id); void EmitEntryPoint(const ir::Function* func, uint32_t id);
/// Emit a block.
/// @param block the block to emit
void EmitBlock(const ir::Block* block);
private: private:
const ir::Module* ir_; const ir::Module* ir_;
spirv::Module module_; spirv::Module module_;
@ -135,6 +141,12 @@ class GeneratorImplIr {
/// The map of constants to their result IDs. /// The map of constants to their result IDs.
utils::Hashmap<const ir::Constant*, uint32_t, 16, ConstantHasher, ConstantEquals> constants_; utils::Hashmap<const ir::Constant*, uint32_t, 16, ConstantHasher, ConstantEquals> constants_;
/// The map of instructions to their result IDs.
utils::Hashmap<const ir::Instruction*, uint32_t, 8> instructions_;
/// The current function that is being emitted.
Function current_function_;
bool zero_init_workgroup_memory_ = false; bool zero_init_workgroup_memory_ = false;
}; };