Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
f7ac724
Make IdString::begins_width/ends_with take std::string_view so we avo…
rocallahan Oct 16, 2025
ae219cb
Make IdString::contains take std::string_view so we avoid a strlen wh…
rocallahan Oct 16, 2025
d70924a
Store IdString lengths and use them
rocallahan Aug 20, 2025
3a4fa32
Remove explicit empty-string check when looking up IdStrings
rocallahan Oct 16, 2025
8b8939e
Make RTLIL::Design::get_all_designs() unconditionally defined
rocallahan Oct 9, 2025
2ca7b2f
Remove YOSYS_USE_STICKY_IDS
rocallahan Oct 9, 2025
b3f79ed
Create RTLIL::OwningIdString and use it in a few places
rocallahan Oct 9, 2025
bc78955
Implement IdString garbage collection instead of refcounting.
rocallahan Oct 10, 2025
3c2caff
Make IdString refcounts a hashtable containing only the nonzero refco…
rocallahan Oct 13, 2025
5cc3f27
Remove StaticIdString and just use IdString now that we can make it c…
rocallahan Oct 14, 2025
bf732df
Make new_id/new_id_suffix taking string_view to avoid allocating strings
rocallahan Oct 13, 2025
442a969
Ensure that `new_id(_suffix)()` cannot create collisions with existin…
rocallahan Oct 13, 2025
2075b34
Make NEW_ID create IDs whose string allocation is delayed
rocallahan Oct 13, 2025
a534fda
Optimize IdString operations to avoid calling c_str()
rocallahan Oct 13, 2025
e4a5bd7
Avoid calling IdString::c_str() in opt_clean
rocallahan Oct 13, 2025
609da65
Fix verilog backend to avoid IdString::c_str()
rocallahan Oct 13, 2025
cd47727
Fix AbcModuleState::remap_name() to avoid calling IdString::c_str()
rocallahan Oct 13, 2025
7371388
Add timing stats for IdString garbage collection
rocallahan Oct 16, 2025
054de3c
tests: remove unstable FPGA synthesis result checks
widlarizer Oct 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 15 additions & 7 deletions backends/verilog/verilog_backend.cc
Original file line number Diff line number Diff line change
Expand Up @@ -108,22 +108,30 @@ IdString initial_id;

void reset_auto_counter_id(RTLIL::IdString id, bool may_rename)
{
const char *str = id.c_str();
auto it = id.begin();
auto it_end = id.end();
if (it == it_end)
return;

if (*str == '$' && may_rename && !norename)
if (*it == '$' && may_rename && !norename)
auto_name_map[id] = auto_name_counter++;

if (str[0] != '\\' || str[1] != '_' || str[2] == 0)
if (*it != '\\' || *it != '_' || (it + 1) == it_end)
return;

for (int i = 2; str[i] != 0; i++) {
if (str[i] == '_' && str[i+1] == 0)
it += 2;
auto start = it;
while (it != it_end) {
char ch = *it;
if (ch == '_' && (it + 1) == it_end)
continue;
if (str[i] < '0' || str[i] > '9')
if (ch < '0' || ch > '9')
return;
}

int num = atoi(str+2);
std::string s;
std::copy(start, it_end, std::back_inserter(s));
int num = atoi(s.c_str());
if (num >= auto_name_offset)
auto_name_offset = num + 1;
}
Expand Down
2 changes: 2 additions & 0 deletions kernel/driver.cc
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,8 @@ int main(int argc, char **argv)
total_ns += it.second->runtime_ns + 1;
timedat.insert(make_tuple(it.second->runtime_ns + 1, it.second->call_counter, it.first));
}
timedat.insert(make_tuple(RTLIL::OwningIdString::garbage_collection_ns() + 1,
RTLIL::OwningIdString::garbage_collection_count(), "id_gc"));

