Skip to content

Teach kmir to reduce SMIR K definitions over a set of CFG roots#845

Open
sskeirik wants to merge 6 commits intomasterfrom
srs/multiple_roots_closure
Open

Teach kmir to reduce SMIR K definitions over a set of CFG roots#845
sskeirik wants to merge 6 commits intomasterfrom
srs/multiple_roots_closure

Conversation

@sskeirik
Copy link
Copy Markdown
Collaborator

No description provided.

@sskeirik sskeirik requested a review from jberthold November 14, 2025 02:35
@sskeirik sskeirik marked this pull request as draft November 14, 2025 02:36
Stevengre and others added 3 commits March 23, 2026 01:05
Resolve conflicts in __main__.py, kmir.py, and options.py by keeping both
the PR's cfg_roots feature and master's refactored prove pipeline (with
_prove.py, add_module, max_workers, break_on_function support).

- __main__.py: add --cfg-roots alongside master's --add-module and --max-workers args
- kmir.py: keep master's delegated prove_program (via _prove.py)
- options.py: add cfg_roots field to master's unified ProveOpts class
- _prove.py: use cfg_roots for reduce_to when available

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
After merging origin/master, fix the cfg_roots feature so that
start_symbol is dynamically combined at usage time rather than
baked into cfg_roots during __init__. This prevents stale roots
when start_symbol is reassigned after construction (e.g. in tests
with multiple start symbols per file).

Also adapts compute_closure call sites to the new Sequence[Ty]
signature and fixes minor style issues (quote style, black formatting).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add INFO-level logging in _prove.py showing before/after symbol table
reduction stats (original items, reduced items, pruning percentage,
root count, elapsed time) to make the cfg_roots feature observable.

Add test_cfg_roots_prove_pipeline integration test that proves with
a single root vs multiple roots using arith.smir.json (where add and
mul are independent leaf functions), verifying that multi-root reduces
to strictly more items than single-root.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Stevengre
Copy link
Copy Markdown
Contributor

cfg_roots Testing Report

Merged origin/master and tested the --cfg-roots feature end-to-end. Added reduction stats logging and integration tests. Here are the findings:

Bug Fix

Found and fixed a bug where cfg_roots list was baked with start_symbol during ProveOpts.__init__, causing stale roots when start_symbol was reassigned after construction (e.g., in tests with multiple start symbols per file). Fix: start_symbol is now dynamically combined at usage time in _prove.py.

New: Reduction Stats Logging

Added INFO-level logging showing before/after symbol table reduction:

INFO - Symbol table reduction: 922 -> 128 items (794 pruned, 86.1%), 1 root(s), 44.6ms

Integration Test

Added test_cfg_roots_prove_pipeline using arith.smir.json (11 items, add and mul are independent leaf functions):

  • Single root add: 11 → 1 item
  • Multi root [add, mul]: 11 → 2 items
  • Verifies that multi-root strictly expands the retained function set

Real-World Demo: solana-token test_process_approve

Tested with p-token.smir.json (922 items, 911 functions, 8 linked crates):

Scenario Items After Reduction Pruned Pruning % Kompile Time Total Time
Single root (test_process_approve) 128 794 86.1% ~30s 1m40s
All 32 test roots 548 374 40.6% ~70s 3m45s

Key observation: Using all 32 test roots retains 4.3x more items (548 vs 128), which increases kompile time by ~2.3x. The function equations count (3132) stays the same because reduce_to only filters items, not types or allocs.

Recommendation: --cfg-roots should be used selectively — only include roots that share dependencies with the start symbol, rather than all test entry points. The feature is most valuable for cases where the call graph analysis misses indirect references needed by the proof.

Tests Passing

  • make check
  • make test-unit (38 tests) ✅
  • test_cfg_roots_prove_pipeline
  • kmir prove with/without --cfg-roots

@Stevengre Stevengre marked this pull request as ready for review March 26, 2026 03:24
@Stevengre Stevengre self-assigned this Mar 26, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4bdb7ea9ea

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Copy Markdown
Member

@jberthold jberthold left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Codex review raises a valid point - the given option might be ignored if it is passed to a prove command and continues a proof.
Maybe the code can still be merged but as a stand-alone tool like the kmir link command? That decouples it from proving where artefacts are saved and reloaded.

Address reviewer feedback (jberthold): decouple SMIR reduction from
`prove` into a standalone CLI command, following the `kmir link` pattern.

- Add `kmir reduce` command: takes SMIR JSON + roots → outputs reduced
  SMIR JSON. Supports comma-separated roots or @file syntax.
- Add `ReduceOpts` dataclass in options.py
- Remove `--cfg-roots` from `prove`/`prove-rs` to avoid proof cache
  invalidation issues (proof identity doesn't include cfg_roots)
- Keep reduction stats logging in _prove.py for start_symbol reduction
- Update integration test to verify standalone reduce behavior

Intended workflow:
  kmir link *.smir.json -o linked.smir.json
  kmir reduce linked.smir.json -r root1,root2 -o reduced.smir.json
  kmir prove-rs --smir reduced.smir.json --start-symbol root1

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Stevengre
Copy link
Copy Markdown
Contributor

Addressing reviewer feedback

@jberthold Good suggestion — I've refactored --cfg-roots out of prove into a standalone kmir reduce command (commit f077d618), following the kmir link pattern. This also addresses the Codex review point about proof cache invalidation.

New kmir reduce command

# Comma-separated roots
kmir reduce linked.smir.json --roots fn1,fn2,fn3 -o reduced.smir.json

# Or read roots from a file
kmir reduce linked.smir.json --roots @roots.txt -o reduced.smir.json

Intended workflow

kmir link *.smir.json -o linked.smir.json          # merge crates
kmir reduce linked.smir.json -r root1,root2 -o reduced.smir.json  # prune
kmir prove-rs --smir reduced.smir.json --start-symbol root1       # prove

What changed

  • Added kmir reduce CLI command with ReduceOpts dataclass
  • Removed --cfg-roots from prove/prove-rs (avoids proof identity mismatch)
  • prove still does reduce_to(start_symbol) internally with stats logging
  • Integration test verifies standalone reduce behavior (single vs multi-root)

Copy link
Copy Markdown
Member

@jberthold jberthold left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM now (with a minor comment), thanks

Comment on lines +78 to +88
original_items = len(smir_info.items)
t0 = time.monotonic()
smir_info = smir_info.reduce_to(opts.start_symbol)
reduction_ms = (time.monotonic() - t0) * 1000
reduced_items = len(smir_info.items)
pruned = original_items - reduced_items
pct = (pruned / original_items * 100) if original_items > 0 else 0
_LOGGER.info(
f'Symbol table reduction: {original_items} -> {reduced_items} items'
f' ({pruned} pruned, {pct:.1f}%), {reduction_ms:.1f}ms'
)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe not necessary? (minor)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants