redscript-mc 2.6.2 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +11 -0
- package/CHANGELOG.md +18 -9
- package/README-benchmarks.md +48 -0
- package/README-vscode-test.md +251 -0
- package/RELEASE_NOTES.md +74 -0
- package/ROADMAP.md +131 -167
- package/benchmarks/_shared.ts +468 -0
- package/benchmarks/baseline.json +2816 -0
- package/benchmarks/baseline.md +13 -0
- package/benchmarks/compiler-perf.report.json +207 -0
- package/benchmarks/compiler-perf.ts +76 -0
- package/benchmarks/results.md +13 -0
- package/benchmarks/stdlib-complexity.report.json +2606 -0
- package/benchmarks/stdlib-complexity.ts +54 -0
- package/benchmarks/stdlib-size.md +57 -0
- package/benchmarks/stdlib-size.ts +91 -0
- package/coverage-report.md +177 -0
- package/dist/src/__tests__/budget.test.js +4 -0
- package/dist/src/__tests__/cache/cache-behavior.test.d.ts +10 -0
- package/dist/src/__tests__/cache/cache-behavior.test.js +425 -0
- package/dist/src/__tests__/cache-extra.test.d.ts +5 -0
- package/dist/src/__tests__/cache-extra.test.js +211 -0
- package/dist/src/__tests__/cli-init.test.d.ts +1 -0
- package/dist/src/__tests__/cli-init.test.js +97 -0
- package/dist/src/__tests__/cli-publish.test.d.ts +9 -0
- package/dist/src/__tests__/cli-publish.test.js +189 -0
- package/dist/src/__tests__/cli.test.js +76 -0
- package/dist/src/__tests__/compile-preprocess.test.d.ts +11 -0
- package/dist/src/__tests__/compile-preprocess.test.js +328 -0
- package/dist/src/__tests__/compiler/break-stmt.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/break-stmt.test.js +58 -0
- package/dist/src/__tests__/compiler/const-decl.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/const-decl.test.js +123 -0
- package/dist/src/__tests__/compiler/continue-stmt.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/continue-stmt.test.js +67 -0
- package/dist/src/__tests__/compiler/coroutine-extended.test.d.ts +17 -0
- package/dist/src/__tests__/compiler/coroutine-extended.test.js +565 -0
- package/dist/src/__tests__/compiler/deprecated.test.d.ts +4 -0
- package/dist/src/__tests__/compiler/deprecated.test.js +285 -0
- package/dist/src/__tests__/compiler/do-while.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/do-while.test.js +120 -0
- package/dist/src/__tests__/compiler/enum-payload.test.d.ts +9 -0
- package/dist/src/__tests__/compiler/enum-payload.test.js +272 -0
- package/dist/src/__tests__/compiler/interface.test.d.ts +10 -0
- package/dist/src/__tests__/compiler/interface.test.js +258 -0
- package/dist/src/__tests__/compiler/labeled-loops.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/labeled-loops.test.js +263 -0
- package/dist/src/__tests__/compiler/match-string.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/match-string.test.js +43 -0
- package/dist/src/__tests__/compiler/memoize.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/memoize.test.js +113 -0
- package/dist/src/__tests__/compiler/method-chain.test.d.ts +5 -0
- package/dist/src/__tests__/compiler/method-chain.test.js +115 -0
- package/dist/src/__tests__/compiler/module-import.test.d.ts +12 -0
- package/dist/src/__tests__/compiler/module-import.test.js +261 -0
- package/dist/src/__tests__/compiler/option-extensions.test.d.ts +6 -0
- package/dist/src/__tests__/compiler/option-extensions.test.js +191 -0
- package/dist/src/__tests__/compiler/profile-decorator.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/profile-decorator.test.js +69 -0
- package/dist/src/__tests__/compiler/string-advanced.test.d.ts +7 -0
- package/dist/src/__tests__/compiler/string-advanced.test.js +281 -0
- package/dist/src/__tests__/compiler/struct-extends.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/struct-extends.test.js +95 -0
- package/dist/src/__tests__/compiler/throttle-retry.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/throttle-retry.test.js +166 -0
- package/dist/src/__tests__/compiler/tuple-type.test.d.ts +10 -0
- package/dist/src/__tests__/compiler/tuple-type.test.js +229 -0
- package/dist/src/__tests__/compiler/watch-decorator.test.d.ts +1 -0
- package/dist/src/__tests__/compiler/watch-decorator.test.js +65 -0
- package/dist/src/__tests__/config/project-config.test.d.ts +1 -0
- package/dist/src/__tests__/config/project-config.test.js +199 -0
- package/dist/src/__tests__/config-decorator.test.d.ts +8 -0
- package/dist/src/__tests__/config-decorator.test.js +142 -0
- package/dist/src/__tests__/diagnostics-extra.test.d.ts +6 -0
- package/dist/src/__tests__/diagnostics-extra.test.js +132 -0
- package/dist/src/__tests__/emit/compile-branches.test.d.ts +1 -0
- package/dist/src/__tests__/emit/compile-branches.test.js +123 -0
- package/dist/src/__tests__/emit/compile-coverage.test.d.ts +25 -0
- package/dist/src/__tests__/emit/compile-coverage.test.js +617 -0
- package/dist/src/__tests__/emit/compile-extra-branches.test.d.ts +12 -0
- package/dist/src/__tests__/emit/compile-extra-branches.test.js +225 -0
- package/dist/src/__tests__/emit/compile-mocked-branches.test.d.ts +0 -0
- package/dist/src/__tests__/emit/compile-mocked-branches.test.js +238 -0
- package/dist/src/__tests__/emit/execute-chain.test.d.ts +10 -0
- package/dist/src/__tests__/emit/execute-chain.test.js +94 -0
- package/dist/src/__tests__/emit/index.test.js +2 -1
- package/dist/src/__tests__/emit/modules-branches.test.d.ts +1 -0
- package/dist/src/__tests__/emit/modules-branches.test.js +88 -0
- package/dist/src/__tests__/emit/modules-coverage.test.d.ts +15 -0
- package/dist/src/__tests__/emit/modules-coverage.test.js +221 -0
- package/dist/src/__tests__/emit/modules-errors.test.d.ts +12 -0
- package/dist/src/__tests__/emit/modules-errors.test.js +169 -0
- package/dist/src/__tests__/emit/modules-rewrite.test.d.ts +17 -0
- package/dist/src/__tests__/emit/modules-rewrite.test.js +204 -0
- package/dist/src/__tests__/emit/source-map.test.d.ts +1 -0
- package/dist/src/__tests__/emit/source-map.test.js +167 -0
- package/dist/src/__tests__/enum.test.js +9 -4
- package/dist/src/__tests__/error-recovery.test.d.ts +7 -0
- package/dist/src/__tests__/error-recovery.test.js +217 -0
- package/dist/src/__tests__/events-types-extra.test.d.ts +10 -0
- package/dist/src/__tests__/events-types-extra.test.js +91 -0
- package/dist/src/__tests__/events-types.test.d.ts +4 -0
- package/dist/src/__tests__/events-types.test.js +56 -0
- package/dist/src/__tests__/formatter.test.js +13 -5
- package/dist/src/__tests__/hir/lower-extra.test.d.ts +9 -0
- package/dist/src/__tests__/hir/lower-extra.test.js +140 -0
- package/dist/src/__tests__/hir/monomorphize-extra.test.d.ts +15 -0
- package/dist/src/__tests__/hir/monomorphize-extra.test.js +200 -0
- package/dist/src/__tests__/hir/monomorphize-extra2.test.d.ts +16 -0
- package/dist/src/__tests__/hir/monomorphize-extra2.test.js +316 -0
- package/dist/src/__tests__/incremental.test.js +10 -2
- package/dist/src/__tests__/index-extra.test.d.ts +10 -0
- package/dist/src/__tests__/index-extra.test.js +71 -0
- package/dist/src/__tests__/lexer.test.js +2 -2
- package/dist/src/__tests__/lint/rules.test.d.ts +5 -0
- package/dist/src/__tests__/lint/rules.test.js +208 -0
- package/dist/src/__tests__/lir/lower.test.js +29 -0
- package/dist/src/__tests__/lir/verify.test.js +30 -0
- package/dist/src/__tests__/lsp/completion.test.d.ts +7 -0
- package/dist/src/__tests__/lsp/completion.test.js +583 -0
- package/dist/src/__tests__/lsp/definition.test.d.ts +7 -0
- package/dist/src/__tests__/lsp/definition.test.js +454 -0
- package/dist/src/__tests__/lsp/diagnostics.test.d.ts +10 -0
- package/dist/src/__tests__/lsp/diagnostics.test.js +98 -0
- package/dist/src/__tests__/lsp/hover-docs.test.d.ts +10 -0
- package/dist/src/__tests__/lsp/hover-docs.test.js +210 -0
- package/dist/src/__tests__/lsp.test.js +4 -1
- package/dist/src/__tests__/mc-integration/item-entity-events.test.js +4 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-2.test.js +4 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-3.test.d.ts +13 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-3.test.js +1227 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-4.test.d.ts +13 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-4.test.js +1509 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-5.test.d.ts +14 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-5.test.js +1374 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-6.test.d.ts +10 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-6.test.js +759 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-7.test.d.ts +13 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage-7.test.js +855 -0
- package/dist/src/__tests__/mc-integration/stdlib-coverage.test.js +4 -0
- package/dist/src/__tests__/mc-integration/syntax-coverage.test.js +4 -0
- package/dist/src/__tests__/mc-validator-coverage.test.d.ts +13 -0
- package/dist/src/__tests__/mc-validator-coverage.test.js +296 -0
- package/dist/src/__tests__/mc-validator-extra.test.d.ts +13 -0
- package/dist/src/__tests__/mc-validator-extra.test.js +245 -0
- package/dist/src/__tests__/mir/lower-extra.test.d.ts +20 -0
- package/dist/src/__tests__/mir/lower-extra.test.js +361 -0
- package/dist/src/__tests__/mir/lower-extra2.test.d.ts +17 -0
- package/dist/src/__tests__/mir/lower-extra2.test.js +317 -0
- package/dist/src/__tests__/mir/lower-extra3.test.d.ts +19 -0
- package/dist/src/__tests__/mir/lower-extra3.test.js +249 -0
- package/dist/src/__tests__/mir/lower-extra4.test.d.ts +23 -0
- package/dist/src/__tests__/mir/lower-extra4.test.js +606 -0
- package/dist/src/__tests__/mir/lower-extra5.test.d.ts +25 -0
- package/dist/src/__tests__/mir/lower-extra5.test.js +543 -0
- package/dist/src/__tests__/mir/lower-extra6.test.d.ts +16 -0
- package/dist/src/__tests__/mir/lower-extra6.test.js +471 -0
- package/dist/src/__tests__/mir/lower-extra7.test.d.ts +35 -0
- package/dist/src/__tests__/mir/lower-extra7.test.js +921 -0
- package/dist/src/__tests__/mir/lower-extra8.test.d.ts +19 -0
- package/dist/src/__tests__/mir/lower-extra8.test.js +626 -0
- package/dist/src/__tests__/mir/lower-extra9.test.d.ts +14 -0
- package/dist/src/__tests__/mir/lower-extra9.test.js +717 -0
- package/dist/src/__tests__/optimizer/auto-inline.test.d.ts +1 -0
- package/dist/src/__tests__/optimizer/auto-inline.test.js +176 -0
- package/dist/src/__tests__/optimizer/cse.test.d.ts +4 -0
- package/dist/src/__tests__/optimizer/cse.test.js +178 -0
- package/dist/src/__tests__/optimizer/inline_fn.test.d.ts +1 -0
- package/dist/src/__tests__/optimizer/inline_fn.test.js +221 -0
- package/dist/src/__tests__/optimizer/licm.test.d.ts +1 -0
- package/dist/src/__tests__/optimizer/licm.test.js +244 -0
- package/dist/src/__tests__/optimizer/optimizer-extended.test.d.ts +12 -0
- package/dist/src/__tests__/optimizer/optimizer-extended.test.js +993 -0
- package/dist/src/__tests__/optimizer/strength-reduction.test.d.ts +1 -0
- package/dist/src/__tests__/optimizer/strength-reduction.test.js +86 -0
- package/dist/src/__tests__/optimizer/tco.test.d.ts +14 -0
- package/dist/src/__tests__/optimizer/tco.test.js +203 -0
- package/dist/src/__tests__/parser-coverage.test.d.ts +25 -0
- package/dist/src/__tests__/parser-coverage.test.js +491 -0
- package/dist/src/__tests__/parser-extra.test.d.ts +6 -0
- package/dist/src/__tests__/parser-extra.test.js +451 -0
- package/dist/src/__tests__/parser.test.js +12 -0
- package/dist/src/__tests__/repl-extra.test.d.ts +13 -0
- package/dist/src/__tests__/repl-extra.test.js +174 -0
- package/dist/src/__tests__/repl-server-extra.test.d.ts +10 -0
- package/dist/src/__tests__/repl-server-extra.test.js +161 -0
- package/dist/src/__tests__/repl-server.test.d.ts +6 -0
- package/dist/src/__tests__/repl-server.test.js +146 -0
- package/dist/src/__tests__/runtime-extra.test.d.ts +15 -0
- package/dist/src/__tests__/runtime-extra.test.js +732 -0
- package/dist/src/__tests__/singleton-decorator.test.d.ts +11 -0
- package/dist/src/__tests__/singleton-decorator.test.js +260 -0
- package/dist/src/__tests__/sourcemap.test.js +1 -1
- package/dist/src/__tests__/stdlib/advanced.test.d.ts +5 -0
- package/dist/src/__tests__/stdlib/advanced.test.js +301 -0
- package/dist/src/__tests__/stdlib/bigint.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/bigint.test.js +83 -0
- package/dist/src/__tests__/stdlib/bits.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/bits.test.js +96 -0
- package/dist/src/__tests__/stdlib/bossbar.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/bossbar.test.js +72 -0
- package/dist/src/__tests__/stdlib/color.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/color.test.js +84 -0
- package/dist/src/__tests__/stdlib/combat.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/combat.test.js +64 -0
- package/dist/src/__tests__/stdlib/cooldown.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/cooldown.test.js +64 -0
- package/dist/src/__tests__/stdlib/dialog.test.js +15 -7
- package/dist/src/__tests__/stdlib/ecs.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/ecs.test.js +81 -0
- package/dist/src/__tests__/stdlib/effects.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/effects.test.js +72 -0
- package/dist/src/__tests__/stdlib/events.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/events.test.js +55 -0
- package/dist/src/__tests__/stdlib/expr.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/expr.test.js +77 -0
- package/dist/src/__tests__/stdlib/fft.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/fft.test.js +82 -0
- package/dist/src/__tests__/stdlib/graph.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/graph.test.js +102 -0
- package/dist/src/__tests__/stdlib/interactions.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/interactions.test.js +60 -0
- package/dist/src/__tests__/stdlib/inventory.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/inventory.test.js +68 -0
- package/dist/src/__tests__/stdlib/linalg.test.d.ts +5 -0
- package/dist/src/__tests__/stdlib/linalg.test.js +78 -0
- package/dist/src/__tests__/stdlib/map.test.d.ts +1 -0
- package/dist/src/__tests__/stdlib/map.test.js +84 -0
- package/dist/src/__tests__/stdlib/math.test.js +19 -6
- package/dist/src/__tests__/stdlib/math_hp.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/math_hp.test.js +80 -0
- package/dist/src/__tests__/stdlib/mobs.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/mobs.test.js +61 -0
- package/dist/src/__tests__/stdlib/noise.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/noise.test.js +73 -0
- package/dist/src/__tests__/stdlib/ode.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/ode.test.js +68 -0
- package/dist/src/__tests__/stdlib/parabola.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/parabola.test.js +77 -0
- package/dist/src/__tests__/stdlib/particles.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/particles.test.js +68 -0
- package/dist/src/__tests__/stdlib/physics.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/physics.test.js +76 -0
- package/dist/src/__tests__/stdlib/player.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/player.test.js +64 -0
- package/dist/src/__tests__/stdlib/quaternion.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/quaternion.test.js +73 -0
- package/dist/src/__tests__/stdlib/queue.test.d.ts +1 -0
- package/dist/src/__tests__/stdlib/queue.test.js +97 -0
- package/dist/src/__tests__/stdlib/random.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/random.test.js +76 -0
- package/dist/src/__tests__/stdlib/result.test.d.ts +12 -0
- package/dist/src/__tests__/stdlib/result.test.js +329 -0
- package/dist/src/__tests__/stdlib/scheduler.test.js +19 -8
- package/dist/src/__tests__/stdlib/set_int.test.d.ts +1 -0
- package/dist/src/__tests__/stdlib/set_int.test.js +88 -0
- package/dist/src/__tests__/stdlib/sets.test.d.ts +6 -0
- package/dist/src/__tests__/stdlib/sets.test.js +60 -0
- package/dist/src/__tests__/stdlib/signal.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/signal.test.js +84 -0
- package/dist/src/__tests__/stdlib/spawn.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/spawn.test.js +68 -0
- package/dist/src/__tests__/stdlib/string.test.d.ts +12 -0
- package/dist/src/__tests__/stdlib/string.test.js +231 -0
- package/dist/src/__tests__/stdlib/strings.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/strings.test.js +83 -0
- package/dist/src/__tests__/stdlib/tags.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/tags.test.js +57 -0
- package/dist/src/__tests__/stdlib/teams.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/teams.test.js +72 -0
- package/dist/src/__tests__/stdlib/timer.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/timer.test.js +79 -0
- package/dist/src/__tests__/stdlib/vec.test.d.ts +5 -0
- package/dist/src/__tests__/stdlib/vec.test.js +94 -0
- package/dist/src/__tests__/stdlib/world.test.d.ts +4 -0
- package/dist/src/__tests__/stdlib/world.test.js +72 -0
- package/dist/src/__tests__/struct-display.test.d.ts +1 -0
- package/dist/src/__tests__/struct-display.test.js +64 -0
- package/dist/src/__tests__/test-framework/runner.test.d.ts +10 -0
- package/dist/src/__tests__/test-framework/runner.test.js +193 -0
- package/dist/src/__tests__/tuner/adapters.test.d.ts +14 -0
- package/dist/src/__tests__/tuner/adapters.test.js +194 -0
- package/dist/src/__tests__/tuner/simulator-extra.test.d.ts +4 -0
- package/dist/src/__tests__/tuner/simulator-extra.test.js +193 -0
- package/dist/src/__tests__/typechecker-coverage.test.d.ts +30 -0
- package/dist/src/__tests__/typechecker-coverage.test.js +627 -0
- package/dist/src/__tests__/typechecker.test.js +3 -3
- package/dist/src/__tests__/watch-decorator.test.d.ts +1 -0
- package/dist/src/__tests__/watch-decorator.test.js +54 -0
- package/dist/src/ast/types.d.ts +102 -3
- package/dist/src/cache/incremental.d.ts +13 -14
- package/dist/src/cache/incremental.js +106 -89
- package/dist/src/cache/index.d.ts +8 -2
- package/dist/src/cache/index.js +18 -6
- package/dist/src/cli.d.ts +1 -0
- package/dist/src/cli.js +466 -17
- package/dist/src/config/project-config.d.ts +29 -0
- package/dist/src/config/project-config.js +180 -0
- package/dist/src/diagnostics/index.d.ts +9 -0
- package/dist/src/diagnostics/index.js +18 -1
- package/dist/src/emit/compile.d.ts +10 -0
- package/dist/src/emit/compile.js +395 -50
- package/dist/src/emit/index.d.ts +40 -0
- package/dist/src/emit/index.js +307 -14
- package/dist/src/emit/modules.js +21 -3
- package/dist/src/emit/sourcemap.d.ts +23 -27
- package/dist/src/emit/sourcemap.js +52 -30
- package/dist/src/formatter/index.js +33 -8
- package/dist/src/hir/deprecated.d.ts +13 -0
- package/dist/src/hir/deprecated.js +218 -0
- package/dist/src/hir/lower.js +114 -8
- package/dist/src/hir/monomorphize.js +22 -2
- package/dist/src/hir/types.d.ts +65 -1
- package/dist/src/index.d.ts +6 -0
- package/dist/src/index.js +18 -3
- package/dist/src/lexer/index.d.ts +2 -1
- package/dist/src/lexer/index.js +39 -3
- package/dist/src/lint/index.d.ts +45 -0
- package/dist/src/lint/index.js +930 -0
- package/dist/src/lir/lower.js +29 -2
- package/dist/src/lir/types.d.ts +2 -0
- package/dist/src/lsp/server.js +92 -5
- package/dist/src/mir/lower.js +775 -34
- package/dist/src/mir/macro.js +36 -2
- package/dist/src/mir/types.d.ts +12 -0
- package/dist/src/mir/verify.js +9 -0
- package/dist/src/optimizer/auto-inline.d.ts +2 -0
- package/dist/src/optimizer/auto-inline.js +67 -0
- package/dist/src/optimizer/cse.d.ts +20 -0
- package/dist/src/optimizer/cse.js +234 -0
- package/dist/src/optimizer/inline.d.ts +26 -0
- package/dist/src/optimizer/inline.js +286 -0
- package/dist/src/optimizer/interprocedural.js +4 -0
- package/dist/src/optimizer/licm.d.ts +32 -0
- package/dist/src/optimizer/licm.js +371 -0
- package/dist/src/optimizer/pipeline.js +12 -2
- package/dist/src/optimizer/strength_reduction.d.ts +15 -0
- package/dist/src/optimizer/strength_reduction.js +90 -0
- package/dist/src/optimizer/tco.d.ts +53 -0
- package/dist/src/optimizer/tco.js +238 -0
- package/dist/src/parser/index.d.ts +32 -0
- package/dist/src/parser/index.js +421 -59
- package/dist/src/repl-server.d.ts +13 -0
- package/dist/src/repl-server.js +127 -0
- package/dist/src/structs/expand.d.ts +15 -0
- package/dist/src/structs/expand.js +46 -0
- package/dist/src/testing/runner.d.ts +40 -0
- package/dist/src/testing/runner.js +237 -0
- package/dist/src/typechecker/index.d.ts +3 -0
- package/dist/src/typechecker/index.js +254 -9
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/doc-drafts/redscript-docs/docs/en/stdlib/graph.md +104 -0
- package/doc-drafts/redscript-docs/docs/en/stdlib/parabola.md +113 -0
- package/doc-drafts/redscript-docs/docs/en/stdlib/pathfind.md +104 -0
- package/doc-drafts/redscript-docs/docs/en/stdlib/physics.md +134 -0
- package/doc-drafts/redscript-docs/docs/en/stdlib/quaternion.md +135 -0
- package/doc-drafts/redscript-docs/docs/zh/stdlib/graph.md +104 -0
- package/doc-drafts/redscript-docs/docs/zh/stdlib/parabola.md +113 -0
- package/doc-drafts/redscript-docs/docs/zh/stdlib/pathfind.md +104 -0
- package/doc-drafts/redscript-docs/docs/zh/stdlib/physics.md +134 -0
- package/doc-drafts/redscript-docs/docs/zh/stdlib/quaternion.md +135 -0
- package/docs/stdlib/result.md +156 -0
- package/docs/stdlib/result.zh.md +156 -0
- package/editors/vscode/fixtures/test.mcrs +7 -0
- package/editors/vscode/out/extension.js +2095 -225
- package/editors/vscode/out/lsp-server.js +519 -51
- package/editors/vscode/package-lock.json +9 -4
- package/editors/vscode/package.json +1 -1
- package/examples/display-demo.mcrs +64 -0
- package/examples/game/racing.mcrs +301 -0
- package/examples/game/tower_defense.mcrs +311 -0
- package/examples/math/physics_sim.mcrs +322 -0
- package/examples/rpg/boss_fight.mcrs +313 -0
- package/examples/rpg/health_system.mcrs +237 -0
- package/examples/rpg/inventory.mcrs +265 -0
- package/examples/util/debug_hud.mcrs +279 -0
- package/jest.config.js +10 -0
- package/package.json +12 -3
- package/playground/index.html +823 -0
- package/scripts/gen-docs.ts +533 -0
- package/scripts/update-redscript-docs-stdlib.sh +770 -0
- package/src/__tests__/budget.test.ts +5 -0
- package/src/__tests__/cache/cache-behavior.test.ts +480 -0
- package/src/__tests__/cache-extra.test.ts +199 -0
- package/src/__tests__/cli-docs.test.ts +77 -0
- package/src/__tests__/cli-init.test.ts +91 -0
- package/src/__tests__/cli-publish.test.ts +190 -0
- package/src/__tests__/cli.test.ts +117 -1
- package/src/__tests__/compile-preprocess.test.ts +366 -0
- package/src/__tests__/compiler/break-stmt.test.ts +66 -0
- package/src/__tests__/compiler/const-decl.test.ts +141 -0
- package/src/__tests__/compiler/continue-stmt.test.ts +81 -0
- package/src/__tests__/compiler/coroutine-extended.test.ts +723 -0
- package/src/__tests__/compiler/deprecated.test.ts +305 -0
- package/src/__tests__/compiler/do-while.test.ts +130 -0
- package/src/__tests__/compiler/enum-payload.test.ts +299 -0
- package/src/__tests__/compiler/interface.test.ts +287 -0
- package/src/__tests__/compiler/labeled-loops.test.ts +279 -0
- package/src/__tests__/compiler/match-string.test.ts +45 -0
- package/src/__tests__/compiler/memoize.test.ts +126 -0
- package/src/__tests__/compiler/method-chain.test.ts +121 -0
- package/src/__tests__/compiler/module-import.test.ts +240 -0
- package/src/__tests__/compiler/option-extensions.test.ts +207 -0
- package/src/__tests__/compiler/profile-decorator.test.ts +79 -0
- package/src/__tests__/compiler/string-advanced.test.ts +310 -0
- package/src/__tests__/compiler/struct-extends.test.ts +109 -0
- package/src/__tests__/compiler/throttle-retry.test.ts +191 -0
- package/src/__tests__/compiler/tuple-type.test.ts +263 -0
- package/src/__tests__/compiler/watch-decorator.test.ts +72 -0
- package/src/__tests__/config/project-config.test.ts +181 -0
- package/src/__tests__/config-decorator.test.ts +157 -0
- package/src/__tests__/diagnostics-extra.test.ts +155 -0
- package/src/__tests__/emit/compile-branches.test.ts +135 -0
- package/src/__tests__/emit/compile-coverage.test.ts +696 -0
- package/src/__tests__/emit/compile-extra-branches.test.ts +228 -0
- package/src/__tests__/emit/compile-mocked-branches.test.ts +249 -0
- package/src/__tests__/emit/compile.test.ts +6 -1
- package/src/__tests__/emit/execute-chain.test.ts +114 -0
- package/src/__tests__/emit/index.test.ts +2 -1
- package/src/__tests__/emit/modules-branches.test.ts +90 -0
- package/src/__tests__/emit/modules-coverage.test.ts +241 -0
- package/src/__tests__/emit/modules-errors.test.ts +192 -0
- package/src/__tests__/emit/modules-rewrite.test.ts +232 -0
- package/src/__tests__/emit/source-map.test.ts +152 -0
- package/src/__tests__/enum.test.ts +9 -4
- package/src/__tests__/error-recovery.test.ts +226 -0
- package/src/__tests__/events-types-extra.test.ts +110 -0
- package/src/__tests__/events-types.test.ts +66 -0
- package/src/__tests__/formatter.test.ts +15 -5
- package/src/__tests__/generics.test.ts +16 -9
- package/src/__tests__/hir/lower-extra.test.ts +151 -0
- package/src/__tests__/hir/monomorphize-coverage.test.ts +432 -0
- package/src/__tests__/hir/monomorphize-extra.test.ts +220 -0
- package/src/__tests__/hir/monomorphize-extra2.test.ts +350 -0
- package/src/__tests__/impl.test.ts +12 -8
- package/src/__tests__/incremental.test.ts +10 -2
- package/src/__tests__/index-extra.test.ts +79 -0
- package/src/__tests__/lexer.test.ts +2 -2
- package/src/__tests__/lint/hir-coverage.test.ts +1716 -0
- package/src/__tests__/lint/rules-coverage.test.ts +598 -0
- package/src/__tests__/lint/rules.test.ts +230 -0
- package/src/__tests__/lir/lower.test.ts +33 -0
- package/src/__tests__/lir/verify.test.ts +33 -0
- package/src/__tests__/lsp/completion.test.ts +687 -0
- package/src/__tests__/lsp/definition.test.ts +499 -0
- package/src/__tests__/lsp/diagnostics.test.ts +108 -0
- package/src/__tests__/lsp/hover-docs.test.ts +222 -0
- package/src/__tests__/lsp.test.ts +4 -1
- package/src/__tests__/mc-integration/item-entity-events.test.ts +5 -0
- package/src/__tests__/mc-integration/stdlib-coverage-2.test.ts +5 -0
- package/src/__tests__/mc-integration/stdlib-coverage-3.test.ts +1105 -0
- package/src/__tests__/mc-integration/stdlib-coverage-4.test.ts +1366 -0
- package/src/__tests__/mc-integration/stdlib-coverage-5.test.ts +1245 -0
- package/src/__tests__/mc-integration/stdlib-coverage-6.test.ts +755 -0
- package/src/__tests__/mc-integration/stdlib-coverage-7.test.ts +771 -0
- package/src/__tests__/mc-integration/stdlib-coverage.test.ts +5 -0
- package/src/__tests__/mc-integration/syntax-coverage.test.ts +5 -0
- package/src/__tests__/mc-validator-coverage.test.ts +325 -0
- package/src/__tests__/mc-validator-extra.test.ts +252 -0
- package/src/__tests__/mir/lower-extra.test.ts +402 -0
- package/src/__tests__/mir/lower-extra2.test.ts +348 -0
- package/src/__tests__/mir/lower-extra3.test.ts +277 -0
- package/src/__tests__/mir/lower-extra4.test.ts +636 -0
- package/src/__tests__/mir/lower-extra5.test.ts +612 -0
- package/src/__tests__/mir/lower-extra6.test.ts +520 -0
- package/src/__tests__/mir/lower-extra7.test.ts +1045 -0
- package/src/__tests__/mir/lower-extra8.test.ts +704 -0
- package/src/__tests__/mir/lower-extra9.test.ts +821 -0
- package/src/__tests__/optimizer/auto-inline.test.ts +206 -0
- package/src/__tests__/optimizer/cse.test.ts +195 -0
- package/src/__tests__/optimizer/inline_fn.test.ts +263 -0
- package/src/__tests__/optimizer/licm.test.ts +358 -0
- package/src/__tests__/optimizer/nbt-coalesce.test.ts +147 -0
- package/src/__tests__/optimizer/optimizer-extended.test.ts +1081 -0
- package/src/__tests__/optimizer/scoreboard-batch.test.ts +141 -0
- package/src/__tests__/optimizer/strength-reduction.test.ts +111 -0
- package/src/__tests__/optimizer/tco-coverage.test.ts +309 -0
- package/src/__tests__/optimizer/tco.test.ts +238 -0
- package/src/__tests__/option.test.ts +14 -7
- package/src/__tests__/parser-coverage.test.ts +576 -0
- package/src/__tests__/parser-extra.test.ts +531 -0
- package/src/__tests__/parser.test.ts +14 -0
- package/src/__tests__/repl-extra.test.ts +195 -0
- package/src/__tests__/repl-server-extra.test.ts +150 -0
- package/src/__tests__/repl-server.test.ts +122 -0
- package/src/__tests__/runtime-extra.test.ts +862 -0
- package/src/__tests__/singleton-decorator.test.ts +285 -0
- package/src/__tests__/sourcemap.test.ts +1 -1
- package/src/__tests__/stdlib/advanced.test.ts +312 -0
- package/src/__tests__/stdlib/bigint.test.ts +57 -0
- package/src/__tests__/stdlib/bits.test.ts +75 -0
- package/src/__tests__/stdlib/bossbar.test.ts +45 -0
- package/src/__tests__/stdlib/color.test.ts +60 -0
- package/src/__tests__/stdlib/combat.test.ts +35 -0
- package/src/__tests__/stdlib/cooldown.test.ts +35 -0
- package/src/__tests__/stdlib/dialog.test.ts +14 -6
- package/src/__tests__/stdlib/ecs.test.ts +54 -0
- package/src/__tests__/stdlib/effects.test.ts +45 -0
- package/src/__tests__/stdlib/events.test.ts +23 -0
- package/src/__tests__/stdlib/expr.test.ts +48 -0
- package/src/__tests__/stdlib/fft.test.ts +54 -0
- package/src/__tests__/stdlib/graph.test.ts +77 -0
- package/src/__tests__/stdlib/interactions.test.ts +30 -0
- package/src/__tests__/stdlib/inventory.test.ts +40 -0
- package/src/__tests__/stdlib/linalg.test.ts +52 -0
- package/src/__tests__/stdlib/map.test.ts +55 -0
- package/src/__tests__/stdlib/math.test.ts +19 -5
- package/src/__tests__/stdlib/math_hp.test.ts +55 -0
- package/src/__tests__/stdlib/mobs.test.ts +40 -0
- package/src/__tests__/stdlib/noise.test.ts +46 -0
- package/src/__tests__/stdlib/ode.test.ts +40 -0
- package/src/__tests__/stdlib/parabola.test.ts +51 -0
- package/src/__tests__/stdlib/particles.test.ts +40 -0
- package/src/__tests__/stdlib/physics.test.ts +50 -0
- package/src/__tests__/stdlib/player.test.ts +35 -0
- package/src/__tests__/stdlib/quaternion.test.ts +46 -0
- package/src/__tests__/stdlib/queue.test.ts +73 -0
- package/src/__tests__/stdlib/random.test.ts +50 -0
- package/src/__tests__/stdlib/result.test.ts +326 -0
- package/src/__tests__/stdlib/scheduler.test.ts +18 -7
- package/src/__tests__/stdlib/set_int.test.ts +62 -0
- package/src/__tests__/stdlib/sets.test.ts +28 -0
- package/src/__tests__/stdlib/signal.test.ts +60 -0
- package/src/__tests__/stdlib/spawn.test.ts +40 -0
- package/src/__tests__/stdlib/string.test.ts +224 -0
- package/src/__tests__/stdlib/strings.test.ts +55 -0
- package/src/__tests__/stdlib/tags.test.ts +32 -0
- package/src/__tests__/stdlib/teams.test.ts +45 -0
- package/src/__tests__/stdlib/timer.test.ts +53 -0
- package/src/__tests__/stdlib/vec.test.ts +72 -0
- package/src/__tests__/stdlib/world.test.ts +45 -0
- package/src/__tests__/struct-display.test.ts +69 -0
- package/src/__tests__/test-framework/runner.test.ts +208 -0
- package/src/__tests__/tuner/adapters.test.ts +232 -0
- package/src/__tests__/tuner/simulator-extra.test.ts +222 -0
- package/src/__tests__/tuple.test.ts +11 -4
- package/src/__tests__/typechecker-coverage.test.ts +671 -0
- package/src/__tests__/typechecker.test.ts +4 -3
- package/src/__tests__/watch-decorator.test.ts +59 -0
- package/src/ast/types.ts +65 -3
- package/src/cache/incremental.ts +128 -99
- package/src/cache/index.ts +35 -8
- package/src/cli.ts +538 -29
- package/src/config/project-config.ts +176 -0
- package/src/diagnostics/index.ts +22 -0
- package/src/docs.ts +98 -0
- package/src/emit/compile.ts +408 -51
- package/src/emit/index.ts +366 -18
- package/src/emit/modules.ts +19 -3
- package/src/emit/sourcemap.ts +64 -43
- package/src/formatter/index.ts +35 -8
- package/src/hir/deprecated.ts +212 -0
- package/src/hir/lower.ts +128 -8
- package/src/hir/monomorphize.ts +24 -2
- package/src/hir/types.ts +26 -1
- package/src/index.ts +23 -3
- package/src/lexer/index.ts +45 -6
- package/src/lint/index.ts +922 -0
- package/src/lir/lower.ts +30 -2
- package/src/lir/types.ts +4 -0
- package/src/lsp/server.ts +100 -1
- package/src/mir/lower.ts +785 -40
- package/src/mir/macro.ts +30 -2
- package/src/mir/types.ts +13 -0
- package/src/mir/verify.ts +10 -2
- package/src/optimizer/auto-inline.ts +86 -0
- package/src/optimizer/copy_prop.ts +2 -2
- package/src/optimizer/coroutine.ts +3 -3
- package/src/optimizer/cse.ts +205 -0
- package/src/optimizer/dce.ts +2 -2
- package/src/optimizer/inline.ts +335 -0
- package/src/optimizer/interprocedural.ts +5 -1
- package/src/optimizer/licm.ts +454 -0
- package/src/optimizer/nbt-coalesce.ts +109 -0
- package/src/optimizer/pipeline.ts +16 -2
- package/src/optimizer/scoreboard-batch.ts +52 -0
- package/src/optimizer/strength_reduction.ts +95 -0
- package/src/optimizer/tco.ts +267 -0
- package/src/optimizer/unroll.ts +2 -2
- package/src/parser/index.ts +426 -53
- package/src/repl-server.ts +102 -0
- package/src/stdlib/advanced.mcrs +271 -101
- package/src/stdlib/bigint.mcrs +97 -11
- package/src/stdlib/bits.mcrs +75 -12
- package/src/stdlib/bossbar.mcrs +37 -8
- package/src/stdlib/calculus.mcrs +82 -26
- package/src/stdlib/color.mcrs +98 -16
- package/src/stdlib/combat.mcrs +23 -5
- package/src/stdlib/cooldown.mcrs +19 -0
- package/src/stdlib/dialog.mcrs +45 -7
- package/src/stdlib/easing.mcrs +132 -12
- package/src/stdlib/ecs.mcrs +142 -25
- package/src/stdlib/effects.mcrs +88 -12
- package/src/stdlib/events.mcrs +21 -2
- package/src/stdlib/expr.mcrs +18 -3
- package/src/stdlib/fft.mcrs +66 -56
- package/src/stdlib/geometry.mcrs +137 -39
- package/src/stdlib/graph.mcrs +73 -0
- package/src/stdlib/heap.mcrs +49 -8
- package/src/stdlib/i18n/zh.yaml +2891 -0
- package/src/stdlib/interactions.mcrs +43 -20
- package/src/stdlib/inventory.mcrs +14 -3
- package/src/stdlib/linalg.mcrs +185 -30
- package/src/stdlib/list.mcrs +168 -18
- package/src/stdlib/map.mcrs +112 -0
- package/src/stdlib/math.mcrs +68 -18
- package/src/stdlib/math_hp.mcrs +124 -33
- package/src/stdlib/matrix.mcrs +133 -20
- package/src/stdlib/mobs.mcrs +87 -0
- package/src/stdlib/noise.mcrs +65 -21
- package/src/stdlib/ode.mcrs +96 -0
- package/src/stdlib/parabola.mcrs +104 -29
- package/src/stdlib/particles.mcrs +78 -21
- package/src/stdlib/pathfind.mcrs +89 -35
- package/src/stdlib/physics.mcrs +134 -26
- package/src/stdlib/player.mcrs +18 -0
- package/src/stdlib/quaternion.mcrs +213 -9
- package/src/stdlib/queue.mcrs +123 -0
- package/src/stdlib/random.mcrs +63 -18
- package/src/stdlib/result.mcrs +111 -0
- package/src/stdlib/scheduler.mcrs +59 -10
- package/src/stdlib/set_int.mcrs +240 -0
- package/src/stdlib/sets.mcrs +49 -19
- package/src/stdlib/signal.mcrs +151 -79
- package/src/stdlib/sort.mcrs +44 -24
- package/src/stdlib/spawn.mcrs +30 -7
- package/src/stdlib/state.mcrs +40 -5
- package/src/stdlib/strings.mcrs +131 -3
- package/src/stdlib/tags.mcrs +2 -2
- package/src/stdlib/teams.mcrs +22 -10
- package/src/stdlib/timer.mcrs +36 -6
- package/src/stdlib/vec.mcrs +44 -9
- package/src/stdlib/world.mcrs +57 -25
- package/src/structs/expand.ts +64 -0
- package/src/testing/runner.ts +271 -0
- package/src/typechecker/index.ts +273 -9
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Loop-Invariant Code Motion (LICM) — MIR optimization pass.
|
|
4
|
+
*
|
|
5
|
+
* For each natural loop (detected by the loop_header / loop_body / loop_latch
|
|
6
|
+
* naming convention used by the RedScript HIR→MIR lowering), instructions
|
|
7
|
+
* whose operands are not modified inside the loop and that have no side
|
|
8
|
+
* effects are hoisted to a newly-inserted preheader block that jumps to the
|
|
9
|
+
* loop header.
|
|
10
|
+
*
|
|
11
|
+
* Algorithm:
|
|
12
|
+
* 1. Identify all loops via the loop_header block naming convention.
|
|
13
|
+
* 2. Collect all temps defined anywhere in the loop (variant set).
|
|
14
|
+
* 3. Walk each loop block's instructions; an instruction is loop-invariant
|
|
15
|
+
* when:
|
|
16
|
+
* a. It has no side effects (no call, nbt_write, score_write, etc.).
|
|
17
|
+
* b. Every operand is either a constant OR a temp not in the variant set.
|
|
18
|
+
* 4. Insert a fresh preheader block before the loop header, redirect the
|
|
19
|
+
* predecessor(s) of the header (excluding the back-edge latch) to the
|
|
20
|
+
* preheader, and move the hoisted instructions there.
|
|
21
|
+
* 5. Remove hoisted instructions from their original blocks.
|
|
22
|
+
* 6. Recompute predecessor lists.
|
|
23
|
+
*
|
|
24
|
+
* Limitations:
|
|
25
|
+
* - Only handles the canonical loop shape produced by the RedScript compiler
|
|
26
|
+
* (loop_header / loop_body / loop_latch block id prefixes).
|
|
27
|
+
* - Requires that the loop have exactly one non-back-edge predecessor of
|
|
28
|
+
* the header (i.e. one entry edge).
|
|
29
|
+
* - Does not hoist instructions that could trap (div/mod with a variable
|
|
30
|
+
* denominator) — we conservatively keep those in place.
|
|
31
|
+
*/
|
|
32
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
33
|
+
exports.licm = licm;
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Public API
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
function licm(fn) {
|
|
38
|
+
let current = fn;
|
|
39
|
+
let changed = true;
|
|
40
|
+
// Iterate to fixpoint — multiple loops, or newly-exposed invariants
|
|
41
|
+
while (changed) {
|
|
42
|
+
changed = false;
|
|
43
|
+
const result = tryHoistOne(current);
|
|
44
|
+
if (result !== current) {
|
|
45
|
+
current = result;
|
|
46
|
+
changed = true;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return current;
|
|
50
|
+
}
|
|
51
|
+
function tryHoistOne(fn) {
|
|
52
|
+
const blockMap = new Map(fn.blocks.map(b => [b.id, b]));
|
|
53
|
+
for (const block of fn.blocks) {
|
|
54
|
+
if (!block.id.startsWith('loop_header'))
|
|
55
|
+
continue;
|
|
56
|
+
const info = analyzeLoop(fn, blockMap, block);
|
|
57
|
+
if (!info)
|
|
58
|
+
continue;
|
|
59
|
+
const hoisted = collectInvariant(info, blockMap);
|
|
60
|
+
if (hoisted.length === 0)
|
|
61
|
+
continue;
|
|
62
|
+
return applyHoist(fn, blockMap, info, hoisted);
|
|
63
|
+
}
|
|
64
|
+
return fn;
|
|
65
|
+
}
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
// Loop detection
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
function analyzeLoop(fn, blockMap, header) {
|
|
70
|
+
// Header must branch (loop condition check)
|
|
71
|
+
if (header.term.kind !== 'branch')
|
|
72
|
+
return null;
|
|
73
|
+
// Find the latch: the block that jumps back to the header
|
|
74
|
+
const latchId = findLatch(fn, header.id);
|
|
75
|
+
if (!latchId)
|
|
76
|
+
return null;
|
|
77
|
+
// Find the non-back-edge predecessor (the block that first enters the loop)
|
|
78
|
+
const preHeaderPredId = findPreHeaderPred(fn, header.id, latchId);
|
|
79
|
+
if (!preHeaderPredId)
|
|
80
|
+
return null;
|
|
81
|
+
// Collect all loop block ids: header + any block reachable from header
|
|
82
|
+
// that can reach the latch (simple: everything up to and including latch)
|
|
83
|
+
const loopBlockIds = collectLoopBlocks(fn, blockMap, header.id, latchId);
|
|
84
|
+
return { headerId: header.id, loopBlockIds, preHeaderPredId, latchId };
|
|
85
|
+
}
|
|
86
|
+
/** Find the latch: a predecessor of header that is dominated by header.
|
|
87
|
+
* In the canonical shape, it's the block with id prefix loop_latch that
|
|
88
|
+
* jumps back to the header. Fall back to any predecessor != preheader. */
|
|
89
|
+
function findLatch(fn, headerId) {
|
|
90
|
+
for (const block of fn.blocks) {
|
|
91
|
+
if (block.id.startsWith('loop_latch')) {
|
|
92
|
+
const targets = getTermTargets(block.term);
|
|
93
|
+
if (targets.includes(headerId))
|
|
94
|
+
return block.id;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// Fallback: any predecessor that comes after the header in block order
|
|
98
|
+
// (a back-edge in the CFG)
|
|
99
|
+
const headerIdx = fn.blocks.findIndex(b => b.id === headerId);
|
|
100
|
+
for (let i = headerIdx + 1; i < fn.blocks.length; i++) {
|
|
101
|
+
const block = fn.blocks[i];
|
|
102
|
+
const targets = getTermTargets(block.term);
|
|
103
|
+
if (targets.includes(headerId))
|
|
104
|
+
return block.id;
|
|
105
|
+
}
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
/** Find the single non-latch predecessor of the header. */
|
|
109
|
+
function findPreHeaderPred(fn, headerId, latchId) {
|
|
110
|
+
const preds = [];
|
|
111
|
+
for (const block of fn.blocks) {
|
|
112
|
+
if (block.id === latchId)
|
|
113
|
+
continue;
|
|
114
|
+
const targets = getTermTargets(block.term);
|
|
115
|
+
if (targets.includes(headerId))
|
|
116
|
+
preds.push(block.id);
|
|
117
|
+
}
|
|
118
|
+
return preds.length === 1 ? preds[0] : null;
|
|
119
|
+
}
|
|
120
|
+
/** BFS/DFS: collect all block ids that are in the loop (header..latch). */
|
|
121
|
+
function collectLoopBlocks(fn, blockMap, headerId, latchId) {
|
|
122
|
+
const result = new Set();
|
|
123
|
+
const queue = [headerId];
|
|
124
|
+
while (queue.length > 0) {
|
|
125
|
+
const id = queue.shift();
|
|
126
|
+
if (result.has(id))
|
|
127
|
+
continue;
|
|
128
|
+
result.add(id);
|
|
129
|
+
if (id === latchId)
|
|
130
|
+
continue; // don't expand past the latch's targets
|
|
131
|
+
const block = blockMap.get(id);
|
|
132
|
+
if (!block)
|
|
133
|
+
continue;
|
|
134
|
+
for (const target of getTermTargets(block.term)) {
|
|
135
|
+
// Only follow edges that stay inside the loop (don't chase the exit edge)
|
|
136
|
+
// Heuristic: follow targets that have 'loop_' prefix or are the latch
|
|
137
|
+
if (!result.has(target) && isLoopBlock(target, headerId)) {
|
|
138
|
+
queue.push(target);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return result;
|
|
143
|
+
}
|
|
144
|
+
function isLoopBlock(id, headerId) {
|
|
145
|
+
// A block belongs to the loop if it has a loop_ prefix derived from the same
|
|
146
|
+
// loop as headerId, or is the header itself.
|
|
147
|
+
if (id === headerId)
|
|
148
|
+
return true;
|
|
149
|
+
// Extract the loop suffix from headerId: "loop_header" or "loop_header_N"
|
|
150
|
+
const suffix = headerId.replace(/^loop_header/, '');
|
|
151
|
+
return (id.startsWith('loop_body' + suffix) ||
|
|
152
|
+
id.startsWith('loop_latch' + suffix) ||
|
|
153
|
+
id.startsWith('loop_header' + suffix) ||
|
|
154
|
+
// Nested loop blocks will have further prefixes — include them
|
|
155
|
+
id.startsWith('loop_') && id.includes(suffix));
|
|
156
|
+
}
|
|
157
|
+
function collectInvariant(info, blockMap) {
|
|
158
|
+
// Step 1: collect the set of all temps defined (written) anywhere in the loop
|
|
159
|
+
const variantTemps = new Set();
|
|
160
|
+
for (const id of info.loopBlockIds) {
|
|
161
|
+
const block = blockMap.get(id);
|
|
162
|
+
if (!block)
|
|
163
|
+
continue;
|
|
164
|
+
for (const instr of block.instrs) {
|
|
165
|
+
const dst = getInstrDst(instr);
|
|
166
|
+
if (dst !== null)
|
|
167
|
+
variantTemps.add(dst);
|
|
168
|
+
}
|
|
169
|
+
// Terminator dsts (there are none in practice, but be safe)
|
|
170
|
+
const termDst = getInstrDst(block.term);
|
|
171
|
+
if (termDst !== null)
|
|
172
|
+
variantTemps.add(termDst);
|
|
173
|
+
}
|
|
174
|
+
// Step 2: iteratively find invariant instructions
|
|
175
|
+
// (an instr whose operands are all non-variant can itself be treated as
|
|
176
|
+
// non-variant after it is removed, exposing further candidates)
|
|
177
|
+
const hoisted = [];
|
|
178
|
+
let changed = true;
|
|
179
|
+
const removedKeys = new Set(); // "blockId:index"
|
|
180
|
+
while (changed) {
|
|
181
|
+
changed = false;
|
|
182
|
+
for (const id of info.loopBlockIds) {
|
|
183
|
+
const block = blockMap.get(id);
|
|
184
|
+
if (!block)
|
|
185
|
+
continue;
|
|
186
|
+
for (let i = 0; i < block.instrs.length; i++) {
|
|
187
|
+
const key = `${id}:${i}`;
|
|
188
|
+
if (removedKeys.has(key))
|
|
189
|
+
continue;
|
|
190
|
+
const instr = block.instrs[i];
|
|
191
|
+
const dst = getInstrDst(instr);
|
|
192
|
+
// Must have a dst (otherwise it's a side-effectful no-dst instr)
|
|
193
|
+
if (dst === null)
|
|
194
|
+
continue;
|
|
195
|
+
// Must not have side effects
|
|
196
|
+
if (hasSideEffects(instr))
|
|
197
|
+
continue;
|
|
198
|
+
// Skip div/mod with variable denominator (potential trap)
|
|
199
|
+
if ((instr.kind === 'div' || instr.kind === 'mod') && instr.b.kind === 'temp')
|
|
200
|
+
continue;
|
|
201
|
+
// All source operands must be invariant (not in variantTemps)
|
|
202
|
+
if (!allOperandsInvariant(instr, variantTemps))
|
|
203
|
+
continue;
|
|
204
|
+
// This instruction is loop-invariant — hoist it
|
|
205
|
+
hoisted.push({ fromBlockId: id, instrIndex: i, instr });
|
|
206
|
+
removedKeys.add(key);
|
|
207
|
+
// After hoisting, the dst is no longer variant inside the loop
|
|
208
|
+
variantTemps.delete(dst);
|
|
209
|
+
changed = true;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return hoisted;
|
|
214
|
+
}
|
|
215
|
+
function allOperandsInvariant(instr, variantTemps) {
|
|
216
|
+
for (const op of getSourceOperands(instr)) {
|
|
217
|
+
if (op.kind === 'temp' && variantTemps.has(op.name))
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
// ---------------------------------------------------------------------------
|
|
223
|
+
// Applying the hoist
|
|
224
|
+
// ---------------------------------------------------------------------------
|
|
225
|
+
function applyHoist(fn, blockMap, info, hoisted) {
|
|
226
|
+
const { headerId, preHeaderPredId, latchId } = info;
|
|
227
|
+
// Build a key set for quick lookup: "blockId:instrIndex"
|
|
228
|
+
const hoistedKeys = new Set(hoisted.map(h => `${h.fromBlockId}:${h.instrIndex}`));
|
|
229
|
+
// Collect hoisted instrs in order (they were collected left-to-right)
|
|
230
|
+
const hoistedInstrs = hoisted.map(h => h.instr);
|
|
231
|
+
// Insert a fresh preheader block
|
|
232
|
+
const preHeaderId = headerId.replace('loop_header', 'loop_preheader');
|
|
233
|
+
const preHeaderBlock = {
|
|
234
|
+
id: preHeaderId,
|
|
235
|
+
instrs: hoistedInstrs,
|
|
236
|
+
term: { kind: 'jump', target: headerId },
|
|
237
|
+
preds: [], // will be recomputed
|
|
238
|
+
};
|
|
239
|
+
// Rewrite the predecessor's jump from header → preHeader
|
|
240
|
+
const newBlocks = [];
|
|
241
|
+
for (const block of fn.blocks) {
|
|
242
|
+
if (block.id === preHeaderPredId) {
|
|
243
|
+
// Redirect its outgoing edge(s) from headerId to preHeaderId
|
|
244
|
+
newBlocks.push({
|
|
245
|
+
...block,
|
|
246
|
+
term: redirectTerm(block.term, headerId, preHeaderId),
|
|
247
|
+
});
|
|
248
|
+
// Insert the new preheader right after this block
|
|
249
|
+
newBlocks.push(preHeaderBlock);
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
// Remove hoisted instructions from their source blocks
|
|
253
|
+
if (info.loopBlockIds.has(block.id)) {
|
|
254
|
+
const newInstrs = block.instrs.filter((_, i) => !hoistedKeys.has(`${block.id}:${i}`));
|
|
255
|
+
newBlocks.push({ ...block, instrs: newInstrs });
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
newBlocks.push(block);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return { ...fn, blocks: recomputePreds(newBlocks) };
|
|
263
|
+
}
|
|
264
|
+
function redirectTerm(term, from, to) {
|
|
265
|
+
switch (term.kind) {
|
|
266
|
+
case 'jump':
|
|
267
|
+
return term.target === from ? { ...term, target: to } : term;
|
|
268
|
+
case 'branch':
|
|
269
|
+
return {
|
|
270
|
+
...term,
|
|
271
|
+
then: term.then === from ? to : term.then,
|
|
272
|
+
else: term.else === from ? to : term.else,
|
|
273
|
+
};
|
|
274
|
+
default:
|
|
275
|
+
return term;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
// ---------------------------------------------------------------------------
|
|
279
|
+
// Helpers
|
|
280
|
+
// ---------------------------------------------------------------------------
|
|
281
|
+
function hasSideEffects(instr) {
|
|
282
|
+
return (instr.kind === 'call' ||
|
|
283
|
+
instr.kind === 'call_macro' ||
|
|
284
|
+
instr.kind === 'call_context' ||
|
|
285
|
+
instr.kind === 'nbt_write' ||
|
|
286
|
+
instr.kind === 'nbt_write_dynamic' ||
|
|
287
|
+
instr.kind === 'score_write');
|
|
288
|
+
}
|
|
289
|
+
function getInstrDst(instr) {
|
|
290
|
+
switch (instr.kind) {
|
|
291
|
+
case 'const':
|
|
292
|
+
case 'copy':
|
|
293
|
+
case 'add':
|
|
294
|
+
case 'sub':
|
|
295
|
+
case 'mul':
|
|
296
|
+
case 'div':
|
|
297
|
+
case 'mod':
|
|
298
|
+
case 'neg':
|
|
299
|
+
case 'cmp':
|
|
300
|
+
case 'and':
|
|
301
|
+
case 'or':
|
|
302
|
+
case 'not':
|
|
303
|
+
case 'nbt_read':
|
|
304
|
+
case 'nbt_read_dynamic':
|
|
305
|
+
case 'nbt_list_len':
|
|
306
|
+
case 'string_match':
|
|
307
|
+
case 'score_read':
|
|
308
|
+
return instr.dst;
|
|
309
|
+
case 'call':
|
|
310
|
+
case 'call_macro':
|
|
311
|
+
return instr.dst;
|
|
312
|
+
default:
|
|
313
|
+
return null;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
function getSourceOperands(instr) {
|
|
317
|
+
switch (instr.kind) {
|
|
318
|
+
case 'copy':
|
|
319
|
+
case 'neg':
|
|
320
|
+
case 'not':
|
|
321
|
+
return [instr.src];
|
|
322
|
+
case 'add':
|
|
323
|
+
case 'sub':
|
|
324
|
+
case 'mul':
|
|
325
|
+
case 'div':
|
|
326
|
+
case 'mod':
|
|
327
|
+
case 'cmp':
|
|
328
|
+
case 'and':
|
|
329
|
+
case 'or':
|
|
330
|
+
return [instr.a, instr.b];
|
|
331
|
+
case 'nbt_write':
|
|
332
|
+
return [instr.src];
|
|
333
|
+
case 'nbt_write_dynamic':
|
|
334
|
+
return [instr.indexSrc, instr.valueSrc];
|
|
335
|
+
case 'nbt_read_dynamic':
|
|
336
|
+
return [instr.indexSrc];
|
|
337
|
+
case 'call':
|
|
338
|
+
return [...instr.args];
|
|
339
|
+
case 'call_macro':
|
|
340
|
+
return instr.args.map(a => a.value);
|
|
341
|
+
case 'branch':
|
|
342
|
+
return [instr.cond];
|
|
343
|
+
case 'return':
|
|
344
|
+
return instr.value ? [instr.value] : [];
|
|
345
|
+
case 'score_write':
|
|
346
|
+
return [instr.src];
|
|
347
|
+
default:
|
|
348
|
+
return [];
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
function getTermTargets(term) {
|
|
352
|
+
switch (term.kind) {
|
|
353
|
+
case 'jump': return [term.target];
|
|
354
|
+
case 'branch': return [term.then, term.else];
|
|
355
|
+
default: return [];
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
function recomputePreds(blocks) {
|
|
359
|
+
const predMap = new Map();
|
|
360
|
+
for (const b of blocks)
|
|
361
|
+
predMap.set(b.id, []);
|
|
362
|
+
for (const block of blocks) {
|
|
363
|
+
for (const target of getTermTargets(block.term)) {
|
|
364
|
+
const preds = predMap.get(target);
|
|
365
|
+
if (preds)
|
|
366
|
+
preds.push(block.id);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
return blocks.map(b => ({ ...b, preds: predMap.get(b.id) ?? [] }));
|
|
370
|
+
}
|
|
371
|
+
//# sourceMappingURL=licm.js.map
|
|
@@ -13,13 +13,18 @@ exports.selectorCache = void 0;
|
|
|
13
13
|
exports.optimizeFunction = optimizeFunction;
|
|
14
14
|
exports.optimizeModule = optimizeModule;
|
|
15
15
|
const constant_fold_1 = require("./constant_fold");
|
|
16
|
+
const strength_reduction_1 = require("./strength_reduction");
|
|
16
17
|
const copy_prop_1 = require("./copy_prop");
|
|
17
18
|
const dce_1 = require("./dce");
|
|
18
19
|
const block_merge_1 = require("./block_merge");
|
|
19
20
|
const branch_simplify_1 = require("./branch_simplify");
|
|
20
21
|
const unroll_1 = require("./unroll");
|
|
22
|
+
const licm_1 = require("./licm");
|
|
21
23
|
const nbt_batch_1 = require("./nbt-batch");
|
|
22
24
|
const interprocedural_1 = require("./interprocedural");
|
|
25
|
+
const auto_inline_1 = require("./auto-inline");
|
|
26
|
+
const inline_1 = require("./inline");
|
|
27
|
+
const cse_1 = require("./cse");
|
|
23
28
|
// selectorCache is intentionally excluded from the default pipeline:
|
|
24
29
|
// it emits synthetic __sel_cleanup_* / __sel_tag_* call_context instructions
|
|
25
30
|
// that require codegen support before being used end-to-end.
|
|
@@ -27,8 +32,11 @@ var selector_cache_1 = require("./selector-cache");
|
|
|
27
32
|
Object.defineProperty(exports, "selectorCache", { enumerable: true, get: function () { return selector_cache_1.selectorCache; } });
|
|
28
33
|
const defaultPasses = [
|
|
29
34
|
unroll_1.loopUnroll,
|
|
35
|
+
licm_1.licm,
|
|
30
36
|
nbt_batch_1.nbtBatchRead,
|
|
31
37
|
constant_fold_1.constantFold,
|
|
38
|
+
strength_reduction_1.strengthReduction,
|
|
39
|
+
cse_1.cse,
|
|
32
40
|
copy_prop_1.copyProp,
|
|
33
41
|
branch_simplify_1.branchSimplify,
|
|
34
42
|
dce_1.dce,
|
|
@@ -48,9 +56,11 @@ function optimizeFunction(fn, passes = defaultPasses) {
|
|
|
48
56
|
return current;
|
|
49
57
|
}
|
|
50
58
|
function optimizeModule(mod, passes) {
|
|
59
|
+
// Module-level pass: inline @inline-marked functions before per-function opts
|
|
60
|
+
const inlined = (0, auto_inline_1.autoInlineSmallFunctions)((0, inline_1.inlinePass)(mod));
|
|
51
61
|
const perFnOptimized = {
|
|
52
|
-
...
|
|
53
|
-
functions:
|
|
62
|
+
...inlined,
|
|
63
|
+
functions: inlined.functions.map(fn => optimizeFunction(fn, passes)),
|
|
54
64
|
};
|
|
55
65
|
// Module-level pass: interprocedural constant propagation
|
|
56
66
|
return (0, interprocedural_1.interproceduralConstProp)(perFnOptimized);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strength Reduction — MIR algebraic simplification pass.
|
|
3
|
+
*
|
|
4
|
+
* Rewrites expensive or redundant arithmetic into cheaper equivalents:
|
|
5
|
+
* - x * 2 -> x + x
|
|
6
|
+
* - x * 1 -> x
|
|
7
|
+
* - x * 0 -> 0
|
|
8
|
+
* - x + 0 -> x
|
|
9
|
+
* - x - 0 -> x
|
|
10
|
+
* - x / 1 -> x
|
|
11
|
+
* - x ^ 1 -> x
|
|
12
|
+
* - x * -1 -> -x
|
|
13
|
+
*/
|
|
14
|
+
import type { MIRFunction } from '../mir/types';
|
|
15
|
+
export declare function strengthReduction(fn: MIRFunction): MIRFunction;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Strength Reduction — MIR algebraic simplification pass.
|
|
4
|
+
*
|
|
5
|
+
* Rewrites expensive or redundant arithmetic into cheaper equivalents:
|
|
6
|
+
* - x * 2 -> x + x
|
|
7
|
+
* - x * 1 -> x
|
|
8
|
+
* - x * 0 -> 0
|
|
9
|
+
* - x + 0 -> x
|
|
10
|
+
* - x - 0 -> x
|
|
11
|
+
* - x / 1 -> x
|
|
12
|
+
* - x ^ 1 -> x
|
|
13
|
+
* - x * -1 -> -x
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.strengthReduction = strengthReduction;
|
|
17
|
+
function strengthReduction(fn) {
|
|
18
|
+
return {
|
|
19
|
+
...fn,
|
|
20
|
+
blocks: fn.blocks.map(rewriteBlock),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function rewriteBlock(block) {
|
|
24
|
+
return {
|
|
25
|
+
...block,
|
|
26
|
+
instrs: block.instrs.map(instr => rewriteInstr(instr) ?? instr),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function rewriteInstr(instr) {
|
|
30
|
+
const powInstr = asPowInstr(instr);
|
|
31
|
+
if (powInstr && isConst(powInstr.b, 1))
|
|
32
|
+
return makeCopy(powInstr.dst, powInstr.a, powInstr.sourceLoc);
|
|
33
|
+
switch (instr.kind) {
|
|
34
|
+
case 'mul':
|
|
35
|
+
return rewriteMul(instr);
|
|
36
|
+
case 'add':
|
|
37
|
+
if (isConst(instr.a, 0))
|
|
38
|
+
return makeCopy(instr.dst, instr.b, instr.sourceLoc);
|
|
39
|
+
if (isConst(instr.b, 0))
|
|
40
|
+
return makeCopy(instr.dst, instr.a, instr.sourceLoc);
|
|
41
|
+
return null;
|
|
42
|
+
case 'sub':
|
|
43
|
+
if (isConst(instr.b, 0))
|
|
44
|
+
return makeCopy(instr.dst, instr.a, instr.sourceLoc);
|
|
45
|
+
return null;
|
|
46
|
+
case 'div':
|
|
47
|
+
if (isConst(instr.b, 1))
|
|
48
|
+
return makeCopy(instr.dst, instr.a, instr.sourceLoc);
|
|
49
|
+
return null;
|
|
50
|
+
default:
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function rewriteMul(instr) {
|
|
55
|
+
if (isConst(instr.a, 0) || isConst(instr.b, 0))
|
|
56
|
+
return makeConst(instr.dst, 0, instr.sourceLoc);
|
|
57
|
+
if (isConst(instr.a, 1))
|
|
58
|
+
return makeCopy(instr.dst, instr.b, instr.sourceLoc);
|
|
59
|
+
if (isConst(instr.b, 1))
|
|
60
|
+
return makeCopy(instr.dst, instr.a, instr.sourceLoc);
|
|
61
|
+
if (isConst(instr.a, -1))
|
|
62
|
+
return makeNeg(instr.dst, instr.b, instr.sourceLoc);
|
|
63
|
+
if (isConst(instr.b, -1))
|
|
64
|
+
return makeNeg(instr.dst, instr.a, instr.sourceLoc);
|
|
65
|
+
if (isConst(instr.a, 2))
|
|
66
|
+
return makeAdd(instr.dst, instr.b, instr.b, instr.sourceLoc);
|
|
67
|
+
if (isConst(instr.b, 2))
|
|
68
|
+
return makeAdd(instr.dst, instr.a, instr.a, instr.sourceLoc);
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
function isConst(op, value) {
|
|
72
|
+
return op.kind === 'const' && op.value === value;
|
|
73
|
+
}
|
|
74
|
+
function asPowInstr(instr) {
|
|
75
|
+
const candidate = instr;
|
|
76
|
+
return candidate.kind === 'pow' ? candidate : null;
|
|
77
|
+
}
|
|
78
|
+
function makeCopy(dst, src, sourceLoc) {
|
|
79
|
+
return sourceLoc ? { kind: 'copy', dst, src, sourceLoc } : { kind: 'copy', dst, src };
|
|
80
|
+
}
|
|
81
|
+
function makeConst(dst, value, sourceLoc) {
|
|
82
|
+
return sourceLoc ? { kind: 'const', dst, value, sourceLoc } : { kind: 'const', dst, value };
|
|
83
|
+
}
|
|
84
|
+
function makeNeg(dst, src, sourceLoc) {
|
|
85
|
+
return sourceLoc ? { kind: 'neg', dst, src, sourceLoc } : { kind: 'neg', dst, src };
|
|
86
|
+
}
|
|
87
|
+
function makeAdd(dst, a, b, sourceLoc) {
|
|
88
|
+
return sourceLoc ? { kind: 'add', dst, a, b, sourceLoc } : { kind: 'add', dst, a, b };
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=strength_reduction.js.map
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tail Call Optimization (TCO) — MIR optimization pass.
|
|
3
|
+
*
|
|
4
|
+
* Detects direct self-tail-calls and converts them into loops, eliminating
|
|
5
|
+
* the recursive function call entirely.
|
|
6
|
+
*
|
|
7
|
+
* ## Definition
|
|
8
|
+
* A tail call is a `call` instruction whose result is immediately returned
|
|
9
|
+
* in the same block (i.e., the block's terminator is `return` and the last
|
|
10
|
+
* non-terminator instruction is `call dst fn args` where fn === current fn,
|
|
11
|
+
* and the return value is that dst temp).
|
|
12
|
+
*
|
|
13
|
+
* ## Transformation
|
|
14
|
+
* Given a function like:
|
|
15
|
+
*
|
|
16
|
+
* fn factorial(n, acc):
|
|
17
|
+
* entry:
|
|
18
|
+
* t0 = cmp le n 1
|
|
19
|
+
* branch t0 → base_case, recurse
|
|
20
|
+
* base_case:
|
|
21
|
+
* return acc
|
|
22
|
+
* recurse:
|
|
23
|
+
* t1 = mul acc n
|
|
24
|
+
* t2 = sub n 1
|
|
25
|
+
* t3 = call factorial(t2, t1) ← tail call
|
|
26
|
+
* return t3
|
|
27
|
+
*
|
|
28
|
+
* We:
|
|
29
|
+
* 1. Create a new "__tco_entry" preamble block that copies original params
|
|
30
|
+
* into "loop parameter" temps (__lp0, __lp1, ...) and jumps to the
|
|
31
|
+
* original entry block.
|
|
32
|
+
* 2. In all blocks (including entry), substitute uses of original param
|
|
33
|
+
* temps with loop params, so subsequent iterations use updated values.
|
|
34
|
+
* 3. In tail-call blocks: evaluate call args (to avoid aliasing), assign
|
|
35
|
+
* results to loop params, and jump back to original entry — no call emitted.
|
|
36
|
+
*/
|
|
37
|
+
import type { MIRFunction, BlockId } from '../mir/types';
|
|
38
|
+
/**
|
|
39
|
+
* Attempt to apply TCO to a single function.
|
|
40
|
+
* Returns the transformed function if any tail calls were optimized,
|
|
41
|
+
* or the original function unchanged if no self-tail-calls were found.
|
|
42
|
+
*/
|
|
43
|
+
export declare function tailCallOptimize(fn: MIRFunction): MIRFunction;
|
|
44
|
+
/**
|
|
45
|
+
* Returns a list of tail-call block descriptors for every block that contains
|
|
46
|
+
* a self-tail-call: the last non-terminator instruction is a `call` to the
|
|
47
|
+
* same function, and the block terminator is `return` of that call's result.
|
|
48
|
+
*/
|
|
49
|
+
export declare function findTailCallBlocks(fn: MIRFunction): Array<{
|
|
50
|
+
blockId: BlockId;
|
|
51
|
+
callIdx: number;
|
|
52
|
+
argCount: number;
|
|
53
|
+
}>;
|