From 5803461c24b8d1520cabce66cd9ba7c7994246a7 Mon Sep 17 00:00:00 2001 From: nella Date: Mon, 26 Jan 2026 22:10:10 +0100 Subject: [PATCH] opt_dff pattern extraction. --- kernel/pattern.h | 98 +++++++++++++++++++++++++++++++++++++++ passes/opt/opt_dff.cc | 48 +------------------ passes/opt/opt_dff_comp.h | 31 ------------- 3 files changed, 100 insertions(+), 77 deletions(-) create mode 100644 kernel/pattern.h delete mode 100644 passes/opt/opt_dff_comp.h diff --git a/kernel/pattern.h b/kernel/pattern.h new file mode 100644 index 000000000..13892ebc5 --- /dev/null +++ b/kernel/pattern.h @@ -0,0 +1,98 @@ +#ifndef OPT_DFF_COMP_H +#define OPT_DFF_COMP_H + +#include "kernel/rtlil.h" +#include +#include + +YOSYS_NAMESPACE_BEGIN + +/** + * Pattern matching utilities for control signal analysis. + * + * A pattern_t maps control signals to required values, representing a + * product term (conjunction): {A=1, B=0} means "A AND !B". + * + * A patterns_t is a set of patterns representing a sum-of-products: + * {{A=1, B=0}, {A=0, C=1}} means "(A AND !B) OR (!A AND C)". + * + * Used for analyzing MUX tree control paths in DFF optimization. + */ + +typedef std::map pattern_t; // Control signal -> required vals +typedef std::set patterns_t; // Alternative patterns (OR) + +/** + * Find if two patterns differ in exactly one variable. + * Example: {A=1,B=1} vs {A=1,B=0} returns B, allows simplification: (A&B) | (A&!B) => A + */ +inline std::optional find_complementary_pattern_var( + const pattern_t& left, + const pattern_t& right +) { + std::optional ret; + for (const auto &pt : left) { + // Left requires signal that right doesn't constrain - incompatible domains + if (right.count(pt.first) == 0) + return std::nullopt; + // Signal has same required value in both - not the complement variable + if (right.at(pt.first) == pt.second) + continue; + // Already found one differing signal, now found another - not simplifiable + if (ret) + return std::nullopt; + // First differing signal - candidate complement variable + ret = pt.first; + } + return ret; +} + +/** + * Simplify a sum-of-products by merging complementary patterns: (A&B) | (A&!B) => A, + * and removing redundant patterns: A | (A&B) => A + */ +inline void simplify_patterns(patterns_t& patterns) { + auto new_patterns = patterns; + + // Merge complementary patterns + bool optimized; + do { + optimized = false; + for (auto i = patterns.begin(); i != patterns.end(); i++) { + for (auto j = std::next(i, 1); j != patterns.end(); j++) { + const auto& left = (GetSize(*j) <= GetSize(*i)) ? *j : *i; + auto right = (GetSize(*i) < GetSize(*j)) ? *j : *i; + const auto complementary_var = find_complementary_pattern_var(left, right); + + if (complementary_var && new_patterns.count(right)) { + new_patterns.erase(right); + right.erase(complementary_var.value()); + new_patterns.insert(right); + optimized = true; + } + } + } + patterns = new_patterns; + } while(optimized); + + // Remove redundant patterns + for (auto i = patterns.begin(); i != patterns.end(); ++i) { + for (auto j = std::next(i, 1); j != patterns.end(); ++j) { + const auto& left = (GetSize(*j) <= GetSize(*i)) ? *j : *i; + const auto& right = (GetSize(*i) < GetSize(*j)) ? *j : *i; + bool redundant = true; + + for (const auto& pt : left) + if (right.count(pt.first) == 0 || right.at(pt.first) != pt.second) + redundant = false; + if (redundant) + new_patterns.erase(right); + } + } + + patterns = std::move(new_patterns); +} + +YOSYS_NAMESPACE_END + +#endif diff --git a/passes/opt/opt_dff.cc b/passes/opt/opt_dff.cc index 31260fd96..ff14d367f 100644 --- a/passes/opt/opt_dff.cc +++ b/passes/opt/opt_dff.cc @@ -26,8 +26,8 @@ #include "kernel/sigtools.h" #include "kernel/ffinit.h" #include "kernel/ff.h" +#include "kernel/pattern.h" #include "passes/techmap/simplemap.h" -#include "passes/opt/opt_dff_comp.h" #include #include @@ -57,8 +57,7 @@ struct OptDffWorker dict bit2mux; // Signal bit to driving MUX // Pattern matching for clock enable - typedef std::map pattern_t; // Control signal -> required vals - typedef std::set patterns_t; // Alternative patterns (OR) + typedef std::map pattern_t; typedef std::pair ctrl_t; // Control signal typedef std::set ctrls_t; // Control signals (AND) @@ -221,49 +220,6 @@ struct OptDffWorker return ret; } - void simplify_patterns(patterns_t& patterns) - { - auto new_patterns = patterns; - - // Remove complimentary patterns - bool optimized; - do { - optimized = false; - for (auto i = patterns.begin(); i != patterns.end(); i++) { - for (auto j = std::next(i, 1); j != patterns.end(); j++) { - const auto& left = (GetSize(*j) <= GetSize(*i)) ? *j : *i; - auto right = (GetSize(*i) < GetSize(*j)) ? *j : *i; - const auto complimentary_var = find_complementary_pattern_var(left, right); - - if (complimentary_var && new_patterns.count(right)) { - new_patterns.erase(right); - right.erase(complimentary_var.value()); - new_patterns.insert(right); - optimized = true; - } - } - } - patterns = new_patterns; - } while(optimized); - - // Remove redundant patterns - for (auto i = patterns.begin(); i != patterns.end(); ++i) { - for (auto j = std::next(i, 1); j != patterns.end(); ++j) { - const auto& left = (GetSize(*j) <= GetSize(*i)) ? *j : *i; - const auto& right = (GetSize(*i) < GetSize(*j)) ? *j : *i; - bool redundant = true; - - for (const auto& pt : left) - if (right.count(pt.first) == 0 || right.at(pt.first) != pt.second) - redundant = false; - if (redundant) - new_patterns.erase(right); - } - } - - patterns = std::move(new_patterns); - } - ctrl_t make_patterns_logic(const patterns_t &patterns, const ctrls_t &ctrls, bool make_gates) { if (patterns.empty() && GetSize(ctrls) == 1) diff --git a/passes/opt/opt_dff_comp.h b/passes/opt/opt_dff_comp.h deleted file mode 100644 index edad8e6c1..000000000 --- a/passes/opt/opt_dff_comp.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef OPT_DFF_COMP_H -#define OPT_DFF_COMP_H - -#include "kernel/rtlil.h" -#include -#include - -YOSYS_NAMESPACE_BEGIN - -typedef std::map pattern_t; - -inline std::optional find_complementary_pattern_var( - const pattern_t& left, - const pattern_t& right -) { - std::optional ret; - for (const auto &pt : left) { - if (right.count(pt.first) == 0) - return std::nullopt; - if (right.at(pt.first) == pt.second) - continue; - if (ret) - return std::nullopt; - ret = pt.first; - } - return ret; -} - -YOSYS_NAMESPACE_END - -#endif