\ Pre-loaded user-immediate vocabulary. \ i32 arithmetic + bitwise : + ( i32 i32 -- i32 ) 0x6a emit-u8 ; immediate : - ( i32 i32 -- i32 ) 0x6b emit-u8 ; immediate : * ( i32 i32 -- i32 ) 0x6c emit-u8 ; immediate : / ( i32 i32 -- i32 ) 0x6d emit-u8 ; immediate : /u ( i32 i32 -- i32 ) 0x6e emit-u8 ; immediate : % ( i32 i32 -- i32 ) 0x6f emit-u8 ; immediate : %u ( i32 i32 -- i32 ) 0x70 emit-u8 ; immediate : & ( i32 i32 -- i32 ) 0x71 emit-u8 ; immediate : | ( i32 i32 -- i32 ) 0x72 emit-u8 ; immediate : ^ ( i32 i32 -- i32 ) 0x73 emit-u8 ; immediate : << ( i32 i32 -- i32 ) 0x74 emit-u8 ; immediate : >> ( i32 i32 -- i32 ) 0x75 emit-u8 ; immediate : >>u ( i32 i32 -- i32 ) 0x76 emit-u8 ; immediate \ i32 comparison : =0 ( i32 -- i32 ) 0x45 emit-u8 ; immediate : <>0 ( i32 -- i32 ) 0x45 emit-u8 0x45 emit-u8 ; immediate : = ( i32 i32 -- i32 ) 0x46 emit-u8 ; immediate : <> ( i32 i32 -- i32 ) 0x47 emit-u8 ; immediate : < ( i32 i32 -- i32 ) 0x48 emit-u8 ; immediate : ( i32 i32 -- i32 ) 0x4a emit-u8 ; immediate : >u ( i32 i32 -- i32 ) 0x4b emit-u8 ; immediate : <= ( i32 i32 -- i32 ) 0x4c emit-u8 ; immediate : <=u ( i32 i32 -- i32 ) 0x4d emit-u8 ; immediate : >= ( i32 i32 -- i32 ) 0x4e emit-u8 ; immediate : >=u ( i32 i32 -- i32 ) 0x4f emit-u8 ; immediate : negate ( i32 -- i32 ) 0x41 emit-u8 -1 emit-sleb 0x6c emit-u8 ; immediate : ~ ( i32 -- i32 ) 0x41 emit-u8 -1 emit-sleb 0x73 emit-u8 ; immediate : ctz ( i32 -- i32 ) 0x68 emit-u8 ; immediate \ `: NAME N lit ; immediate` splices i32.const N inline. : lit ( i32 -- ) 0x41 emit-u8 emit-sleb ; immediate \ Internal type tags. Bits 0-3 = log2(size in bytes); bits 4-7 = kind. \ kind 1=int, 2=float, 3=vec, 4=any/wildcard. Size = 1 << (tag & 0xF). \ Translated to wasm valtype bytes at the emit boundary (tag-to-valtype). \ `immediate` so the dead compiled body is stripped. : T.byte ( -- i32 ) 0x10 ; immediate : T.i32 ( -- i32 ) 0x12 ; immediate : T.f32 ( -- i32 ) 0x22 ; immediate : T.v128 ( -- i32 ) 0x34 ; immediate : T.any ( -- i32 ) 0x40 ; immediate : drop ( any -- ) 0x1a emit-u8 ; immediate : dup ( i32 -- i32 i32 ) T.i32 alloc-temp { t } t ltee t lget ; immediate : swap ( i32 i32 -- i32 i32 ) T.i32 alloc-temp { a } T.i32 alloc-temp { b } a lset b lset a lget b lget ; immediate : over ( i32 i32 -- i32 i32 i32 ) T.i32 alloc-temp { a } T.i32 alloc-temp { b } a lset b lset b lget a lget b lget ; immediate : nip ( i32 i32 -- i32 ) T.i32 alloc-temp { a } T.i32 alloc-temp { b } a lset b lset a lget ; immediate : rot ( i32 i32 i32 -- i32 i32 i32 ) T.i32 alloc-temp { a } T.i32 alloc-temp { b } T.i32 alloc-temp { c } a lset b lset c lset b lget a lget c lget ; immediate : select ( i32 i32 i32 -- i32 ) 0x1b emit-u8 ; immediate \ Loads take (op align). Stores swap (val addr) to wasm's (addr val). \ fold-memarg rolls a preceding `i32.const N; i32.add` (N in 0..63) into offset. : emit-load ( i32 i32 -- ) \ op align fold-memarg { op align offset } op emit-u8 align emit-u8 offset emit-uleb ; immediate : emit-swap ( -- ) T.i32 alloc-temp { a } T.i32 alloc-temp { b } a lset b lset a lget b lget ; immediate : emit-store ( i32 i32 -- ) \ op align fold-memarg { op align offset } emit-swap op emit-u8 align emit-u8 offset emit-uleb ; immediate \ bulk memory: fc-prefix + 1-byte subop + memidx=0 wordlist mem mem edit : fill ( i32 i32 i32 -- ) 0xFC emit-u8 0x0B emit-u8 0x00 emit-u8 ; immediate : copy ( i32 i32 i32 -- ) 0xFC emit-u8 0x0A emit-u8 0x00 emit-u8 0x00 emit-u8 ; immediate save : @ ( i32 -- i32 ) 0x28 2 emit-load ; immediate : c@ ( i32 -- i32 ) 0x2d 0 emit-load ; immediate : w@ ( i32 -- i32 ) 0x2f 1 emit-load ; immediate : ! ( i32 i32 -- ) 0x36 2 emit-store ; immediate : c! ( i32 i32 -- ) 0x3a 0 emit-store ; immediate : w! ( i32 i32 -- ) 0x3b 1 emit-store ; immediate \ f32: bare names inside the f32 wordlist. `f32 open ... close` to use. : trunc_sat_f32_s ( f32 -- i32 ) 0xFC emit-u8 0x00 emit-u8 ; immediate : reinterpret_f32 ( f32 -- i32 ) 0xBC emit-u8 ; immediate : emit-f32-swap ( -- ) T.i32 alloc-temp { a } T.f32 alloc-temp { b } a lset b lset a lget b lget ; immediate wordlist f32 f32 edit : + ( f32 f32 -- f32 ) 0x92 emit-u8 ; immediate : - ( f32 f32 -- f32 ) 0x93 emit-u8 ; immediate : * ( f32 f32 -- f32 ) 0x94 emit-u8 ; immediate : / ( f32 f32 -- f32 ) 0x95 emit-u8 ; immediate : = ( f32 f32 -- i32 ) 0x5B emit-u8 ; immediate : <> ( f32 f32 -- i32 ) 0x5C emit-u8 ; immediate : < ( f32 f32 -- i32 ) 0x5D emit-u8 ; immediate : > ( f32 f32 -- i32 ) 0x5E emit-u8 ; immediate : <= ( f32 f32 -- i32 ) 0x5F emit-u8 ; immediate : >= ( f32 f32 -- i32 ) 0x60 emit-u8 ; immediate : abs ( f32 -- f32 ) 0x8B emit-u8 ; immediate : neg ( f32 -- f32 ) 0x8C emit-u8 ; immediate : sqrt ( f32 -- f32 ) 0x91 emit-u8 ; immediate : min ( f32 f32 -- f32 ) 0x96 emit-u8 ; immediate : max ( f32 f32 -- f32 ) 0x97 emit-u8 ; immediate : nearest ( f32 -- f32 ) 0x90 emit-u8 ; immediate : convert_i32_s ( i32 -- f32 ) 0xB2 emit-u8 ; immediate : dup ( f32 -- f32 f32 ) T.f32 alloc-temp { t } t ltee t lget ; immediate : swap ( f32 f32 -- f32 f32 ) T.f32 alloc-temp { a } T.f32 alloc-temp { b } a lset b lset a lget b lget ; immediate : @ ( i32 -- f32 ) 0x2A 2 emit-load ; immediate : ! ( f32 i32 -- ) fold-memarg { offset } emit-f32-swap 0x38 emit-u8 2 emit-u8 offset emit-uleb ; immediate save \ SIMD: simd. = 0xFD + uleb(subop). v128 wordlist holds type-agnostic ops; \ each lane width has its own. : simd. ( i32 -- ) 0xFD emit-u8 emit-uleb ; immediate \ v128.! needs (v128, i32) -> (i32, v128) swap, not the i32-specific one. : emit-v128-swap ( -- ) T.i32 alloc-temp { a } T.v128 alloc-temp { b } a lset b lset a lget b lget ; immediate wordlist v128 v128 edit : @ ( i32 -- v128 ) fold-memarg { offset } 0x00 simd. 4 emit-u8 offset emit-uleb ; immediate : ! ( v128 i32 -- ) fold-memarg { offset } emit-v128-swap 0x0B simd. 4 emit-u8 offset emit-uleb ; immediate : dup ( v128 -- v128 v128 ) T.v128 alloc-temp { t } t ltee t lget ; immediate : & ( v128 v128 -- v128 ) 0x4E simd. ; immediate : | ( v128 v128 -- v128 ) 0x50 simd. ; immediate : ^ ( v128 v128 -- v128 ) 0x51 simd. ; immediate : bitselect ( v128 v128 v128 -- v128 ) 0x52 simd. ; immediate save wordlist f32x4 f32x4 edit : splat ( f32 -- v128 ) 0x13 simd. ; immediate : + ( v128 v128 -- v128 ) 0xE4 simd. ; immediate : - ( v128 v128 -- v128 ) 0xE5 simd. ; immediate : * ( v128 v128 -- v128 ) 0xE6 simd. ; immediate : / ( v128 v128 -- v128 ) 0xE7 simd. ; immediate : lane0 ( v128 -- f32 ) 0x1F simd. 0 emit-u8 ; immediate : lane1 ( v128 -- f32 ) 0x1F simd. 1 emit-u8 ; immediate : lane2 ( v128 -- f32 ) 0x1F simd. 2 emit-u8 ; immediate : lane3 ( v128 -- f32 ) 0x1F simd. 3 emit-u8 ; immediate save wordlist i32x4 i32x4 edit : splat ( i32 -- v128 ) 0x11 simd. ; immediate : + ( v128 v128 -- v128 ) 0xAE simd. ; immediate : - ( v128 v128 -- v128 ) 0xB1 simd. ; immediate : * ( v128 v128 -- v128 ) 0xB5 simd. ; immediate : >>u ( v128 i32 -- v128 ) 0xAD simd. ; immediate : lane0 ( v128 -- i32 ) 0x1B simd. 0 emit-u8 ; immediate : lane1 ( v128 -- i32 ) 0x1B simd. 1 emit-u8 ; immediate : lane2 ( v128 -- i32 ) 0x1B simd. 2 emit-u8 ; immediate : lane3 ( v128 -- i32 ) 0x1B simd. 3 emit-u8 ; immediate save wordlist i16x8 i16x8 edit : narrow_i32x4_u ( v128 v128 -- v128 ) 0x86 simd. ; immediate save wordlist i8x16 i8x16 edit : splat ( i32 -- v128 ) 0x0F simd. ; immediate : swizzle ( v128 v128 -- v128 ) 0x0E simd. ; immediate : = ( v128 v128 -- v128 ) 0x23 simd. ; immediate : > ( v128 i32 -- v128 ) 0x6C simd. ; immediate save