[libc-commits] [libc] [libc][docs] Add developer guide for source-level code coverage (PR #214692)

Tapiwa Gonga via libc-commits libc-commits at lists.llvm.org
Thu Aug 27 04:00:04 PDT 2026


https://github.com/tapiwagonga updated https://github.com/llvm/llvm-project/pull/214692

>From 5eadf0251a4ce16c0664925d2fb3cbc8533b3db5 Mon Sep 17 00:00:00 2001
From: Tapiwa Gonga <tapiwagonga at google.com>
Date: Wed, 19 Aug 2026 14:28:48 +0000
Subject: [PATCH 1/6] [libc][docs] Add developer guide for code coverage and
 MC/DC

---
 libc/docs/dev/code_coverage.md | 382 +++++++++++++++++++++++++++++++++
 libc/docs/dev/index.md         |   1 +
 2 files changed, 383 insertions(+)
 create mode 100644 libc/docs/dev/code_coverage.md

diff --git a/libc/docs/dev/code_coverage.md b/libc/docs/dev/code_coverage.md
new file mode 100644
index 0000000000000..971ab9011de40
--- /dev/null
+++ b/libc/docs/dev/code_coverage.md
@@ -0,0 +1,382 @@
+# Code Coverage in LLVM-libc
+
+(code_coverage)=
+
+This document describes how to configure, generate, and view code coverage and Modified Condition / Decision Coverage (MC/DC) reports for LLVM-libc.
+
+---
+
+## Overview
+
+Code coverage measures the proportion of source code executed during testing. In LLVM-libc, coverage metrics identify untested edge cases, prevent regressions across supported architectures, and provide verification evidence for safety-critical systems.
+
+### Coverage Modes
+
+* **Statement and Branch Coverage:**  
+  Measures line execution and verifies whether conditional branches evaluated to both true and false paths.
+
+* **Modified Condition / Decision Coverage (MC/DC):**  
+  Evaluates boolean conditions within compound decisions (such as `if (A && B)`). Verifies that each individual sub-condition is tested with both true and false values and independently affects the outcome of the enclosing decision. Required by safety-critical standards such as DO-178C (aviation) and ISO 26262 (automotive).
+
+---
+
+## Prerequisites & Toolchain Setup
+
+Generating coverage reports requires Clang, LLVM profile tools, CMake, and Ninja:
+
+* **Compiler:** Clang 18 or later (Clang 21 or later is required for MC/DC instrumentation).
+* **LLVM Utilities:** Matching major versions of `llvm-profdata` and `llvm-cov`.
+* **Build System:** CMake 3.28+ and Ninja.
+
+### Toolchain Installation (Debian/Ubuntu)
+
+Install the required compiler, tooling, and build utilities:
+
+```bash
+sudo apt install clang-21 llvm-21-tools lld-21 ninja-build cmake
+```
+
+### Configuring Tool Links
+
+Because Debian and Ubuntu install LLVM tools with version suffixes (such as `llvm-profdata-21`), you can configure unversioned aliases using either of the following methods:
+
+#### Method A: User-Level Setup (Recommended - No `sudo` required)
+
+```bash
+mkdir -p ~/.local/bin
+ln -sf $(which llvm-profdata-21 2>/dev/null || which llvm-profdata) ~/.local/bin/llvm-profdata
+ln -sf $(which llvm-cov-21 2>/dev/null || which llvm-cov) ~/.local/bin/llvm-cov
+export PATH="$HOME/.local/bin:$PATH"
+```
+
+#### Method B: System-Wide Alternatives (Requires `sudo`)
+
+```bash
+sudo update-alternatives --install /usr/bin/llvm-profdata llvm-profdata /usr/bin/llvm-profdata-21 100
+sudo update-alternatives --install /usr/bin/llvm-cov llvm-cov /usr/bin/llvm-cov-21 100
+```
+
+:::{note}
+Compiling the full suite of unit tests with coverage instrumentation encompasses ~10,000 target nodes. On multi-core workstations, parallel compilation completes in a few minutes. On resource-constrained systems, virtual machines with 2–4 cores, or cold builds without compiler caching, the initial build may take up to 30 minutes.
+:::
+
+---
+
+## Cleaning Profile Counters
+
+Before running a new coverage test pass, remove existing `.profraw` and `.profdata` files to avoid merging stale profiling data:
+
+```bash
+find build-cov -name "libc_cov_*.profraw" -delete 2>/dev/null || true
+rm -f build-cov/libc_full.profdata libc_full.profdata profraw_list.txt
+```
+
+---
+
+## How to Run Standard Coverage (Statement and Branch)
+
+Standard coverage records line execution and branch direction metrics across all LLVM-libc entrypoints and support routines.
+
+### 1. CMake Configuration
+
+Configure LLVM-libc with `-DLLVM_LIBC_ENABLE_COVERAGE=ON`:
+
+```bash
+cmake -G Ninja -S runtimes -B build-cov \
+  -DCMAKE_C_COMPILER=clang \
+  -DCMAKE_CXX_COMPILER=clang++ \
+  -DCMAKE_BUILD_TYPE=Debug \
+  -DLLVM_ENABLE_RUNTIMES=libc \
+  -DLLVM_LIBC_FULL_BUILD=ON \
+  -DLLVM_LIBC_ENABLE_COVERAGE=ON \
+  -DLIBC_ENABLE_MCDC=OFF \
+  -DLIBC_TEST_UNIT_TEST_ONLY=ON \
+  -DLIBC_TEST_SKIP_DEATH_TESTS=ON
+```
+
+### 2. Build Unit Tests
+
+Compile the test suite:
+
+```bash
+ninja -k 0 -C build-cov libc-unit-tests || true
+```
+
+### 3. Run Unit Tests
+
+Execute the compiled unit test binaries in parallel across available CPU cores:
+
+```bash
+# Clean stale counters
+find build-cov -name "libc_cov_*.profraw" -delete 2>/dev/null || true
+rm -f libc_full.profdata profraw_list.txt
+
+# Run all test binaries with isolated PID profile names
+export LLVM_PROFILE_FILE="libc_cov_%p.profraw"
+(cd build-cov && find libc/test -type f -executable -name "*__build__" | xargs -P $(nproc) -I {} sh -c '{} > /dev/null 2>&1 || true')
+```
+
+### 4. Merge Profile Counters
+
+Resolve the matching profile merge tool and aggregate the emitted raw counters:
+
+```bash
+# Auto-detect matching llvm-profdata based on active Clang version
+CLANG_MAJOR=$(clang --version | sed -n 's/.*version \([0-9]*\).*/\1/p')
+LLVM_PROFDATA=$(which llvm-profdata-$CLANG_MAJOR 2>/dev/null || which llvm-profdata)
+
+find . build-cov -name "libc_cov_*.profraw" > profraw_list.txt
+$LLVM_PROFDATA merge -sparse --input-files=profraw_list.txt -o libc_full.profdata
+```
+
+### 5. View Coverage Reports
+
+Collect test binary object references and discover the coverage viewer:
+
+```bash
+CLANG_MAJOR=$(clang --version | sed -n 's/.*version \([0-9]*\).*/\1/p')
+LLVM_COV=$(which llvm-cov-$CLANG_MAJOR 2>/dev/null || which llvm-cov)
+
+EXECUTABLES=($(find build-cov -type f -executable -name "*__build__"))
+OBJECTS=("${EXECUTABLES[@]:1}")
+OBJECTS=("${OBJECTS[@]/#/-object=}")
+```
+
+#### Terminal Summary Table
+
+Display a directory-by-directory coverage report in the terminal:
+
+```bash
+$LLVM_COV report \
+  -instr-profile=libc_full.profdata \
+  "${EXECUTABLES[0]}" "${OBJECTS[@]}" \
+  --show-branch-summary \
+  -ignore-filename-regex=".*(test|utils).*"
+```
+
+#### Interactive HTML Dashboard
+
+Generate a browsable HTML site with source file coverage drill-downs:
+
+```bash
+$LLVM_COV show \
+  -format=html \
+  -output-dir=coverage_html \
+  -instr-profile=libc_full.profdata \
+  "${EXECUTABLES[0]}" "${OBJECTS[@]}" \
+  --show-directory-coverage \
+  --show-branches=count \
+  --compilation-dir=. \
+  --path-equivalence="$PWD,." \
+  -ignore-filename-regex=".*(test|utils).*"
+
+# Open in browser
+xdg-open coverage_html/index.html
+```
+
+---
+
+## How to Run Modified Condition / Decision Coverage (MC/DC)
+
+MC/DC instrumentation captures condition-level truth tables for compound logical expressions in addition to statement and branch metrics.
+
+### 1. CMake Configuration
+
+Enable MC/DC instrumentation by adding `-DLIBC_ENABLE_MCDC=ON`:
+
+```bash
+cmake -G Ninja -S runtimes -B build-cov \
+  -DCMAKE_C_COMPILER=clang \
+  -DCMAKE_CXX_COMPILER=clang++ \
+  -DCMAKE_BUILD_TYPE=Debug \
+  -DLLVM_ENABLE_RUNTIMES=libc \
+  -DLLVM_LIBC_FULL_BUILD=ON \
+  -DLLVM_LIBC_ENABLE_COVERAGE=ON \
+  -DLIBC_ENABLE_MCDC=ON \
+  -DLIBC_TEST_UNIT_TEST_ONLY=ON \
+  -DLIBC_TEST_SKIP_DEATH_TESTS=ON
+```
+
+### 2. Build Unit Tests
+
+Compile the test binaries:
+
+```bash
+ninja -k 0 -C build-cov libc-unit-tests || true
+```
+
+### 3. Run Unit Tests
+
+Execute the compiled unit test binaries in parallel:
+
+```bash
+# Clean stale counters
+find build-cov -name "libc_cov_*.profraw" -delete 2>/dev/null || true
+rm -f libc_full.profdata profraw_list.txt
+
+# Run all test binaries with isolated PID profile names
+export LLVM_PROFILE_FILE="libc_cov_%p.profraw"
+(cd build-cov && find libc/test -type f -executable -name "*__build__" | xargs -P $(nproc) -I {} sh -c '{} > /dev/null 2>&1 || true')
+```
+
+### 4. Merge Profile Counters
+
+Merge the raw counters into an indexed profile dataset:
+
+```bash
+# Auto-detect matching llvm-profdata based on active Clang version
+CLANG_MAJOR=$(clang --version | sed -n 's/.*version \([0-9]*\).*/\1/p')
+LLVM_PROFDATA=$(which llvm-profdata-$CLANG_MAJOR 2>/dev/null || which llvm-profdata)
+
+find . build-cov -name "libc_cov_*.profraw" > profraw_list.txt
+$LLVM_PROFDATA merge -sparse --input-files=profraw_list.txt -o libc_full.profdata
+```
+
+### 5. View MC/DC Coverage Reports
+
+Collect test binary object references:
+
+```bash
+CLANG_MAJOR=$(clang --version | sed -n 's/.*version \([0-9]*\).*/\1/p')
+LLVM_COV=$(which llvm-cov-$CLANG_MAJOR 2>/dev/null || which llvm-cov)
+
+EXECUTABLES=($(find build-cov -type f -executable -name "*__build__"))
+OBJECTS=("${EXECUTABLES[@]:1}")
+OBJECTS=("${OBJECTS[@]/#/-object=}")
+```
+
+#### Terminal Summary Table with MC/DC Metrics
+
+Display statement, branch, and MC/DC decision coverage percentages in the terminal:
+
+```bash
+$LLVM_COV report \
+  -instr-profile=libc_full.profdata \
+  "${EXECUTABLES[0]}" "${OBJECTS[@]}" \
+  --show-branch-summary \
+  --show-mcdc-summary \
+  -ignore-filename-regex=".*(test|utils).*"
+```
+
+#### Interactive HTML Dashboard with MC/DC Analysis
+
+Generate an interactive HTML dashboard containing MC/DC decision breakdown tables and line-by-line coverage:
+
+```bash
+$LLVM_COV show \
+  -format=html \
+  -output-dir=coverage_mcdc_html \
+  -instr-profile=libc_full.profdata \
+  "${EXECUTABLES[0]}" "${OBJECTS[@]}" \
+  --show-directory-coverage \
+  --show-branches=count \
+  --show-mcdc \
+  --show-mcdc-summary \
+  --compilation-dir=. \
+  --path-equivalence="$PWD,." \
+  -ignore-filename-regex=".*(test|utils).*"
+
+# Open in browser
+xdg-open coverage_mcdc_html/index.html
+```
+
+---
+
+## Running Coverage for a Single Target
+
+To quickly inspect coverage for an individual entrypoint (e.g. `strlen`) without building the entire library:
+
+```bash
+# 1. Build the specific test binary
+ninja -C build-cov libc.test.src.string.strlen_test.__unit__.__build__
+
+# 2. Run the test binary
+export LLVM_PROFILE_FILE="libc_cov_%p.profraw"
+./build-cov/libc/test/src/string/libc.test.src.string.strlen_test.__unit__.__build__
+
+# 3. Merge profiles
+CLANG_MAJOR=$(clang --version | sed -n 's/.*version \([0-9]*\).*/\1/p')
+LLVM_PROFDATA=$(which llvm-profdata-$CLANG_MAJOR 2>/dev/null || which llvm-profdata)
+LLVM_COV=$(which llvm-cov-$CLANG_MAJOR 2>/dev/null || which llvm-cov)
+
+find . build-cov -name "libc_cov_*.profraw" > profraw_list.txt
+$LLVM_PROFDATA merge -sparse --input-files=profraw_list.txt -o libc_single.profdata
+
+# 4. View MC/DC truth table in terminal
+TEST_BIN="./build-cov/libc/test/src/string/libc.test.src.string.strlen_test.__unit__.__build__"
+$LLVM_COV show \
+  -instr-profile=libc_single.profdata \
+  "$TEST_BIN" \
+  --show-branches=count \
+  --show-mcdc \
+  libc/src/string/strlen.cpp
+```
+
+---
+
+## Interpreting Results
+
+Understanding coverage metrics helps developers assess test completeness, identify uncovered edge cases, and author targeted unit tests.
+
+### Terminal Summary Metrics
+
+When executing `llvm-cov report`, the terminal output summarizes coverage across files and directories:
+
+* **Region Coverage:**  
+  Measures execution of discrete Abstract Syntax Tree (AST) expression sub-blocks (such as the body of an `if` statement or ternary expressions). A lower region coverage than line coverage indicates partially executed expressions on lines that were counted as hit.
+
+* **Line Coverage:**  
+  Tracks physical source lines executed during the test run. Unexecuted lines represent functions, conditional branches, or error recovery handlers that were never invoked.
+
+* **Branch Coverage:**  
+  Evaluates conditional branch outcomes. If a branch indicates `50%` coverage, the condition was only ever evaluated in one direction (for example, always `True`), leaving the alternative path (`False`) untested.
+
+* **MC/DC Coverage:**  
+  Reports the percentage of compound boolean decisions where every atomic sub-condition was demonstrated to independently determine the final decision outcome.
+
+### HTML Dashboard and Source Inspection
+
+The interactive HTML dashboard (`coverage_html/index.html`) provides line-by-line visual inspection of source implementations:
+
+#### Line Execution Highlights
+
+* **Green Lines:** Source code executed by tests. The margin integer indicates execution count.
+* **Red Lines:** Unexecuted code that requires additional unit test coverage.
+
+#### Branch Markers
+
+Conditional statements display branch hit counts inline in the format `[True: N, False: M]`. An entry of `[True: 10, False: 0]` indicates that the conditional expression was never evaluated as False during testing. Adding a unit test where the condition evaluates to False resolves this gap.
+
+#### MC/DC Truth Tables and Condition Diagnostics
+
+When `--show-mcdc` is enabled, `llvm-cov` renders a boolean truth table directly below compound decisions:
+
+```
+   19|    517|  if (c < 0 || c > 255)
+  ------------------
+  |  Executed MC/DC Test Vectors:
+  |     C1, C2    Result
+  |  1 { F,  F  = F      }
+  |  2 { T,  -  = T      }
+  |
+  |  C1-Pair: covered (1, 2)
+  |  C2-Pair: not covered
+  |  MC/DC Coverage for Decision: 50.00%
+  ------------------
+```
+
+##### Understanding the Truth Table
+
+1. **Identify the Conditions:**  
+   In `if (c < 0 || c > 255)`, condition **C1** is `c < 0` and **C2** is `c > 255`.
+
+2. **Inspect Executed Vectors:**  
+   * **Vector 1 (`F, F = F`):** Tested with an in-range value (e.g. `c = 100`). Both C1 and C2 evaluated to False, producing a False outcome.
+   * **Vector 2 (`T, - = T`):** Tested with a negative value (e.g. `c = -1`). C1 evaluated to True, which immediately satisfied the `if` statement (C2 was short-circuited `-`).
+
+3. **Evaluate Coverage Status:**  
+   * **`C1-Pair: covered (1, 2)`:** Verified. Comparing Vector 1 and Vector 2 proves that toggling C1 alone flips the overall decision outcome.
+   * **`C2-Pair: not covered`:** Missing. C2 was never tested in a state where it independently caused the `if` condition to become True.
+
+4. **How to Fix the Gap:**  
+   Add a unit test case with `c = 256`. This evaluates C1 as False and C2 as True (`3 { F, True = True }`), forming the missing independence pair `(1, 3)` for C2 and achieving 100% MC/DC coverage.
diff --git a/libc/docs/dev/index.md b/libc/docs/dev/index.md
index 4ce78540c8fad..be0d0018df249 100644
--- a/libc/docs/dev/index.md
+++ b/libc/docs/dev/index.md
@@ -8,6 +8,7 @@ Navigate to the links below for information on the respective topics:
 :maxdepth: 1
 
 building_docs
+code_coverage
 code_style
 source_tree_layout
 entrypoints

>From f518aed04d63e8d41ffc624150035c532516f498 Mon Sep 17 00:00:00 2001
From: Tapiwa Gonga <tapiwagonga at google.com>
Date: Wed, 26 Aug 2026 12:33:19 +0000
Subject: [PATCH 2/6] [libc][docs] Update code coverage developer guide with
 step-by-step instructions and MC/DC truth table analysis

---
 libc/docs/dev/code_coverage.md | 376 +++++++++++++++------------------
 1 file changed, 167 insertions(+), 209 deletions(-)

diff --git a/libc/docs/dev/code_coverage.md b/libc/docs/dev/code_coverage.md
index 971ab9011de40..2077a97e36e83 100644
--- a/libc/docs/dev/code_coverage.md
+++ b/libc/docs/dev/code_coverage.md
@@ -1,22 +1,8 @@
-# Code Coverage in LLVM-libc
-
 (code_coverage)=
 
-This document describes how to configure, generate, and view code coverage and Modified Condition / Decision Coverage (MC/DC) reports for LLVM-libc.
-
----
-
-## Overview
-
-Code coverage measures the proportion of source code executed during testing. In LLVM-libc, coverage metrics identify untested edge cases, prevent regressions across supported architectures, and provide verification evidence for safety-critical systems.
+# Code Coverage
 
-### Coverage Modes
-
-* **Statement and Branch Coverage:**  
-  Measures line execution and verifies whether conditional branches evaluated to both true and false paths.
-
-* **Modified Condition / Decision Coverage (MC/DC):**  
-  Evaluates boolean conditions within compound decisions (such as `if (A && B)`). Verifies that each individual sub-condition is tested with both true and false values and independently affects the outcome of the enclosing decision. Required by safety-critical standards such as DO-178C (aviation) and ISO 26262 (automotive).
+LLVM-libc supports generating statement, branch, and Modified Condition / Decision Coverage (MC/DC) reports locally. Because `llvm-libc` unit tests run in freestanding test harnesses, coverage counters and boolean decision bitmasks are captured directly and written to disk upon test completion using internal Linux kernel system calls.
 
 ---
 
@@ -28,332 +14,294 @@ Generating coverage reports requires Clang, LLVM profile tools, CMake, and Ninja
 * **LLVM Utilities:** Matching major versions of `llvm-profdata` and `llvm-cov`.
 * **Build System:** CMake 3.28+ and Ninja.
 
-### Toolchain Installation (Debian/Ubuntu)
-
-Install the required compiler, tooling, and build utilities:
-
-```bash
-sudo apt install clang-21 llvm-21-tools lld-21 ninja-build cmake
-```
-
-### Configuring Tool Links
-
-Because Debian and Ubuntu install LLVM tools with version suffixes (such as `llvm-profdata-21`), you can configure unversioned aliases using either of the following methods:
-
-#### Method A: User-Level Setup (Recommended - No `sudo` required)
-
-```bash
-mkdir -p ~/.local/bin
-ln -sf $(which llvm-profdata-21 2>/dev/null || which llvm-profdata) ~/.local/bin/llvm-profdata
-ln -sf $(which llvm-cov-21 2>/dev/null || which llvm-cov) ~/.local/bin/llvm-cov
-export PATH="$HOME/.local/bin:$PATH"
-```
+### Toolchain Discovery
 
-#### Method B: System-Wide Alternatives (Requires `sudo`)
+If your Linux distribution packages version-suffixed binaries (e.g. `clang-21`, `llvm-profdata-21`), you can resolve them automatically:
 
 ```bash
-sudo update-alternatives --install /usr/bin/llvm-profdata llvm-profdata /usr/bin/llvm-profdata-21 100
-sudo update-alternatives --install /usr/bin/llvm-cov llvm-cov /usr/bin/llvm-cov-21 100
+CLANG_MAJOR=$(clang --version | sed -n 's/.*version \([0-9]*\).*/\1/p')
+LLVM_PROFDATA=$(which llvm-profdata-$CLANG_MAJOR 2>/dev/null || which llvm-profdata)
+LLVM_COV=$(which llvm-cov-$CLANG_MAJOR 2>/dev/null || which llvm-cov)
 ```
 
-:::{note}
-Compiling the full suite of unit tests with coverage instrumentation encompasses ~10,000 target nodes. On multi-core workstations, parallel compilation completes in a few minutes. On resource-constrained systems, virtual machines with 2–4 cores, or cold builds without compiler caching, the initial build may take up to 30 minutes.
-:::
-
 ---
 
 ## Cleaning Profile Counters
 
-Before running a new coverage test pass, remove existing `.profraw` and `.profdata` files to avoid merging stale profiling data:
+Removes previously generated raw profile counter files (`.profraw`) and merged profile databases (`.profdata`) so that new coverage runs record clean, non-aggregated execution data:
 
 ```bash
-find build-cov -name "libc_cov_*.profraw" -delete 2>/dev/null || true
-rm -f build-cov/libc_full.profdata libc_full.profdata profraw_list.txt
+find . -name "libc_cov_*.profraw" -delete 2>/dev/null || true
+rm -f libc_full.profdata libc_mcdc.profdata libc_single.profdata profraw_list.txt
 ```
 
 ---
 
-## How to Run Standard Coverage (Statement and Branch)
+## Standard Statement & Branch Coverage
 
-Standard coverage records line execution and branch direction metrics across all LLVM-libc entrypoints and support routines.
+Standard coverage measures physical line execution and conditional branch outcomes across all LLVM-libc entrypoints and internal support utilities.
 
 ### 1. CMake Configuration
 
-Configure LLVM-libc with `-DLLVM_LIBC_ENABLE_COVERAGE=ON`:
+Configures CMake to build LLVM-libc in overlay mode, setting `-DLIBC_ENABLE_COVERAGE=ON` to pass Clang's `-fprofile-instr-generate` and `-fcoverage-mapping` flags to the compiler:
 
 ```bash
 cmake -G Ninja -S runtimes -B build-cov \
   -DCMAKE_C_COMPILER=clang \
   -DCMAKE_CXX_COMPILER=clang++ \
   -DCMAKE_BUILD_TYPE=Debug \
-  -DLLVM_ENABLE_RUNTIMES=libc \
-  -DLLVM_LIBC_FULL_BUILD=ON \
-  -DLLVM_LIBC_ENABLE_COVERAGE=ON \
-  -DLIBC_ENABLE_MCDC=OFF \
-  -DLIBC_TEST_UNIT_TEST_ONLY=ON \
-  -DLIBC_TEST_SKIP_DEATH_TESTS=ON
+  -DLLVM_ENABLE_RUNTIMES="libc" \
+  -DLLVM_LIBC_FULL_BUILD=OFF \
+  -DLIBC_ENABLE_COVERAGE=ON
 ```
 
-### 2. Build Unit Tests
+### 2. Build and Execute All Unit Tests
 
-Compile the test suite:
+Compiles all libc unit test executables and executes them in parallel. As each test completes, its test harness writes execution counters to a PID-specific `.profraw` file via direct Linux syscalls:
 
 ```bash
-ninja -k 0 -C build-cov libc-unit-tests || true
+ninja -k 0 -C build-cov libc-unit-tests
 ```
 
-### 3. Run Unit Tests
-
-Execute the compiled unit test binaries in parallel across available CPU cores:
-
-```bash
-# Clean stale counters
-find build-cov -name "libc_cov_*.profraw" -delete 2>/dev/null || true
-rm -f libc_full.profdata profraw_list.txt
-
-# Run all test binaries with isolated PID profile names
-export LLVM_PROFILE_FILE="libc_cov_%p.profraw"
-(cd build-cov && find libc/test -type f -executable -name "*__build__" | xargs -P $(nproc) -I {} sh -c '{} > /dev/null 2>&1 || true')
-```
+:::{note}
+In LLVM-libc, `libc-unit-tests` builds and executes tests in a single invocation. The `-k 0` flag ensures Ninja continues executing all remaining test targets even if an individual edge-case test encounters an error. To only compile test binaries without immediately executing them, use `ninja -C build-cov libc-unit-tests-build`.
+:::
 
-### 4. Merge Profile Counters
+### 3. Merge Profile Counters
 
-Resolve the matching profile merge tool and aggregate the emitted raw counters:
+Scans the build tree for all generated `.profraw` files and indexes them into a unified, sparse `.profdata` archive using `llvm-profdata`:
 
 ```bash
-# Auto-detect matching llvm-profdata based on active Clang version
-CLANG_MAJOR=$(clang --version | sed -n 's/.*version \([0-9]*\).*/\1/p')
-LLVM_PROFDATA=$(which llvm-profdata-$CLANG_MAJOR 2>/dev/null || which llvm-profdata)
-
-find . build-cov -name "libc_cov_*.profraw" > profraw_list.txt
-$LLVM_PROFDATA merge -sparse --input-files=profraw_list.txt -o libc_full.profdata
+find . -name "libc_cov_*.profraw" > profraw_list.txt
+llvm-profdata merge -sparse -f profraw_list.txt -o libc_full.profdata
 ```
 
-### 5. View Coverage Reports
+### 4. Generate Coverage Reports
 
-Collect test binary object references and discover the coverage viewer:
+Collects all compiled test binary paths and invokes `llvm-cov` to correlate recorded profile counters against the libc source tree:
 
 ```bash
-CLANG_MAJOR=$(clang --version | sed -n 's/.*version \([0-9]*\).*/\1/p')
-LLVM_COV=$(which llvm-cov-$CLANG_MAJOR 2>/dev/null || which llvm-cov)
-
-EXECUTABLES=($(find build-cov -type f -executable -name "*__build__"))
-OBJECTS=("${EXECUTABLES[@]:1}")
-OBJECTS=("${OBJECTS[@]/#/-object=}")
+TEST_BINS=($(find build-cov -type f -executable -name "*__build__"))
+OBJECT_FLAGS=()
+for bin in "${TEST_BINS[@]:1}"; do
+  OBJECT_FLAGS+=("-object=$bin")
+done
 ```
 
 #### Terminal Summary Table
-
-Display a directory-by-directory coverage report in the terminal:
+Prints an aggregated terminal summary showing line, region, and branch coverage percentages for each file:
 
 ```bash
-$LLVM_COV report \
+llvm-cov report \
   -instr-profile=libc_full.profdata \
-  "${EXECUTABLES[0]}" "${OBJECTS[@]}" \
+  "${TEST_BINS[0]}" "${OBJECT_FLAGS[@]}" \
   --show-branch-summary \
   -ignore-filename-regex=".*(test|utils).*"
 ```
 
 #### Interactive HTML Dashboard
-
-Generate a browsable HTML site with source file coverage drill-downs:
+Generates an interactive HTML dashboard containing sortable directory metrics and syntax-highlighted source views:
 
 ```bash
-$LLVM_COV show \
+llvm-cov show \
   -format=html \
   -output-dir=coverage_html \
   -instr-profile=libc_full.profdata \
-  "${EXECUTABLES[0]}" "${OBJECTS[@]}" \
+  "${TEST_BINS[0]}" "${OBJECT_FLAGS[@]}" \
   --show-directory-coverage \
   --show-branches=count \
-  --compilation-dir=. \
-  --path-equivalence="$PWD,." \
   -ignore-filename-regex=".*(test|utils).*"
 
-# Open in browser
+# Open dashboard in browser
 xdg-open coverage_html/index.html
 ```
 
 ---
 
-## How to Run Modified Condition / Decision Coverage (MC/DC)
+## Modified Condition / Decision Coverage (MC/DC)
 
-MC/DC instrumentation captures condition-level truth tables for compound logical expressions in addition to statement and branch metrics.
+MC/DC evaluates boolean sub-conditions within compound logical expressions (such as `if (A && B)`). It verifies that each individual sub-condition evaluates to both true and false and independently affects the outcome of the enclosing decision.
 
 ### 1. CMake Configuration
 
-Enable MC/DC instrumentation by adding `-DLIBC_ENABLE_MCDC=ON`:
+Configures CMake with `-fcoverage-mcdc` alongside profiling flags, enabling the compiler frontend to generate boolean condition bitmaps for compound decisions:
 
 ```bash
-cmake -G Ninja -S runtimes -B build-cov \
+cmake -G Ninja -S runtimes -B build-cov-mcdc \
   -DCMAKE_C_COMPILER=clang \
   -DCMAKE_CXX_COMPILER=clang++ \
   -DCMAKE_BUILD_TYPE=Debug \
-  -DLLVM_ENABLE_RUNTIMES=libc \
-  -DLLVM_LIBC_FULL_BUILD=ON \
-  -DLLVM_LIBC_ENABLE_COVERAGE=ON \
-  -DLIBC_ENABLE_MCDC=ON \
-  -DLIBC_TEST_UNIT_TEST_ONLY=ON \
-  -DLIBC_TEST_SKIP_DEATH_TESTS=ON
-```
-
-### 2. Build Unit Tests
-
-Compile the test binaries:
-
-```bash
-ninja -k 0 -C build-cov libc-unit-tests || true
+  -DLLVM_ENABLE_RUNTIMES="libc" \
+  -DLLVM_LIBC_FULL_BUILD=OFF \
+  -DLIBC_ENABLE_COVERAGE=ON \
+  -DCMAKE_C_FLAGS="-fprofile-instr-generate -fcoverage-mapping -fcoverage-mcdc" \
+  -DCMAKE_CXX_FLAGS="-fprofile-instr-generate -fcoverage-mapping -fcoverage-mcdc"
 ```
 
-### 3. Run Unit Tests
+### 2. Build and Execute Tests
 
-Execute the compiled unit test binaries in parallel:
+Compiles and executes all unit tests with MC/DC instrumentation enabled, saving condition evaluation bitmasks into raw profile files upon completion:
 
 ```bash
-# Clean stale counters
-find build-cov -name "libc_cov_*.profraw" -delete 2>/dev/null || true
-rm -f libc_full.profdata profraw_list.txt
-
-# Run all test binaries with isolated PID profile names
-export LLVM_PROFILE_FILE="libc_cov_%p.profraw"
-(cd build-cov && find libc/test -type f -executable -name "*__build__" | xargs -P $(nproc) -I {} sh -c '{} > /dev/null 2>&1 || true')
+ninja -k 0 -C build-cov-mcdc libc-unit-tests
 ```
 
-### 4. Merge Profile Counters
+### 3. Merge Profiles
 
-Merge the raw counters into an indexed profile dataset:
+Indexes and merges all MC/DC `.profraw` files into a unified `libc_mcdc.profdata` archive for report generation:
 
 ```bash
-# Auto-detect matching llvm-profdata based on active Clang version
-CLANG_MAJOR=$(clang --version | sed -n 's/.*version \([0-9]*\).*/\1/p')
-LLVM_PROFDATA=$(which llvm-profdata-$CLANG_MAJOR 2>/dev/null || which llvm-profdata)
-
-find . build-cov -name "libc_cov_*.profraw" > profraw_list.txt
-$LLVM_PROFDATA merge -sparse --input-files=profraw_list.txt -o libc_full.profdata
+find . -name "libc_cov_*.profraw" > profraw_list.txt
+llvm-profdata merge -sparse -f profraw_list.txt -o libc_mcdc.profdata
 ```
 
-### 5. View MC/DC Coverage Reports
+### 4. Generate Reports
 
-Collect test binary object references:
+Maps MC/DC bitmap records to source AST decisions and evaluates condition independence pairs:
 
 ```bash
-CLANG_MAJOR=$(clang --version | sed -n 's/.*version \([0-9]*\).*/\1/p')
-LLVM_COV=$(which llvm-cov-$CLANG_MAJOR 2>/dev/null || which llvm-cov)
-
-EXECUTABLES=($(find build-cov -type f -executable -name "*__build__"))
-OBJECTS=("${EXECUTABLES[@]:1}")
-OBJECTS=("${OBJECTS[@]/#/-object=}")
+TEST_BINS=($(find build-cov-mcdc -type f -executable -name "*__build__"))
+OBJECT_FLAGS=()
+for bin in "${TEST_BINS[@]:1}"; do
+  OBJECT_FLAGS+=("-object=$bin")
+done
 ```
 
-#### Terminal Summary Table with MC/DC Metrics
-
-Display statement, branch, and MC/DC decision coverage percentages in the terminal:
+#### Terminal Summary Table
+Displays the terminal coverage summary including MC/DC Condition and Missed Condition percentages:
 
 ```bash
-$LLVM_COV report \
-  -instr-profile=libc_full.profdata \
-  "${EXECUTABLES[0]}" "${OBJECTS[@]}" \
+llvm-cov report \
+  -instr-profile=libc_mcdc.profdata \
+  "${TEST_BINS[0]}" "${OBJECT_FLAGS[@]}" \
   --show-branch-summary \
   --show-mcdc-summary \
   -ignore-filename-regex=".*(test|utils).*"
 ```
 
-#### Interactive HTML Dashboard with MC/DC Analysis
-
-Generate an interactive HTML dashboard containing MC/DC decision breakdown tables and line-by-line coverage:
+#### Interactive HTML Dashboard
+Produces an HTML report with expandable MC/DC decision truth tables and test vector coverage breakdowns:
 
 ```bash
-$LLVM_COV show \
+llvm-cov show \
   -format=html \
   -output-dir=coverage_mcdc_html \
-  -instr-profile=libc_full.profdata \
-  "${EXECUTABLES[0]}" "${OBJECTS[@]}" \
+  -instr-profile=libc_mcdc.profdata \
+  "${TEST_BINS[0]}" "${OBJECT_FLAGS[@]}" \
   --show-directory-coverage \
   --show-branches=count \
   --show-mcdc \
   --show-mcdc-summary \
-  --compilation-dir=. \
-  --path-equivalence="$PWD,." \
   -ignore-filename-regex=".*(test|utils).*"
 
-# Open in browser
+# Open dashboard in browser
 xdg-open coverage_mcdc_html/index.html
 ```
 
 ---
 
-## Running Coverage for a Single Target
+## Running Coverage for a Single Test
+
+When developing or modifying a specific function, running coverage on a single unit test allows rapid iteration (~2 seconds) without compiling and running the entire library suite.
+
+The commands below use `libc.test.src.ctype.isalpha_test` (which tests `libc/src/ctype/isalpha.cpp`) as an example. You can test any other entrypoint by substituting the target name and source file path:
+* **Target pattern:** `libc.test.<path_to_test>.<test_name>` (e.g. `libc.test.src.string.strlen_test`)
+* **Source path pattern:** `libc/<path_to_source>/<source_file>.cpp` (e.g. `libc/src/string/strlen.cpp`)
+
+### 1. Build and Execute the Targeted Test
 
-To quickly inspect coverage for an individual entrypoint (e.g. `strlen`) without building the entire library:
+Compiles and runs only the specified unit test binary, immediately dumping execution profile counters for fast feedback (~2 seconds):
 
 ```bash
-# 1. Build the specific test binary
-ninja -C build-cov libc.test.src.string.strlen_test.__unit__.__build__
+# For a standard coverage build
+ninja -C build-cov libc.test.src.ctype.isalpha_test
 
-# 2. Run the test binary
-export LLVM_PROFILE_FILE="libc_cov_%p.profraw"
-./build-cov/libc/test/src/string/libc.test.src.string.strlen_test.__unit__.__build__
+# For an MC/DC build
+ninja -C build-cov-mcdc libc.test.src.ctype.isalpha_test
+```
 
-# 3. Merge profiles
-CLANG_MAJOR=$(clang --version | sed -n 's/.*version \([0-9]*\).*/\1/p')
-LLVM_PROFDATA=$(which llvm-profdata-$CLANG_MAJOR 2>/dev/null || which llvm-profdata)
-LLVM_COV=$(which llvm-cov-$CLANG_MAJOR 2>/dev/null || which llvm-cov)
+### 2. Merge the Profile
+
+Merges the single test's raw profile into an indexed database for targeted inspection:
+
+```bash
+find . -name "libc_cov_*.profraw" > profraw_list.txt
+llvm-profdata merge -sparse -f profraw_list.txt -o libc_single.profdata
+```
+
+### 3. View the Terminal Report
+
+Renders the coverage metrics or line-by-line truth table for the specific source file being tested:
 
-find . build-cov -name "libc_cov_*.profraw" > profraw_list.txt
-$LLVM_PROFDATA merge -sparse --input-files=profraw_list.txt -o libc_single.profdata
+```bash
+# Standard summary report
+llvm-cov report \
+  -instr-profile=libc_single.profdata \
+  ./build-cov/libc/test/src/ctype/libc.test.src.ctype.isalpha_test.__build__ \
+  libc/src/ctype/isalpha.cpp
 
-# 4. View MC/DC truth table in terminal
-TEST_BIN="./build-cov/libc/test/src/string/libc.test.src.string.strlen_test.__unit__.__build__"
-$LLVM_COV show \
+# Line-by-line coverage and truth table inspection
+llvm-cov show \
   -instr-profile=libc_single.profdata \
-  "$TEST_BIN" \
+  ./build-cov-mcdc/libc/test/src/ctype/libc.test.src.ctype.isalpha_test.__build__ \
   --show-branches=count \
   --show-mcdc \
-  libc/src/string/strlen.cpp
+  libc/src/ctype/isalpha.cpp
 ```
 
 ---
 
 ## Interpreting Results
 
-Understanding coverage metrics helps developers assess test completeness, identify uncovered edge cases, and author targeted unit tests.
-
-### Terminal Summary Metrics
-
-When executing `llvm-cov report`, the terminal output summarizes coverage across files and directories:
-
-* **Region Coverage:**  
-  Measures execution of discrete Abstract Syntax Tree (AST) expression sub-blocks (such as the body of an `if` statement or ternary expressions). A lower region coverage than line coverage indicates partially executed expressions on lines that were counted as hit.
+### Coverage Metrics Overview
 
 * **Line Coverage:**  
-  Tracks physical source lines executed during the test run. Unexecuted lines represent functions, conditional branches, or error recovery handlers that were never invoked.
-
+  Measures whether each physical line of executable source code was reached at least once during testing.
 * **Branch Coverage:**  
-  Evaluates conditional branch outcomes. If a branch indicates `50%` coverage, the condition was only ever evaluated in one direction (for example, always `True`), leaving the alternative path (`False`) untested.
-
+  Measures whether each conditional branch evaluated to both its `True` and `False` paths. For example, if an `if (x > 0)` branch is taken 10 times but never skipped, branch coverage is 50% because the `False` path was never exercised.
 * **MC/DC Coverage:**  
-  Reports the percentage of compound boolean decisions where every atomic sub-condition was demonstrated to independently determine the final decision outcome.
+  Evaluates compound boolean expressions (such as `if (A && B)` or `if (A || B)`). It verifies that each individual condition was tested as both True and False, and demonstrated that it could independently change the overall outcome of the decision.
 
-### HTML Dashboard and Source Inspection
+### Understanding Summary Reports (`llvm-cov report`)
 
-The interactive HTML dashboard (`coverage_html/index.html`) provides line-by-line visual inspection of source implementations:
+The summary table produced by `llvm-cov report` displays metrics across individual source files and overall totals:
 
-#### Line Execution Highlights
+* **Regions / Missed Regions:** A region is a continuous segment of code (such as a function body or basic block). Missed regions indicate code blocks that were never executed.
+* **Functions / Missed Functions:** The total number of entrypoints or subroutines executed vs unexecuted.
+* **Lines / Missed Lines:** Physical source lines executed vs unexecuted.
+* **Branches / Missed Branches:** The total count of decision directions (both True and False) evaluated.
+* **MC/DC Conditions / Missed Conditions:** The count of individual boolean sub-conditions that demonstrated independent decision control.
 
-* **Green Lines:** Source code executed by tests. The margin integer indicates execution count.
-* **Red Lines:** Unexecuted code that requires additional unit test coverage.
+### Understanding Annotated Source Code (`llvm-cov show`)
 
-#### Branch Markers
+When viewing annotated source listings:
+* **Line Number (Left Column):** The corresponding line in the source file.
+* **Execution Count (Second Column):** The number of times that line was executed (for example, `517` means 517 executions; `0` indicates unexecuted code).
+* **Branch Annotations:** Shows the exact number of times each branch path evaluated True and False:
+  ```text
+  |  Branch (19:7):  [True: 256, False: 261]
+  |  Branch (19:16): [True: 0,   False: 261]
+  ```
+  In this example, the second branch at column 16 was evaluated False 261 times, but was never evaluated True (`True: 0`), indicating an untested branch path.
 
-Conditional statements display branch hit counts inline in the format `[True: N, False: M]`. An entry of `[True: 10, False: 0]` indicates that the conditional expression was never evaluated as False during testing. Adding a unit test where the condition evaluates to False resolves this gap.
+### Understanding the MC/DC Truth Table Output
 
-#### MC/DC Truth Tables and Condition Diagnostics
+When inspecting with `--show-mcdc`, `llvm-cov` prints a truth table underneath each compound decision statement.
 
-When `--show-mcdc` is enabled, `llvm-cov` renders a boolean truth table directly below compound decisions:
+For example, inspecting `libc/src/ctype/isalpha.cpp` produces:
 
-```
-   19|    517|  if (c < 0 || c > 255)
+```text
+   18|    517|LLVM_LIBC_FUNCTION(int, isalpha, (int c)) {
+   19|    517|  if (c < 0 || c > cpp::numeric_limits<unsigned char>::max())
   ------------------
+  |  Branch (19:7): [True: 256, False: 261]
+  |  Branch (19:16): [True: 0, False: 261]
+  ------------------
+  |---> MC/DC Decision Region (19:7) to (19:61)
+  |  Number of Conditions: 2
+  |     Condition C1 --> (19:7)
+  |     Condition C2 --> (19:16)
+  |
   |  Executed MC/DC Test Vectors:
   |     C1, C2    Result
   |  1 { F,  F  = F      }
@@ -363,20 +311,30 @@ When `--show-mcdc` is enabled, `llvm-cov` renders a boolean truth table directly
   |  C2-Pair: not covered
   |  MC/DC Coverage for Decision: 50.00%
   ------------------
+   20|    256|    return 0;
+   21|    261|  return static_cast<int>(internal::isalpha(static_cast<char>(c)));
+   22|    517|}
 ```
 
-##### Understanding the Truth Table
+#### Step-by-Step Breakdown:
 
-1. **Identify the Conditions:**  
-   In `if (c < 0 || c > 255)`, condition **C1** is `c < 0` and **C2** is `c > 255`.
+1. **Conditions (C1, C2):**  
+   The decision on line 19 contains two sub-conditions: `if (c < 0 || c > 255)`.
+   * **C1** is the first condition: `c < 0`
+   * **C2** is the second condition: `c > 255`
 
-2. **Inspect Executed Vectors:**  
-   * **Vector 1 (`F, F = F`):** Tested with an in-range value (e.g. `c = 100`). Both C1 and C2 evaluated to False, producing a False outcome.
-   * **Vector 2 (`T, - = T`):** Tested with a negative value (e.g. `c = -1`). C1 evaluated to True, which immediately satisfied the `if` statement (C2 was short-circuited `-`).
+2. **Executed Test Vectors:**  
+   Each numbered row records an observed combination of condition inputs and the resulting decision outcome:
+   * **Vector 1 (`F, F = F`):** Tested with a valid character (e.g. `c = 'a'`). Both C1 and C2 evaluated to False, producing an overall result of False.
+   * **Vector 2 (`T, - = T`):** Tested with a negative value (e.g. `c = -1`). C1 evaluated to True, producing an overall result of True. The hyphen (`-`) indicates that C2 was short-circuited by the compiler and not evaluated.
 
-3. **Evaluate Coverage Status:**  
-   * **`C1-Pair: covered (1, 2)`:** Verified. Comparing Vector 1 and Vector 2 proves that toggling C1 alone flips the overall decision outcome.
-   * **`C2-Pair: not covered`:** Missing. C2 was never tested in a state where it independently caused the `if` condition to become True.
+3. **Condition Pairs & Independent Effect:**  
+   To satisfy MC/DC, each condition must show that toggling its value from False to True directly flips the overall decision outcome while holding other conditions constant:
+   * **`C1-Pair: covered (1, 2)`:** Comparing Vector 1 (`F, F = F`) and Vector 2 (`T, - = T`) shows that changing C1 from False to True flipped the result from False to True. C1 is fully covered.
+   * **`C2-Pair: not covered`:** There is no test vector where C2 evaluated to True while C1 remained False. Therefore, C2 has not yet proved independent control over the decision.
 
-4. **How to Fix the Gap:**  
-   Add a unit test case with `c = 256`. This evaluates C1 as False and C2 as True (`3 { F, True = True }`), forming the missing independence pair `(1, 3)` for C2 and achieving 100% MC/DC coverage.
+4. **How to Reach 100% Decision Coverage:**  
+   To complete coverage for C2:
+   * Add a test case with an out-of-range positive value (such as `c = 256`).
+   * This executes Vector 3 (`F, T = T`), where C1 is False and C2 is True, yielding an overall True outcome.
+   * Comparing Vector 1 (`F, F = F`) and Vector 3 (`F, T = T`) forms the independence pair `(1, 3)` for C2, demonstrating that C2 independently controls the decision and achieving 100% MC/DC coverage.

>From 12de0a7c4bd336022a13c53eb52a446c44cbbdfa Mon Sep 17 00:00:00 2001
From: Tapiwa Gonga <tapiwagonga at google.com>
Date: Wed, 26 Aug 2026 12:41:48 +0000
Subject: [PATCH 3/6] [libc][docs] Simplify MC/DC truth table analysis in code
 coverage developer guide

---
 libc/docs/dev/code_coverage.md | 83 ++++++++++------------------------
 1 file changed, 23 insertions(+), 60 deletions(-)

diff --git a/libc/docs/dev/code_coverage.md b/libc/docs/dev/code_coverage.md
index 2077a97e36e83..6823170539d42 100644
--- a/libc/docs/dev/code_coverage.md
+++ b/libc/docs/dev/code_coverage.md
@@ -262,7 +262,7 @@ llvm-cov show \
 * **MC/DC Coverage:**  
   Evaluates compound boolean expressions (such as `if (A && B)` or `if (A || B)`). It verifies that each individual condition was tested as both True and False, and demonstrated that it could independently change the overall outcome of the decision.
 
-### Understanding Summary Reports (`llvm-cov report`)
+### Interpreting Summary Reports (`llvm-cov report`)
 
 The summary table produced by `llvm-cov report` displays metrics across individual source files and overall totals:
 
@@ -272,69 +272,32 @@ The summary table produced by `llvm-cov report` displays metrics across individu
 * **Branches / Missed Branches:** The total count of decision directions (both True and False) evaluated.
 * **MC/DC Conditions / Missed Conditions:** The count of individual boolean sub-conditions that demonstrated independent decision control.
 
-### Understanding Annotated Source Code (`llvm-cov show`)
+### Interpreting MC/DC Truth Tables
 
-When viewing annotated source listings:
-* **Line Number (Left Column):** The corresponding line in the source file.
-* **Execution Count (Second Column):** The number of times that line was executed (for example, `517` means 517 executions; `0` indicates unexecuted code).
-* **Branch Annotations:** Shows the exact number of times each branch path evaluated True and False:
-  ```text
-  |  Branch (19:7):  [True: 256, False: 261]
-  |  Branch (19:16): [True: 0,   False: 261]
-  ```
-  In this example, the second branch at column 16 was evaluated False 261 times, but was never evaluated True (`True: 0`), indicating an untested branch path.
-
-### Understanding the MC/DC Truth Table Output
-
-When inspecting with `--show-mcdc`, `llvm-cov` prints a truth table underneath each compound decision statement.
-
-For example, inspecting `libc/src/ctype/isalpha.cpp` produces:
+When inspecting with `--show-mcdc`, `llvm-cov` displays an MC/DC analysis box beneath each compound decision:
 
 ```text
-   18|    517|LLVM_LIBC_FUNCTION(int, isalpha, (int c)) {
-   19|    517|  if (c < 0 || c > cpp::numeric_limits<unsigned char>::max())
-  ------------------
-  |  Branch (19:7): [True: 256, False: 261]
-  |  Branch (19:16): [True: 0, False: 261]
-  ------------------
-  |---> MC/DC Decision Region (19:7) to (19:61)
-  |  Number of Conditions: 2
-  |     Condition C1 --> (19:7)
-  |     Condition C2 --> (19:16)
+   19|  if (c < 0 || c > 255)
+  -----------------------------------------------
+  | Conditions: C1 = (c < 0), C2 = (c > 255)
   |
-  |  Executed MC/DC Test Vectors:
-  |     C1, C2    Result
-  |  1 { F,  F  = F      }
-  |  2 { T,  -  = T      }
+  | Executed Test Vectors:
+  |    C1, C2    Result
+  | 1 { F,  F  = F      }  (tested with c = 'a')
+  | 2 { T,  -  = T      }  (tested with c = -1)
   |
-  |  C1-Pair: covered (1, 2)
-  |  C2-Pair: not covered
-  |  MC/DC Coverage for Decision: 50.00%
-  ------------------
-   20|    256|    return 0;
-   21|    261|  return static_cast<int>(internal::isalpha(static_cast<char>(c)));
-   22|    517|}
+  | C1-Pair: covered (1, 2)
+  | C2-Pair: not covered
+  | MC/DC Coverage: 50.00%
+  -----------------------------------------------
 ```
 
-#### Step-by-Step Breakdown:
-
-1. **Conditions (C1, C2):**  
-   The decision on line 19 contains two sub-conditions: `if (c < 0 || c > 255)`.
-   * **C1** is the first condition: `c < 0`
-   * **C2** is the second condition: `c > 255`
-
-2. **Executed Test Vectors:**  
-   Each numbered row records an observed combination of condition inputs and the resulting decision outcome:
-   * **Vector 1 (`F, F = F`):** Tested with a valid character (e.g. `c = 'a'`). Both C1 and C2 evaluated to False, producing an overall result of False.
-   * **Vector 2 (`T, - = T`):** Tested with a negative value (e.g. `c = -1`). C1 evaluated to True, producing an overall result of True. The hyphen (`-`) indicates that C2 was short-circuited by the compiler and not evaluated.
-
-3. **Condition Pairs & Independent Effect:**  
-   To satisfy MC/DC, each condition must show that toggling its value from False to True directly flips the overall decision outcome while holding other conditions constant:
-   * **`C1-Pair: covered (1, 2)`:** Comparing Vector 1 (`F, F = F`) and Vector 2 (`T, - = T`) shows that changing C1 from False to True flipped the result from False to True. C1 is fully covered.
-   * **`C2-Pair: not covered`:** There is no test vector where C2 evaluated to True while C1 remained False. Therefore, C2 has not yet proved independent control over the decision.
-
-4. **How to Reach 100% Decision Coverage:**  
-   To complete coverage for C2:
-   * Add a test case with an out-of-range positive value (such as `c = 256`).
-   * This executes Vector 3 (`F, T = T`), where C1 is False and C2 is True, yielding an overall True outcome.
-   * Comparing Vector 1 (`F, F = F`) and Vector 3 (`F, T = T`) forms the independence pair `(1, 3)` for C2, demonstrating that C2 independently controls the decision and achieving 100% MC/DC coverage.
+* **Conditions:** **C1** represents `c < 0` and **C2** represents `c > 255`.
+* **Executed Vectors:**
+  * **Vector 1 (`F, F = F`):** Tested with a valid character (`c = 'a'`). Both C1 and C2 evaluated False, producing an overall False result.
+  * **Vector 2 (`T, - = T`):** Tested with a negative value (`c = -1`). C1 evaluated True, producing an overall True result. The hyphen (`-`) indicates C2 was short-circuited and not evaluated.
+* **Condition Pairs:**
+  * **`C1-Pair: covered (1, 2)`:** Comparing Vector 1 and Vector 2 proves that changing C1 from False to True directly flipped the result from False to True. C1 is fully covered.
+  * **`C2-Pair: not covered`:** C2 was never tested in a state where it independently turned the result True while C1 was False.
+* **Reaching 100% Coverage:**
+  Add a test with a value above 255 (`c = 256`). This executes Vector 3 (`F, T = T`), forming the independence pair `(1, 3)` for C2 and reaching 100% MC/DC coverage.

>From 552d11e9de3f5128a2211a58150087c6149c79c4 Mon Sep 17 00:00:00 2001
From: Tapiwa Gonga <tapiwagonga at google.com>
Date: Wed, 26 Aug 2026 12:49:56 +0000
Subject: [PATCH 4/6] [libc][docs] Simplify single-test coverage wording in
 developer guide

---
 libc/docs/dev/code_coverage.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libc/docs/dev/code_coverage.md b/libc/docs/dev/code_coverage.md
index 6823170539d42..3c9d063bca955 100644
--- a/libc/docs/dev/code_coverage.md
+++ b/libc/docs/dev/code_coverage.md
@@ -202,7 +202,7 @@ xdg-open coverage_mcdc_html/index.html
 
 ## Running Coverage for a Single Test
 
-When developing or modifying a specific function, running coverage on a single unit test allows rapid iteration (~2 seconds) without compiling and running the entire library suite.
+When developing or modifying a specific function, coverage can be collected for a single test without building and executing the entire test suite.
 
 The commands below use `libc.test.src.ctype.isalpha_test` (which tests `libc/src/ctype/isalpha.cpp`) as an example. You can test any other entrypoint by substituting the target name and source file path:
 * **Target pattern:** `libc.test.<path_to_test>.<test_name>` (e.g. `libc.test.src.string.strlen_test`)
@@ -210,7 +210,7 @@ The commands below use `libc.test.src.ctype.isalpha_test` (which tests `libc/src
 
 ### 1. Build and Execute the Targeted Test
 
-Compiles and runs only the specified unit test binary, immediately dumping execution profile counters for fast feedback (~2 seconds):
+Compiles and runs only the specified test binary, immediately writing execution profile counters to disk upon completion:
 
 ```bash
 # For a standard coverage build

>From 352b7db65bf188a5f7fac8f00b03a3c82cfd3d96 Mon Sep 17 00:00:00 2001
From: Tapiwa Gonga <tapiwagonga at google.com>
Date: Wed, 26 Aug 2026 12:58:04 +0000
Subject: [PATCH 5/6] [libc][docs] Update code coverage developer guide with
 step-by-step instructions and MC/DC truth table analysis

---
 libc/docs/dev/code_coverage.md | 22 ++++++++++++++--------
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/libc/docs/dev/code_coverage.md b/libc/docs/dev/code_coverage.md
index 3c9d063bca955..409efaa8a4df6 100644
--- a/libc/docs/dev/code_coverage.md
+++ b/libc/docs/dev/code_coverage.md
@@ -88,7 +88,9 @@ for bin in "${TEST_BINS[@]:1}"; do
 done
 ```
 
-#### Terminal Summary Table
+Reports can be generated in different formats:
+
+#### Option 1: Terminal Summary Report
 Prints an aggregated terminal summary showing line, region, and branch coverage percentages for each file:
 
 ```bash
@@ -99,7 +101,7 @@ llvm-cov report \
   -ignore-filename-regex=".*(test|utils).*"
 ```
 
-#### Interactive HTML Dashboard
+#### Option 2: Interactive HTML Dashboard
 Generates an interactive HTML dashboard containing sortable directory metrics and syntax-highlighted source views:
 
 ```bash
@@ -167,7 +169,9 @@ for bin in "${TEST_BINS[@]:1}"; do
 done
 ```
 
-#### Terminal Summary Table
+Reports can be generated in two formats depending on your needs:
+
+#### Option 1: Terminal Summary Report
 Displays the terminal coverage summary including MC/DC Condition and Missed Condition percentages:
 
 ```bash
@@ -179,7 +183,7 @@ llvm-cov report \
   -ignore-filename-regex=".*(test|utils).*"
 ```
 
-#### Interactive HTML Dashboard
+#### Option 2: Interactive HTML Dashboard
 Produces an HTML report with expandable MC/DC decision truth tables and test vector coverage breakdowns:
 
 ```bash
@@ -231,16 +235,18 @@ llvm-profdata merge -sparse -f profraw_list.txt -o libc_single.profdata
 
 ### 3. View the Terminal Report
 
-Renders the coverage metrics or line-by-line truth table for the specific source file being tested:
+Reports can be viewed as an overall file summary or an annotated line-by-line breakdown:
 
+#### Option 1: Summary Table Report
 ```bash
-# Standard summary report
 llvm-cov report \
   -instr-profile=libc_single.profdata \
   ./build-cov/libc/test/src/ctype/libc.test.src.ctype.isalpha_test.__build__ \
   libc/src/ctype/isalpha.cpp
+```
 
-# Line-by-line coverage and truth table inspection
+#### Option 2: Line-by-Line & Truth Table View
+```bash
 llvm-cov show \
   -instr-profile=libc_single.profdata \
   ./build-cov-mcdc/libc/test/src/ctype/libc.test.src.ctype.isalpha_test.__build__ \
@@ -262,7 +268,7 @@ llvm-cov show \
 * **MC/DC Coverage:**  
   Evaluates compound boolean expressions (such as `if (A && B)` or `if (A || B)`). It verifies that each individual condition was tested as both True and False, and demonstrated that it could independently change the overall outcome of the decision.
 
-### Interpreting Summary Reports (`llvm-cov report`)
+### Interpreting Reports 
 
 The summary table produced by `llvm-cov report` displays metrics across individual source files and overall totals:
 

>From c8e6e23fb75ad079e7780a663ecc9c57b88ef3e6 Mon Sep 17 00:00:00 2001
From: Tapiwa Gonga <tapiwagonga at google.com>
Date: Thu, 27 Aug 2026 10:59:44 +0000
Subject: [PATCH 6/6] docs(libc): add link to official Clang coverage
 documentation

---
 libc/docs/dev/code_coverage.md | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libc/docs/dev/code_coverage.md b/libc/docs/dev/code_coverage.md
index 409efaa8a4df6..e9e1655ae7a9b 100644
--- a/libc/docs/dev/code_coverage.md
+++ b/libc/docs/dev/code_coverage.md
@@ -259,6 +259,8 @@ llvm-cov show \
 
 ## Interpreting Results
 
+For detailed documentation on the LLVM coverage reporting format, refer to the [official Clang Source-Based Code Coverage documentation](https://clang.llvm.org/docs/SourceBasedCodeCoverage.html#interpreting-reports).
+
 ### Coverage Metrics Overview
 
 * **Line Coverage:**  



More information about the libc-commits mailing list