From 830cb633e54d4eff25fe0df205610c54a95ef220 Mon Sep 17 00:00:00 2001 From: Marco Bartoli Date: Fri, 18 Sep 2026 20:25:37 +0200 Subject: [PATCH] Optimize covergroup bin metadata lookup (#8404) --- include/verilated_covergroup.cpp | 11 ++--- test_regress/t/t_covergroup_bin_counts.out | 14 ++++++ test_regress/t/t_covergroup_bin_counts.v | 50 ++++++++++++++++++++++ 3 files changed, 70 insertions(+), 5 deletions(-) diff --git a/include/verilated_covergroup.cpp b/include/verilated_covergroup.cpp index 845a4caf9..258db6940 100644 --- a/include/verilated_covergroup.cpp +++ b/include/verilated_covergroup.cpp @@ -67,11 +67,12 @@ std::string VlCoverpoint::normalBinName(uint32_t crossIdx) const { } const VlCovNamer& VlCoverpoint::namerFor(uint32_t i) const { - // Namers are appended in ascending order covering [0, m_total), - for (const VlCovNamer& nm : m_namers) { - if (i < nm.base() + nm.count()) return nm; - } - VL_UNREACHABLE; // LCOV_EXCL_LINE + // Namers are appended in ascending order covering [0, m_total). + const auto it = std::upper_bound( + m_namers.begin(), m_namers.end(), i, + [](uint32_t bin, const VlCovNamer& namer) { return bin < namer.base(); }); + assert(it != m_namers.begin()); + return *std::prev(it); } std::string VlCoverpoint::binName(uint32_t i) const { diff --git a/test_regress/t/t_covergroup_bin_counts.out b/test_regress/t/t_covergroup_bin_counts.out index 7aec83995..0d825867c 100644 --- a/test_regress/t/t_covergroup_bin_counts.out +++ b/test_regress/t/t_covergroup_bin_counts.out @@ -7,6 +7,20 @@ cg_mixed.opcode.load: 1 cg_mixed.opcode.nop: 1 cg_mixed.opcode.other: 1 cg_mixed.opcode.store: 1 +cg_namers.cp.first: 1 +cg_namers.cp.ignored[0] [ignore]: 1 +cg_namers.cp.ignored[1] [ignore]: 1 +cg_namers.cp.illegal [illegal]: 0 +cg_namers.cp.last: 5 +cg_namers.cp.middle[0]: 2 +cg_namers.cp.middle[1]: 3 +cg_namers.cp.middle[2]: 4 +cg_namers.cp_tag.zero: 17 +cg_namers.cx.first_x_zero [cross]: 1 +cg_namers.cx.last_x_zero [cross]: 5 +cg_namers.cx.middle[0]_x_zero [cross]: 2 +cg_namers.cx.middle[1]_x_zero [cross]: 3 +cg_namers.cx.middle[2]_x_zero [cross]: 4 cg_sel.cp.hi: 1 cg_sel.cp.lo: 1 cg_unbounded.cp.lo: 1 diff --git a/test_regress/t/t_covergroup_bin_counts.v b/test_regress/t/t_covergroup_bin_counts.v index 71843a091..715106ad9 100644 --- a/test_regress/t/t_covergroup_bin_counts.v +++ b/test_regress/t/t_covergroup_bin_counts.v @@ -16,6 +16,8 @@ module t; logic [3:0] data; logic [7:0] opcode; logic signed [3:0] sdata; + bit [6:0] named_value; + bit tag; typedef struct packed {bit [7:0] value;} f_t; f_t f1; @@ -79,6 +81,32 @@ module t; } endgroup + covergroup cg_namers; + cp: coverpoint named_value { + // Empty groups share a base index with the following nonempty namer. + bins empty_first[] = {[3 : 1]}; + bins first = {7}; + ignore_bins ignored[] = {8, 9}; + bins middle[] = {20, 21, 22}; + bins empty_middle[] = {[3 : 1]}; + bins empty_next[] = {[5 : 4]}; + illegal_bins illegal = {30}; + bins last = {31}; + bins empty_last[] = {[3 : 1]}; + } + cp_tag: coverpoint tag { + bins zero = {0}; + } + cx: cross cp, cp_tag; + endgroup + + covergroup cg_empty_namers; + cp: coverpoint named_value { + bins first[] = {[3 : 1]}; + bins last[] = {[5 : 4]}; + } + endgroup + cg cg_inst; cg_mixed cg_mixed_inst; cg_db cg_db_inst; @@ -87,6 +115,8 @@ module t; cg_unbounded_all cg_unbounded_all_inst; cg_unbounded_signed cg_unbounded_signed_inst; cg_sel cg_sel_inst; + cg_namers cg_namers_inst; + cg_empty_namers cg_empty_namers_inst; initial begin cg_inst = new; @@ -97,6 +127,8 @@ module t; cg_unbounded_all_inst = new; cg_unbounded_signed_inst = new; cg_sel_inst = new; + cg_namers_inst = new; + cg_empty_namers_inst = new; data = 0; cg_inst.sample(); // zero: 1 @@ -169,6 +201,24 @@ module t; cg_sel_inst.sample(); // nibble 9 -> hi (upper bits F ignored) `checkr(cg_sel_inst.get_inst_coverage(), 100.0); + for (int i = 0; i < 5; ++i) begin + case (i) + 0: named_value = 7; + 1: named_value = 20; + 2: named_value = 21; + 3: named_value = 22; + default: named_value = 31; + endcase + repeat (i + 1) cg_namers_inst.sample(); + end + named_value = 8; + cg_namers_inst.sample(); + named_value = 9; + cg_namers_inst.sample(); + cg_empty_namers_inst.sample(); + `checkr(cg_namers_inst.get_inst_coverage(), 100.0); + `checkr(cg_empty_namers_inst.get_inst_coverage(), 100.0); + $write("*-* All Finished *-*\n"); $finish; end