From b71dcdb3dd200b061285eb8d6e864b2cfb469718 Mon Sep 17 00:00:00 2001
From: Zalathar <Zalathar@users.noreply.github.com>
Date: Sun, 21 Apr 2024 18:50:05 +1000
Subject: [PATCH 1/4] coverage: Add another simple test for guarded match arms

---
 tests/coverage/branch/guard-simple.cov-map  | 24 ++++++++++++++++++
 tests/coverage/branch/guard-simple.coverage | 28 +++++++++++++++++++++
 tests/coverage/branch/guard-simple.rs       | 19 ++++++++++++++
 3 files changed, 71 insertions(+)
 create mode 100644 tests/coverage/branch/guard-simple.cov-map
 create mode 100644 tests/coverage/branch/guard-simple.coverage
 create mode 100644 tests/coverage/branch/guard-simple.rs

diff --git a/tests/coverage/branch/guard-simple.cov-map b/tests/coverage/branch/guard-simple.cov-map
new file mode 100644
index 0000000000000..8eb9c54ff4bca
--- /dev/null
+++ b/tests/coverage/branch/guard-simple.cov-map
@@ -0,0 +1,24 @@
+Function name: guard_simple::never_taken
+Raw bytes (56): 0x[01, 01, 04, 01, 05, 11, 09, 0f, 0d, 05, 09, 08, 01, 08, 01, 02, 1e, 20, 05, 02, 02, 0e, 00, 1e, 05, 00, 22, 00, 24, 11, 01, 0e, 00, 1e, 20, 09, 06, 00, 0e, 00, 1e, 09, 00, 22, 00, 24, 0d, 01, 0e, 00, 10, 0b, 02, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 4
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Counter(4), rhs = Counter(2)
+- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(3)
+- expression 3 operands: lhs = Counter(1), rhs = Counter(2)
+Number of file 0 mappings: 8
+- Code(Counter(0)) at (prev + 8, 1) to (start + 2, 30)
+- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 2, 14) to (start + 0, 30)
+    true  = c1
+    false = (c0 - c1)
+- Code(Counter(1)) at (prev + 0, 34) to (start + 0, 36)
+- Code(Counter(4)) at (prev + 1, 14) to (start + 0, 30)
+- Branch { true: Counter(2), false: Expression(1, Sub) } at (prev + 0, 14) to (start + 0, 30)
+    true  = c2
+    false = (c4 - c2)
+- Code(Counter(2)) at (prev + 0, 34) to (start + 0, 36)
+- Code(Counter(3)) at (prev + 1, 14) to (start + 0, 16)
+- Code(Expression(2, Add)) at (prev + 2, 1) to (start + 0, 2)
+    = ((c1 + c2) + c3)
+
diff --git a/tests/coverage/branch/guard-simple.coverage b/tests/coverage/branch/guard-simple.coverage
new file mode 100644
index 0000000000000..ac90c48c44342
--- /dev/null
+++ b/tests/coverage/branch/guard-simple.coverage
@@ -0,0 +1,28 @@
+   LL|       |#![feature(coverage_attribute)]
+   LL|       |//@ edition: 2021
+   LL|       |//@ compile-flags: -Zcoverage-options=branch
+   LL|       |//@ llvm-cov-flags: --show-branches=count
+   LL|       |
+   LL|       |use core::hint::black_box;
+   LL|       |
+   LL|      1|fn never_taken() {
+   LL|      1|    match black_box(false) {
+   LL|      1|        _ if black_box(false) => {}
+                                               ^0
+  ------------------
+  |  Branch (LL:14): [True: 0, False: 1]
+  ------------------
+   LL|      1|        _ if black_box(false) => {}
+                                               ^0
+  ------------------
+  |  Branch (LL:14): [True: 0, False: 1]
+  ------------------
+   LL|      1|        _ => {}
+   LL|       |    }
+   LL|      1|}
+   LL|       |
+   LL|       |#[coverage(off)]
+   LL|       |fn main() {
+   LL|       |    never_taken();
+   LL|       |}
+
diff --git a/tests/coverage/branch/guard-simple.rs b/tests/coverage/branch/guard-simple.rs
new file mode 100644
index 0000000000000..92fea499cd98d
--- /dev/null
+++ b/tests/coverage/branch/guard-simple.rs
@@ -0,0 +1,19 @@
+#![feature(coverage_attribute)]
+//@ edition: 2021
+//@ compile-flags: -Zcoverage-options=branch
+//@ llvm-cov-flags: --show-branches=count
+
+use core::hint::black_box;
+
+fn never_taken() {
+    match black_box(false) {
+        _ if black_box(false) => {}
+        _ if black_box(false) => {}
+        _ => {}
+    }
+}
+
+#[coverage(off)]
+fn main() {
+    never_taken();
+}

From 79e5b4f7c06bd1f476aa833d0ca80c1472cce158 Mon Sep 17 00:00:00 2001
From: Zalathar <Zalathar@users.noreply.github.com>
Date: Sun, 21 Apr 2024 14:11:14 +1000
Subject: [PATCH 2/4] coverage: Represent branches as a list of arms

Within the `InstrumentCoverage` pass, we now represent branches as a list of
arms, instead of a true/false pair, until we prepare the final table of
mappings to be attached to the MIR body.

(We then flatten the list into two-way branches by treating each arm as a
branch between its success block, and the total of all later arms.)

Currently all of the branches produced by MIR building are still two-way, but
this is a step towards allowing many-way branches.
---
 .../src/coverageinfo/map_data.rs              | 10 ++-
 .../src/coverage/counters.rs                  |  7 +-
 .../src/coverage/mappings.rs                  | 36 ++++-----
 .../rustc_mir_transform/src/coverage/mod.rs   | 76 +++++++++++++------
 4 files changed, 87 insertions(+), 42 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
