Add writer to emit the AST.

This CL adds a new `SyntaxTree` writer and a `dump-syntax-tree` option
to the `tint` program which emits a copy of the AST to the terminal.

Change-Id: I83f6cd7aad3413b0a823728e8aac0d551421b33a
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/122540
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
dan sinclair 2023-03-06 17:48:33 +00:00 committed by Dawn LUCI CQ
parent 63d0fabeb1
commit a753ad47a4
9 changed files with 1739 additions and 0 deletions

View File

@ -157,6 +157,7 @@ option_if_not_defined(TINT_BUILD_MSL_WRITER "Build the MSL output writer" ${DAWN
option_if_not_defined(TINT_BUILD_SPV_WRITER "Build the SPIR-V output writer" ${DAWN_ENABLE_VULKAN}) option_if_not_defined(TINT_BUILD_SPV_WRITER "Build the SPIR-V output writer" ${DAWN_ENABLE_VULKAN})
option_if_not_defined(TINT_BUILD_WGSL_WRITER "Build the WGSL output writer" ON) option_if_not_defined(TINT_BUILD_WGSL_WRITER "Build the WGSL output writer" ON)
option_if_not_defined(TINT_BUILD_SYNTAX_TREE_WRITER "Build the syntax tree writer" OFF)
option_if_not_defined(TINT_BUILD_IR "Build the IR" ON) option_if_not_defined(TINT_BUILD_IR "Build the IR" ON)
option_if_not_defined(TINT_BUILD_FUZZERS "Build fuzzers" OFF) option_if_not_defined(TINT_BUILD_FUZZERS "Build fuzzers" OFF)
@ -292,6 +293,7 @@ message(STATUS "Tint build HLSL writer: ${TINT_BUILD_HLSL_WRITER}")
message(STATUS "Tint build MSL writer: ${TINT_BUILD_MSL_WRITER}") message(STATUS "Tint build MSL writer: ${TINT_BUILD_MSL_WRITER}")
message(STATUS "Tint build SPIR-V writer: ${TINT_BUILD_SPV_WRITER}") message(STATUS "Tint build SPIR-V writer: ${TINT_BUILD_SPV_WRITER}")
message(STATUS "Tint build WGSL writer: ${TINT_BUILD_WGSL_WRITER}") message(STATUS "Tint build WGSL writer: ${TINT_BUILD_WGSL_WRITER}")
message(STATUS "Tint build Syntax Tree writer: ${TINT_BUILD_SYNTAX_TREE_WRITER}")
message(STATUS "Tint build IR: ${TINT_BUILD_IR}") message(STATUS "Tint build IR: ${TINT_BUILD_IR}")
message(STATUS "Tint build fuzzers: ${TINT_BUILD_FUZZERS}") message(STATUS "Tint build fuzzers: ${TINT_BUILD_FUZZERS}")
message(STATUS "Tint build SPIRV-Tools fuzzer: ${TINT_BUILD_SPIRV_TOOLS_FUZZER}") message(STATUS "Tint build SPIRV-Tools fuzzer: ${TINT_BUILD_SPIRV_TOOLS_FUZZER}")
@ -521,6 +523,8 @@ function(tint_core_compile_options TARGET)
target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_MSL_WRITER=$<BOOL:${TINT_BUILD_MSL_WRITER}>) target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_MSL_WRITER=$<BOOL:${TINT_BUILD_MSL_WRITER}>)
target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_SPV_WRITER=$<BOOL:${TINT_BUILD_SPV_WRITER}>) target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_SPV_WRITER=$<BOOL:${TINT_BUILD_SPV_WRITER}>)
target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_WGSL_WRITER=$<BOOL:${TINT_BUILD_WGSL_WRITER}>) target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_WGSL_WRITER=$<BOOL:${TINT_BUILD_WGSL_WRITER}>)
target_compile_definitions(${TARGET} PUBLIC
-DTINT_BUILD_SYNTAX_TREE_WRITER=$<BOOL:${TINT_BUILD_SYNTAX_TREE_WRITER}>)
target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_IR=$<BOOL:${TINT_BUILD_IR}>) target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_IR=$<BOOL:${TINT_BUILD_IR}>)
common_compile_options(${TARGET}) common_compile_options(${TARGET})

View File