if (timing_details)
{
Expand Down
2 changes: 1 addition & 1 deletion kernel/io.cc
Original file line number Diff line number Diff line change
Expand Up @@ -587,7 +587,7 @@ void format_emit_idstring(std::string &result, std::string_view spec, int *dynam
{
if (spec == "%s") {
// Format checking will have guaranteed num_dynamic_ints == 0.
result += arg.c_str();
arg.append_to(&result);
return;
}
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg.c_str());
Expand Down
35 changes: 31 additions & 4 deletions kernel/register.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,23 @@ std::map<std::string, Backend*> backend_register;

std::vector<std::string> Frontend::next_args;

bool GarbageCollectionGuard::is_enabled_ = true;

static bool garbage_collection_requested = false;

void request_garbage_collection()
{
garbage_collection_requested = true;
}

void try_collect_garbage()
{
if (!GarbageCollectionGuard::is_enabled() || !garbage_collection_requested)
return;
garbage_collection_requested = false;
RTLIL::OwningIdString::collect_garbage();
}

Pass::Pass(std::string name, std::string short_help, source_location location) :
pass_name(name), short_help(short_help), location(location)
{
Expand Down Expand Up @@ -112,6 +129,11 @@ void Pass::post_execute(Pass::pre_post_exec_state_t state)
int64_t time_ns = PerformanceTimer::query() - state.begin_ns;
runtime_ns += time_ns;
current_pass = state.parent_pass;
subtract_from_current_runtime_ns(time_ns);
}

void Pass::subtract_from_current_runtime_ns(int64_t time_ns)
{
if (current_pass)
current_pass->runtime_ns -= time_ns;
}
Expand Down Expand Up @@ -263,14 +285,19 @@ void Pass::call(RTLIL::Design *design, std::vector<std::string> args)

if (pass_register.count(args[0]) == 0)
log_cmd_error("No such command: %s (type 'help' for a command overview)\n", args[0]);
Pass *pass = pass_register[args[0]];

// Collect garbage before the next pass if requested. No need to collect garbage after the last pass.
try_collect_garbage();
GarbageCollectionGuard gc_guard(pass->allow_garbage_collection_during_pass());

if (pass_register[args[0]]->experimental_flag)
if (pass->experimental_flag)
log_experimental(args[0]);

size_t orig_sel_stack_pos = design->selection_stack.size();
auto state = pass_register[args[0]]->pre_execute();
pass_register[args[0]]->execute(args, design);
pass_register[args[0]]->post_execute(state);
auto state = pass->pre_execute();
pass->execute(args, design);
pass->post_execute(state);
while (design->selection_stack.size() > orig_sel_stack_pos)
design->pop_selection();
}
Expand Down
32 changes: 32 additions & 0 deletions kernel/register.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,30 @@ struct source_location { // dummy placeholder

YOSYS_NAMESPACE_BEGIN

// Track whether garbage collection is enabled. Garbage collection must be disabled
// while any RTLIL objects (e.g. non-owning non-immortal IdStrings) exist outside Designs.
// Garbage collection is disabled whenever any GarbageCollectionGuard(false) is on the
// stack. These objects must be stack-allocated on the main thread.
class GarbageCollectionGuard
{
bool was_enabled;
static bool is_enabled_;
public:
GarbageCollectionGuard(bool allow) : was_enabled(is_enabled_) {
is_enabled_ &= allow;
}
~GarbageCollectionGuard() {
is_enabled_ = was_enabled;
}
static bool is_enabled() { return is_enabled_; }
};

// Call from anywhere to request GC at the next safe point.
void request_garbage_collection();

// GC if GarbageCollectionGuard::is_enabled() and GC was requested.
void try_collect_garbage();

struct Pass
{
std::string pass_name, short_help;
Expand All @@ -71,6 +95,8 @@ struct Pass
bool experimental_flag = false;
bool internal_flag = false;

static void subtract_from_current_runtime_ns(int64_t time_ns);

void experimental() {
experimental_flag = true;
}
Expand Down Expand Up @@ -108,6 +134,10 @@ struct Pass
virtual void on_register();
virtual void on_shutdown();
virtual bool replace_existing_pass() const { return false; }

// This should return false if the pass holds onto RTLIL objects outside a Design while it
// calls nested passes. For safety, we default to assuming the worst.
virtual bool allow_garbage_collection_during_pass() const { return false; }
};

struct ScriptPass : Pass
Expand All @@ -126,6 +156,8 @@ struct ScriptPass : Pass
void run_nocheck(std::string command, std::string info = std::string());
void run_script(RTLIL::Design *design, std::string run_from = std::string(), std::string run_to = std::string());
void help_script();

bool allow_garbage_collection_during_pass() const override { return true; }
};

struct Frontend : Pass
Expand Down
Loading
Loading