diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 83a20814a..5e0356fd3 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -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 current_case_assigned_bits; + ProcessGenerator(std::unique_ptr 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 &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 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 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;