perf(codegen): inline the slot load for guarded numeric array index reads#5132
perf(codegen): inline the slot load for guarded numeric array index reads#5132TheHypnoo wants to merge 7 commits into
Conversation
…eads A numeric `arr[i]` read is lowered as a typed-feedback guard followed, on the fast path, by a call to `js_array_numeric_get_f64_unboxed`. But the `numeric_array_index_get_guard` on the way into the fast block already proves everything that helper re-checks: a plain non-forwarded `Array`, in raw-f64 numeric layout, with `index` in bounds (`plain_array_index_guard(.., in_bounds =true)` && `js_array_is_numeric_f64_layout`). So the helper's hot path just does `return *elements_ptr.add(index)` after re-validating — a redundant call per read. Emit that slot load inline (`getelementptr` + `load double` at `arr + 8 + index*8`) instead, matching the helper exactly. Raw-f64 arrays are dense (no HOLE slots) and hold raw f64s, so no hole→undefined translation is needed; the non-raw path already inlines (with the hole check) and is unchanged. Out-of- bounds / negative / non-number indices fail the guard and route to the boxed fallback exactly as before. 04_array_read: 149ms -> 91ms (~1.6x). numeric_array_numeric is read+write so it is now write-bound (neutral). Part of closing the AOT array-element-access gap (see #5094). Verified: 29/29 suite benchmarks match Node; OOB/negative/hole reads on numeric arrays return undefined identical to Node; codegen tests pass (the hot-path test now asserts the inline load instead of the unboxed-get call).
|
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 (1)
📝 WalkthroughWalkthroughIn ChangesInline numeric array element load
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
…ne GET The inline numeric array read no longer emits a call to js_array_numeric_get_f64_unboxed; the slot is loaded inline after the guard. Update the native-region-proof IR check to assert the guard (js_typed_feedback_numeric_array_index_get_guard) is present and that the helper call is elided, instead of requiring the now-removed call. The native-rep structural record still tags the logical consumer, so numeric_array_get_fast_f64 continues to prove the checked_native fast path.
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 `@benchmarks/compiler_output/workloads.toml`:
- Around line 627-630: The workload check for numeric_array_uses_unboxed_get at
lines 627-630 only verifies the presence of the guard and absence of the helper
function call, but does not assert that the expected direct inline-load
instruction is actually present in the IR output. Add a regex_contains or
contains check to verify the presence of the direct load instruction (such as
"load double") to strengthen the test and ensure it validates the complete
inline-load fast path optimization, preventing regressions where the helper
removal occurs without the expected inline load taking place.
🪄 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: 24f156c4-8dd6-479e-b179-ce281344a06d
📒 Files selected for processing (1)
benchmarks/compiler_output/workloads.toml
…path Per CodeRabbit: prove the optimization contract positively, not just by helper removal. Add a regex asserting the guarded fast block (bidx.num.fast) computes the element pointer via inttoptr and performs an inline 'load double' before branching to the merge block. Keeps the guard presence + helper-call-absence checks. Validated against the optimized llvm_after IR the harness gates on.
test_generic_native_rep_checks_require_configured_records fed synthetic IR with the old 'call double @js_array_numeric_get_f64_unboxed' shape, which no longer matches the updated numeric_array_uses_unboxed_get check (guard present + inline inttoptr/load double in bidx.num.fast + helper call elided). Update the fixture IR to the inlined fast-path shape; push/set still exercise their guarded raw-f64 helpers. Native-rep records keep the logical get consumer tag, so the structural checks are unchanged.
What
For a numeric (
raw-f64) array readarr[i]that already passes thenumeric_array_index_get_guard, emit the slot load inline instead ofcalling the runtime helper
js_array_numeric_get_f64_unboxed.Why it's safe
The guard on the way into the fast block already proves everything the helper
re-checks:
Array(plain_array_index_guard),js_array_is_numeric_f64_layout),indexin bounds (plain_array_index_guard(.., in_bounds=true)).Raw-f64 arrays are dense (no
HOLEslots) and each slot holds a rawf64, sothe helper's hot path reduces to
return *elements_ptr.add(index). We emitexactly that:
load doubleatarr + 8 + i*8(ArrayHeader:length@0,capacity@4,elements@8). The non-numericelsebranch already addressedelements the same way.
Impact
array_readmicro-benchmark: 149ms → 91ms (~1.6×) by removing theper-element call + redundant re-validation.
Validation
undefined, negative index→
undefined.tests/typed_feedback.rsto assert the IR no longer containscall double @js_array_numeric_get_f64_unboxedand now containsload double.gap/issue/parity-module baseline (none array-indexing related). Zero new
regressions.
Summary by CodeRabbit
Performance
doubleelement load in the guarded typed-feedback path.Tests
doubleloads are generated.