perf(codegen): keep Math.*-result arithmetic on the inline fmul fast path (#6511)#6525
Conversation
…path (PerryTS#6511) Between 0.5.1220 and 0.5.1260, a multiply whose operands are Math.* results (e.g. `Math.sqrt(i) * Math.sin(i * 0.001)`) lost its inline `fmul` and started routing through the BigInt-aware dynamic helper — two non-leaf ToNumeric calls per iteration, ~1.45x wall-clock on the issue's mixed-transcendental kernel. Root cause: the PerryTS#5970 correctness routing sends every mul/div/mod/sub/ pow/bitwise op through `js_dynamic_<op>` when an operand is not statically numeric, and `is_numeric_expr` had no arms for the dedicated Math.* HIR nodes, so every Math.* call result failed the test. All Math.* lowerings coerce their operands internally (`js_math_to_number`: BigInt/Symbol throw) and emit a raw-f64-returning intrinsic or runtime helper, so their results can never be a boxed BigInt — recognize all of them as statically numeric. Repro A/B (arm64, same runtime archives, alternating runs, min of 6, chk identical to node): 43 ms before, 14 ms after — the fast path now skips the two `js_number_coerce` leaf calls 0.5.1220 still made, so this lands faster than the original baseline too. Verification: new native-proof IR tests pin the routing (inline fmul, no js_dynamic_mul / js_number_coerce for Math-result multiplies; an Any-typed operand still takes the BigInt-aware helper), the full native_proof_regressions suite (242) and perry-codegen unit tests (188) pass, and the bigint/math gap tests (the PerryTS#5970 surfaces) are byte-identical to node. Fixes PerryTS#6511 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthrough
ChangesMath numeric fast paths
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@crates/perry-codegen/tests/native_proof_regressions/math_mul_fastpath.rs`:
- Around line 45-66: Add equivalent coverage for the Math.sqrt/Math.sin multiply
lowering behavior to cargo-test-visible unit tests under the perry-codegen
source, reusing the existing IR-generation helpers where available. Preserve
assertions for sqrt and sin intrinsics, inline fmul emission, and absence of
js_dynamic_mul and js_number_coerce; keep the existing integration regression
test unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: d261dd9e-7bf4-4f0c-bfc7-cdd9cc9bf105
📒 Files selected for processing (3)
crates/perry-codegen/src/type_analysis/numeric.rscrates/perry-codegen/tests/native_proof_regressions.rscrates/perry-codegen/tests/native_proof_regressions/math_mul_fastpath.rs
…th routing CodeRabbit review: integration suites under crates/*/tests/*.rs only run on nightly/tag workflows, so mirror the PerryTS#6511 routing assertions (inline fmul + intrinsics, no js_dynamic_mul/js_number_coerce; Any operand keeps the PerryTS#5970 dynamic-helper routing) as --lib unit tests under type_analysis/numeric/ where every per-PR cargo-test sees them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
crates/perry-codegen/src/type_analysis/numeric/tests.rs (1)
141-142: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winRemove the unrelated multiplication from this
fmulassertion.Line 168 already generates
fmulfori * 0.001, so the positive assertion can pass without proving that the outerMath.sqrt(...) * Math.sin(...)was lowered inline. GiveMathSina non-multiplication operand so the onlyfmulrepresents the route under test.Proposed test adjustment
- // The `#6511` repro shape: `for (i = 0; i < 64; i++) acc += Math.sqrt(i) - // * Math.sin(i * 0.001);` + // Isolate multiplication between two Math.* results so any emitted + // `fmul` necessarily represents the routing under test. ... - Expr::MathSin(Box::new(mul(Expr::LocalGet(2), Expr::Number(0.001)))), + Expr::MathSin(Box::new(Expr::Number(0.001))),Also applies to: 168-168, 180-183
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/perry-codegen/src/type_analysis/numeric/tests.rs` around lines 141 - 142, Update the numeric test around MathSin and its fmul assertions so MathSin receives a non-multiplication operand, removing the unrelated outer Math.sqrt(...) * Math.sin(...) multiplication. Ensure the remaining fmul is produced only by the route under test, while preserving the existing positive and negative assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@crates/perry-codegen/src/type_analysis/numeric/tests.rs`:
- Around line 141-142: Update the numeric test around MathSin and its fmul
assertions so MathSin receives a non-multiplication operand, removing the
unrelated outer Math.sqrt(...) * Math.sin(...) multiplication. Ensure the
remaining fmul is produced only by the route under test, while preserving the
existing positive and negative assertions.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 222bc2c1-b665-439c-9158-dcf36d2215cc
📒 Files selected for processing (2)
crates/perry-codegen/src/type_analysis/numeric.rscrates/perry-codegen/src/type_analysis/numeric/tests.rs
🚧 Files skipped from review as they are similar to previous changes (1)
- crates/perry-codegen/src/type_analysis/numeric.rs
CodeRabbit re-review: the MathSin operand's `i * 0.001` emitted its own fmul, so the positive `fmul double` assertion could pass without the outer Math.sqrt(i) * Math.sin(...) being inline. Use a call-free `Math.sin(i)` operand in both test twins so the only fmul in the probe is the multiply under test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Nitpick addressed in the latest commit: the |
Fixes #6511.
Root cause
The #5970 BigInt-correctness routing (632e68e) sends
mul/div/mod/sub/powand the bitwise ops through theToNumeric-running dynamic helper whenever an operand is not statically numeric — andis_numeric_exprhad no arms for the dedicatedMath.*HIR nodes (MathSqrt,MathSin, …). EveryMath.*call result failed the "statically numeric" test, soMath.sqrt(i) * Math.sin(i * 0.001)lost its inlinefmuland paid two non-leaf re-coercion calls per iteration (~1.45x on the issue's kernel).Fix
Recognize all
Math.*expression nodes as statically numeric. Every one of their lowerings coerces its operands internally (js_math_to_number— BigInt and Symbol throw per spec) and emits a raw-f64-returning LLVM intrinsic or runtime helper, never a NaN-tagged value, so aMath.*result can never be the boxed BigInt the #5970 routing exists to catch. The routing itself is untouched: a possibly-object operand still takes the dynamic helper (pinned by a new negative-control test).Measurements
Issue repro, arm64, identical runtime archives, alternating runs, min of 6, checksum identical to node (
chk=1710):Faster than the original 0.5.1220 baseline too — the restored fast path no longer emits the two
js_number_coerceleaf calls 0.5.1220 still made, and node runs the same file in 24 ms on this machine.Verification
native_proof_regressions/math_mul_fastpath.rs: the issue's accumulator-loop shape emits inlinefmul+llvm.sqrt.f64/llvm.sin.f64with nojs_dynamic_mul/js_number_coercecalls; div/sub stay inline; anAny-typed operand still routes throughjs_dynamic_mul(fix(runtime,codegen): #5894 — ToNumeric on object operands for BigInt arithmetic/bitwise ops #5970 semantics preserved).native_proof_regressionssuite: 242 passed.perry-codegenunit tests: 188 passed.test_gap_bigint*,test_gap_number_math,test_gap_2754_2907_2908_bigint_semantics,test_gap_6339_i32_arith_chain_copy,test_gap_number_nondecimal_overflow,test_gap_number_string_2864_2948_2855): byte-identical to node.No version bump / changelog per the external-contribution convention (maintainer folds metadata at merge).
Note: the required
lintjob is currently red on every open PR from a main-side issue — the "Public benchmark evidence freshness" step fails withpublic artifact benchmark inputs changed; regenerate it with ./benchmarks/run_public_baseline.sh(see #6509/#6510/#6512/#6514). Additionally, once that step is fixed, the file-size gate behind it will flagcrates/perry-hir/src/lower/widget_decl.rs(2372 > 2000 lines, grew in #6513). Neither is caused by this diff.🤖 Generated with Claude Code
Summary by CodeRabbit
Bug Fixes
Math.*expressions so arithmetic using their results preferentially uses optimized numeric operations when safe.Any/object-like, keeping BigInt-aware lowering as needed.Tests
Math.*multiply/divide/subtract routing and intrinsic usage, including cases that must avoid or allow dynamic helpers.