Add an allocator to store the symbol names.

This CL adds an allocator, owned by the SymbolTable, which stores the
names of all the symbols in the table. The Symbols then have a
`string_view` to their name.

Change-Id: I28e5b2aefcf9f67c1877b7ebab52416f780bd8c6
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/127300
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
This commit is contained in:
dan sinclair 2023-04-18 19:31:21 +00:00 committed by Dawn LUCI CQ
parent 00882100f4
commit b353ebe752
15 changed files with 79 additions and 87 deletions

View File

@ -172,7 +172,6 @@ option_if_not_defined(TINT_BUILD_REMOTE_COMPILE "Build the remote-compile tool f
option_if_not_defined(TINT_ENABLE_BREAK_IN_DEBUGGER "Enable tint::debugger::Break()" OFF) option_if_not_defined(TINT_ENABLE_BREAK_IN_DEBUGGER "Enable tint::debugger::Break()" OFF)
option_if_not_defined(TINT_CHECK_CHROMIUM_STYLE "Check for [chromium-style] issues during build" OFF) option_if_not_defined(TINT_CHECK_CHROMIUM_STYLE "Check for [chromium-style] issues during build" OFF)
option_if_not_defined(TINT_SYMBOL_STORE_DEBUG_NAME "Enable storing of name in tint::ast::Symbol to help debugging the AST" OFF)
option_if_not_defined(TINT_RANDOMIZE_HASHES "Randomize the hash seed value to detect non-deterministic output" OFF) option_if_not_defined(TINT_RANDOMIZE_HASHES "Randomize the hash seed value to detect non-deterministic output" OFF)
# Recommended setting for compability with future abseil releases. # Recommended setting for compability with future abseil releases.

View File

@ -786,9 +786,6 @@ target_link_libraries(tint_val tint_utils_io)
add_library(libtint ${TINT_LIB_SRCS}) add_library(libtint ${TINT_LIB_SRCS})
tint_default_compile_options(libtint) tint_default_compile_options(libtint)
target_link_libraries(libtint tint_diagnostic_utils absl_strings) target_link_libraries(libtint tint_diagnostic_utils absl_strings)
if (${TINT_SYMBOL_STORE_DEBUG_NAME})
target_compile_definitions(libtint PUBLIC "TINT_SYMBOL_STORE_DEBUG_NAME=1")
endif()
set_target_properties(libtint PROPERTIES OUTPUT_NAME "tint") set_target_properties(libtint PROPERTIES OUTPUT_NAME "tint")
if (${TINT_BUILD_FUZZERS}) if (${TINT_BUILD_FUZZERS})

View File

@ -24,12 +24,12 @@ using IdentifierExpressionTest = TestHelper;
TEST_F(IdentifierExpressionTest, Creation) { TEST_F(IdentifierExpressionTest, Creation) {
auto* i = Expr("ident"); auto* i = Expr("ident");
EXPECT_EQ(i->identifier->symbol, Symbol(1, ID())); EXPECT_EQ(i->identifier->symbol, Symbol(1, ID(), "ident"));
} }
TEST_F(IdentifierExpressionTest, CreationTemplated) { TEST_F(IdentifierExpressionTest, CreationTemplated) {
auto* i = Expr(Ident("ident", true)); auto* i = Expr(Ident("ident", true));
EXPECT_EQ(i->identifier->symbol, Symbol(1, ID())); EXPECT_EQ(i->identifier->symbol, Symbol(1, ID(), "ident"));
auto* tmpl_ident = i->identifier->As<TemplatedIdentifier>(); auto* tmpl_ident = i->identifier->As<TemplatedIdentifier>();
ASSERT_NE(tmpl_ident, nullptr); ASSERT_NE(tmpl_ident, nullptr);
EXPECT_EQ(tmpl_ident->arguments.Length(), 1_u); EXPECT_EQ(tmpl_ident->arguments.Length(), 1_u);
@ -38,7 +38,7 @@ TEST_F(IdentifierExpressionTest, CreationTemplated) {
TEST_F(IdentifierExpressionTest, Creation_WithSource) { TEST_F(IdentifierExpressionTest, Creation_WithSource) {
auto* i = Expr(Source{{20, 2}}, "ident"); auto* i = Expr(Source{{20, 2}}, "ident");
EXPECT_EQ(i->identifier->symbol, Symbol(1, ID())); EXPECT_EQ(i->identifier->symbol, Symbol(1, ID(), "ident"));
EXPECT_EQ(i->source.range, (Source::Range{{20, 2}})); EXPECT_EQ(i->source.range, (Source::Range{{20, 2}}));
EXPECT_EQ(i->identifier->source.range, (Source::Range{{20, 2}})); EXPECT_EQ(i->identifier->source.range, (Source::Range{{20, 2}}));

View File

@ -22,12 +22,12 @@ using IdentifierTest = TestHelper;
TEST_F(IdentifierTest, Creation) { TEST_F(IdentifierTest, Creation) {
auto* i = Ident("ident"); auto* i = Ident("ident");
EXPECT_EQ(i->symbol, Symbol(1, ID())); EXPECT_EQ(i->symbol, Symbol(1, ID(), "ident"));
} }
TEST_F(IdentifierTest, Creation_WithSource) { TEST_F(IdentifierTest, Creation_WithSource) {
auto* i = Ident(Source{{20, 2}}, "ident"); auto* i = Ident(Source{{20, 2}}, "ident");
EXPECT_EQ(i->symbol, Symbol(1, ID())); EXPECT_EQ(i->symbol, Symbol(1, ID(), "ident"));
auto src = i->source; auto src = i->source;
EXPECT_EQ(src.range.begin.line, 20u); EXPECT_EQ(src.range.begin.line, 20u);

View File

@ -33,7 +33,7 @@ CloneContext::CloneContext(ProgramBuilder* to, Program const* from, bool auto_cl
// Almost all transforms will want to clone all symbols before doing any // Almost all transforms will want to clone all symbols before doing any
// work, to avoid any newly created symbols clashing with existing symbols // work, to avoid any newly created symbols clashing with existing symbols
// in the source program and causing them to be renamed. // in the source program and causing them to be renamed.
from->Symbols().Foreach([&](Symbol s, const std::string&) { Clone(s); }); from->Symbols().Foreach([&](Symbol s) { Clone(s); });
} }
} }

View File

@ -76,7 +76,7 @@ ProgramBuilder ProgramBuilder::Wrap(const Program* program) {
builder.ast_ = builder.ast_ =
builder.create<ast::Module>(program->AST().source, program->AST().GlobalDeclarations()); builder.create<ast::Module>(program->AST().source, program->AST().GlobalDeclarations());
builder.sem_ = sem::Info::Wrap(program->Sem()); builder.sem_ = sem::Info::Wrap(program->Sem());
builder.symbols_ = program->Symbols(); builder.symbols_.Wrap(program->Symbols());
builder.diagnostics_ = program->Diagnostics(); builder.diagnostics_ = program->Diagnostics();
return builder; return builder;
} }

View File

@ -21,7 +21,7 @@ namespace tint::reader::spirv {
namespace { namespace {
TEST(SpvParserTypeTest, SameArgumentsGivesSamePointer) { TEST(SpvParserTypeTest, SameArgumentsGivesSamePointer) {
Symbol sym(Symbol(1, {})); Symbol sym(Symbol(1, {}, "1"));
TypeManager ty; TypeManager ty;
EXPECT_EQ(ty.Void(), ty.Void()); EXPECT_EQ(ty.Void(), ty.Void());
@ -50,8 +50,8 @@ TEST(SpvParserTypeTest, SameArgumentsGivesSamePointer) {
} }
TEST(SpvParserTypeTest, DifferentArgumentsGivesDifferentPointer) { TEST(SpvParserTypeTest, DifferentArgumentsGivesDifferentPointer) {
Symbol sym_a(Symbol(1, {})); Symbol sym_a(Symbol(1, {}, "1"));
Symbol sym_b(Symbol(2, {})); Symbol sym_b(Symbol(2, {}, "2"));
TypeManager ty; TypeManager ty;
EXPECT_NE(ty.Pointer(ty.I32(), builtin::AddressSpace::kUndefined), EXPECT_NE(ty.Pointer(ty.I32(), builtin::AddressSpace::kUndefined),

View File

@ -23,8 +23,8 @@ class ScopeStackTest : public ProgramBuilder, public testing::Test {};
TEST_F(ScopeStackTest, Get) { TEST_F(ScopeStackTest, Get) {
ScopeStack<Symbol, uint32_t> s; ScopeStack<Symbol, uint32_t> s;
Symbol a(1, ID()); Symbol a(1, ID(), "1");
Symbol b(3, ID()); Symbol b(3, ID(), "3");
s.Push(); s.Push();
s.Set(a, 5u); s.Set(a, 5u);
s.Set(b, 10u); s.Set(b, 10u);
@ -45,14 +45,14 @@ TEST_F(ScopeStackTest, Get) {
TEST_F(ScopeStackTest, Get_MissingSymbol) { TEST_F(ScopeStackTest, Get_MissingSymbol) {
ScopeStack<Symbol, uint32_t> s; ScopeStack<Symbol, uint32_t> s;
Symbol sym(1, ID()); Symbol sym(1, ID(), "1");
EXPECT_EQ(s.Get(sym), 0u); EXPECT_EQ(s.Get(sym), 0u);
} }
TEST_F(ScopeStackTest, Set) { TEST_F(ScopeStackTest, Set) {
ScopeStack<Symbol, uint32_t> s; ScopeStack<Symbol, uint32_t> s;
Symbol a(1, ID()); Symbol a(1, ID(), "1");
Symbol b(2, ID()); Symbol b(2, ID(), "2");
EXPECT_EQ(s.Set(a, 5u), 0u); EXPECT_EQ(s.Set(a, 5u), 0u);
EXPECT_EQ(s.Get(a), 5u); EXPECT_EQ(s.Get(a), 5u);
@ -69,8 +69,8 @@ TEST_F(ScopeStackTest, Set) {
TEST_F(ScopeStackTest, Clear) { TEST_F(ScopeStackTest, Clear) {
ScopeStack<Symbol, uint32_t> s; ScopeStack<Symbol, uint32_t> s;
Symbol a(1, ID()); Symbol a(1, ID(), "1");
Symbol b(2, ID()); Symbol b(2, ID(), "2");
EXPECT_EQ(s.Set(a, 5u), 0u); EXPECT_EQ(s.Set(a, 5u), 0u);
EXPECT_EQ(s.Get(a), 5u); EXPECT_EQ(s.Get(a), 5u);

View File

@ -20,12 +20,8 @@ namespace tint {
Symbol::Symbol() = default; Symbol::Symbol() = default;
Symbol::Symbol(uint32_t val, tint::ProgramID program_id) : val_(val), program_id_(program_id) {} Symbol::Symbol(uint32_t val, tint::ProgramID pid, std::string_view name)
: val_(val), program_id_(pid), name_(name) {}
#if TINT_SYMBOL_STORE_DEBUG_NAME
Symbol::Symbol(uint32_t val, tint::ProgramID pid, std::string debug_name)
: val_(val), program_id_(pid), debug_name_(std::move(debug_name)) {}
#endif
Symbol::Symbol(const Symbol& o) = default; Symbol::Symbol(const Symbol& o) = default;
@ -56,4 +52,8 @@ std::string Symbol::to_str() const {
return "$" + std::to_string(val_); return "$" + std::to_string(val_);
} }
std::string Symbol::Name() const {
return std::string(name_);
}
} // namespace tint } // namespace tint

View File

@ -15,13 +15,6 @@
#ifndef SRC_TINT_SYMBOL_H_ #ifndef SRC_TINT_SYMBOL_H_
#define SRC_TINT_SYMBOL_H_ #define SRC_TINT_SYMBOL_H_
// If TINT_SYMBOL_STORE_DEBUG_NAME is 1, Symbol instances store a `debug_name_`
// member initialized with the name of the identifier they represent. This
// member is not exposed, but is useful for debugging purposes.
#ifndef TINT_SYMBOL_STORE_DEBUG_NAME
#define TINT_SYMBOL_STORE_DEBUG_NAME 0
#endif
#include <string> #include <string>
#include "src/tint/program_id.h" #include "src/tint/program_id.h"
@ -34,17 +27,12 @@ class Symbol {
/// Constructor /// Constructor
/// An invalid symbol /// An invalid symbol
Symbol(); Symbol();
/// Constructor
/// @param val the symbol value
/// @param program_id the identifier of the program that owns this Symbol
Symbol(uint32_t val, tint::ProgramID program_id);
#if TINT_SYMBOL_STORE_DEBUG_NAME
/// Constructor /// Constructor
/// @param val the symbol value /// @param val the symbol value
/// @param pid the identifier of the program that owns this Symbol /// @param pid the identifier of the program that owns this Symbol
/// @param debug_name name of symbols used only for debugging /// @param name the name this symbol represents
Symbol(uint32_t val, tint::ProgramID pid, std::string debug_name); Symbol(uint32_t val, tint::ProgramID pid, std::string_view name);
#endif
/// Copy constructor /// Copy constructor
/// @param o the symbol to copy /// @param o the symbol to copy
Symbol(const Symbol& o); Symbol(const Symbol& o);
@ -88,15 +76,17 @@ class Symbol {
/// @return the string representation of the symbol /// @return the string representation of the symbol
std::string to_str() const; std::string to_str() const;
/// Converts the symbol to the registered name
/// @returns the string representing the name of the symbol
std::string Name() const;
/// @returns the identifier of the Program that owns this symbol. /// @returns the identifier of the Program that owns this symbol.
tint::ProgramID ProgramID() const { return program_id_; } tint::ProgramID ProgramID() const { return program_id_; }
private: private:
uint32_t val_ = static_cast<uint32_t>(-1); uint32_t val_ = static_cast<uint32_t>(-1);
tint::ProgramID program_id_; tint::ProgramID program_id_;
#if TINT_SYMBOL_STORE_DEBUG_NAME std::string_view name_;
std::string debug_name_;
#endif
}; };
/// @param sym the Symbol /// @param sym the Symbol

View File

@ -20,14 +20,10 @@ namespace tint {
SymbolTable::SymbolTable(tint::ProgramID program_id) : program_id_(program_id) {} SymbolTable::SymbolTable(tint::ProgramID program_id) : program_id_(program_id) {}
SymbolTable::SymbolTable(const SymbolTable&) = default;
SymbolTable::SymbolTable(SymbolTable&&) = default; SymbolTable::SymbolTable(SymbolTable&&) = default;
SymbolTable::~SymbolTable() = default; SymbolTable::~SymbolTable() = default;
SymbolTable& SymbolTable::operator=(const SymbolTable& other) = default;
SymbolTable& SymbolTable::operator=(SymbolTable&&) = default; SymbolTable& SymbolTable::operator=(SymbolTable&&) = default;
Symbol SymbolTable::Register(const std::string& name) { Symbol SymbolTable::Register(const std::string& name) {
@ -38,15 +34,19 @@ Symbol SymbolTable::Register(const std::string& name) {
return *it; return *it;
} }
#if TINT_SYMBOL_STORE_DEBUG_NAME char* name_mem = name_allocator_.Allocate(name.length() + 1);
Symbol sym(next_symbol_, program_id_, name); if (name_mem == nullptr) {
#else return Symbol();
Symbol sym(next_symbol_, program_id_); }
#endif
memcpy(name_mem, name.data(), name.length() + 1);
std::string_view nv(name_mem, name.length());
Symbol sym(next_symbol_, program_id_, nv);
++next_symbol_; ++next_symbol_;
name_to_symbol_.Add(name, sym); name_to_symbol_.Add(name_mem, sym);
symbol_to_name_.Add(sym, name);
return sym; return sym;
} }
@ -58,12 +58,7 @@ Symbol SymbolTable::Get(const std::string& name) const {
std::string SymbolTable::NameFor(const Symbol symbol) const { std::string SymbolTable::NameFor(const Symbol symbol) const {
TINT_ASSERT_PROGRAM_IDS_EQUAL(Symbol, program_id_, symbol); TINT_ASSERT_PROGRAM_IDS_EQUAL(Symbol, program_id_, symbol);
auto it = symbol_to_name_.Find(symbol); return symbol.Name();
if (!it) {
return symbol.to_str();
}
return *it;
} }
Symbol SymbolTable::New(std::string prefix /* = "" */) { Symbol SymbolTable::New(std::string prefix /* = "" */) {

View File

@ -16,9 +16,10 @@
#define SRC_TINT_SYMBOL_TABLE_H_ #define SRC_TINT_SYMBOL_TABLE_H_
#include <string> #include <string>
#include "utils/hashmap.h"
#include "src/tint/symbol.h" #include "src/tint/symbol.h"
#include "utils/bump_allocator.h"
#include "utils/hashmap.h"
namespace tint { namespace tint {
@ -29,22 +30,29 @@ class SymbolTable {
/// @param program_id the identifier of the program that owns this symbol /// @param program_id the identifier of the program that owns this symbol
/// table /// table
explicit SymbolTable(tint::ProgramID program_id); explicit SymbolTable(tint::ProgramID program_id);
/// Copy constructor
SymbolTable(const SymbolTable&);
/// Move Constructor /// Move Constructor
SymbolTable(SymbolTable&&); SymbolTable(SymbolTable&&);
/// Destructor /// Destructor
~SymbolTable(); ~SymbolTable();
/// Copy assignment
/// @param other the symbol table to copy
/// @returns the new symbol table
SymbolTable& operator=(const SymbolTable& other);
/// Move assignment /// Move assignment
/// @param other the symbol table to move /// @param other the symbol table to move
/// @returns the symbol table /// @returns the symbol table
SymbolTable& operator=(SymbolTable&& other); SymbolTable& operator=(SymbolTable&& other);
/// Wrap sets this symbol table to hold symbols which point to the allocated names in @p o.
/// The symbol table after Wrap is intended to temporarily extend the objects
/// of an existing immutable SymbolTable
/// As the copied objects are owned by @p o, @p o must not be destructed
/// or assigned while using this symbol table.
/// @param o the immutable SymbolTable to extend
void Wrap(const SymbolTable& o) {
next_symbol_ = o.next_symbol_;
name_to_symbol_ = o.name_to_symbol_;
last_prefix_to_index_ = o.last_prefix_to_index_;
program_id_ = o.program_id_;
}
/// Registers a name into the symbol table, returning the Symbol. /// Registers a name into the symbol table, returning the Symbol.
/// @param name the name to register /// @param name the name to register
/// @returns the symbol representing the given name /// @returns the symbol representing the given name
@ -70,11 +78,11 @@ class SymbolTable {
/// Foreach calls the callback function `F` for each symbol in the table. /// Foreach calls the callback function `F` for each symbol in the table.
/// @param callback must be a function or function-like object with the /// @param callback must be a function or function-like object with the
/// signature: `void(Symbol, const std::string&)` /// signature: `void(Symbol)`
template <typename F> template <typename F>
void Foreach(F&& callback) const { void Foreach(F&& callback) const {
for (auto it : symbol_to_name_) { for (auto it : name_to_symbol_) {
callback(it.key, it.value); callback(it.value);
} }
} }
@ -82,13 +90,17 @@ class SymbolTable {
tint::ProgramID ProgramID() const { return program_id_; } tint::ProgramID ProgramID() const { return program_id_; }
private: private:
SymbolTable(const SymbolTable&) = delete;
SymbolTable& operator=(const SymbolTable& other) = delete;
// The value to be associated to the next registered symbol table entry. // The value to be associated to the next registered symbol table entry.
uint32_t next_symbol_ = 1; uint32_t next_symbol_ = 1;
utils::Hashmap<Symbol, std::string, 0> symbol_to_name_; utils::Hashmap<std::string_view, Symbol, 0> name_to_symbol_;
utils::Hashmap<std::string, Symbol, 0> name_to_symbol_;
utils::Hashmap<std::string, size_t, 0> last_prefix_to_index_; utils::Hashmap<std::string, size_t, 0> last_prefix_to_index_;
tint::ProgramID program_id_; tint::ProgramID program_id_;
utils::BumpAllocator name_allocator_;
}; };
/// @param symbol_table the SymbolTable /// @param symbol_table the SymbolTable

View File

@ -24,16 +24,16 @@ using SymbolTableTest = testing::Test;
TEST_F(SymbolTableTest, GeneratesSymbolForName) { TEST_F(SymbolTableTest, GeneratesSymbolForName) {
auto program_id = ProgramID::New(); auto program_id = ProgramID::New();
SymbolTable s{program_id}; SymbolTable s{program_id};
EXPECT_EQ(Symbol(1, program_id), s.Register("name")); EXPECT_EQ(Symbol(1, program_id, "name"), s.Register("name"));
EXPECT_EQ(Symbol(2, program_id), s.Register("another_name")); EXPECT_EQ(Symbol(2, program_id, "another_name"), s.Register("another_name"));
} }
TEST_F(SymbolTableTest, DeduplicatesNames) { TEST_F(SymbolTableTest, DeduplicatesNames) {
auto program_id = ProgramID::New(); auto program_id = ProgramID::New();
SymbolTable s{program_id}; SymbolTable s{program_id};
EXPECT_EQ(Symbol(1, program_id), s.Register("name")); EXPECT_EQ(Symbol(1, program_id, "name"), s.Register("name"));
EXPECT_EQ(Symbol(2, program_id), s.Register("another_name")); EXPECT_EQ(Symbol(2, program_id, "another_name"), s.Register("another_name"));
EXPECT_EQ(Symbol(1, program_id), s.Register("name")); EXPECT_EQ(Symbol(1, program_id, "name"), s.Register("name"));
} }
TEST_F(SymbolTableTest, ReturnsNameForSymbol) { TEST_F(SymbolTableTest, ReturnsNameForSymbol) {
@ -46,7 +46,7 @@ TEST_F(SymbolTableTest, ReturnsNameForSymbol) {
TEST_F(SymbolTableTest, ReturnsBlankForMissingSymbol) { TEST_F(SymbolTableTest, ReturnsBlankForMissingSymbol) {
auto program_id = ProgramID::New(); auto program_id = ProgramID::New();
SymbolTable s{program_id}; SymbolTable s{program_id};
EXPECT_EQ("$2", s.NameFor(Symbol(2, program_id))); EXPECT_EQ("$2", s.NameFor(Symbol(2, program_id, "$2")));
} }
TEST_F(SymbolTableTest, AssertsForBlankString) { TEST_F(SymbolTableTest, AssertsForBlankString) {

View File

@ -22,12 +22,12 @@ namespace {
using SymbolTest = testing::Test; using SymbolTest = testing::Test;
TEST_F(SymbolTest, ToStr) { TEST_F(SymbolTest, ToStr) {
Symbol sym(1, ProgramID::New()); Symbol sym(1, ProgramID::New(), "");
EXPECT_EQ("$1", sym.to_str()); EXPECT_EQ("$1", sym.to_str());
} }
TEST_F(SymbolTest, CopyAssign) { TEST_F(SymbolTest, CopyAssign) {
Symbol sym1(1, ProgramID::New()); Symbol sym1(1, ProgramID::New(), "");
Symbol sym2; Symbol sym2;
EXPECT_FALSE(sym2.IsValid()); EXPECT_FALSE(sym2.IsValid());
@ -38,9 +38,9 @@ TEST_F(SymbolTest, CopyAssign) {
TEST_F(SymbolTest, Comparison) { TEST_F(SymbolTest, Comparison) {
auto program_id = ProgramID::New(); auto program_id = ProgramID::New();
Symbol sym1(1, program_id); Symbol sym1(1, program_id, "1");
Symbol sym2(2, program_id); Symbol sym2(2, program_id, "2");
Symbol sym3(1, program_id); Symbol sym3(1, program_id, "3");
EXPECT_TRUE(sym1 == sym3); EXPECT_TRUE(sym1 == sym3);
EXPECT_FALSE(sym1 != sym3); EXPECT_FALSE(sym1 != sym3);

View File

@ -55,8 +55,7 @@
</Type> </Type>
<Type Name="tint::Symbol"> <Type Name="tint::Symbol">
<!-- Requires TINT_SYMBOL_STORE_DEBUG_NAME defined to 1 --> <DisplayString Optional="true">{name_,sb}</DisplayString>
<DisplayString Optional="true">{debug_name_,sb}</DisplayString>
</Type> </Type>
<!--=================================================================--> <!--=================================================================-->