mirror of
https://github.com/hanzoai/wasm2go.git
synced 2026-10-30 15:06:48 +00:00
* Support the wasm SIMD proposal with native asm lowering (arm64/amd64) One revision spanning the SIMD (0xfd v128) proposal end to end: SSA representation, lowering, scalar reference helpers, and a gcasm asm backend that turns the hot paths into native SIMD — measured on a full llama.cpp build transpiled to pure Go, which this makes run at V8-class speed (prompt eval beats V8 on arm64). Frontend and SSA: - v128 values are [2]uint64 pairs in little-endian lane order; pure ops lower to CSE-able helper calls, memory ops keep statement order, v128.const/shuffle ride as [2]uint64 aux. The full scalar helper set is the reference semantics (saturation, NaN propagation, round-to-even, swizzle OOB, shift masking). - Exception handling lowers to plain branches instead of panic/recover — a check-and-branch after each may-raise call, a per-try dispatch block running the catch-clause chain — covering the C++-shaped patterns (multi-clause catch, delegate targets, rethrow depths) without runtime unwinding, so EH bodies stay eligible for the asm backend. This replaces the closure/recover lowering that #39 extended; its tests are retained unchanged. - Giant functions outline into tractable units (whole loops included, packed u64 boundaries for v128 values), keeping gc compile times and register pressure sane on llama.cpp-sized modules. gcasm backend: - SIMD helper calls splice inline as native NEON/SSE instead of marshalled calls; v128 SSA values travel register-to-register in pair form. Call-tree windows fuse into single splices with region invariant hoisting, bounds-check coalescing, store sinks and scalar-chain internalization; whole countdown loops fuse with an in-splice unroll lane. - Superinstruction selection inside fused regions: 8-bit dot patterns (SMULL+SADALP), SDOT for full 16-byte dots, FMUL by element, scale-lookup addressing, inlined integer division, the software fp32->fp16 idiom lowered to FCVT (both the table-gather and the packed store form), and ggml q8_0 row/column pairing via the traits nrows patch with an SMMLA 2x2 tile kernel. - Runtime CPU-feature dispatch gates spliced bodies (dotprod on arm64, x86-64-v2 SSE on amd64); WASM2GO_FAST_MATH opts into raw-SDOT/FMLA/dual-accumulator forms that trade wasm bit-exactness for native-build-style rounding, validated by token-level equivalence against native llama.cpp. - Guard-page linear memory eliminates per-access bounds checks; jump tables replace the compare tree for br_table. Tooling and CI: - WASM2GO_F16_TABLE asserts the address of ggml's runtime-built f16 table; the transpiler warns when the asserted address matches no gather site (the address moves with every data-layout shift, and a stale assertion silently costs ~7% decode throughput). - The coverage gate runs with -count=1: a cached package result merges incomplete coverage data into the -coverpkg profile, deflating the total by 10+ points depending on what the runner's restored cache contained — the gate must never consume cached results. - Coverage threshold moves to 83% for the enlarged tree; transpile output is deterministic and outline rejections are explained in the build log. Co-Authored-By: Claude Fable 5 <[email protected]> * Replace environment-variable switches with typed Options; drop debug code Configuration now flows through one channel: transpile.Options gains OutlineMinValues, SIMDUnroll, FuseLoops, FuseLoopUnroll, F16TableAddr and FastMath (with matching CLI flags), the gcasm backend receives them as a Config threaded through ModuleOffsets, and no code path branches on an environment variable anymore. Integrator entry points (the wasmify protoc plugin, the CLI) convert their external configuration into these options exactly once. Deleted outright, per the no-env rule and because they were diagnostics rather than build modes: - every WASM2GO_NO_* kill switch and bisection knob (SSA pass disabling, fallback ranges, fuse-window caps, outline limits, inliner windows) — git history keeps them for the next hunt; - every env-gated debug printer (fuse/inline/outline/nrc2/f16/SSA dumps and the near-miss tracers) and the capture-tree keepers; - the dormant multi-exit loop structuring (opt-in, measured slower) and the SSA f32->f16 rewrite entry superseded by the gcasm peephole (its shared idiom matchers stay for the f16 store pass); - the runtime WASM2GO_CPU_PORTABLE override in the generated CPU feature probes. The nil-offsets error paths exposed by the threading get nil-safe Config accessors, and the outline share/v128-min/inliner caps become plain constants at their measured production values. Behavior under default options is unchanged: transpiled output for the non-SIMD and EH fixtures is byte-identical to the previous commit, and the only SIMD-bundle difference is the removed env check in the emitted cpufeat runtime files. Co-Authored-By: Claude Fable 5 <[email protected]> --------- Co-authored-by: Claude Fable 5 <[email protected]>
223 lines
12 KiB
Go
223 lines
12 KiB
Go
// Code generated by tools/gen-simd-asm/gen.py; DO NOT EDIT.
|
|
|
|
//go:build amd64.v2
|
|
|
|
package helpers
|
|
|
|
func simd_f32x4_abs(a [2]uint64) [2]uint64
|
|
func simd_f32x4_add(a, b [2]uint64) [2]uint64
|
|
func simd_f32x4_ceil(a [2]uint64) [2]uint64
|
|
func simd_f32x4_convert_i32x4_s(a [2]uint64) [2]uint64
|
|
func simd_f32x4_convert_i32x4_u(a [2]uint64) [2]uint64
|
|
func simd_f32x4_demote_f64x2_zero(a [2]uint64) [2]uint64
|
|
func simd_f32x4_div(a, b [2]uint64) [2]uint64
|
|
func simd_f32x4_eq(a, b [2]uint64) [2]uint64
|
|
func simd_f32x4_floor(a [2]uint64) [2]uint64
|
|
func simd_f32x4_ge(a, b [2]uint64) [2]uint64
|
|
func simd_f32x4_gt(a, b [2]uint64) [2]uint64
|
|
func simd_f32x4_le(a, b [2]uint64) [2]uint64
|
|
func simd_f32x4_lt(a, b [2]uint64) [2]uint64
|
|
func simd_f32x4_max(a, b [2]uint64) [2]uint64
|
|
func simd_f32x4_min(a, b [2]uint64) [2]uint64
|
|
func simd_f32x4_mul(a, b [2]uint64) [2]uint64
|
|
func simd_f32x4_ne(a, b [2]uint64) [2]uint64
|
|
func simd_f32x4_nearest(a [2]uint64) [2]uint64
|
|
func simd_f32x4_neg(a [2]uint64) [2]uint64
|
|
func simd_f32x4_pmax(a, b [2]uint64) [2]uint64
|
|
func simd_f32x4_pmin(a, b [2]uint64) [2]uint64
|
|
func simd_f32x4_splat(x float32) [2]uint64
|
|
func simd_f32x4_sqrt(a [2]uint64) [2]uint64
|
|
func simd_f32x4_sub(a, b [2]uint64) [2]uint64
|
|
func simd_f32x4_trunc(a [2]uint64) [2]uint64
|
|
func simd_f64x2_abs(a [2]uint64) [2]uint64
|
|
func simd_f64x2_add(a, b [2]uint64) [2]uint64
|
|
func simd_f64x2_ceil(a [2]uint64) [2]uint64
|
|
func simd_f64x2_convert_low_i32x4_s(a [2]uint64) [2]uint64
|
|
func simd_f64x2_convert_low_i32x4_u(a [2]uint64) [2]uint64
|
|
func simd_f64x2_div(a, b [2]uint64) [2]uint64
|
|
func simd_f64x2_eq(a, b [2]uint64) [2]uint64
|
|
func simd_f64x2_floor(a [2]uint64) [2]uint64
|
|
func simd_f64x2_ge(a, b [2]uint64) [2]uint64
|
|
func simd_f64x2_gt(a, b [2]uint64) [2]uint64
|
|
func simd_f64x2_le(a, b [2]uint64) [2]uint64
|
|
func simd_f64x2_lt(a, b [2]uint64) [2]uint64
|
|
func simd_f64x2_max(a, b [2]uint64) [2]uint64
|
|
func simd_f64x2_min(a, b [2]uint64) [2]uint64
|
|
func simd_f64x2_mul(a, b [2]uint64) [2]uint64
|
|
func simd_f64x2_ne(a, b [2]uint64) [2]uint64
|
|
func simd_f64x2_nearest(a [2]uint64) [2]uint64
|
|
func simd_f64x2_neg(a [2]uint64) [2]uint64
|
|
func simd_f64x2_pmax(a, b [2]uint64) [2]uint64
|
|
func simd_f64x2_pmin(a, b [2]uint64) [2]uint64
|
|
func simd_f64x2_promote_low_f32x4(a [2]uint64) [2]uint64
|
|
func simd_f64x2_splat(x float64) [2]uint64
|
|
func simd_f64x2_sqrt(a [2]uint64) [2]uint64
|
|
func simd_f64x2_sub(a, b [2]uint64) [2]uint64
|
|
func simd_f64x2_trunc(a [2]uint64) [2]uint64
|
|
func simd_i16x8_abs(a [2]uint64) [2]uint64
|
|
func simd_i16x8_add(a, b [2]uint64) [2]uint64
|
|
func simd_i16x8_add_sat_s(a, b [2]uint64) [2]uint64
|
|
func simd_i16x8_add_sat_u(a, b [2]uint64) [2]uint64
|
|
func simd_i16x8_all_true(a [2]uint64) int32
|
|
func simd_i16x8_avgr_u(a, b [2]uint64) [2]uint64
|
|
func simd_i16x8_bitmask(a [2]uint64) int32
|
|
func simd_i16x8_eq(a, b [2]uint64) [2]uint64
|
|
func simd_i16x8_extadd_pairwise_i8x16_s(a [2]uint64) [2]uint64
|
|
func simd_i16x8_extadd_pairwise_i8x16_u(a [2]uint64) [2]uint64
|
|
func simd_i16x8_extend_high_i8x16_s(a [2]uint64) [2]uint64
|
|
func simd_i16x8_extend_high_i8x16_u(a [2]uint64) [2]uint64
|
|
func simd_i16x8_extend_low_i8x16_s(a [2]uint64) [2]uint64
|
|
func simd_i16x8_extend_low_i8x16_u(a [2]uint64) [2]uint64
|
|
func simd_i16x8_extmul_high_i8x16_s(a, b [2]uint64) [2]uint64
|
|
func simd_i16x8_extmul_high_i8x16_u(a, b [2]uint64) [2]uint64
|
|
func simd_i16x8_extmul_low_i8x16_s(a, b [2]uint64) [2]uint64
|
|
func simd_i16x8_extmul_low_i8x16_u(a, b [2]uint64) [2]uint64
|
|
func simd_i16x8_ge_s(a, b [2]uint64) [2]uint64
|
|
func simd_i16x8_ge_u(a, b [2]uint64) [2]uint64
|
|
func simd_i16x8_gt_s(a, b [2]uint64) [2]uint64
|
|
func simd_i16x8_gt_u(a, b [2]uint64) [2]uint64
|
|
func simd_i16x8_le_s(a, b [2]uint64) [2]uint64
|
|
func simd_i16x8_le_u(a, b [2]uint64) [2]uint64
|
|
func simd_i16x8_lt_s(a, b [2]uint64) [2]uint64
|
|
func simd_i16x8_lt_u(a, b [2]uint64) [2]uint64
|
|
func simd_i16x8_max_s(a, b [2]uint64) [2]uint64
|
|
func simd_i16x8_max_u(a, b [2]uint64) [2]uint64
|
|
func simd_i16x8_min_s(a, b [2]uint64) [2]uint64
|
|
func simd_i16x8_min_u(a, b [2]uint64) [2]uint64
|
|
func simd_i16x8_mul(a, b [2]uint64) [2]uint64
|
|
func simd_i16x8_narrow_i32x4_s(a, b [2]uint64) [2]uint64
|
|
func simd_i16x8_narrow_i32x4_u(a, b [2]uint64) [2]uint64
|
|
func simd_i16x8_ne(a, b [2]uint64) [2]uint64
|
|
func simd_i16x8_neg(a [2]uint64) [2]uint64
|
|
func simd_i16x8_q15mulr_sat_s(a, b [2]uint64) [2]uint64
|
|
func simd_i16x8_shl(a [2]uint64, s int32) [2]uint64
|
|
func simd_i16x8_shr_s(a [2]uint64, s int32) [2]uint64
|
|
func simd_i16x8_shr_u(a [2]uint64, s int32) [2]uint64
|
|
func simd_i16x8_splat(x int32) [2]uint64
|
|
func simd_i16x8_sub(a, b [2]uint64) [2]uint64
|
|
func simd_i16x8_sub_sat_s(a, b [2]uint64) [2]uint64
|
|
func simd_i16x8_sub_sat_u(a, b [2]uint64) [2]uint64
|
|
func simd_i32x4_abs(a [2]uint64) [2]uint64
|
|
func simd_i32x4_add(a, b [2]uint64) [2]uint64
|
|
func simd_i32x4_all_true(a [2]uint64) int32
|
|
func simd_i32x4_bitmask(a [2]uint64) int32
|
|
func simd_i32x4_dot_i16x8_s(a, b [2]uint64) [2]uint64
|
|
func simd_i32x4_eq(a, b [2]uint64) [2]uint64
|
|
func simd_i32x4_extadd_pairwise_i16x8_s(a [2]uint64) [2]uint64
|
|
func simd_i32x4_extadd_pairwise_i16x8_u(a [2]uint64) [2]uint64
|
|
func simd_i32x4_extend_high_i16x8_s(a [2]uint64) [2]uint64
|
|
func simd_i32x4_extend_high_i16x8_u(a [2]uint64) [2]uint64
|
|
func simd_i32x4_extend_low_i16x8_s(a [2]uint64) [2]uint64
|
|
func simd_i32x4_extend_low_i16x8_u(a [2]uint64) [2]uint64
|
|
func simd_i32x4_extmul_high_i16x8_s(a, b [2]uint64) [2]uint64
|
|
func simd_i32x4_extmul_high_i16x8_u(a, b [2]uint64) [2]uint64
|
|
func simd_i32x4_extmul_low_i16x8_s(a, b [2]uint64) [2]uint64
|
|
func simd_i32x4_extmul_low_i16x8_u(a, b [2]uint64) [2]uint64
|
|
func simd_i32x4_ge_s(a, b [2]uint64) [2]uint64
|
|
func simd_i32x4_ge_u(a, b [2]uint64) [2]uint64
|
|
func simd_i32x4_gt_s(a, b [2]uint64) [2]uint64
|
|
func simd_i32x4_gt_u(a, b [2]uint64) [2]uint64
|
|
func simd_i32x4_le_s(a, b [2]uint64) [2]uint64
|
|
func simd_i32x4_le_u(a, b [2]uint64) [2]uint64
|
|
func simd_i32x4_lt_s(a, b [2]uint64) [2]uint64
|
|
func simd_i32x4_lt_u(a, b [2]uint64) [2]uint64
|
|
func simd_i32x4_max_s(a, b [2]uint64) [2]uint64
|
|
func simd_i32x4_max_u(a, b [2]uint64) [2]uint64
|
|
func simd_i32x4_min_s(a, b [2]uint64) [2]uint64
|
|
func simd_i32x4_min_u(a, b [2]uint64) [2]uint64
|
|
func simd_i32x4_mul(a, b [2]uint64) [2]uint64
|
|
func simd_i32x4_ne(a, b [2]uint64) [2]uint64
|
|
func simd_i32x4_neg(a [2]uint64) [2]uint64
|
|
func simd_i32x4_shl(a [2]uint64, s int32) [2]uint64
|
|
func simd_i32x4_shr_s(a [2]uint64, s int32) [2]uint64
|
|
func simd_i32x4_shr_u(a [2]uint64, s int32) [2]uint64
|
|
func simd_i32x4_splat(x int32) [2]uint64
|
|
func simd_i32x4_sub(a, b [2]uint64) [2]uint64
|
|
func simd_i32x4_trunc_sat_f32x4_s(a [2]uint64) [2]uint64
|
|
func simd_i32x4_trunc_sat_f32x4_u(a [2]uint64) [2]uint64
|
|
func simd_i32x4_trunc_sat_f64x2_s_zero(a [2]uint64) [2]uint64
|
|
func simd_i32x4_trunc_sat_f64x2_u_zero(a [2]uint64) [2]uint64
|
|
func simd_i64x2_abs(a [2]uint64) [2]uint64
|
|
func simd_i64x2_add(a, b [2]uint64) [2]uint64
|
|
func simd_i64x2_all_true(a [2]uint64) int32
|
|
func simd_i64x2_bitmask(a [2]uint64) int32
|
|
func simd_i64x2_eq(a, b [2]uint64) [2]uint64
|
|
func simd_i64x2_extend_high_i32x4_s(a [2]uint64) [2]uint64
|
|
func simd_i64x2_extend_high_i32x4_u(a [2]uint64) [2]uint64
|
|
func simd_i64x2_extend_low_i32x4_s(a [2]uint64) [2]uint64
|
|
func simd_i64x2_extend_low_i32x4_u(a [2]uint64) [2]uint64
|
|
func simd_i64x2_extmul_high_i32x4_s(a, b [2]uint64) [2]uint64
|
|
func simd_i64x2_extmul_high_i32x4_u(a, b [2]uint64) [2]uint64
|
|
func simd_i64x2_extmul_low_i32x4_s(a, b [2]uint64) [2]uint64
|
|
func simd_i64x2_extmul_low_i32x4_u(a, b [2]uint64) [2]uint64
|
|
func simd_i64x2_ge_s(a, b [2]uint64) [2]uint64
|
|
func simd_i64x2_gt_s(a, b [2]uint64) [2]uint64
|
|
func simd_i64x2_le_s(a, b [2]uint64) [2]uint64
|
|
func simd_i64x2_lt_s(a, b [2]uint64) [2]uint64
|
|
func simd_i64x2_ne(a, b [2]uint64) [2]uint64
|
|
func simd_i64x2_neg(a [2]uint64) [2]uint64
|
|
func simd_i64x2_shl(a [2]uint64, s int32) [2]uint64
|
|
func simd_i64x2_shr_u(a [2]uint64, s int32) [2]uint64
|
|
func simd_i64x2_splat(x int64) [2]uint64
|
|
func simd_i64x2_sub(a, b [2]uint64) [2]uint64
|
|
func simd_i8x16_abs(a [2]uint64) [2]uint64
|
|
func simd_i8x16_add(a, b [2]uint64) [2]uint64
|
|
func simd_i8x16_add_sat_s(a, b [2]uint64) [2]uint64
|
|
func simd_i8x16_add_sat_u(a, b [2]uint64) [2]uint64
|
|
func simd_i8x16_all_true(a [2]uint64) int32
|
|
func simd_i8x16_avgr_u(a, b [2]uint64) [2]uint64
|
|
func simd_i8x16_bitmask(a [2]uint64) int32
|
|
func simd_i8x16_eq(a, b [2]uint64) [2]uint64
|
|
func simd_i8x16_ge_s(a, b [2]uint64) [2]uint64
|
|
func simd_i8x16_ge_u(a, b [2]uint64) [2]uint64
|
|
func simd_i8x16_gt_s(a, b [2]uint64) [2]uint64
|
|
func simd_i8x16_gt_u(a, b [2]uint64) [2]uint64
|
|
func simd_i8x16_le_s(a, b [2]uint64) [2]uint64
|
|
func simd_i8x16_le_u(a, b [2]uint64) [2]uint64
|
|
func simd_i8x16_lt_s(a, b [2]uint64) [2]uint64
|
|
func simd_i8x16_lt_u(a, b [2]uint64) [2]uint64
|
|
func simd_i8x16_max_s(a, b [2]uint64) [2]uint64
|
|
func simd_i8x16_max_u(a, b [2]uint64) [2]uint64
|
|
func simd_i8x16_min_s(a, b [2]uint64) [2]uint64
|
|
func simd_i8x16_min_u(a, b [2]uint64) [2]uint64
|
|
func simd_i8x16_narrow_i16x8_s(a, b [2]uint64) [2]uint64
|
|
func simd_i8x16_narrow_i16x8_u(a, b [2]uint64) [2]uint64
|
|
func simd_i8x16_ne(a, b [2]uint64) [2]uint64
|
|
func simd_i8x16_neg(a [2]uint64) [2]uint64
|
|
func simd_i8x16_popcnt(a [2]uint64) [2]uint64
|
|
func simd_i8x16_shl(a [2]uint64, s int32) [2]uint64
|
|
func simd_i8x16_shr_s(a [2]uint64, s int32) [2]uint64
|
|
func simd_i8x16_shr_u(a [2]uint64, s int32) [2]uint64
|
|
func simd_i8x16_shuffle(a, b, pat [2]uint64) [2]uint64
|
|
func simd_i8x16_splat(x int32) [2]uint64
|
|
func simd_i8x16_sub(a, b [2]uint64) [2]uint64
|
|
func simd_i8x16_sub_sat_s(a, b [2]uint64) [2]uint64
|
|
func simd_i8x16_sub_sat_u(a, b [2]uint64) [2]uint64
|
|
func simd_i8x16_swizzle(a, s [2]uint64) [2]uint64
|
|
func simd_v128_and(a, b [2]uint64) [2]uint64
|
|
func simd_v128_andnot(a, b [2]uint64) [2]uint64
|
|
func simd_v128_any_true(a [2]uint64) int32
|
|
func simd_v128_bitselect(a, b, c [2]uint64) [2]uint64
|
|
func simd_v128_not(a [2]uint64) [2]uint64
|
|
func simd_v128_or(a, b [2]uint64) [2]uint64
|
|
func simd_v128_xor(a, b [2]uint64) [2]uint64
|
|
|
|
// Ops without a native body on this arch use the scalar reference.
|
|
func simd_f16x4_cvt_bits(a [2]uint64) int64 { return simd_f16x4_cvt_bits_scalar(a) }
|
|
func simd_f32x4_extract_lane(v [2]uint64, lane int32) float32 { return simd_f32x4_extract_lane_scalar(v, lane) }
|
|
func simd_f32x4_replace_lane(v [2]uint64, lane int32, x float32) [2]uint64 { return simd_f32x4_replace_lane_scalar(v, lane, x) }
|
|
func simd_f64x2_extract_lane(v [2]uint64, lane int32) float64 { return simd_f64x2_extract_lane_scalar(v, lane) }
|
|
func simd_f64x2_replace_lane(v [2]uint64, lane int32, x float64) [2]uint64 { return simd_f64x2_replace_lane_scalar(v, lane, x) }
|
|
func simd_i16x8_extract_lane_s(v [2]uint64, lane int32) int32 { return simd_i16x8_extract_lane_s_scalar(v, lane) }
|
|
func simd_i16x8_extract_lane_u(v [2]uint64, lane int32) int32 { return simd_i16x8_extract_lane_u_scalar(v, lane) }
|
|
func simd_i16x8_replace_lane(v [2]uint64, lane int32, x int32) [2]uint64 { return simd_i16x8_replace_lane_scalar(v, lane, x) }
|
|
func simd_i32x4_extract_lane(v [2]uint64, lane int32) int32 { return simd_i32x4_extract_lane_scalar(v, lane) }
|
|
func simd_i32x4_replace_lane(v [2]uint64, lane int32, x int32) [2]uint64 { return simd_i32x4_replace_lane_scalar(v, lane, x) }
|
|
func simd_i64x2_extract_lane(v [2]uint64, lane int32) int64 { return simd_i64x2_extract_lane_scalar(v, lane) }
|
|
func simd_i64x2_mul(a, b [2]uint64) [2]uint64 { return simd_i64x2_mul_scalar(a, b) }
|
|
func simd_i64x2_replace_lane(v [2]uint64, lane int32, x int64) [2]uint64 { return simd_i64x2_replace_lane_scalar(v, lane, x) }
|
|
func simd_i64x2_shr_s(a [2]uint64, s int32) [2]uint64 { return simd_i64x2_shr_s_scalar(a, s) }
|
|
func simd_i8x16_extract_lane_s(v [2]uint64, lane int32) int32 { return simd_i8x16_extract_lane_s_scalar(v, lane) }
|
|
func simd_i8x16_extract_lane_u(v [2]uint64, lane int32) int32 { return simd_i8x16_extract_lane_u_scalar(v, lane) }
|
|
func simd_i8x16_replace_lane(v [2]uint64, lane int32, x int32) [2]uint64 { return simd_i8x16_replace_lane_scalar(v, lane, x) }
|