[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:
parent
21703b9cb5
commit
5e7807f02b
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue