use himada_core::HardwareDNA;
#[cfg(target_arch = "wasm32")]
pub fn dot_f64_wasm(a: &[f64], b: &[f64]) -> f64 {
use std::arch::wasm32::*;
let len = a.len().min(b.len());
let mut i = 0;
let mut acc = f64x2_splat(0.0);
unsafe {
while i + 2 <= len {
let va = v128_load(a.as_ptr().add(i) as *const v128);
let vb = v128_load(b.as_ptr().add(i) as *const v128);
acc = f64x2_add(acc, f64x2_mul(va, vb));
i += 2;
}
}
let tmp: [f64; 2] = unsafe { std::mem::transmute(acc) };
let mut sum = tmp[0] + tmp[1];
for j in i..len { sum += a[j] * b[j]; }
sum
}
#[cfg(target_arch = "wasm32")]
pub fn dot_f64_wasm_supported(_: &HardwareDNA) -> bool { true }
#[cfg(not(target_arch = "wasm32"))]
pub fn dot_f64_wasm(_: &[f64], _: &[f64]) -> f64 { 0.0 }
#[cfg(not(target_arch = "wasm32"))]
pub fn dot_f64_wasm_supported(_: &HardwareDNA) -> bool { false }
#[cfg(target_arch = "wasm32")]
pub fn reduce_sum_f64_wasm(a: &[f64]) -> f64 {
use std::arch::wasm32::*;
let len = a.len();
let mut i = 0;
let mut acc = f64x2_splat(0.0);
unsafe {
while i + 2 <= len {
let v = v128_load(a.as_ptr().add(i) as *const v128);
acc = f64x2_add(acc, v);
i += 2;
}
}
let tmp: [f64; 2] = unsafe { std::mem::transmute(acc) };
let mut sum = tmp[0] + tmp[1];
for j in i..len { sum += a[j]; }
sum
}
#[cfg(target_arch = "wasm32")]
pub fn reduce_sum_f64_wasm_supported(_: &HardwareDNA) -> bool { true }
#[cfg(not(target_arch = "wasm32"))]
pub fn reduce_sum_f64_wasm(_: &[f64]) -> f64 { 0.0 }
#[cfg(not(target_arch = "wasm32"))]
pub fn reduce_sum_f64_wasm_supported(_: &HardwareDNA) -> bool { false }
#[cfg(target_arch = "wasm32")]
pub fn reduce_max_f64_wasm(a: &[f64]) -> f64 {
use std::arch::wasm32::*;
let len = a.len();
if len == 0 { return f64::NEG_INFINITY; }
let mut i = 0;
let mut acc = f64x2_splat(f64::NEG_INFINITY);
unsafe {
while i + 2 <= len {
let v = v128_load(a.as_ptr().add(i) as *const v128);
acc = f64x2_max(acc, v);
i += 2;
}
}
let tmp: [f64; 2] = unsafe { std::mem::transmute(acc) };
let mut max = tmp[0].max(tmp[1]);
for j in i..len { if a[j] > max { max = a[j]; } }
max
}
#[cfg(target_arch = "wasm32")]
pub fn reduce_max_f64_wasm_supported(_: &HardwareDNA) -> bool { true }
#[cfg(not(target_arch = "wasm32"))]
pub fn reduce_max_f64_wasm(_: &[f64]) -> f64 { 0.0 }
#[cfg(not(target_arch = "wasm32"))]
pub fn reduce_max_f64_wasm_supported(_: &HardwareDNA) -> bool { false }
#[cfg(target_arch = "wasm32")]
pub fn abs_max_f64_wasm(a: &[f64]) -> f64 {
use std::arch::wasm32::*;
let len = a.len();
if len == 0 { return 0.0; }
let mut i = 0;
let mut acc = f64x2_splat(0.0);
unsafe {
while i + 2 <= len {
let v = v128_load(a.as_ptr().add(i) as *const v128);
acc = f64x2_max(acc, f64x2_abs(v));
i += 2;
}
}
let tmp: [f64; 2] = unsafe { std::mem::transmute(acc) };
let mut max = tmp[0].max(tmp[1]);
for j in i..len { let x = a[j].abs(); if x > max { max = x; } }
max
}
#[cfg(target_arch = "wasm32")]
pub fn abs_max_f64_wasm_supported(_: &HardwareDNA) -> bool { true }
#[cfg(not(target_arch = "wasm32"))]
pub fn abs_max_f64_wasm(_: &[f64]) -> f64 { 0.0 }
#[cfg(not(target_arch = "wasm32"))]
pub fn abs_max_f64_wasm_supported(_: &HardwareDNA) -> bool { false }
#[cfg(target_arch = "wasm32")]
pub fn hadamard_product_f64_wasm(a: &[f64], b: &[f64], out: &mut [f64]) {
use std::arch::wasm32::*;
let len = a.len().min(b.len()).min(out.len());
let mut i = 0;
unsafe {
while i + 2 <= len {
let va = v128_load(a.as_ptr().add(i) as *const v128);
let vb = v128_load(b.as_ptr().add(i) as *const v128);
v128_store(out.as_mut_ptr().add(i) as *mut v128, f64x2_mul(va, vb));
i += 2;
}
}
for j in i..len { out[j] = a[j] * b[j]; }
}
#[cfg(target_arch = "wasm32")]
pub fn hadamard_product_f64_wasm_supported(_: &HardwareDNA) -> bool { true }
#[cfg(not(target_arch = "wasm32"))]
pub fn hadamard_product_f64_wasm(_: &[f64], _: &[f64], _: &mut [f64]) {}
#[cfg(not(target_arch = "wasm32"))]
pub fn hadamard_product_f64_wasm_supported(_: &HardwareDNA) -> bool { false }
#[cfg(target_arch = "wasm32")]
pub fn add_f64_wasm(a: &[f64], b: &[f64], out: &mut [f64]) {
use std::arch::wasm32::*;
let len = a.len().min(b.len()).min(out.len());
let mut i = 0;
unsafe {
while i + 2 <= len {
let va = v128_load(a.as_ptr().add(i) as *const v128);
let vb = v128_load(b.as_ptr().add(i) as *const v128);
v128_store(out.as_mut_ptr().add(i) as *mut v128, f64x2_add(va, vb));
i += 2;
}
}
for j in i..len { out[j] = a[j] + b[j]; }
}
#[cfg(target_arch = "wasm32")]
pub fn add_f64_wasm_supported(_: &HardwareDNA) -> bool { true }
#[cfg(not(target_arch = "wasm32"))]
pub fn add_f64_wasm(_: &[f64], _: &[f64], _: &mut [f64]) {}
#[cfg(not(target_arch = "wasm32"))]
pub fn add_f64_wasm_supported(_: &HardwareDNA) -> bool { false }
#[cfg(target_arch = "wasm32")]
pub fn sub_f64_wasm(a: &[f64], b: &[f64], out: &mut [f64]) {
use std::arch::wasm32::*;
let len = a.len().min(b.len()).min(out.len());
let mut i = 0;
unsafe {
while i + 2 <= len {
let va = v128_load(a.as_ptr().add(i) as *const v128);
let vb = v128_load(b.as_ptr().add(i) as *const v128);
v128_store(out.as_mut_ptr().add(i) as *mut v128, f64x2_sub(va, vb));
i += 2;
}
}
for j in i..len { out[j] = a[j] - b[j]; }
}
#[cfg(target_arch = "wasm32")]
pub fn sub_f64_wasm_supported(_: &HardwareDNA) -> bool { true }
#[cfg(not(target_arch = "wasm32"))]
pub fn sub_f64_wasm(_: &[f64], _: &[f64], _: &mut [f64]) {}
#[cfg(not(target_arch = "wasm32"))]
pub fn sub_f64_wasm_supported(_: &HardwareDNA) -> bool { false }
#[cfg(target_arch = "wasm32")]
pub fn mul_f64_wasm(a: &[f64], b: &[f64], out: &mut [f64]) {
use std::arch::wasm32::*;
let len = a.len().min(b.len()).min(out.len());
let mut i = 0;
unsafe {
while i + 2 <= len {
let va = v128_load(a.as_ptr().add(i) as *const v128);
let vb = v128_load(b.as_ptr().add(i) as *const v128);
v128_store(out.as_mut_ptr().add(i) as *mut v128, f64x2_mul(va, vb));
i += 2;
}
}
for j in i..len { out[j] = a[j] * b[j]; }
}
#[cfg(target_arch = "wasm32")]
pub fn mul_f64_wasm_supported(_: &HardwareDNA) -> bool { true }
#[cfg(not(target_arch = "wasm32"))]
pub fn mul_f64_wasm(_: &[f64], _: &[f64], _: &mut [f64]) {}
#[cfg(not(target_arch = "wasm32"))]
pub fn mul_f64_wasm_supported(_: &HardwareDNA) -> bool { false }
#[cfg(target_arch = "wasm32")]
pub fn negate_f64_wasm(a: &[f64], out: &mut [f64]) {
use std::arch::wasm32::*;
let len = a.len().min(out.len());
let mut i = 0;
unsafe {
while i + 2 <= len {
let v = v128_load(a.as_ptr().add(i) as *const v128);
v128_store(out.as_mut_ptr().add(i) as *mut v128, f64x2_neg(v));
i += 2;
}
}
for j in i..len { out[j] = -a[j]; }
}
#[cfg(target_arch = "wasm32")]
pub fn negate_f64_wasm_supported(_: &HardwareDNA) -> bool { true }
#[cfg(not(target_arch = "wasm32"))]
pub fn negate_f64_wasm(_: &[f64], _: &mut [f64]) {}
#[cfg(not(target_arch = "wasm32"))]
pub fn negate_f64_wasm_supported(_: &HardwareDNA) -> bool { false }
#[cfg(target_arch = "wasm32")]
pub fn clamp_f64_wasm(a: &[f64], min: f64, max: f64, out: &mut [f64]) {
use std::arch::wasm32::*;
let len = a.len().min(out.len());
let mut i = 0;
let vmin = f64x2_splat(min);
let vmax = f64x2_splat(max);
unsafe {
while i + 2 <= len {
let v = v128_load(a.as_ptr().add(i) as *const v128);
v128_store(out.as_mut_ptr().add(i) as *mut v128, f64x2_max(f64x2_min(v, vmax), vmin));
i += 2;
}
}
for j in i..len { out[j] = a[j].clamp(min, max); }
}
#[cfg(target_arch = "wasm32")]
pub fn clamp_f64_wasm_supported(_: &HardwareDNA) -> bool { true }
#[cfg(not(target_arch = "wasm32"))]
pub fn clamp_f64_wasm(_: &[f64], _: f64, _: f64, _: &mut [f64]) {}
#[cfg(not(target_arch = "wasm32"))]
pub fn clamp_f64_wasm_supported(_: &HardwareDNA) -> bool { false }
#[cfg(target_arch = "wasm32")]
pub fn dot_f32_wasm(a: &[f32], b: &[f32]) -> f32 {
use std::arch::wasm32::*;
let len = a.len().min(b.len());
let mut i = 0;
let mut acc = f32x4_splat(0.0);
unsafe {
while i + 4 <= len {
let va = v128_load(a.as_ptr().add(i) as *const v128);
let vb = v128_load(b.as_ptr().add(i) as *const v128);
acc = f32x4_add(acc, f32x4_mul(va, vb));
i += 4;
}
}
let tmp: [f32; 4] = unsafe { std::mem::transmute(acc) };
let mut sum = tmp[0] + tmp[1] + tmp[2] + tmp[3];
for j in i..len { sum += a[j] * b[j]; }
sum
}
#[cfg(target_arch = "wasm32")]
pub fn dot_f32_wasm_supported(_: &HardwareDNA) -> bool { true }
#[cfg(not(target_arch = "wasm32"))]
pub fn dot_f32_wasm(_: &[f32], _: &[f32]) -> f32 { 0.0 }
#[cfg(not(target_arch = "wasm32"))]
pub fn dot_f32_wasm_supported(_: &HardwareDNA) -> bool { false }
#[cfg(target_arch = "wasm32")]
pub fn reduce_sum_f32_wasm(a: &[f32]) -> f32 {
use std::arch::wasm32::*;
let len = a.len();
let mut i = 0;
let mut acc = f32x4_splat(0.0);
unsafe {
while i + 4 <= len {
let v = v128_load(a.as_ptr().add(i) as *const v128);
acc = f32x4_add(acc, v);
i += 4;
}
}
let tmp: [f32; 4] = unsafe { std::mem::transmute(acc) };
let mut sum = tmp[0] + tmp[1] + tmp[2] + tmp[3];
for j in i..len { sum += a[j]; }
sum
}
#[cfg(target_arch = "wasm32")]
pub fn reduce_sum_f32_wasm_supported(_: &HardwareDNA) -> bool { true }
#[cfg(not(target_arch = "wasm32"))]
pub fn reduce_sum_f32_wasm(_: &[f32]) -> f32 { 0.0 }
#[cfg(not(target_arch = "wasm32"))]
pub fn reduce_sum_f32_wasm_supported(_: &HardwareDNA) -> bool { false }
#[cfg(target_arch = "wasm32")]
pub fn reduce_max_f32_wasm(a: &[f32]) -> f32 {
use std::arch::wasm32::*;
let len = a.len();
if len == 0 { return f32::NEG_INFINITY; }
let mut i = 0;
let mut acc = f32x4_splat(f32::NEG_INFINITY);
unsafe {
while i + 4 <= len {
let v = v128_load(a.as_ptr().add(i) as *const v128);
acc = f32x4_max(acc, v);
i += 4;
}
}
let tmp: [f32; 4] = unsafe { std::mem::transmute(acc) };
let mut max = tmp[0].max(tmp[1]).max(tmp[2]).max(tmp[3]);
for j in i..len { if a[j] > max { max = a[j]; } }
max
}
#[cfg(target_arch = "wasm32")]
pub fn reduce_max_f32_wasm_supported(_: &HardwareDNA) -> bool { true }
#[cfg(not(target_arch = "wasm32"))]
pub fn reduce_max_f32_wasm(_: &[f32]) -> f32 { 0.0 }
#[cfg(not(target_arch = "wasm32"))]
pub fn reduce_max_f32_wasm_supported(_: &HardwareDNA) -> bool { false }
#[cfg(target_arch = "wasm32")]
pub fn abs_max_f32_wasm(a: &[f32]) -> f32 {
use std::arch::wasm32::*;
let len = a.len();
if len == 0 { return 0.0; }
let mut i = 0;
let mut acc = f32x4_splat(0.0);
unsafe {
while i + 4 <= len {
let v = v128_load(a.as_ptr().add(i) as *const v128);
acc = f32x4_max(acc, f32x4_abs(v));
i += 4;
}
}
let tmp: [f32; 4] = unsafe { std::mem::transmute(acc) };
let mut max = tmp[0].max(tmp[1]).max(tmp[2]).max(tmp[3]);
for j in i..len { let x = a[j].abs(); if x > max { max = x; } }
max
}
#[cfg(target_arch = "wasm32")]
pub fn abs_max_f32_wasm_supported(_: &HardwareDNA) -> bool { true }
#[cfg(not(target_arch = "wasm32"))]
pub fn abs_max_f32_wasm(_: &[f32]) -> f32 { 0.0 }
#[cfg(not(target_arch = "wasm32"))]
pub fn abs_max_f32_wasm_supported(_: &HardwareDNA) -> bool { false }
#[cfg(target_arch = "wasm32")]
pub fn hadamard_product_f32_wasm(a: &[f32], b: &[f32], out: &mut [f32]) {
use std::arch::wasm32::*;
let len = a.len().min(b.len()).min(out.len());
let mut i = 0;
unsafe {
while i + 4 <= len {
let va = v128_load(a.as_ptr().add(i) as *const v128);
let vb = v128_load(b.as_ptr().add(i) as *const v128);
v128_store(out.as_mut_ptr().add(i) as *mut v128, f32x4_mul(va, vb));
i += 4;
}
}
for j in i..len { out[j] = a[j] * b[j]; }
}
#[cfg(target_arch = "wasm32")]
pub fn hadamard_product_f32_wasm_supported(_: &HardwareDNA) -> bool { true }
#[cfg(not(target_arch = "wasm32"))]
pub fn hadamard_product_f32_wasm(_: &[f32], _: &[f32], _: &mut [f32]) {}
#[cfg(not(target_arch = "wasm32"))]
pub fn hadamard_product_f32_wasm_supported(_: &HardwareDNA) -> bool { false }
#[cfg(target_arch = "wasm32")]
pub fn add_f32_wasm(a: &[f32], b: &[f32], out: &mut [f32]) {
use std::arch::wasm32::*;
let len = a.len().min(b.len()).min(out.len());
let mut i = 0;
unsafe {
while i + 4 <= len {
let va = v128_load(a.as_ptr().add(i) as *const v128);
let vb = v128_load(b.as_ptr().add(i) as *const v128);
v128_store(out.as_mut_ptr().add(i) as *mut v128, f32x4_add(va, vb));
i += 4;
}
}
for j in i..len { out[j] = a[j] + b[j]; }
}
#[cfg(target_arch = "wasm32")]
pub fn add_f32_wasm_supported(_: &HardwareDNA) -> bool { true }
#[cfg(not(target_arch = "wasm32"))]
pub fn add_f32_wasm(_: &[f32], _: &[f32], _: &mut [f32]) {}
#[cfg(not(target_arch = "wasm32"))]
pub fn add_f32_wasm_supported(_: &HardwareDNA) -> bool { false }
#[cfg(target_arch = "wasm32")]
pub fn sub_f32_wasm(a: &[f32], b: &[f32], out: &mut [f32]) {
use std::arch::wasm32::*;
let len = a.len().min(b.len()).min(out.len());
let mut i = 0;
unsafe {
while i + 4 <= len {
let va = v128_load(a.as_ptr().add(i) as *const v128);
let vb = v128_load(b.as_ptr().add(i) as *const v128);
v128_store(out.as_mut_ptr().add(i) as *mut v128, f32x4_sub(va, vb));
i += 4;
}
}
for j in i..len { out[j] = a[j] - b[j]; }
}
#[cfg(target_arch = "wasm32")]
pub fn sub_f32_wasm_supported(_: &HardwareDNA) -> bool { true }
#[cfg(not(target_arch = "wasm32"))]
pub fn sub_f32_wasm(_: &[f32], _: &[f32], _: &mut [f32]) {}
#[cfg(not(target_arch = "wasm32"))]
pub fn sub_f32_wasm_supported(_: &HardwareDNA) -> bool { false }
#[cfg(target_arch = "wasm32")]
pub fn mul_f32_wasm(a: &[f32], b: &[f32], out: &mut [f32]) {
use std::arch::wasm32::*;
let len = a.len().min(b.len()).min(out.len());
let mut i = 0;
unsafe {
while i + 4 <= len {
let va = v128_load(a.as_ptr().add(i) as *const v128);
let vb = v128_load(b.as_ptr().add(i) as *const v128);
v128_store(out.as_mut_ptr().add(i) as *mut v128, f32x4_mul(va, vb));
i += 4;
}
}
for j in i..len { out[j] = a[j] * b[j]; }
}
#[cfg(target_arch = "wasm32")]
pub fn mul_f32_wasm_supported(_: &HardwareDNA) -> bool { true }
#[cfg(not(target_arch = "wasm32"))]
pub fn mul_f32_wasm(_: &[f32], _: &[f32], _: &mut [f32]) {}
#[cfg(not(target_arch = "wasm32"))]
pub fn mul_f32_wasm_supported(_: &HardwareDNA) -> bool { false }
#[cfg(target_arch = "wasm32")]
pub fn negate_f32_wasm(a: &[f32], out: &mut [f32]) {
use std::arch::wasm32::*;
let len = a.len().min(out.len());
let mut i = 0;
unsafe {
while i + 4 <= len {
let v = v128_load(a.as_ptr().add(i) as *const v128);
v128_store(out.as_mut_ptr().add(i) as *mut v128, f32x4_neg(v));
i += 4;
}
}
for j in i..len { out[j] = -a[j]; }
}
#[cfg(target_arch = "wasm32")]
pub fn negate_f32_wasm_supported(_: &HardwareDNA) -> bool { true }
#[cfg(not(target_arch = "wasm32"))]
pub fn negate_f32_wasm(_: &[f32], _: &mut [f32]) {}
#[cfg(not(target_arch = "wasm32"))]
pub fn negate_f32_wasm_supported(_: &HardwareDNA) -> bool { false }
#[cfg(target_arch = "wasm32")]
pub fn clamp_f32_wasm(a: &[f32], min: f32, max: f32, out: &mut [f32]) {
use std::arch::wasm32::*;
let len = a.len().min(out.len());
let mut i = 0;
let vmin = f32x4_splat(min);
let vmax = f32x4_splat(max);
unsafe {
while i + 4 <= len {
let v = v128_load(a.as_ptr().add(i) as *const v128);
v128_store(out.as_mut_ptr().add(i) as *mut v128, f32x4_max(f32x4_min(v, vmax), vmin));
i += 4;
}
}
for j in i..len { out[j] = a[j].clamp(min, max); }
}
#[cfg(target_arch = "wasm32")]
pub fn clamp_f32_wasm_supported(_: &HardwareDNA) -> bool { true }
#[cfg(not(target_arch = "wasm32"))]
pub fn clamp_f32_wasm(_: &[f32], _: f32, _: f32, _: &mut [f32]) {}
#[cfg(not(target_arch = "wasm32"))]
pub fn clamp_f32_wasm_supported(_: &HardwareDNA) -> bool { false }
#[cfg(target_arch = "wasm32")]
pub fn dot_i32_wasm(a: &[i32], b: &[i32]) -> i32 {
use std::arch::wasm32::*;
let len = a.len().min(b.len());
let mut i = 0;
let mut acc = i32x4_splat(0);
unsafe {
while i + 4 <= len {
let va = v128_load(a.as_ptr().add(i) as *const v128);
let vb = v128_load(b.as_ptr().add(i) as *const v128);
acc = i32x4_add(acc, i32x4_mul(va, vb));
i += 4;
}
}
let tmp: [i32; 4] = unsafe { std::mem::transmute(acc) };
let mut sum = tmp[0] + tmp[1] + tmp[2] + tmp[3];
for j in i..len { sum += a[j] * b[j]; }
sum
}
#[cfg(target_arch = "wasm32")]
pub fn dot_i32_wasm_supported(_: &HardwareDNA) -> bool { true }
#[cfg(not(target_arch = "wasm32"))]
pub fn dot_i32_wasm(_: &[i32], _: &[i32]) -> i32 { 0 }
#[cfg(not(target_arch = "wasm32"))]
pub fn dot_i32_wasm_supported(_: &HardwareDNA) -> bool { false }
#[cfg(target_arch = "wasm32")]
pub fn reduce_sum_i32_wasm(a: &[i32]) -> i32 {
use std::arch::wasm32::*;
let len = a.len();
let mut i = 0;
let mut acc = i32x4_splat(0);
unsafe {
while i + 4 <= len {
let v = v128_load(a.as_ptr().add(i) as *const v128);
acc = i32x4_add(acc, v);
i += 4;
}
}
let tmp: [i32; 4] = unsafe { std::mem::transmute(acc) };
let mut sum = tmp[0] + tmp[1] + tmp[2] + tmp[3];
for j in i..len { sum += a[j]; }
sum
}
#[cfg(target_arch = "wasm32")]
pub fn reduce_sum_i32_wasm_supported(_: &HardwareDNA) -> bool { true }
#[cfg(not(target_arch = "wasm32"))]
pub fn reduce_sum_i32_wasm(_: &[i32]) -> i32 { 0 }
#[cfg(not(target_arch = "wasm32"))]
pub fn reduce_sum_i32_wasm_supported(_: &HardwareDNA) -> bool { false }
#[cfg(target_arch = "wasm32")]
pub fn reduce_max_i32_wasm(a: &[i32]) -> i32 {
use std::arch::wasm32::*;
let len = a.len();
if len == 0 { return i32::MIN; }
let mut i = 0;
let mut acc = i32x4_splat(i32::MIN);
unsafe {
while i + 4 <= len {
let v = v128_load(a.as_ptr().add(i) as *const v128);
acc = i32x4_max(acc, v);
i += 4;
}
}
let tmp: [i32; 4] = unsafe { std::mem::transmute(acc) };
let mut max = tmp[0].max(tmp[1]).max(tmp[2]).max(tmp[3]);
for j in i..len { if a[j] > max { max = a[j]; } }
max
}
#[cfg(target_arch = "wasm32")]
pub fn reduce_max_i32_wasm_supported(_: &HardwareDNA) -> bool { true }
#[cfg(not(target_arch = "wasm32"))]
pub fn reduce_max_i32_wasm(_: &[i32]) -> i32 { 0 }
#[cfg(not(target_arch = "wasm32"))]
pub fn reduce_max_i32_wasm_supported(_: &HardwareDNA) -> bool { false }
#[cfg(target_arch = "wasm32")]
pub fn abs_max_i32_wasm(a: &[i32]) -> i32 {
use std::arch::wasm32::*;
let len = a.len();
if len == 0 { return 0; }
let mut i = 0;
let mut acc = i32x4_splat(0);
unsafe {
while i + 4 <= len {
let v = v128_load(a.as_ptr().add(i) as *const v128);
acc = i32x4_max(acc, i32x4_abs(v));
i += 4;
}
}
let tmp: [i32; 4] = unsafe { std::mem::transmute(acc) };
let mut max = tmp[0].max(tmp[1]).max(tmp[2]).max(tmp[3]);
for j in i..len { let x = a[j].abs(); if x > max { max = x; } }
max
}
#[cfg(target_arch = "wasm32")]
pub fn abs_max_i32_wasm_supported(_: &HardwareDNA) -> bool { true }
#[cfg(not(target_arch = "wasm32"))]
pub fn abs_max_i32_wasm(_: &[i32]) -> i32 { 0 }
#[cfg(not(target_arch = "wasm32"))]
pub fn abs_max_i32_wasm_supported(_: &HardwareDNA) -> bool { false }
#[cfg(target_arch = "wasm32")]
pub fn hadamard_product_i32_wasm(a: &[i32], b: &[i32], out: &mut [i32]) {
use std::arch::wasm32::*;
let len = a.len().min(b.len()).min(out.len());
let mut i = 0;
unsafe {
while i + 4 <= len {
let va = v128_load(a.as_ptr().add(i) as *const v128);
let vb = v128_load(b.as_ptr().add(i) as *const v128);
v128_store(out.as_mut_ptr().add(i) as *mut v128, i32x4_mul(va, vb));
i += 4;
}
}
for j in i..len { out[j] = a[j] * b[j]; }
}
#[cfg(target_arch = "wasm32")]
pub fn hadamard_product_i32_wasm_supported(_: &HardwareDNA) -> bool { true }
#[cfg(not(target_arch = "wasm32"))]
pub fn hadamard_product_i32_wasm(_: &[i32], _: &[i32], _: &mut [i32]) {}
#[cfg(not(target_arch = "wasm32"))]
pub fn hadamard_product_i32_wasm_supported(_: &HardwareDNA) -> bool { false }
#[cfg(target_arch = "wasm32")]
pub fn add_i32_wasm(a: &[i32], b: &[i32], out: &mut [i32]) {
use std::arch::wasm32::*;
let len = a.len().min(b.len()).min(out.len());
let mut i = 0;
unsafe {
while i + 4 <= len {
let va = v128_load(a.as_ptr().add(i) as *const v128);
let vb = v128_load(b.as_ptr().add(i) as *const v128);
v128_store(out.as_mut_ptr().add(i) as *mut v128, i32x4_add(va, vb));
i += 4;
}
}
for j in i..len { out[j] = a[j] + b[j]; }
}
#[cfg(target_arch = "wasm32")]
pub fn add_i32_wasm_supported(_: &HardwareDNA) -> bool { true }
#[cfg(not(target_arch = "wasm32"))]
pub fn add_i32_wasm(_: &[i32], _: &[i32], _: &mut [i32]) {}
#[cfg(not(target_arch = "wasm32"))]
pub fn add_i32_wasm_supported(_: &HardwareDNA) -> bool { false }
#[cfg(target_arch = "wasm32")]
pub fn sub_i32_wasm(a: &[i32], b: &[i32], out: &mut [i32]) {
use std::arch::wasm32::*;
let len = a.len().min(b.len()).min(out.len());
let mut i = 0;
unsafe {
while i + 4 <= len {
let va = v128_load(a.as_ptr().add(i) as *const v128);
let vb = v128_load(b.as_ptr().add(i) as *const v128);
v128_store(out.as_mut_ptr().add(i) as *mut v128, i32x4_sub(va, vb));
i += 4;
}
}
for j in i..len { out[j] = a[j] - b[j]; }
}
#[cfg(target_arch = "wasm32")]
pub fn sub_i32_wasm_supported(_: &HardwareDNA) -> bool { true }
#[cfg(not(target_arch = "wasm32"))]
pub fn sub_i32_wasm(_: &[i32], _: &[i32], _: &mut [i32]) {}
#[cfg(not(target_arch = "wasm32"))]
pub fn sub_i32_wasm_supported(_: &HardwareDNA) -> bool { false }
#[cfg(target_arch = "wasm32")]
pub fn mul_i32_wasm(a: &[i32], b: &[i32], out: &mut [i32]) {
use std::arch::wasm32::*;
let len = a.len().min(b.len()).min(out.len());
let mut i = 0;
unsafe {
while i + 4 <= len {
let va = v128_load(a.as_ptr().add(i) as *const v128);
let vb = v128_load(b.as_ptr().add(i) as *const v128);
v128_store(out.as_mut_ptr().add(i) as *mut v128, i32x4_mul(va, vb));
i += 4;
}
}
for j in i..len { out[j] = a[j] * b[j]; }
}
#[cfg(target_arch = "wasm32")]
pub fn mul_i32_wasm_supported(_: &HardwareDNA) -> bool { true }
#[cfg(not(target_arch = "wasm32"))]
pub fn mul_i32_wasm(_: &[i32], _: &[i32], _: &mut [i32]) {}
#[cfg(not(target_arch = "wasm32"))]
pub fn mul_i32_wasm_supported(_: &HardwareDNA) -> bool { false }
#[cfg(target_arch = "wasm32")]
pub fn negate_i32_wasm(a: &[i32], out: &mut [i32]) {
use std::arch::wasm32::*;
let len = a.len().min(out.len());
let mut i = 0;
unsafe {
while i + 4 <= len {
let v = v128_load(a.as_ptr().add(i) as *const v128);
v128_store(out.as_mut_ptr().add(i) as *mut v128, i32x4_neg(v));
i += 4;
}
}
for j in i..len { out[j] = -a[j]; }
}
#[cfg(target_arch = "wasm32")]
pub fn negate_i32_wasm_supported(_: &HardwareDNA) -> bool { true }
#[cfg(not(target_arch = "wasm32"))]
pub fn negate_i32_wasm(_: &[i32], _: &mut [i32]) {}
#[cfg(not(target_arch = "wasm32"))]
pub fn negate_i32_wasm_supported(_: &HardwareDNA) -> bool { false }
#[cfg(target_arch = "wasm32")]
pub fn clamp_i32_wasm(a: &[i32], min: i32, max: i32, out: &mut [i32]) {
use std::arch::wasm32::*;
let len = a.len().min(out.len());
let mut i = 0;
let vmin = i32x4_splat(min);
let vmax = i32x4_splat(max);
unsafe {
while i + 4 <= len {
let v = v128_load(a.as_ptr().add(i) as *const v128);
v128_store(out.as_mut_ptr().add(i) as *mut v128, i32x4_max(i32x4_min(v, vmax), vmin));
i += 4;
}
}
for j in i..len { out[j] = a[j].clamp(min, max); }
}
#[cfg(target_arch = "wasm32")]
pub fn clamp_i32_wasm_supported(_: &HardwareDNA) -> bool { true }
#[cfg(not(target_arch = "wasm32"))]
pub fn clamp_i32_wasm(_: &[i32], _: i32, _: i32, _: &mut [i32]) {}
#[cfg(not(target_arch = "wasm32"))]
pub fn clamp_i32_wasm_supported(_: &HardwareDNA) -> bool { false }