@ -78,6 +78,12 @@ config("tint_public_config") {
defines += [ "TINT_BUILD_GLSL_WRITER=0" ] defines += [ "TINT_BUILD_GLSL_WRITER=0" ]
} }
if (tint_build_syntax_tree_writer) {
defines += [ "TINT_BUILD_SYNTAX_TREE_WRITER=1" ]
} else {
defines += [ "TINT_BUILD_SYNTAX_TREE_WRITER=0" ]
}
include_dirs = [ include_dirs = [
"${tint_root_dir}/", "${tint_root_dir}/",
"${tint_root_dir}/include/", "${tint_root_dir}/include/",
@ -1045,6 +1051,25 @@ libtint_source_set("libtint_glsl_writer_src") {
] ]
} }
libtint_source_set("libtint_syntax_tree_writer_src") {
sources = [
"writer/syntax_tree/generator.cc",
"writer/syntax_tree/generator.h",
"writer/syntax_tree/generator_impl.cc",
"writer/syntax_tree/generator_impl.h",
]
deps = [
":libtint_ast_src",
":libtint_base_src",
":libtint_builtins_src",
":libtint_program_src",
":libtint_sem_src",
":libtint_type_src",
":libtint_writer_src",
]
}
source_set("libtint") { source_set("libtint") {
public_deps = [ public_deps = [
":libtint_ast_src", ":libtint_ast_src",
@ -1089,6 +1114,10 @@ source_set("libtint") {
public_deps += [ ":libtint_glsl_writer_src" ] public_deps += [ ":libtint_glsl_writer_src" ]
} }
if (tint_build_syntax_tree_writer) {
public_deps += [ ":libtint_syntax_tree_writer_src" ]
}
configs += [ ":tint_common_config" ] configs += [ ":tint_common_config" ]
public_configs = [ ":tint_public_config" ] public_configs = [ ":tint_public_config" ]

View File

@ -677,6 +677,15 @@ if(${TINT_BUILD_HLSL_WRITER})
) )
endif() endif()
if(${TINT_BUILD_SYNTAX_TREE_WRITER})
list(APPEND TINT_LIB_SRCS
writer/syntax_tree/generator.cc
writer/syntax_tree/generator.h
writer/syntax_tree/generator_impl.cc
writer/syntax_tree/generator_impl.h
)
endif()
if(${TINT_BUILD_IR}) if(${TINT_BUILD_IR})
list(APPEND TINT_LIB_SRCS list(APPEND TINT_LIB_SRCS
ir/binary.cc ir/binary.cc

View File

@ -29,6 +29,10 @@
#include "glslang/Public/ShaderLang.h" #include "glslang/Public/ShaderLang.h"
#endif // TINT_BUILD_GLSL_WRITER #endif // TINT_BUILD_GLSL_WRITER
#if TINT_BUILD_SYNTAX_TREE_WRITER
#include "src/tint/writer/syntax_tree/generator.h"
#endif // TINT_BUILD_SYNTAX_TREE_WRITER
#if TINT_BUILD_SPV_READER #if TINT_BUILD_SPV_READER
#include "spirv-tools/libspirv.hpp" #include "spirv-tools/libspirv.hpp"
#endif // TINT_BUILD_SPV_READER #endif // TINT_BUILD_SPV_READER
@ -106,6 +110,10 @@ struct Options {
bool dump_ir = false; bool dump_ir = false;
bool dump_ir_graph = false; bool dump_ir_graph = false;
#endif // TINT_BUILD_IR #endif // TINT_BUILD_IR
#if TINT_BUILD_SYNTAX_TREE_WRITER
bool dump_syntax_tree = false;
#endif // TINB_BUILD_SYNTAX_TREE_WRITER
}; };
const char kUsage[] = R"(Usage: tint [options] <input-file> const char kUsage[] = R"(Usage: tint [options] <input-file>
@ -383,6 +391,10 @@ bool ParseArgs(const std::vector<std::string>& args, Options* opts) {
} else if (arg == "--dump-ir-graph") { } else if (arg == "--dump-ir-graph") {
opts->dump_ir_graph = true; opts->dump_ir_graph = true;
#endif // TINT_BUILD_IR #endif // TINT_BUILD_IR
#if TINT_BUILD_SYNTAX_TREE_WRITER
} else if (arg == "--dump-ast") {
opts->dump_syntax_tree = true;
#endif // TINT_BUILD_SYNTAX_TREE_WRITER
} else if (arg == "--xcrun") { } else if (arg == "--xcrun") {
++i; ++i;
if (i >= args.size()) { if (i >= args.size()) {
@ -1055,6 +1067,9 @@ int main(int argc, const char** argv) {
" --dump-ir -- Writes the IR to stdout\n" " --dump-ir -- Writes the IR to stdout\n"
" --dump-ir-graph -- Writes the IR graph to 'tint.dot' as a dot graph\n"; " --dump-ir-graph -- Writes the IR graph to 'tint.dot' as a dot graph\n";
#endif // TINT_BUILD_IR #endif // TINT_BUILD_IR
#if TINT_BUILD_SYNTAX_TREE_WRITER
usage += " --dump-ast -- Writes the AST to stdout\n";
#endif // TINT_BUILD_SYNTAX_TREE_WRITER
std::cout << usage << std::endl; std::cout << usage << std::endl;
return 0; return 0;
@ -1092,6 +1107,18 @@ int main(int argc, const char** argv) {
return 1; return 1;
} }
#if TINT_BUILD_SYNTAX_TREE_WRITER
if (options.dump_syntax_tree) {
tint::writer::syntax_tree::Options gen_options;
auto result = tint::writer::syntax_tree::Generate(program.get(), gen_options);
if (!result.success) {
std::cerr << "Failed to dump AST: " << result.error << std::endl;
} else {
std::cout << result.ast << std::endl;
}
}
#endif // TINT_BUILD_SYNTAX_TREE_WRITER
#if TINT_BUILD_IR #if TINT_BUILD_IR
if (options.dump_ir || options.dump_ir_graph) { if (options.dump_ir || options.dump_ir_graph) {
auto result = tint::ir::Module::FromProgram(program.get()); auto result = tint::ir::Module::FromProgram(program.get());

View File

@ -0,0 +1,36 @@
// Copyright 2023 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/tint/writer/syntax_tree/generator.h"
#include "src/tint/writer/syntax_tree/generator_impl.h"
namespace tint::writer::syntax_tree {
Result::Result() = default;
Result::~Result() = default;
Result::Result(const Result&) = default;
Result Generate(const Program* program, const Options&) {
Result result;
// Generate the AST dump.
auto impl = std::make_unique<GeneratorImpl>(program);
result.success = impl->Generate();
result.error = impl->error();
result.ast = impl->result();
return result;
}
} // namespace tint::writer::syntax_tree

View File

@ -0,0 +1,65 @@
// Copyright 2023 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_TINT_WRITER_SYNTAX_TREE_GENERATOR_H_
#define SRC_TINT_WRITER_SYNTAX_TREE_GENERATOR_H_
#include <memory>
#include <string>
#include "src/tint/writer/text.h"
// Forward declarations
namespace tint {
class Program;
} // namespace tint
namespace tint::writer::syntax_tree {
class GeneratorImpl;
/// Configuration options used for generating AST.
struct Options {};
/// The result produced when generating AST.
struct Result {
/// Constructor
Result();
/// Destructor
~Result();
/// Copy constructor
Result(const Result&);
/// True if generation was successful.
bool success = false;
/// The errors generated during code generation, if any.
std::string error;
/// The generated AST.
std::string ast = "";
};
/// Generate an AST dump for a program, according to a set of configuration options.
/// The result will contain the AST, as well as success status and diagnostic information.
/// @param program the program to dump
/// @param options the configuration options to use when dumping
/// @returns the resulting AST dump and supplementary information
Result Generate(const Program* program, const Options& options);
} // namespace tint::writer::syntax_tree
#endif // SRC_TINT_WRITER_SYNTAX_TREE_GENERATOR_H_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,215 @@
// Copyright 2023 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_TINT_WRITER_SYNTAX_TREE_GENERATOR_IMPL_H_
#define SRC_TINT_WRITER_SYNTAX_TREE_GENERATOR_IMPL_H_
#include <string>
#include "src/tint/ast/assignment_statement.h"
#include "src/tint/ast/binary_expression.h"
#include "src/tint/ast/bitcast_expression.h"
#include "src/tint/ast/break_if_statement.h"
#include "src/tint/ast/break_statement.h"
#include "src/tint/ast/compound_assignment_statement.h"
#include "src/tint/ast/continue_statement.h"
#include "src/tint/ast/discard_statement.h"
#include "src/tint/ast/for_loop_statement.h"
#include "src/tint/ast/if_statement.h"
#include "src/tint/ast/index_accessor_expression.h"
#include "src/tint/ast/loop_statement.h"
#include "src/tint/ast/member_accessor_expression.h"
#include "src/tint/ast/return_statement.h"
#include "src/tint/ast/switch_statement.h"
#include "src/tint/ast/unary_op_expression.h"
#include "src/tint/program.h"
#include "src/tint/sem/struct.h"
#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/text_generator.h"
namespace tint::writer::syntax_tree {
/// Implementation class for AST generator
class GeneratorImpl : public TextGenerator {
public:
/// Constructor
/// @param program the program
explicit GeneratorImpl(const Program* program);
~GeneratorImpl();
/// Generates the result data
/// @returns true on successful generation; false otherwise
bool Generate();
/// Handles generating a diagnostic control
/// @param diagnostic the diagnostic control node
/// @returns true if the diagnostic control was emitted
bool EmitDiagnosticControl(const ast::DiagnosticControl& diagnostic);
/// Handles generating an enable directive
/// @param enable the enable node
/// @returns true if the enable directive was emitted
bool EmitEnable(const ast::Enable* enable);
/// Handles generating a declared type
/// @param ty the declared type to generate
/// @returns true if the declared type was emitted
bool EmitTypeDecl(const ast::TypeDecl* ty);
/// Handles an index accessor expression
/// @param expr the expression to emit
/// @returns true if the index accessor was emitted
bool EmitIndexAccessor(const ast::IndexAccessorExpression* expr);
/// Handles an assignment statement
/// @param stmt the statement to emit
/// @returns true if the statement was emitted successfully
bool EmitAssign(const ast::AssignmentStatement* stmt);
/// Handles generating a binary expression
/// @param expr the binary expression
/// @returns true if the expression was emitted, false otherwise
bool EmitBinary(const ast::BinaryExpression* expr);
/// Handles generating a binary operator
/// @param op the binary operator
/// @returns true if the operator was emitted, false otherwise
bool EmitBinaryOp(const ast::BinaryOp op);
/// Handles generating a bitcast expression
/// @param expr the bitcast expression
/// @returns true if the bitcast was emitted
bool EmitBitcast(const ast::BitcastExpression* expr);
/// Handles a block statement
/// @param stmt the statement to emit
/// @returns true if the statement was emitted successfully
bool EmitBlock(const ast::BlockStatement* stmt);
/// Handles emitting the start of a block statement (including attributes)
/// @param stmt the block statement to emit the header for
/// @returns true if the statement was emitted successfully
bool EmitBlockHeader(const ast::BlockStatement* stmt);
/// Handles a break statement
/// @param stmt the statement to emit
/// @returns true if the statement was emitted successfully
bool EmitBreak(const ast::BreakStatement* stmt);
/// Handles a break-if statement
/// @param stmt the statement to emit
/// @returns true if the statement was emitted successfully
bool EmitBreakIf(const ast::BreakIfStatement* stmt);
/// Handles generating a call expression
/// @param expr the call expression
/// @returns true if the call expression is emitted
bool EmitCall(const ast::CallExpression* expr);
/// Handles a case statement
/// @param stmt the statement
/// @returns true if the statment was emitted successfully
bool EmitCase(const ast::CaseStatement* stmt);
/// Handles a compound assignment statement
/// @param stmt the statement to emit
/// @returns true if the statement was emitted successfully
bool EmitCompoundAssign(const ast::CompoundAssignmentStatement* stmt);
/// Handles generating a literal expression
/// @param expr the literal expression expression
/// @returns true if the literal expression is emitted
bool EmitLiteral(const ast::LiteralExpression* expr);
/// Handles a continue statement
/// @param stmt the statement to emit
/// @returns true if the statement was emitted successfully
bool EmitContinue(const ast::ContinueStatement* stmt);
/// Handles generate an Expression
/// @param expr the expression
/// @returns true if the expression was emitted
bool EmitExpression(const ast::Expression* expr);
/// Handles generating a function
/// @param func the function to generate
/// @returns true if the function was emitted
bool EmitFunction(const ast::Function* func);
/// Handles generating an identifier expression
/// @param expr the identifier expression
/// @returns true if the identifier was emitted
bool EmitIdentifier(const ast::IdentifierExpression* expr);
/// Handles generating an identifier
/// @param ident the identifier
/// @returns true if the identifier was emitted
bool EmitIdentifier(const ast::Identifier* ident);
/// Handles an if statement
/// @param stmt the statement to emit
/// @returns true if the statement was successfully emitted
bool EmitIf(const ast::IfStatement* stmt);
/// Handles an increment/decrement statement
/// @param stmt the statement to emit
/// @returns true if the statement was successfully emitted
bool EmitIncrementDecrement(const ast::IncrementDecrementStatement* stmt);
/// Handles generating a discard statement
/// @param stmt the discard statement
/// @returns true if the statement was successfully emitted
bool EmitDiscard(const ast::DiscardStatement* stmt);
/// Handles a loop statement
/// @param stmt the statement to emit
/// @returns true if the statement was emtited
bool EmitLoop(const ast::LoopStatement* stmt);
/// Handles a for-loop statement
/// @param stmt the statement to emit
/// @returns true if the statement was emtited
bool EmitForLoop(const ast::ForLoopStatement* stmt);
/// Handles a while statement
/// @param stmt the statement to emit
/// @returns true if the statement was emtited
bool EmitWhile(const ast::WhileStatement* stmt);
/// Handles a member accessor expression
/// @param expr the member accessor expression
/// @returns true if the member accessor was emitted
bool EmitMemberAccessor(const ast::MemberAccessorExpression* expr);
/// Handles return statements
/// @param stmt the statement to emit
/// @returns true if the statement was successfully emitted
bool EmitReturn(const ast::ReturnStatement* stmt);
/// Handles const assertion statements
/// @param stmt the statement to emit
/// @returns true if the statement was successfully emitted
bool EmitConstAssert(const ast::ConstAssert* stmt);
/// Handles statement
/// @param stmt the statement to emit
/// @returns true if the statement was emitted
bool EmitStatement(const ast::Statement* stmt);
/// Handles a statement list
/// @param stmts the statements to emit
/// @returns true if the statements were emitted
bool EmitStatements(utils::VectorRef<const ast::Statement*> stmts);
/// Handles a statement list with an increased indentation
/// @param stmts the statements to emit
/// @returns true if the statements were emitted
bool EmitStatementsWithIndent(utils::VectorRef<const ast::Statement*> stmts);
/// Handles generating a switch statement
/// @param stmt the statement to emit
/// @returns true if the statement was emitted
bool EmitSwitch(const ast::SwitchStatement* stmt);
/// Handles generating a struct declaration
/// @param str the struct
/// @returns true if the struct is emitted
bool EmitStructType(const ast::Struct* str);
/// Handles emitting an image format
/// @param fmt the format to generate
/// @returns true if the format is emitted
bool EmitImageFormat(const builtin::TexelFormat fmt);
/// Handles a unary op expression
/// @param expr the expression to emit
/// @returns true if the expression was emitted
bool EmitUnaryOp(const ast::UnaryOpExpression* expr);
/// Handles generating a variable
/// @param var the variable to generate
/// @returns true if the variable was emitted
bool EmitVariable(const ast::Variable* var);
/// Handles generating a attribute list
/// @param attrs the attribute list
/// @returns true if the attributes were emitted
bool EmitAttributes(utils::VectorRef<const ast::Attribute*> attrs);
};
} // namespace tint::writer::syntax_tree
#endif // SRC_TINT_WRITER_SYNTAX_TREE_GENERATOR_IMPL_H_

View File

@ -72,6 +72,11 @@ declare_args() {
tint_build_glsl_writer = true tint_build_glsl_writer = true
} }
# Build the Syntax Tree writer
if (!defined(tint_build_syntax_tree_writer)) {
tint_build_syntax_tree_writer = false
}
# Build unittests # Build unittests
if (!defined(tint_build_unittests)) { if (!defined(tint_build_unittests)) {
tint_build_unittests = true tint_build_unittests = true