feat(optimizer): fold array length and indexing on literal arrays (#225) - #292
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #225.
A pattern match on a fixed-length array whose scrutinee is a manifest array literal is decidable at compile time, but the optimizer left it as a runtime length check plus element reads. This PR adds the three transformations the issue proposes, and the existing folds finish the job.
The rules
reduceArrayRead— thereduceObjectPropsibling for arrays: foldsarrayLengthover an in-placeLiteralArrayto its element count, and an in-rangeArrayIndexto the element itself. The issue's piece (2) turned out simpler than proposed: the IR'sArrayIndexalready carries a staticNaturalindex, so no literal-index matching is needed. The length folds against the IR element count, which is exact — aLiteralArraycodegens to a hole-free positional table — so the caveat about Lua's#over tables with holes never arises:propagateKnownArrayThroughLet— the literal-array sibling ofpropagateKnownCtorThroughLet(#214). The match's scrutinee is let-bound and read several times (one length check plus one read per element), so it is never in place forreduceArrayReadto see. When the binder is read only through in-range array reads, each length read becomes the element count, each element read becomes a fresh element-binder bound once to the element (the field-binder discipline of #214, so an element read at several sites is never duplicated), and the binding is dropped. The rule declines on a whole-value read or an out-of-range index —Query.hasWholeValueArrayReadmirrorshasWholeValueReadincluding the out-of-range-counts-as-whole-value guard.End to end
The motivating shape from the issue, in the
Golden.ArrayPatternMatchgolden — before:after:
Every literal-array call site in that golden folds to its constant (
30,-1,-1,9); theeval/golden.txtoracle is untouched and still passes. The survivingM.Golden_ArrayPatternMatch_Test_firstTwo = …entries in the newgolden.luaare the harness shape, not a leak: the golden pipeline linksAsModule, so the now-uncalled helpers stay reachable as exports — the same residue every other golden with exported-but-unused-by-mainhelpers shows.Tests
Test-first, per the issue: the unit specs were red before the rules landed. The in-place folds and their decline cases (out-of-range index, unknown-length array) are pinned at
optimizedExpressionlevel; the no-duplication discipline is pinned by analphaEqcheck that a twice-read non-trivial element becomes one binder read twice. The full collapse runs throughoptimizedUberModuleChecked(mirroring the #214 end-to-end test), because the rewrite chain deliberately leaves the spent element-binders for DCE — that run also lints every pass boundary, so a GUC or scoping violation from folding through the Let would fail there. Two properties: the collapse across generated scalar elements, and well-scopedness when the index is fuzzed out of range:cabal test allis green, and the randomized specs were stressed across several seeds.