Skip to content

perf(codegen): retain guarded array accumulators as i32 - #8613

Merged
proggeramlug merged 2 commits into
PerryTS:mainfrom
proggeramlug:perf/8606-typed-array-round2
Aug 22, 2026
Merged

perf(codegen): retain guarded array accumulators as i32#8613
proggeramlug merged 2 commits into
PerryTS:mainfrom
proggeramlug:perf/8606-typed-array-round2

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Summary

  • propagate runtime-backed number[] parameter proofs into native-region fact collection
  • retain guarded-array Feistel accumulators in canonical i32 slots after a conservative root-level normalization proof
  • keep nested bitwise operands native across mutable numeric locals and bounds-proven typed-array reads
  • preserve the generic fallback when the entry guard or dominance proof is absent

typed_array result

Exact issue workload, three-run medians on this host:

metric issue baseline this PR change
retired instructions 14.68B 9.66B -34.2%
cycles 8.10B 5.96B -26.5%
user CPU 2.73s 2.01s -26.4%

The specialized encipherUntyped function contains zero js_number_coerce calls after this change. Output remains checksum:-821955270.

Validation

  • cargo test -p perry-codegen --lib (1,163 passed, 1 ignored)
  • cargo test --release -p perry-codegen --lib (1,163 passed, 1 ignored)
  • cargo clippy -p perry --bins
  • cargo check -p perry
  • release build of perry, perry-runtime-static, and perry-stdlib-static
  • exact workload checksum, symbol inspection, and three-run hardware-counter comparison

No version bump.

Fixes #8606

Summary by CodeRabbit

  • Performance Improvements
    • Improved numeric-array and typed-array processing for bitwise operations.
    • Reduced unnecessary numeric conversions in optimized execution paths.
    • Preserved integer representations more effectively for faster calculations.
    • Maintained existing results, including checksum consistency.
  • Bug Fixes
    • Improved handling of nested bitwise operations, conditional paths, and out-of-bounds array reads.
    • Ensured numeric-array optimizations apply only when type and normalization guarantees are valid.
  • Tests
    • Added coverage for guarded numeric arrays, normalization order, and unreachable execution paths.

@coderabbitai

coderabbitai Bot commented Aug 22, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b7721a4f-20db-45de-b694-e1fecefcae9d

📥 Commits

Reviewing files that changed from the base of the PR and between 5f2c6c6 and 659d6ee.

📒 Files selected for processing (7)
  • changelog.d/8613-guarded-array-i32.md
  • crates/perry-codegen/src/codegen/function.rs
  • crates/perry-codegen/src/codegen/ordinary_param_guard_tests.rs
  • crates/perry-codegen/src/collectors/hir_facts.rs
  • crates/perry-codegen/src/collectors/int_valued_ta_locals.rs
  • crates/perry-codegen/src/collectors/int_valued_ta_locals/tests.rs
  • crates/perry-codegen/src/expr/mod.rs

Included review availability: Your plan provides up to 8 included reviews per hour; 5 remain after this review.


📝 Walkthrough

Walkthrough

The change propagates numeric-array parameter proofs into native fact collection. Guarded numeric-array reads can seed exact i32 analysis after valid root-level normalization. Bitwise lowering consumes the proof, and tests verify canonical i32 representation without js_number_coerce.

Changes

Guarded numeric-array i32 optimization

Layer / File(s) Summary
Numeric-array specialization wiring
crates/perry-codegen/src/codegen/function.rs, crates/perry-codegen/src/collectors/hir_facts.rs
Specialized parameters with Number or Int32 array elements are collected and passed through native fact-graph construction.
Guarded-array fact and observation analysis
crates/perry-codegen/src/collectors/int_valued_ta_locals.rs, crates/perry-codegen/src/collectors/int_valued_ta_locals/tests.rs
The collector recognizes guarded numeric-array reads, preserves OOB undefined behavior, tracks exact i32 normalization, and validates control-flow cases with tests.
Bitwise lowering and specialization validation
crates/perry-codegen/src/expr/mod.rs, crates/perry-codegen/src/codegen/ordinary_param_guard_tests.rs, changelog.d/8613-guarded-array-i32.md
Bitwise operands use region-proven i32 values or finite-aware ToInt32 conversion. The code-generation test checks that the specialized clone has no js_number_coerce calls. The changelog records measured performance results.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: ⚪ Minimal · up to 659d6

