Split Program into Program and ProgramBuilder

Program is now immutable*, and remains part of the public Tint
interface.

ProgramBuilder is the mutable builder for Programs, and is not part of
the public Tint interface. ast::Builder has been folded into
ProgramBuilder.

Immutable Programs can be cloned into a mutable ProgramBuilder with
Program::CloneAsBuilder().

Mutable ProgramBuilders can be moved into immutable Programs.

* - mostly immutable. It still has a move constructor and move
  assignment operator - required for practical usage - and the
  semantic information on AST nodes is still mutable.

Bug: tint:390
Change-Id: Ia856c50b1880c2f95c91467a9eef5024cbc380c6
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/38240
Reviewed-by: dan sinclair <dsinclair@chromium.org>
This commit is contained in:
Ben Clayton
2021-01-26 16:57:10 +00:00
parent 1f7e18bbc0
commit a6b9a8eb2f
186 changed files with 3324 additions and 2645 deletions

View File

@@ -23,7 +23,6 @@
#include "src/ast/bitcast_expression.h"
#include "src/ast/block_statement.h"
#include "src/ast/break_statement.h"
#include "src/ast/builder.h"
#include "src/ast/call_expression.h"
#include "src/ast/call_statement.h"
#include "src/ast/case_statement.h"
@@ -44,6 +43,7 @@
#include "src/ast/variable.h"
#include "src/ast/variable_decl_statement.h"
#include "src/clone_context.h"
#include "src/program_builder.h"
#include "src/type/array_type.h"
#include "src/type/matrix_type.h"
#include "src/type/u32_type.h"
@@ -56,13 +56,14 @@ BoundArrayAccessors::BoundArrayAccessors() = default;
BoundArrayAccessors::~BoundArrayAccessors() = default;
Transform::Output BoundArrayAccessors::Run(const Program* in) {
Output out;
CloneContext(&out.program, in)
ProgramBuilder out;
diag::List diagnostics;
CloneContext(&out, in)
.ReplaceAll([&](CloneContext* ctx, ast::ArrayAccessorExpression* expr) {
return Transform(expr, ctx, &out.diagnostics);
return Transform(expr, ctx, &diagnostics);
})
.Clone();
return out;
return Output(Program(std::move(out)), std::move(diagnostics));
}
ast::ArrayAccessorExpression* BoundArrayAccessors::Transform(
@@ -75,8 +76,8 @@ ast::ArrayAccessorExpression* BoundArrayAccessors::Transform(
return nullptr;
}
ast::Builder b(ctx->dst);
using u32 = ast::Builder::u32;
ProgramBuilder& b = *ctx->dst;
using u32 = ProgramBuilder::u32;
uint32_t size = 0;
bool is_vec = ret_type->Is<type::Vector>();

View File

@@ -24,6 +24,8 @@
#include "src/ast/scalar_constructor_expression.h"
#include "src/ast/variable.h"
#include "src/clone_context.h"
#include "src/program.h"
#include "src/program_builder.h"
#include "src/type/f32_type.h"
#include "src/type/type_manager.h"
@@ -39,41 +41,39 @@ EmitVertexPointSize::EmitVertexPointSize() = default;
EmitVertexPointSize::~EmitVertexPointSize() = default;
Transform::Output EmitVertexPointSize::Run(const Program* in) {
Output out;
if (!in->AST().Functions().HasStage(ast::PipelineStage::kVertex)) {
// If the module doesn't have any vertex stages, then there's nothing to do.
out.program = in->Clone();
return out;
return Output(Program(in->Clone()));
}
auto* f32 = out.program.create<type::F32>();
ProgramBuilder out;
auto* f32 = out.create<type::F32>();
// Declare the pointsize builtin output variable.
auto* pointsize_var = out.program.create<ast::Variable>(
Source{}, // source
out.program.Symbols().Register(kPointSizeVar), // symbol
ast::StorageClass::kOutput, // storage_class
f32, // type
false, // is_const
nullptr, // constructor
auto* pointsize_var = out.create<ast::Variable>(
Source{}, // source
out.Symbols().Register(kPointSizeVar), // symbol
ast::StorageClass::kOutput, // storage_class
f32, // type
false, // is_const
nullptr, // constructor
ast::VariableDecorationList{
// decorations
out.program.create<ast::BuiltinDecoration>(Source{},
ast::Builtin::kPointSize),
out.create<ast::BuiltinDecoration>(Source{},
ast::Builtin::kPointSize),
});
out.program.AST().AddGlobalVariable(pointsize_var);
out.AST().AddGlobalVariable(pointsize_var);
// Build the AST expression & statement for assigning pointsize one.
auto* one = out.program.create<ast::ScalarConstructorExpression>(
Source{}, out.program.create<ast::FloatLiteral>(Source{}, f32, 1.0f));
auto* pointsize_ident = out.program.create<ast::IdentifierExpression>(
Source{}, out.program.Symbols().Register(kPointSizeVar));
auto* pointsize_assign = out.program.create<ast::AssignmentStatement>(
Source{}, pointsize_ident, one);
auto* one = out.create<ast::ScalarConstructorExpression>(
Source{}, out.create<ast::FloatLiteral>(Source{}, f32, 1.0f));
auto* pointsize_ident = out.create<ast::IdentifierExpression>(
Source{}, out.Symbols().Register(kPointSizeVar));
auto* pointsize_assign =
out.create<ast::AssignmentStatement>(Source{}, pointsize_ident, one);
// Add the pointsize assignment statement to the front of all vertex stages.
CloneContext(&out.program, in)
CloneContext(&out, in)
.ReplaceAll(
[&](CloneContext* ctx, ast::Function* func) -> ast::Function* {
if (func->pipeline_stage() != ast::PipelineStage::kVertex) {
@@ -83,7 +83,7 @@ Transform::Output EmitVertexPointSize::Run(const Program* in) {
})
.Clone();
return out;
return Output(Program(std::move(out)));
}
} // namespace transform

View File

@@ -47,6 +47,8 @@
#include "src/ast/variable_decl_statement.h"
#include "src/ast/variable_decoration.h"
#include "src/clone_context.h"
#include "src/program.h"
#include "src/program_builder.h"
#include "src/type/struct_type.h"
#include "src/type/u32_type.h"
#include "src/type_determiner.h"
@@ -99,15 +101,20 @@ Transform::Output FirstIndexOffset::Run(const Program* in) {
// Running TypeDeterminer as we require local_referenced_builtin_variables()
// to be populated. TODO(bclayton) - it should not be necessary to re-run the
// type determiner if semantic information is already generated. Remove.
// TODO(https://crbug.com/tint/390): Remove this const_cast hack!
TypeDeterminer td(const_cast<Program*>(in));
if (!td.Determine()) {
diag::Diagnostic err;
err.severity = diag::Severity::Error;
err.message = td.error();
Output out;
out.diagnostics.add(std::move(err));
return out;
Program program;
{
ProgramBuilder builder = in->CloneAsBuilder();
TypeDeterminer td(&builder);
if (!td.Determine()) {
diag::Diagnostic err;
err.severity = diag::Severity::Error;
err.message = td.error();
Output out;
out.diagnostics.add(std::move(err));
return out;
}
program = Program(std::move(builder));
in = &program;
}
Symbol vertex_index_sym;
@@ -116,9 +123,9 @@ Transform::Output FirstIndexOffset::Run(const Program* in) {
// Lazilly construct the UniformBuffer on first call to
// maybe_create_buffer_var()
ast::Variable* buffer_var = nullptr;
auto maybe_create_buffer_var = [&](Program* program) {
auto maybe_create_buffer_var = [&](ProgramBuilder* dst) {
if (buffer_var == nullptr) {
buffer_var = AddUniformBuffer(program);
buffer_var = AddUniformBuffer(dst);
}
};
@@ -126,8 +133,8 @@ Transform::Output FirstIndexOffset::Run(const Program* in) {
// add a CreateFirstIndexOffset() statement to each function that uses one of
// these builtins.
Output out;
CloneContext(&out.program, in)
ProgramBuilder out;
CloneContext(&out, in)
.ReplaceAll([&](CloneContext* ctx, ast::Variable* var) -> ast::Variable* {
for (ast::VariableDecoration* dec : var->decorations()) {
if (auto* blt_dec = dec->As<ast::BuiltinDecoration>()) {
@@ -174,7 +181,7 @@ Transform::Output FirstIndexOffset::Run(const Program* in) {
})
.Clone();
return out;
return Output(Program(std::move(out)));
}
bool FirstIndexOffset::HasVertexIndex() {
@@ -195,7 +202,7 @@ uint32_t FirstIndexOffset::GetFirstInstanceOffset() {
return instance_index_offset_;
}
ast::Variable* FirstIndexOffset::AddUniformBuffer(Program* dst) {
ast::Variable* FirstIndexOffset::AddUniformBuffer(ProgramBuilder* dst) {
auto* u32_type = dst->create<type::U32>();
ast::StructMemberList members;
uint32_t offset = 0;
@@ -251,7 +258,7 @@ ast::VariableDeclStatement* FirstIndexOffset::CreateFirstIndexOffset(
const std::string& original_name,
const std::string& field_name,
ast::Variable* buffer_var,
Program* dst) {
ProgramBuilder* dst) {
auto* buffer =
dst->create<ast::IdentifierExpression>(Source{}, buffer_var->symbol());

View File

@@ -89,19 +89,19 @@ class FirstIndexOffset : public Transform {
uint32_t GetFirstInstanceOffset();
private:
/// Adds uniform buffer with firstVertex/Instance to `program`
/// Adds uniform buffer with firstVertex/Instance to the program builder
/// @returns variable of new uniform buffer
ast::Variable* AddUniformBuffer(Program* program);
ast::Variable* AddUniformBuffer(ProgramBuilder* builder);
/// Adds constant with modified original_name builtin to func
/// @param original_name the name of the original builtin used in function
/// @param field_name name of field in firstVertex/Instance buffer
/// @param buffer_var variable of firstVertex/Instance buffer
/// @param program the target program to contain the new ast nodes
/// @param builder the target to contain the new ast nodes
ast::VariableDeclStatement* CreateFirstIndexOffset(
const std::string& original_name,
const std::string& field_name,
ast::Variable* buffer_var,
Program* program);
ProgramBuilder* builder);
uint32_t binding_;
uint32_t group_;

View File

@@ -14,6 +14,7 @@
#include "src/transform/manager.h"
#include "src/program_builder.h"
#include "src/type_determiner.h"
namespace tint {
@@ -35,16 +36,10 @@ Transform::Output Manager::Run(const Program* program) {
program = &out.program;
}
} else {
out.program = program->Clone();
out.program = Program(program->Clone());
}
TypeDeterminer td(&out.program);
if (!td.Determine()) {
diag::Diagnostic err;
err.severity = diag::Severity::Error;
err.message = td.error();
out.diagnostics.add(std::move(err));
}
out.diagnostics.add(TypeDeterminer::Run(&out.program));
return out;
}

View File

@@ -21,6 +21,8 @@
#include <vector>
#include "gtest/gtest.h"
#include "src/program.h"
#include "src/program_builder.h"
#include "src/reader/wgsl/parser.h"
#include "src/transform/manager.h"
#include "src/type_determiner.h"
@@ -46,29 +48,33 @@ class TransformTest : public testing::Test {
return "WGSL reader failed:\n" + parser.error();
}
diag::Formatter::Style style;
style.print_newline_at_end = false;
auto program = parser.program();
TypeDeterminer td(&program);
if (!td.Determine()) {
return "Type determination failed:\n" + td.error();
{
auto diagnostics = TypeDeterminer::Run(&program);
if (diagnostics.contains_errors()) {
return "Type determination failed:\n" +
diag::Formatter(style).format(diagnostics);
}
}
Manager manager;
for (auto& transform : transforms) {
manager.append(std::move(transform));
}
auto result = manager.Run(&program);
{
Manager manager;
for (auto& transform : transforms) {
manager.append(std::move(transform));
}
auto result = manager.Run(&program);
if (result.diagnostics.contains_errors()) {
diag::Formatter::Style style;
style.print_newline_at_end = false;
return "manager().Run() errored:\n" +
diag::Formatter(style).format(result.diagnostics);
if (result.diagnostics.contains_errors()) {
return "manager().Run() errored:\n" +
diag::Formatter(style).format(result.diagnostics);
}
program = std::move(result.program);
}
// Release the source program to ensure there's no uncloned data in result
{ auto tmp = std::move(program); }
writer::wgsl::Generator generator(&result.program);
writer::wgsl::Generator generator(&program);
if (!generator.Generate()) {
return "WGSL writer failed:\n" + generator.error();
}

View File

@@ -17,6 +17,7 @@
#include "src/ast/block_statement.h"
#include "src/ast/function.h"
#include "src/clone_context.h"
#include "src/program_builder.h"
namespace tint {
namespace transform {
@@ -28,12 +29,6 @@ Transform::Output::Output(Program&& p) : program(std::move(p)) {}
Transform::Output::Output(Program&& p, diag::List&& d)
: program(std::move(p)), diagnostics(std::move(d)) {}
Transform::Output::~Output() = default;
Transform::Output::Output(Output&&) = default;
Transform::Output& Transform::Output::operator=(Output&& rhs) = default;
Transform::Transform() = default;
Transform::~Transform() = default;

View File

@@ -47,18 +47,6 @@ class Transform {
/// @param diags the list of diagnostics to move into this Output
Output(Program&& program, diag::List&& diags);
/// Move constructor
/// @param output the output to move into this Output
Output(Output&& output);
/// Destructor
~Output();
/// Move assignment operator
/// @param rhs the Output to move into this Output
/// @returns this Output
Output& operator=(Output&& rhs);
/// The transformed program. May be empty on error.
Program program;
/// Diagnostics raised while running the Transform.

View File

@@ -33,6 +33,8 @@
#include "src/ast/variable.h"
#include "src/ast/variable_decl_statement.h"
#include "src/clone_context.h"
#include "src/program.h"
#include "src/program_builder.h"
#include "src/type/array_type.h"
#include "src/type/f32_type.h"
#include "src/type/i32_type.h"
@@ -101,9 +103,9 @@ Transform::Output VertexPulling::Run(const Program* in) {
// TODO(idanr): Make sure we covered all error cases, to guarantee the
// following stages will pass
Output out;
ProgramBuilder out;
CloneContext ctx(&out.program, in);
CloneContext ctx(&out, in);
State state{ctx, cfg};
state.FindOrInsertVertexIndexIfUsed();
state.FindOrInsertInstanceIndexIfUsed();
@@ -122,7 +124,7 @@ Transform::Output VertexPulling::Run(const Program* in) {
});
ctx.Clone();
return out;
return Output(Program(std::move(out)));
}
VertexPulling::Config::Config() = default;