From a75e0b2e9283b6947c5e144067da0794aac7ede4 Mon Sep 17 00:00:00 2001 From: nella Date: Mon, 26 Jan 2026 14:24:01 +0100 Subject: [PATCH] opt_dff minor cleanup, added tests for comp var. --- passes/opt/opt_dff.cc | 20 +- passes/opt/opt_dff_comp.h | 31 +++ .../opt/optDffFindComplementaryPatternTest.cc | 179 ++++++++++++++++++ 3 files changed, 215 insertions(+), 15 deletions(-) create mode 100644 passes/opt/opt_dff_comp.h create mode 100644 tests/unit/opt/optDffFindComplementaryPatternTest.cc diff --git a/passes/opt/opt_dff.cc b/passes/opt/opt_dff.cc index c78145549..ad891af90 100644 --- a/passes/opt/opt_dff.cc +++ b/passes/opt/opt_dff.cc @@ -27,6 +27,7 @@ #include "kernel/ffinit.h" #include "kernel/ff.h" #include "passes/techmap/simplemap.h" +#include "passes/opt/opt_dff_comp.h" #include #include @@ -55,7 +56,7 @@ struct OptDffWorker dict bitusers; // Signal sink count dict bit2mux; // Signal bit to driving MUX - // Eattern matching for clock enable + // Pattern matching for clock enable typedef std::map pattern_t; // Control signal -> required vals typedef std::set patterns_t; // Alternative patterns (OR) typedef std::pair ctrl_t; // Control signal @@ -224,17 +225,6 @@ struct OptDffWorker { auto new_patterns = patterns; - auto find_comp = [](const auto& left, const auto& right) -> std::optional { - std::optional ret; - for (const auto &pt: left) { - if (right.count(pt.first) == 0) return {}; - if (right.at(pt.first) == pt.second) continue; - if (ret) return {}; - ret = pt.first; - } - return ret; - }; - // Remove complimentary patterns bool optimized; do { @@ -243,7 +233,7 @@ struct OptDffWorker 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_comp(left, right); + const auto complimentary_var = find_complementary_pattern_var(left, right); if (complimentary_var && new_patterns.count(right)) { new_patterns.erase(right); @@ -624,7 +614,7 @@ struct OptDffWorker ctrls_t resets; State reset_val = ff.has_srst ? ff.val_srst[i] : State::Sx; - while (bit2mux.count(ff.sig_d[i]) && bitusers[ff.sig_d[i]] == 1) { + if (bit2mux.count(ff.sig_d[i]) && bitusers[ff.sig_d[i]] == 1) { cell_int_t mbit = bit2mux.at(ff.sig_d[i]); if (GetSize(mbit.first->getPort(ID::S)) != 1) break; @@ -712,7 +702,7 @@ struct OptDffWorker for (int i = 0; i < ff.width; i++) { ctrls_t enables; - while (bit2mux.count(ff.sig_d[i]) && bitusers[ff.sig_d[i]] == 1) { + if (bit2mux.count(ff.sig_d[i]) && bitusers[ff.sig_d[i]] == 1) { cell_int_t mbit = bit2mux.at(ff.sig_d[i]); if (GetSize(mbit.first->getPort(ID::S)) != 1) break; diff --git a/passes/opt/opt_dff_comp.h b/passes/opt/opt_dff_comp.h new file mode 100644 index 000000000..edad8e6c1 --- /dev/null +++ b/passes/opt/opt_dff_comp.h @@ -0,0 +1,31 @@ +#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 diff --git a/tests/unit/opt/optDffFindComplementaryPatternTest.cc b/tests/unit/opt/optDffFindComplementaryPatternTest.cc new file mode 100644 index 000000000..38fa4bd2d --- /dev/null +++ b/tests/unit/opt/optDffFindComplementaryPatternTest.cc @@ -0,0 +1,179 @@ +#include +#include "passes/opt/opt_dff_comp.h" + +YOSYS_NAMESPACE_BEGIN + +class FindComplementaryPatternVarTest : public ::testing::Test { +protected: + RTLIL::Design *design; + RTLIL::Module *module; + RTLIL::Wire *wire_a; + RTLIL::Wire *wire_b; + RTLIL::Wire *wire_c; + RTLIL::Wire *bus; + + void SetUp() override { + design = new RTLIL::Design; + module = design->addModule(ID(test_module)); + wire_a = module->addWire(ID(a)); + wire_b = module->addWire(ID(b)); + wire_c = module->addWire(ID(c)); + bus = module->addWire(ID(bus), 4); + } + + void TearDown() override { + delete design; + } + + RTLIL::SigBit bit(RTLIL::Wire *w, int offset = 0) { + return RTLIL::SigBit(w, offset); + } +}; + +TEST_F(FindComplementaryPatternVarTest, EmptyPatterns) { + pattern_t left, right; + + auto result = find_complementary_pattern_var(left, right); + EXPECT_FALSE(result.has_value()); +} + +TEST_F(FindComplementaryPatternVarTest, IdenticalSingleVar) { + pattern_t left, right; + left[bit(wire_a)] = true; + right[bit(wire_a)] = true; + + auto result = find_complementary_pattern_var(left, right); + EXPECT_FALSE(result.has_value()); +} + +TEST_F(FindComplementaryPatternVarTest, ComplementarySingleVar) { + pattern_t left, right; + left[bit(wire_a)] = true; + right[bit(wire_a)] = false; + + auto result = find_complementary_pattern_var(left, right); + ASSERT_TRUE(result.has_value()); + EXPECT_EQ(result.value(), bit(wire_a)); +} + +TEST_F(FindComplementaryPatternVarTest, MissingKeyInRight) { + pattern_t left, right; + left[bit(wire_a)] = true; + left[bit(wire_b)] = false; + right[bit(wire_a)] = true; + + auto result = find_complementary_pattern_var(left, right); + EXPECT_FALSE(result.has_value()); +} + +TEST_F(FindComplementaryPatternVarTest, TwoVarsOneComplementary) { + pattern_t left, right; + left[bit(wire_a)] = true; + left[bit(wire_b)] = false; + right[bit(wire_a)] = true; + right[bit(wire_b)] = true; + + auto result = find_complementary_pattern_var(left, right); + ASSERT_TRUE(result.has_value()); + EXPECT_EQ(result.value(), bit(wire_b)); +} + +TEST_F(FindComplementaryPatternVarTest, TwoVarsBothComplementary) { + pattern_t left, right; + left[bit(wire_a)] = true; + left[bit(wire_b)] = false; + right[bit(wire_a)] = false; + right[bit(wire_b)] = true; + + auto result = find_complementary_pattern_var(left, right); + EXPECT_FALSE(result.has_value()); +} + +TEST_F(FindComplementaryPatternVarTest, LeftSubsetOfRight) { + pattern_t left, right; + left[bit(wire_a)] = true; + left[bit(wire_b)] = false; + right[bit(wire_a)] = true; + right[bit(wire_b)] = true; + right[bit(wire_c)] = false; + + auto result = find_complementary_pattern_var(left, right); + ASSERT_TRUE(result.has_value()); + EXPECT_EQ(result.value(), bit(wire_b)); +} + +TEST_F(FindComplementaryPatternVarTest, ThreeVarsAllSame) { + pattern_t left, right; + left[bit(wire_a)] = true; + left[bit(wire_b)] = false; + left[bit(wire_c)] = true; + right[bit(wire_a)] = true; + right[bit(wire_b)] = false; + right[bit(wire_c)] = true; + + auto result = find_complementary_pattern_var(left, right); + EXPECT_FALSE(result.has_value()); +} + +TEST_F(FindComplementaryPatternVarTest, PracticalPatternSimplification) { + pattern_t pattern1, pattern2; + pattern1[bit(bus, 0)] = true; + pattern1[bit(bus, 1)] = true; + pattern2[bit(bus, 0)] = true; + pattern2[bit(bus, 1)] = false; + + auto result = find_complementary_pattern_var(pattern1, pattern2); + ASSERT_TRUE(result.has_value()); + EXPECT_EQ(result.value(), bit(bus, 1)); + + // Swapped args + auto result2 = find_complementary_pattern_var(pattern2, pattern1); + ASSERT_TRUE(result2.has_value()); + EXPECT_EQ(result2.value(), bit(bus, 1)); +} + +TEST_F(FindComplementaryPatternVarTest, MuxTreeClockEnableDetection) { + pattern_t feedback_path1, feedback_path2; + feedback_path1[bit(wire_a)] = true; + feedback_path1[bit(wire_b)] = true; + feedback_path2[bit(wire_a)] = true; + feedback_path2[bit(wire_b)] = false; + + auto comp = find_complementary_pattern_var(feedback_path1, feedback_path2); + ASSERT_TRUE(comp.has_value()); + EXPECT_EQ(comp.value(), bit(wire_b)); + + pattern_t simplified = feedback_path1; + simplified.erase(comp.value()); + + EXPECT_EQ(simplified.size(), 1); + EXPECT_TRUE(simplified.count(bit(wire_a))); + EXPECT_TRUE(simplified[bit(wire_a)]); +} + +TEST_F(FindComplementaryPatternVarTest, AsymmetricPatterns) { + pattern_t left, right; + left[bit(wire_a)] = true; + right[bit(wire_a)] = false; + right[bit(wire_b)] = true; + right[bit(wire_c)] = false; + + auto result = find_complementary_pattern_var(left, right); + ASSERT_TRUE(result.has_value()); + EXPECT_EQ(result.value(), bit(wire_a)); +} + +TEST_F(FindComplementaryPatternVarTest, WireOffsetDistinction) { + pattern_t left, right; + left[bit(bus, 0)] = true; + left[bit(bus, 1)] = false; + right[bit(bus, 0)] = true; + right[bit(bus, 1)] = true; + right[bit(bus, 2)] = false; + + auto result = find_complementary_pattern_var(left, right); + ASSERT_TRUE(result.has_value()); + EXPECT_EQ(result.value(), bit(bus, 1)); +} + +YOSYS_NAMESPACE_END