This change specializes guarded numeric array code generation to retain i32 values and reports substantial benchmark improvements while preserving the generic fallback; no actionable merge-blocking risk remains after normal checks and review.

Sequence Diagram(s)

sequenceDiagram
  participant FunctionSpecialization
  participant NativeFactGraph
  participant I32LocalCollector
  participant BitwiseLowering
  FunctionSpecialization->>NativeFactGraph: pass numeric-array parameter proofs
  NativeFactGraph->>I32LocalCollector: pass guarded numeric-array IDs
  I32LocalCollector->>I32LocalCollector: classify reads and root-level exact normalization
  I32LocalCollector->>BitwiseLowering: provide region-proven i32 expressions
  BitwiseLowering->>BitwiseLowering: lower bitwise operands without js_number_coerce
Loading

Suggested reviewers: jdalton

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 68.57% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 35 functions across 6 files. (1 skipped: 1 unsupported.) Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the primary codegen optimization: retaining guarded array accumulators as i32.
Description check ✅ Passed The description explains the changes, links issue #8606, reports performance results, and lists validation commands.
Linked Issues check ✅ Passed The changes address #8606 by optimizing the typed_array path, preserving the required checksum, and reducing retired instructions and execution time.
Out of Scope Changes check ✅ Passed The code, tests, and changelog entry are directly related to the guarded-array codegen optimization and its typed_array performance target.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@proggeramlug

Copy link
Copy Markdown
Contributor Author

Merging as a validated batch of three, stacked on current main.

check result
cargo check --workspace --all-targets exit 0
perry-codegen --lib 1167 passed, 1 ignored
perry-runtime --lib (RUST_TEST_THREADS=1) 2634 passed, 4 ignored
all seven ratchets 0
cargo fmt --all -- --check 0

Ratchets re-run against the current baseline immediately before merge.

#8610's ratchet debt is resolved. It was held twice for +2 bare raw-handle reads in class_registry/construct.rs (7 against a ceiling of 5) and +1 open-coded StringHeader payload offset. On head c9b994d0f both gates now report clean — 925/925 raw-handle reads, 108 modules within ceilings, payload inventory exit 0. Converted rather than baseline-refreshed, which was the right call given the counts had gone up. Thanks for taking that rather than reaching for --write-baseline; construct.rs runs during instance construction, so a raw handle held across an allocating call there is exactly the shape that yields a stale pointer surfacing cycles later somewhere unrelated.

#8613 and #8614 are aimed at the two tickets filed after the last sweep#8606 (typed_array round 2, where the wall ratio now exceeds the instruction ratio) and #8607 (pipeline, still 1.74x instructions at ~1.05x cycles). Worth being explicit about what this validation does and does not establish: the gates and suites say these are safe to land, not that they are faster. Both are perf changes, and the corpus sweep after merging is the actual verdict. I will run it and report against those tickets.

Two metadata fixes applied while staging (fork PRs, so they could not be pushed to the branches): #8610 shipped without a changelog.d fragment, so I wrote one; #8614's was keyed 8607- after its issue and is now PR-keyed.

@proggeramlug
proggeramlug merged commit 0c04218 into PerryTS:main Aug 22, 2026
44 of 48 checks passed
@proggeramlug
proggeramlug deleted the perf/8606-typed-array-round2 branch August 22, 2026 17:17
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.

Opt target — typed_array round 2: 3.87x Node, 2.24x instructions

1 participant