2021-01-26 16:57:10 +00:00
|
|
|
// Copyright 2021 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/program_builder.h"
|
|
|
|
|
2021-02-03 17:19:59 +00:00
|
|
|
#include "src/ast/assignment_statement.h"
|
2021-03-31 13:26:43 +00:00
|
|
|
#include "src/ast/call_statement.h"
|
2021-02-03 17:19:59 +00:00
|
|
|
#include "src/ast/variable_decl_statement.h"
|
2021-03-31 20:43:26 +00:00
|
|
|
#include "src/debug.h"
|
2021-01-29 11:22:40 +00:00
|
|
|
#include "src/demangler.h"
|
2021-01-29 16:43:41 +00:00
|
|
|
#include "src/semantic/expression.h"
|
2021-01-26 16:57:10 +00:00
|
|
|
|
|
|
|
namespace tint {
|
|
|
|
|
|
|
|
ProgramBuilder::ProgramBuilder()
|
2021-02-17 16:23:52 +00:00
|
|
|
: ast_(ast_nodes_.Create<ast::Module>(Source{})) {}
|
2021-01-26 16:57:10 +00:00
|
|
|
|
|
|
|
ProgramBuilder::ProgramBuilder(ProgramBuilder&& rhs)
|
2021-02-17 16:23:52 +00:00
|
|
|
: types_(std::move(rhs.types_)),
|
2021-01-29 15:17:30 +00:00
|
|
|
ast_nodes_(std::move(rhs.ast_nodes_)),
|
|
|
|
sem_nodes_(std::move(rhs.sem_nodes_)),
|
2021-01-26 16:57:10 +00:00
|
|
|
ast_(rhs.ast_),
|
2021-01-29 10:55:40 +00:00
|
|
|
sem_(std::move(rhs.sem_)),
|
2021-01-26 16:57:10 +00:00
|
|
|
symbols_(std::move(rhs.symbols_)) {
|
|
|
|
rhs.MarkAsMoved();
|
|
|
|
}
|
|
|
|
|
|
|
|
ProgramBuilder::~ProgramBuilder() = default;
|
|
|
|
|
|
|
|
ProgramBuilder& ProgramBuilder::operator=(ProgramBuilder&& rhs) {
|
|
|
|
rhs.MarkAsMoved();
|
|
|
|
AssertNotMoved();
|
|
|
|
types_ = std::move(rhs.types_);
|
2021-01-29 15:17:30 +00:00
|
|
|
ast_nodes_ = std::move(rhs.ast_nodes_);
|
|
|
|
sem_nodes_ = std::move(rhs.sem_nodes_);
|
2021-01-26 16:57:10 +00:00
|
|
|
ast_ = rhs.ast_;
|
2021-01-29 10:55:40 +00:00
|
|
|
sem_ = std::move(rhs.sem_);
|
2021-01-26 16:57:10 +00:00
|
|
|
symbols_ = std::move(rhs.symbols_);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2021-01-29 11:59:32 +00:00
|
|
|
ProgramBuilder ProgramBuilder::Wrap(const Program* program) {
|
|
|
|
ProgramBuilder builder;
|
|
|
|
builder.types_ = type::Manager::Wrap(program->Types());
|
|
|
|
builder.ast_ = builder.create<ast::Module>(
|
2021-02-09 21:39:10 +00:00
|
|
|
program->AST().source(), program->AST().GlobalDeclarations());
|
2021-01-29 11:59:32 +00:00
|
|
|
builder.sem_ = semantic::Info::Wrap(program->Sem());
|
|
|
|
builder.symbols_ = program->Symbols();
|
|
|
|
builder.diagnostics_ = program->Diagnostics();
|
|
|
|
return builder;
|
|
|
|
}
|
|
|
|
|
2021-01-26 16:57:10 +00:00
|
|
|
bool ProgramBuilder::IsValid() const {
|
ast: Replace IsValid() with TINT_ASSERT()
The readers must not produce invalid ASTs.
If readers cannot produce a valid AST, then they should error instead.
If a reader does produce an invalid AST, this change catches this bad behavior early, significantly helping identify the root of the broken logic.
IsValid() made a bit more sense in the days where the AST was mutable, and was constructed by calling setters on the nodes to build up the tree.
In order to detect bad ASTs, IsValid() would have to perform an entire AST traversal and give a yes / no answer for the entire tree. Not only was this slow, an answer of 'no' didn't tell you *where* the AST was invalid, resulting in a lot of manual debugging.
Now that the AST is fully immutable, all child nodes need to be built before their parents. The AST node constructors now become a perfect place to perform pointer sanity checking.
The argument for attempting to catch and handle invalid ASTs is not a compelling one.
Invalid ASTs are invalid compiler behavior, not something that should ever happen with a correctly functioning compiler.
If this were to happen in production, the user would be utterly clueless to _why_ the program is invalid, or _how_ to fix it.
Attempting to handle invalid ASTs is just masking a much larger problem.
Let's just let the fuzzers do their job to catch any of these cases early.
Fixed: chromium:1185569
Change-Id: I6496426a3a9da9d42627d2c1ca23917bfd04cc5c
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/44048
Commit-Queue: Ben Clayton <bclayton@chromium.org>
Reviewed-by: David Neto <dneto@google.com>
2021-03-10 11:41:49 +00:00
|
|
|
return !diagnostics_.contains_errors();
|
2021-01-26 16:57:10 +00:00
|
|
|
}
|
|
|
|
|
2021-01-29 11:22:40 +00:00
|
|
|
std::string ProgramBuilder::str(const ast::Node* node) const {
|
|
|
|
return Demangler().Demangle(Symbols(), node->str(Sem()));
|
|
|
|
}
|
|
|
|
|
2021-01-26 16:57:10 +00:00
|
|
|
void ProgramBuilder::MarkAsMoved() {
|
|
|
|
AssertNotMoved();
|
|
|
|
moved_ = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ProgramBuilder::AssertNotMoved() const {
|
2021-03-31 20:43:26 +00:00
|
|
|
if (moved_) {
|
|
|
|
TINT_ICE(const_cast<ProgramBuilder*>(this)->Diagnostics())
|
|
|
|
<< "Attempting to use ProgramBuilder after it has been moved";
|
|
|
|
}
|
2021-01-26 16:57:10 +00:00
|
|
|
}
|
|
|
|
|
2021-01-29 16:43:41 +00:00
|
|
|
type::Type* ProgramBuilder::TypeOf(ast::Expression* expr) const {
|
|
|
|
auto* sem = Sem().Get(expr);
|
|
|
|
return sem ? sem->Type() : nullptr;
|
|
|
|
}
|
|
|
|
|
2021-03-31 12:46:52 +00:00
|
|
|
ast::ConstructorExpression* ProgramBuilder::ConstructValueFilledWith(
|
|
|
|
type::Type* type,
|
|
|
|
int elem_value) {
|
|
|
|
auto* unwrapped_type = type->UnwrapAliasIfNeeded();
|
|
|
|
if (unwrapped_type->Is<type::Bool>()) {
|
|
|
|
return create<ast::ScalarConstructorExpression>(
|
|
|
|
create<ast::BoolLiteral>(type, elem_value == 0 ? false : true));
|
|
|
|
}
|
|
|
|
if (unwrapped_type->Is<type::I32>()) {
|
|
|
|
return create<ast::ScalarConstructorExpression>(create<ast::SintLiteral>(
|
|
|
|
type, static_cast<ProgramBuilder::i32>(elem_value)));
|
|
|
|
}
|
|
|
|
if (unwrapped_type->Is<type::U32>()) {
|
|
|
|
return create<ast::ScalarConstructorExpression>(create<ast::UintLiteral>(
|
|
|
|
type, static_cast<ProgramBuilder::u32>(elem_value)));
|
|
|
|
}
|
|
|
|
if (unwrapped_type->Is<type::F32>()) {
|
|
|
|
return create<ast::ScalarConstructorExpression>(create<ast::FloatLiteral>(
|
|
|
|
type, static_cast<ProgramBuilder::f32>(elem_value)));
|
|
|
|
}
|
|
|
|
if (auto* v = unwrapped_type->As<type::Vector>()) {
|
|
|
|
auto* elem_default_value = ConstructValueFilledWith(v->type(), elem_value);
|
|
|
|
ast::ExpressionList el(v->size());
|
|
|
|
std::fill(el.begin(), el.end(), elem_default_value);
|
|
|
|
return create<ast::TypeConstructorExpression>(type, std::move(el));
|
|
|
|
}
|
|
|
|
if (auto* m = unwrapped_type->As<type::Matrix>()) {
|
|
|
|
auto* col_vec_type = create<type::Vector>(m->type(), m->rows());
|
|
|
|
auto* vec_default_value =
|
|
|
|
ConstructValueFilledWith(col_vec_type, elem_value);
|
|
|
|
ast::ExpressionList el(m->columns());
|
|
|
|
std::fill(el.begin(), el.end(), vec_default_value);
|
|
|
|
return create<ast::TypeConstructorExpression>(type, std::move(el));
|
|
|
|
}
|
|
|
|
TINT_ASSERT(false);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2021-01-26 16:57:10 +00:00
|
|
|
ProgramBuilder::TypesBuilder::TypesBuilder(ProgramBuilder* pb) : builder(pb) {}
|
|
|
|
|
2021-02-03 17:19:59 +00:00
|
|
|
ast::VariableDeclStatement* ProgramBuilder::WrapInStatement(ast::Variable* v) {
|
|
|
|
return create<ast::VariableDeclStatement>(v);
|
|
|
|
}
|
|
|
|
|
|
|
|
ast::Statement* ProgramBuilder::WrapInStatement(ast::Expression* expr) {
|
2021-03-31 13:26:43 +00:00
|
|
|
// Create a temporary variable of inferred type from expr.
|
|
|
|
return Decl(Var(symbols_.New(), nullptr, ast::StorageClass::kFunction, expr));
|
2021-02-03 17:19:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ast::Statement* ProgramBuilder::WrapInStatement(ast::Statement* stmt) {
|
|
|
|
return stmt;
|
|
|
|
}
|
|
|
|
|
2021-03-19 14:04:51 +00:00
|
|
|
ast::Function* ProgramBuilder::WrapInFunction(ast::StatementList stmts) {
|
2021-04-07 15:54:11 +00:00
|
|
|
return Func("test_function", {}, ty.void_(), std::move(stmts),
|
|
|
|
{create<ast::StageDecoration>(ast::PipelineStage::kCompute)});
|
2021-01-26 16:57:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace tint
|