Overview
Branch coverage is a code-coverage metric that measures the fraction of decision-point edges (branches) in a program that are exercised by a test suite. Specifically, branch coverage indicates whether all possible branches of a conditional statement — including if-else-if, case, and for-loop constructs — have been executed; execution of only the "True branch" of a conditional yields 50% branch coverage.[1] Branch coverage of source code is a very widely used test criterion and is similar in nature to line coverage, MC/DC, and other test objectives such as assertion-violation coverage, since all of these reduce to the question of whether many test objectives are reachable by some test input.[2]
Formally, for a set of test inputs (\mathcal{S}), a set of branches (\mathcal{B}), and a branch (b) that can be evaluated to a Boolean value (v), branch coverage can be expressed as[6]
$$\mathrm{Cov}_{\text{branch}}(\mathcal{S}) = \frac{|{(b,v): \exists X, b \text{ evaluated to } v \text{ in } X}|}{2|\mathcal{B}|}$$
where the denominator (2|\mathcal{B}|) accounts for both true and false evaluations of every branch. Branch coverage is one of the main code-coverage types alongside statement coverage and path coverage, and is part of the broader notion of code coverage.[1]
Branch coverage in pre-silicon validation
In pre-silicon validation, branch coverage is one of the basic coverage metrics used at the unit-level testing phase, alongside statement coverage, to quantify the validation of individual modules. Once individually validated blocks proceed to interconnection testing, path coverage is used to quantify inter-block communication, and full-chip validation then shifts toward functionality-based coverage metrics rather than individual metrics such as statement and branch coverage.[1]
Branch coverage in post-silicon validation
In post-silicon validation, however, pre-silicon-like code coverage metrics — including statement, branch, and path coverage — are not readily applicable, because post-silicon contains logic equivalent to RTL code rather than the RTL source itself. Capturing branch coverage in post-silicon is therefore limited to proof-of-concept demonstrations and would not add value for quantifying validation. Implementing such code-based metrics in post-silicon also requires additional on-chip logic to capture and transfer the coverage information, increasing design time and cost.[1]
Branch coverage in hardware/processor fuzzing
Branch coverage is widely adopted as a feedback signal by hardware and processor fuzzers operating on RTL simulations. Because many RTL constructs (multiplexers, finite-state-machine transitions, conditional execution paths) only activate their branches under rare conditions, fuzzers instrument branch coverage to steer stimulus generation toward hard-to-activate areas of the design.
TheHuzz
In processor fuzzers such as TheHuzz, branch coverage is one of several hardware-oriented coverage metrics collected from RTL simulation. TheHuzz uses Synopsys VCS to simulate the target hardware and writes custom Python scripts that process the VCS logs to extract a union of coverage metrics including statement, branch, toggle, expression, and condition coverage, along with instruction traces.[3]
TheHuzz specifically adopts branch coverage to test each branching construct (the when block in its example) for both its when and otherwise conditions.[3] The optimizer of TheHuzz profiles each instruction–mutation (IM) pair to record which coverage points it hits, where C denotes the union of coverage metrics (statement, branch, expression, toggle, FSM, condition) and D : P × C → {0,1} indicates whether an IM pair hits a coverage point. The optimizer then finds the smallest subset Q of IM pairs that covers all the coverage points identified during profiling, and uses these optimal weights so that the seed generator selects instructions and the stimulus generator selects mutation techniques, thereby eliminating underperforming instructions and mutations.[3]
In TheHuzz's stimulus generator, every time new inputs are generated, the code coverage data of those inputs is used to discard underperforming inputs and retain only the inputs that trigger new coverage points — including new branch coverage points — steering the fuzzer toward discovering new coverage points quickly.[3]
FuSS
The FuSS framework (Fuzzing with Selective Symbolic execution) treats branch coverage as one of its primary evaluation metrics when validating RISC-V SoC designs. FuSS synergistically integrates coverage-guided fuzzing with selective symbolic execution: when hardware fuzzing reaches a coverage plateau, FuSS invokes selective symbolic execution that exploits the existing fuzzing trajectory to produce a minimal input sequence that efficiently explores hard-to-activate branches, avoiding the state-space explosion that affects property-checking-based alternatives.[5]
Empirical evaluation on four RISC-V SoC benchmarks (PicoSoC, UeRVSoC, VeeRwolf, and CVA6) shows that:
- Traditional fuzzing reaches a branch coverage plateau of approximately 80%.
- Fuzzing augmented with property checking outperforms traditional fuzzing but plateaus at around 88% branch coverage due to state-space explosion.
- FuSS achieves close to 100% branch coverage in less than 10 hours by seamlessly integrating selective symbolic execution with prior fuzzing efforts, focusing on hard-to-reach branches such as those inside multiplexers, FSM transitions, and complex conditionals.[5]
FuSS further demonstrates that coverage-plateau detection can be automated so that symbolic execution is invoked only when needed, and that pruning the fuzzer-generated program and aligning it with the hardware's control flow graph reduces the symbolic-execution search space to a small region between the current fuzzing trajectory and the target branch.[5]
GoldenFuzz
GoldenFuzz (a fuzzing framework that leverages golden reference models) formally defines branch coverage over a set of test inputs (\mathcal{S}) as (\mathrm{Cov}_{\text{branch}}(\mathcal{S}) = |{(b,v): \exists X, b \text{ evaluated to } v \text{ in } X}| / (2|\mathcal{B}|)), counting both true and false evaluations of every branch.[6] This branch-coverage metric is one of several code-coverage metrics tracked by GoldenFuzz alongside condition, expression, FSM, and toggle coverage, and is used in the framework's two-stage coverage-driven exploration to drive differential trace comparison between the device under test (DUT) and a golden reference model (GRM).[6]
Coverage-directed test generation with uGP and FireDrill
MicroGP (uGP) and FireDrill are coverage-directed test-generation (CDG) tools used in industrial hardware verification flows; both target branch coverage as one of the code-coverage metrics driving the search.[7]
In an industrial evaluation contrasting Evolutionary uGP (Evo), Random uGP (Rnd), and FireDrill (FD) on three configurations that differ in their secondary sorting of individuals (ASC, DSC, BIRTH), branch coverage — together with Expression (E) and Toggle (T) coverage — is used to score tests during the genetic-algorithm evolution.[7] Empirical results from that evaluation show that:
- Single-best test branch coverage ranged across approximately 86–94% for all configurations and methods.[7]
- Cumulative branch coverage after running a regression suite reached 98–99% across configurations.[7]
- Branch coverage results correlate positively with test size, but Evo uGP runs were unable to trade off the lack of code diversity in their evolved tests for higher branch coverage, while Rnd uGP and FD ran with smaller test sizes and still achieved comparable or better branch coverage.[7]
- Counter-intuitively, Expression coverage exceeded Branch coverage during coverage progression; the remaining uncovered branches tend to depend on simple antecedent variables and could be reached if such variables were satisfied, motivating the use of branch coverage together with expression coverage when guiding CDG.[7]
The BIRTH configuration produced the best Branch coverage results on average, reaffirming the correlation between test size and Branch coverage.[7]
Limitations and stronger criteria
- Concolic test generation targets exhaustive branch coverage, but covers paths more efficiently than branches, which limits its ability to provide an explanation (such as unreachability proofs) for branches that are not covered. Modern tools often obtain high coverage scores without being able to provide an explanation for why some branches are not covered, such as a demonstration that they are unreachable.[2]
- In continuous-integration settings, branch coverage is treated as a relatively weak coverage criterion; mutation coverage is a stronger metric that reveals additional weaknesses in the test suite compared to branch coverage, at acceptable performance overhead during the project build. Three reasons limit mutation coverage adoption: (1) the difficulty of its integration into the build system, (2) the perception that branch coverage is "good enough", and (3) the performance overhead during the build.[4]
- In hardware fuzzing, branch coverage alone is insufficient for some bug classes: existing fuzzers that rely on branch (or other restricted) coverage cannot cover bugs related to floating wires (high-impedance state, CWE-1189), signal transitions on MUX select signals, MUX DFFs, or certain protocol-level bugs. TheHuzz therefore combines branch coverage with statement, toggle, expression, condition, and FSM coverage to capture a broader range of hardware behaviors.[3]
- Pure coverage-guided fuzzing on RTL designs plateaus at roughly 80% branch coverage because hard-to-activate basic blocks remain unreachable from random mutations alone; property-checking-based augmentation pushes this to ~88% but still suffers from state-space explosion, motivating selective-symbolic-execution hybrids such as FuSS.[5]
- Branch coverage (a code-based metric) does not readily translate to post-silicon validation, where the silicon contains logic equivalent to RTL code rather than the RTL source itself; applying branch coverage in post-silicon would require additional on-chip logic to capture coverage information, increasing design time and cost without adding clear validation value.[1]
References
[1] "Unified Coverage Methodology for SoC Post-Silicon Validation" (chunk ids: 94dda0b8-2b6d-4d90-98cb-85b8199fd03c, 9558e166-a0c2-46ba-b218-6c52c9f1b571, 18bd92ff-4ffa-492f-af4f-02e2e012ca38) — https://www.scirp.org/journal/paperinformation?paperid=71278 [2] "Towards exhaustive branch coverage with PathCrawler" — https://arxiv.org/abs/2105.05517v1 [3] "TheHuzz: Instruction Fuzzing of Processors Using Golden Reference Models" (USENIX Security 2022, chunk ids: 7d1ca475-9c0c-4b68-bc24-db339ffa3987, fedd43f9-88d9-4388-a2c7-805a2eea51f4, 401f59d6-8bcf-4b91-b70f-90125d8d19e0) — https://www.usenix.org/system/files/sec22fall_kande.pdf [4] "Comparing Mutation Coverage Against Branch Coverage in an Industrial Setting" — https://arxiv.org/abs/2104.11767v1 [5] "FuSS: Coverage-Directed Hardware Fuzzing with Selective Symbolic Execution" (Jayasena, Nallapaneni, Mishra; ACM TECS 2025, chunk ids: 42d5be23-32a7-4abc-8507-0dd983e10874, 73d5005f-c13b-40f6-ac7f-400accef9635, 035b9f02-515b-497b-8cf9-52141812a28a) — https://www.cise.ufl.edu/research/cad/Publications/tecs25.pdf [6] "GoldenFuzz Fuzzing Framework" (chunk ids: fd177784-da3b-4bdb-9d4d-18bea91e20cc) — https://www.emergentmind.com/topics/goldenfuzz [7] "Feedback-based Coverage Directed Test Generation: An industrial evaluation" (Ioannides, Barrett, Eder; chunk ids: 6c1d225b-654f-416a-9e67-29582c7ddbe3, f623fe56-bb98-4601-815a-3eb6a8de11a5, 27ad60a8-e917-4e26-b314-6a6287536593) — https://dl.icdst.org/pdfs/files3/05ff05bd010a198d8b9ba8d013583499.pdf