From 676ac184edf5386f6f9c7d7dfbc9d363179b3142 Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Mon, 6 Jul 2026 21:35:51 -0700 Subject: [PATCH] opt_prienc: guard ConstEval fingerprint inputs against constant/aliased bits The round-robin detector fed sigmap(wire) signals straight into ConstEval::set() while sweeping test vectors. On real designs a candidate bus can have bits tied to constants, repeated bits, or a req/start pair that alias to the same net after sigmap. ConstEval::set() asserts (current_val[i].wire != NULL || current_val[i] == value[i]) when asked to re-pin such a bit to a conflicting value, crashing the pass (consteval.h:83) on designs like veer/picorv32/murax/raygentop under formal synthesis. Add clean_set_signals() and reject any fingerprint candidate whose set-signals contain constant bits, repeated bits, or overlap each other, in both the priority-encoder and round-robin paths. Skipping an unclean candidate only forgoes a possible rewrite; it never produces an incorrect one. Clean candidates (the intended patterns) are unaffected. Co-authored-by: Cursor --- passes/opt/opt_prienc.cc | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/passes/opt/opt_prienc.cc b/passes/opt/opt_prienc.cc index 7231db45e..07089283c 100644 --- a/passes/opt/opt_prienc.cc +++ b/passes/opt/opt_prienc.cc @@ -243,6 +243,23 @@ struct OptPriEncWorker { return vs; } + // ConstEval::set() requires every (sigmap-canonical) bit it pins to be a + // distinct free wire bit. Real designs can tie parts of a bus to constants + // or alias nets together, so guard the fingerprint inputs: reject signals + // containing constant or repeated bits, and (across the whole set) any + // overlap between them. This prevents a ConstEval assertion; skipping an + // unclean candidate only forgoes a possible rewrite, never yields a wrong + // one. + static bool clean_set_signals(std::initializer_list sigs) { + pool seen; + for (const SigSpec* sp : sigs) + for (auto bit : *sp) { + if (bit.wire == nullptr) return false; + if (!seen.insert(bit).second) return false; + } + return true; + } + // Run all candidate test vectors through ConstEval and try to match each of // the four PE variants against the recorded outputs. Returns the matched // variant, or NONE. @@ -257,6 +274,9 @@ struct OptPriEncWorker { if (!clz_full_ok && !ctz_full_ok && !clz_short_ok && !ctz_short_ok) return PEVariant::NONE; + if (!clean_set_signals({&T_sig})) + return PEVariant::NONE; + auto vs = gen_test_vectors(N); for (auto& v : vs) { ce.push(); @@ -440,6 +460,8 @@ struct OptPriEncWorker { int fingerprint_rr(SigSpec req_sig, SigSpec start_sig, SigSpec S_sig, int N, int W) { ConstEval ce(module); + if (!clean_set_signals({&req_sig, &start_sig})) + return -1; bool ok0 = true, ok1 = true; auto deck = gen_test_vectors(N); int checks = 0;