jz 0.6.0 → 0.8.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/README.md +99 -72
- package/bench/README.md +253 -100
- package/bench/bench.svg +58 -81
- package/cli.js +85 -12
- package/dist/interop.js +1 -0
- package/dist/jz.js +6196 -0
- package/index.d.ts +126 -0
- package/index.js +222 -35
- package/interop.js +240 -141
- package/layout.js +34 -18
- package/module/array.js +99 -111
- package/module/collection.js +124 -30
- package/module/console.js +1 -1
- package/module/core.js +163 -19
- package/module/json.js +3 -3
- package/module/math.js +162 -3
- package/module/number.js +268 -13
- package/module/object.js +37 -5
- package/module/regex.js +8 -7
- package/module/simd.js +37 -5
- package/module/string.js +203 -168
- package/module/typedarray.js +565 -112
- package/package.json +26 -7
- package/src/abi/string.js +29 -29
- package/src/ast.js +19 -2
- package/src/autoload.js +3 -0
- package/src/compile/analyze-scans.js +174 -11
- package/src/compile/analyze.js +101 -4
- package/src/compile/cse-load.js +200 -0
- package/src/compile/emit-assign.js +82 -20
- package/src/compile/emit.js +592 -51
- package/src/compile/index.js +504 -89
- package/src/compile/infer.js +36 -1
- package/src/compile/loop-divmod.js +109 -0
- package/src/compile/loop-model.js +91 -0
- package/src/compile/loop-square.js +102 -0
- package/src/compile/narrow.js +275 -41
- package/src/compile/peel-stencil.js +215 -0
- package/src/compile/plan/advise.js +55 -1
- package/src/compile/plan/common.js +29 -0
- package/src/compile/plan/index.js +8 -1
- package/src/compile/plan/inline.js +180 -22
- package/src/compile/plan/literals.js +313 -24
- package/src/compile/plan/scope.js +115 -39
- package/src/compile/program-facts.js +21 -2
- package/src/ctx.js +96 -19
- package/src/helper-counters.js +137 -0
- package/src/ir.js +157 -20
- package/src/kind-traits.js +34 -3
- package/src/kind.js +79 -4
- package/src/op-policy.js +5 -2
- package/src/ops.js +119 -0
- package/src/optimize/index.js +1274 -151
- package/src/optimize/recurse.js +182 -0
- package/src/optimize/vectorize.js +4187 -253
- package/src/prepare/index.js +75 -14
- package/src/prepare/lift-iife.js +149 -0
- package/src/reps.js +6 -2
- package/src/static.js +9 -0
- package/src/type.js +63 -51
- package/src/wat/assemble.js +286 -21
- package/src/widen.js +21 -0
- package/src/wat/optimize.js +0 -3760
package/module/regex.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import { typed, asF64, asI64, UNDEF_NAN, NULL_NAN, mkPtrIR, temp, tempI32 } from '../src/ir.js'
|
|
11
11
|
import { emit, deps } from '../src/bridge.js'
|
|
12
|
-
import { ctx, err, inc, PTR, LAYOUT,
|
|
12
|
+
import { ctx, err, inc, PTR, LAYOUT, registerGetter, declGlobal } from '../src/ctx.js'
|
|
13
13
|
import { valTypeOf } from '../src/kind.js'
|
|
14
14
|
import { VAL } from '../src/reps.js'
|
|
15
15
|
|
|
@@ -746,13 +746,14 @@ export default (ctx) => {
|
|
|
746
746
|
(if (i32.eqz (i32.and (local.get $aux) (i32.const ${LAYOUT.SSO_BIT})))
|
|
747
747
|
(then (return (call $__ptr_offset (local.get $ptr)))))
|
|
748
748
|
(local.set $off (call $__ptr_offset (local.get $ptr)))
|
|
749
|
-
(local.set $len (i32.and (local.get $aux) (i32.const 7)))
|
|
749
|
+
(local.set $len (i32.and (i32.shr_u (local.get $aux) (i32.const 10)) (i32.const 7)))
|
|
750
750
|
(local.set $buf (call $__alloc (local.get $len)))
|
|
751
751
|
(local.set $i (i32.const 0))
|
|
752
752
|
(block $done (loop $next
|
|
753
753
|
(br_if $done (i32.ge_u (local.get $i) (local.get $len)))
|
|
754
|
+
;; 7-bit ASCII SSO: char i at payload bit i*7 (read from the full i64 ptr; chars 4-5 span aux).
|
|
754
755
|
(i32.store8 (i32.add (local.get $buf) (local.get $i))
|
|
755
|
-
(i32.and (
|
|
756
|
+
(i32.wrap_i64 (i64.and (i64.shr_u (local.get $ptr) (i64.mul (i64.extend_i32_u (local.get $i)) (i64.const 7))) (i64.const 0x7f))))
|
|
756
757
|
(local.set $i (i32.add (local.get $i) (i32.const 1)))
|
|
757
758
|
(br $next)))
|
|
758
759
|
(local.get $buf))`
|
|
@@ -911,14 +912,14 @@ export default (ctx) => {
|
|
|
911
912
|
// RegExp.prototype.source — the pattern text. A literal stores it verbatim
|
|
912
913
|
// (already grammar-escaped), so `/A/.source` is the 6-char "A".
|
|
913
914
|
// An empty pattern serializes to "(?:)" so the result re-parses to a regex.
|
|
914
|
-
|
|
915
|
+
registerGetter('.regex:source', (obj) => {
|
|
915
916
|
const a = regexAstOf(obj)
|
|
916
917
|
return emit(['str', (a && a[1]) || '(?:)'])
|
|
917
918
|
})
|
|
918
919
|
|
|
919
920
|
// RegExp.prototype.flags — flag characters in canonical order (sec-get-regexp.prototype.flags).
|
|
920
921
|
const FLAG_ORDER = 'dgimsvy'
|
|
921
|
-
|
|
922
|
+
registerGetter('.regex:flags', (obj) => {
|
|
922
923
|
const f = flagsOf(obj)
|
|
923
924
|
return emit(['str', [...FLAG_ORDER].filter(c => f.includes(c)).join('')])
|
|
924
925
|
})
|
|
@@ -927,10 +928,10 @@ export default (ctx) => {
|
|
|
927
928
|
for (const [prop, ch] of [
|
|
928
929
|
['global', 'g'], ['ignoreCase', 'i'], ['multiline', 'm'], ['dotAll', 's'],
|
|
929
930
|
['unicode', 'u'], ['sticky', 'y'], ['hasIndices', 'd'], ['unicodeSets', 'v'],
|
|
930
|
-
])
|
|
931
|
+
]) registerGetter(`.regex:${prop}`, (obj) => typed(['f64.const', flagsOf(obj).includes(ch) ? 1 : 0], 'f64'))
|
|
931
932
|
|
|
932
933
|
// lastIndex — for /g and /y regexes, reads the mutable global; others always 0.
|
|
933
|
-
|
|
934
|
+
registerGetter('.regex:lastIndex', (obj) => {
|
|
934
935
|
const id = resolveRegex(obj)
|
|
935
936
|
if (id != null) {
|
|
936
937
|
const flags = flagsOf(obj)
|
package/module/simd.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* SIMD module — source-level f32x4 / i32x4 intrinsics that lower 1:1 to wasm
|
|
3
|
-
* (v128). Lets a jz kernel process 4 lanes per instruction:
|
|
4
|
-
* kernels (mandelbrot, raymarcher) run 4 pixels/rays in masked
|
|
5
|
-
*
|
|
2
|
+
* SIMD module — source-level f32x4 / i32x4 / f64x2 intrinsics that lower 1:1 to wasm
|
|
3
|
+
* SIMD (v128). Lets a jz kernel process 4 (or, for f64x2, 2) lanes per instruction:
|
|
4
|
+
* the per-pixel-parallel kernels (mandelbrot, raymarcher) run 4 pixels/rays in masked
|
|
5
|
+
* lockstep, and the attractors kernel packs its two sines + two cosines two-per-f64x2.
|
|
6
|
+
* Several-fold over scalar V8 (validated: SIMD-4 mandelbrot ≈ 4.6× a warm-V8 scalar loop).
|
|
6
7
|
*
|
|
7
8
|
* A v128 value is just a local whose wasm type is `v128` (exprType returns 'v128'
|
|
8
9
|
* for these calls; emit passes it through without an f64/i32 coercion). Building
|
|
@@ -18,11 +19,14 @@
|
|
|
18
19
|
* i32x4.splat(n) / add/sub(a,b) / lane(v,k)
|
|
19
20
|
* v128.and/or/xor(a,b) / not(a) / bitselect(t,f,mask)
|
|
20
21
|
* v128.anyTrue(v) / v128.allTrue(v) → i32 (loop-exit tests)
|
|
22
|
+
* f64x2.splat(x) / lanes(a,b) / add/sub/mul/div/min/max / sqrt/abs/neg/… / cmp
|
|
23
|
+
* f64x2.sin(v) / f64x2.cos(v) → both lanes through one poly ($math.sin2/$math.cos2)
|
|
24
|
+
* f64x2.lane(v, k) extract lane k (0..1) as a number
|
|
21
25
|
*
|
|
22
26
|
* @module simd
|
|
23
27
|
*/
|
|
24
28
|
import { typed, asF64, asI32 } from '../src/ir.js'
|
|
25
|
-
import { emit } from '../src/bridge.js'
|
|
29
|
+
import { emit, emitter } from '../src/bridge.js'
|
|
26
30
|
import { err } from '../src/ctx.js'
|
|
27
31
|
|
|
28
32
|
export default (ctx) => {
|
|
@@ -82,4 +86,32 @@ export default (ctx) => {
|
|
|
82
86
|
// ── lane extract (read a single lane back to a scalar) ───────────────────────
|
|
83
87
|
e['f32x4.lane'] = (v, k) => F(['f64.promote_f32', ['f32x4.extract_lane', laneIdx(k), op(v)]])
|
|
84
88
|
e['i32x4.lane'] = (v, k) => I(['i32x4.extract_lane', laneIdx(k), op(v)])
|
|
89
|
+
|
|
90
|
+
// ── f64x2 — two full-precision f64 lanes (no f32 demotion) ───────────────────
|
|
91
|
+
// For kernels whose hot value is f64: two independent angles/coords per instruction.
|
|
92
|
+
// `f64x2.sin`/`f64x2.cos` lower to the shared $math.sin2/$math.cos2 poly (module/math.js)
|
|
93
|
+
// — sin and cos of distinct args pack two-per-vector and ≈halve transcendental cost.
|
|
94
|
+
const lane2 = (k) => {
|
|
95
|
+
const v = typeof k === 'number' ? k : (Array.isArray(k) && k.length === 2 && k[0] == null && typeof k[1] === 'number') ? k[1] : null
|
|
96
|
+
if (v == null || (v | 0) !== v || v < 0 || v > 1)
|
|
97
|
+
err(`f64x2 lane index must be a 0..1 literal (got ${JSON.stringify(k)}).`)
|
|
98
|
+
return v
|
|
99
|
+
}
|
|
100
|
+
e['f64x2.splat'] = (a) => V(['f64x2.splat', asF64(emit(a))])
|
|
101
|
+
e['f64x2.lanes'] = (a, b) => V(['f64x2.replace_lane', 1, ['f64x2.splat', asF64(emit(a))], asF64(emit(b))])
|
|
102
|
+
for (const o of ['add', 'sub', 'mul', 'div', 'min', 'max'])
|
|
103
|
+
e[`f64x2.${o}`] = (a, b) => V([`f64x2.${o}`, op(a), op(b)])
|
|
104
|
+
for (const o of ['sqrt', 'abs', 'neg', 'floor', 'ceil', 'trunc', 'nearest'])
|
|
105
|
+
e[`f64x2.${o}`] = (a) => V([`f64x2.${o}`, op(a)])
|
|
106
|
+
for (const o of ['eq', 'ne', 'lt', 'le', 'gt', 'ge'])
|
|
107
|
+
e[`f64x2.${o}`] = (a, b) => V([`f64x2.${o}`, op(a), op(b)])
|
|
108
|
+
e['f64x2.sin'] = emitter(['math.sin2'], (a) => V(['call', '$math.sin2', op(a)]))
|
|
109
|
+
e['f64x2.cos'] = emitter(['math.cos2'], (a) => V(['call', '$math.cos2', op(a)]))
|
|
110
|
+
// f64x2.log/exp/exp2 lower to the true-vectorized $math.log_v/$math.exp_v/$math.exp2_v polys —
|
|
111
|
+
// both lanes through one fdlibm/2^f evaluation (≈2× over two scalar calls), bit-exact via a
|
|
112
|
+
// hot-path-vectorized + scalar-edge-fallback split (module/math.js).
|
|
113
|
+
e['f64x2.log'] = emitter(['math.log_v'], (a) => V(['call', '$math.log_v', op(a)]))
|
|
114
|
+
e['f64x2.exp'] = emitter(['math.exp_v'], (a) => V(['call', '$math.exp_v', op(a)]))
|
|
115
|
+
e['f64x2.exp2'] = emitter(['math.exp2_v'], (a) => V(['call', '$math.exp2_v', op(a)]))
|
|
116
|
+
e['f64x2.lane'] = (v, k) => F(['f64x2.extract_lane', lane2(k), op(v)])
|
|
85
117
|
}
|