watr 4.5.3 → 4.6.1
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/dist/watr.js +565 -44
- package/dist/watr.min.js +6 -6
- package/dist/watr.wasm +0 -0
- package/package.json +8 -3
- package/readme.md +1 -1
- package/src/optimize.js +670 -49
- package/types/src/optimize.d.ts +107 -6
- package/types/src/optimize.d.ts.map +1 -1
package/types/src/optimize.d.ts
CHANGED
|
@@ -67,11 +67,6 @@ export function strength(ast: any[]): any[];
|
|
|
67
67
|
* @returns {Array}
|
|
68
68
|
*/
|
|
69
69
|
export function branch(ast: any[]): any[];
|
|
70
|
-
/**
|
|
71
|
-
* Propagate values through locals and eliminate single-use/dead locals.
|
|
72
|
-
* Constants propagate to all uses; pure single-use exprs inline into get site.
|
|
73
|
-
* Multi-pass with batch counting for convergence.
|
|
74
|
-
*/
|
|
75
70
|
export function propagate(ast: any): any;
|
|
76
71
|
/**
|
|
77
72
|
* Inline tiny functions (single expression, no locals, no params or simple params).
|
|
@@ -79,6 +74,36 @@ export function propagate(ast: any): any;
|
|
|
79
74
|
* @returns {Array}
|
|
80
75
|
*/
|
|
81
76
|
export function inline(ast: any[]): any[];
|
|
77
|
+
/**
|
|
78
|
+
* Inline functions that are called from exactly one place into their lone caller,
|
|
79
|
+
* then delete them. Unlike {@link inline} (which duplicates tiny stateless bodies),
|
|
80
|
+
* this never duplicates code and never inflates: each inlined function drops a
|
|
81
|
+
* function-section entry, a type-section entry (if now unused), and a `call`
|
|
82
|
+
* instruction, paying back only a `block`/`local.set` wrapper. This is what
|
|
83
|
+
* `wasm-opt -Oz` does — collapsing helper chains down to a couple of functions —
|
|
84
|
+
* and it's the bulk of the gap between hand-tuned WASM and naive codegen.
|
|
85
|
+
*
|
|
86
|
+
* A function `$f` qualifies when it is, all of:
|
|
87
|
+
* • named, with named params and locals (numeric indices can't be safely renamed);
|
|
88
|
+
* • referenced exactly once across the whole module, by a plain `call` (no
|
|
89
|
+
* `return_call`, `ref.func`, `elem`, `export`, or `start` reference, and not
|
|
90
|
+
* recursive);
|
|
91
|
+
* • single-result or void (a multi-value result can't be modeled as `(block (result …))`);
|
|
92
|
+
* • free of numeric (depth-relative) branch labels — those would shift under the
|
|
93
|
+
* extra block nesting — and of `return_call*` in its body.
|
|
94
|
+
*
|
|
95
|
+
* `(call $f a0 a1 …)` becomes
|
|
96
|
+
* (block $__inlN (result T)?
|
|
97
|
+
* (local.set $__inlN_p0 a0) (local.set $__inlN_p1 a1) … ;; args evaluated once, in order
|
|
98
|
+
* …body, params/locals renamed to $__inlN_*, `return X` → `br $__inlN X`…)
|
|
99
|
+
* and the renamed params+locals are appended to the caller's `local` decls; the
|
|
100
|
+
* body's own block/loop/if labels are renamed too so they can't shadow the caller's.
|
|
101
|
+
* Runs to a fixpoint so helper chains fully collapse.
|
|
102
|
+
*
|
|
103
|
+
* @param {Array} ast
|
|
104
|
+
* @returns {Array}
|
|
105
|
+
*/
|
|
106
|
+
export function inlineOnce(ast: any[]): any[];
|
|
82
107
|
/**
|
|
83
108
|
* Normalize options to { opt: bool } map.
|
|
84
109
|
* @param {boolean|string|Object} opts
|
|
@@ -95,11 +120,15 @@ export namespace OPTS {
|
|
|
95
120
|
let branch: boolean;
|
|
96
121
|
let propagate: boolean;
|
|
97
122
|
let inline: boolean;
|
|
123
|
+
let inlineOnce: boolean;
|
|
98
124
|
let vacuum: boolean;
|
|
125
|
+
let mergeBlocks: boolean;
|
|
126
|
+
let coalesce: boolean;
|
|
99
127
|
let peephole: boolean;
|
|
100
128
|
let globals: boolean;
|
|
101
129
|
let offset: boolean;
|
|
102
130
|
let unbranch: boolean;
|
|
131
|
+
let loopify: boolean;
|
|
103
132
|
let stripmut: boolean;
|
|
104
133
|
let brif: boolean;
|
|
105
134
|
let foldarms: boolean;
|
|
@@ -123,7 +152,14 @@ export function vacuum(ast: any[]): any[];
|
|
|
123
152
|
*/
|
|
124
153
|
export function peephole(ast: any[]): any[];
|
|
125
154
|
/**
|
|
126
|
-
* Replace global.get of immutable
|
|
155
|
+
* Replace `global.get` of an immutable, const-initialised global with the
|
|
156
|
+
* constant — but only when it doesn't grow the module. A `global.get` costs
|
|
157
|
+
* ~2 B; an `i32.const 12345` costs 4 B; an `f64.const` costs 9 B. Naively
|
|
158
|
+
* inlining a big constant read from many sites trades a few cheap reads + one
|
|
159
|
+
* global decl for many fat immediates — pure bloat (and the node-count size
|
|
160
|
+
* guard can't see it: same number of AST nodes). So we only propagate a global
|
|
161
|
+
* when `refs·constSize ≤ refs·2 + declSize`; when every read is replaced and
|
|
162
|
+
* the global isn't exported, its now-dead decl is dropped here too.
|
|
127
163
|
* @param {Array} ast
|
|
128
164
|
* @returns {Array}
|
|
129
165
|
*/
|
|
@@ -136,6 +172,31 @@ export function offset(ast: any): any;
|
|
|
136
172
|
* @returns {Array}
|
|
137
173
|
*/
|
|
138
174
|
export function unbranch(ast: any[]): any[];
|
|
175
|
+
/**
|
|
176
|
+
* Collapse the `while`-emit idiom into a single loop.
|
|
177
|
+
*
|
|
178
|
+
* (block $A
|
|
179
|
+
* (loop $B
|
|
180
|
+
* (br_if $A (i32.eqz cond)) ;; exit when cond is false
|
|
181
|
+
* …body…
|
|
182
|
+
* (br $B) ;; continue
|
|
183
|
+
* ))
|
|
184
|
+
*
|
|
185
|
+
* becomes
|
|
186
|
+
*
|
|
187
|
+
* (loop $B
|
|
188
|
+
* (if cond (then …body… (br $B))))
|
|
189
|
+
*
|
|
190
|
+
* Saves ~3 B per while-loop (drop the outer block framing + the `i32.eqz`,
|
|
191
|
+
* trade `br_if`→`if`). Safe only when:
|
|
192
|
+
* - the block contains nothing but the loop (plus optional `type` slot),
|
|
193
|
+
* - block / loop are void (no result),
|
|
194
|
+
* - $A is never targeted from within body (only the head `br_if` uses it).
|
|
195
|
+
*
|
|
196
|
+
* @param {Array} ast
|
|
197
|
+
* @returns {Array}
|
|
198
|
+
*/
|
|
199
|
+
export function loopify(ast: any[]): any[];
|
|
139
200
|
/**
|
|
140
201
|
* Strip mutability from globals that are never written.
|
|
141
202
|
* Enables globals constant-propagation for more globals.
|
|
@@ -186,5 +247,45 @@ export function packData(ast: any[]): any[];
|
|
|
186
247
|
* @returns {Array}
|
|
187
248
|
*/
|
|
188
249
|
export function minifyImports(ast: any[]): any[];
|
|
250
|
+
/**
|
|
251
|
+
* Unwrap redundant blocks whose label is never targeted. The block's stack
|
|
252
|
+
* effect is determined entirely by its body, so removing the `block`/`end`
|
|
253
|
+
* framing is sound as long as no `br` reaches into the block from inside.
|
|
254
|
+
*
|
|
255
|
+
* Two complementary patterns:
|
|
256
|
+
*
|
|
257
|
+
* 1. **Block at scope level** (sibling in `func`/`block`/`loop`/`then`/`else`):
|
|
258
|
+
* splice body into the parent scope. Works for untyped, `(result T)`-typed,
|
|
259
|
+
* or even `(param …)`-typed blocks — in all cases the body produces the
|
|
260
|
+
* same net stack effect as the framed block did, at the same position.
|
|
261
|
+
* 2. **Result-typed block in expression position** (`(block (result T) expr)`
|
|
262
|
+
* as the value of some operand): collapse to `expr` if the body is a
|
|
263
|
+
* single value expression. Catches the wrappers jz codegen leaves around
|
|
264
|
+
* arena allocations once `propagate` has folded the intermediate
|
|
265
|
+
* set/get pairs to a single call.
|
|
266
|
+
*
|
|
267
|
+
* Pattern 2 runs first (post-order) so pattern 1 sees the cleaned-up parents.
|
|
268
|
+
* @param {Array} ast
|
|
269
|
+
* @returns {Array}
|
|
270
|
+
*/
|
|
271
|
+
export function mergeBlocks(ast: any[]): any[];
|
|
272
|
+
/**
|
|
273
|
+
* Share local slots between same-type locals with non-overlapping live ranges.
|
|
274
|
+
* Live range = [first pos, last pos] of any local.get/set/tee, extended over
|
|
275
|
+
* any loop containing a reference (so a value read across loop iterations stays
|
|
276
|
+
* intact). Greedy slot assignment by start position. Params and unnamed/numeric
|
|
277
|
+
* references are left alone; `localReuse` later removes the renamed-away decls.
|
|
278
|
+
*
|
|
279
|
+
* Soundness: WASM zero-initializes locals at function entry, so a local whose
|
|
280
|
+
* first reference (in walk order) is a `local.get` *relies* on that implicit
|
|
281
|
+
* zero — coalescing it into a slot whose previous user left a non-zero residue
|
|
282
|
+
* would silently change behavior (e.g. a `for (let i=0; …)` loop counter
|
|
283
|
+
* inheriting `N*4` from a sibling temp). Such "read-first" locals can still
|
|
284
|
+
* serve as a slot's *primary* (the slot then keeps the function's zero start),
|
|
285
|
+
* but can never be a donor merged into an existing slot.
|
|
286
|
+
* @param {Array} ast
|
|
287
|
+
* @returns {Array}
|
|
288
|
+
*/
|
|
289
|
+
export function coalesceLocals(ast: any[]): any[];
|
|
189
290
|
export { count as size };
|
|
190
291
|
//# sourceMappingURL=optimize.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"optimize.d.ts","sourceRoot":"","sources":["../../src/optimize.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"optimize.d.ts","sourceRoot":"","sources":["../../src/optimize.js"],"names":[],"mappings":"AAonFA;;;;;;;;;;;GAWG;AACH,sCATW,QAAM,MAAM,SACZ,OAAO,GAAC,MAAM,MAAO,SAkF/B;AA9pFD;;;;GAIG;AACH,4BAHW,GAAG,GACD,MAAM,CAOlB;AAED;;;;GAIG;AACH,wCAFa,MAAM,CAIlB;AAwGD;;;;;GAKG;AACH,6CAgJC;AA2KD;;;;GAIG;AACH,wCAwBC;AAoMD;;;;GAIG;AACH,4CAqBC;AA+CD;;;;;GAKG;AACH,8CAmDC;AA7QD;;;;GAIG;AACH,4CASC;AAID;;;;GAIG;AACH,4CA6DC;AAID;;;;GAIG;AACH,0CAuCC;AAgYD,yCAoCC;AAID;;;;GAIG;AACH,0CAiGC;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,8CAgKC;AAp0CD;;;;GAIG;AACH,gCAHW,OAAO,GAAC,MAAM,MAAO,OAa/B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAugDD;;;;;GAKG;AACH,0CAgDC;AAyED;;;;GAIG;AACH,4CAQC;AA4BD;;;;;;;;;;;GAWG;AACH,2CAyDC;AAID,2EAA2E;AAC3E,sCAgEC;AAID;;;;GAIG;AACH,4CAyCC;AAID;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,2CAiDC;AAID;;;;;GAKG;AACH,4CAqBC;AAID;;;;;;GAMG;AACH,wCAmBC;AAID;;;;;GAKG;AACH,4CAiDC;AAoCD;;;;;GAKG;AACH,0CA8DC;AAiWD,uCAyBC;AAtXD;;;;;GAKG;AACH,8CAyEC;AAoID;;;;GAIG;AACH,4CAyDC;AAqBD;;;;;GAKG;AACH,iDAgBC;AAnoCD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,+CA2CC;AAID;;;;;;;;;;;;;;;;GAgBG;AACH,kDAyFC"}
|