index b969fe27a99be..a73ae810c2278 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
@@ -66,7 +66,15 @@ impl<'tcx> FunctionCoverageCollector<'tcx> {
         // For each expression ID that is directly used by one or more mappings,
         // mark it as not-yet-seen. This indicates that we expect to see a
         // corresponding `ExpressionUsed` statement during MIR traversal.
-        for term in function_coverage_info.mappings.iter().flat_map(|m| m.kind.terms()) {
+        for term in function_coverage_info
+            .mappings
+            .iter()
+            // For many-armed branches, some branch mappings will have expressions
+            // that don't correspond to any node in the control-flow graph, so don't
+            // expect to see `ExpressionUsed` statements for them.
+            .filter(|m| !matches!(m.kind, MappingKind::Branch { .. }))
+            .flat_map(|m| m.kind.terms())
+        {
             if let CovTerm::Expression(id) = term {
                 expressions_seen.remove(id);
             }
diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs
index a8b0f4a8d6df4..40fdc905147b6 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters.rs
@@ -101,7 +101,12 @@ impl CoverageCounters {
         BcbCounter::Counter { id }
     }
 
-    fn make_expression(&mut self, lhs: BcbCounter, op: Op, rhs: BcbCounter) -> BcbCounter {
+    pub(super) fn make_expression(
+        &mut self,
+        lhs: BcbCounter,
+        op: Op,
+        rhs: BcbCounter,
+    ) -> BcbCounter {
         let new_expr = BcbExpression { lhs, op, rhs };
         *self
             .expressions_memo
diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs
index 759bb7c1f9d96..81fe971cf9215 100644
--- a/compiler/rustc_mir_transform/src/coverage/mappings.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs
@@ -21,14 +21,11 @@ pub(super) struct CodeMapping {
     pub(super) bcb: BasicCoverageBlock,
 }
 
-/// This is separate from [`MCDCBranch`] to help prepare for larger changes
-/// that will be needed for improved branch coverage in the future.
-/// (See <https://github.com/rust-lang/rust/pull/124217>.)
 #[derive(Debug)]
-pub(super) struct BranchPair {
+pub(super) struct BranchArm {
     pub(super) span: Span,
-    pub(super) true_bcb: BasicCoverageBlock,
-    pub(super) false_bcb: BasicCoverageBlock,
+    pub(super) pre_guard_bcb: BasicCoverageBlock,
+    pub(super) arm_taken_bcb: BasicCoverageBlock,
 }
 
 /// Associates an MC/DC branch span with condition info besides fields for normal branch.
@@ -56,7 +53,7 @@ pub(super) struct MCDCDecision {
 #[derive(Default)]
 pub(super) struct ExtractedMappings {
     pub(super) code_mappings: Vec<CodeMapping>,
-    pub(super) branch_pairs: Vec<BranchPair>,
+    pub(super) branch_arm_lists: Vec<Vec<BranchArm>>,
     pub(super) mcdc_bitmap_bytes: u32,
     pub(super) mcdc_branches: Vec<MCDCBranch>,
     pub(super) mcdc_decisions: Vec<MCDCDecision>,
@@ -71,7 +68,7 @@ pub(super) fn extract_all_mapping_info_from_mir<'tcx>(
     basic_coverage_blocks: &CoverageGraph,
 ) -> ExtractedMappings {
     let mut code_mappings = vec![];
-    let mut branch_pairs = vec![];
+    let mut branch_arm_lists = vec![];
     let mut mcdc_bitmap_bytes = 0;
     let mut mcdc_branches = vec![];
     let mut mcdc_decisions = vec![];
@@ -93,7 +90,7 @@ pub(super) fn extract_all_mapping_info_from_mir<'tcx>(
         extract_refined_covspans(mir_body, hir_info, basic_coverage_blocks, &mut code_mappings);
     }
 
-    branch_pairs.extend(extract_branch_pairs(mir_body, hir_info, basic_coverage_blocks));
+    branch_arm_lists.extend(extract_branch_arm_lists(mir_body, hir_info, basic_coverage_blocks));
 
     extract_mcdc_mappings(
         mir_body,
@@ -106,7 +103,7 @@ pub(super) fn extract_all_mapping_info_from_mir<'tcx>(
 
     ExtractedMappings {
         code_mappings,
-        branch_pairs,
+        branch_arm_lists,
         mcdc_bitmap_bytes,
         mcdc_branches,
         mcdc_decisions,
@@ -121,7 +118,7 @@ impl ExtractedMappings {
         // Fully destructure self to make sure we don't miss any fields that have mappings.
         let Self {
             code_mappings,
-            branch_pairs,
+            branch_arm_lists,
             mcdc_bitmap_bytes: _,
             mcdc_branches,
             mcdc_decisions,
@@ -136,9 +133,11 @@ impl ExtractedMappings {
         for &CodeMapping { span: _, bcb } in code_mappings {
             insert(bcb);
         }
-        for &BranchPair { true_bcb, false_bcb, .. } in branch_pairs {
-            insert(true_bcb);
-            insert(false_bcb);
+        for &BranchArm { span: _, pre_guard_bcb, arm_taken_bcb } in
+            branch_arm_lists.iter().flatten()
+        {
+            insert(pre_guard_bcb);
+            insert(arm_taken_bcb);
         }
         for &MCDCBranch { true_bcb, false_bcb, .. } in mcdc_branches {
             insert(true_bcb);
@@ -179,16 +178,16 @@ fn resolve_block_markers(
 }
 
 // FIXME: There is currently a lot of redundancy between
-// `extract_branch_pairs` and `extract_mcdc_mappings`. This is needed so
+// `extract_branch_arm_lists` and `extract_mcdc_mappings`. This is needed so
 // that they can each be modified without interfering with the other, but in
 // the long term we should try to bring them together again when branch coverage
 // and MC/DC coverage support are more mature.
 
-pub(super) fn extract_branch_pairs(
+pub(super) fn extract_branch_arm_lists(
     mir_body: &mir::Body<'_>,
     hir_info: &ExtractedHirInfo,
     basic_coverage_blocks: &CoverageGraph,
-) -> Vec<BranchPair> {
+) -> Vec<Vec<BranchArm>> {
     let Some(branch_info) = mir_body.coverage_branch_info.as_deref() else { return vec![] };
 
     let block_markers = resolve_block_markers(branch_info, mir_body);
@@ -211,7 +210,8 @@ pub(super) fn extract_branch_pairs(
             let true_bcb = bcb_from_marker(true_marker)?;
             let false_bcb = bcb_from_marker(false_marker)?;
 
-            Some(BranchPair { span, true_bcb, false_bcb })
+            let arm = |bcb| BranchArm { span, pre_guard_bcb: bcb, arm_taken_bcb: bcb };
+            Some(vec![arm(true_bcb), arm(false_bcb)])
         })
         .collect::<Vec<_>>()
 }
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index 4a64d21f3d17b..a8c8c37d8d08a 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -8,7 +8,7 @@ mod spans;
 mod tests;
 
 use rustc_middle::mir::coverage::{
-    CodeRegion, CoverageKind, DecisionInfo, FunctionCoverageInfo, Mapping, MappingKind,
+    CodeRegion, CoverageKind, DecisionInfo, FunctionCoverageInfo, Mapping, MappingKind, Op,
 };
 use rustc_middle::mir::{
     self, BasicBlock, BasicBlockData, SourceInfo, Statement, StatementKind, Terminator,
@@ -21,7 +21,7 @@ use rustc_span::{BytePos, Pos, RelativeBytePos, Span, Symbol};
 
 use crate::coverage::counters::{CounterIncrementSite, CoverageCounters};
 use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph};
-use crate::coverage::mappings::ExtractedMappings;
+use crate::coverage::mappings::{BranchArm, ExtractedMappings};
 use crate::MirPass;
 
 /// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected
@@ -91,10 +91,10 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
     }
 
     let bcb_has_counter_mappings = |bcb| bcbs_with_counter_mappings.contains(bcb);
-    let coverage_counters =
+    let mut coverage_counters =
         CoverageCounters::make_bcb_counters(&basic_coverage_blocks, bcb_has_counter_mappings);
 
-    let mappings = create_mappings(tcx, &hir_info, &extracted_mappings, &coverage_counters);
+    let mappings = create_mappings(tcx, &hir_info, &extracted_mappings, &mut coverage_counters);
     if mappings.is_empty() {
         // No spans could be converted into valid mappings, so skip this function.
         debug!("no spans could be converted into valid mappings; skipping");
@@ -136,7 +136,7 @@ fn create_mappings<'tcx>(
     tcx: TyCtxt<'tcx>,
     hir_info: &ExtractedHirInfo,
     extracted_mappings: &ExtractedMappings,
-    coverage_counters: &CoverageCounters,
+    coverage_counters: &mut CoverageCounters,
 ) -> Vec<Mapping> {
     let source_map = tcx.sess.source_map();
     let body_span = hir_info.body_span;
@@ -148,24 +148,66 @@ fn create_mappings<'tcx>(
         &source_file.name.for_scope(tcx.sess, RemapPathScopeComponents::MACRO).to_string_lossy(),
     );
 
-    let term_for_bcb = |bcb| {
-        coverage_counters
-            .bcb_counter(bcb)
-            .expect("all BCBs with spans were given counters")
-            .as_term()
-    };
     let region_for_span = |span: Span| make_code_region(source_map, file_name, span, body_span);
 
     // Fully destructure the mappings struct to make sure we don't miss any kinds.
     let ExtractedMappings {
         code_mappings,
-        branch_pairs,
+        branch_arm_lists,
         mcdc_bitmap_bytes: _,
         mcdc_branches,
         mcdc_decisions,
     } = extracted_mappings;
     let mut mappings = Vec::new();
 
+    // Process branch arms first, because they might need to mutate `coverage_counters`
+    // to create new expressions.
+    for arm_list in branch_arm_lists {
+        let mut arms_rev = arm_list.iter().rev();
+
+        let mut rest_counter = {
+            // The last arm's span is ignored, because its BCB is only used as the
+            // false branch of the second-last arm; it's not a branch of its own.
+            let Some(&BranchArm { span: _, pre_guard_bcb, arm_taken_bcb }) = arms_rev.next() else {
+                continue;
+            };
+            debug_assert_eq!(pre_guard_bcb, arm_taken_bcb, "last arm should not have a guard");
+            coverage_counters.bcb_counter(pre_guard_bcb).expect("all relevant BCBs have counters")
+        };
+
+        // All relevant BCBs should have counters, so we can `.unwrap()` them.
+        for &BranchArm { span, pre_guard_bcb, arm_taken_bcb } in arms_rev {
+            // Number of times the pattern matched.
+            let matched_counter = coverage_counters.bcb_counter(pre_guard_bcb).unwrap();
+            // Number of times the pattern matched and the guard succeeded.
+            let arm_taken_counter = coverage_counters.bcb_counter(arm_taken_bcb).unwrap();
+            // Total number of times execution logically reached this pattern.
+            let reached_counter =
+                coverage_counters.make_expression(rest_counter, Op::Add, arm_taken_counter);
+            // Number of times execution reached this pattern, but didn't match it.
+            let unmatched_counter =
+                coverage_counters.make_expression(reached_counter, Op::Subtract, matched_counter);
+
+            let kind = MappingKind::Branch {
+                true_term: matched_counter.as_term(),
+                false_term: unmatched_counter.as_term(),
+            };
+
+            if let Some(code_region) = region_for_span(span) {
+                mappings.push(Mapping { kind, code_region });
+            }
+
+            rest_counter = reached_counter;
+        }
+    }
+
+    let term_for_bcb = |bcb| {
+        coverage_counters
+            .bcb_counter(bcb)
+            .expect("all BCBs with spans were given counters")
+            .as_term()
+    };
+
     mappings.extend(code_mappings.iter().filter_map(
         // Ordinary code mappings are the simplest kind.
         |&mappings::CodeMapping { span, bcb }| {
@@ -175,16 +217,6 @@ fn create_mappings<'tcx>(
         },
     ));
 
-    mappings.extend(branch_pairs.iter().filter_map(
-        |&mappings::BranchPair { span, true_bcb, false_bcb }| {
-            let true_term = term_for_bcb(true_bcb);
-            let false_term = term_for_bcb(false_bcb);
-            let kind = MappingKind::Branch { true_term, false_term };
-            let code_region = region_for_span(span)?;
-            Some(Mapping { kind, code_region })
-        },
-    ));
-
     mappings.extend(mcdc_branches.iter().filter_map(
         |&mappings::MCDCBranch { span, true_bcb, false_bcb, condition_info, decision_depth: _ }| {
             let code_region = region_for_span(span)?;

From a513c92fdcd720efe8132a6db48ec8e4b07557b2 Mon Sep 17 00:00:00 2001
From: Zalathar <Zalathar@users.noreply.github.com>
Date: Sun, 21 Apr 2024 14:28:08 +1000
Subject: [PATCH 3/4] coverage: Represent branches as a list of arms during MIR
 building, too

---
 compiler/rustc_middle/src/mir/coverage.rs     | 12 +++--
 compiler/rustc_middle/src/mir/pretty.rs       | 19 ++++----
 .../rustc_mir_build/src/build/coverageinfo.rs | 23 ++++-----
 .../src/coverage/mappings.rs                  | 47 ++++++++++++-------
 ...rage_cleanup.main.CleanupPostBorrowck.diff |  7 ++-
 ...erage_cleanup.main.InstrumentCoverage.diff |  7 ++-
 6 files changed, 72 insertions(+), 43 deletions(-)

diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
index da25fbb0a82b3..1597d8a34a978 100644
--- a/compiler/rustc_middle/src/mir/coverage.rs
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -282,17 +282,21 @@ pub struct BranchInfo {
     /// injected into the MIR body. This makes it possible to allocate per-ID
     /// data structures without having to scan the entire body first.
     pub num_block_markers: usize,
-    pub branch_spans: Vec<BranchSpan>,
+    pub branch_arm_lists: Vec<Vec<BranchArm>>,
     pub mcdc_branch_spans: Vec<MCDCBranchSpan>,
     pub mcdc_decision_spans: Vec<MCDCDecisionSpan>,
 }
 
 #[derive(Clone, Debug)]
 #[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
-pub struct BranchSpan {
+pub struct BranchArm {
     pub span: Span,
-    pub true_marker: BlockMarkerId,
-    pub false_marker: BlockMarkerId,
+    /// Marks the block that is jumped to after this arm's pattern matches,
+    /// but before its guard is checked.
+    pub pre_guard_marker: BlockMarkerId,
+    /// Marks the block that is jumped to after this arm's guard succeeds.
+    /// If this is equal to `pre_guard_marker`, the arm has no guard.
+    pub arm_taken_marker: BlockMarkerId,
 }
 
 #[derive(Copy, Clone, Debug)]
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 4657f4dcf8132..0b1f09926ee3e 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -487,14 +487,18 @@ fn write_coverage_branch_info(
     branch_info: &coverage::BranchInfo,
     w: &mut dyn io::Write,
 ) -> io::Result<()> {
-    let coverage::BranchInfo { branch_spans, mcdc_branch_spans, mcdc_decision_spans, .. } =
+    let coverage::BranchInfo { branch_arm_lists, mcdc_branch_spans, mcdc_decision_spans, .. } =
         branch_info;
 
-    for coverage::BranchSpan { span, true_marker, false_marker } in branch_spans {
-        writeln!(
-            w,
-            "{INDENT}coverage branch {{ true: {true_marker:?}, false: {false_marker:?} }} => {span:?}",
-        )?;
+    for arms in branch_arm_lists {
+        writeln!(w, "{INDENT}coverage branches {{")?;
+        for coverage::BranchArm { span, pre_guard_marker, arm_taken_marker } in arms {
+            writeln!(w, "{INDENT}{INDENT}{pre_guard_marker:?}, {arm_taken_marker:?} => {span:?}")?;
+        }
+        writeln!(w, "{INDENT}}}")?;
+    }
+    if !branch_arm_lists.is_empty() {
+        writeln!(w)?;
     }
 
     for coverage::MCDCBranchSpan {
@@ -521,8 +525,7 @@ fn write_coverage_branch_info(
         )?;
     }
 
-    if !branch_spans.is_empty() || !mcdc_branch_spans.is_empty() || !mcdc_decision_spans.is_empty()
-    {
+    if !mcdc_branch_spans.is_empty() || !mcdc_decision_spans.is_empty() {
         writeln!(w)?;
     }
 
diff --git a/compiler/rustc_mir_build/src/build/coverageinfo.rs b/compiler/rustc_mir_build/src/build/coverageinfo.rs
index 876faca5172ac..17df2595907d6 100644
--- a/compiler/rustc_mir_build/src/build/coverageinfo.rs
+++ b/compiler/rustc_mir_build/src/build/coverageinfo.rs
@@ -2,7 +2,7 @@ use std::assert_matches::assert_matches;
 use std::collections::hash_map::Entry;
 
 use rustc_data_structures::fx::FxHashMap;
-use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, CoverageKind};
+use rustc_middle::mir::coverage::{BlockMarkerId, BranchArm, CoverageKind};
 use rustc_middle::mir::{self, BasicBlock, SourceInfo, UnOp};
 use rustc_middle::thir::{ExprId, ExprKind, Pat, Thir};
 use rustc_middle::ty::TyCtxt;
@@ -18,7 +18,7 @@ pub(crate) struct BranchInfoBuilder {
     nots: FxHashMap<ExprId, NotInfo>,
 
     markers: BlockMarkerGen,
-    branch_spans: Vec<BranchSpan>,
+    branch_arm_lists: Vec<Vec<BranchArm>>,
 
     mcdc_info: Option<MCDCInfoBuilder>,
 }
@@ -70,7 +70,7 @@ impl BranchInfoBuilder {
             Some(Self {
                 nots: FxHashMap::default(),
                 markers: BlockMarkerGen::default(),
-                branch_spans: vec![],
+                branch_arm_lists: vec![],
                 mcdc_info: tcx.sess.instrument_coverage_mcdc().then(MCDCInfoBuilder::new),
             })
         } else {
@@ -141,11 +141,12 @@ impl BranchInfoBuilder {
             let true_marker = self.markers.inject_block_marker(cfg, source_info, true_block);
             let false_marker = self.markers.inject_block_marker(cfg, source_info, false_block);
 
-            self.branch_spans.push(BranchSpan {
+            let arm = |marker| BranchArm {
                 span: source_info.span,
-                true_marker,
-                false_marker,
-            });
+                pre_guard_marker: marker,
+                arm_taken_marker: marker,
+            };
+            self.branch_arm_lists.push(vec![arm(true_marker), arm(false_marker)]);
         }
     }
 
@@ -153,12 +154,12 @@ impl BranchInfoBuilder {
         let Self {
             nots: _,
             markers: BlockMarkerGen { num_block_markers },
-            branch_spans,
+            branch_arm_lists,
             mcdc_info,
         } = self;
 
         if num_block_markers == 0 {
-            assert!(branch_spans.is_empty());
+            assert!(branch_arm_lists.is_empty());
             return None;
         }
 
@@ -167,7 +168,7 @@ impl BranchInfoBuilder {
 
         Some(Box::new(mir::coverage::BranchInfo {
             num_block_markers,
-            branch_spans,
+            branch_arm_lists,
             mcdc_branch_spans,
             mcdc_decision_spans,
         }))
@@ -240,7 +241,7 @@ impl<'tcx> Builder<'_, 'tcx> {
     }
 
     /// If branch coverage is enabled, inject marker statements into `then_block`
-    /// and `else_block`, and record their IDs in the table of branch spans.
+    /// and `else_block`, and record their IDs in the branch table.
     pub(crate) fn visit_coverage_branch_condition(
         &mut self,
         mut expr_id: ExprId,
diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs
index 81fe971cf9215..3e3ac6a180e56 100644
--- a/compiler/rustc_mir_transform/src/coverage/mappings.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs
@@ -3,7 +3,7 @@ use std::collections::BTreeSet;
 use rustc_data_structures::graph::DirectedGraph;
 use rustc_index::bit_set::BitSet;
 use rustc_index::IndexVec;
-use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, ConditionInfo, CoverageKind};
+use rustc_middle::mir::coverage::{BlockMarkerId, ConditionInfo, CoverageKind};
 use rustc_middle::mir::{self, BasicBlock, StatementKind};
 use rustc_middle::ty::TyCtxt;
 use rustc_span::Span;
@@ -193,25 +193,40 @@ pub(super) fn extract_branch_arm_lists(
     let block_markers = resolve_block_markers(branch_info, mir_body);
 
     branch_info
-        .branch_spans
+        .branch_arm_lists
         .iter()
-        .filter_map(|&BranchSpan { span: raw_span, true_marker, false_marker }| {
-            // For now, ignore any branch span that was introduced by
-            // expansion. This makes things like assert macros less noisy.
-            if !raw_span.ctxt().outer_expn_data().is_root() {
-                return None;
+        .filter_map(|arms| {
+            let mut bcb_arms = Vec::with_capacity(arms.len());
+
+            // If any arm can't be resolved, return None to skip the entire list
+            // of arms that contains it.
+            for &mir::coverage::BranchArm { span: raw_span, pre_guard_marker, arm_taken_marker } in
+                arms
+            {
+                // For now, ignore any branch span that was introduced by
+                // expansion. This makes things like assert macros less noisy.
+                if !raw_span.ctxt().outer_expn_data().is_root() {
+                    return None;
+                }
+
+                let (span, _) =
+                    unexpand_into_body_span_with_visible_macro(raw_span, hir_info.body_span)?;
+
+                let pre_guard_bcb =
+                    basic_coverage_blocks.bcb_from_bb(block_markers[pre_guard_marker]?)?;
+                let arm_taken_bcb =
+                    basic_coverage_blocks.bcb_from_bb(block_markers[arm_taken_marker]?)?;
+
+                bcb_arms.push(BranchArm { span, pre_guard_bcb, arm_taken_bcb });
             }
-            let (span, _) =
-                unexpand_into_body_span_with_visible_macro(raw_span, hir_info.body_span)?;
-
-            let bcb_from_marker =
-                |marker: BlockMarkerId| basic_coverage_blocks.bcb_from_bb(block_markers[marker]?);
+            assert_eq!(arms.len(), bcb_arms.len());
 
-            let true_bcb = bcb_from_marker(true_marker)?;
-            let false_bcb = bcb_from_marker(false_marker)?;
+            if bcb_arms.len() < 2 {
+                debug_assert!(false, "MIR building shouldn't create branches with <2 arms");
+                return None;
+            }
 
-            let arm = |bcb| BranchArm { span, pre_guard_bcb: bcb, arm_taken_bcb: bcb };
-            Some(vec![arm(true_bcb), arm(false_bcb)])
+            Some(bcb_arms)
         })
         .collect::<Vec<_>>()
 }
diff --git a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff
index efb1559baf5eb..974ef70d5c9cd 100644
--- a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff
+++ b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff
@@ -5,14 +5,17 @@
       let mut _0: ();
       let mut _1: bool;
   
-      coverage branch { true: BlockMarkerId(0), false: BlockMarkerId(1) } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0)
+      coverage branches {
+          BlockMarkerId(0), BlockMarkerId(0) => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0)
+          BlockMarkerId(1), BlockMarkerId(1) => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0)
+      }
   
       coverage ExpressionId(0) => Expression { lhs: Counter(0), op: Subtract, rhs: Counter(1) };
+      coverage Branch { true_term: Expression(0), false_term: Counter(1) } => $DIR/instrument_coverage_cleanup.rs:14:8 - 14:36;
       coverage Code(Counter(0)) => $DIR/instrument_coverage_cleanup.rs:13:1 - 14:36;
       coverage Code(Expression(0)) => $DIR/instrument_coverage_cleanup.rs:14:37 - 14:39;
       coverage Code(Counter(1)) => $DIR/instrument_coverage_cleanup.rs:14:39 - 14:40;
       coverage Code(Counter(0)) => $DIR/instrument_coverage_cleanup.rs:15:1 - 15:2;
-      coverage Branch { true_term: Expression(0), false_term: Counter(1) } => $DIR/instrument_coverage_cleanup.rs:14:8 - 14:36;
   
       bb0: {
           Coverage::CounterIncrement(0);
diff --git a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff
index a0fe9a5c05cd1..f6d7fb296ec03 100644
--- a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff
+++ b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff
@@ -5,14 +5,17 @@
       let mut _0: ();
       let mut _1: bool;
   
-      coverage branch { true: BlockMarkerId(0), false: BlockMarkerId(1) } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0)
+      coverage branches {
+          BlockMarkerId(0), BlockMarkerId(0) => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0)
+          BlockMarkerId(1), BlockMarkerId(1) => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0)
+      }
   
 +     coverage ExpressionId(0) => Expression { lhs: Counter(0), op: Subtract, rhs: Counter(1) };
++     coverage Branch { true_term: Expression(0), false_term: Counter(1) } => $DIR/instrument_coverage_cleanup.rs:14:8 - 14:36;
 +     coverage Code(Counter(0)) => $DIR/instrument_coverage_cleanup.rs:13:1 - 14:36;
 +     coverage Code(Expression(0)) => $DIR/instrument_coverage_cleanup.rs:14:37 - 14:39;
 +     coverage Code(Counter(1)) => $DIR/instrument_coverage_cleanup.rs:14:39 - 14:40;
 +     coverage Code(Counter(0)) => $DIR/instrument_coverage_cleanup.rs:15:1 - 15:2;
-+     coverage Branch { true_term: Expression(0), false_term: Counter(1) } => $DIR/instrument_coverage_cleanup.rs:14:8 - 14:36;
 + 
       bb0: {
 +         Coverage::CounterIncrement(0);

From 59595611af7b2987bff41dbfbe434eaaf72fa3e8 Mon Sep 17 00:00:00 2001
From: Zalathar <Zalathar@users.noreply.github.com>
Date: Thu, 18 Apr 2024 20:39:02 +1000
Subject: [PATCH 4/4] coverage: Treat each match arm as a "branch" for branch
 coverage

---
 .../rustc_mir_build/src/build/coverageinfo.rs |  32 +++++
 .../rustc_mir_build/src/build/matches/mod.rs  |  21 ++-
 tests/coverage/branch/guard-simple.cov-map    |  33 +++--
 tests/coverage/branch/guard-simple.coverage   |   2 +
 tests/coverage/branch/guard.cov-map           |  46 ++++--
 tests/coverage/branch/guard.coverage          |   5 +
 tests/coverage/branch/match-arms.cov-map      | 132 ++++++++++++++----
 tests/coverage/branch/match-arms.coverage     |  15 +-
 tests/coverage/branch/match-arms.rs           |   2 +-
 ...ch_match_arms.main.InstrumentCoverage.diff |  21 +++
 10 files changed, 249 insertions(+), 60 deletions(-)

diff --git a/compiler/rustc_mir_build/src/build/coverageinfo.rs b/compiler/rustc_mir_build/src/build/coverageinfo.rs
index 17df2595907d6..6634514f9cfca 100644
--- a/compiler/rustc_mir_build/src/build/coverageinfo.rs
+++ b/compiler/rustc_mir_build/src/build/coverageinfo.rs
@@ -33,6 +33,12 @@ struct NotInfo {
     is_flipped: bool,
 }
 
+pub(crate) struct MatchArm {
+    pub(crate) source_info: SourceInfo,
+    pub(crate) pre_binding_block: Option<BasicBlock>,
+    pub(crate) arm_block: BasicBlock,
+}
+
 #[derive(Default)]
 struct BlockMarkerGen {
     num_block_markers: usize,
@@ -150,6 +156,32 @@ impl BranchInfoBuilder {
         }
     }
 
+    pub(crate) fn add_match_arms(&mut self, cfg: &mut CFG<'_>, arms: &[MatchArm]) {
+        // Match expressions with 0-1 arms don't have any branches for their arms.
+        if arms.len() < 2 {
+            return;
+        }
+
+        // FIXME(#124118) The current implementation of branch coverage for
+        // match arms can't handle or-patterns.
+        if arms.iter().any(|arm| arm.pre_binding_block.is_none()) {
+            return;
+        }
+
+        let branch_arms = arms
+            .iter()
+            .map(|&MatchArm { source_info, pre_binding_block, arm_block }| {
+                let pre_guard_marker =
+                    self.markers.inject_block_marker(cfg, source_info, pre_binding_block.unwrap());
+                let arm_taken_marker =
+                    self.markers.inject_block_marker(cfg, source_info, arm_block);
+                BranchArm { span: source_info.span, pre_guard_marker, arm_taken_marker }
+            })
+            .collect::<Vec<_>>();
+
+        self.branch_arm_lists.push(branch_arms);
+    }
+
     pub(crate) fn into_done(self) -> Option<Box<mir::coverage::BranchInfo>> {
         let Self {
             nots: _,
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 932406fd1aaf2..baf810cb718f0 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -8,7 +8,7 @@
 use crate::build::expr::as_place::PlaceBuilder;
 use crate::build::scope::DropKind;
 use crate::build::ForGuard::{self, OutsideGuard, RefWithinGuard};
-use crate::build::{BlockAnd, BlockAndExtension, Builder};
+use crate::build::{coverageinfo, BlockAnd, BlockAndExtension, Builder};
 use crate::build::{GuardFrame, GuardFrameLocal, LocalsForNode};
 use rustc_data_structures::{fx::FxIndexMap, stack::ensure_sufficient_stack};
 use rustc_hir::{BindingMode, ByRef};
@@ -473,6 +473,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         outer_source_info: SourceInfo,
         fake_borrow_temps: Vec<(Place<'tcx>, Local, FakeBorrowKind)>,
     ) -> BlockAnd<()> {
+        let mut coverage_match_arms = self.coverage_branch_info.is_some().then_some(vec![]);
+
         let arm_end_blocks: Vec<_> = arm_candidates
             .into_iter()
             .map(|(arm, candidate)| {
@@ -507,6 +509,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         opt_scrutinee_place,
                     );
 
+                    let pre_binding_block = candidate.pre_binding_block;
+
                     let arm_block = this.bind_pattern(
                         outer_source_info,
                         candidate,
@@ -516,6 +520,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         false,
                     );
 
+                    if let Some(coverage_match_arms) = coverage_match_arms.as_mut() {
+                        coverage_match_arms.push(coverageinfo::MatchArm {
+                            source_info: this.source_info(arm.pattern.span),
+                            pre_binding_block,
+                            arm_block,
+                        })
+                    }
+
                     this.fixed_temps_scope = old_dedup_scope;
 
                     if let Some(source_scope) = scope {
@@ -527,6 +539,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             })
             .collect();
 
+        if let Some(coverage_match_arms) = coverage_match_arms {
+            self.coverage_branch_info
+                .as_mut()
+                .expect("checked when creating `coverage_match_arms`")
+                .add_match_arms(&mut self.cfg, &coverage_match_arms);
+        }
+
         // all the arm blocks will rejoin here
         let end_block = self.cfg.start_new_block();
 
diff --git a/tests/coverage/branch/guard-simple.cov-map b/tests/coverage/branch/guard-simple.cov-map
index 8eb9c54ff4bca..50654ae661afb 100644
--- a/tests/coverage/branch/guard-simple.cov-map
+++ b/tests/coverage/branch/guard-simple.cov-map
@@ -1,24 +1,35 @@
 Function name: guard_simple::never_taken
-Raw bytes (56): 0x[01, 01, 04, 01, 05, 11, 09, 0f, 0d, 05, 09, 08, 01, 08, 01, 02, 1e, 20, 05, 02, 02, 0e, 00, 1e, 05, 00, 22, 00, 24, 11, 01, 0e, 00, 1e, 20, 09, 06, 00, 0e, 00, 1e, 09, 00, 22, 00, 24, 0d, 01, 0e, 00, 10, 0b, 02, 01, 00, 02]
+Raw bytes (80): 0x[01, 01, 09, 07, 01, 17, 05, 0d, 09, 01, 05, 17, 11, 0d, 09, 11, 09, 23, 0d, 05, 09, 0a, 01, 08, 01, 02, 1e, 20, 01, 02, 02, 09, 00, 0a, 20, 05, 0e, 00, 0e, 00, 1e, 05, 00, 22, 00, 24, 20, 11, 12, 01, 09, 00, 0a, 11, 00, 0e, 00, 1e, 20, 09, 1a, 00, 0e, 00, 1e, 09, 00, 22, 00, 24, 0d, 01, 0e, 00, 10, 1f, 02, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 4
-- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(4), rhs = Counter(2)
-- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(3)
-- expression 3 operands: lhs = Counter(1), rhs = Counter(2)
-Number of file 0 mappings: 8
+Number of expressions: 9
+- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(0)
+- expression 1 operands: lhs = Expression(5, Add), rhs = Counter(1)
+- expression 2 operands: lhs = Counter(3), rhs = Counter(2)
+- expression 3 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(4)
+- expression 5 operands: lhs = Counter(3), rhs = Counter(2)
+- expression 6 operands: lhs = Counter(4), rhs = Counter(2)
+- expression 7 operands: lhs = Expression(8, Add), rhs = Counter(3)
+- expression 8 operands: lhs = Counter(1), rhs = Counter(2)
+Number of file 0 mappings: 10
 - Code(Counter(0)) at (prev + 8, 1) to (start + 2, 30)
-- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 2, 14) to (start + 0, 30)
+- Branch { true: Counter(0), false: Expression(0, Sub) } at (prev + 2, 9) to (start + 0, 10)
+    true  = c0
+    false = (((c3 + c2) + c1) - c0)
+- Branch { true: Counter(1), false: Expression(3, Sub) } at (prev + 0, 14) to (start + 0, 30)
     true  = c1
     false = (c0 - c1)
 - Code(Counter(1)) at (prev + 0, 34) to (start + 0, 36)
-- Code(Counter(4)) at (prev + 1, 14) to (start + 0, 30)
-- Branch { true: Counter(2), false: Expression(1, Sub) } at (prev + 0, 14) to (start + 0, 30)
+- Branch { true: Counter(4), false: Expression(4, Sub) } at (prev + 1, 9) to (start + 0, 10)
+    true  = c4
+    false = ((c3 + c2) - c4)
+- Code(Counter(4)) at (prev + 0, 14) to (start + 0, 30)
+- Branch { true: Counter(2), false: Expression(6, Sub) } at (prev + 0, 14) to (start + 0, 30)
     true  = c2
     false = (c4 - c2)
 - Code(Counter(2)) at (prev + 0, 34) to (start + 0, 36)
 - Code(Counter(3)) at (prev + 1, 14) to (start + 0, 16)
-- Code(Expression(2, Add)) at (prev + 2, 1) to (start + 0, 2)
+- Code(Expression(7, Add)) at (prev + 2, 1) to (start + 0, 2)
     = ((c1 + c2) + c3)
 
diff --git a/tests/coverage/branch/guard-simple.coverage b/tests/coverage/branch/guard-simple.coverage
index ac90c48c44342..06ad332a927da 100644
--- a/tests/coverage/branch/guard-simple.coverage
+++ b/tests/coverage/branch/guard-simple.coverage
@@ -10,11 +10,13 @@
    LL|      1|        _ if black_box(false) => {}
                                                ^0
   ------------------
+  |  Branch (LL:9): [True: 1, False: 0]
   |  Branch (LL:14): [True: 0, False: 1]
   ------------------
    LL|      1|        _ if black_box(false) => {}
                                                ^0
   ------------------
+  |  Branch (LL:9): [True: 1, False: 0]
   |  Branch (LL:14): [True: 0, False: 1]
   ------------------
    LL|      1|        _ => {}
diff --git a/tests/coverage/branch/guard.cov-map b/tests/coverage/branch/guard.cov-map
index d67c3d349a14e..18dd0c302cbfa 100644
--- a/tests/coverage/branch/guard.cov-map
+++ b/tests/coverage/branch/guard.cov-map
@@ -1,32 +1,48 @@
 Function name: guard::branch_match_guard
-Raw bytes (85): 0x[01, 01, 06, 19, 0d, 05, 09, 0f, 15, 13, 11, 17, 0d, 05, 09, 0d, 01, 0c, 01, 01, 10, 1d, 03, 0b, 00, 0c, 15, 01, 14, 02, 0a, 0d, 03, 0e, 00, 0f, 19, 00, 14, 00, 19, 20, 0d, 02, 00, 14, 00, 1e, 0d, 00, 1d, 02, 0a, 11, 03, 0e, 00, 0f, 1d, 00, 14, 00, 19, 20, 11, 09, 00, 14, 00, 1e, 11, 00, 1d, 02, 0a, 17, 03, 0e, 02, 0a, 0b, 04, 01, 00, 02]
+Raw bytes (120): 0x[01, 01, 0d, 1b, 0d, 33, 11, 05, 09, 03, 19, 19, 0d, 1b, 1d, 33, 11, 05, 09, 05, 09, 2b, 15, 2f, 11, 33, 0d, 05, 09, 10, 01, 0c, 01, 01, 10, 1d, 03, 0b, 00, 0c, 20, 15, 03, 01, 09, 00, 10, 15, 00, 14, 02, 0a, 20, 19, 0e, 03, 09, 00, 10, 0d, 00, 0e, 00, 0f, 19, 00, 14, 00, 19, 20, 0d, 12, 00, 14, 00, 1e, 0d, 00, 1d, 02, 0a, 20, 1d, 16, 03, 09, 00, 10, 11, 00, 0e, 00, 0f, 1d, 00, 14, 00, 19, 20, 11, 09, 00, 14, 00, 1e, 11, 00, 1d, 02, 0a, 33, 03, 0e, 02, 0a, 27, 04, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 6
-- expression 0 operands: lhs = Counter(6), rhs = Counter(3)
-- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(5)
-- expression 3 operands: lhs = Expression(4, Add), rhs = Counter(4)
-- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(3)
-- expression 5 operands: lhs = Counter(1), rhs = Counter(2)
-Number of file 0 mappings: 13
+Number of expressions: 13
+- expression 0 operands: lhs = Expression(6, Add), rhs = Counter(3)
+- expression 1 operands: lhs = Expression(12, Add), rhs = Counter(4)
+- expression 2 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 3 operands: lhs = Expression(0, Add), rhs = Counter(6)
+- expression 4 operands: lhs = Counter(6), rhs = Counter(3)
+- expression 5 operands: lhs = Expression(6, Add), rhs = Counter(7)
+- expression 6 operands: lhs = Expression(12, Add), rhs = Counter(4)
+- expression 7 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 8 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 9 operands: lhs = Expression(10, Add), rhs = Counter(5)
+- expression 10 operands: lhs = Expression(11, Add), rhs = Counter(4)
+- expression 11 operands: lhs = Expression(12, Add), rhs = Counter(3)
+- expression 12 operands: lhs = Counter(1), rhs = Counter(2)
+Number of file 0 mappings: 16
 - Code(Counter(0)) at (prev + 12, 1) to (start + 1, 16)
 - Code(Counter(7)) at (prev + 3, 11) to (start + 0, 12)
-- Code(Counter(5)) at (prev + 1, 20) to (start + 2, 10)
-- Code(Counter(3)) at (prev + 3, 14) to (start + 0, 15)
+- Branch { true: Counter(5), false: Expression(0, Add) } at (prev + 1, 9) to (start + 0, 16)
+    true  = c5
+    false = (((c1 + c2) + c4) + c3)
+- Code(Counter(5)) at (prev + 0, 20) to (start + 2, 10)
+- Branch { true: Counter(6), false: Expression(3, Sub) } at (prev + 3, 9) to (start + 0, 16)
+    true  = c6
+    false = ((((c1 + c2) + c4) + c3) - c6)
+- Code(Counter(3)) at (prev + 0, 14) to (start + 0, 15)
 - Code(Counter(6)) at (prev + 0, 20) to (start + 0, 25)
-- Branch { true: Counter(3), false: Expression(0, Sub) } at (prev + 0, 20) to (start + 0, 30)
+- Branch { true: Counter(3), false: Expression(4, Sub) } at (prev + 0, 20) to (start + 0, 30)
     true  = c3
     false = (c6 - c3)
 - Code(Counter(3)) at (prev + 0, 29) to (start + 2, 10)
-- Code(Counter(4)) at (prev + 3, 14) to (start + 0, 15)
+- Branch { true: Counter(7), false: Expression(5, Sub) } at (prev + 3, 9) to (start + 0, 16)
+    true  = c7
+    false = (((c1 + c2) + c4) - c7)
+- Code(Counter(4)) at (prev + 0, 14) to (start + 0, 15)
 - Code(Counter(7)) at (prev + 0, 20) to (start + 0, 25)
 - Branch { true: Counter(4), false: Counter(2) } at (prev + 0, 20) to (start + 0, 30)
     true  = c4
     false = c2
 - Code(Counter(4)) at (prev + 0, 29) to (start + 2, 10)
-- Code(Expression(5, Add)) at (prev + 3, 14) to (start + 2, 10)
+- Code(Expression(12, Add)) at (prev + 3, 14) to (start + 2, 10)
     = (c1 + c2)
-- Code(Expression(2, Add)) at (prev + 4, 1) to (start + 0, 2)
+- Code(Expression(9, Add)) at (prev + 4, 1) to (start + 0, 2)
     = ((((c1 + c2) + c3) + c4) + c5)
 
diff --git a/tests/coverage/branch/guard.coverage b/tests/coverage/branch/guard.coverage
index f89b965b5d0f7..6b1b650d4703c 100644
--- a/tests/coverage/branch/guard.coverage
+++ b/tests/coverage/branch/guard.coverage
@@ -14,17 +14,22 @@
    LL|       |
    LL|      1|    match x {
    LL|      1|        Some(0) => {
+  ------------------
+  |  Branch (LL:9): [True: 1, False: 3]
+  ------------------
    LL|      1|            println!("zero");
    LL|      1|        }
    LL|      3|        Some(x) if x % 2 == 0 => {
                            ^2
   ------------------
+  |  Branch (LL:9): [True: 3, False: 0]
   |  Branch (LL:20): [True: 2, False: 1]
   ------------------
    LL|      2|            println!("is nonzero and even");
    LL|      2|        }
    LL|      1|        Some(x) if x % 3 == 0 => {
   ------------------
+  |  Branch (LL:9): [True: 1, False: 0]
   |  Branch (LL:20): [True: 1, False: 0]
   ------------------
    LL|      1|            println!("is nonzero and odd, but divisible by 3");
diff --git a/tests/coverage/branch/match-arms.cov-map b/tests/coverage/branch/match-arms.cov-map
index 1f17f11baaa07..04c39db4c5c31 100644
--- a/tests/coverage/branch/match-arms.cov-map
+++ b/tests/coverage/branch/match-arms.cov-map
@@ -1,60 +1,130 @@
 Function name: match_arms::guards
-Raw bytes (88): 0x[01, 01, 08, 07, 15, 0b, 11, 0f, 0d, 00, 09, 17, 25, 1b, 21, 1f, 1d, 03, 19, 0c, 01, 30, 01, 01, 10, 29, 03, 0b, 00, 10, 19, 01, 11, 00, 29, 20, 19, 09, 00, 17, 00, 1b, 1d, 01, 11, 00, 29, 20, 1d, 0d, 00, 17, 00, 1b, 21, 01, 11, 00, 29, 20, 21, 11, 00, 17, 00, 1b, 25, 01, 11, 00, 29, 20, 25, 15, 00, 17, 00, 1b, 03, 01, 0e, 00, 18, 13, 03, 05, 01, 02]
+Raw bytes (212): 0x[01, 01, 2a, 07, 35, 2b, 19, 4b, 1d, 67, 21, 9b, 01, 25, 9f, 01, 15, a3, 01, 11, a7, 01, 0d, 00, 09, 2b, 31, 4b, 1d, 67, 21, 9b, 01, 25, 9f, 01, 15, a3, 01, 11, a7, 01, 0d, 00, 09, 4b, 2d, 67, 21, 9b, 01, 25, 9f, 01, 15, a3, 01, 11, a7, 01, 0d, 00, 09, 67, 29, 9b, 01, 25, 9f, 01, 15, a3, 01, 11, a7, 01, 0d, 00, 09, 9f, 01, 15, a3, 01, 11, a7, 01, 0d, 00, 09, 8f, 01, 25, 93, 01, 21, 97, 01, 1d, 9b, 01, 19, 9f, 01, 15, a3, 01, 11, a7, 01, 0d, 00, 09, 10, 01, 30, 01, 01, 10, 29, 03, 0b, 00, 10, 20, 35, 02, 01, 09, 00, 13, 19, 00, 11, 00, 29, 20, 19, 09, 00, 17, 00, 1b, 20, 31, 26, 01, 09, 00, 13, 1d, 00, 11, 00, 29, 20, 1d, 0d, 00, 17, 00, 1b, 20, 2d, 46, 01, 09, 00, 13, 21, 00, 11, 00, 29, 20, 21, 11, 00, 17, 00, 1b, 20, 29, 62, 01, 09, 00, 13, 25, 00, 11, 00, 29, 20, 25, 15, 00, 17, 00, 1b, 9b, 01, 01, 0e, 00, 18, 8b, 01, 03, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 8
-- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(5)
-- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(4)
-- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(3)
-- expression 3 operands: lhs = Zero, rhs = Counter(2)
-- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(9)
-- expression 5 operands: lhs = Expression(6, Add), rhs = Counter(8)
-- expression 6 operands: lhs = Expression(7, Add), rhs = Counter(7)
-- expression 7 operands: lhs = Expression(0, Add), rhs = Counter(6)
-Number of file 0 mappings: 12
+Number of expressions: 42
+- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(13)
+- expression 1 operands: lhs = Expression(10, Add), rhs = Counter(6)
+- expression 2 operands: lhs = Expression(18, Add), rhs = Counter(7)
+- expression 3 operands: lhs = Expression(25, Add), rhs = Counter(8)
+- expression 4 operands: lhs = Expression(38, Add), rhs = Counter(9)
+- expression 5 operands: lhs = Expression(39, Add), rhs = Counter(5)
+- expression 6 operands: lhs = Expression(40, Add), rhs = Counter(4)
+- expression 7 operands: lhs = Expression(41, Add), rhs = Counter(3)
+- expression 8 operands: lhs = Zero, rhs = Counter(2)
+- expression 9 operands: lhs = Expression(10, Add), rhs = Counter(12)
+- expression 10 operands: lhs = Expression(18, Add), rhs = Counter(7)
+- expression 11 operands: lhs = Expression(25, Add), rhs = Counter(8)
+- expression 12 operands: lhs = Expression(38, Add), rhs = Counter(9)
+- expression 13 operands: lhs = Expression(39, Add), rhs = Counter(5)
+- expression 14 operands: lhs = Expression(40, Add), rhs = Counter(4)
+- expression 15 operands: lhs = Expression(41, Add), rhs = Counter(3)
+- expression 16 operands: lhs = Zero, rhs = Counter(2)
+- expression 17 operands: lhs = Expression(18, Add), rhs = Counter(11)
+- expression 18 operands: lhs = Expression(25, Add), rhs = Counter(8)
+- expression 19 operands: lhs = Expression(38, Add), rhs = Counter(9)
+- expression 20 operands: lhs = Expression(39, Add), rhs = Counter(5)
+- expression 21 operands: lhs = Expression(40, Add), rhs = Counter(4)
+- expression 22 operands: lhs = Expression(41, Add), rhs = Counter(3)
+- expression 23 operands: lhs = Zero, rhs = Counter(2)
+- expression 24 operands: lhs = Expression(25, Add), rhs = Counter(10)
+- expression 25 operands: lhs = Expression(38, Add), rhs = Counter(9)
+- expression 26 operands: lhs = Expression(39, Add), rhs = Counter(5)
+- expression 27 operands: lhs = Expression(40, Add), rhs = Counter(4)
+- expression 28 operands: lhs = Expression(41, Add), rhs = Counter(3)
+- expression 29 operands: lhs = Zero, rhs = Counter(2)
+- expression 30 operands: lhs = Expression(39, Add), rhs = Counter(5)
+- expression 31 operands: lhs = Expression(40, Add), rhs = Counter(4)
+- expression 32 operands: lhs = Expression(41, Add), rhs = Counter(3)
+- expression 33 operands: lhs = Zero, rhs = Counter(2)
+- expression 34 operands: lhs = Expression(35, Add), rhs = Counter(9)
+- expression 35 operands: lhs = Expression(36, Add), rhs = Counter(8)
+- expression 36 operands: lhs = Expression(37, Add), rhs = Counter(7)
+- expression 37 operands: lhs = Expression(38, Add), rhs = Counter(6)
+- expression 38 operands: lhs = Expression(39, Add), rhs = Counter(5)
+- expression 39 operands: lhs = Expression(40, Add), rhs = Counter(4)
+- expression 40 operands: lhs = Expression(41, Add), rhs = Counter(3)
+- expression 41 operands: lhs = Zero, rhs = Counter(2)
+Number of file 0 mappings: 16
 - Code(Counter(0)) at (prev + 48, 1) to (start + 1, 16)
 - Code(Counter(10)) at (prev + 3, 11) to (start + 0, 16)
-- Code(Counter(6)) at (prev + 1, 17) to (start + 0, 41)
+- Branch { true: Counter(13), false: Expression(0, Sub) } at (prev + 1, 9) to (start + 0, 19)
+    true  = c13
+    false = (((((((((Zero + c2) + c3) + c4) + c5) + c9) + c8) + c7) + c6) - c13)
+- Code(Counter(6)) at (prev + 0, 17) to (start + 0, 41)
 - Branch { true: Counter(6), false: Counter(2) } at (prev + 0, 23) to (start + 0, 27)
     true  = c6
     false = c2
-- Code(Counter(7)) at (prev + 1, 17) to (start + 0, 41)
+- Branch { true: Counter(12), false: Expression(9, Sub) } at (prev + 1, 9) to (start + 0, 19)
+    true  = c12
+    false = ((((((((Zero + c2) + c3) + c4) + c5) + c9) + c8) + c7) - c12)
+- Code(Counter(7)) at (prev + 0, 17) to (start + 0, 41)
 - Branch { true: Counter(7), false: Counter(3) } at (prev + 0, 23) to (start + 0, 27)
     true  = c7
     false = c3
-- Code(Counter(8)) at (prev + 1, 17) to (start + 0, 41)
+- Branch { true: Counter(11), false: Expression(17, Sub) } at (prev + 1, 9) to (start + 0, 19)
+    true  = c11
+    false = (((((((Zero + c2) + c3) + c4) + c5) + c9) + c8) - c11)
+- Code(Counter(8)) at (prev + 0, 17) to (start + 0, 41)
 - Branch { true: Counter(8), false: Counter(4) } at (prev + 0, 23) to (start + 0, 27)
     true  = c8
     false = c4
-- Code(Counter(9)) at (prev + 1, 17) to (start + 0, 41)
+- Branch { true: Counter(10), false: Expression(24, Sub) } at (prev + 1, 9) to (start + 0, 19)
+    true  = c10
+    false = ((((((Zero + c2) + c3) + c4) + c5) + c9) - c10)
+- Code(Counter(9)) at (prev + 0, 17) to (start + 0, 41)
 - Branch { true: Counter(9), false: Counter(5) } at (prev + 0, 23) to (start + 0, 27)
     true  = c9
     false = c5
-- Code(Expression(0, Add)) at (prev + 1, 14) to (start + 0, 24)
+- Code(Expression(38, Add)) at (prev + 1, 14) to (start + 0, 24)
     = ((((Zero + c2) + c3) + c4) + c5)
-- Code(Expression(4, Add)) at (prev + 3, 5) to (start + 1, 2)
+- Code(Expression(34, Add)) at (prev + 3, 5) to (start + 1, 2)
     = ((((((((Zero + c2) + c3) + c4) + c5) + c6) + c7) + c8) + c9)
 
 Function name: match_arms::match_arms
-Raw bytes (51): 0x[01, 01, 06, 05, 07, 0b, 11, 09, 0d, 13, 02, 17, 09, 11, 0d, 07, 01, 18, 01, 01, 10, 05, 03, 0b, 00, 10, 11, 01, 11, 00, 21, 0d, 01, 11, 00, 21, 09, 01, 11, 00, 21, 02, 01, 11, 00, 21, 0f, 03, 05, 01, 02]
+Raw bytes (102): 0x[01, 01, 15, 17, 0d, 4a, 09, 05, 4f, 53, 11, 09, 0d, 4a, 09, 05, 4f, 53, 11, 09, 0d, 05, 4f, 53, 11, 09, 0d, 05, 4f, 53, 11, 09, 0d, 43, 4a, 47, 09, 11, 0d, 05, 4f, 53, 11, 09, 0d, 0a, 01, 18, 01, 01, 10, 05, 03, 0b, 00, 10, 20, 11, 03, 01, 09, 00, 13, 11, 00, 11, 00, 21, 20, 0d, 17, 01, 09, 00, 13, 0d, 00, 11, 00, 21, 20, 09, 4a, 01, 09, 00, 13, 09, 00, 11, 00, 21, 4a, 01, 11, 00, 21, 3f, 03, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 6
-- expression 0 operands: lhs = Counter(1), rhs = Expression(1, Add)
-- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(4)
-- expression 2 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 3 operands: lhs = Expression(4, Add), rhs = Expression(0, Sub)
-- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(2)
-- expression 5 operands: lhs = Counter(4), rhs = Counter(3)
-Number of file 0 mappings: 7
+Number of expressions: 21
+- expression 0 operands: lhs = Expression(5, Add), rhs = Counter(3)
+- expression 1 operands: lhs = Expression(18, Sub), rhs = Counter(2)
+- expression 2 operands: lhs = Counter(1), rhs = Expression(19, Add)
+- expression 3 operands: lhs = Expression(20, Add), rhs = Counter(4)
+- expression 4 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 5 operands: lhs = Expression(18, Sub), rhs = Counter(2)
+- expression 6 operands: lhs = Counter(1), rhs = Expression(19, Add)
+- expression 7 operands: lhs = Expression(20, Add), rhs = Counter(4)
+- expression 8 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 9 operands: lhs = Counter(1), rhs = Expression(19, Add)
+- expression 10 operands: lhs = Expression(20, Add), rhs = Counter(4)
+- expression 11 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 12 operands: lhs = Counter(1), rhs = Expression(19, Add)
+- expression 13 operands: lhs = Expression(20, Add), rhs = Counter(4)
+- expression 14 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 15 operands: lhs = Expression(16, Add), rhs = Expression(18, Sub)
+- expression 16 operands: lhs = Expression(17, Add), rhs = Counter(2)
+- expression 17 operands: lhs = Counter(4), rhs = Counter(3)
+- expression 18 operands: lhs = Counter(1), rhs = Expression(19, Add)
+- expression 19 operands: lhs = Expression(20, Add), rhs = Counter(4)
+- expression 20 operands: lhs = Counter(2), rhs = Counter(3)
+Number of file 0 mappings: 10
 - Code(Counter(0)) at (prev + 24, 1) to (start + 1, 16)
 - Code(Counter(1)) at (prev + 3, 11) to (start + 0, 16)
-- Code(Counter(4)) at (prev + 1, 17) to (start + 0, 33)
-- Code(Counter(3)) at (prev + 1, 17) to (start + 0, 33)
-- Code(Counter(2)) at (prev + 1, 17) to (start + 0, 33)
-- Code(Expression(0, Sub)) at (prev + 1, 17) to (start + 0, 33)
+- Branch { true: Counter(4), false: Expression(0, Add) } at (prev + 1, 9) to (start + 0, 19)
+    true  = c4
+    false = (((c1 - ((c2 + c3) + c4)) + c2) + c3)
+- Code(Counter(4)) at (prev + 0, 17) to (start + 0, 33)
+- Branch { true: Counter(3), false: Expression(5, Add) } at (prev + 1, 9) to (start + 0, 19)
+    true  = c3
+    false = ((c1 - ((c2 + c3) + c4)) + c2)
+- Code(Counter(3)) at (prev + 0, 17) to (start + 0, 33)
+- Branch { true: Counter(2), false: Expression(18, Sub) } at (prev + 1, 9) to (start + 0, 19)
+    true  = c2
+    false = (c1 - ((c2 + c3) + c4))
+- Code(Counter(2)) at (prev + 0, 17) to (start + 0, 33)
+- Code(Expression(18, Sub)) at (prev + 1, 17) to (start + 0, 33)
     = (c1 - ((c2 + c3) + c4))
-- Code(Expression(3, Add)) at (prev + 3, 5) to (start + 1, 2)
+- Code(Expression(15, Add)) at (prev + 3, 5) to (start + 1, 2)
     = (((c4 + c3) + c2) + (c1 - ((c2 + c3) + c4)))
 
 Function name: match_arms::or_patterns
diff --git a/tests/coverage/branch/match-arms.coverage b/tests/coverage/branch/match-arms.coverage
index ea8a6f97ab154..c02c86c202e21 100644
--- a/tests/coverage/branch/match-arms.coverage
+++ b/tests/coverage/branch/match-arms.coverage
@@ -26,8 +26,17 @@
    LL|       |
    LL|     15|    match value {
    LL|      8|        Enum::D(d) => consume(d),
+  ------------------
+  |  Branch (LL:9): [True: 8, False: 7]
+  ------------------
    LL|      4|        Enum::C(c) => consume(c),
+  ------------------
+  |  Branch (LL:9): [True: 4, False: 3]
+  ------------------
    LL|      2|        Enum::B(b) => consume(b),
+  ------------------
+  |  Branch (LL:9): [True: 2, False: 1]
+  ------------------
    LL|      1|        Enum::A(a) => consume(a),
    LL|       |    }
    LL|       |
@@ -53,18 +62,22 @@
    LL|      3|    match value {
    LL|      8|        Enum::D(d) if cond => consume(d),
   ------------------
+  |  Branch (LL:9): [True: 24, False: 21]
   |  Branch (LL:23): [True: 8, False: 16]
   ------------------
    LL|      4|        Enum::C(c) if cond => consume(c),
   ------------------
+  |  Branch (LL:9): [True: 12, False: 25]
   |  Branch (LL:23): [True: 4, False: 8]
   ------------------
    LL|      2|        Enum::B(b) if cond => consume(b),
   ------------------
+  |  Branch (LL:9): [True: 6, False: 27]
   |  Branch (LL:23): [True: 2, False: 4]
   ------------------
    LL|      1|        Enum::A(a) if cond => consume(a),
   ------------------
+  |  Branch (LL:9): [True: 3, False: 28]
   |  Branch (LL:23): [True: 1, False: 2]
   ------------------
    LL|     30|        _ => consume(0),
@@ -101,5 +114,5 @@
    LL|       |    }
    LL|       |}
    LL|       |
-   LL|       |// FIXME(#124118) Actually instrument match arms for branch coverage.
+   LL|       |// FIXME(#124118) Support match expressions with or-patterns.
 
diff --git a/tests/coverage/branch/match-arms.rs b/tests/coverage/branch/match-arms.rs
index 63151f59ffe9b..0cc55e2212b72 100644
--- a/tests/coverage/branch/match-arms.rs
+++ b/tests/coverage/branch/match-arms.rs
@@ -87,4 +87,4 @@ fn main() {
     }
 }
 
-// FIXME(#124118) Actually instrument match arms for branch coverage.
+// FIXME(#124118) Support match expressions with or-patterns.
diff --git a/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff
index e60f71f47b1ed..889d02a7e9647 100644
--- a/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff
+++ b/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff
@@ -26,12 +26,25 @@
           debug a => _9;
       }
   
+      coverage branches {
+          BlockMarkerId(0), BlockMarkerId(1) => $DIR/branch_match_arms.rs:16:9: 16:19 (#0)
+          BlockMarkerId(2), BlockMarkerId(3) => $DIR/branch_match_arms.rs:17:9: 17:19 (#0)
+          BlockMarkerId(4), BlockMarkerId(5) => $DIR/branch_match_arms.rs:18:9: 18:19 (#0)
+          BlockMarkerId(6), BlockMarkerId(7) => $DIR/branch_match_arms.rs:19:9: 19:19 (#0)
+      }
+  
 +     coverage ExpressionId(0) => Expression { lhs: Counter(1), op: Add, rhs: Counter(2) };
 +     coverage ExpressionId(1) => Expression { lhs: Expression(0), op: Add, rhs: Counter(3) };
 +     coverage ExpressionId(2) => Expression { lhs: Counter(0), op: Subtract, rhs: Expression(1) };
 +     coverage ExpressionId(3) => Expression { lhs: Counter(3), op: Add, rhs: Counter(2) };
 +     coverage ExpressionId(4) => Expression { lhs: Expression(3), op: Add, rhs: Counter(1) };
 +     coverage ExpressionId(5) => Expression { lhs: Expression(4), op: Add, rhs: Expression(2) };
++     coverage ExpressionId(6) => Expression { lhs: Expression(2), op: Add, rhs: Counter(1) };
++     coverage ExpressionId(7) => Expression { lhs: Expression(6), op: Add, rhs: Counter(2) };
++     coverage ExpressionId(8) => Expression { lhs: Expression(7), op: Add, rhs: Counter(3) };
++     coverage Branch { true_term: Counter(1), false_term: Expression(2) } => $DIR/branch_match_arms.rs:18:9 - 18:19;
++     coverage Branch { true_term: Counter(2), false_term: Expression(6) } => $DIR/branch_match_arms.rs:17:9 - 17:19;
++     coverage Branch { true_term: Counter(3), false_term: Expression(7) } => $DIR/branch_match_arms.rs:16:9 - 16:19;
 +     coverage Code(Counter(0)) => $DIR/branch_match_arms.rs:14:1 - 15:21;
 +     coverage Code(Counter(3)) => $DIR/branch_match_arms.rs:16:17 - 16:33;
 +     coverage Code(Counter(2)) => $DIR/branch_match_arms.rs:17:17 - 17:33;
@@ -55,16 +68,19 @@
   
       bb2: {
 +         Coverage::CounterIncrement(3);
+          Coverage::BlockMarker(0);
           falseEdge -> [real: bb6, imaginary: bb3];
       }
   
       bb3: {
 +         Coverage::CounterIncrement(2);
+          Coverage::BlockMarker(2);
           falseEdge -> [real: bb8, imaginary: bb4];
       }
   
       bb4: {
 +         Coverage::CounterIncrement(1);
+          Coverage::BlockMarker(4);
           falseEdge -> [real: bb10, imaginary: bb5];
       }
   
@@ -74,6 +90,8 @@
           _9 = ((_1 as A).0: u32);
           StorageLive(_10);
           _10 = _9;
+          Coverage::BlockMarker(6);
+          Coverage::BlockMarker(7);
           _0 = consume(move _10) -> [return: bb12, unwind: bb14];
       }
   
@@ -82,6 +100,7 @@
           _3 = ((_1 as D).0: u32);
           StorageLive(_4);
           _4 = _3;
+          Coverage::BlockMarker(1);
           _0 = consume(move _4) -> [return: bb7, unwind: bb14];
       }
   
@@ -96,6 +115,7 @@
           _5 = ((_1 as C).0: u32);
           StorageLive(_6);
           _6 = _5;
+          Coverage::BlockMarker(3);
           _0 = consume(move _6) -> [return: bb9, unwind: bb14];
       }
   
@@ -110,6 +130,7 @@
           _7 = ((_1 as B).0: u32);
           StorageLive(_8);
           _8 = _7;
+          Coverage::BlockMarker(5);
           _0 = consume(move _8) -> [return: bb11, unwind: bb14];
       }