ast: Add Module.Clone()
Deep-clones all `Node`s and `Type`s into a new module. Instead of writing a million standalone tests that'll only ever test the existing fields of each type, I've opted to write the tests using wgsl<->ast<->wgsl conversion. This means the tests require the enabling of TINT_BUILD_WGSL_READER and TINT_BUILD_WGSL_WRITER, but I believe this is much easier to maintain. I'm aware there are probably gaps in the tests, and that even full coverage is likely to rapidly rot, so I've also added fuzzers/tint_ast_clone_fuzzer.cc - a fuzzer based test that ensures that all AST modules can be cloned with identical reproduction. I've run this across 100 cores of a 3990x for 4 hours, fixing the single issue it detected. Note: Expressions do not currently clone their `TypeManager` determined types. This is for two reasons: (a) This initial CL is mahoosive enough. (b) I'm uncertain whether we actually want to clone this info, or to re-run the `TypeDeterminer` after each AST transform. Maybe it should be optional. Time will tell. Fixed: tint:307 Change-Id: Id90fab06aaa740c805d12b66f3f11d1f452c6805 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/33300 Commit-Queue: Ben Clayton <bclayton@google.com> Reviewed-by: dan sinclair <dsinclair@chromium.org> Reviewed-by: David Neto <dneto@google.com>
This commit is contained in:
parent
f1b0e1ee57
commit
ed2b97811e
14
BUILD.gn
14
BUILD.gn
|
@ -251,6 +251,8 @@ source_set("libtint_core_src") {
|
|||
"src/ast/call_statement.h",
|
||||
"src/ast/case_statement.cc",
|
||||
"src/ast/case_statement.h",
|
||||
"src/ast/clone_context.cc",
|
||||
"src/ast/clone_context.h",
|
||||
"src/ast/constant_id_decoration.cc",
|
||||
"src/ast/constant_id_decoration.h",
|
||||
"src/ast/constructor_expression.cc",
|
||||
|
@ -772,6 +774,7 @@ source_set("tint_unittests_core_src") {
|
|||
"src/ast/loop_statement_test.cc",
|
||||
"src/ast/member_accessor_expression_test.cc",
|
||||
"src/ast/module_test.cc",
|
||||
"src/ast/module_clone_test.cc",
|
||||
"src/ast/null_literal_test.cc",
|
||||
"src/ast/return_statement_test.cc",
|
||||
"src/ast/scalar_constructor_expression_test.cc",
|
||||
|
@ -1309,6 +1312,17 @@ if (build_with_chromium) {
|
|||
]
|
||||
}
|
||||
}
|
||||
|
||||
if (tint_build_wgsl_reader && tint_build_wgsl_writer) {
|
||||
fuzzer_test("tint_spv_reader_fuzzer") {
|
||||
sources = [ "fuzzers/tint_ast_clone_fuzzer.cc" ]
|
||||
deps = [
|
||||
":libtint_wgsl_reader_src",
|
||||
":libtint_wgsl_writer_src",
|
||||
":tint_fuzzer_common",
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
|
|
|
@ -28,7 +28,7 @@ endif()
|
|||
|
||||
option(TINT_BUILD_DOCS "Build documentation" ON)
|
||||
option(TINT_BUILD_SPV_READER "Build the SPIR-V input reader" ON)
|
||||
option(TINT_BUILD_WGSL_READER "Builde the WGSL input reader" ON)
|
||||
option(TINT_BUILD_WGSL_READER "Build the WGSL input reader" ON)
|
||||
option(TINT_BUILD_HLSL_WRITER "Build the HLSL output writer" ON)
|
||||
option(TINT_BUILD_MSL_WRITER "Build the MSL output writer" ON)
|
||||
option(TINT_BUILD_SPV_WRITER "Build the SPIR-V output writer" ON)
|
||||
|
|
|
@ -26,3 +26,7 @@ endif()
|
|||
if (${TINT_BUILD_SPV_READER})
|
||||
add_tint_fuzzer(tint_spv_reader_fuzzer)
|
||||
endif()
|
||||
|
||||
if (${TINT_BUILD_WGSL_READER} AND ${TINT_BUILD_WGSL_WRITER})
|
||||
add_tint_fuzzer(tint_ast_clone_fuzzer)
|
||||
endif()
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
// Copyright 2020 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 <iostream>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "src/reader/wgsl/parser_impl.h"
|
||||
#include "src/writer/wgsl/generator.h"
|
||||
|
||||
#define ASSERT_EQ(A, B) \
|
||||
do { \
|
||||
decltype(A) assert_a = (A); \
|
||||
decltype(B) assert_b = (B); \
|
||||
if (assert_a != assert_b) { \
|
||||
std::cerr << "ASSERT_EQ(" #A ", " #B ") failed:\n" \
|
||||
<< #A << " was: " << assert_a << "\n" \
|
||||
<< #B << " was: " << assert_b << "\n"; \
|
||||
__builtin_trap(); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define ASSERT_TRUE(A) \
|
||||
do { \
|
||||
decltype(A) assert_a = (A); \
|
||||
if (!assert_a) { \
|
||||
std::cerr << "ASSERT_TRUE(" #A ") failed:\n" \
|
||||
<< #A << " was: " << assert_a << "\n"; \
|
||||
__builtin_trap(); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
std::string str(reinterpret_cast<const char*>(data), size);
|
||||
|
||||
tint::Source::File file("test.wgsl", str);
|
||||
|
||||
// Parse the wgsl, create the src module
|
||||
tint::Context ctx;
|
||||
tint::reader::wgsl::ParserImpl parser(&ctx, &file);
|
||||
parser.set_max_errors(1);
|
||||
if (!parser.Parse()) {
|
||||
return 0;
|
||||
}
|
||||
auto src = parser.module();
|
||||
|
||||
// Clone the src module to dst
|
||||
auto dst = src.Clone();
|
||||
|
||||
// Expect the AST printed with to_str() to match
|
||||
ASSERT_EQ(src.to_str(), dst.to_str());
|
||||
|
||||
// Check that none of the AST nodes or type pointers in dst are found in src
|
||||
std::unordered_set<tint::ast::Node*> src_nodes;
|
||||
for (auto& src_node : src.nodes()) {
|
||||
src_nodes.emplace(src_node.get());
|
||||
}
|
||||
std::unordered_set<tint::ast::type::Type*> src_types;
|
||||
for (auto& src_type : src.types()) {
|
||||
src_types.emplace(src_type.second.get());
|
||||
}
|
||||
for (auto& dst_node : dst.nodes()) {
|
||||
ASSERT_EQ(src_nodes.count(dst_node.get()), 0u);
|
||||
}
|
||||
for (auto& dst_type : dst.types()) {
|
||||
ASSERT_EQ(src_types.count(dst_type.second.get()), 0u);
|
||||
}
|
||||
|
||||
// Regenerate the wgsl for the src module. We use this instead of the original
|
||||
// source so that reformatting doesn't impact the final wgsl comparision.
|
||||
// Note that the src module is moved into the generator and this generator has
|
||||
// a limited scope, so that the src module is released before we attempt to
|
||||
// print the dst module.
|
||||
// This guarantee that all the source module nodes and types are destructed
|
||||
// and freed.
|
||||
// ASAN should error if there's any remaining references in dst when we try to
|
||||
// reconstruct the WGSL.
|
||||
std::string src_wgsl;
|
||||
{
|
||||
tint::writer::wgsl::Generator src_gen(std::move(src));
|
||||
ASSERT_TRUE(src_gen.Generate());
|
||||
src_wgsl = src_gen.result();
|
||||
}
|
||||
|
||||
// Print the dst module, check it matches the original source
|
||||
tint::writer::wgsl::Generator dst_gen(std::move(dst));
|
||||
ASSERT_TRUE(dst_gen.Generate());
|
||||
auto dst_wgsl = dst_gen.result();
|
||||
ASSERT_EQ(src_wgsl, dst_wgsl);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -72,6 +72,8 @@ set(TINT_LIB_SRCS
|
|||
ast/call_statement.h
|
||||
ast/case_statement.cc
|
||||
ast/case_statement.h
|
||||
ast/clone_context.cc
|
||||
ast/clone_context.h
|
||||
ast/constant_id_decoration.cc
|
||||
ast/constant_id_decoration.h
|
||||
ast/constructor_expression.cc
|
||||
|
@ -381,6 +383,7 @@ set(TINT_TEST_SRCS
|
|||
ast/loop_statement_test.cc
|
||||
ast/member_accessor_expression_test.cc
|
||||
ast/module_test.cc
|
||||
ast/module_clone_test.cc
|
||||
ast/null_literal_test.cc
|
||||
ast/binary_expression_test.cc
|
||||
ast/return_statement_test.cc
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "src/ast/access_decoration.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
|
@ -27,5 +30,9 @@ void AccessDecoration::to_str(std::ostream& out, size_t indent) const {
|
|||
out << "AccessDecoration{" << value_ << "}" << std::endl;
|
||||
}
|
||||
|
||||
AccessDecoration* AccessDecoration::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<AccessDecoration>(value_, ctx->Clone(source()));
|
||||
}
|
||||
|
||||
} // namespace ast
|
||||
} // namespace tint
|
||||
|
|
|
@ -40,6 +40,14 @@ class AccessDecoration : public Castable<AccessDecoration, TypeDecoration> {
|
|||
/// @param indent number of spaces to indent the node when writing
|
||||
void to_str(std::ostream& out, size_t indent) const override;
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
AccessDecoration* Clone(CloneContext* ctx) const override;
|
||||
|
||||
private:
|
||||
AccessControl value_ = ast::AccessControl::kReadWrite;
|
||||
};
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "src/ast/array_accessor_expression.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
|
@ -33,6 +36,12 @@ ArrayAccessorExpression::ArrayAccessorExpression(ArrayAccessorExpression&&) =
|
|||
|
||||
ArrayAccessorExpression::~ArrayAccessorExpression() = default;
|
||||
|
||||
ArrayAccessorExpression* ArrayAccessorExpression::Clone(
|
||||
CloneContext* ctx) const {
|
||||
return ctx->mod->create<ArrayAccessorExpression>(ctx->Clone(array_),
|
||||
ctx->Clone(idx_expr_));
|
||||
}
|
||||
|
||||
bool ArrayAccessorExpression::IsValid() const {
|
||||
if (array_ == nullptr || !array_->IsValid())
|
||||
return false;
|
||||
|
|
|
@ -57,6 +57,14 @@ class ArrayAccessorExpression
|
|||
/// @returns the index expression
|
||||
Expression* idx_expr() const { return idx_expr_; }
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
ArrayAccessorExpression* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "src/ast/assignment_statement.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
|
@ -31,6 +34,11 @@ AssignmentStatement::AssignmentStatement(AssignmentStatement&&) = default;
|
|||
|
||||
AssignmentStatement::~AssignmentStatement() = default;
|
||||
|
||||
AssignmentStatement* AssignmentStatement::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<AssignmentStatement>(
|
||||
ctx->Clone(source()), ctx->Clone(lhs_), ctx->Clone(rhs_));
|
||||
}
|
||||
|
||||
bool AssignmentStatement::IsValid() const {
|
||||
if (lhs_ == nullptr || !lhs_->IsValid())
|
||||
return false;
|
||||
|
|
|
@ -55,6 +55,14 @@ class AssignmentStatement : public Castable<AssignmentStatement, Statement> {
|
|||
/// @returns the right side expression
|
||||
Expression* rhs() const { return rhs_; }
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
AssignmentStatement* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "src/ast/binary_expression.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
|
@ -34,6 +37,11 @@ BinaryExpression::BinaryExpression(BinaryExpression&&) = default;
|
|||
|
||||
BinaryExpression::~BinaryExpression() = default;
|
||||
|
||||
BinaryExpression* BinaryExpression::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<BinaryExpression>(ctx->Clone(source()), op_,
|
||||
ctx->Clone(lhs_), ctx->Clone(rhs_));
|
||||
}
|
||||
|
||||
bool BinaryExpression::IsValid() const {
|
||||
if (lhs_ == nullptr || !lhs_->IsValid()) {
|
||||
return false;
|
||||
|
|
|
@ -125,6 +125,14 @@ class BinaryExpression : public Castable<BinaryExpression, Expression> {
|
|||
/// @returns the right side expression
|
||||
Expression* rhs() const { return rhs_; }
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
BinaryExpression* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "src/ast/binding_decoration.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
|
@ -27,5 +30,9 @@ void BindingDecoration::to_str(std::ostream& out, size_t indent) const {
|
|||
out << "BindingDecoration{" << value_ << "}" << std::endl;
|
||||
}
|
||||
|
||||
BindingDecoration* BindingDecoration::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<BindingDecoration>(value_, ctx->Clone(source()));
|
||||
}
|
||||
|
||||
} // namespace ast
|
||||
} // namespace tint
|
||||
|
|
|
@ -40,6 +40,14 @@ class BindingDecoration
|
|||
/// @param indent number of spaces to indent the node when writing
|
||||
void to_str(std::ostream& out, size_t indent) const override;
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
BindingDecoration* Clone(CloneContext* ctx) const override;
|
||||
|
||||
private:
|
||||
uint32_t value_;
|
||||
};
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "src/ast/bitcast_expression.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
|
@ -30,6 +33,11 @@ BitcastExpression::BitcastExpression(const Source& source,
|
|||
BitcastExpression::BitcastExpression(BitcastExpression&&) = default;
|
||||
BitcastExpression::~BitcastExpression() = default;
|
||||
|
||||
BitcastExpression* BitcastExpression::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<BitcastExpression>(
|
||||
ctx->Clone(source()), ctx->Clone(type_), ctx->Clone(expr_));
|
||||
}
|
||||
|
||||
bool BitcastExpression::IsValid() const {
|
||||
if (expr_ == nullptr || !expr_->IsValid())
|
||||
return false;
|
||||
|
|
|
@ -55,6 +55,14 @@ class BitcastExpression : public Castable<BitcastExpression, Expression> {
|
|||
/// @returns the expression
|
||||
Expression* expr() const { return expr_; }
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
BitcastExpression* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "src/ast/block_statement.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
|
@ -25,6 +28,12 @@ BlockStatement::BlockStatement(BlockStatement&&) = default;
|
|||
|
||||
BlockStatement::~BlockStatement() = default;
|
||||
|
||||
BlockStatement* BlockStatement::Clone(CloneContext* ctx) const {
|
||||
auto* cloned = ctx->mod->create<BlockStatement>(ctx->Clone(source()));
|
||||
cloned->statements_ = ctx->Clone(statements_);
|
||||
return cloned;
|
||||
}
|
||||
|
||||
bool BlockStatement::IsValid() const {
|
||||
for (auto* stmt : *this) {
|
||||
if (stmt == nullptr || !stmt->IsValid()) {
|
||||
|
|
|
@ -85,6 +85,14 @@ class BlockStatement : public Castable<BlockStatement, Statement> {
|
|||
return statements_.end();
|
||||
}
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
BlockStatement* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "src/ast/bool_literal.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
|
@ -30,5 +33,9 @@ std::string BoolLiteral::name() const {
|
|||
return value_ ? "__bool_true" : "__bool_false";
|
||||
}
|
||||
|
||||
BoolLiteral* BoolLiteral::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<BoolLiteral>(ctx->Clone(type()), value_);
|
||||
}
|
||||
|
||||
} // namespace ast
|
||||
} // namespace tint
|
||||
|
|
|
@ -42,6 +42,14 @@ class BoolLiteral : public Castable<BoolLiteral, Literal> {
|
|||
/// @returns the literal as a string
|
||||
std::string to_str() const override;
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
BoolLiteral* Clone(CloneContext* ctx) const override;
|
||||
|
||||
private:
|
||||
bool value_;
|
||||
};
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "src/ast/break_statement.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
|
@ -25,6 +28,10 @@ BreakStatement::BreakStatement(BreakStatement&&) = default;
|
|||
|
||||
BreakStatement::~BreakStatement() = default;
|
||||
|
||||
BreakStatement* BreakStatement::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<BreakStatement>(ctx->Clone(source()));
|
||||
}
|
||||
|
||||
bool BreakStatement::IsValid() const {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,14 @@ class BreakStatement : public Castable<BreakStatement, Statement> {
|
|||
BreakStatement(BreakStatement&&);
|
||||
~BreakStatement() override;
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
BreakStatement* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "src/ast/builtin_decoration.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
|
@ -27,5 +30,9 @@ void BuiltinDecoration::to_str(std::ostream& out, size_t indent) const {
|
|||
out << "BuiltinDecoration{" << builtin_ << "}" << std::endl;
|
||||
}
|
||||
|
||||
BuiltinDecoration* BuiltinDecoration::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<BuiltinDecoration>(builtin_, ctx->Clone(source()));
|
||||
}
|
||||
|
||||
} // namespace ast
|
||||
} // namespace tint
|
||||
|
|
|
@ -39,6 +39,14 @@ class BuiltinDecoration
|
|||
/// @param indent number of spaces to indent the node when writing
|
||||
void to_str(std::ostream& out, size_t indent) const override;
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
BuiltinDecoration* Clone(CloneContext* ctx) const override;
|
||||
|
||||
private:
|
||||
Builtin builtin_ = Builtin::kNone;
|
||||
};
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "src/ast/call_expression.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
|
@ -31,6 +34,11 @@ CallExpression::CallExpression(CallExpression&&) = default;
|
|||
|
||||
CallExpression::~CallExpression() = default;
|
||||
|
||||
CallExpression* CallExpression::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<CallExpression>(
|
||||
ctx->Clone(source()), ctx->Clone(func_), ctx->Clone(params_));
|
||||
}
|
||||
|
||||
bool CallExpression::IsValid() const {
|
||||
if (func_ == nullptr || !func_->IsValid())
|
||||
return false;
|
||||
|
|
|
@ -54,6 +54,14 @@ class CallExpression : public Castable<CallExpression, Expression> {
|
|||
/// @returns the parameters
|
||||
const ExpressionList& params() const { return params_; }
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
CallExpression* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#include "src/ast/call_statement.h"
|
||||
|
||||
#include "src/ast/call_expression.h"
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
@ -27,6 +29,10 @@ CallStatement::CallStatement(CallStatement&&) = default;
|
|||
|
||||
CallStatement::~CallStatement() = default;
|
||||
|
||||
CallStatement* CallStatement::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<CallStatement>(ctx->Clone(call_));
|
||||
}
|
||||
|
||||
bool CallStatement::IsValid() const {
|
||||
return call_ != nullptr && call_->IsValid();
|
||||
}
|
||||
|
|
|
@ -42,6 +42,14 @@ class CallStatement : public Castable<CallStatement, Statement> {
|
|||
/// @returns the call expression
|
||||
CallExpression* expr() const { return call_; }
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
CallStatement* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "src/ast/case_statement.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
|
@ -31,6 +34,11 @@ CaseStatement::CaseStatement(CaseStatement&&) = default;
|
|||
|
||||
CaseStatement::~CaseStatement() = default;
|
||||
|
||||
CaseStatement* CaseStatement::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<CaseStatement>(
|
||||
ctx->Clone(source()), ctx->Clone(selectors_), ctx->Clone(body_));
|
||||
}
|
||||
|
||||
bool CaseStatement::IsValid() const {
|
||||
return body_ != nullptr && body_->IsValid();
|
||||
}
|
||||
|
|
|
@ -70,6 +70,14 @@ class CaseStatement : public Castable<CaseStatement, Statement> {
|
|||
/// @returns the case body
|
||||
BlockStatement* body() { return body_; }
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
CaseStatement* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright 2020 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/ast/clone_context.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
CloneContext::CloneContext(Module* m) : mod(m) {}
|
||||
CloneContext::~CloneContext() = default;
|
||||
|
||||
} // namespace ast
|
||||
} // namespace tint
|
|
@ -0,0 +1,90 @@
|
|||
// Copyright 2020 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_AST_CLONE_CONTEXT_H_
|
||||
#define SRC_AST_CLONE_CONTEXT_H_
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "src/source.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
class Module;
|
||||
|
||||
/// CloneContext holds the state used while cloning AST nodes and types.
|
||||
class CloneContext {
|
||||
public:
|
||||
/// Constructor
|
||||
/// @param m the target module to clone into
|
||||
explicit CloneContext(Module* m);
|
||||
/// Destructor
|
||||
~CloneContext();
|
||||
|
||||
/// Clones the `Node` or `type::Type` @p a into the module #mod if @p a is not
|
||||
/// null. If @p a is null, then Clone() returns null. If @p a has been cloned
|
||||
/// already by this CloneContext then the same cloned pointer is returned.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param a the `Node` or `type::Type` to clone
|
||||
/// @return the cloned node
|
||||
template <typename T>
|
||||
T* Clone(T* a) {
|
||||
if (a == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto it = cloned_.find(a);
|
||||
if (it != cloned_.end()) {
|
||||
return static_cast<T*>(it->second);
|
||||
}
|
||||
auto* c = a->Clone(this);
|
||||
cloned_.emplace(a, c);
|
||||
return static_cast<T*>(c);
|
||||
}
|
||||
|
||||
/// Clones the `Source` @p s into @p mod
|
||||
/// TODO(bclayton) - Currently this 'clone' is a shallow copy. If/when
|
||||
/// `Source.File`s are owned by the `Module` this should make a copy of the
|
||||
/// file.
|
||||
/// @param s the `Source` to clone
|
||||
/// @return the cloned source
|
||||
Source Clone(const Source& s) { return s; }
|
||||
|
||||
/// Clones each of the elements of the vector @p v into the module #mod.
|
||||
/// @param v the vector to clone
|
||||
/// @return the cloned vector
|
||||
template <typename T>
|
||||
std::vector<T> Clone(const std::vector<T>& v) {
|
||||
std::vector<T> out;
|
||||
out.reserve(v.size());
|
||||
for (auto& el : v) {
|
||||
out.emplace_back(Clone(el));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/// The target module to clone into.
|
||||
Module* const mod;
|
||||
|
||||
private:
|
||||
std::unordered_map<void*, void*> cloned_;
|
||||
};
|
||||
|
||||
} // namespace ast
|
||||
} // namespace tint
|
||||
|
||||
#endif // SRC_AST_CLONE_CONTEXT_H_
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "src/ast/constant_id_decoration.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
|
@ -27,5 +30,9 @@ void ConstantIdDecoration::to_str(std::ostream& out, size_t indent) const {
|
|||
out << "ConstantIdDecoration{" << value_ << "}" << std::endl;
|
||||
}
|
||||
|
||||
ConstantIdDecoration* ConstantIdDecoration::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<ConstantIdDecoration>(value_, ctx->Clone(source()));
|
||||
}
|
||||
|
||||
} // namespace ast
|
||||
} // namespace tint
|
||||
|
|
|
@ -39,6 +39,14 @@ class ConstantIdDecoration
|
|||
/// @param indent number of spaces to indent the node when writing
|
||||
void to_str(std::ostream& out, size_t indent) const override;
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
ConstantIdDecoration* Clone(CloneContext* ctx) const override;
|
||||
|
||||
private:
|
||||
uint32_t value_ = 0;
|
||||
};
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "src/ast/continue_statement.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
|
@ -25,6 +28,10 @@ ContinueStatement::ContinueStatement(ContinueStatement&&) = default;
|
|||
|
||||
ContinueStatement::~ContinueStatement() = default;
|
||||
|
||||
ContinueStatement* ContinueStatement::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<ContinueStatement>(ctx->Clone(source()));
|
||||
}
|
||||
|
||||
bool ContinueStatement::IsValid() const {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -35,6 +35,14 @@ class ContinueStatement : public Castable<ContinueStatement, Statement> {
|
|||
ContinueStatement(ContinueStatement&&);
|
||||
~ContinueStatement() override;
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
ContinueStatement* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
|
|
|
@ -17,8 +17,10 @@
|
|||
#include <cassert>
|
||||
|
||||
#include "src/ast/builtin_decoration.h"
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/constant_id_decoration.h"
|
||||
#include "src/ast/location_decoration.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
@ -69,6 +71,18 @@ uint32_t DecoratedVariable::constant_id() const {
|
|||
return 0;
|
||||
}
|
||||
|
||||
DecoratedVariable* DecoratedVariable::Clone(CloneContext* ctx) const {
|
||||
auto* cloned = ctx->mod->create<DecoratedVariable>();
|
||||
cloned->set_source(ctx->Clone(source()));
|
||||
cloned->set_name(name());
|
||||
cloned->set_storage_class(storage_class());
|
||||
cloned->set_type(ctx->Clone(type()));
|
||||
cloned->set_constructor(ctx->Clone(constructor()));
|
||||
cloned->set_is_const(is_const());
|
||||
cloned->set_decorations(ctx->Clone(decorations()));
|
||||
return cloned;
|
||||
}
|
||||
|
||||
bool DecoratedVariable::IsValid() const {
|
||||
return Variable::IsValid();
|
||||
}
|
||||
|
|
|
@ -56,6 +56,14 @@ class DecoratedVariable : public Castable<DecoratedVariable, Variable> {
|
|||
/// |HasConstantIdDecoration| has been called first.
|
||||
uint32_t constant_id() const;
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
DecoratedVariable* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the name and path are both present
|
||||
bool IsValid() const override;
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "src/ast/discard_statement.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
|
@ -25,6 +28,10 @@ DiscardStatement::DiscardStatement(DiscardStatement&&) = default;
|
|||
|
||||
DiscardStatement::~DiscardStatement() = default;
|
||||
|
||||
DiscardStatement* DiscardStatement::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<DiscardStatement>(ctx->Clone(source()));
|
||||
}
|
||||
|
||||
bool DiscardStatement::IsValid() const {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,14 @@ class DiscardStatement : public Castable<DiscardStatement, Statement> {
|
|||
DiscardStatement(DiscardStatement&&);
|
||||
~DiscardStatement() override;
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
DiscardStatement* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "src/ast/else_statement.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
|
@ -34,6 +37,11 @@ ElseStatement::ElseStatement(ElseStatement&&) = default;
|
|||
|
||||
ElseStatement::~ElseStatement() = default;
|
||||
|
||||
ElseStatement* ElseStatement::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<ElseStatement>(
|
||||
ctx->Clone(source()), ctx->Clone(condition_), ctx->Clone(body_));
|
||||
}
|
||||
|
||||
bool ElseStatement::IsValid() const {
|
||||
if (body_ == nullptr || !body_->IsValid()) {
|
||||
return false;
|
||||
|
|
|
@ -67,6 +67,14 @@ class ElseStatement : public Castable<ElseStatement, Statement> {
|
|||
/// @returns the else body
|
||||
BlockStatement* body() { return body_; }
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
ElseStatement* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ class Expr : public Expression {
|
|||
public:
|
||||
Expr() : Expression() {}
|
||||
|
||||
Expr* Clone(CloneContext*) const override { return nullptr; }
|
||||
bool IsValid() const override { return true; }
|
||||
void to_str(std::ostream&, size_t) const override {}
|
||||
};
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "src/ast/fallthrough_statement.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
|
@ -26,6 +29,10 @@ FallthroughStatement::FallthroughStatement(FallthroughStatement&&) = default;
|
|||
|
||||
FallthroughStatement::~FallthroughStatement() = default;
|
||||
|
||||
FallthroughStatement* FallthroughStatement::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<FallthroughStatement>(ctx->Clone(source()));
|
||||
}
|
||||
|
||||
bool FallthroughStatement::IsValid() const {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,14 @@ class FallthroughStatement : public Castable<FallthroughStatement, Statement> {
|
|||
FallthroughStatement(FallthroughStatement&&);
|
||||
~FallthroughStatement() override;
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
FallthroughStatement* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
#include <limits>
|
||||
#include <sstream>
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
|
@ -37,5 +40,9 @@ std::string FloatLiteral::name() const {
|
|||
return out.str();
|
||||
}
|
||||
|
||||
FloatLiteral* FloatLiteral::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<FloatLiteral>(ctx->Clone(type()), value_);
|
||||
}
|
||||
|
||||
} // namespace ast
|
||||
} // namespace tint
|
||||
|
|
|
@ -40,6 +40,14 @@ class FloatLiteral : public Castable<FloatLiteral, Literal> {
|
|||
/// @returns the literal as a string
|
||||
std::string to_str() const override;
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
FloatLiteral* Clone(CloneContext* ctx) const override;
|
||||
|
||||
private:
|
||||
float value_;
|
||||
};
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
|
||||
#include <sstream>
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/decorated_variable.h"
|
||||
#include "src/ast/module.h"
|
||||
#include "src/ast/stage_decoration.h"
|
||||
#include "src/ast/type/multisampled_texture_type.h"
|
||||
#include "src/ast/type/sampled_texture_type.h"
|
||||
|
@ -213,6 +215,14 @@ const Statement* Function::get_last_statement() const {
|
|||
return body_->last();
|
||||
}
|
||||
|
||||
Function* Function::Clone(CloneContext* ctx) const {
|
||||
auto* cloned = ctx->mod->create<Function>(
|
||||
ctx->Clone(source()), name_, ctx->Clone(params_),
|
||||
ctx->Clone(return_type_), ctx->Clone(body_));
|
||||
cloned->set_decorations(ctx->Clone(decorations_));
|
||||
return cloned;
|
||||
}
|
||||
|
||||
bool Function::IsValid() const {
|
||||
for (auto* param : params_) {
|
||||
if (param == nullptr || !param->IsValid())
|
||||
|
|
|
@ -190,6 +190,14 @@ class Function : public Castable<Function, Node> {
|
|||
/// @returns the function body
|
||||
BlockStatement* body() { return body_; }
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
Function* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the name and type are both present
|
||||
bool IsValid() const override;
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "src/ast/identifier_expression.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
|
@ -28,6 +31,10 @@ IdentifierExpression::IdentifierExpression(IdentifierExpression&&) = default;
|
|||
|
||||
IdentifierExpression::~IdentifierExpression() = default;
|
||||
|
||||
IdentifierExpression* IdentifierExpression::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<IdentifierExpression>(ctx->Clone(source()), name_);
|
||||
}
|
||||
|
||||
bool IdentifierExpression::IsValid() const {
|
||||
return !name_.empty();
|
||||
}
|
||||
|
|
|
@ -61,6 +61,14 @@ class IdentifierExpression : public Castable<IdentifierExpression, Expression> {
|
|||
/// @returns true if this identifier is for an intrinsic
|
||||
bool IsIntrinsic() const { return intrinsic_ != Intrinsic::kNone; }
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
IdentifierExpression* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
|
|
|
@ -14,7 +14,9 @@
|
|||
|
||||
#include "src/ast/if_statement.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/else_statement.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
@ -31,6 +33,13 @@ IfStatement::IfStatement(IfStatement&&) = default;
|
|||
|
||||
IfStatement::~IfStatement() = default;
|
||||
|
||||
IfStatement* IfStatement::Clone(CloneContext* ctx) const {
|
||||
auto* cloned = ctx->mod->create<IfStatement>(
|
||||
ctx->Clone(source()), ctx->Clone(condition_), ctx->Clone(body_));
|
||||
cloned->else_statements_ = ctx->Clone(else_statements_);
|
||||
return cloned;
|
||||
}
|
||||
|
||||
bool IfStatement::IsValid() const {
|
||||
if (condition_ == nullptr || !condition_->IsValid()) {
|
||||
return false;
|
||||
|
|
|
@ -71,6 +71,14 @@ class IfStatement : public Castable<IfStatement, Statement> {
|
|||
/// @returns true if there are else statements
|
||||
bool has_else_statements() const { return !else_statements_.empty(); }
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
IfStatement* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "src/ast/location_decoration.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
|
@ -27,5 +30,9 @@ void LocationDecoration::to_str(std::ostream& out, size_t indent) const {
|
|||
out << "LocationDecoration{" << value_ << "}" << std::endl;
|
||||
}
|
||||
|
||||
LocationDecoration* LocationDecoration::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<LocationDecoration>(value_, ctx->Clone(source()));
|
||||
}
|
||||
|
||||
} // namespace ast
|
||||
} // namespace tint
|
||||
|
|
|
@ -40,6 +40,14 @@ class LocationDecoration
|
|||
/// @param indent number of spaces to indent the node when writing
|
||||
void to_str(std::ostream& out, size_t indent) const override;
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
LocationDecoration* Clone(CloneContext* ctx) const override;
|
||||
|
||||
private:
|
||||
uint32_t value_;
|
||||
};
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "src/ast/loop_statement.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
|
@ -29,6 +32,11 @@ LoopStatement::LoopStatement(LoopStatement&&) = default;
|
|||
|
||||
LoopStatement::~LoopStatement() = default;
|
||||
|
||||
LoopStatement* LoopStatement::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<LoopStatement>(
|
||||
ctx->Clone(source()), ctx->Clone(body_), ctx->Clone(continuing_));
|
||||
}
|
||||
|
||||
bool LoopStatement::IsValid() const {
|
||||
if (body_ == nullptr || !body_->IsValid()) {
|
||||
return false;
|
||||
|
|
|
@ -62,6 +62,14 @@ class LoopStatement : public Castable<LoopStatement, Statement> {
|
|||
return continuing_ != nullptr && !continuing_->empty();
|
||||
}
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
LoopStatement* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "src/ast/member_accessor_expression.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
|
@ -33,6 +36,12 @@ MemberAccessorExpression::MemberAccessorExpression(MemberAccessorExpression&&) =
|
|||
|
||||
MemberAccessorExpression::~MemberAccessorExpression() = default;
|
||||
|
||||
MemberAccessorExpression* MemberAccessorExpression::Clone(
|
||||
CloneContext* ctx) const {
|
||||
return ctx->mod->create<MemberAccessorExpression>(
|
||||
ctx->Clone(source()), ctx->Clone(struct_), ctx->Clone(member_));
|
||||
}
|
||||
|
||||
bool MemberAccessorExpression::IsValid() const {
|
||||
if (struct_ == nullptr || !struct_->IsValid()) {
|
||||
return false;
|
||||
|
|
|
@ -59,6 +59,14 @@ class MemberAccessorExpression
|
|||
/// @returns the member expression
|
||||
IdentifierExpression* member() const { return member_; }
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
MemberAccessorExpression* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include <sstream>
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/type/struct_type.h"
|
||||
|
||||
namespace tint {
|
||||
|
@ -27,6 +28,23 @@ Module::Module(Module&&) = default;
|
|||
|
||||
Module::~Module() = default;
|
||||
|
||||
Module Module::Clone() {
|
||||
Module out;
|
||||
|
||||
CloneContext ctx(&out);
|
||||
for (auto* ty : constructed_types_) {
|
||||
out.constructed_types_.emplace_back(ctx.Clone(ty));
|
||||
}
|
||||
for (auto* var : global_variables_) {
|
||||
out.global_variables_.emplace_back(ctx.Clone(var));
|
||||
}
|
||||
for (auto* func : functions_) {
|
||||
out.functions_.emplace_back(ctx.Clone(func));
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
Function* Module::FindFunctionByName(const std::string& name) const {
|
||||
for (auto* func : functions_) {
|
||||
if (func->name() == name) {
|
||||
|
|
|
@ -42,6 +42,9 @@ class Module {
|
|||
Module(Module&&);
|
||||
~Module();
|
||||
|
||||
/// @return a deep copy of this module
|
||||
Module Clone();
|
||||
|
||||
/// Add a global variable to the module
|
||||
/// @param var the variable to add
|
||||
void AddGlobalVariable(Variable* var) { global_variables_.push_back(var); }
|
||||
|
@ -135,6 +138,9 @@ class Module {
|
|||
return type_mgr_.types();
|
||||
}
|
||||
|
||||
/// @returns all the declared nodes in the module
|
||||
const std::vector<std::unique_ptr<ast::Node>>& nodes() { return ast_nodes_; }
|
||||
|
||||
private:
|
||||
Module(const Module&) = delete;
|
||||
|
||||
|
|
|
@ -0,0 +1,168 @@
|
|||
// Copyright 2020 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/ast/case_statement.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "src/reader/wgsl/parser.h"
|
||||
#include "src/writer/wgsl/generator.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
namespace {
|
||||
|
||||
TEST(ModuleCloneTest, Clone) {
|
||||
#if TINT_BUILD_WGSL_READER && TINT_BUILD_WGSL_WRITER
|
||||
// Shader that exercises the bulk of the AST nodes and types.
|
||||
// See also fuzzers/tint_ast_clone_fuzzer.cc for further coverage of cloning.
|
||||
Source::File file("test.wgsl", R"([[block]]
|
||||
struct S {
|
||||
[[offset(0)]]
|
||||
m0 : u32;
|
||||
[[offset(4)]]
|
||||
m1 : array<u32>;
|
||||
};
|
||||
|
||||
type t0 = [[stride(16)]] array<vec4<f32>>;
|
||||
type t1 = [[stride(32)]] array<vec4<f32>>;
|
||||
|
||||
const c0 : i32 = 10;
|
||||
const c1 : bool = true;
|
||||
|
||||
var<uniform> g0 : u32 = 20u;
|
||||
var<out> g1 : f32 = 123.0;
|
||||
var<uniform> g2 : texture_2d<f32>;
|
||||
var<uniform> g3 : texture_storage_ro_2d<r32uint>;
|
||||
var<uniform> g4 : texture_storage_wo_2d<rg32float>;
|
||||
var<uniform> g5 : texture_storage_ro_2d<r32uint>;
|
||||
var<uniform> g6 : texture_storage_wo_2d<rg32float>;
|
||||
|
||||
[[builtin(position)]] var<uniform> g7 : vec3<f32>;
|
||||
[[set(10), binding(20)]] var<storage_buffer> g7 : S;
|
||||
[[set(10), binding(20)]] var<storage_buffer> g8 : [[access(read)]]
|
||||
S;
|
||||
[[set(10), binding(20)]] var<storage_buffer> g9 : [[access(read_write)]]
|
||||
S;
|
||||
|
||||
fn f0(p0 : bool) -> f32 {
|
||||
if (p0) {
|
||||
return 1.0;
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
fn f1(p0 : f32, p1 : i32) -> f32 {
|
||||
var l0 : i32 = 3;
|
||||
var l1 : f32 = 8;
|
||||
var l2 : u32 = bitcast<u32>(4);
|
||||
var l3 : vec2<u32> = vec2<u32>(l0, l1);
|
||||
var l4 : S;
|
||||
var l5 : u32 = l4.m1[5];
|
||||
var l6 : ptr<private, u32>;
|
||||
l6 = null;
|
||||
loop {
|
||||
l0 = (p1 + 2);
|
||||
if (((l0 % 4) == 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
continuing {
|
||||
if (1 == 2) {
|
||||
l0 = l0 - 1;
|
||||
} else {
|
||||
l0 = l0 - 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
switch(l2) {
|
||||
case 0: {
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
return f0(true);
|
||||
}
|
||||
default: {
|
||||
discard;
|
||||
}
|
||||
}
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
[[stage(fragment)]]
|
||||
fn main() -> void {
|
||||
f1(1.0, 2);
|
||||
}
|
||||
|
||||
)");
|
||||
|
||||
// Parse the wgsl, create the src module
|
||||
Context ctx;
|
||||
reader::wgsl::Parser parser(&ctx, &file);
|
||||
ASSERT_TRUE(parser.Parse()) << parser.error();
|
||||
auto src = parser.module();
|
||||
|
||||
// Clone the src module to dst
|
||||
auto dst = src.Clone();
|
||||
|
||||
// Expect the AST printed with to_str() to match
|
||||
EXPECT_EQ(src.to_str(), dst.to_str());
|
||||
|
||||
// Check that none of the AST nodes or type pointers in dst are found in src
|
||||
std::unordered_set<ast::Node*> src_nodes;
|
||||
for (auto& src_node : src.nodes()) {
|
||||
src_nodes.emplace(src_node.get());
|
||||
}
|
||||
std::unordered_set<ast::type::Type*> src_types;
|
||||
for (auto& src_type : src.types()) {
|
||||
src_types.emplace(src_type.second.get());
|
||||
}
|
||||
for (auto& dst_node : dst.nodes()) {
|
||||
ASSERT_EQ(src_nodes.count(dst_node.get()), 0u) << dst_node->str();
|
||||
}
|
||||
for (auto& dst_type : dst.types()) {
|
||||
ASSERT_EQ(src_types.count(dst_type.second.get()), 0u)
|
||||
<< dst_type.second->type_name();
|
||||
}
|
||||
|
||||
// Regenerate the wgsl for the src module. We use this instead of the original
|
||||
// source so that reformatting doesn't impact the final wgsl comparision.
|
||||
// Note that the src module is moved into the generator and this generator has
|
||||
// a limited scope, so that the src module is released before we attempt to
|
||||
// print the dst module.
|
||||
// This guarantee that all the source module nodes and types are destructed
|
||||
// and freed.
|
||||
// ASAN should error if there's any remaining references in dst when we try to
|
||||
// reconstruct the WGSL.
|
||||
std::string src_wgsl;
|
||||
{
|
||||
writer::wgsl::Generator src_gen(std::move(src));
|
||||
ASSERT_TRUE(src_gen.Generate());
|
||||
src_wgsl = src_gen.result();
|
||||
}
|
||||
|
||||
// Print the dst module, check it matches the original source
|
||||
writer::wgsl::Generator dst_gen(std::move(dst));
|
||||
ASSERT_TRUE(dst_gen.Generate());
|
||||
auto dst_wgsl = dst_gen.result();
|
||||
ASSERT_EQ(src_wgsl, dst_wgsl);
|
||||
|
||||
#else // #if TINT_BUILD_WGSL_READER && TINT_BUILD_WGSL_WRITER
|
||||
GTEST_SKIP() << "ModuleCloneTest requires TINT_BUILD_WGSL_READER and "
|
||||
"TINT_BUILD_WGSL_WRITER to be enabled";
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace ast
|
||||
} // namespace tint
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "src/castable.h"
|
||||
#include "src/source.h"
|
||||
|
@ -24,11 +25,26 @@
|
|||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
class Module;
|
||||
class CloneContext;
|
||||
|
||||
namespace type {
|
||||
class Type;
|
||||
}
|
||||
|
||||
/// AST base class node
|
||||
class Node : public Castable<Node> {
|
||||
public:
|
||||
~Node() override;
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
virtual Node* Clone(CloneContext* ctx) const = 0;
|
||||
|
||||
/// @returns the node source data
|
||||
const Source& source() const { return source_; }
|
||||
/// Sets the source data
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "src/ast/null_literal.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
|
@ -29,5 +32,9 @@ std::string NullLiteral::name() const {
|
|||
return "__null" + type()->type_name();
|
||||
}
|
||||
|
||||
NullLiteral* NullLiteral::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<NullLiteral>(ctx->Clone(type()));
|
||||
}
|
||||
|
||||
} // namespace ast
|
||||
} // namespace tint
|
||||
|
|
|
@ -35,6 +35,14 @@ class NullLiteral : public Castable<NullLiteral, Literal> {
|
|||
|
||||
/// @returns the literal as a string
|
||||
std::string to_str() const override;
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
NullLiteral* Clone(CloneContext* ctx) const override;
|
||||
};
|
||||
|
||||
} // namespace ast
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "src/ast/return_statement.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
|
@ -30,6 +33,11 @@ ReturnStatement::ReturnStatement(ReturnStatement&&) = default;
|
|||
|
||||
ReturnStatement::~ReturnStatement() = default;
|
||||
|
||||
ReturnStatement* ReturnStatement::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<ReturnStatement>(ctx->Clone(source()),
|
||||
ctx->Clone(value_));
|
||||
}
|
||||
|
||||
bool ReturnStatement::IsValid() const {
|
||||
if (value_ != nullptr) {
|
||||
return value_->IsValid();
|
||||
|
|
|
@ -51,6 +51,14 @@ class ReturnStatement : public Castable<ReturnStatement, Statement> {
|
|||
/// @returns true if the return has a value
|
||||
bool has_value() const { return value_ != nullptr; }
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
ReturnStatement* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "src/ast/scalar_constructor_expression.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
|
@ -31,6 +34,12 @@ ScalarConstructorExpression::ScalarConstructorExpression(
|
|||
|
||||
ScalarConstructorExpression::~ScalarConstructorExpression() = default;
|
||||
|
||||
ScalarConstructorExpression* ScalarConstructorExpression::Clone(
|
||||
CloneContext* ctx) const {
|
||||
return ctx->mod->create<ScalarConstructorExpression>(ctx->Clone(source()),
|
||||
ctx->Clone(literal_));
|
||||
}
|
||||
|
||||
bool ScalarConstructorExpression::IsValid() const {
|
||||
return literal_ != nullptr;
|
||||
}
|
||||
|
|
|
@ -47,6 +47,14 @@ class ScalarConstructorExpression
|
|||
/// @returns the literal value
|
||||
Literal* literal() const { return literal_; }
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
ScalarConstructorExpression* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "src/ast/set_decoration.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
|
@ -27,5 +30,9 @@ void SetDecoration::to_str(std::ostream& out, size_t indent) const {
|
|||
out << "SetDecoration{" << value_ << "}" << std::endl;
|
||||
}
|
||||
|
||||
SetDecoration* SetDecoration::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<SetDecoration>(value_, ctx->Clone(source()));
|
||||
}
|
||||
|
||||
} // namespace ast
|
||||
} // namespace tint
|
||||
|
|
|
@ -39,6 +39,14 @@ class SetDecoration : public Castable<SetDecoration, VariableDecoration> {
|
|||
/// @param indent number of spaces to indent the node when writing
|
||||
void to_str(std::ostream& out, size_t indent) const override;
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
SetDecoration* Clone(CloneContext* ctx) const override;
|
||||
|
||||
private:
|
||||
uint32_t value_;
|
||||
};
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "src/ast/sint_literal.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
|
@ -30,5 +33,9 @@ std::string SintLiteral::name() const {
|
|||
return "__sint" + type()->type_name() + "_" + std::to_string(value_);
|
||||
}
|
||||
|
||||
SintLiteral* SintLiteral::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<SintLiteral>(ctx->Clone(type()), value_);
|
||||
}
|
||||
|
||||
} // namespace ast
|
||||
} // namespace tint
|
||||
|
|
|
@ -43,6 +43,14 @@ class SintLiteral : public Castable<SintLiteral, IntLiteral> {
|
|||
/// @returns the literal as a string
|
||||
std::string to_str() const override;
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
SintLiteral* Clone(CloneContext* ctx) const override;
|
||||
|
||||
private:
|
||||
int32_t value_;
|
||||
};
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "src/ast/stage_decoration.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
|
@ -27,5 +30,9 @@ void StageDecoration::to_str(std::ostream& out, size_t indent) const {
|
|||
out << "StageDecoration{" << stage_ << "}" << std::endl;
|
||||
}
|
||||
|
||||
StageDecoration* StageDecoration::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<StageDecoration>(stage_, ctx->Clone(source()));
|
||||
}
|
||||
|
||||
} // namespace ast
|
||||
} // namespace tint
|
||||
|
|
|
@ -38,6 +38,14 @@ class StageDecoration : public Castable<StageDecoration, FunctionDecoration> {
|
|||
/// @param indent number of spaces to indent the node when writing
|
||||
void to_str(std::ostream& out, size_t indent) const override;
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
StageDecoration* Clone(CloneContext* ctx) const override;
|
||||
|
||||
private:
|
||||
PipelineStage stage_ = PipelineStage::kNone;
|
||||
};
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "src/ast/stride_decoration.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
|
@ -27,5 +30,9 @@ void StrideDecoration::to_str(std::ostream& out, size_t indent) const {
|
|||
out << "stride " << stride_;
|
||||
}
|
||||
|
||||
StrideDecoration* StrideDecoration::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<StrideDecoration>(stride_, ctx->Clone(source()));
|
||||
}
|
||||
|
||||
} // namespace ast
|
||||
} // namespace tint
|
||||
|
|
|
@ -41,6 +41,14 @@ class StrideDecoration : public Castable<StrideDecoration, ArrayDecoration> {
|
|||
/// @param indent number of spaces to indent the node when writing
|
||||
void to_str(std::ostream& out, size_t indent) const override;
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
StrideDecoration* Clone(CloneContext* ctx) const override;
|
||||
|
||||
private:
|
||||
uint32_t stride_;
|
||||
};
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
#include "src/ast/struct.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
#include "src/ast/struct_block_decoration.h"
|
||||
|
||||
namespace tint {
|
||||
|
@ -61,6 +63,11 @@ bool Struct::IsBlockDecorated() const {
|
|||
return false;
|
||||
}
|
||||
|
||||
Struct* Struct::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<Struct>(
|
||||
ctx->Clone(source()), ctx->Clone(decorations_), ctx->Clone(members_));
|
||||
}
|
||||
|
||||
bool Struct::IsValid() const {
|
||||
for (auto* mem : members_) {
|
||||
if (mem == nullptr || !mem->IsValid()) {
|
||||
|
|
|
@ -76,6 +76,14 @@ class Struct : public Castable<Struct, Node> {
|
|||
/// @returns true if the struct is block decorated
|
||||
bool IsBlockDecorated() const;
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
Struct* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "src/ast/struct_block_decoration.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
|
@ -27,5 +30,9 @@ void StructBlockDecoration::to_str(std::ostream& out, size_t indent) const {
|
|||
out << "block";
|
||||
}
|
||||
|
||||
StructBlockDecoration* StructBlockDecoration::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<StructBlockDecoration>(ctx->Clone(source()));
|
||||
}
|
||||
|
||||
} // namespace ast
|
||||
} // namespace tint
|
||||
|
|
|
@ -37,6 +37,14 @@ class StructBlockDecoration
|
|||
/// @param out the stream to write to
|
||||
/// @param indent number of spaces to indent the node when writing
|
||||
void to_str(std::ostream& out, size_t indent) const override;
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
StructBlockDecoration* Clone(CloneContext* ctx) const override;
|
||||
};
|
||||
|
||||
/// List of struct decorations
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
#include "src/ast/struct_member.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
#include "src/ast/struct_member_offset_decoration.h"
|
||||
|
||||
namespace tint {
|
||||
|
@ -57,6 +59,11 @@ uint32_t StructMember::offset() const {
|
|||
return 0;
|
||||
}
|
||||
|
||||
StructMember* StructMember::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<StructMember>(
|
||||
ctx->Clone(source()), name_, ctx->Clone(type_), ctx->Clone(decorations_));
|
||||
}
|
||||
|
||||
bool StructMember::IsValid() const {
|
||||
if (name_.empty() || type_ == nullptr) {
|
||||
return false;
|
||||
|
|
|
@ -77,6 +77,14 @@ class StructMember : public Castable<StructMember, Node> {
|
|||
/// @returns the offset decoration value.
|
||||
uint32_t offset() const;
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
StructMember* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "src/ast/struct_member_offset_decoration.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
|
@ -29,5 +32,11 @@ void StructMemberOffsetDecoration::to_str(std::ostream& out,
|
|||
out << "offset " << std::to_string(offset_);
|
||||
}
|
||||
|
||||
StructMemberOffsetDecoration* StructMemberOffsetDecoration::Clone(
|
||||
CloneContext* ctx) const {
|
||||
return ctx->mod->create<StructMemberOffsetDecoration>(offset_,
|
||||
ctx->Clone(source()));
|
||||
}
|
||||
|
||||
} // namespace ast
|
||||
} // namespace tint
|
||||
|
|
|
@ -42,6 +42,14 @@ class StructMemberOffsetDecoration
|
|||
/// @param indent number of spaces to indent the node when writing
|
||||
void to_str(std::ostream& out, size_t indent) const override;
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
StructMemberOffsetDecoration* Clone(CloneContext* ctx) const override;
|
||||
|
||||
private:
|
||||
uint32_t offset_;
|
||||
};
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#include "src/ast/switch_statement.h"
|
||||
|
||||
#include "src/ast/case_statement.h"
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
|
@ -33,6 +35,11 @@ SwitchStatement::SwitchStatement(SwitchStatement&&) = default;
|
|||
|
||||
SwitchStatement::~SwitchStatement() = default;
|
||||
|
||||
SwitchStatement* SwitchStatement::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<SwitchStatement>(
|
||||
ctx->Clone(source()), ctx->Clone(condition_), ctx->Clone(body_));
|
||||
}
|
||||
|
||||
bool SwitchStatement::IsValid() const {
|
||||
if (condition_ == nullptr || !condition_->IsValid()) {
|
||||
return false;
|
||||
|
|
|
@ -60,6 +60,14 @@ class SwitchStatement : public Castable<SwitchStatement, Statement> {
|
|||
/// @returns the Switch body
|
||||
const CaseStatementList& body() const { return body_; }
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @note Semantic information such as resolved expression type and intrinsic
|
||||
/// information is not cloned.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned node
|
||||
SwitchStatement* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
|
||||
#include <assert.h>
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
namespace type {
|
||||
|
@ -54,6 +57,10 @@ uint64_t AccessControl::BaseAlignment(MemoryLayout mem_layout) const {
|
|||
return subtype_->BaseAlignment(mem_layout);
|
||||
}
|
||||
|
||||
AccessControl* AccessControl::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<AccessControl>(access_, ctx->Clone(subtype_));
|
||||
}
|
||||
|
||||
} // namespace type
|
||||
} // namespace ast
|
||||
} // namespace tint
|
||||
|
|
|
@ -60,6 +60,11 @@ class AccessControl : public Castable<AccessControl, Type> {
|
|||
/// 0 for non-host shareable types.
|
||||
uint64_t BaseAlignment(MemoryLayout mem_layout) const override;
|
||||
|
||||
/// Clones this type and all transitive types using the `CloneContext` `ctx`.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned type
|
||||
AccessControl* Clone(CloneContext* ctx) const override;
|
||||
|
||||
private:
|
||||
ast::AccessControl access_ = ast::AccessControl::kReadOnly;
|
||||
Type* subtype_ = nullptr;
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
|
||||
#include <assert.h>
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
namespace type {
|
||||
|
@ -41,6 +44,10 @@ uint64_t Alias::BaseAlignment(MemoryLayout mem_layout) const {
|
|||
return subtype_->BaseAlignment(mem_layout);
|
||||
}
|
||||
|
||||
Alias* Alias::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<Alias>(name_, ctx->Clone(subtype_));
|
||||
}
|
||||
|
||||
} // namespace type
|
||||
} // namespace ast
|
||||
} // namespace tint
|
||||
|
|
|
@ -52,6 +52,11 @@ class Alias : public Castable<Alias, Type> {
|
|||
/// 0 for non-host shareable types.
|
||||
uint64_t BaseAlignment(MemoryLayout mem_layout) const override;
|
||||
|
||||
/// Clones this type and all transitive types using the `CloneContext` `ctx`.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned type
|
||||
Alias* Clone(CloneContext* ctx) const override;
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
Type* subtype_ = nullptr;
|
||||
|
|
|
@ -15,7 +15,10 @@
|
|||
#include "src/ast/type/array_type.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <memory>
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
#include "src/ast/stride_decoration.h"
|
||||
#include "src/ast/type/vector_type.h"
|
||||
|
||||
|
@ -92,6 +95,12 @@ std::string Array::type_name() const {
|
|||
return type_name;
|
||||
}
|
||||
|
||||
Array* Array::Clone(CloneContext* ctx) const {
|
||||
auto cloned = std::make_unique<Array>(ctx->Clone(subtype_), size_);
|
||||
cloned->set_decorations(ctx->Clone(decorations()));
|
||||
return ctx->mod->unique_type(std::move(cloned));
|
||||
}
|
||||
|
||||
} // namespace type
|
||||
} // namespace ast
|
||||
} // namespace tint
|
||||
|
|
|
@ -74,6 +74,11 @@ class Array : public Castable<Array, Type> {
|
|||
/// @returns the name for the type
|
||||
std::string type_name() const override;
|
||||
|
||||
/// Clones this type and all transitive types using the `CloneContext` `ctx`.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned type
|
||||
Array* Clone(CloneContext* ctx) const override;
|
||||
|
||||
private:
|
||||
Type* subtype_ = nullptr;
|
||||
uint32_t size_ = 0;
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "src/ast/type/bool_type.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
namespace type {
|
||||
|
@ -28,6 +31,10 @@ std::string Bool::type_name() const {
|
|||
return "__bool";
|
||||
}
|
||||
|
||||
Bool* Bool::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<Bool>();
|
||||
}
|
||||
|
||||
} // namespace type
|
||||
} // namespace ast
|
||||
} // namespace tint
|
||||
|
|
|
@ -34,6 +34,11 @@ class Bool : public Castable<Bool, Type> {
|
|||
|
||||
/// @returns the name for this type
|
||||
std::string type_name() const override;
|
||||
|
||||
/// Clones this type and all transitive types using the `CloneContext` `ctx`.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned type
|
||||
Bool* Clone(CloneContext* ctx) const override;
|
||||
};
|
||||
|
||||
} // namespace type
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
#include <cassert>
|
||||
#include <sstream>
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
namespace type {
|
||||
|
@ -47,6 +50,10 @@ std::string DepthTexture::type_name() const {
|
|||
return out.str();
|
||||
}
|
||||
|
||||
DepthTexture* DepthTexture::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<DepthTexture>(dim());
|
||||
}
|
||||
|
||||
} // namespace type
|
||||
} // namespace ast
|
||||
} // namespace tint
|
||||
|
|
|
@ -35,6 +35,11 @@ class DepthTexture : public Castable<DepthTexture, Texture> {
|
|||
|
||||
/// @returns the name for this type
|
||||
std::string type_name() const override;
|
||||
|
||||
/// Clones this type and all transitive types using the `CloneContext` `ctx`.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned type
|
||||
DepthTexture* Clone(CloneContext* ctx) const override;
|
||||
};
|
||||
|
||||
} // namespace type
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "src/ast/type/f32_type.h"
|
||||
|
||||
#include "src/ast/clone_context.h"
|
||||
#include "src/ast/module.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
namespace type {
|
||||
|
@ -36,6 +39,10 @@ uint64_t F32::BaseAlignment(MemoryLayout) const {
|
|||
return 4;
|
||||
}
|
||||
|
||||
F32* F32::Clone(CloneContext* ctx) const {
|
||||
return ctx->mod->create<F32>();
|
||||
}
|
||||
|
||||
} // namespace type
|
||||
} // namespace ast
|
||||
} // namespace tint
|
||||
|
|
|
@ -44,6 +44,11 @@ class F32 : public Castable<F32, Type> {
|
|||
/// @returns base alignment for the type, in bytes.
|
||||
/// 0 for non-host shareable types.
|
||||
uint64_t BaseAlignment(MemoryLayout mem_layout) const override;
|
||||
|
||||
/// Clones this type and all transitive types using the `CloneContext` `ctx`.
|
||||
/// @param ctx the clone context
|
||||
/// @return the newly cloned type
|
||||
F32* Clone(CloneContext* ctx) const override;
|
||||
};
|
||||
|
||||
} // namespace type
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue