3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2026-03-23 04:49:15 +00:00

genrtlil: even faster removeSignalFromCaseTree

This commit is contained in:
Emil J. Tywoniak 2026-03-18 18:26:28 +01:00
parent 27737c6e2e
commit ad7a776d73

View file

@ -342,6 +342,9 @@ struct AST_INTERNAL::ProcessGenerator
// The most recently assigned $print or $check cell \PRIORITY.
int last_effect_priority;
// Track which signals have been assigned in current_case to avoid unnecessary removeSignalFromCaseTree calls
pool<RTLIL::SigBit> current_case_assigned_bits;
ProcessGenerator(std::unique_ptr<AstNode> a, RTLIL::SigSpec initSyncSignalsArg = RTLIL::SigSpec()) : always(std::move(a)), initSyncSignals(initSyncSignalsArg), last_effect_priority(0)
{
// rewrite lookahead references
@ -430,6 +433,10 @@ struct AST_INTERNAL::ProcessGenerator
subst_rvalue_map = subst_lvalue_from.to_sigbit_dict(RTLIL::SigSpec(RTLIL::State::Sx, GetSize(subst_lvalue_from)));
} else {
addChunkActions(current_case->actions, subst_lvalue_to, subst_lvalue_from);
// Track initial assignments
for (auto &bit : subst_lvalue_to)
if (bit.wire != NULL)
current_case_assigned_bits.insert(bit);
}
// process the AST
@ -559,8 +566,26 @@ struct AST_INTERNAL::ProcessGenerator
// the third assignment.
void removeSignalFromCaseTree(const pool<RTLIL::SigBit> &pattern_bits, RTLIL::CaseRule *cs)
{
for (auto it = cs->actions.begin(); it != cs->actions.end(); it++)
it->first.remove2(pattern_bits, &it->second);
// Optimization: check actions in reverse order and stop early if we've found all pattern bits
pool<RTLIL::SigBit> remaining_bits = pattern_bits;
for (auto it = cs->actions.rbegin(); it != cs->actions.rend(); ++it) {
bool has_pattern = false;
for (auto &bit : it->first) {
if (bit.wire != NULL && remaining_bits.count(bit)) {
has_pattern = true;
remaining_bits.erase(bit);
}
}
if (has_pattern) {
it->first.remove2(pattern_bits, &it->second);
}
// Early exit if we've processed all bits in pattern
if (remaining_bits.empty())
break;
}
for (auto it = cs->switches.begin(); it != cs->switches.end(); it++)
for (auto it2 = (*it)->cases.begin(); it2 != (*it)->cases.end(); it2++)
@ -633,7 +658,23 @@ struct AST_INTERNAL::ProcessGenerator
subst_rvalue_map.set(unmapped_lvalue[i], rvalue[i]);
}
removeSignalFromCaseTree(lvalue, current_case);
// Check if any bits in lvalue have been assigned before in current_case
bool has_overlap = false;
for (auto &bit : lvalue) {
if (bit.wire != NULL && current_case_assigned_bits.count(bit)) {
has_overlap = true;
break;
}
}
if (has_overlap)
removeSignalFromCaseTree(lvalue, current_case);
// Track newly assigned bits
for (auto &bit : lvalue)
if (bit.wire != NULL)
current_case_assigned_bits.insert(bit);
remove_unwanted_lvalue_bits(lvalue, rvalue);
current_case->actions.push_back(RTLIL::SigSig(lvalue, rvalue));
}
@ -680,9 +721,15 @@ struct AST_INTERNAL::ProcessGenerator
RTLIL::CaseRule *backup_case = current_case;
current_case = new RTLIL::CaseRule;
pool<RTLIL::SigBit> backup_assigned_bits = std::move(current_case_assigned_bits);
current_case_assigned_bits.clear();
set_src_attr(current_case, child.get());
last_generated_case = current_case;
addChunkActions(current_case->actions, this_case_eq_ltemp, this_case_eq_rvalue);
// Track temp assignments
for (auto &bit : this_case_eq_ltemp)
if (bit.wire != NULL)
current_case_assigned_bits.insert(bit);
for (auto& node : child->children) {
if (node->type == AST_DEFAULT)
default_case = current_case;
@ -696,6 +743,7 @@ struct AST_INTERNAL::ProcessGenerator
else
log_assert(current_case->compare.size() == 0);
current_case = backup_case;
current_case_assigned_bits = std::move(backup_assigned_bits);
subst_lvalue_map.restore();
subst_rvalue_map.restore();
@ -724,8 +772,24 @@ struct AST_INTERNAL::ProcessGenerator
subst_rvalue_map.set(this_case_eq_lvalue[i], this_case_eq_ltemp[i]);
this_case_eq_lvalue.replace(subst_lvalue_map.stdmap());
removeSignalFromCaseTree(this_case_eq_lvalue, current_case);
// Check if any bits in lvalue have been assigned before in current_case
bool has_overlap = false;
for (auto &bit : this_case_eq_lvalue) {
if (bit.wire != NULL && current_case_assigned_bits.count(bit)) {
has_overlap = true;
break;
}
}
if (has_overlap)
removeSignalFromCaseTree(this_case_eq_lvalue, current_case);
addChunkActions(current_case->actions, this_case_eq_lvalue, this_case_eq_ltemp);
// Track newly assigned bits
for (auto &bit : this_case_eq_lvalue)
if (bit.wire != NULL)
current_case_assigned_bits.insert(bit);
}
break;