Skip to content
Merged
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
2319d82
Make IdString::begins_width/ends_with take std::string_view so we avo…
rocallahan Oct 16, 2025
32641bb
Make IdString::contains take std::string_view so we avoid a strlen wh…
rocallahan Oct 16, 2025
2063990
Store IdString lengths and use them
rocallahan Aug 20, 2025
e84bc3c
Remove explicit empty-string check when looking up IdStrings
rocallahan Oct 16, 2025
0fe79ce
Make RTLIL::Design::get_all_designs() unconditionally defined
rocallahan Oct 9, 2025
d28f97e
Remove YOSYS_USE_STICKY_IDS
rocallahan Oct 9, 2025
5133b4b
Create RTLIL::OwningIdString and use it in a few places
rocallahan Oct 9, 2025
54bde15
Implement IdString garbage collection instead of refcounting.
rocallahan Oct 10, 2025
b0e2d75
Make IdString refcounts a hashtable containing only the nonzero refco…
rocallahan Oct 13, 2025
b3f3f42
Remove StaticIdString and just use IdString now that we can make it c…
rocallahan Oct 14, 2025
9577a02
Make new_id/new_id_suffix taking string_view to avoid allocating strings
rocallahan Oct 13, 2025
8895757
Ensure that `new_id(_suffix)()` cannot create collisions with existin…
rocallahan Oct 13, 2025
e95ed7b
Make NEW_ID create IDs whose string allocation is delayed
rocallahan Oct 13, 2025
df8444c
Optimize IdString operations to avoid calling c_str()
rocallahan Oct 13, 2025
325b27f
Avoid calling IdString::c_str() in opt_clean
rocallahan Oct 13, 2025
c4c389f
Fix verilog backend to avoid IdString::c_str()
rocallahan Oct 13, 2025
8c2984d
Fix AbcModuleState::remap_name() to avoid calling IdString::c_str()
rocallahan Oct 13, 2025
578d658
Add timing stats for IdString garbage collection
rocallahan Oct 16, 2025
ae28172
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 @@ -606,7 +606,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