Separate WAsm micro-kernels and scalar micro-kernels
- WAsm-specific microkernels explicitly use f32.min/f32.max WAsm instructions
- About 2% end-to-end improvement on x86, no change on ARM64
PiperOrigin-RevId: 283845483
diff --git a/src/f32-avgpool/mp9p8q-wasm.c b/src/f32-avgpool/mp9p8q-wasm.c
new file mode 100644
index 0000000..415b8fb
--- /dev/null
+++ b/src/f32-avgpool/mp9p8q-wasm.c
@@ -0,0 +1,170 @@
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/avgpool.h>
+#include <xnnpack/math.h>
+
+
+void xnn_f32_avgpool_ukernel_mp9p8q__wasm(
+ size_t n,
+ size_t ks,
+ size_t kc,
+ const float** input,
+ const float* zero,
+ float* buffer,
+ float* output,
+ size_t input_increment,
+ size_t output_increment,
+ const union xnn_f32_avgpool_params params[restrict static 1])
+{
+ assert(n != 0);
+ assert(ks > 9);
+ assert(kc != 0);
+
+ const float vmultiplier = params->scalar.multiplier;
+ const float voutput_min = params->scalar.output_min;
+ const float voutput_max = params->scalar.output_max;
+
+ do {
+ {
+ const float* i0 = *input++;
+ const float* i1 = *input++;
+ const float* i2 = *input++;
+ const float* i3 = *input++;
+ const float* i4 = *input++;
+ const float* i5 = *input++;
+ const float* i6 = *input++;
+ const float* i7 = *input++;
+ const float* i8 = *input++;
+
+ float* b = buffer;
+ size_t k = kc;
+ do {
+ const float vi0 = *i0++;
+ const float vi1 = *i1++;
+ const float vi2 = *i2++;
+ const float vi3 = *i3++;
+ const float vi4 = *i4++;
+ const float vi5 = *i5++;
+ const float vi6 = *i6++;
+ const float vi7 = *i7++;
+ const float vi8 = *i8++;
+
+ const float vsum01 = vi0 + vi1;
+ const float vsum23 = vi2 + vi3;
+ const float vsum45 = vi4 + vi5;
+ const float vsum67 = vi6 + vi7;
+ const float vsum018 = vsum01 + vi8;
+ const float vsum2345 = vsum23 + vsum45;
+ const float vsum01678 = vsum018 + vsum67;
+ const float vsum = vsum2345 + vsum01678;
+
+ *b++ = vsum;
+ } while (--k != 0);
+ }
+
+ size_t m = ks;
+ for (m -= 9; m > 8; m -= 8) {
+ const float* i0 = *input++;
+ const float* i1 = *input++;
+ const float* i2 = *input++;
+ const float* i3 = *input++;
+ const float* i4 = *input++;
+ const float* i5 = *input++;
+ const float* i6 = *input++;
+ const float* i7 = *input++;
+
+ float* b = buffer;
+ size_t k = kc;
+ do {
+ const float vi0 = *i0++;
+ const float vi1 = *i1++;
+ const float vi2 = *i2++;
+ const float vi3 = *i3++;
+ const float vi4 = *i4++;
+ const float vi5 = *i5++;
+ const float vi6 = *i6++;
+ const float vi7 = *i7++;
+ const float vacc = *b;
+
+ const float vsum01 = vi0 + vi1;
+ const float vsum23 = vi2 + vi3;
+ const float vsum45 = vi4 + vi5;
+ const float vsum67 = vi6 + vi7;
+ const float vsum01a = vsum01 + vacc;
+ const float vsum2345 = vsum23 + vsum45;
+ const float vsum0167a = vsum01a + vsum67;
+ const float vsum = vsum2345 + vsum0167a;
+
+ *b++ = vsum;
+ } while (--k != 0);
+ }
+
+ {
+ const float* i0 = input[0];
+ const float* i1 = input[1];
+ const float* i2 = input[2];
+ const float* i3 = input[3];
+ const float* i4 = input[4];
+ const float* i5 = input[5];
+ const float* i6 = input[6];
+ const float* i7 = input[7];
+ input = (const float**) ((uintptr_t) input + input_increment);
+ if (m < 2) {
+ i1 = zero;
+ }
+ if (m <= 2) {
+ i2 = zero;
+ }
+ if (m < 4) {
+ i3 = zero;
+ }
+ if (m <= 4) {
+ i4 = zero;
+ }
+ if (m < 6) {
+ i5 = zero;
+ }
+ if (m <= 6) {
+ i6 = zero;
+ }
+ if (m != 8) {
+ i7 = zero;
+ }
+
+ size_t k = kc;
+ float* b = buffer;
+ do {
+ const float vi0 = *i0++;
+ const float vi1 = *i1++;
+ const float vi2 = *i2++;
+ const float vi3 = *i3++;
+ const float vi4 = *i4++;
+ const float vi5 = *i5++;
+ const float vi6 = *i6++;
+ const float vi7 = *i7++;
+ const float vacc = *b++;
+
+ const float vsum01 = vi0 + vi1;
+ const float vsum23 = vi2 + vi3;
+ const float vsum45 = vi4 + vi5;
+ const float vsum67 = vi6 + vi7;
+ const float vsum01a = vsum01 + vacc;
+ const float vsum2345 = vsum23 + vsum45;
+ const float vsum0167a = vsum01a + vsum67;
+ const float vsum = vsum2345 + vsum0167a;
+
+ float vout = vsum * vmultiplier;
+ vout = __builtin_wasm_max_f32(vout, voutput_min);
+ vout = __builtin_wasm_min_f32(vout, voutput_max);
+
+ *output++ = vout;
+ } while (--k != 0);
+ }
+ output = (float*) ((uintptr_t) output + output_increment);
+ } while (--n != 0);
+}
diff --git a/src/f32-avgpool/up9-wasm.c b/src/f32-avgpool/up9-wasm.c
new file mode 100644
index 0000000..2f9a444
--- /dev/null
+++ b/src/f32-avgpool/up9-wasm.c
@@ -0,0 +1,97 @@
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/avgpool.h>
+#include <xnnpack/math.h>
+
+
+void xnn_f32_avgpool_ukernel_up9__wasm(
+ size_t n,
+ size_t ks,
+ size_t kc,
+ const float** input,
+ const float* zero,
+ float* output,
+ size_t input_increment,
+ size_t output_increment,
+ const union xnn_f32_avgpool_params params[restrict static 1])
+{
+ assert(n != 0);
+ assert(ks != 0);
+ assert(ks <= 9);
+ assert(kc != 0);
+
+ const float vmultiplier = params->scalar.multiplier;
+ const float voutput_min = params->scalar.output_min;
+ const float voutput_max = params->scalar.output_max;
+
+ do {
+ const float* i0 = input[0];
+ const float* i1 = input[1];
+ const float* i2 = input[2];
+ const float* i3 = input[3];
+ const float* i4 = input[4];
+ const float* i5 = input[5];
+ const float* i6 = input[6];
+ const float* i7 = input[7];
+ const float* i8 = input[8];
+ input = (const float**) ((uintptr_t) input + input_increment);
+ if (ks < 2) {
+ i1 = zero;
+ }
+ if (ks <= 2) {
+ i2 = zero;
+ }
+ if (ks < 4) {
+ i3 = zero;
+ }
+ if (ks <= 4) {
+ i4 = zero;
+ }
+ if (ks < 6) {
+ i5 = zero;
+ }
+ if (ks <= 6) {
+ i6 = zero;
+ }
+ if (ks < 8) {
+ i7 = zero;
+ }
+ if (ks <= 8) {
+ i8 = zero;
+ }
+
+ size_t k = kc;
+ do {
+ const float vi0 = *i0++;
+ const float vi1 = *i1++;
+ const float vi2 = *i2++;
+ const float vi3 = *i3++;
+ const float vi4 = *i4++;
+ const float vi5 = *i5++;
+ const float vi6 = *i6++;
+ const float vi7 = *i7++;
+ const float vi8 = *i8++;
+
+ const float vsum01 = vi0 + vi1;
+ const float vsum23 = vi2 + vi3;
+ const float vsum45 = vi4 + vi5;
+ const float vsum67 = vi6 + vi7;
+ const float vsum018 = vsum01 + vi8;
+ const float vsum2345 = vsum23 + vsum45;
+ const float vsum01678 = vsum018 + vsum67;
+ const float vsum = vsum2345 + vsum01678;
+
+ float vout = vsum * vmultiplier;
+ vout = __builtin_wasm_max_f32(vout, voutput_min);
+ vout = __builtin_wasm_min_f32(vout, voutput_max);
+
+ *output++ = vout;
+ } while (--k != 0);
+ output = (float*) ((uintptr_t) output + output_increment);
+ } while (--n != 0);
+}
diff --git a/src/f32-clamp/wasm.c b/src/f32-clamp/wasm.c
new file mode 100644
index 0000000..5dbf6c1
--- /dev/null
+++ b/src/f32-clamp/wasm.c
@@ -0,0 +1,44 @@
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/clamp.h>
+#include <xnnpack/math.h>
+
+
+void xnn_f32_clamp_ukernel__wasm(
+ size_t n,
+ const float* x,
+ float* y,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(n != 0);
+ assert(n % sizeof(float) == 0);
+
+ const float vy_max = params->scalar.max;
+ const float vy_min = params->scalar.min;
+
+ for (; n >= 2 * sizeof(float); n -= 2 * sizeof(float)) {
+ const float vx0 = x[0];
+ const float vx1 = x[1];
+ x += 2;
+
+ float vy0 = __builtin_wasm_max_f32(vx0, vy_min);
+ float vy1 = __builtin_wasm_max_f32(vx1, vy_min);
+ vy0 = __builtin_wasm_min_f32(vy0, vy_max);
+ vy1 = __builtin_wasm_min_f32(vy1, vy_max);
+
+ y[0] = vy0;
+ y[1] = vy1;
+ y += 2;
+ }
+ if (n != 0) {
+ const float vx = *x;
+ float vy = __builtin_wasm_max_f32(vx, vy_min);
+ vy = __builtin_wasm_min_f32(vy, vy_max);
+ *y = vy;
+ }
+}
diff --git a/src/f32-dwconv/gen/up1x25-wasm-acc2.c b/src/f32-dwconv/gen/up1x25-wasm-acc2.c
new file mode 100644
index 0000000..599629b
--- /dev/null
+++ b/src/f32-dwconv/gen/up1x25-wasm-acc2.c
@@ -0,0 +1,176 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-dwconv/up-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/dwconv.h>
+#include <xnnpack/math.h>
+
+
+void xnn_f32_dwconv_ukernel_up1x25__wasm_acc2(
+ size_t channels,
+ size_t output_width,
+ const float** input,
+ const float* weights,
+ float* output,
+ size_t input_stride,
+ size_t output_increment,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(channels != 0);
+ assert(output_width != 0);
+
+ const float vmin = params->scalar.min;
+ const float vmax = params->scalar.max;
+ do {
+ const float* i0 = input[0];
+ const float* i1 = input[1];
+ const float* i2 = input[2];
+ const float* i3 = input[3];
+ const float* i4 = input[4];
+ const float* i5 = input[5];
+ const float* i6 = input[6];
+ const float* i7 = input[7];
+ const float* i8 = input[8];
+ const float* i9 = input[9];
+ const float* i10 = input[10];
+ const float* i11 = input[11];
+ const float* i12 = input[12];
+ const float* i13 = input[13];
+ const float* i14 = input[14];
+ const float* i15 = input[15];
+ const float* i16 = input[16];
+ const float* i17 = input[17];
+ const float* i18 = input[18];
+ const float* i19 = input[19];
+ const float* i20 = input[20];
+ const float* i21 = input[21];
+ const float* i22 = input[22];
+ const float* i23 = input[23];
+ const float* i24 = input[24];
+ input = (const float**) ((uintptr_t) input + input_stride);
+
+ size_t c = channels;
+ const float* w = weights;
+ do {
+ float vacc0p0 = w[0];
+
+ const float vi0 = *i0++;
+ const float vk0 = w[1];
+ vacc0p0 += vi0 * vk0;
+
+ const float vi1 = *i1++;
+ const float vk1 = w[2];
+ float vacc0p1 = vi1 * vk1;
+
+ const float vi2 = *i2++;
+ const float vk2 = w[3];
+ vacc0p0 += vi2 * vk2;
+
+ const float vi3 = *i3++;
+ const float vk3 = w[4];
+ vacc0p1 += vi3 * vk3;
+
+ const float vi4 = *i4++;
+ const float vk4 = w[5];
+ vacc0p0 += vi4 * vk4;
+
+ const float vi5 = *i5++;
+ const float vk5 = w[6];
+ vacc0p1 += vi5 * vk5;
+
+ const float vi6 = *i6++;
+ const float vk6 = w[7];
+ vacc0p0 += vi6 * vk6;
+
+ const float vi7 = *i7++;
+ const float vk7 = w[8];
+ vacc0p1 += vi7 * vk7;
+
+ const float vi8 = *i8++;
+ const float vk8 = w[9];
+ vacc0p0 += vi8 * vk8;
+
+ const float vi9 = *i9++;
+ const float vk9 = w[10];
+ vacc0p1 += vi9 * vk9;
+
+ const float vi10 = *i10++;
+ const float vk10 = w[11];
+ vacc0p0 += vi10 * vk10;
+
+ const float vi11 = *i11++;
+ const float vk11 = w[12];
+ vacc0p1 += vi11 * vk11;
+
+ const float vi12 = *i12++;
+ const float vk12 = w[13];
+ vacc0p0 += vi12 * vk12;
+
+ const float vi13 = *i13++;
+ const float vk13 = w[14];
+ vacc0p1 += vi13 * vk13;
+
+ const float vi14 = *i14++;
+ const float vk14 = w[15];
+ vacc0p0 += vi14 * vk14;
+
+ const float vi15 = *i15++;
+ const float vk15 = w[16];
+ vacc0p1 += vi15 * vk15;
+
+ const float vi16 = *i16++;
+ const float vk16 = w[17];
+ vacc0p0 += vi16 * vk16;
+
+ const float vi17 = *i17++;
+ const float vk17 = w[18];
+ vacc0p1 += vi17 * vk17;
+
+ const float vi18 = *i18++;
+ const float vk18 = w[19];
+ vacc0p0 += vi18 * vk18;
+
+ const float vi19 = *i19++;
+ const float vk19 = w[20];
+ vacc0p1 += vi19 * vk19;
+
+ const float vi20 = *i20++;
+ const float vk20 = w[21];
+ vacc0p0 += vi20 * vk20;
+
+ const float vi21 = *i21++;
+ const float vk21 = w[22];
+ vacc0p1 += vi21 * vk21;
+
+ const float vi22 = *i22++;
+ const float vk22 = w[23];
+ vacc0p0 += vi22 * vk22;
+
+ const float vi23 = *i23++;
+ const float vk23 = w[24];
+ vacc0p1 += vi23 * vk23;
+
+ const float vi24 = *i24++;
+ const float vk24 = w[25];
+ vacc0p0 += vi24 * vk24;
+
+ w += 26;
+
+ vacc0p0 += vacc0p1;
+
+ float vacc0 = __builtin_wasm_max_f32(vacc0p0, vmin);
+ vacc0 = __builtin_wasm_min_f32(vacc0, vmax);
+
+ *output++ = vacc0;
+ } while (--c != 0);
+
+ output = (float*) ((uintptr_t) output + output_increment);
+ } while (--output_width != 0);
+}
diff --git a/src/f32-dwconv/gen/up1x25-wasm.c b/src/f32-dwconv/gen/up1x25-wasm.c
new file mode 100644
index 0000000..d4b8185
--- /dev/null
+++ b/src/f32-dwconv/gen/up1x25-wasm.c
@@ -0,0 +1,175 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-dwconv/up-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/dwconv.h>
+#include <xnnpack/math.h>
+
+
+void xnn_f32_dwconv_ukernel_up1x25__wasm(
+ size_t channels,
+ size_t output_width,
+ const float** input,
+ const float* weights,
+ float* output,
+ size_t input_stride,
+ size_t output_increment,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(channels != 0);
+ assert(output_width != 0);
+
+ const float vmin = params->scalar.min;
+ const float vmax = params->scalar.max;
+ do {
+ const float* i0 = input[0];
+ const float* i1 = input[1];
+ const float* i2 = input[2];
+ const float* i3 = input[3];
+ const float* i4 = input[4];
+ const float* i5 = input[5];
+ const float* i6 = input[6];
+ const float* i7 = input[7];
+ const float* i8 = input[8];
+ const float* i9 = input[9];
+ const float* i10 = input[10];
+ const float* i11 = input[11];
+ const float* i12 = input[12];
+ const float* i13 = input[13];
+ const float* i14 = input[14];
+ const float* i15 = input[15];
+ const float* i16 = input[16];
+ const float* i17 = input[17];
+ const float* i18 = input[18];
+ const float* i19 = input[19];
+ const float* i20 = input[20];
+ const float* i21 = input[21];
+ const float* i22 = input[22];
+ const float* i23 = input[23];
+ const float* i24 = input[24];
+ input = (const float**) ((uintptr_t) input + input_stride);
+
+ size_t c = channels;
+ const float* w = weights;
+ do {
+ float vacc0p0 = w[0];
+
+ const float vi0 = *i0++;
+ const float vk0 = w[1];
+ vacc0p0 += vi0 * vk0;
+
+ const float vi1 = *i1++;
+ const float vk1 = w[2];
+ vacc0p0 += vi1 * vk1;
+
+ const float vi2 = *i2++;
+ const float vk2 = w[3];
+ vacc0p0 += vi2 * vk2;
+
+ const float vi3 = *i3++;
+ const float vk3 = w[4];
+ vacc0p0 += vi3 * vk3;
+
+ const float vi4 = *i4++;
+ const float vk4 = w[5];
+ vacc0p0 += vi4 * vk4;
+
+ const float vi5 = *i5++;
+ const float vk5 = w[6];
+ vacc0p0 += vi5 * vk5;
+
+ const float vi6 = *i6++;
+ const float vk6 = w[7];
+ vacc0p0 += vi6 * vk6;
+
+ const float vi7 = *i7++;
+ const float vk7 = w[8];
+ vacc0p0 += vi7 * vk7;
+
+ const float vi8 = *i8++;
+ const float vk8 = w[9];
+ vacc0p0 += vi8 * vk8;
+
+ const float vi9 = *i9++;
+ const float vk9 = w[10];
+ vacc0p0 += vi9 * vk9;
+
+ const float vi10 = *i10++;
+ const float vk10 = w[11];
+ vacc0p0 += vi10 * vk10;
+
+ const float vi11 = *i11++;
+ const float vk11 = w[12];
+ vacc0p0 += vi11 * vk11;
+
+ const float vi12 = *i12++;
+ const float vk12 = w[13];
+ vacc0p0 += vi12 * vk12;
+
+ const float vi13 = *i13++;
+ const float vk13 = w[14];
+ vacc0p0 += vi13 * vk13;
+
+ const float vi14 = *i14++;
+ const float vk14 = w[15];
+ vacc0p0 += vi14 * vk14;
+
+ const float vi15 = *i15++;
+ const float vk15 = w[16];
+ vacc0p0 += vi15 * vk15;
+
+ const float vi16 = *i16++;
+ const float vk16 = w[17];
+ vacc0p0 += vi16 * vk16;
+
+ const float vi17 = *i17++;
+ const float vk17 = w[18];
+ vacc0p0 += vi17 * vk17;
+
+ const float vi18 = *i18++;
+ const float vk18 = w[19];
+ vacc0p0 += vi18 * vk18;
+
+ const float vi19 = *i19++;
+ const float vk19 = w[20];
+ vacc0p0 += vi19 * vk19;
+
+ const float vi20 = *i20++;
+ const float vk20 = w[21];
+ vacc0p0 += vi20 * vk20;
+
+ const float vi21 = *i21++;
+ const float vk21 = w[22];
+ vacc0p0 += vi21 * vk21;
+
+ const float vi22 = *i22++;
+ const float vk22 = w[23];
+ vacc0p0 += vi22 * vk22;
+
+ const float vi23 = *i23++;
+ const float vk23 = w[24];
+ vacc0p0 += vi23 * vk23;
+
+ const float vi24 = *i24++;
+ const float vk24 = w[25];
+ vacc0p0 += vi24 * vk24;
+
+ w += 26;
+
+
+ float vacc0 = __builtin_wasm_max_f32(vacc0p0, vmin);
+ vacc0 = __builtin_wasm_min_f32(vacc0, vmax);
+
+ *output++ = vacc0;
+ } while (--c != 0);
+
+ output = (float*) ((uintptr_t) output + output_increment);
+ } while (--output_width != 0);
+}
diff --git a/src/f32-dwconv/gen/up1x4-wasm-acc2.c b/src/f32-dwconv/gen/up1x4-wasm-acc2.c
new file mode 100644
index 0000000..a54b065
--- /dev/null
+++ b/src/f32-dwconv/gen/up1x4-wasm-acc2.c
@@ -0,0 +1,71 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-dwconv/up-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/dwconv.h>
+#include <xnnpack/math.h>
+
+
+void xnn_f32_dwconv_ukernel_up1x4__wasm_acc2(
+ size_t channels,
+ size_t output_width,
+ const float** input,
+ const float* weights,
+ float* output,
+ size_t input_stride,
+ size_t output_increment,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(channels != 0);
+ assert(output_width != 0);
+
+ const float vmin = params->scalar.min;
+ const float vmax = params->scalar.max;
+ do {
+ const float* i0 = input[0];
+ const float* i1 = input[1];
+ const float* i2 = input[2];
+ const float* i3 = input[3];
+ input = (const float**) ((uintptr_t) input + input_stride);
+
+ size_t c = channels;
+ const float* w = weights;
+ do {
+ float vacc0p0 = w[0];
+
+ const float vi0 = *i0++;
+ const float vk0 = w[1];
+ vacc0p0 += vi0 * vk0;
+
+ const float vi1 = *i1++;
+ const float vk1 = w[2];
+ float vacc0p1 = vi1 * vk1;
+
+ const float vi2 = *i2++;
+ const float vk2 = w[3];
+ vacc0p0 += vi2 * vk2;
+
+ const float vi3 = *i3++;
+ const float vk3 = w[4];
+ vacc0p1 += vi3 * vk3;
+
+ w += 5;
+
+ vacc0p0 += vacc0p1;
+
+ float vacc0 = __builtin_wasm_max_f32(vacc0p0, vmin);
+ vacc0 = __builtin_wasm_min_f32(vacc0, vmax);
+
+ *output++ = vacc0;
+ } while (--c != 0);
+
+ output = (float*) ((uintptr_t) output + output_increment);
+ } while (--output_width != 0);
+}
diff --git a/src/f32-dwconv/gen/up1x4-wasm.c b/src/f32-dwconv/gen/up1x4-wasm.c
new file mode 100644
index 0000000..b0f1e1d
--- /dev/null
+++ b/src/f32-dwconv/gen/up1x4-wasm.c
@@ -0,0 +1,70 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-dwconv/up-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/dwconv.h>
+#include <xnnpack/math.h>
+
+
+void xnn_f32_dwconv_ukernel_up1x4__wasm(
+ size_t channels,
+ size_t output_width,
+ const float** input,
+ const float* weights,
+ float* output,
+ size_t input_stride,
+ size_t output_increment,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(channels != 0);
+ assert(output_width != 0);
+
+ const float vmin = params->scalar.min;
+ const float vmax = params->scalar.max;
+ do {
+ const float* i0 = input[0];
+ const float* i1 = input[1];
+ const float* i2 = input[2];
+ const float* i3 = input[3];
+ input = (const float**) ((uintptr_t) input + input_stride);
+
+ size_t c = channels;
+ const float* w = weights;
+ do {
+ float vacc0p0 = w[0];
+
+ const float vi0 = *i0++;
+ const float vk0 = w[1];
+ vacc0p0 += vi0 * vk0;
+
+ const float vi1 = *i1++;
+ const float vk1 = w[2];
+ vacc0p0 += vi1 * vk1;
+
+ const float vi2 = *i2++;
+ const float vk2 = w[3];
+ vacc0p0 += vi2 * vk2;
+
+ const float vi3 = *i3++;
+ const float vk3 = w[4];
+ vacc0p0 += vi3 * vk3;
+
+ w += 5;
+
+
+ float vacc0 = __builtin_wasm_max_f32(vacc0p0, vmin);
+ vacc0 = __builtin_wasm_min_f32(vacc0, vmax);
+
+ *output++ = vacc0;
+ } while (--c != 0);
+
+ output = (float*) ((uintptr_t) output + output_increment);
+ } while (--output_width != 0);
+}
diff --git a/src/f32-dwconv/gen/up1x9-wasm-acc2.c b/src/f32-dwconv/gen/up1x9-wasm-acc2.c
new file mode 100644
index 0000000..758a09b
--- /dev/null
+++ b/src/f32-dwconv/gen/up1x9-wasm-acc2.c
@@ -0,0 +1,96 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-dwconv/up-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/dwconv.h>
+#include <xnnpack/math.h>
+
+
+void xnn_f32_dwconv_ukernel_up1x9__wasm_acc2(
+ size_t channels,
+ size_t output_width,
+ const float** input,
+ const float* weights,
+ float* output,
+ size_t input_stride,
+ size_t output_increment,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(channels != 0);
+ assert(output_width != 0);
+
+ const float vmin = params->scalar.min;
+ const float vmax = params->scalar.max;
+ do {
+ const float* i0 = input[0];
+ const float* i1 = input[1];
+ const float* i2 = input[2];
+ const float* i3 = input[3];
+ const float* i4 = input[4];
+ const float* i5 = input[5];
+ const float* i6 = input[6];
+ const float* i7 = input[7];
+ const float* i8 = input[8];
+ input = (const float**) ((uintptr_t) input + input_stride);
+
+ size_t c = channels;
+ const float* w = weights;
+ do {
+ float vacc0p0 = w[0];
+
+ const float vi0 = *i0++;
+ const float vk0 = w[1];
+ vacc0p0 += vi0 * vk0;
+
+ const float vi1 = *i1++;
+ const float vk1 = w[2];
+ float vacc0p1 = vi1 * vk1;
+
+ const float vi2 = *i2++;
+ const float vk2 = w[3];
+ vacc0p0 += vi2 * vk2;
+
+ const float vi3 = *i3++;
+ const float vk3 = w[4];
+ vacc0p1 += vi3 * vk3;
+
+ const float vi4 = *i4++;
+ const float vk4 = w[5];
+ vacc0p0 += vi4 * vk4;
+
+ const float vi5 = *i5++;
+ const float vk5 = w[6];
+ vacc0p1 += vi5 * vk5;
+
+ const float vi6 = *i6++;
+ const float vk6 = w[7];
+ vacc0p0 += vi6 * vk6;
+
+ const float vi7 = *i7++;
+ const float vk7 = w[8];
+ vacc0p1 += vi7 * vk7;
+
+ const float vi8 = *i8++;
+ const float vk8 = w[9];
+ vacc0p0 += vi8 * vk8;
+
+ w += 10;
+
+ vacc0p0 += vacc0p1;
+
+ float vacc0 = __builtin_wasm_max_f32(vacc0p0, vmin);
+ vacc0 = __builtin_wasm_min_f32(vacc0, vmax);
+
+ *output++ = vacc0;
+ } while (--c != 0);
+
+ output = (float*) ((uintptr_t) output + output_increment);
+ } while (--output_width != 0);
+}
diff --git a/src/f32-dwconv/gen/up1x9-wasm.c b/src/f32-dwconv/gen/up1x9-wasm.c
new file mode 100644
index 0000000..8292a75
--- /dev/null
+++ b/src/f32-dwconv/gen/up1x9-wasm.c
@@ -0,0 +1,95 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-dwconv/up-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/dwconv.h>
+#include <xnnpack/math.h>
+
+
+void xnn_f32_dwconv_ukernel_up1x9__wasm(
+ size_t channels,
+ size_t output_width,
+ const float** input,
+ const float* weights,
+ float* output,
+ size_t input_stride,
+ size_t output_increment,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(channels != 0);
+ assert(output_width != 0);
+
+ const float vmin = params->scalar.min;
+ const float vmax = params->scalar.max;
+ do {
+ const float* i0 = input[0];
+ const float* i1 = input[1];
+ const float* i2 = input[2];
+ const float* i3 = input[3];
+ const float* i4 = input[4];
+ const float* i5 = input[5];
+ const float* i6 = input[6];
+ const float* i7 = input[7];
+ const float* i8 = input[8];
+ input = (const float**) ((uintptr_t) input + input_stride);
+
+ size_t c = channels;
+ const float* w = weights;
+ do {
+ float vacc0p0 = w[0];
+
+ const float vi0 = *i0++;
+ const float vk0 = w[1];
+ vacc0p0 += vi0 * vk0;
+
+ const float vi1 = *i1++;
+ const float vk1 = w[2];
+ vacc0p0 += vi1 * vk1;
+
+ const float vi2 = *i2++;
+ const float vk2 = w[3];
+ vacc0p0 += vi2 * vk2;
+
+ const float vi3 = *i3++;
+ const float vk3 = w[4];
+ vacc0p0 += vi3 * vk3;
+
+ const float vi4 = *i4++;
+ const float vk4 = w[5];
+ vacc0p0 += vi4 * vk4;
+
+ const float vi5 = *i5++;
+ const float vk5 = w[6];
+ vacc0p0 += vi5 * vk5;
+
+ const float vi6 = *i6++;
+ const float vk6 = w[7];
+ vacc0p0 += vi6 * vk6;
+
+ const float vi7 = *i7++;
+ const float vk7 = w[8];
+ vacc0p0 += vi7 * vk7;
+
+ const float vi8 = *i8++;
+ const float vk8 = w[9];
+ vacc0p0 += vi8 * vk8;
+
+ w += 10;
+
+
+ float vacc0 = __builtin_wasm_max_f32(vacc0p0, vmin);
+ vacc0 = __builtin_wasm_min_f32(vacc0, vmax);
+
+ *output++ = vacc0;
+ } while (--c != 0);
+
+ output = (float*) ((uintptr_t) output + output_increment);
+ } while (--output_width != 0);
+}
diff --git a/src/f32-dwconv/gen/up2x25-wasm-acc2.c b/src/f32-dwconv/gen/up2x25-wasm-acc2.c
new file mode 100644
index 0000000..e411a68
--- /dev/null
+++ b/src/f32-dwconv/gen/up2x25-wasm-acc2.c
@@ -0,0 +1,396 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-dwconv/up-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/dwconv.h>
+#include <xnnpack/math.h>
+
+
+void xnn_f32_dwconv_ukernel_up2x25__wasm_acc2(
+ size_t channels,
+ size_t output_width,
+ const float** input,
+ const float* weights,
+ float* output,
+ size_t input_stride,
+ size_t output_increment,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(channels != 0);
+ assert(output_width != 0);
+
+ const float vmin = params->scalar.min;
+ const float vmax = params->scalar.max;
+ do {
+ const float* i0 = input[0];
+ const float* i1 = input[1];
+ const float* i2 = input[2];
+ const float* i3 = input[3];
+ const float* i4 = input[4];
+ const float* i5 = input[5];
+ const float* i6 = input[6];
+ const float* i7 = input[7];
+ const float* i8 = input[8];
+ const float* i9 = input[9];
+ const float* i10 = input[10];
+ const float* i11 = input[11];
+ const float* i12 = input[12];
+ const float* i13 = input[13];
+ const float* i14 = input[14];
+ const float* i15 = input[15];
+ const float* i16 = input[16];
+ const float* i17 = input[17];
+ const float* i18 = input[18];
+ const float* i19 = input[19];
+ const float* i20 = input[20];
+ const float* i21 = input[21];
+ const float* i22 = input[22];
+ const float* i23 = input[23];
+ const float* i24 = input[24];
+ input = (const float**) ((uintptr_t) input + input_stride);
+
+ size_t c = channels;
+ const float* w = weights;
+ for (; c >= 2; c -= 2) {
+ float vacc0p0 = w[0];
+ float vacc1p0 = w[1];
+
+
+ const float vi0x0 = i0[0];
+ const float vi0x1 = i0[1];
+ i0 += 2;
+
+ const float vk0x0 = w[2];
+ vacc0p0 += vi0x0 * vk0x0;
+ const float vk0x1 = w[3];
+ vacc1p0 += vi0x1 * vk0x1;
+
+ const float vi1x0 = i1[0];
+ const float vi1x1 = i1[1];
+ i1 += 2;
+
+ const float vk1x0 = w[4];
+ float vacc0p1 = vi1x0 * vk1x0;
+ const float vk1x1 = w[5];
+ float vacc1p1 = vi1x1 * vk1x1;
+
+ const float vi2x0 = i2[0];
+ const float vi2x1 = i2[1];
+ i2 += 2;
+
+ const float vk2x0 = w[6];
+ vacc0p0 += vi2x0 * vk2x0;
+ const float vk2x1 = w[7];
+ vacc1p0 += vi2x1 * vk2x1;
+
+ const float vi3x0 = i3[0];
+ const float vi3x1 = i3[1];
+ i3 += 2;
+
+ const float vk3x0 = w[8];
+ vacc0p1 += vi3x0 * vk3x0;
+ const float vk3x1 = w[9];
+ vacc1p1 += vi3x1 * vk3x1;
+
+ const float vi4x0 = i4[0];
+ const float vi4x1 = i4[1];
+ i4 += 2;
+
+ const float vk4x0 = w[10];
+ vacc0p0 += vi4x0 * vk4x0;
+ const float vk4x1 = w[11];
+ vacc1p0 += vi4x1 * vk4x1;
+
+ const float vi5x0 = i5[0];
+ const float vi5x1 = i5[1];
+ i5 += 2;
+
+ const float vk5x0 = w[12];
+ vacc0p1 += vi5x0 * vk5x0;
+ const float vk5x1 = w[13];
+ vacc1p1 += vi5x1 * vk5x1;
+
+ const float vi6x0 = i6[0];
+ const float vi6x1 = i6[1];
+ i6 += 2;
+
+ const float vk6x0 = w[14];
+ vacc0p0 += vi6x0 * vk6x0;
+ const float vk6x1 = w[15];
+ vacc1p0 += vi6x1 * vk6x1;
+
+ const float vi7x0 = i7[0];
+ const float vi7x1 = i7[1];
+ i7 += 2;
+
+ const float vk7x0 = w[16];
+ vacc0p1 += vi7x0 * vk7x0;
+ const float vk7x1 = w[17];
+ vacc1p1 += vi7x1 * vk7x1;
+
+ const float vi8x0 = i8[0];
+ const float vi8x1 = i8[1];
+ i8 += 2;
+
+ const float vk8x0 = w[18];
+ vacc0p0 += vi8x0 * vk8x0;
+ const float vk8x1 = w[19];
+ vacc1p0 += vi8x1 * vk8x1;
+
+ const float vi9x0 = i9[0];
+ const float vi9x1 = i9[1];
+ i9 += 2;
+
+ const float vk9x0 = w[20];
+ vacc0p1 += vi9x0 * vk9x0;
+ const float vk9x1 = w[21];
+ vacc1p1 += vi9x1 * vk9x1;
+
+ const float vi10x0 = i10[0];
+ const float vi10x1 = i10[1];
+ i10 += 2;
+
+ const float vk10x0 = w[22];
+ vacc0p0 += vi10x0 * vk10x0;
+ const float vk10x1 = w[23];
+ vacc1p0 += vi10x1 * vk10x1;
+
+ const float vi11x0 = i11[0];
+ const float vi11x1 = i11[1];
+ i11 += 2;
+
+ const float vk11x0 = w[24];
+ vacc0p1 += vi11x0 * vk11x0;
+ const float vk11x1 = w[25];
+ vacc1p1 += vi11x1 * vk11x1;
+
+ const float vi12x0 = i12[0];
+ const float vi12x1 = i12[1];
+ i12 += 2;
+
+ const float vk12x0 = w[26];
+ vacc0p0 += vi12x0 * vk12x0;
+ const float vk12x1 = w[27];
+ vacc1p0 += vi12x1 * vk12x1;
+
+ const float vi13x0 = i13[0];
+ const float vi13x1 = i13[1];
+ i13 += 2;
+
+ const float vk13x0 = w[28];
+ vacc0p1 += vi13x0 * vk13x0;
+ const float vk13x1 = w[29];
+ vacc1p1 += vi13x1 * vk13x1;
+
+ const float vi14x0 = i14[0];
+ const float vi14x1 = i14[1];
+ i14 += 2;
+
+ const float vk14x0 = w[30];
+ vacc0p0 += vi14x0 * vk14x0;
+ const float vk14x1 = w[31];
+ vacc1p0 += vi14x1 * vk14x1;
+
+ const float vi15x0 = i15[0];
+ const float vi15x1 = i15[1];
+ i15 += 2;
+
+ const float vk15x0 = w[32];
+ vacc0p1 += vi15x0 * vk15x0;
+ const float vk15x1 = w[33];
+ vacc1p1 += vi15x1 * vk15x1;
+
+ const float vi16x0 = i16[0];
+ const float vi16x1 = i16[1];
+ i16 += 2;
+
+ const float vk16x0 = w[34];
+ vacc0p0 += vi16x0 * vk16x0;
+ const float vk16x1 = w[35];
+ vacc1p0 += vi16x1 * vk16x1;
+
+ const float vi17x0 = i17[0];
+ const float vi17x1 = i17[1];
+ i17 += 2;
+
+ const float vk17x0 = w[36];
+ vacc0p1 += vi17x0 * vk17x0;
+ const float vk17x1 = w[37];
+ vacc1p1 += vi17x1 * vk17x1;
+
+ const float vi18x0 = i18[0];
+ const float vi18x1 = i18[1];
+ i18 += 2;
+
+ const float vk18x0 = w[38];
+ vacc0p0 += vi18x0 * vk18x0;
+ const float vk18x1 = w[39];
+ vacc1p0 += vi18x1 * vk18x1;
+
+ const float vi19x0 = i19[0];
+ const float vi19x1 = i19[1];
+ i19 += 2;
+
+ const float vk19x0 = w[40];
+ vacc0p1 += vi19x0 * vk19x0;
+ const float vk19x1 = w[41];
+ vacc1p1 += vi19x1 * vk19x1;
+
+ const float vi20x0 = i20[0];
+ const float vi20x1 = i20[1];
+ i20 += 2;
+
+ const float vk20x0 = w[42];
+ vacc0p0 += vi20x0 * vk20x0;
+ const float vk20x1 = w[43];
+ vacc1p0 += vi20x1 * vk20x1;
+
+ const float vi21x0 = i21[0];
+ const float vi21x1 = i21[1];
+ i21 += 2;
+
+ const float vk21x0 = w[44];
+ vacc0p1 += vi21x0 * vk21x0;
+ const float vk21x1 = w[45];
+ vacc1p1 += vi21x1 * vk21x1;
+
+ const float vi22x0 = i22[0];
+ const float vi22x1 = i22[1];
+ i22 += 2;
+
+ const float vk22x0 = w[46];
+ vacc0p0 += vi22x0 * vk22x0;
+ const float vk22x1 = w[47];
+ vacc1p0 += vi22x1 * vk22x1;
+
+ const float vi23x0 = i23[0];
+ const float vi23x1 = i23[1];
+ i23 += 2;
+
+ const float vk23x0 = w[48];
+ vacc0p1 += vi23x0 * vk23x0;
+ const float vk23x1 = w[49];
+ vacc1p1 += vi23x1 * vk23x1;
+
+ const float vi24x0 = i24[0];
+ const float vi24x1 = i24[1];
+ i24 += 2;
+
+ const float vk24x0 = w[50];
+ vacc0p0 += vi24x0 * vk24x0;
+ const float vk24x1 = w[51];
+ vacc1p0 += vi24x1 * vk24x1;
+
+ w += 52;
+
+ // Add up all accumulators to vacc01p0
+ vacc0p0 = vacc0p0 + vacc0p1;
+ vacc1p0 = vacc1p0 + vacc1p1;
+
+ float vacc0 = __builtin_wasm_max_f32(vacc0p0, vmin);
+ float vacc1 = __builtin_wasm_max_f32(vacc1p0, vmin);
+
+ vacc0 = __builtin_wasm_min_f32(vacc0, vmax);
+ vacc1 = __builtin_wasm_min_f32(vacc1, vmax);
+
+ output[0] = vacc0;
+ output[1] = vacc1;
+ output += 2;
+ }
+ for (; c >= 1; c -= 1) {
+ float vacc0p0 = *w++;
+
+ const float vi0 = *i0++;
+ const float vk0 = w[1];
+ vacc0p0 += vi0 * vk0;
+ const float vi1 = *i1++;
+ const float vk1 = w[3];
+ float vacc0p1 = vi1 * vk1;
+ const float vi2 = *i2++;
+ const float vk2 = w[5];
+ vacc0p0 += vi2 * vk2;
+ const float vi3 = *i3++;
+ const float vk3 = w[7];
+ vacc0p1 += vi3 * vk3;
+ const float vi4 = *i4++;
+ const float vk4 = w[9];
+ vacc0p0 += vi4 * vk4;
+ const float vi5 = *i5++;
+ const float vk5 = w[11];
+ vacc0p1 += vi5 * vk5;
+ const float vi6 = *i6++;
+ const float vk6 = w[13];
+ vacc0p0 += vi6 * vk6;
+ const float vi7 = *i7++;
+ const float vk7 = w[15];
+ vacc0p1 += vi7 * vk7;
+ const float vi8 = *i8++;
+ const float vk8 = w[17];
+ vacc0p0 += vi8 * vk8;
+ const float vi9 = *i9++;
+ const float vk9 = w[19];
+ vacc0p1 += vi9 * vk9;
+ const float vi10 = *i10++;
+ const float vk10 = w[21];
+ vacc0p0 += vi10 * vk10;
+ const float vi11 = *i11++;
+ const float vk11 = w[23];
+ vacc0p1 += vi11 * vk11;
+ const float vi12 = *i12++;
+ const float vk12 = w[25];
+ vacc0p0 += vi12 * vk12;
+ const float vi13 = *i13++;
+ const float vk13 = w[27];
+ vacc0p1 += vi13 * vk13;
+ const float vi14 = *i14++;
+ const float vk14 = w[29];
+ vacc0p0 += vi14 * vk14;
+ const float vi15 = *i15++;
+ const float vk15 = w[31];
+ vacc0p1 += vi15 * vk15;
+ const float vi16 = *i16++;
+ const float vk16 = w[33];
+ vacc0p0 += vi16 * vk16;
+ const float vi17 = *i17++;
+ const float vk17 = w[35];
+ vacc0p1 += vi17 * vk17;
+ const float vi18 = *i18++;
+ const float vk18 = w[37];
+ vacc0p0 += vi18 * vk18;
+ const float vi19 = *i19++;
+ const float vk19 = w[39];
+ vacc0p1 += vi19 * vk19;
+ const float vi20 = *i20++;
+ const float vk20 = w[41];
+ vacc0p0 += vi20 * vk20;
+ const float vi21 = *i21++;
+ const float vk21 = w[43];
+ vacc0p1 += vi21 * vk21;
+ const float vi22 = *i22++;
+ const float vk22 = w[45];
+ vacc0p0 += vi22 * vk22;
+ const float vi23 = *i23++;
+ const float vk23 = w[47];
+ vacc0p1 += vi23 * vk23;
+ const float vi24 = *i24++;
+ const float vk24 = w[49];
+ vacc0p0 += vi24 * vk24;
+
+ // Add up all accumulators to vacc01p0
+ vacc0p0 = vacc0p0 + vacc0p1;
+
+ float vacc0 = __builtin_wasm_max_f32(vacc0p0, vmin);
+ vacc0 = __builtin_wasm_min_f32(vacc0, vmax);
+ *output++ = vacc0;
+ }
+
+ output = (float*) ((uintptr_t) output + output_increment);
+ } while (--output_width != 0);
+}
diff --git a/src/f32-dwconv/gen/up2x25-wasm.c b/src/f32-dwconv/gen/up2x25-wasm.c
new file mode 100644
index 0000000..5f82dce
--- /dev/null
+++ b/src/f32-dwconv/gen/up2x25-wasm.c
@@ -0,0 +1,391 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-dwconv/up-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/dwconv.h>
+#include <xnnpack/math.h>
+
+
+void xnn_f32_dwconv_ukernel_up2x25__wasm(
+ size_t channels,
+ size_t output_width,
+ const float** input,
+ const float* weights,
+ float* output,
+ size_t input_stride,
+ size_t output_increment,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(channels != 0);
+ assert(output_width != 0);
+
+ const float vmin = params->scalar.min;
+ const float vmax = params->scalar.max;
+ do {
+ const float* i0 = input[0];
+ const float* i1 = input[1];
+ const float* i2 = input[2];
+ const float* i3 = input[3];
+ const float* i4 = input[4];
+ const float* i5 = input[5];
+ const float* i6 = input[6];
+ const float* i7 = input[7];
+ const float* i8 = input[8];
+ const float* i9 = input[9];
+ const float* i10 = input[10];
+ const float* i11 = input[11];
+ const float* i12 = input[12];
+ const float* i13 = input[13];
+ const float* i14 = input[14];
+ const float* i15 = input[15];
+ const float* i16 = input[16];
+ const float* i17 = input[17];
+ const float* i18 = input[18];
+ const float* i19 = input[19];
+ const float* i20 = input[20];
+ const float* i21 = input[21];
+ const float* i22 = input[22];
+ const float* i23 = input[23];
+ const float* i24 = input[24];
+ input = (const float**) ((uintptr_t) input + input_stride);
+
+ size_t c = channels;
+ const float* w = weights;
+ for (; c >= 2; c -= 2) {
+ float vacc0p0 = w[0];
+ float vacc1p0 = w[1];
+
+
+ const float vi0x0 = i0[0];
+ const float vi0x1 = i0[1];
+ i0 += 2;
+
+ const float vk0x0 = w[2];
+ vacc0p0 += vi0x0 * vk0x0;
+ const float vk0x1 = w[3];
+ vacc1p0 += vi0x1 * vk0x1;
+
+ const float vi1x0 = i1[0];
+ const float vi1x1 = i1[1];
+ i1 += 2;
+
+ const float vk1x0 = w[4];
+ vacc0p0 += vi1x0 * vk1x0;
+ const float vk1x1 = w[5];
+ vacc1p0 += vi1x1 * vk1x1;
+
+ const float vi2x0 = i2[0];
+ const float vi2x1 = i2[1];
+ i2 += 2;
+
+ const float vk2x0 = w[6];
+ vacc0p0 += vi2x0 * vk2x0;
+ const float vk2x1 = w[7];
+ vacc1p0 += vi2x1 * vk2x1;
+
+ const float vi3x0 = i3[0];
+ const float vi3x1 = i3[1];
+ i3 += 2;
+
+ const float vk3x0 = w[8];
+ vacc0p0 += vi3x0 * vk3x0;
+ const float vk3x1 = w[9];
+ vacc1p0 += vi3x1 * vk3x1;
+
+ const float vi4x0 = i4[0];
+ const float vi4x1 = i4[1];
+ i4 += 2;
+
+ const float vk4x0 = w[10];
+ vacc0p0 += vi4x0 * vk4x0;
+ const float vk4x1 = w[11];
+ vacc1p0 += vi4x1 * vk4x1;
+
+ const float vi5x0 = i5[0];
+ const float vi5x1 = i5[1];
+ i5 += 2;
+
+ const float vk5x0 = w[12];
+ vacc0p0 += vi5x0 * vk5x0;
+ const float vk5x1 = w[13];
+ vacc1p0 += vi5x1 * vk5x1;
+
+ const float vi6x0 = i6[0];
+ const float vi6x1 = i6[1];
+ i6 += 2;
+
+ const float vk6x0 = w[14];
+ vacc0p0 += vi6x0 * vk6x0;
+ const float vk6x1 = w[15];
+ vacc1p0 += vi6x1 * vk6x1;
+
+ const float vi7x0 = i7[0];
+ const float vi7x1 = i7[1];
+ i7 += 2;
+
+ const float vk7x0 = w[16];
+ vacc0p0 += vi7x0 * vk7x0;
+ const float vk7x1 = w[17];
+ vacc1p0 += vi7x1 * vk7x1;
+
+ const float vi8x0 = i8[0];
+ const float vi8x1 = i8[1];
+ i8 += 2;
+
+ const float vk8x0 = w[18];
+ vacc0p0 += vi8x0 * vk8x0;
+ const float vk8x1 = w[19];
+ vacc1p0 += vi8x1 * vk8x1;
+
+ const float vi9x0 = i9[0];
+ const float vi9x1 = i9[1];
+ i9 += 2;
+
+ const float vk9x0 = w[20];
+ vacc0p0 += vi9x0 * vk9x0;
+ const float vk9x1 = w[21];
+ vacc1p0 += vi9x1 * vk9x1;
+
+ const float vi10x0 = i10[0];
+ const float vi10x1 = i10[1];
+ i10 += 2;
+
+ const float vk10x0 = w[22];
+ vacc0p0 += vi10x0 * vk10x0;
+ const float vk10x1 = w[23];
+ vacc1p0 += vi10x1 * vk10x1;
+
+ const float vi11x0 = i11[0];
+ const float vi11x1 = i11[1];
+ i11 += 2;
+
+ const float vk11x0 = w[24];
+ vacc0p0 += vi11x0 * vk11x0;
+ const float vk11x1 = w[25];
+ vacc1p0 += vi11x1 * vk11x1;
+
+ const float vi12x0 = i12[0];
+ const float vi12x1 = i12[1];
+ i12 += 2;
+
+ const float vk12x0 = w[26];
+ vacc0p0 += vi12x0 * vk12x0;
+ const float vk12x1 = w[27];
+ vacc1p0 += vi12x1 * vk12x1;
+
+ const float vi13x0 = i13[0];
+ const float vi13x1 = i13[1];
+ i13 += 2;
+
+ const float vk13x0 = w[28];
+ vacc0p0 += vi13x0 * vk13x0;
+ const float vk13x1 = w[29];
+ vacc1p0 += vi13x1 * vk13x1;
+
+ const float vi14x0 = i14[0];
+ const float vi14x1 = i14[1];
+ i14 += 2;
+
+ const float vk14x0 = w[30];
+ vacc0p0 += vi14x0 * vk14x0;
+ const float vk14x1 = w[31];
+ vacc1p0 += vi14x1 * vk14x1;
+
+ const float vi15x0 = i15[0];
+ const float vi15x1 = i15[1];
+ i15 += 2;
+
+ const float vk15x0 = w[32];
+ vacc0p0 += vi15x0 * vk15x0;
+ const float vk15x1 = w[33];
+ vacc1p0 += vi15x1 * vk15x1;
+
+ const float vi16x0 = i16[0];
+ const float vi16x1 = i16[1];
+ i16 += 2;
+
+ const float vk16x0 = w[34];
+ vacc0p0 += vi16x0 * vk16x0;
+ const float vk16x1 = w[35];
+ vacc1p0 += vi16x1 * vk16x1;
+
+ const float vi17x0 = i17[0];
+ const float vi17x1 = i17[1];
+ i17 += 2;
+
+ const float vk17x0 = w[36];
+ vacc0p0 += vi17x0 * vk17x0;
+ const float vk17x1 = w[37];
+ vacc1p0 += vi17x1 * vk17x1;
+
+ const float vi18x0 = i18[0];
+ const float vi18x1 = i18[1];
+ i18 += 2;
+
+ const float vk18x0 = w[38];
+ vacc0p0 += vi18x0 * vk18x0;
+ const float vk18x1 = w[39];
+ vacc1p0 += vi18x1 * vk18x1;
+
+ const float vi19x0 = i19[0];
+ const float vi19x1 = i19[1];
+ i19 += 2;
+
+ const float vk19x0 = w[40];
+ vacc0p0 += vi19x0 * vk19x0;
+ const float vk19x1 = w[41];
+ vacc1p0 += vi19x1 * vk19x1;
+
+ const float vi20x0 = i20[0];
+ const float vi20x1 = i20[1];
+ i20 += 2;
+
+ const float vk20x0 = w[42];
+ vacc0p0 += vi20x0 * vk20x0;
+ const float vk20x1 = w[43];
+ vacc1p0 += vi20x1 * vk20x1;
+
+ const float vi21x0 = i21[0];
+ const float vi21x1 = i21[1];
+ i21 += 2;
+
+ const float vk21x0 = w[44];
+ vacc0p0 += vi21x0 * vk21x0;
+ const float vk21x1 = w[45];
+ vacc1p0 += vi21x1 * vk21x1;
+
+ const float vi22x0 = i22[0];
+ const float vi22x1 = i22[1];
+ i22 += 2;
+
+ const float vk22x0 = w[46];
+ vacc0p0 += vi22x0 * vk22x0;
+ const float vk22x1 = w[47];
+ vacc1p0 += vi22x1 * vk22x1;
+
+ const float vi23x0 = i23[0];
+ const float vi23x1 = i23[1];
+ i23 += 2;
+
+ const float vk23x0 = w[48];
+ vacc0p0 += vi23x0 * vk23x0;
+ const float vk23x1 = w[49];
+ vacc1p0 += vi23x1 * vk23x1;
+
+ const float vi24x0 = i24[0];
+ const float vi24x1 = i24[1];
+ i24 += 2;
+
+ const float vk24x0 = w[50];
+ vacc0p0 += vi24x0 * vk24x0;
+ const float vk24x1 = w[51];
+ vacc1p0 += vi24x1 * vk24x1;
+
+ w += 52;
+
+
+ float vacc0 = __builtin_wasm_max_f32(vacc0p0, vmin);
+ float vacc1 = __builtin_wasm_max_f32(vacc1p0, vmin);
+
+ vacc0 = __builtin_wasm_min_f32(vacc0, vmax);
+ vacc1 = __builtin_wasm_min_f32(vacc1, vmax);
+
+ output[0] = vacc0;
+ output[1] = vacc1;
+ output += 2;
+ }
+ for (; c >= 1; c -= 1) {
+ float vacc0p0 = *w++;
+
+ const float vi0 = *i0++;
+ const float vk0 = w[1];
+ vacc0p0 += vi0 * vk0;
+ const float vi1 = *i1++;
+ const float vk1 = w[3];
+ vacc0p0 += vi1 * vk1;
+ const float vi2 = *i2++;
+ const float vk2 = w[5];
+ vacc0p0 += vi2 * vk2;
+ const float vi3 = *i3++;
+ const float vk3 = w[7];
+ vacc0p0 += vi3 * vk3;
+ const float vi4 = *i4++;
+ const float vk4 = w[9];
+ vacc0p0 += vi4 * vk4;
+ const float vi5 = *i5++;
+ const float vk5 = w[11];
+ vacc0p0 += vi5 * vk5;
+ const float vi6 = *i6++;
+ const float vk6 = w[13];
+ vacc0p0 += vi6 * vk6;
+ const float vi7 = *i7++;
+ const float vk7 = w[15];
+ vacc0p0 += vi7 * vk7;
+ const float vi8 = *i8++;
+ const float vk8 = w[17];
+ vacc0p0 += vi8 * vk8;
+ const float vi9 = *i9++;
+ const float vk9 = w[19];
+ vacc0p0 += vi9 * vk9;
+ const float vi10 = *i10++;
+ const float vk10 = w[21];
+ vacc0p0 += vi10 * vk10;
+ const float vi11 = *i11++;
+ const float vk11 = w[23];
+ vacc0p0 += vi11 * vk11;
+ const float vi12 = *i12++;
+ const float vk12 = w[25];
+ vacc0p0 += vi12 * vk12;
+ const float vi13 = *i13++;
+ const float vk13 = w[27];
+ vacc0p0 += vi13 * vk13;
+ const float vi14 = *i14++;
+ const float vk14 = w[29];
+ vacc0p0 += vi14 * vk14;
+ const float vi15 = *i15++;
+ const float vk15 = w[31];
+ vacc0p0 += vi15 * vk15;
+ const float vi16 = *i16++;
+ const float vk16 = w[33];
+ vacc0p0 += vi16 * vk16;
+ const float vi17 = *i17++;
+ const float vk17 = w[35];
+ vacc0p0 += vi17 * vk17;
+ const float vi18 = *i18++;
+ const float vk18 = w[37];
+ vacc0p0 += vi18 * vk18;
+ const float vi19 = *i19++;
+ const float vk19 = w[39];
+ vacc0p0 += vi19 * vk19;
+ const float vi20 = *i20++;
+ const float vk20 = w[41];
+ vacc0p0 += vi20 * vk20;
+ const float vi21 = *i21++;
+ const float vk21 = w[43];
+ vacc0p0 += vi21 * vk21;
+ const float vi22 = *i22++;
+ const float vk22 = w[45];
+ vacc0p0 += vi22 * vk22;
+ const float vi23 = *i23++;
+ const float vk23 = w[47];
+ vacc0p0 += vi23 * vk23;
+ const float vi24 = *i24++;
+ const float vk24 = w[49];
+ vacc0p0 += vi24 * vk24;
+
+
+ float vacc0 = __builtin_wasm_max_f32(vacc0p0, vmin);
+ vacc0 = __builtin_wasm_min_f32(vacc0, vmax);
+ *output++ = vacc0;
+ }
+
+ output = (float*) ((uintptr_t) output + output_increment);
+ } while (--output_width != 0);
+}
diff --git a/src/f32-dwconv/gen/up2x4-wasm-acc2.c b/src/f32-dwconv/gen/up2x4-wasm-acc2.c
new file mode 100644
index 0000000..113f270
--- /dev/null
+++ b/src/f32-dwconv/gen/up2x4-wasm-acc2.c
@@ -0,0 +1,123 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-dwconv/up-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/dwconv.h>
+#include <xnnpack/math.h>
+
+
+void xnn_f32_dwconv_ukernel_up2x4__wasm_acc2(
+ size_t channels,
+ size_t output_width,
+ const float** input,
+ const float* weights,
+ float* output,
+ size_t input_stride,
+ size_t output_increment,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(channels != 0);
+ assert(output_width != 0);
+
+ const float vmin = params->scalar.min;
+ const float vmax = params->scalar.max;
+ do {
+ const float* i0 = input[0];
+ const float* i1 = input[1];
+ const float* i2 = input[2];
+ const float* i3 = input[3];
+ input = (const float**) ((uintptr_t) input + input_stride);
+
+ size_t c = channels;
+ const float* w = weights;
+ for (; c >= 2; c -= 2) {
+ float vacc0p0 = w[0];
+ float vacc1p0 = w[1];
+
+
+ const float vi0x0 = i0[0];
+ const float vi0x1 = i0[1];
+ i0 += 2;
+
+ const float vk0x0 = w[2];
+ vacc0p0 += vi0x0 * vk0x0;
+ const float vk0x1 = w[3];
+ vacc1p0 += vi0x1 * vk0x1;
+
+ const float vi1x0 = i1[0];
+ const float vi1x1 = i1[1];
+ i1 += 2;
+
+ const float vk1x0 = w[4];
+ float vacc0p1 = vi1x0 * vk1x0;
+ const float vk1x1 = w[5];
+ float vacc1p1 = vi1x1 * vk1x1;
+
+ const float vi2x0 = i2[0];
+ const float vi2x1 = i2[1];
+ i2 += 2;
+
+ const float vk2x0 = w[6];
+ vacc0p0 += vi2x0 * vk2x0;
+ const float vk2x1 = w[7];
+ vacc1p0 += vi2x1 * vk2x1;
+
+ const float vi3x0 = i3[0];
+ const float vi3x1 = i3[1];
+ i3 += 2;
+
+ const float vk3x0 = w[8];
+ vacc0p1 += vi3x0 * vk3x0;
+ const float vk3x1 = w[9];
+ vacc1p1 += vi3x1 * vk3x1;
+
+ w += 10;
+
+ // Add up all accumulators to vacc01p0
+ vacc0p0 = vacc0p0 + vacc0p1;
+ vacc1p0 = vacc1p0 + vacc1p1;
+
+ float vacc0 = __builtin_wasm_max_f32(vacc0p0, vmin);
+ float vacc1 = __builtin_wasm_max_f32(vacc1p0, vmin);
+
+ vacc0 = __builtin_wasm_min_f32(vacc0, vmax);
+ vacc1 = __builtin_wasm_min_f32(vacc1, vmax);
+
+ output[0] = vacc0;
+ output[1] = vacc1;
+ output += 2;
+ }
+ for (; c >= 1; c -= 1) {
+ float vacc0p0 = *w++;
+
+ const float vi0 = *i0++;
+ const float vk0 = w[1];
+ vacc0p0 += vi0 * vk0;
+ const float vi1 = *i1++;
+ const float vk1 = w[3];
+ float vacc0p1 = vi1 * vk1;
+ const float vi2 = *i2++;
+ const float vk2 = w[5];
+ vacc0p0 += vi2 * vk2;
+ const float vi3 = *i3++;
+ const float vk3 = w[7];
+ vacc0p1 += vi3 * vk3;
+
+ // Add up all accumulators to vacc01p0
+ vacc0p0 = vacc0p0 + vacc0p1;
+
+ float vacc0 = __builtin_wasm_max_f32(vacc0p0, vmin);
+ vacc0 = __builtin_wasm_min_f32(vacc0, vmax);
+ *output++ = vacc0;
+ }
+
+ output = (float*) ((uintptr_t) output + output_increment);
+ } while (--output_width != 0);
+}
diff --git a/src/f32-dwconv/gen/up2x4-wasm.c b/src/f32-dwconv/gen/up2x4-wasm.c
new file mode 100644
index 0000000..b1fa49a
--- /dev/null
+++ b/src/f32-dwconv/gen/up2x4-wasm.c
@@ -0,0 +1,118 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-dwconv/up-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/dwconv.h>
+#include <xnnpack/math.h>
+
+
+void xnn_f32_dwconv_ukernel_up2x4__wasm(
+ size_t channels,
+ size_t output_width,
+ const float** input,
+ const float* weights,
+ float* output,
+ size_t input_stride,
+ size_t output_increment,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(channels != 0);
+ assert(output_width != 0);
+
+ const float vmin = params->scalar.min;
+ const float vmax = params->scalar.max;
+ do {
+ const float* i0 = input[0];
+ const float* i1 = input[1];
+ const float* i2 = input[2];
+ const float* i3 = input[3];
+ input = (const float**) ((uintptr_t) input + input_stride);
+
+ size_t c = channels;
+ const float* w = weights;
+ for (; c >= 2; c -= 2) {
+ float vacc0p0 = w[0];
+ float vacc1p0 = w[1];
+
+
+ const float vi0x0 = i0[0];
+ const float vi0x1 = i0[1];
+ i0 += 2;
+
+ const float vk0x0 = w[2];
+ vacc0p0 += vi0x0 * vk0x0;
+ const float vk0x1 = w[3];
+ vacc1p0 += vi0x1 * vk0x1;
+
+ const float vi1x0 = i1[0];
+ const float vi1x1 = i1[1];
+ i1 += 2;
+
+ const float vk1x0 = w[4];
+ vacc0p0 += vi1x0 * vk1x0;
+ const float vk1x1 = w[5];
+ vacc1p0 += vi1x1 * vk1x1;
+
+ const float vi2x0 = i2[0];
+ const float vi2x1 = i2[1];
+ i2 += 2;
+
+ const float vk2x0 = w[6];
+ vacc0p0 += vi2x0 * vk2x0;
+ const float vk2x1 = w[7];
+ vacc1p0 += vi2x1 * vk2x1;
+
+ const float vi3x0 = i3[0];
+ const float vi3x1 = i3[1];
+ i3 += 2;
+
+ const float vk3x0 = w[8];
+ vacc0p0 += vi3x0 * vk3x0;
+ const float vk3x1 = w[9];
+ vacc1p0 += vi3x1 * vk3x1;
+
+ w += 10;
+
+
+ float vacc0 = __builtin_wasm_max_f32(vacc0p0, vmin);
+ float vacc1 = __builtin_wasm_max_f32(vacc1p0, vmin);
+
+ vacc0 = __builtin_wasm_min_f32(vacc0, vmax);
+ vacc1 = __builtin_wasm_min_f32(vacc1, vmax);
+
+ output[0] = vacc0;
+ output[1] = vacc1;
+ output += 2;
+ }
+ for (; c >= 1; c -= 1) {
+ float vacc0p0 = *w++;
+
+ const float vi0 = *i0++;
+ const float vk0 = w[1];
+ vacc0p0 += vi0 * vk0;
+ const float vi1 = *i1++;
+ const float vk1 = w[3];
+ vacc0p0 += vi1 * vk1;
+ const float vi2 = *i2++;
+ const float vk2 = w[5];
+ vacc0p0 += vi2 * vk2;
+ const float vi3 = *i3++;
+ const float vk3 = w[7];
+ vacc0p0 += vi3 * vk3;
+
+
+ float vacc0 = __builtin_wasm_max_f32(vacc0p0, vmin);
+ vacc0 = __builtin_wasm_min_f32(vacc0, vmax);
+ *output++ = vacc0;
+ }
+
+ output = (float*) ((uintptr_t) output + output_increment);
+ } while (--output_width != 0);
+}
diff --git a/src/f32-dwconv/gen/up2x9-wasm-acc2.c b/src/f32-dwconv/gen/up2x9-wasm-acc2.c
new file mode 100644
index 0000000..6411ea6
--- /dev/null
+++ b/src/f32-dwconv/gen/up2x9-wasm-acc2.c
@@ -0,0 +1,188 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-dwconv/up-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/dwconv.h>
+#include <xnnpack/math.h>
+
+
+void xnn_f32_dwconv_ukernel_up2x9__wasm_acc2(
+ size_t channels,
+ size_t output_width,
+ const float** input,
+ const float* weights,
+ float* output,
+ size_t input_stride,
+ size_t output_increment,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(channels != 0);
+ assert(output_width != 0);
+
+ const float vmin = params->scalar.min;
+ const float vmax = params->scalar.max;
+ do {
+ const float* i0 = input[0];
+ const float* i1 = input[1];
+ const float* i2 = input[2];
+ const float* i3 = input[3];
+ const float* i4 = input[4];
+ const float* i5 = input[5];
+ const float* i6 = input[6];
+ const float* i7 = input[7];
+ const float* i8 = input[8];
+ input = (const float**) ((uintptr_t) input + input_stride);
+
+ size_t c = channels;
+ const float* w = weights;
+ for (; c >= 2; c -= 2) {
+ float vacc0p0 = w[0];
+ float vacc1p0 = w[1];
+
+
+ const float vi0x0 = i0[0];
+ const float vi0x1 = i0[1];
+ i0 += 2;
+
+ const float vk0x0 = w[2];
+ vacc0p0 += vi0x0 * vk0x0;
+ const float vk0x1 = w[3];
+ vacc1p0 += vi0x1 * vk0x1;
+
+ const float vi1x0 = i1[0];
+ const float vi1x1 = i1[1];
+ i1 += 2;
+
+ const float vk1x0 = w[4];
+ float vacc0p1 = vi1x0 * vk1x0;
+ const float vk1x1 = w[5];
+ float vacc1p1 = vi1x1 * vk1x1;
+
+ const float vi2x0 = i2[0];
+ const float vi2x1 = i2[1];
+ i2 += 2;
+
+ const float vk2x0 = w[6];
+ vacc0p0 += vi2x0 * vk2x0;
+ const float vk2x1 = w[7];
+ vacc1p0 += vi2x1 * vk2x1;
+
+ const float vi3x0 = i3[0];
+ const float vi3x1 = i3[1];
+ i3 += 2;
+
+ const float vk3x0 = w[8];
+ vacc0p1 += vi3x0 * vk3x0;
+ const float vk3x1 = w[9];
+ vacc1p1 += vi3x1 * vk3x1;
+
+ const float vi4x0 = i4[0];
+ const float vi4x1 = i4[1];
+ i4 += 2;
+
+ const float vk4x0 = w[10];
+ vacc0p0 += vi4x0 * vk4x0;
+ const float vk4x1 = w[11];
+ vacc1p0 += vi4x1 * vk4x1;
+
+ const float vi5x0 = i5[0];
+ const float vi5x1 = i5[1];
+ i5 += 2;
+
+ const float vk5x0 = w[12];
+ vacc0p1 += vi5x0 * vk5x0;
+ const float vk5x1 = w[13];
+ vacc1p1 += vi5x1 * vk5x1;
+
+ const float vi6x0 = i6[0];
+ const float vi6x1 = i6[1];
+ i6 += 2;
+
+ const float vk6x0 = w[14];
+ vacc0p0 += vi6x0 * vk6x0;
+ const float vk6x1 = w[15];
+ vacc1p0 += vi6x1 * vk6x1;
+
+ const float vi7x0 = i7[0];
+ const float vi7x1 = i7[1];
+ i7 += 2;
+
+ const float vk7x0 = w[16];
+ vacc0p1 += vi7x0 * vk7x0;
+ const float vk7x1 = w[17];
+ vacc1p1 += vi7x1 * vk7x1;
+
+ const float vi8x0 = i8[0];
+ const float vi8x1 = i8[1];
+ i8 += 2;
+
+ const float vk8x0 = w[18];
+ vacc0p0 += vi8x0 * vk8x0;
+ const float vk8x1 = w[19];
+ vacc1p0 += vi8x1 * vk8x1;
+
+ w += 20;
+
+ // Add up all accumulators to vacc01p0
+ vacc0p0 = vacc0p0 + vacc0p1;
+ vacc1p0 = vacc1p0 + vacc1p1;
+
+ float vacc0 = __builtin_wasm_max_f32(vacc0p0, vmin);
+ float vacc1 = __builtin_wasm_max_f32(vacc1p0, vmin);
+
+ vacc0 = __builtin_wasm_min_f32(vacc0, vmax);
+ vacc1 = __builtin_wasm_min_f32(vacc1, vmax);
+
+ output[0] = vacc0;
+ output[1] = vacc1;
+ output += 2;
+ }
+ for (; c >= 1; c -= 1) {
+ float vacc0p0 = *w++;
+
+ const float vi0 = *i0++;
+ const float vk0 = w[1];
+ vacc0p0 += vi0 * vk0;
+ const float vi1 = *i1++;
+ const float vk1 = w[3];
+ float vacc0p1 = vi1 * vk1;
+ const float vi2 = *i2++;
+ const float vk2 = w[5];
+ vacc0p0 += vi2 * vk2;
+ const float vi3 = *i3++;
+ const float vk3 = w[7];
+ vacc0p1 += vi3 * vk3;
+ const float vi4 = *i4++;
+ const float vk4 = w[9];
+ vacc0p0 += vi4 * vk4;
+ const float vi5 = *i5++;
+ const float vk5 = w[11];
+ vacc0p1 += vi5 * vk5;
+ const float vi6 = *i6++;
+ const float vk6 = w[13];
+ vacc0p0 += vi6 * vk6;
+ const float vi7 = *i7++;
+ const float vk7 = w[15];
+ vacc0p1 += vi7 * vk7;
+ const float vi8 = *i8++;
+ const float vk8 = w[17];
+ vacc0p0 += vi8 * vk8;
+
+ // Add up all accumulators to vacc01p0
+ vacc0p0 = vacc0p0 + vacc0p1;
+
+ float vacc0 = __builtin_wasm_max_f32(vacc0p0, vmin);
+ vacc0 = __builtin_wasm_min_f32(vacc0, vmax);
+ *output++ = vacc0;
+ }
+
+ output = (float*) ((uintptr_t) output + output_increment);
+ } while (--output_width != 0);
+}
diff --git a/src/f32-dwconv/gen/up2x9-wasm.c b/src/f32-dwconv/gen/up2x9-wasm.c
new file mode 100644
index 0000000..d2d71b8
--- /dev/null
+++ b/src/f32-dwconv/gen/up2x9-wasm.c
@@ -0,0 +1,183 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-dwconv/up-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/dwconv.h>
+#include <xnnpack/math.h>
+
+
+void xnn_f32_dwconv_ukernel_up2x9__wasm(
+ size_t channels,
+ size_t output_width,
+ const float** input,
+ const float* weights,
+ float* output,
+ size_t input_stride,
+ size_t output_increment,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(channels != 0);
+ assert(output_width != 0);
+
+ const float vmin = params->scalar.min;
+ const float vmax = params->scalar.max;
+ do {
+ const float* i0 = input[0];
+ const float* i1 = input[1];
+ const float* i2 = input[2];
+ const float* i3 = input[3];
+ const float* i4 = input[4];
+ const float* i5 = input[5];
+ const float* i6 = input[6];
+ const float* i7 = input[7];
+ const float* i8 = input[8];
+ input = (const float**) ((uintptr_t) input + input_stride);
+
+ size_t c = channels;
+ const float* w = weights;
+ for (; c >= 2; c -= 2) {
+ float vacc0p0 = w[0];
+ float vacc1p0 = w[1];
+
+
+ const float vi0x0 = i0[0];
+ const float vi0x1 = i0[1];
+ i0 += 2;
+
+ const float vk0x0 = w[2];
+ vacc0p0 += vi0x0 * vk0x0;
+ const float vk0x1 = w[3];
+ vacc1p0 += vi0x1 * vk0x1;
+
+ const float vi1x0 = i1[0];
+ const float vi1x1 = i1[1];
+ i1 += 2;
+
+ const float vk1x0 = w[4];
+ vacc0p0 += vi1x0 * vk1x0;
+ const float vk1x1 = w[5];
+ vacc1p0 += vi1x1 * vk1x1;
+
+ const float vi2x0 = i2[0];
+ const float vi2x1 = i2[1];
+ i2 += 2;
+
+ const float vk2x0 = w[6];
+ vacc0p0 += vi2x0 * vk2x0;
+ const float vk2x1 = w[7];
+ vacc1p0 += vi2x1 * vk2x1;
+
+ const float vi3x0 = i3[0];
+ const float vi3x1 = i3[1];
+ i3 += 2;
+
+ const float vk3x0 = w[8];
+ vacc0p0 += vi3x0 * vk3x0;
+ const float vk3x1 = w[9];
+ vacc1p0 += vi3x1 * vk3x1;
+
+ const float vi4x0 = i4[0];
+ const float vi4x1 = i4[1];
+ i4 += 2;
+
+ const float vk4x0 = w[10];
+ vacc0p0 += vi4x0 * vk4x0;
+ const float vk4x1 = w[11];
+ vacc1p0 += vi4x1 * vk4x1;
+
+ const float vi5x0 = i5[0];
+ const float vi5x1 = i5[1];
+ i5 += 2;
+
+ const float vk5x0 = w[12];
+ vacc0p0 += vi5x0 * vk5x0;
+ const float vk5x1 = w[13];
+ vacc1p0 += vi5x1 * vk5x1;
+
+ const float vi6x0 = i6[0];
+ const float vi6x1 = i6[1];
+ i6 += 2;
+
+ const float vk6x0 = w[14];
+ vacc0p0 += vi6x0 * vk6x0;
+ const float vk6x1 = w[15];
+ vacc1p0 += vi6x1 * vk6x1;
+
+ const float vi7x0 = i7[0];
+ const float vi7x1 = i7[1];
+ i7 += 2;
+
+ const float vk7x0 = w[16];
+ vacc0p0 += vi7x0 * vk7x0;
+ const float vk7x1 = w[17];
+ vacc1p0 += vi7x1 * vk7x1;
+
+ const float vi8x0 = i8[0];
+ const float vi8x1 = i8[1];
+ i8 += 2;
+
+ const float vk8x0 = w[18];
+ vacc0p0 += vi8x0 * vk8x0;
+ const float vk8x1 = w[19];
+ vacc1p0 += vi8x1 * vk8x1;
+
+ w += 20;
+
+
+ float vacc0 = __builtin_wasm_max_f32(vacc0p0, vmin);
+ float vacc1 = __builtin_wasm_max_f32(vacc1p0, vmin);
+
+ vacc0 = __builtin_wasm_min_f32(vacc0, vmax);
+ vacc1 = __builtin_wasm_min_f32(vacc1, vmax);
+
+ output[0] = vacc0;
+ output[1] = vacc1;
+ output += 2;
+ }
+ for (; c >= 1; c -= 1) {
+ float vacc0p0 = *w++;
+
+ const float vi0 = *i0++;
+ const float vk0 = w[1];
+ vacc0p0 += vi0 * vk0;
+ const float vi1 = *i1++;
+ const float vk1 = w[3];
+ vacc0p0 += vi1 * vk1;
+ const float vi2 = *i2++;
+ const float vk2 = w[5];
+ vacc0p0 += vi2 * vk2;
+ const float vi3 = *i3++;
+ const float vk3 = w[7];
+ vacc0p0 += vi3 * vk3;
+ const float vi4 = *i4++;
+ const float vk4 = w[9];
+ vacc0p0 += vi4 * vk4;
+ const float vi5 = *i5++;
+ const float vk5 = w[11];
+ vacc0p0 += vi5 * vk5;
+ const float vi6 = *i6++;
+ const float vk6 = w[13];
+ vacc0p0 += vi6 * vk6;
+ const float vi7 = *i7++;
+ const float vk7 = w[15];
+ vacc0p0 += vi7 * vk7;
+ const float vi8 = *i8++;
+ const float vk8 = w[17];
+ vacc0p0 += vi8 * vk8;
+
+
+ float vacc0 = __builtin_wasm_max_f32(vacc0p0, vmin);
+ vacc0 = __builtin_wasm_min_f32(vacc0, vmax);
+ *output++ = vacc0;
+ }
+
+ output = (float*) ((uintptr_t) output + output_increment);
+ } while (--output_width != 0);
+}
diff --git a/src/f32-dwconv/up-scalar.c.in b/src/f32-dwconv/up-scalar.c.in
index a789bbb..0c09c9b 100644
--- a/src/f32-dwconv/up-scalar.c.in
+++ b/src/f32-dwconv/up-scalar.c.in
@@ -13,7 +13,9 @@
#include <xnnpack/math.h>
-void xnn_f32_dwconv_ukernel_up${CHANNEL_TILE}x${KERNEL_TILE}__scalar${"" if ACCUMULATORS == 1 else "_acc%d" % ACCUMULATORS}(
+$MIN_F32 = "__builtin_wasm_min_f32" if WASM else "math_min_f32"
+$MAX_F32 = "__builtin_wasm_max_f32" if WASM else "math_max_f32"
+void xnn_f32_dwconv_ukernel_up${CHANNEL_TILE}x${KERNEL_TILE}__${"wasm" if WASM else "scalar"}${"" if ACCUMULATORS == 1 else "_acc%d" % ACCUMULATORS}(
size_t channels,
size_t output_width,
const float** input,
@@ -66,10 +68,10 @@
$ACC_SLICE *= 2
$for C in range(CHANNEL_TILE):
- float vacc${C} = math_max_f32(vacc${C}p0, vmin);
+ float vacc${C} = ${MAX_F32}(vacc${C}p0, vmin);
$for C in range(CHANNEL_TILE):
- vacc${C} = math_min_f32(vacc${C}, vmax);
+ vacc${C} = ${MIN_F32}(vacc${C}, vmax);
$for C in range(CHANNEL_TILE):
output[${C}] = vacc${C};
@@ -95,8 +97,8 @@
vacc0p${A} = vacc0p${A} + vacc0p${A + ACC_SLICE};
$ACC_SLICE *= 2
- float vacc0 = math_max_f32(vacc0p0, vmin);
- vacc0 = math_min_f32(vacc0, vmax);
+ float vacc0 = ${MAX_F32}(vacc0p0, vmin);
+ vacc0 = ${MIN_F32}(vacc0, vmax);
*output++ = vacc0;
}
$else:
@@ -120,8 +122,8 @@
vacc0p${A} += vacc0p${A + ACC_STEP};
$ACC_STEP *= 2
- float vacc0 = math_max_f32(vacc0p0, vmin);
- vacc0 = math_min_f32(vacc0, vmax);
+ float vacc0 = ${MAX_F32}(vacc0p0, vmin);
+ vacc0 = ${MIN_F32}(vacc0, vmax);
*output++ = vacc0;
} while (--c != 0);
diff --git a/src/f32-gavgpool/mp7p7q-wasm.c b/src/f32-gavgpool/mp7p7q-wasm.c
new file mode 100644
index 0000000..d4fa565
--- /dev/null
+++ b/src/f32-gavgpool/mp7p7q-wasm.c
@@ -0,0 +1,148 @@
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/gavgpool.h>
+#include <xnnpack/math.h>
+
+
+void xnn_f32_gavgpool_ukernel_mp7p7q__wasm(
+ size_t m,
+ size_t n,
+ const float* input,
+ size_t input_stride,
+ const float* zero,
+ float* buffer,
+ float* output,
+ const union xnn_f32_avgpool_params params[restrict static 1])
+{
+ assert(m > 7);
+ assert(n != 0);
+
+ const float* i0 = input;
+ const float* i1 = (const float*) ((uintptr_t) i0 + input_stride);
+ const float* i2 = (const float*) ((uintptr_t) i1 + input_stride);
+ const float* i3 = (const float*) ((uintptr_t) i2 + input_stride);
+ const float* i4 = (const float*) ((uintptr_t) i3 + input_stride);
+ const float* i5 = (const float*) ((uintptr_t) i4 + input_stride);
+ const float* i6 = (const float*) ((uintptr_t) i5 + input_stride);
+ const size_t input_increment = 7 * input_stride - n * sizeof(float);
+
+ float* b = buffer;
+ size_t k = n;
+ do {
+ const float vi0 = *i0++;
+ const float vi1 = *i1++;
+ const float vi2 = *i2++;
+ const float vi3 = *i3++;
+ const float vi4 = *i4++;
+ const float vi5 = *i5++;
+ const float vi6 = *i6++;
+
+ const float vsum01 = vi0 + vi1;
+ const float vsum23 = vi2 + vi3;
+ const float vsum45 = vi4 + vi5;
+
+ const float vsum016 = vsum01 + vi6;
+ const float vsum2345 = vsum23 + vsum45;
+
+ const float vsum = vsum016 + vsum2345;
+
+ *b++ = vsum;
+ } while (--k != 0);
+ for (m -= 7; m > 7; m -= 7) {
+ b = buffer;
+
+ i0 = (const float*) ((uintptr_t) i0 + input_increment);
+ i1 = (const float*) ((uintptr_t) i1 + input_increment);
+ i2 = (const float*) ((uintptr_t) i2 + input_increment);
+ i3 = (const float*) ((uintptr_t) i3 + input_increment);
+ i4 = (const float*) ((uintptr_t) i4 + input_increment);
+ i5 = (const float*) ((uintptr_t) i5 + input_increment);
+ i6 = (const float*) ((uintptr_t) i6 + input_increment);
+
+ size_t k = n;
+ do {
+ const float vi0 = *i0++;
+ const float vi1 = *i1++;
+ const float vi2 = *i2++;
+ const float vi3 = *i3++;
+ const float vi4 = *i4++;
+ const float vi5 = *i5++;
+ const float vi6 = *i6++;
+ const float vacc = *b;
+
+ const float vsum01 = vi0 + vi1;
+ const float vsum23 = vi2 + vi3;
+ const float vsum45 = vi4 + vi5;
+ const float vsum6a = vi6 + vacc;
+
+ const float vsum0123 = vsum01 + vsum23;
+ const float vsum456a = vsum45 + vsum6a;
+
+ const float vsum = vsum0123 + vsum456a;
+
+ *b++ = vsum;
+ } while (--k != 0);
+ }
+
+ i0 = (const float*) ((uintptr_t) i0 + input_increment);
+ i1 = (const float*) ((uintptr_t) i1 + input_increment);
+ if (m < 2) {
+ i1 = zero;
+ }
+ i2 = (const float*) ((uintptr_t) i2 + input_increment);
+ if (m <= 2) {
+ i2 = zero;
+ }
+ i3 = (const float*) ((uintptr_t) i3 + input_increment);
+ if (m < 4) {
+ i3 = zero;
+ }
+ i4 = (const float*) ((uintptr_t) i4 + input_increment);
+ if (m <= 4) {
+ i4 = zero;
+ }
+ i5 = (const float*) ((uintptr_t) i5 + input_increment);
+ if (m < 6) {
+ i5 = zero;
+ }
+ i6 = (const float*) ((uintptr_t) i6 + input_increment);
+ if (m <= 6) {
+ i6 = zero;
+ }
+ const float vmultiplier = params->scalar.multiplier;
+ const float voutput_min = params->scalar.output_min;
+ const float voutput_max = params->scalar.output_max;
+
+ b = buffer;
+ do {
+ const float vi0 = *i0++;
+ const float vi1 = *i1++;
+ const float vi2 = *i2++;
+ const float vi3 = *i3++;
+ const float vi4 = *i4++;
+ const float vi5 = *i5++;
+ const float vi6 = *i6++;
+ const float vacc = *b++;
+
+ const float vsum01 = vi0 + vi1;
+ const float vsum23 = vi2 + vi3;
+ const float vsum45 = vi4 + vi5;
+ const float vsum6a = vi6 + vacc;
+
+ const float vsum0123 = vsum01 + vsum23;
+ const float vsum456a = vsum45 + vsum6a;
+
+ const float vsum = vsum0123 + vsum456a;
+
+ float vout = vsum * vmultiplier;
+ vout = __builtin_wasm_max_f32(vout, voutput_min);
+ vout = __builtin_wasm_min_f32(vout, voutput_max);
+
+ *output++ = vout;
+ } while (--n != 0);
+}
diff --git a/src/f32-gavgpool/up7-wasm.c b/src/f32-gavgpool/up7-wasm.c
new file mode 100644
index 0000000..89afcdf
--- /dev/null
+++ b/src/f32-gavgpool/up7-wasm.c
@@ -0,0 +1,78 @@
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/gavgpool.h>
+#include <xnnpack/math.h>
+
+
+void xnn_f32_gavgpool_ukernel_up7__wasm(
+ size_t m,
+ size_t n,
+ const float* input,
+ size_t input_stride,
+ const float* zero,
+ float* output,
+ const union xnn_f32_avgpool_params params[restrict static 1])
+{
+ assert(m != 0);
+ assert(m <= 7);
+ assert(n != 0);
+
+ const float* i0 = input;
+ const float* i1 = (const float*) ((uintptr_t) i0 + input_stride);
+ if (m < 2) {
+ i1 = zero;
+ }
+ const float* i2 = (const float*) ((uintptr_t) i1 + input_stride);
+ if (m <= 2) {
+ i2 = zero;
+ }
+ const float* i3 = (const float*) ((uintptr_t) i2 + input_stride);
+ if (m < 4) {
+ i3 = zero;
+ }
+ const float* i4 = (const float*) ((uintptr_t) i3 + input_stride);
+ if (m <= 4) {
+ i4 = zero;
+ }
+ const float* i5 = (const float*) ((uintptr_t) i4 + input_stride);
+ if (m < 6) {
+ i5 = zero;
+ }
+ const float* i6 = (const float*) ((uintptr_t) i5 + input_stride);
+ if (m <= 6) {
+ i6 = zero;
+ }
+
+ const float vmultiplier = params->scalar.multiplier;
+ const float voutput_min = params->scalar.output_min;
+ const float voutput_max = params->scalar.output_max;
+ do {
+ const float vi0 = *i0++;
+ const float vi1 = *i1++;
+ const float vi2 = *i2++;
+ const float vi3 = *i3++;
+ const float vi4 = *i4++;
+ const float vi5 = *i5++;
+ const float vi6 = *i6++;
+
+ const float vsum01 = vi0 + vi1;
+ const float vsum23 = vi2 + vi3;
+ const float vsum45 = vi4 + vi5;
+
+ const float vsum016 = vsum01 + vi6;
+ const float vsum2345 = vsum23 + vsum45;
+
+ const float vsum = vsum016 + vsum2345;
+
+ float vout = vsum * vmultiplier;
+ vout = __builtin_wasm_max_f32(vout, voutput_min);
+ vout = __builtin_wasm_min_f32(vout, voutput_max);
+
+ *output++ = vout;
+ } while (--n != 0);
+}
diff --git a/src/f32-gemm/gen-inc/1x4-wasm.c b/src/f32-gemm/gen-inc/1x4-wasm.c
new file mode 100644
index 0000000..b615412
--- /dev/null
+++ b/src/f32-gemm/gen-inc/1x4-wasm.c
@@ -0,0 +1,103 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-gemm/scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/gemm.h>
+#include <xnnpack/math.h>
+
+
+void xnn_f32_gemminc_ukernel_1x4__wasm(
+ size_t mr,
+ size_t nc,
+ size_t kc,
+ const float* restrict a,
+ size_t a_stride,
+ const float* restrict w,
+ float* restrict c,
+ size_t cm_stride,
+ size_t cn_stride,
+ const float*restrict acc,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(mr != 0);
+ assert(mr <= 1);
+ assert(nc != 0);
+ assert(kc != 0);
+ assert(kc % sizeof(float) == 0);
+ assert(a != NULL);
+ assert(w != NULL);
+ assert(c != NULL);
+ assert(acc != NULL);
+
+ const float* a0 = a;
+ float* c0 = c;
+
+ do {
+ float vacc00 = acc[0];
+ float vacc01 = acc[1];
+ float vacc02 = acc[2];
+ float vacc03 = acc[3];
+ acc += 4;
+
+ size_t k = kc;
+ do {
+ const float va0 = *a0++;
+
+ const float vb0 = w[0];
+ const float vb1 = w[1];
+ const float vb2 = w[2];
+ const float vb3 = w[3];
+ w += 4;
+
+ vacc00 += va0 * vb0;
+ vacc01 += va0 * vb1;
+ vacc02 += va0 * vb2;
+ vacc03 += va0 * vb3;
+
+ k -= sizeof(float);
+ } while (k != 0);
+
+ const float vmin = params->scalar.min;
+ vacc00 = __builtin_wasm_max_f32(vacc00, vmin);
+ vacc01 = __builtin_wasm_max_f32(vacc01, vmin);
+ vacc02 = __builtin_wasm_max_f32(vacc02, vmin);
+ vacc03 = __builtin_wasm_max_f32(vacc03, vmin);
+
+ const float vmax = params->scalar.max;
+ vacc00 = __builtin_wasm_min_f32(vacc00, vmax);
+ vacc01 = __builtin_wasm_min_f32(vacc01, vmax);
+ vacc02 = __builtin_wasm_min_f32(vacc02, vmax);
+ vacc03 = __builtin_wasm_min_f32(vacc03, vmax);
+
+ if XNN_LIKELY(nc >= 4) {
+ c0[0] = vacc00;
+ c0[1] = vacc01;
+ c0[2] = vacc02;
+ c0[3] = vacc03;
+ c0 = (float*) ((uintptr_t) c0 + cn_stride);
+
+ a0 = (const void*) ((uintptr_t) a0 - kc);
+
+ nc -= 4;
+ } else {
+ if (nc & 2) {
+ c0[0] = vacc00;
+ c0[1] = vacc01;
+ vacc00 = vacc02;
+ c0 += 2;
+ }
+ if (nc & 1) {
+ c0[0] = vacc00;
+ }
+
+ nc = 0;
+ }
+ } while (nc != 0);
+}
diff --git a/src/f32-gemm/gen-inc/2x4-wasm.c b/src/f32-gemm/gen-inc/2x4-wasm.c
new file mode 100644
index 0000000..c362a76
--- /dev/null
+++ b/src/f32-gemm/gen-inc/2x4-wasm.c
@@ -0,0 +1,137 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-gemm/scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/gemm.h>
+#include <xnnpack/math.h>
+
+
+void xnn_f32_gemminc_ukernel_2x4__wasm(
+ size_t mr,
+ size_t nc,
+ size_t kc,
+ const float* restrict a,
+ size_t a_stride,
+ const float* restrict w,
+ float* restrict c,
+ size_t cm_stride,
+ size_t cn_stride,
+ const float*restrict acc,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(mr != 0);
+ assert(mr <= 2);
+ assert(nc != 0);
+ assert(kc != 0);
+ assert(kc % sizeof(float) == 0);
+ assert(a != NULL);
+ assert(w != NULL);
+ assert(c != NULL);
+ assert(acc != NULL);
+
+ const float* a0 = a;
+ float* c0 = c;
+ const float* a1 = (const float*) ((uintptr_t) a0 + a_stride);
+ float* c1 = (float*) ((uintptr_t) c0 + cm_stride);
+ if XNN_UNPREDICTABLE(mr != 2) {
+ a1 = a0;
+ c1 = c0;
+ }
+
+ do {
+ float vacc00 = acc[0];
+ float vacc01 = acc[1];
+ float vacc02 = acc[2];
+ float vacc03 = acc[3];
+ float vacc10 = acc[4];
+ float vacc11 = acc[5];
+ float vacc12 = acc[6];
+ float vacc13 = acc[7];
+ acc += 8;
+
+ size_t k = kc;
+ do {
+ const float va0 = *a0++;
+ const float va1 = *a1++;
+
+ const float vb0 = w[0];
+ const float vb1 = w[1];
+ const float vb2 = w[2];
+ const float vb3 = w[3];
+ w += 4;
+
+ vacc00 += va0 * vb0;
+ vacc01 += va0 * vb1;
+ vacc02 += va0 * vb2;
+ vacc03 += va0 * vb3;
+ vacc10 += va1 * vb0;
+ vacc11 += va1 * vb1;
+ vacc12 += va1 * vb2;
+ vacc13 += va1 * vb3;
+
+ k -= sizeof(float);
+ } while (k != 0);
+
+ const float vmin = params->scalar.min;
+ vacc00 = __builtin_wasm_max_f32(vacc00, vmin);
+ vacc01 = __builtin_wasm_max_f32(vacc01, vmin);
+ vacc02 = __builtin_wasm_max_f32(vacc02, vmin);
+ vacc03 = __builtin_wasm_max_f32(vacc03, vmin);
+ vacc10 = __builtin_wasm_max_f32(vacc10, vmin);
+ vacc11 = __builtin_wasm_max_f32(vacc11, vmin);
+ vacc12 = __builtin_wasm_max_f32(vacc12, vmin);
+ vacc13 = __builtin_wasm_max_f32(vacc13, vmin);
+
+ const float vmax = params->scalar.max;
+ vacc00 = __builtin_wasm_min_f32(vacc00, vmax);
+ vacc01 = __builtin_wasm_min_f32(vacc01, vmax);
+ vacc02 = __builtin_wasm_min_f32(vacc02, vmax);
+ vacc03 = __builtin_wasm_min_f32(vacc03, vmax);
+ vacc10 = __builtin_wasm_min_f32(vacc10, vmax);
+ vacc11 = __builtin_wasm_min_f32(vacc11, vmax);
+ vacc12 = __builtin_wasm_min_f32(vacc12, vmax);
+ vacc13 = __builtin_wasm_min_f32(vacc13, vmax);
+
+ if XNN_LIKELY(nc >= 4) {
+ c1[0] = vacc10;
+ c1[1] = vacc11;
+ c1[2] = vacc12;
+ c1[3] = vacc13;
+ c1 = (float*) ((uintptr_t) c1 + cn_stride);
+ c0[0] = vacc00;
+ c0[1] = vacc01;
+ c0[2] = vacc02;
+ c0[3] = vacc03;
+ c0 = (float*) ((uintptr_t) c0 + cn_stride);
+
+ a1 = (const void*) ((uintptr_t) a1 - kc);
+ a0 = (const void*) ((uintptr_t) a0 - kc);
+
+ nc -= 4;
+ } else {
+ if (nc & 2) {
+ c1[0] = vacc10;
+ c1[1] = vacc11;
+ vacc10 = vacc12;
+ c1 += 2;
+ c0[0] = vacc00;
+ c0[1] = vacc01;
+ vacc00 = vacc02;
+ c0 += 2;
+ }
+ if (nc & 1) {
+ c1[0] = vacc10;
+ c0[0] = vacc00;
+ }
+
+ nc = 0;
+ }
+ } while (nc != 0);
+}
diff --git a/src/f32-gemm/gen-inc/4x4-wasm.c b/src/f32-gemm/gen-inc/4x4-wasm.c
new file mode 100644
index 0000000..7522a84
--- /dev/null
+++ b/src/f32-gemm/gen-inc/4x4-wasm.c
@@ -0,0 +1,205 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-gemm/scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/gemm.h>
+#include <xnnpack/math.h>
+
+
+void xnn_f32_gemminc_ukernel_4x4__wasm(
+ size_t mr,
+ size_t nc,
+ size_t kc,
+ const float* restrict a,
+ size_t a_stride,
+ const float* restrict w,
+ float* restrict c,
+ size_t cm_stride,
+ size_t cn_stride,
+ const float*restrict acc,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(mr != 0);
+ assert(mr <= 4);
+ assert(nc != 0);
+ assert(kc != 0);
+ assert(kc % sizeof(float) == 0);
+ assert(a != NULL);
+ assert(w != NULL);
+ assert(c != NULL);
+ assert(acc != NULL);
+
+ const float* a0 = a;
+ float* c0 = c;
+ const float* a1 = (const float*) ((uintptr_t) a0 + a_stride);
+ float* c1 = (float*) ((uintptr_t) c0 + cm_stride);
+ if XNN_UNPREDICTABLE(mr < 2) {
+ a1 = a0;
+ c1 = c0;
+ }
+ const float* a2 = (const float*) ((uintptr_t) a1 + a_stride);
+ float* c2 = (float*) ((uintptr_t) c1 + cm_stride);
+ if XNN_UNPREDICTABLE(mr <= 2) {
+ a2 = a1;
+ c2 = c1;
+ }
+ const float* a3 = (const float*) ((uintptr_t) a2 + a_stride);
+ float* c3 = (float*) ((uintptr_t) c2 + cm_stride);
+ if XNN_UNPREDICTABLE(mr != 4) {
+ a3 = a2;
+ c3 = c2;
+ }
+
+ do {
+ float vacc00 = acc[0];
+ float vacc01 = acc[1];
+ float vacc02 = acc[2];
+ float vacc03 = acc[3];
+ float vacc10 = acc[4];
+ float vacc11 = acc[5];
+ float vacc12 = acc[6];
+ float vacc13 = acc[7];
+ float vacc20 = acc[8];
+ float vacc21 = acc[9];
+ float vacc22 = acc[10];
+ float vacc23 = acc[11];
+ float vacc30 = acc[12];
+ float vacc31 = acc[13];
+ float vacc32 = acc[14];
+ float vacc33 = acc[15];
+ acc += 16;
+
+ size_t k = kc;
+ do {
+ const float va0 = *a0++;
+ const float va1 = *a1++;
+ const float va2 = *a2++;
+ const float va3 = *a3++;
+
+ const float vb0 = w[0];
+ const float vb1 = w[1];
+ const float vb2 = w[2];
+ const float vb3 = w[3];
+ w += 4;
+
+ vacc00 += va0 * vb0;
+ vacc01 += va0 * vb1;
+ vacc02 += va0 * vb2;
+ vacc03 += va0 * vb3;
+ vacc10 += va1 * vb0;
+ vacc11 += va1 * vb1;
+ vacc12 += va1 * vb2;
+ vacc13 += va1 * vb3;
+ vacc20 += va2 * vb0;
+ vacc21 += va2 * vb1;
+ vacc22 += va2 * vb2;
+ vacc23 += va2 * vb3;
+ vacc30 += va3 * vb0;
+ vacc31 += va3 * vb1;
+ vacc32 += va3 * vb2;
+ vacc33 += va3 * vb3;
+
+ k -= sizeof(float);
+ } while (k != 0);
+
+ const float vmin = params->scalar.min;
+ vacc00 = __builtin_wasm_max_f32(vacc00, vmin);
+ vacc01 = __builtin_wasm_max_f32(vacc01, vmin);
+ vacc02 = __builtin_wasm_max_f32(vacc02, vmin);
+ vacc03 = __builtin_wasm_max_f32(vacc03, vmin);
+ vacc10 = __builtin_wasm_max_f32(vacc10, vmin);
+ vacc11 = __builtin_wasm_max_f32(vacc11, vmin);
+ vacc12 = __builtin_wasm_max_f32(vacc12, vmin);
+ vacc13 = __builtin_wasm_max_f32(vacc13, vmin);
+ vacc20 = __builtin_wasm_max_f32(vacc20, vmin);
+ vacc21 = __builtin_wasm_max_f32(vacc21, vmin);
+ vacc22 = __builtin_wasm_max_f32(vacc22, vmin);
+ vacc23 = __builtin_wasm_max_f32(vacc23, vmin);
+ vacc30 = __builtin_wasm_max_f32(vacc30, vmin);
+ vacc31 = __builtin_wasm_max_f32(vacc31, vmin);
+ vacc32 = __builtin_wasm_max_f32(vacc32, vmin);
+ vacc33 = __builtin_wasm_max_f32(vacc33, vmin);
+
+ const float vmax = params->scalar.max;
+ vacc00 = __builtin_wasm_min_f32(vacc00, vmax);
+ vacc01 = __builtin_wasm_min_f32(vacc01, vmax);
+ vacc02 = __builtin_wasm_min_f32(vacc02, vmax);
+ vacc03 = __builtin_wasm_min_f32(vacc03, vmax);
+ vacc10 = __builtin_wasm_min_f32(vacc10, vmax);
+ vacc11 = __builtin_wasm_min_f32(vacc11, vmax);
+ vacc12 = __builtin_wasm_min_f32(vacc12, vmax);
+ vacc13 = __builtin_wasm_min_f32(vacc13, vmax);
+ vacc20 = __builtin_wasm_min_f32(vacc20, vmax);
+ vacc21 = __builtin_wasm_min_f32(vacc21, vmax);
+ vacc22 = __builtin_wasm_min_f32(vacc22, vmax);
+ vacc23 = __builtin_wasm_min_f32(vacc23, vmax);
+ vacc30 = __builtin_wasm_min_f32(vacc30, vmax);
+ vacc31 = __builtin_wasm_min_f32(vacc31, vmax);
+ vacc32 = __builtin_wasm_min_f32(vacc32, vmax);
+ vacc33 = __builtin_wasm_min_f32(vacc33, vmax);
+
+ if XNN_LIKELY(nc >= 4) {
+ c3[0] = vacc30;
+ c3[1] = vacc31;
+ c3[2] = vacc32;
+ c3[3] = vacc33;
+ c3 = (float*) ((uintptr_t) c3 + cn_stride);
+ c2[0] = vacc20;
+ c2[1] = vacc21;
+ c2[2] = vacc22;
+ c2[3] = vacc23;
+ c2 = (float*) ((uintptr_t) c2 + cn_stride);
+ c1[0] = vacc10;
+ c1[1] = vacc11;
+ c1[2] = vacc12;
+ c1[3] = vacc13;
+ c1 = (float*) ((uintptr_t) c1 + cn_stride);
+ c0[0] = vacc00;
+ c0[1] = vacc01;
+ c0[2] = vacc02;
+ c0[3] = vacc03;
+ c0 = (float*) ((uintptr_t) c0 + cn_stride);
+
+ a3 = (const void*) ((uintptr_t) a3 - kc);
+ a2 = (const void*) ((uintptr_t) a2 - kc);
+ a1 = (const void*) ((uintptr_t) a1 - kc);
+ a0 = (const void*) ((uintptr_t) a0 - kc);
+
+ nc -= 4;
+ } else {
+ if (nc & 2) {
+ c3[0] = vacc30;
+ c3[1] = vacc31;
+ vacc30 = vacc32;
+ c3 += 2;
+ c2[0] = vacc20;
+ c2[1] = vacc21;
+ vacc20 = vacc22;
+ c2 += 2;
+ c1[0] = vacc10;
+ c1[1] = vacc11;
+ vacc10 = vacc12;
+ c1 += 2;
+ c0[0] = vacc00;
+ c0[1] = vacc01;
+ vacc00 = vacc02;
+ c0 += 2;
+ }
+ if (nc & 1) {
+ c3[0] = vacc30;
+ c2[0] = vacc20;
+ c1[0] = vacc10;
+ c0[0] = vacc00;
+ }
+
+ nc = 0;
+ }
+ } while (nc != 0);
+}
diff --git a/src/f32-gemm/gen/1x4-wasm.c b/src/f32-gemm/gen/1x4-wasm.c
new file mode 100644
index 0000000..706c06b
--- /dev/null
+++ b/src/f32-gemm/gen/1x4-wasm.c
@@ -0,0 +1,101 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-gemm/scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/gemm.h>
+#include <xnnpack/math.h>
+
+
+void xnn_f32_gemm_ukernel_1x4__wasm(
+ size_t mr,
+ size_t nc,
+ size_t kc,
+ const float* restrict a,
+ size_t a_stride,
+ const float* restrict w,
+ float* restrict c,
+ size_t cm_stride,
+ size_t cn_stride,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(mr != 0);
+ assert(mr <= 1);
+ assert(nc != 0);
+ assert(kc != 0);
+ assert(kc % sizeof(float) == 0);
+ assert(a != NULL);
+ assert(w != NULL);
+ assert(c != NULL);
+
+ const float* a0 = a;
+ float* c0 = c;
+
+ do {
+ float vacc00 = w[0];
+ float vacc01 = w[1];
+ float vacc02 = w[2];
+ float vacc03 = w[3];
+ w += 4;
+
+ size_t k = kc;
+ do {
+ const float va0 = *a0++;
+
+ const float vb0 = w[0];
+ const float vb1 = w[1];
+ const float vb2 = w[2];
+ const float vb3 = w[3];
+ w += 4;
+
+ vacc00 += va0 * vb0;
+ vacc01 += va0 * vb1;
+ vacc02 += va0 * vb2;
+ vacc03 += va0 * vb3;
+
+ k -= sizeof(float);
+ } while (k != 0);
+
+ const float vmin = params->scalar.min;
+ vacc00 = __builtin_wasm_max_f32(vacc00, vmin);
+ vacc01 = __builtin_wasm_max_f32(vacc01, vmin);
+ vacc02 = __builtin_wasm_max_f32(vacc02, vmin);
+ vacc03 = __builtin_wasm_max_f32(vacc03, vmin);
+
+ const float vmax = params->scalar.max;
+ vacc00 = __builtin_wasm_min_f32(vacc00, vmax);
+ vacc01 = __builtin_wasm_min_f32(vacc01, vmax);
+ vacc02 = __builtin_wasm_min_f32(vacc02, vmax);
+ vacc03 = __builtin_wasm_min_f32(vacc03, vmax);
+
+ if XNN_LIKELY(nc >= 4) {
+ c0[0] = vacc00;
+ c0[1] = vacc01;
+ c0[2] = vacc02;
+ c0[3] = vacc03;
+ c0 = (float*) ((uintptr_t) c0 + cn_stride);
+
+ a0 = (const void*) ((uintptr_t) a0 - kc);
+
+ nc -= 4;
+ } else {
+ if (nc & 2) {
+ c0[0] = vacc00;
+ c0[1] = vacc01;
+ vacc00 = vacc02;
+ c0 += 2;
+ }
+ if (nc & 1) {
+ c0[0] = vacc00;
+ }
+
+ nc = 0;
+ }
+ } while (nc != 0);
+}
diff --git a/src/f32-gemm/gen/2x4-wasm.c b/src/f32-gemm/gen/2x4-wasm.c
new file mode 100644
index 0000000..989b9f0
--- /dev/null
+++ b/src/f32-gemm/gen/2x4-wasm.c
@@ -0,0 +1,135 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-gemm/scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/gemm.h>
+#include <xnnpack/math.h>
+
+
+void xnn_f32_gemm_ukernel_2x4__wasm(
+ size_t mr,
+ size_t nc,
+ size_t kc,
+ const float* restrict a,
+ size_t a_stride,
+ const float* restrict w,
+ float* restrict c,
+ size_t cm_stride,
+ size_t cn_stride,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(mr != 0);
+ assert(mr <= 2);
+ assert(nc != 0);
+ assert(kc != 0);
+ assert(kc % sizeof(float) == 0);
+ assert(a != NULL);
+ assert(w != NULL);
+ assert(c != NULL);
+
+ const float* a0 = a;
+ float* c0 = c;
+ const float* a1 = (const float*) ((uintptr_t) a0 + a_stride);
+ float* c1 = (float*) ((uintptr_t) c0 + cm_stride);
+ if XNN_UNPREDICTABLE(mr != 2) {
+ a1 = a0;
+ c1 = c0;
+ }
+
+ do {
+ float vacc00 = w[0];
+ float vacc01 = w[1];
+ float vacc02 = w[2];
+ float vacc03 = w[3];
+ w += 4;
+ float vacc10 = vacc00;
+ float vacc11 = vacc01;
+ float vacc12 = vacc02;
+ float vacc13 = vacc03;
+
+ size_t k = kc;
+ do {
+ const float va0 = *a0++;
+ const float va1 = *a1++;
+
+ const float vb0 = w[0];
+ const float vb1 = w[1];
+ const float vb2 = w[2];
+ const float vb3 = w[3];
+ w += 4;
+
+ vacc00 += va0 * vb0;
+ vacc01 += va0 * vb1;
+ vacc02 += va0 * vb2;
+ vacc03 += va0 * vb3;
+ vacc10 += va1 * vb0;
+ vacc11 += va1 * vb1;
+ vacc12 += va1 * vb2;
+ vacc13 += va1 * vb3;
+
+ k -= sizeof(float);
+ } while (k != 0);
+
+ const float vmin = params->scalar.min;
+ vacc00 = __builtin_wasm_max_f32(vacc00, vmin);
+ vacc01 = __builtin_wasm_max_f32(vacc01, vmin);
+ vacc02 = __builtin_wasm_max_f32(vacc02, vmin);
+ vacc03 = __builtin_wasm_max_f32(vacc03, vmin);
+ vacc10 = __builtin_wasm_max_f32(vacc10, vmin);
+ vacc11 = __builtin_wasm_max_f32(vacc11, vmin);
+ vacc12 = __builtin_wasm_max_f32(vacc12, vmin);
+ vacc13 = __builtin_wasm_max_f32(vacc13, vmin);
+
+ const float vmax = params->scalar.max;
+ vacc00 = __builtin_wasm_min_f32(vacc00, vmax);
+ vacc01 = __builtin_wasm_min_f32(vacc01, vmax);
+ vacc02 = __builtin_wasm_min_f32(vacc02, vmax);
+ vacc03 = __builtin_wasm_min_f32(vacc03, vmax);
+ vacc10 = __builtin_wasm_min_f32(vacc10, vmax);
+ vacc11 = __builtin_wasm_min_f32(vacc11, vmax);
+ vacc12 = __builtin_wasm_min_f32(vacc12, vmax);
+ vacc13 = __builtin_wasm_min_f32(vacc13, vmax);
+
+ if XNN_LIKELY(nc >= 4) {
+ c1[0] = vacc10;
+ c1[1] = vacc11;
+ c1[2] = vacc12;
+ c1[3] = vacc13;
+ c1 = (float*) ((uintptr_t) c1 + cn_stride);
+ c0[0] = vacc00;
+ c0[1] = vacc01;
+ c0[2] = vacc02;
+ c0[3] = vacc03;
+ c0 = (float*) ((uintptr_t) c0 + cn_stride);
+
+ a1 = (const void*) ((uintptr_t) a1 - kc);
+ a0 = (const void*) ((uintptr_t) a0 - kc);
+
+ nc -= 4;
+ } else {
+ if (nc & 2) {
+ c1[0] = vacc10;
+ c1[1] = vacc11;
+ vacc10 = vacc12;
+ c1 += 2;
+ c0[0] = vacc00;
+ c0[1] = vacc01;
+ vacc00 = vacc02;
+ c0 += 2;
+ }
+ if (nc & 1) {
+ c1[0] = vacc10;
+ c0[0] = vacc00;
+ }
+
+ nc = 0;
+ }
+ } while (nc != 0);
+}
diff --git a/src/f32-gemm/gen/4x2-wasm.c b/src/f32-gemm/gen/4x2-wasm.c
new file mode 100644
index 0000000..9ea76ce
--- /dev/null
+++ b/src/f32-gemm/gen/4x2-wasm.c
@@ -0,0 +1,143 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-gemm/scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/gemm.h>
+#include <xnnpack/math.h>
+
+
+void xnn_f32_gemm_ukernel_4x2__wasm(
+ size_t mr,
+ size_t nc,
+ size_t kc,
+ const float* restrict a,
+ size_t a_stride,
+ const float* restrict w,
+ float* restrict c,
+ size_t cm_stride,
+ size_t cn_stride,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(mr != 0);
+ assert(mr <= 4);
+ assert(nc != 0);
+ assert(kc != 0);
+ assert(kc % sizeof(float) == 0);
+ assert(a != NULL);
+ assert(w != NULL);
+ assert(c != NULL);
+
+ const float* a0 = a;
+ float* c0 = c;
+ const float* a1 = (const float*) ((uintptr_t) a0 + a_stride);
+ float* c1 = (float*) ((uintptr_t) c0 + cm_stride);
+ if XNN_UNPREDICTABLE(mr < 2) {
+ a1 = a0;
+ c1 = c0;
+ }
+ const float* a2 = (const float*) ((uintptr_t) a1 + a_stride);
+ float* c2 = (float*) ((uintptr_t) c1 + cm_stride);
+ if XNN_UNPREDICTABLE(mr <= 2) {
+ a2 = a1;
+ c2 = c1;
+ }
+ const float* a3 = (const float*) ((uintptr_t) a2 + a_stride);
+ float* c3 = (float*) ((uintptr_t) c2 + cm_stride);
+ if XNN_UNPREDICTABLE(mr != 4) {
+ a3 = a2;
+ c3 = c2;
+ }
+
+ do {
+ float vacc00 = w[0];
+ float vacc01 = w[1];
+ w += 2;
+ float vacc10 = vacc00;
+ float vacc11 = vacc01;
+ float vacc20 = vacc00;
+ float vacc21 = vacc01;
+ float vacc30 = vacc00;
+ float vacc31 = vacc01;
+
+ size_t k = kc;
+ do {
+ const float va0 = *a0++;
+ const float va1 = *a1++;
+ const float va2 = *a2++;
+ const float va3 = *a3++;
+
+ const float vb0 = w[0];
+ const float vb1 = w[1];
+ w += 2;
+
+ vacc00 += va0 * vb0;
+ vacc01 += va0 * vb1;
+ vacc10 += va1 * vb0;
+ vacc11 += va1 * vb1;
+ vacc20 += va2 * vb0;
+ vacc21 += va2 * vb1;
+ vacc30 += va3 * vb0;
+ vacc31 += va3 * vb1;
+
+ k -= sizeof(float);
+ } while (k != 0);
+
+ const float vmin = params->scalar.min;
+ vacc00 = __builtin_wasm_max_f32(vacc00, vmin);
+ vacc01 = __builtin_wasm_max_f32(vacc01, vmin);
+ vacc10 = __builtin_wasm_max_f32(vacc10, vmin);
+ vacc11 = __builtin_wasm_max_f32(vacc11, vmin);
+ vacc20 = __builtin_wasm_max_f32(vacc20, vmin);
+ vacc21 = __builtin_wasm_max_f32(vacc21, vmin);
+ vacc30 = __builtin_wasm_max_f32(vacc30, vmin);
+ vacc31 = __builtin_wasm_max_f32(vacc31, vmin);
+
+ const float vmax = params->scalar.max;
+ vacc00 = __builtin_wasm_min_f32(vacc00, vmax);
+ vacc01 = __builtin_wasm_min_f32(vacc01, vmax);
+ vacc10 = __builtin_wasm_min_f32(vacc10, vmax);
+ vacc11 = __builtin_wasm_min_f32(vacc11, vmax);
+ vacc20 = __builtin_wasm_min_f32(vacc20, vmax);
+ vacc21 = __builtin_wasm_min_f32(vacc21, vmax);
+ vacc30 = __builtin_wasm_min_f32(vacc30, vmax);
+ vacc31 = __builtin_wasm_min_f32(vacc31, vmax);
+
+ if XNN_LIKELY(nc >= 2) {
+ c3[0] = vacc30;
+ c3[1] = vacc31;
+ c3 = (float*) ((uintptr_t) c3 + cn_stride);
+ c2[0] = vacc20;
+ c2[1] = vacc21;
+ c2 = (float*) ((uintptr_t) c2 + cn_stride);
+ c1[0] = vacc10;
+ c1[1] = vacc11;
+ c1 = (float*) ((uintptr_t) c1 + cn_stride);
+ c0[0] = vacc00;
+ c0[1] = vacc01;
+ c0 = (float*) ((uintptr_t) c0 + cn_stride);
+
+ a3 = (const void*) ((uintptr_t) a3 - kc);
+ a2 = (const void*) ((uintptr_t) a2 - kc);
+ a1 = (const void*) ((uintptr_t) a1 - kc);
+ a0 = (const void*) ((uintptr_t) a0 - kc);
+
+ nc -= 2;
+ } else {
+ if (nc & 1) {
+ c3[0] = vacc30;
+ c2[0] = vacc20;
+ c1[0] = vacc10;
+ c0[0] = vacc00;
+ }
+
+ nc = 0;
+ }
+ } while (nc != 0);
+}
diff --git a/src/f32-gemm/gen/4x4-wasm.c b/src/f32-gemm/gen/4x4-wasm.c
new file mode 100644
index 0000000..3b6e37f
--- /dev/null
+++ b/src/f32-gemm/gen/4x4-wasm.c
@@ -0,0 +1,203 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-gemm/scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/gemm.h>
+#include <xnnpack/math.h>
+
+
+void xnn_f32_gemm_ukernel_4x4__wasm(
+ size_t mr,
+ size_t nc,
+ size_t kc,
+ const float* restrict a,
+ size_t a_stride,
+ const float* restrict w,
+ float* restrict c,
+ size_t cm_stride,
+ size_t cn_stride,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(mr != 0);
+ assert(mr <= 4);
+ assert(nc != 0);
+ assert(kc != 0);
+ assert(kc % sizeof(float) == 0);
+ assert(a != NULL);
+ assert(w != NULL);
+ assert(c != NULL);
+
+ const float* a0 = a;
+ float* c0 = c;
+ const float* a1 = (const float*) ((uintptr_t) a0 + a_stride);
+ float* c1 = (float*) ((uintptr_t) c0 + cm_stride);
+ if XNN_UNPREDICTABLE(mr < 2) {
+ a1 = a0;
+ c1 = c0;
+ }
+ const float* a2 = (const float*) ((uintptr_t) a1 + a_stride);
+ float* c2 = (float*) ((uintptr_t) c1 + cm_stride);
+ if XNN_UNPREDICTABLE(mr <= 2) {
+ a2 = a1;
+ c2 = c1;
+ }
+ const float* a3 = (const float*) ((uintptr_t) a2 + a_stride);
+ float* c3 = (float*) ((uintptr_t) c2 + cm_stride);
+ if XNN_UNPREDICTABLE(mr != 4) {
+ a3 = a2;
+ c3 = c2;
+ }
+
+ do {
+ float vacc00 = w[0];
+ float vacc01 = w[1];
+ float vacc02 = w[2];
+ float vacc03 = w[3];
+ w += 4;
+ float vacc10 = vacc00;
+ float vacc11 = vacc01;
+ float vacc12 = vacc02;
+ float vacc13 = vacc03;
+ float vacc20 = vacc00;
+ float vacc21 = vacc01;
+ float vacc22 = vacc02;
+ float vacc23 = vacc03;
+ float vacc30 = vacc00;
+ float vacc31 = vacc01;
+ float vacc32 = vacc02;
+ float vacc33 = vacc03;
+
+ size_t k = kc;
+ do {
+ const float va0 = *a0++;
+ const float va1 = *a1++;
+ const float va2 = *a2++;
+ const float va3 = *a3++;
+
+ const float vb0 = w[0];
+ const float vb1 = w[1];
+ const float vb2 = w[2];
+ const float vb3 = w[3];
+ w += 4;
+
+ vacc00 += va0 * vb0;
+ vacc01 += va0 * vb1;
+ vacc02 += va0 * vb2;
+ vacc03 += va0 * vb3;
+ vacc10 += va1 * vb0;
+ vacc11 += va1 * vb1;
+ vacc12 += va1 * vb2;
+ vacc13 += va1 * vb3;
+ vacc20 += va2 * vb0;
+ vacc21 += va2 * vb1;
+ vacc22 += va2 * vb2;
+ vacc23 += va2 * vb3;
+ vacc30 += va3 * vb0;
+ vacc31 += va3 * vb1;
+ vacc32 += va3 * vb2;
+ vacc33 += va3 * vb3;
+
+ k -= sizeof(float);
+ } while (k != 0);
+
+ const float vmin = params->scalar.min;
+ vacc00 = __builtin_wasm_max_f32(vacc00, vmin);
+ vacc01 = __builtin_wasm_max_f32(vacc01, vmin);
+ vacc02 = __builtin_wasm_max_f32(vacc02, vmin);
+ vacc03 = __builtin_wasm_max_f32(vacc03, vmin);
+ vacc10 = __builtin_wasm_max_f32(vacc10, vmin);
+ vacc11 = __builtin_wasm_max_f32(vacc11, vmin);
+ vacc12 = __builtin_wasm_max_f32(vacc12, vmin);
+ vacc13 = __builtin_wasm_max_f32(vacc13, vmin);
+ vacc20 = __builtin_wasm_max_f32(vacc20, vmin);
+ vacc21 = __builtin_wasm_max_f32(vacc21, vmin);
+ vacc22 = __builtin_wasm_max_f32(vacc22, vmin);
+ vacc23 = __builtin_wasm_max_f32(vacc23, vmin);
+ vacc30 = __builtin_wasm_max_f32(vacc30, vmin);
+ vacc31 = __builtin_wasm_max_f32(vacc31, vmin);
+ vacc32 = __builtin_wasm_max_f32(vacc32, vmin);
+ vacc33 = __builtin_wasm_max_f32(vacc33, vmin);
+
+ const float vmax = params->scalar.max;
+ vacc00 = __builtin_wasm_min_f32(vacc00, vmax);
+ vacc01 = __builtin_wasm_min_f32(vacc01, vmax);
+ vacc02 = __builtin_wasm_min_f32(vacc02, vmax);
+ vacc03 = __builtin_wasm_min_f32(vacc03, vmax);
+ vacc10 = __builtin_wasm_min_f32(vacc10, vmax);
+ vacc11 = __builtin_wasm_min_f32(vacc11, vmax);
+ vacc12 = __builtin_wasm_min_f32(vacc12, vmax);
+ vacc13 = __builtin_wasm_min_f32(vacc13, vmax);
+ vacc20 = __builtin_wasm_min_f32(vacc20, vmax);
+ vacc21 = __builtin_wasm_min_f32(vacc21, vmax);
+ vacc22 = __builtin_wasm_min_f32(vacc22, vmax);
+ vacc23 = __builtin_wasm_min_f32(vacc23, vmax);
+ vacc30 = __builtin_wasm_min_f32(vacc30, vmax);
+ vacc31 = __builtin_wasm_min_f32(vacc31, vmax);
+ vacc32 = __builtin_wasm_min_f32(vacc32, vmax);
+ vacc33 = __builtin_wasm_min_f32(vacc33, vmax);
+
+ if XNN_LIKELY(nc >= 4) {
+ c3[0] = vacc30;
+ c3[1] = vacc31;
+ c3[2] = vacc32;
+ c3[3] = vacc33;
+ c3 = (float*) ((uintptr_t) c3 + cn_stride);
+ c2[0] = vacc20;
+ c2[1] = vacc21;
+ c2[2] = vacc22;
+ c2[3] = vacc23;
+ c2 = (float*) ((uintptr_t) c2 + cn_stride);
+ c1[0] = vacc10;
+ c1[1] = vacc11;
+ c1[2] = vacc12;
+ c1[3] = vacc13;
+ c1 = (float*) ((uintptr_t) c1 + cn_stride);
+ c0[0] = vacc00;
+ c0[1] = vacc01;
+ c0[2] = vacc02;
+ c0[3] = vacc03;
+ c0 = (float*) ((uintptr_t) c0 + cn_stride);
+
+ a3 = (const void*) ((uintptr_t) a3 - kc);
+ a2 = (const void*) ((uintptr_t) a2 - kc);
+ a1 = (const void*) ((uintptr_t) a1 - kc);
+ a0 = (const void*) ((uintptr_t) a0 - kc);
+
+ nc -= 4;
+ } else {
+ if (nc & 2) {
+ c3[0] = vacc30;
+ c3[1] = vacc31;
+ vacc30 = vacc32;
+ c3 += 2;
+ c2[0] = vacc20;
+ c2[1] = vacc21;
+ vacc20 = vacc22;
+ c2 += 2;
+ c1[0] = vacc10;
+ c1[1] = vacc11;
+ vacc10 = vacc12;
+ c1 += 2;
+ c0[0] = vacc00;
+ c0[1] = vacc01;
+ vacc00 = vacc02;
+ c0 += 2;
+ }
+ if (nc & 1) {
+ c3[0] = vacc30;
+ c2[0] = vacc20;
+ c1[0] = vacc10;
+ c0[0] = vacc00;
+ }
+
+ nc = 0;
+ }
+ } while (nc != 0);
+}
diff --git a/src/f32-gemm/scalar.c.in b/src/f32-gemm/scalar.c.in
index 622f106..90d703f 100644
--- a/src/f32-gemm/scalar.c.in
+++ b/src/f32-gemm/scalar.c.in
@@ -9,7 +9,9 @@
#include <xnnpack/math.h>
-void xnn_f32_gemm${"inc" if INC else ""}_ukernel_${MR}x${NR}__scalar(
+$MIN_F32 = "__builtin_wasm_min_f32" if WASM else "math_min_f32"
+$MAX_F32 = "__builtin_wasm_max_f32" if WASM else "math_max_f32"
+void xnn_f32_gemm${"inc" if INC else ""}_ukernel_${MR}x${NR}__${"wasm" if WASM else "scalar"}(
size_t mr,
size_t nc,
size_t kc,
@@ -88,12 +90,12 @@
const float vmin = params->scalar.min;
$for M in range(MR):
$for N in range(NR):
- vacc${M}${N} = math_max_f32(vacc${M}${N}, vmin);
+ vacc${M}${N} = ${MAX_F32}(vacc${M}${N}, vmin);
const float vmax = params->scalar.max;
$for M in range(MR):
$for N in range(NR):
- vacc${M}${N} = math_min_f32(vacc${M}${N}, vmax);
+ vacc${M}${N} = ${MIN_F32}(vacc${M}${N}, vmax);
if XNN_LIKELY(nc >= ${NR}) {
$for M in reversed(range(MR)):
diff --git a/src/f32-hswish/wasm.c b/src/f32-hswish/wasm.c
new file mode 100644
index 0000000..3a0d2bb
--- /dev/null
+++ b/src/f32-hswish/wasm.c
@@ -0,0 +1,36 @@
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/hswish.h>
+#include <xnnpack/math.h>
+
+
+void xnn_f32_hswish_ukernel__wasm(
+ size_t n,
+ const float* x,
+ float* y,
+ const union xnn_f32_hswish_params params[restrict static 1])
+{
+ assert(n != 0);
+ assert(n % sizeof(float) == 0);
+
+ const float vsixth = params->scalar.sixth;
+ const float vhalf = params->scalar.half;
+ const float vone = params->scalar.one;
+ assert(vhalf == 0.5f);
+ assert(vone == 1.0f);
+
+ do {
+ const float vx = *x++;
+
+ const float vt = __builtin_wasm_min_f32(__builtin_wasm_max_f32(vx * vsixth + vhalf, 0.0f), vone);
+ const float vy = vt * vx;
+
+ *y++ = vy;
+ n -= 4;
+ } while (n != 0);
+}
diff --git a/src/f32-igemm/gen/1x4-wasm.c b/src/f32-igemm/gen/1x4-wasm.c
new file mode 100644
index 0000000..79d8c42
--- /dev/null
+++ b/src/f32-igemm/gen/1x4-wasm.c
@@ -0,0 +1,115 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-igemm/scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/igemm.h>
+#include <xnnpack/math.h>
+
+
+void xnn_f32_igemm_ukernel_1x4__wasm(
+ size_t mr,
+ size_t nc,
+ size_t kc,
+ size_t ks,
+ const float**restrict a,
+ const float*restrict w,
+ float*restrict c,
+ size_t cm_stride,
+ size_t cn_stride,
+ size_t a_offset,
+ const float* zero,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(mr != 0);
+ assert(mr <= 1);
+ assert(nc != 0);
+ assert(kc != 0);
+ assert(kc % sizeof(float) == 0);
+ assert(ks != 0);
+ assert(ks % (1 * sizeof(void*)) == 0);
+ assert(a_offset % sizeof(float) == 0);
+ assert(a != NULL);
+ assert(w != NULL);
+ assert(c != NULL);
+
+ float* c0 = c;
+
+ do {
+ float vacc00 = w[0];
+ float vacc01 = w[1];
+ float vacc02 = w[2];
+ float vacc03 = w[3];
+ w += 4;
+
+ size_t p = ks;
+ do {
+ const float* restrict a0 = a[0];
+ assert(a0 != NULL);
+ if XNN_UNPREDICTABLE(a0 != zero) {
+ a0 = (const float*) ((uintptr_t) a0 + a_offset);
+ }
+ a += 1;
+
+ size_t k = kc;
+ do {
+ const float va0 = *a0++;
+
+ const float vb0 = w[0];
+ const float vb1 = w[1];
+ const float vb2 = w[2];
+ const float vb3 = w[3];
+ w += 4;
+
+ vacc00 += va0 * vb0;
+ vacc01 += va0 * vb1;
+ vacc02 += va0 * vb2;
+ vacc03 += va0 * vb3;
+
+ k -= sizeof(float);
+ } while (k != 0);
+ p -= 1 * sizeof(void*);
+ } while (p != 0);
+
+ const float vmin = params->scalar.min;
+ vacc00 = __builtin_wasm_max_f32(vacc00, vmin);
+ vacc01 = __builtin_wasm_max_f32(vacc01, vmin);
+ vacc02 = __builtin_wasm_max_f32(vacc02, vmin);
+ vacc03 = __builtin_wasm_max_f32(vacc03, vmin);
+
+ const float vmax = params->scalar.max;
+ vacc00 = __builtin_wasm_min_f32(vacc00, vmax);
+ vacc01 = __builtin_wasm_min_f32(vacc01, vmax);
+ vacc02 = __builtin_wasm_min_f32(vacc02, vmax);
+ vacc03 = __builtin_wasm_min_f32(vacc03, vmax);
+
+ if XNN_LIKELY(nc >= 4) {
+ c0[0] = vacc00;
+ c0[1] = vacc01;
+ c0[2] = vacc02;
+ c0[3] = vacc03;
+ c0 = (float*) ((uintptr_t) c0 + cn_stride);
+
+ a = (const float**restrict) ((uintptr_t) a - ks);
+ nc -= 4;
+ } else {
+ if (nc & 2) {
+ c0[0] = vacc00;
+ c0[1] = vacc01;
+ vacc00 = vacc02;
+ c0 += 2;
+ }
+ if (nc & 1) {
+ c0[0] = vacc00;
+ }
+
+ nc = 0;
+ }
+ } while (nc != 0);
+}
diff --git a/src/f32-igemm/gen/2x4-wasm.c b/src/f32-igemm/gen/2x4-wasm.c
new file mode 100644
index 0000000..5347636
--- /dev/null
+++ b/src/f32-igemm/gen/2x4-wasm.c
@@ -0,0 +1,151 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-igemm/scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/igemm.h>
+#include <xnnpack/math.h>
+
+
+void xnn_f32_igemm_ukernel_2x4__wasm(
+ size_t mr,
+ size_t nc,
+ size_t kc,
+ size_t ks,
+ const float**restrict a,
+ const float*restrict w,
+ float*restrict c,
+ size_t cm_stride,
+ size_t cn_stride,
+ size_t a_offset,
+ const float* zero,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(mr != 0);
+ assert(mr <= 2);
+ assert(nc != 0);
+ assert(kc != 0);
+ assert(kc % sizeof(float) == 0);
+ assert(ks != 0);
+ assert(ks % (2 * sizeof(void*)) == 0);
+ assert(a_offset % sizeof(float) == 0);
+ assert(a != NULL);
+ assert(w != NULL);
+ assert(c != NULL);
+
+ float* c0 = c;
+ float* c1 = (float*) ((uintptr_t) c0 + cm_stride);
+ if XNN_UNPREDICTABLE(mr != 2) {
+ c1 = c0;
+ }
+
+ do {
+ float vacc00 = w[0];
+ float vacc01 = w[1];
+ float vacc02 = w[2];
+ float vacc03 = w[3];
+ float vacc10 = vacc00;
+ float vacc11 = vacc01;
+ float vacc12 = vacc02;
+ float vacc13 = vacc03;
+ w += 4;
+
+ size_t p = ks;
+ do {
+ const float* restrict a0 = a[0];
+ assert(a0 != NULL);
+ if XNN_UNPREDICTABLE(a0 != zero) {
+ a0 = (const float*) ((uintptr_t) a0 + a_offset);
+ }
+ const float* restrict a1 = a[1];
+ assert(a1 != NULL);
+ if XNN_UNPREDICTABLE(a1 != zero) {
+ a1 = (const float*) ((uintptr_t) a1 + a_offset);
+ }
+ a += 2;
+
+ size_t k = kc;
+ do {
+ const float va0 = *a0++;
+ const float va1 = *a1++;
+
+ const float vb0 = w[0];
+ const float vb1 = w[1];
+ const float vb2 = w[2];
+ const float vb3 = w[3];
+ w += 4;
+
+ vacc00 += va0 * vb0;
+ vacc01 += va0 * vb1;
+ vacc02 += va0 * vb2;
+ vacc03 += va0 * vb3;
+ vacc10 += va1 * vb0;
+ vacc11 += va1 * vb1;
+ vacc12 += va1 * vb2;
+ vacc13 += va1 * vb3;
+
+ k -= sizeof(float);
+ } while (k != 0);
+ p -= 2 * sizeof(void*);
+ } while (p != 0);
+
+ const float vmin = params->scalar.min;
+ vacc00 = __builtin_wasm_max_f32(vacc00, vmin);
+ vacc01 = __builtin_wasm_max_f32(vacc01, vmin);
+ vacc02 = __builtin_wasm_max_f32(vacc02, vmin);
+ vacc03 = __builtin_wasm_max_f32(vacc03, vmin);
+ vacc10 = __builtin_wasm_max_f32(vacc10, vmin);
+ vacc11 = __builtin_wasm_max_f32(vacc11, vmin);
+ vacc12 = __builtin_wasm_max_f32(vacc12, vmin);
+ vacc13 = __builtin_wasm_max_f32(vacc13, vmin);
+
+ const float vmax = params->scalar.max;
+ vacc00 = __builtin_wasm_min_f32(vacc00, vmax);
+ vacc01 = __builtin_wasm_min_f32(vacc01, vmax);
+ vacc02 = __builtin_wasm_min_f32(vacc02, vmax);
+ vacc03 = __builtin_wasm_min_f32(vacc03, vmax);
+ vacc10 = __builtin_wasm_min_f32(vacc10, vmax);
+ vacc11 = __builtin_wasm_min_f32(vacc11, vmax);
+ vacc12 = __builtin_wasm_min_f32(vacc12, vmax);
+ vacc13 = __builtin_wasm_min_f32(vacc13, vmax);
+
+ if XNN_LIKELY(nc >= 4) {
+ c1[0] = vacc10;
+ c1[1] = vacc11;
+ c1[2] = vacc12;
+ c1[3] = vacc13;
+ c1 = (float*) ((uintptr_t) c1 + cn_stride);
+ c0[0] = vacc00;
+ c0[1] = vacc01;
+ c0[2] = vacc02;
+ c0[3] = vacc03;
+ c0 = (float*) ((uintptr_t) c0 + cn_stride);
+
+ a = (const float**restrict) ((uintptr_t) a - ks);
+ nc -= 4;
+ } else {
+ if (nc & 2) {
+ c1[0] = vacc10;
+ c1[1] = vacc11;
+ vacc10 = vacc12;
+ c1 += 2;
+ c0[0] = vacc00;
+ c0[1] = vacc01;
+ vacc00 = vacc02;
+ c0 += 2;
+ }
+ if (nc & 1) {
+ c1[0] = vacc10;
+ c0[0] = vacc00;
+ }
+
+ nc = 0;
+ }
+ } while (nc != 0);
+}
diff --git a/src/f32-igemm/gen/4x2-wasm.c b/src/f32-igemm/gen/4x2-wasm.c
new file mode 100644
index 0000000..7127072
--- /dev/null
+++ b/src/f32-igemm/gen/4x2-wasm.c
@@ -0,0 +1,163 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-igemm/scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/igemm.h>
+#include <xnnpack/math.h>
+
+
+void xnn_f32_igemm_ukernel_4x2__wasm(
+ size_t mr,
+ size_t nc,
+ size_t kc,
+ size_t ks,
+ const float**restrict a,
+ const float*restrict w,
+ float*restrict c,
+ size_t cm_stride,
+ size_t cn_stride,
+ size_t a_offset,
+ const float* zero,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(mr != 0);
+ assert(mr <= 4);
+ assert(nc != 0);
+ assert(kc != 0);
+ assert(kc % sizeof(float) == 0);
+ assert(ks != 0);
+ assert(ks % (4 * sizeof(void*)) == 0);
+ assert(a_offset % sizeof(float) == 0);
+ assert(a != NULL);
+ assert(w != NULL);
+ assert(c != NULL);
+
+ float* c0 = c;
+ float* c1 = (float*) ((uintptr_t) c0 + cm_stride);
+ if XNN_UNPREDICTABLE(mr < 2) {
+ c1 = c0;
+ }
+ float* c2 = (float*) ((uintptr_t) c1 + cm_stride);
+ if XNN_UNPREDICTABLE(mr <= 2) {
+ c2 = c1;
+ }
+ float* c3 = (float*) ((uintptr_t) c2 + cm_stride);
+ if XNN_UNPREDICTABLE(mr != 4) {
+ c3 = c2;
+ }
+
+ do {
+ float vacc00 = w[0];
+ float vacc01 = w[1];
+ float vacc10 = vacc00;
+ float vacc11 = vacc01;
+ float vacc20 = vacc00;
+ float vacc21 = vacc01;
+ float vacc30 = vacc00;
+ float vacc31 = vacc01;
+ w += 2;
+
+ size_t p = ks;
+ do {
+ const float* restrict a0 = a[0];
+ assert(a0 != NULL);
+ if XNN_UNPREDICTABLE(a0 != zero) {
+ a0 = (const float*) ((uintptr_t) a0 + a_offset);
+ }
+ const float* restrict a1 = a[1];
+ assert(a1 != NULL);
+ if XNN_UNPREDICTABLE(a1 != zero) {
+ a1 = (const float*) ((uintptr_t) a1 + a_offset);
+ }
+ const float* restrict a2 = a[2];
+ assert(a2 != NULL);
+ if XNN_UNPREDICTABLE(a2 != zero) {
+ a2 = (const float*) ((uintptr_t) a2 + a_offset);
+ }
+ const float* restrict a3 = a[3];
+ assert(a3 != NULL);
+ if XNN_UNPREDICTABLE(a3 != zero) {
+ a3 = (const float*) ((uintptr_t) a3 + a_offset);
+ }
+ a += 4;
+
+ size_t k = kc;
+ do {
+ const float va0 = *a0++;
+ const float va1 = *a1++;
+ const float va2 = *a2++;
+ const float va3 = *a3++;
+
+ const float vb0 = w[0];
+ const float vb1 = w[1];
+ w += 2;
+
+ vacc00 += va0 * vb0;
+ vacc01 += va0 * vb1;
+ vacc10 += va1 * vb0;
+ vacc11 += va1 * vb1;
+ vacc20 += va2 * vb0;
+ vacc21 += va2 * vb1;
+ vacc30 += va3 * vb0;
+ vacc31 += va3 * vb1;
+
+ k -= sizeof(float);
+ } while (k != 0);
+ p -= 4 * sizeof(void*);
+ } while (p != 0);
+
+ const float vmin = params->scalar.min;
+ vacc00 = __builtin_wasm_max_f32(vacc00, vmin);
+ vacc01 = __builtin_wasm_max_f32(vacc01, vmin);
+ vacc10 = __builtin_wasm_max_f32(vacc10, vmin);
+ vacc11 = __builtin_wasm_max_f32(vacc11, vmin);
+ vacc20 = __builtin_wasm_max_f32(vacc20, vmin);
+ vacc21 = __builtin_wasm_max_f32(vacc21, vmin);
+ vacc30 = __builtin_wasm_max_f32(vacc30, vmin);
+ vacc31 = __builtin_wasm_max_f32(vacc31, vmin);
+
+ const float vmax = params->scalar.max;
+ vacc00 = __builtin_wasm_min_f32(vacc00, vmax);
+ vacc01 = __builtin_wasm_min_f32(vacc01, vmax);
+ vacc10 = __builtin_wasm_min_f32(vacc10, vmax);
+ vacc11 = __builtin_wasm_min_f32(vacc11, vmax);
+ vacc20 = __builtin_wasm_min_f32(vacc20, vmax);
+ vacc21 = __builtin_wasm_min_f32(vacc21, vmax);
+ vacc30 = __builtin_wasm_min_f32(vacc30, vmax);
+ vacc31 = __builtin_wasm_min_f32(vacc31, vmax);
+
+ if XNN_LIKELY(nc >= 2) {
+ c3[0] = vacc30;
+ c3[1] = vacc31;
+ c3 = (float*) ((uintptr_t) c3 + cn_stride);
+ c2[0] = vacc20;
+ c2[1] = vacc21;
+ c2 = (float*) ((uintptr_t) c2 + cn_stride);
+ c1[0] = vacc10;
+ c1[1] = vacc11;
+ c1 = (float*) ((uintptr_t) c1 + cn_stride);
+ c0[0] = vacc00;
+ c0[1] = vacc01;
+ c0 = (float*) ((uintptr_t) c0 + cn_stride);
+
+ a = (const float**restrict) ((uintptr_t) a - ks);
+ nc -= 2;
+ } else {
+ if (nc & 1) {
+ c3[0] = vacc30;
+ c2[0] = vacc20;
+ c1[0] = vacc10;
+ c0[0] = vacc00;
+ }
+
+ nc = 0;
+ }
+ } while (nc != 0);
+}
diff --git a/src/f32-igemm/gen/4x4-wasm.c b/src/f32-igemm/gen/4x4-wasm.c
new file mode 100644
index 0000000..cf6da4e
--- /dev/null
+++ b/src/f32-igemm/gen/4x4-wasm.c
@@ -0,0 +1,223 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-igemm/scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/igemm.h>
+#include <xnnpack/math.h>
+
+
+void xnn_f32_igemm_ukernel_4x4__wasm(
+ size_t mr,
+ size_t nc,
+ size_t kc,
+ size_t ks,
+ const float**restrict a,
+ const float*restrict w,
+ float*restrict c,
+ size_t cm_stride,
+ size_t cn_stride,
+ size_t a_offset,
+ const float* zero,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(mr != 0);
+ assert(mr <= 4);
+ assert(nc != 0);
+ assert(kc != 0);
+ assert(kc % sizeof(float) == 0);
+ assert(ks != 0);
+ assert(ks % (4 * sizeof(void*)) == 0);
+ assert(a_offset % sizeof(float) == 0);
+ assert(a != NULL);
+ assert(w != NULL);
+ assert(c != NULL);
+
+ float* c0 = c;
+ float* c1 = (float*) ((uintptr_t) c0 + cm_stride);
+ if XNN_UNPREDICTABLE(mr < 2) {
+ c1 = c0;
+ }
+ float* c2 = (float*) ((uintptr_t) c1 + cm_stride);
+ if XNN_UNPREDICTABLE(mr <= 2) {
+ c2 = c1;
+ }
+ float* c3 = (float*) ((uintptr_t) c2 + cm_stride);
+ if XNN_UNPREDICTABLE(mr != 4) {
+ c3 = c2;
+ }
+
+ do {
+ float vacc00 = w[0];
+ float vacc01 = w[1];
+ float vacc02 = w[2];
+ float vacc03 = w[3];
+ float vacc10 = vacc00;
+ float vacc11 = vacc01;
+ float vacc12 = vacc02;
+ float vacc13 = vacc03;
+ float vacc20 = vacc00;
+ float vacc21 = vacc01;
+ float vacc22 = vacc02;
+ float vacc23 = vacc03;
+ float vacc30 = vacc00;
+ float vacc31 = vacc01;
+ float vacc32 = vacc02;
+ float vacc33 = vacc03;
+ w += 4;
+
+ size_t p = ks;
+ do {
+ const float* restrict a0 = a[0];
+ assert(a0 != NULL);
+ if XNN_UNPREDICTABLE(a0 != zero) {
+ a0 = (const float*) ((uintptr_t) a0 + a_offset);
+ }
+ const float* restrict a1 = a[1];
+ assert(a1 != NULL);
+ if XNN_UNPREDICTABLE(a1 != zero) {
+ a1 = (const float*) ((uintptr_t) a1 + a_offset);
+ }
+ const float* restrict a2 = a[2];
+ assert(a2 != NULL);
+ if XNN_UNPREDICTABLE(a2 != zero) {
+ a2 = (const float*) ((uintptr_t) a2 + a_offset);
+ }
+ const float* restrict a3 = a[3];
+ assert(a3 != NULL);
+ if XNN_UNPREDICTABLE(a3 != zero) {
+ a3 = (const float*) ((uintptr_t) a3 + a_offset);
+ }
+ a += 4;
+
+ size_t k = kc;
+ do {
+ const float va0 = *a0++;
+ const float va1 = *a1++;
+ const float va2 = *a2++;
+ const float va3 = *a3++;
+
+ const float vb0 = w[0];
+ const float vb1 = w[1];
+ const float vb2 = w[2];
+ const float vb3 = w[3];
+ w += 4;
+
+ vacc00 += va0 * vb0;
+ vacc01 += va0 * vb1;
+ vacc02 += va0 * vb2;
+ vacc03 += va0 * vb3;
+ vacc10 += va1 * vb0;
+ vacc11 += va1 * vb1;
+ vacc12 += va1 * vb2;
+ vacc13 += va1 * vb3;
+ vacc20 += va2 * vb0;
+ vacc21 += va2 * vb1;
+ vacc22 += va2 * vb2;
+ vacc23 += va2 * vb3;
+ vacc30 += va3 * vb0;
+ vacc31 += va3 * vb1;
+ vacc32 += va3 * vb2;
+ vacc33 += va3 * vb3;
+
+ k -= sizeof(float);
+ } while (k != 0);
+ p -= 4 * sizeof(void*);
+ } while (p != 0);
+
+ const float vmin = params->scalar.min;
+ vacc00 = __builtin_wasm_max_f32(vacc00, vmin);
+ vacc01 = __builtin_wasm_max_f32(vacc01, vmin);
+ vacc02 = __builtin_wasm_max_f32(vacc02, vmin);
+ vacc03 = __builtin_wasm_max_f32(vacc03, vmin);
+ vacc10 = __builtin_wasm_max_f32(vacc10, vmin);
+ vacc11 = __builtin_wasm_max_f32(vacc11, vmin);
+ vacc12 = __builtin_wasm_max_f32(vacc12, vmin);
+ vacc13 = __builtin_wasm_max_f32(vacc13, vmin);
+ vacc20 = __builtin_wasm_max_f32(vacc20, vmin);
+ vacc21 = __builtin_wasm_max_f32(vacc21, vmin);
+ vacc22 = __builtin_wasm_max_f32(vacc22, vmin);
+ vacc23 = __builtin_wasm_max_f32(vacc23, vmin);
+ vacc30 = __builtin_wasm_max_f32(vacc30, vmin);
+ vacc31 = __builtin_wasm_max_f32(vacc31, vmin);
+ vacc32 = __builtin_wasm_max_f32(vacc32, vmin);
+ vacc33 = __builtin_wasm_max_f32(vacc33, vmin);
+
+ const float vmax = params->scalar.max;
+ vacc00 = __builtin_wasm_min_f32(vacc00, vmax);
+ vacc01 = __builtin_wasm_min_f32(vacc01, vmax);
+ vacc02 = __builtin_wasm_min_f32(vacc02, vmax);
+ vacc03 = __builtin_wasm_min_f32(vacc03, vmax);
+ vacc10 = __builtin_wasm_min_f32(vacc10, vmax);
+ vacc11 = __builtin_wasm_min_f32(vacc11, vmax);
+ vacc12 = __builtin_wasm_min_f32(vacc12, vmax);
+ vacc13 = __builtin_wasm_min_f32(vacc13, vmax);
+ vacc20 = __builtin_wasm_min_f32(vacc20, vmax);
+ vacc21 = __builtin_wasm_min_f32(vacc21, vmax);
+ vacc22 = __builtin_wasm_min_f32(vacc22, vmax);
+ vacc23 = __builtin_wasm_min_f32(vacc23, vmax);
+ vacc30 = __builtin_wasm_min_f32(vacc30, vmax);
+ vacc31 = __builtin_wasm_min_f32(vacc31, vmax);
+ vacc32 = __builtin_wasm_min_f32(vacc32, vmax);
+ vacc33 = __builtin_wasm_min_f32(vacc33, vmax);
+
+ if XNN_LIKELY(nc >= 4) {
+ c3[0] = vacc30;
+ c3[1] = vacc31;
+ c3[2] = vacc32;
+ c3[3] = vacc33;
+ c3 = (float*) ((uintptr_t) c3 + cn_stride);
+ c2[0] = vacc20;
+ c2[1] = vacc21;
+ c2[2] = vacc22;
+ c2[3] = vacc23;
+ c2 = (float*) ((uintptr_t) c2 + cn_stride);
+ c1[0] = vacc10;
+ c1[1] = vacc11;
+ c1[2] = vacc12;
+ c1[3] = vacc13;
+ c1 = (float*) ((uintptr_t) c1 + cn_stride);
+ c0[0] = vacc00;
+ c0[1] = vacc01;
+ c0[2] = vacc02;
+ c0[3] = vacc03;
+ c0 = (float*) ((uintptr_t) c0 + cn_stride);
+
+ a = (const float**restrict) ((uintptr_t) a - ks);
+ nc -= 4;
+ } else {
+ if (nc & 2) {
+ c3[0] = vacc30;
+ c3[1] = vacc31;
+ vacc30 = vacc32;
+ c3 += 2;
+ c2[0] = vacc20;
+ c2[1] = vacc21;
+ vacc20 = vacc22;
+ c2 += 2;
+ c1[0] = vacc10;
+ c1[1] = vacc11;
+ vacc10 = vacc12;
+ c1 += 2;
+ c0[0] = vacc00;
+ c0[1] = vacc01;
+ vacc00 = vacc02;
+ c0 += 2;
+ }
+ if (nc & 1) {
+ c3[0] = vacc30;
+ c2[0] = vacc20;
+ c1[0] = vacc10;
+ c0[0] = vacc00;
+ }
+
+ nc = 0;
+ }
+ } while (nc != 0);
+}
diff --git a/src/f32-igemm/scalar.c.in b/src/f32-igemm/scalar.c.in
index e4a8161..d713f51 100644
--- a/src/f32-igemm/scalar.c.in
+++ b/src/f32-igemm/scalar.c.in
@@ -9,7 +9,9 @@
#include <xnnpack/math.h>
-void xnn_f32_igemm_ukernel_${MR}x${NR}__scalar(
+$MIN_F32 = "__builtin_wasm_min_f32" if WASM else "math_min_f32"
+$MAX_F32 = "__builtin_wasm_max_f32" if WASM else "math_max_f32"
+void xnn_f32_igemm_ukernel_${MR}x${NR}__${"wasm" if WASM else "scalar"}(
size_t mr,
size_t nc,
size_t kc,
@@ -90,12 +92,12 @@
const float vmin = params->scalar.min;
$for M in range(MR):
$for N in range(NR):
- vacc${M}${N} = math_max_f32(vacc${M}${N}, vmin);
+ vacc${M}${N} = ${MAX_F32}(vacc${M}${N}, vmin);
const float vmax = params->scalar.max;
$for M in range(MR):
$for N in range(NR):
- vacc${M}${N} = math_min_f32(vacc${M}${N}, vmax);
+ vacc${M}${N} = ${MIN_F32}(vacc${M}${N}, vmax);
if XNN_LIKELY(nc >= ${NR}) {
$for M in reversed(range(MR)):
diff --git a/src/f32-maxpool/9p8x-wasm-c1.c b/src/f32-maxpool/9p8x-wasm-c1.c
new file mode 100644
index 0000000..fcad9e5
--- /dev/null
+++ b/src/f32-maxpool/9p8x-wasm-c1.c
@@ -0,0 +1,173 @@
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/maxpool.h>
+#include <xnnpack/math.h>
+
+
+void xnn_f32_maxpool_ukernel_9p8x__wasm_c1(
+ size_t output_pixels,
+ size_t kernel_elements,
+ size_t channels,
+ const float** input,
+ size_t input_offset,
+ float* output,
+ size_t input_increment,
+ size_t output_increment,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(output_pixels != 0);
+ assert(kernel_elements != 0);
+ assert(channels != 0);
+
+ const float voutput_min = params->scalar.min;
+ const float voutput_max = params->scalar.max;
+ do {
+ float* o = output;
+ {
+ const float* i0 = *input++;
+ const float* i1 = *input++;
+ const float* i2 = *input++;
+ const float* i3 = *input++;
+ const float* i4 = *input++;
+ const float* i5 = *input++;
+ const float* i6 = *input++;
+ const float* i7 = *input++;
+ const float* i8 = *input++;
+ i0 = (const float*) ((uintptr_t) i0 + input_offset);
+ i1 = (const float*) ((uintptr_t) i1 + input_offset);
+ i2 = (const float*) ((uintptr_t) i2 + input_offset);
+ i3 = (const float*) ((uintptr_t) i3 + input_offset);
+ i4 = (const float*) ((uintptr_t) i4 + input_offset);
+ i5 = (const float*) ((uintptr_t) i5 + input_offset);
+ i6 = (const float*) ((uintptr_t) i6 + input_offset);
+ i7 = (const float*) ((uintptr_t) i7 + input_offset);
+ i8 = (const float*) ((uintptr_t) i8 + input_offset);
+ if (kernel_elements < 2) {
+ i1 = i0;
+ }
+ if (kernel_elements <= 2) {
+ i2 = i0;
+ }
+ if (kernel_elements < 4) {
+ i3 = i0;
+ }
+ if (kernel_elements <= 4) {
+ i4 = i0;
+ }
+ if (kernel_elements < 6) {
+ i5 = i0;
+ }
+ if (kernel_elements <= 6) {
+ i6 = i0;
+ }
+ if (kernel_elements < 8) {
+ i7 = i0;
+ }
+ if (kernel_elements <= 8) {
+ i8 = i0;
+ }
+
+ size_t c = channels;
+ do {
+ const float vi0 = *i0++;
+ const float vi1 = *i1++;
+ const float vi2 = *i2++;
+ const float vi3 = *i3++;
+ const float vi4 = *i4++;
+ const float vi5 = *i5++;
+ const float vi6 = *i6++;
+ const float vi7 = *i7++;
+ const float vi8 = *i8++;
+
+ const float vmax01 = __builtin_wasm_max_f32(vi0, vi1);
+ const float vmax23 = __builtin_wasm_max_f32(vi2, vi3);
+ const float vmax45 = __builtin_wasm_max_f32(vi4, vi5);
+ const float vmax67 = __builtin_wasm_max_f32(vi6, vi7);
+ const float vmax018 = __builtin_wasm_max_f32(vmax01, vi8);
+
+ const float vmax2345 = __builtin_wasm_max_f32(vmax23, vmax45);
+ const float vmax01678 = __builtin_wasm_max_f32(vmax018, vmax67);
+ float vout = __builtin_wasm_max_f32(vmax2345, vmax01678);
+ vout = __builtin_wasm_max_f32(vout, voutput_min);
+ vout = __builtin_wasm_min_f32(vout, voutput_max);
+
+ *o++ = vout;
+ } while (--c != 0);
+ }
+
+ for (ptrdiff_t k = (ptrdiff_t) kernel_elements - 9; k > 0; k -= 8) {
+ const float* i0 = *input++;
+ const float* i1 = *input++;
+ const float* i2 = *input++;
+ const float* i3 = *input++;
+ const float* i4 = *input++;
+ const float* i5 = *input++;
+ const float* i6 = *input++;
+ const float* i7 = *input++;
+ i0 = (const float*) ((uintptr_t) i0 + input_offset);
+ i1 = (const float*) ((uintptr_t) i1 + input_offset);
+ i2 = (const float*) ((uintptr_t) i2 + input_offset);
+ i3 = (const float*) ((uintptr_t) i3 + input_offset);
+ i4 = (const float*) ((uintptr_t) i4 + input_offset);
+ i5 = (const float*) ((uintptr_t) i5 + input_offset);
+ i6 = (const float*) ((uintptr_t) i6 + input_offset);
+ i7 = (const float*) ((uintptr_t) i7 + input_offset);
+ if (k < 2) {
+ i1 = i0;
+ }
+ if (k <= 2) {
+ i2 = i0;
+ }
+ if (k < 4) {
+ i3 = i0;
+ }
+ if (k <= 4) {
+ i4 = i0;
+ }
+ if (k < 6) {
+ i5 = i0;
+ }
+ if (k <= 6) {
+ i6 = i0;
+ }
+ if (k < 8) {
+ i7 = i0;
+ }
+
+ o = output;
+ size_t c = channels;
+ do {
+ const float vi0 = *i0++;
+ const float vi1 = *i1++;
+ const float vi2 = *i2++;
+ const float vi3 = *i3++;
+ const float vi4 = *i4++;
+ const float vi5 = *i5++;
+ const float vi6 = *i6++;
+ const float vi7 = *i7++;
+ const float vi8 = *o;
+
+ const float vmax01 = __builtin_wasm_max_f32(vi0, vi1);
+ const float vmax23 = __builtin_wasm_max_f32(vi2, vi3);
+ const float vmax45 = __builtin_wasm_max_f32(vi4, vi5);
+ const float vmax67 = __builtin_wasm_max_f32(vi6, vi7);
+ const float vmax018 = __builtin_wasm_max_f32(vmax01, vi8);
+
+ const float vmax2345 = __builtin_wasm_max_f32(vmax23, vmax45);
+ const float vmax01678 = __builtin_wasm_max_f32(vmax018, vmax67);
+ float vout = __builtin_wasm_max_f32(vmax2345, vmax01678);
+ vout = __builtin_wasm_max_f32(vout, voutput_min);
+ vout = __builtin_wasm_min_f32(vout, voutput_max);
+
+ *o++ = vout;
+ } while (--c != 0);
+ }
+ input = (const float**) ((uintptr_t) input + input_increment);
+ output = (float*) ((uintptr_t) o + output_increment);
+ } while (--output_pixels != 0);
+}
diff --git a/src/f32-pavgpool/mp9p8q-wasm.c b/src/f32-pavgpool/mp9p8q-wasm.c
new file mode 100644
index 0000000..479f0a6
--- /dev/null
+++ b/src/f32-pavgpool/mp9p8q-wasm.c
@@ -0,0 +1,172 @@
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/pavgpool.h>
+#include <xnnpack/math.h>
+
+
+void xnn_f32_pavgpool_ukernel_mp9p8q__wasm(
+ size_t n,
+ size_t ks,
+ size_t kc,
+ const float** input,
+ const float* zero,
+ const float* multiplier,
+ float* buffer,
+ float* output,
+ size_t input_increment,
+ size_t output_increment,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(n != 0);
+ assert(ks > 9);
+ assert(kc != 0);
+
+ const float voutput_min = params->scalar.min;
+ const float voutput_max = params->scalar.max;
+
+ do {
+ {
+ const float* i0 = *input++;
+ const float* i1 = *input++;
+ const float* i2 = *input++;
+ const float* i3 = *input++;
+ const float* i4 = *input++;
+ const float* i5 = *input++;
+ const float* i6 = *input++;
+ const float* i7 = *input++;
+ const float* i8 = *input++;
+
+ float* b = buffer;
+ size_t k = kc;
+ do {
+ const float vi0 = *i0++;
+ const float vi1 = *i1++;
+ const float vi2 = *i2++;
+ const float vi3 = *i3++;
+ const float vi4 = *i4++;
+ const float vi5 = *i5++;
+ const float vi6 = *i6++;
+ const float vi7 = *i7++;
+ const float vi8 = *i8++;
+
+ const float vsum01 = vi0 + vi1;
+ const float vsum23 = vi2 + vi3;
+ const float vsum45 = vi4 + vi5;
+ const float vsum67 = vi6 + vi7;
+ const float vsum018 = vsum01 + vi8;
+ const float vsum2345 = vsum23 + vsum45;
+ const float vsum01678 = vsum018 + vsum67;
+ const float vsum = vsum2345 + vsum01678;
+
+ *b++ = vsum;
+ } while (--k != 0);
+ }
+
+ size_t m = ks;
+ for (m -= 9; m > 8; m -= 8) {
+ const float* i0 = *input++;
+ const float* i1 = *input++;
+ const float* i2 = *input++;
+ const float* i3 = *input++;
+ const float* i4 = *input++;
+ const float* i5 = *input++;
+ const float* i6 = *input++;
+ const float* i7 = *input++;
+
+ float* b = buffer;
+ size_t k = kc;
+ do {
+ const float vi0 = *i0++;
+ const float vi1 = *i1++;
+ const float vi2 = *i2++;
+ const float vi3 = *i3++;
+ const float vi4 = *i4++;
+ const float vi5 = *i5++;
+ const float vi6 = *i6++;
+ const float vi7 = *i7++;
+ const float vacc = *b;
+
+ const float vsum01 = vi0 + vi1;
+ const float vsum23 = vi2 + vi3;
+ const float vsum45 = vi4 + vi5;
+ const float vsum67 = vi6 + vi7;
+ const float vsum01a = vsum01 + vacc;
+ const float vsum2345 = vsum23 + vsum45;
+ const float vsum0167a = vsum01a + vsum67;
+ const float vsum = vsum2345 + vsum0167a;
+
+ *b++ = vsum;
+ } while (--k != 0);
+ }
+
+ {
+ const float* i0 = input[0];
+ const float* i1 = input[1];
+ const float* i2 = input[2];
+ const float* i3 = input[3];
+ const float* i4 = input[4];
+ const float* i5 = input[5];
+ const float* i6 = input[6];
+ const float* i7 = input[7];
+ input = (const float**) ((uintptr_t) input + input_increment);
+ if (m < 2) {
+ i1 = zero;
+ }
+ if (m <= 2) {
+ i2 = zero;
+ }
+ if (m < 4) {
+ i3 = zero;
+ }
+ if (m <= 4) {
+ i4 = zero;
+ }
+ if (m < 6) {
+ i5 = zero;
+ }
+ if (m <= 6) {
+ i6 = zero;
+ }
+ if (m != 8) {
+ i7 = zero;
+ }
+
+ const float vmultiplier = *multiplier++;
+
+ size_t k = kc;
+ float* b = buffer;
+ do {
+ const float vi0 = *i0++;
+ const float vi1 = *i1++;
+ const float vi2 = *i2++;
+ const float vi3 = *i3++;
+ const float vi4 = *i4++;
+ const float vi5 = *i5++;
+ const float vi6 = *i6++;
+ const float vi7 = *i7++;
+ const float vacc = *b++;
+
+ const float vsum01 = vi0 + vi1;
+ const float vsum23 = vi2 + vi3;
+ const float vsum45 = vi4 + vi5;
+ const float vsum67 = vi6 + vi7;
+ const float vsum01a = vsum01 + vacc;
+ const float vsum2345 = vsum23 + vsum45;
+ const float vsum0167a = vsum01a + vsum67;
+ const float vsum = vsum2345 + vsum0167a;
+
+ float vout = vsum * vmultiplier;
+ vout = __builtin_wasm_max_f32(vout, voutput_min);
+ vout = __builtin_wasm_min_f32(vout, voutput_max);
+
+ *output++ = vout;
+ } while (--k != 0);
+ }
+ output = (float*) ((uintptr_t) output + output_increment);
+ } while (--n != 0);
+}
diff --git a/src/f32-pavgpool/up9-wasm.c b/src/f32-pavgpool/up9-wasm.c
new file mode 100644
index 0000000..6932907
--- /dev/null
+++ b/src/f32-pavgpool/up9-wasm.c
@@ -0,0 +1,99 @@
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/pavgpool.h>
+#include <xnnpack/math.h>
+
+
+void xnn_f32_pavgpool_ukernel_up9__wasm(
+ size_t n,
+ size_t ks,
+ size_t kc,
+ const float** input,
+ const float* zero,
+ const float* multiplier,
+ float* output,
+ size_t input_increment,
+ size_t output_increment,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(n != 0);
+ assert(ks != 0);
+ assert(ks <= 9);
+ assert(kc != 0);
+
+ const float voutput_min = params->scalar.min;
+ const float voutput_max = params->scalar.max;
+
+ do {
+ const float* i0 = input[0];
+ const float* i1 = input[1];
+ const float* i2 = input[2];
+ const float* i3 = input[3];
+ const float* i4 = input[4];
+ const float* i5 = input[5];
+ const float* i6 = input[6];
+ const float* i7 = input[7];
+ const float* i8 = input[8];
+ input = (const float**) ((uintptr_t) input + input_increment);
+ if (ks < 2) {
+ i1 = zero;
+ }
+ if (ks <= 2) {
+ i2 = zero;
+ }
+ if (ks < 4) {
+ i3 = zero;
+ }
+ if (ks <= 4) {
+ i4 = zero;
+ }
+ if (ks < 6) {
+ i5 = zero;
+ }
+ if (ks <= 6) {
+ i6 = zero;
+ }
+ if (ks < 8) {
+ i7 = zero;
+ }
+ if (ks <= 8) {
+ i8 = zero;
+ }
+
+ const float vmultiplier = *multiplier++;
+
+ size_t k = kc;
+ do {
+ const float vi0 = *i0++;
+ const float vi1 = *i1++;
+ const float vi2 = *i2++;
+ const float vi3 = *i3++;
+ const float vi4 = *i4++;
+ const float vi5 = *i5++;
+ const float vi6 = *i6++;
+ const float vi7 = *i7++;
+ const float vi8 = *i8++;
+
+ const float vsum01 = vi0 + vi1;
+ const float vsum23 = vi2 + vi3;
+ const float vsum45 = vi4 + vi5;
+ const float vsum67 = vi6 + vi7;
+ const float vsum018 = vsum01 + vi8;
+ const float vsum2345 = vsum23 + vsum45;
+ const float vsum01678 = vsum018 + vsum67;
+ const float vsum = vsum2345 + vsum01678;
+
+ float vout = vsum * vmultiplier;
+ vout = __builtin_wasm_max_f32(vout, voutput_min);
+ vout = __builtin_wasm_min_f32(vout, voutput_max);
+
+ *output++ = vout;
+ } while (--k != 0);
+ output = (float*) ((uintptr_t) output + output_increment);
+ } while (--n != 0);
+}
diff --git a/src/f32-prelu/gen/wasm-2x1.c b/src/f32-prelu/gen/wasm-2x1.c
new file mode 100644
index 0000000..30dceff
--- /dev/null
+++ b/src/f32-prelu/gen/wasm-2x1.c
@@ -0,0 +1,79 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-prelu/scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <math.h>
+
+#include <xnnpack/math.h>
+#include <xnnpack/prelu.h>
+
+
+void xnn_f32_prelu_ukernel__wasm_2x1(
+ size_t rows,
+ size_t channels,
+ const float*restrict input,
+ size_t input_stride,
+ const float*restrict weights,
+ float*restrict output,
+ size_t output_stride,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(rows != 0);
+ assert(channels != 0);
+ assert(channels % sizeof(float) == 0);
+
+ const float* i0 = input;
+ float* o0 = output;
+ const float* i1 = (const float*) ((uintptr_t) i0 + input_stride);
+ float* o1 = (float*) ((uintptr_t) o0 + output_stride);
+ if XNN_UNPREDICTABLE(rows < 2) {
+ i1 = i0;
+ o1 = o0;
+ }
+
+ const size_t input_increment = input_stride * 2 - channels;
+ const size_t output_increment = output_stride * 2 - channels;
+
+ const float vmin = params->scalar.min;
+ const float vmax = params->scalar.max;
+ do {
+ const float* w = weights;
+ size_t c = channels;
+ do {
+ const float vw = *w++;
+
+ const float vi0 = *i0++;
+ const float vi1 = *i1++;
+
+ float vacc0 = signbit(vi0) ? vi0 * vw : vi0;
+ float vacc1 = signbit(vi1) ? vi1 * vw : vi1;
+
+ vacc0 = __builtin_wasm_max_f32(vacc0, vmin);
+ vacc1 = __builtin_wasm_max_f32(vacc1, vmin);
+
+ vacc0 = __builtin_wasm_min_f32(vacc0, vmax);
+ vacc1 = __builtin_wasm_min_f32(vacc1, vmax);
+
+ *o0++ = vacc0;
+ *o1++ = vacc1;
+
+ c -= sizeof(float);
+ } while (c != 0);
+ i0 = (const float*) ((uintptr_t) i0 + input_increment);
+ o0 = (float*) ((uintptr_t) o0 + output_increment);
+ i1 = (const float*) ((uintptr_t) i1 + input_increment);
+ o1 = (float*) ((uintptr_t) o1 + output_increment);
+ if XNN_UNPREDICTABLE(rows < 4) {
+ i1 = i0;
+ o1 = o0;
+ }
+ rows = doz(rows, 2);
+ } while (rows != 0);
+}
diff --git a/src/f32-prelu/gen/wasm-2x4.c b/src/f32-prelu/gen/wasm-2x4.c
new file mode 100644
index 0000000..9ec1380
--- /dev/null
+++ b/src/f32-prelu/gen/wasm-2x4.c
@@ -0,0 +1,134 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-prelu/scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <math.h>
+
+#include <xnnpack/math.h>
+#include <xnnpack/prelu.h>
+
+
+void xnn_f32_prelu_ukernel__wasm_2x4(
+ size_t rows,
+ size_t channels,
+ const float*restrict input,
+ size_t input_stride,
+ const float*restrict weights,
+ float*restrict output,
+ size_t output_stride,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(rows != 0);
+ assert(channels != 0);
+ assert(channels % sizeof(float) == 0);
+
+ const float* i0 = input;
+ float* o0 = output;
+ const float* i1 = (const float*) ((uintptr_t) i0 + input_stride);
+ float* o1 = (float*) ((uintptr_t) o0 + output_stride);
+ if XNN_UNPREDICTABLE(rows < 2) {
+ i1 = i0;
+ o1 = o0;
+ }
+
+ const size_t input_increment = input_stride * 2 - channels;
+ const size_t output_increment = output_stride * 2 - channels;
+
+ const float vmin = params->scalar.min;
+ const float vmax = params->scalar.max;
+ do {
+ const float* w = weights;
+ size_t c = channels;
+ for (; c >= 4 * sizeof(float); c -= 4 * sizeof(float)) {
+ const float vw0 = w[0];
+ const float vw1 = w[1];
+ const float vw2 = w[2];
+ const float vw3 = w[3];
+
+ const float vi0x0 = i0[0];
+ const float vi0x1 = i0[1];
+ const float vi0x2 = i0[2];
+ const float vi0x3 = i0[3];
+ i0 += 4;
+ const float vi1x0 = i1[0];
+ const float vi1x1 = i1[1];
+ const float vi1x2 = i1[2];
+ const float vi1x3 = i1[3];
+ i1 += 4;
+
+ float vacc0x0 = signbit(vi0x0) ? vi0x0 * vw0 : vi0x0;
+ float vacc0x1 = signbit(vi0x1) ? vi0x1 * vw1 : vi0x1;
+ float vacc0x2 = signbit(vi0x2) ? vi0x2 * vw2 : vi0x2;
+ float vacc0x3 = signbit(vi0x3) ? vi0x3 * vw3 : vi0x3;
+ float vacc1x0 = signbit(vi1x0) ? vi1x0 * vw0 : vi1x0;
+ float vacc1x1 = signbit(vi1x1) ? vi1x1 * vw1 : vi1x1;
+ float vacc1x2 = signbit(vi1x2) ? vi1x2 * vw2 : vi1x2;
+ float vacc1x3 = signbit(vi1x3) ? vi1x3 * vw3 : vi1x3;
+
+ vacc0x0 = __builtin_wasm_max_f32(vacc0x0, vmin);
+ vacc0x1 = __builtin_wasm_max_f32(vacc0x1, vmin);
+ vacc0x2 = __builtin_wasm_max_f32(vacc0x2, vmin);
+ vacc0x3 = __builtin_wasm_max_f32(vacc0x3, vmin);
+ vacc1x0 = __builtin_wasm_max_f32(vacc1x0, vmin);
+ vacc1x1 = __builtin_wasm_max_f32(vacc1x1, vmin);
+ vacc1x2 = __builtin_wasm_max_f32(vacc1x2, vmin);
+ vacc1x3 = __builtin_wasm_max_f32(vacc1x3, vmin);
+
+ vacc0x0 = __builtin_wasm_min_f32(vacc0x0, vmax);
+ vacc0x1 = __builtin_wasm_min_f32(vacc0x1, vmax);
+ vacc0x2 = __builtin_wasm_min_f32(vacc0x2, vmax);
+ vacc0x3 = __builtin_wasm_min_f32(vacc0x3, vmax);
+ vacc1x0 = __builtin_wasm_min_f32(vacc1x0, vmax);
+ vacc1x1 = __builtin_wasm_min_f32(vacc1x1, vmax);
+ vacc1x2 = __builtin_wasm_min_f32(vacc1x2, vmax);
+ vacc1x3 = __builtin_wasm_min_f32(vacc1x3, vmax);
+
+ o0[0] = vacc0x0;
+ o0[1] = vacc0x1;
+ o0[2] = vacc0x2;
+ o0[3] = vacc0x3;
+ o0 += 4;
+ o1[0] = vacc1x0;
+ o1[1] = vacc1x1;
+ o1[2] = vacc1x2;
+ o1[3] = vacc1x3;
+ o1 += 4;
+
+ w += 4;
+ }
+ for (; c != 0; c -= sizeof(float)) {
+ const float vw = *w++;
+
+ const float vi0 = *i0++;
+ const float vi1 = *i1++;
+
+ float vacc0 = signbit(vi0) ? vi0 * vw : vi0;
+ float vacc1 = signbit(vi1) ? vi1 * vw : vi1;
+
+ vacc0 = __builtin_wasm_max_f32(vacc0, vmin);
+ vacc1 = __builtin_wasm_max_f32(vacc1, vmin);
+
+ vacc0 = __builtin_wasm_min_f32(vacc0, vmax);
+ vacc1 = __builtin_wasm_min_f32(vacc1, vmax);
+
+ *o0++ = vacc0;
+ *o1++ = vacc1;
+ }
+ i0 = (const float*) ((uintptr_t) i0 + input_increment);
+ o0 = (float*) ((uintptr_t) o0 + output_increment);
+ i1 = (const float*) ((uintptr_t) i1 + input_increment);
+ o1 = (float*) ((uintptr_t) o1 + output_increment);
+ if XNN_UNPREDICTABLE(rows < 4) {
+ i1 = i0;
+ o1 = o0;
+ }
+ rows = doz(rows, 2);
+ } while (rows != 0);
+}
diff --git a/src/f32-prelu/scalar.c.in b/src/f32-prelu/scalar.c.in
index f776987..e0f9bc3 100644
--- a/src/f32-prelu/scalar.c.in
+++ b/src/f32-prelu/scalar.c.in
@@ -14,7 +14,9 @@
#include <xnnpack/prelu.h>
-void xnn_f32_prelu_ukernel__scalar_${ROW_TILE}x${CHANNEL_TILE}(
+$MIN_F32 = "__builtin_wasm_min_f32" if WASM else "math_min_f32"
+$MAX_F32 = "__builtin_wasm_max_f32" if WASM else "math_max_f32"
+void xnn_f32_prelu_ukernel__${"wasm" if WASM else "scalar"}_${ROW_TILE}x${CHANNEL_TILE}(
size_t rows,
size_t channels,
const float*restrict input,
@@ -68,11 +70,11 @@
$for M in range(ROW_TILE):
$for C in range(CHANNEL_TILE):
- vacc${M}x${ABC[C]} = math_max_f32(vacc${M}x${ABC[C]}, vmin);
+ vacc${M}x${ABC[C]} = ${MAX_F32}(vacc${M}x${ABC[C]}, vmin);
$for M in range(ROW_TILE):
$for C in range(CHANNEL_TILE):
- vacc${M}x${ABC[C]} = math_min_f32(vacc${M}x${ABC[C]}, vmax);
+ vacc${M}x${ABC[C]} = ${MIN_F32}(vacc${M}x${ABC[C]}, vmax);
$for M in range(ROW_TILE):
$for C in range(CHANNEL_TILE):
@@ -91,10 +93,10 @@
float vacc${M} = signbit(vi${M}) ? vi${M} * vw : vi${M};
$for M in range(ROW_TILE):
- vacc${M} = math_max_f32(vacc${M}, vmin);
+ vacc${M} = ${MAX_F32}(vacc${M}, vmin);
$for M in range(ROW_TILE):
- vacc${M} = math_min_f32(vacc${M}, vmax);
+ vacc${M} = ${MIN_F32}(vacc${M}, vmax);
$for M in range(ROW_TILE):
*o${M}++ = vacc${M};
@@ -112,11 +114,11 @@
$for M in range(ROW_TILE):
$for C in range(CHANNEL_TILE):
- vacc${M} = math_max_f32(vacc${M}, vmin);
+ vacc${M} = ${MAX_F32}(vacc${M}, vmin);
$for M in range(ROW_TILE):
$for C in range(CHANNEL_TILE):
- vacc${M} = math_min_f32(vacc${M}, vmax);
+ vacc${M} = ${MIN_F32}(vacc${M}, vmax);
$for M in range(ROW_TILE):
*o${M}++ = vacc${M};
diff --git a/src/f32-vbinary/gen/vadd-wasm-x1.c b/src/f32-vbinary/gen/vadd-wasm-x1.c
new file mode 100644
index 0000000..ee2811e
--- /dev/null
+++ b/src/f32-vbinary/gen/vadd-wasm-x1.c
@@ -0,0 +1,38 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-vbinary/vop-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/common.h>
+#include <xnnpack/math.h>
+#include <xnnpack/vbinary.h>
+
+
+void xnn_f32_vadd_ukernel__wasm_x1(
+ size_t n,
+ const float* a,
+ const float* b,
+ float* y,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(n != 0);
+ assert(n % sizeof(float) == 0);
+
+ const float vy_min = params->scalar.min;
+ const float vy_max = params->scalar.max;
+
+ for (; n >= sizeof(float); n -= sizeof(float)) {
+ const float va = *a++;
+ const float vb = *b++;
+ float vy = va + vb;
+ vy = __builtin_wasm_max_f32(vy, vy_min);
+ vy = __builtin_wasm_min_f32(vy, vy_max);
+ *y++ = vy;
+ }
+}
diff --git a/src/f32-vbinary/gen/vadd-wasm-x2.c b/src/f32-vbinary/gen/vadd-wasm-x2.c
new file mode 100644
index 0000000..86fb847
--- /dev/null
+++ b/src/f32-vbinary/gen/vadd-wasm-x2.c
@@ -0,0 +1,60 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-vbinary/vop-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/common.h>
+#include <xnnpack/math.h>
+#include <xnnpack/vbinary.h>
+
+
+void xnn_f32_vadd_ukernel__wasm_x2(
+ size_t n,
+ const float* a,
+ const float* b,
+ float* y,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(n != 0);
+ assert(n % sizeof(float) == 0);
+
+ const float vy_min = params->scalar.min;
+ const float vy_max = params->scalar.max;
+
+ for (; n >= 2 * sizeof(float); n -= 2 * sizeof(float)) {
+ const float va0 = a[0];
+ const float va1 = a[1];
+ a += 2;
+
+ const float vb0 = b[0];
+ const float vb1 = b[1];
+ b += 2;
+
+ float vy0 = va0 + vb0;
+ float vy1 = va1 + vb1;
+
+ vy0 = __builtin_wasm_max_f32(vy0, vy_min);
+ vy1 = __builtin_wasm_max_f32(vy1, vy_min);
+
+ vy0 = __builtin_wasm_min_f32(vy0, vy_max);
+ vy1 = __builtin_wasm_min_f32(vy1, vy_max);
+
+ y[0] = vy0;
+ y[1] = vy1;
+ y += 2;
+ }
+ if XNN_UNLIKELY(n != 0) {
+ const float va = *a;
+ const float vb = *b;
+ float vy = va + vb;
+ vy = __builtin_wasm_max_f32(vy, vy_min);
+ vy = __builtin_wasm_min_f32(vy, vy_max);
+ *y = vy;
+ }
+}
diff --git a/src/f32-vbinary/gen/vadd-wasm-x4.c b/src/f32-vbinary/gen/vadd-wasm-x4.c
new file mode 100644
index 0000000..11da45e
--- /dev/null
+++ b/src/f32-vbinary/gen/vadd-wasm-x4.c
@@ -0,0 +1,75 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-vbinary/vop-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/common.h>
+#include <xnnpack/math.h>
+#include <xnnpack/vbinary.h>
+
+
+void xnn_f32_vadd_ukernel__wasm_x4(
+ size_t n,
+ const float* a,
+ const float* b,
+ float* y,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(n != 0);
+ assert(n % sizeof(float) == 0);
+
+ const float vy_min = params->scalar.min;
+ const float vy_max = params->scalar.max;
+
+ for (; n >= 4 * sizeof(float); n -= 4 * sizeof(float)) {
+ const float va0 = a[0];
+ const float va1 = a[1];
+ const float va2 = a[2];
+ const float va3 = a[3];
+ a += 4;
+
+ const float vb0 = b[0];
+ const float vb1 = b[1];
+ const float vb2 = b[2];
+ const float vb3 = b[3];
+ b += 4;
+
+ float vy0 = va0 + vb0;
+ float vy1 = va1 + vb1;
+ float vy2 = va2 + vb2;
+ float vy3 = va3 + vb3;
+
+ vy0 = __builtin_wasm_max_f32(vy0, vy_min);
+ vy1 = __builtin_wasm_max_f32(vy1, vy_min);
+ vy2 = __builtin_wasm_max_f32(vy2, vy_min);
+ vy3 = __builtin_wasm_max_f32(vy3, vy_min);
+
+ vy0 = __builtin_wasm_min_f32(vy0, vy_max);
+ vy1 = __builtin_wasm_min_f32(vy1, vy_max);
+ vy2 = __builtin_wasm_min_f32(vy2, vy_max);
+ vy3 = __builtin_wasm_min_f32(vy3, vy_max);
+
+ y[0] = vy0;
+ y[1] = vy1;
+ y[2] = vy2;
+ y[3] = vy3;
+ y += 4;
+ }
+ if XNN_UNLIKELY(n != 0) {
+ do {
+ const float va = *a++;
+ const float vb = *b++;
+ float vy = va + vb;
+ vy = __builtin_wasm_max_f32(vy, vy_min);
+ vy = __builtin_wasm_min_f32(vy, vy_max);
+ *y++ = vy;
+ n -= sizeof(float);
+ } while (n != 0);
+ }
+}
diff --git a/src/f32-vbinary/gen/vaddc-wasm-x1.c b/src/f32-vbinary/gen/vaddc-wasm-x1.c
new file mode 100644
index 0000000..141a621
--- /dev/null
+++ b/src/f32-vbinary/gen/vaddc-wasm-x1.c
@@ -0,0 +1,38 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-vbinary/vopc-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/common.h>
+#include <xnnpack/math.h>
+#include <xnnpack/vbinary.h>
+
+
+void xnn_f32_vaddc_ukernel__wasm_x1(
+ size_t n,
+ const float* a,
+ const float* b,
+ float* y,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(n != 0);
+ assert(n % sizeof(float) == 0);
+
+ const float vy_min = params->scalar.min;
+ const float vy_max = params->scalar.max;
+
+ const float vb = *b;
+ for (; n >= sizeof(float); n -= sizeof(float)) {
+ const float va = *a++;
+ float vy = va + vb;
+ vy = __builtin_wasm_max_f32(vy, vy_min);
+ vy = __builtin_wasm_min_f32(vy, vy_max);
+ *y++ = vy;
+ }
+}
diff --git a/src/f32-vbinary/gen/vaddc-wasm-x2.c b/src/f32-vbinary/gen/vaddc-wasm-x2.c
new file mode 100644
index 0000000..bd4d0c6
--- /dev/null
+++ b/src/f32-vbinary/gen/vaddc-wasm-x2.c
@@ -0,0 +1,56 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-vbinary/vopc-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/common.h>
+#include <xnnpack/math.h>
+#include <xnnpack/vbinary.h>
+
+
+void xnn_f32_vaddc_ukernel__wasm_x2(
+ size_t n,
+ const float* a,
+ const float* b,
+ float* y,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(n != 0);
+ assert(n % sizeof(float) == 0);
+
+ const float vy_min = params->scalar.min;
+ const float vy_max = params->scalar.max;
+
+ const float vb = *b;
+ for (; n >= 2 * sizeof(float); n -= 2 * sizeof(float)) {
+ const float va0 = a[0];
+ const float va1 = a[1];
+ a += 2;
+
+ float vy0 = va0 + vb;
+ float vy1 = va1 + vb;
+
+ vy0 = __builtin_wasm_max_f32(vy0, vy_min);
+ vy1 = __builtin_wasm_max_f32(vy1, vy_min);
+
+ vy0 = __builtin_wasm_min_f32(vy0, vy_max);
+ vy1 = __builtin_wasm_min_f32(vy1, vy_max);
+
+ y[0] = vy0;
+ y[1] = vy1;
+ y += 2;
+ }
+ if XNN_UNLIKELY(n != 0) {
+ const float va = *a;
+ float vy = va + vb;
+ vy = __builtin_wasm_max_f32(vy, vy_min);
+ vy = __builtin_wasm_min_f32(vy, vy_max);
+ *y = vy;
+ }
+}
diff --git a/src/f32-vbinary/gen/vaddc-wasm-x4.c b/src/f32-vbinary/gen/vaddc-wasm-x4.c
new file mode 100644
index 0000000..4a99e20
--- /dev/null
+++ b/src/f32-vbinary/gen/vaddc-wasm-x4.c
@@ -0,0 +1,69 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-vbinary/vopc-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/common.h>
+#include <xnnpack/math.h>
+#include <xnnpack/vbinary.h>
+
+
+void xnn_f32_vaddc_ukernel__wasm_x4(
+ size_t n,
+ const float* a,
+ const float* b,
+ float* y,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(n != 0);
+ assert(n % sizeof(float) == 0);
+
+ const float vy_min = params->scalar.min;
+ const float vy_max = params->scalar.max;
+
+ const float vb = *b;
+ for (; n >= 4 * sizeof(float); n -= 4 * sizeof(float)) {
+ const float va0 = a[0];
+ const float va1 = a[1];
+ const float va2 = a[2];
+ const float va3 = a[3];
+ a += 4;
+
+ float vy0 = va0 + vb;
+ float vy1 = va1 + vb;
+ float vy2 = va2 + vb;
+ float vy3 = va3 + vb;
+
+ vy0 = __builtin_wasm_max_f32(vy0, vy_min);
+ vy1 = __builtin_wasm_max_f32(vy1, vy_min);
+ vy2 = __builtin_wasm_max_f32(vy2, vy_min);
+ vy3 = __builtin_wasm_max_f32(vy3, vy_min);
+
+ vy0 = __builtin_wasm_min_f32(vy0, vy_max);
+ vy1 = __builtin_wasm_min_f32(vy1, vy_max);
+ vy2 = __builtin_wasm_min_f32(vy2, vy_max);
+ vy3 = __builtin_wasm_min_f32(vy3, vy_max);
+
+ y[0] = vy0;
+ y[1] = vy1;
+ y[2] = vy2;
+ y[3] = vy3;
+ y += 4;
+ }
+ if XNN_UNLIKELY(n != 0) {
+ do {
+ const float va = *a++;
+ float vy = va + vb;
+ vy = __builtin_wasm_max_f32(vy, vy_min);
+ vy = __builtin_wasm_min_f32(vy, vy_max);
+ *y++ = vy;
+ n -= sizeof(float);
+ } while (n != 0);
+ }
+}
diff --git a/src/f32-vbinary/gen/vmul-wasm-x1.c b/src/f32-vbinary/gen/vmul-wasm-x1.c
new file mode 100644
index 0000000..f837a8a
--- /dev/null
+++ b/src/f32-vbinary/gen/vmul-wasm-x1.c
@@ -0,0 +1,38 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-vbinary/vop-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/common.h>
+#include <xnnpack/math.h>
+#include <xnnpack/vbinary.h>
+
+
+void xnn_f32_vmul_ukernel__wasm_x1(
+ size_t n,
+ const float* a,
+ const float* b,
+ float* y,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(n != 0);
+ assert(n % sizeof(float) == 0);
+
+ const float vy_min = params->scalar.min;
+ const float vy_max = params->scalar.max;
+
+ for (; n >= sizeof(float); n -= sizeof(float)) {
+ const float va = *a++;
+ const float vb = *b++;
+ float vy = va * vb;
+ vy = __builtin_wasm_max_f32(vy, vy_min);
+ vy = __builtin_wasm_min_f32(vy, vy_max);
+ *y++ = vy;
+ }
+}
diff --git a/src/f32-vbinary/gen/vmul-wasm-x2.c b/src/f32-vbinary/gen/vmul-wasm-x2.c
new file mode 100644
index 0000000..7b5b038
--- /dev/null
+++ b/src/f32-vbinary/gen/vmul-wasm-x2.c
@@ -0,0 +1,60 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-vbinary/vop-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/common.h>
+#include <xnnpack/math.h>
+#include <xnnpack/vbinary.h>
+
+
+void xnn_f32_vmul_ukernel__wasm_x2(
+ size_t n,
+ const float* a,
+ const float* b,
+ float* y,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(n != 0);
+ assert(n % sizeof(float) == 0);
+
+ const float vy_min = params->scalar.min;
+ const float vy_max = params->scalar.max;
+
+ for (; n >= 2 * sizeof(float); n -= 2 * sizeof(float)) {
+ const float va0 = a[0];
+ const float va1 = a[1];
+ a += 2;
+
+ const float vb0 = b[0];
+ const float vb1 = b[1];
+ b += 2;
+
+ float vy0 = va0 * vb0;
+ float vy1 = va1 * vb1;
+
+ vy0 = __builtin_wasm_max_f32(vy0, vy_min);
+ vy1 = __builtin_wasm_max_f32(vy1, vy_min);
+
+ vy0 = __builtin_wasm_min_f32(vy0, vy_max);
+ vy1 = __builtin_wasm_min_f32(vy1, vy_max);
+
+ y[0] = vy0;
+ y[1] = vy1;
+ y += 2;
+ }
+ if XNN_UNLIKELY(n != 0) {
+ const float va = *a;
+ const float vb = *b;
+ float vy = va * vb;
+ vy = __builtin_wasm_max_f32(vy, vy_min);
+ vy = __builtin_wasm_min_f32(vy, vy_max);
+ *y = vy;
+ }
+}
diff --git a/src/f32-vbinary/gen/vmul-wasm-x4.c b/src/f32-vbinary/gen/vmul-wasm-x4.c
new file mode 100644
index 0000000..518dcfc
--- /dev/null
+++ b/src/f32-vbinary/gen/vmul-wasm-x4.c
@@ -0,0 +1,75 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-vbinary/vop-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/common.h>
+#include <xnnpack/math.h>
+#include <xnnpack/vbinary.h>
+
+
+void xnn_f32_vmul_ukernel__wasm_x4(
+ size_t n,
+ const float* a,
+ const float* b,
+ float* y,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(n != 0);
+ assert(n % sizeof(float) == 0);
+
+ const float vy_min = params->scalar.min;
+ const float vy_max = params->scalar.max;
+
+ for (; n >= 4 * sizeof(float); n -= 4 * sizeof(float)) {
+ const float va0 = a[0];
+ const float va1 = a[1];
+ const float va2 = a[2];
+ const float va3 = a[3];
+ a += 4;
+
+ const float vb0 = b[0];
+ const float vb1 = b[1];
+ const float vb2 = b[2];
+ const float vb3 = b[3];
+ b += 4;
+
+ float vy0 = va0 * vb0;
+ float vy1 = va1 * vb1;
+ float vy2 = va2 * vb2;
+ float vy3 = va3 * vb3;
+
+ vy0 = __builtin_wasm_max_f32(vy0, vy_min);
+ vy1 = __builtin_wasm_max_f32(vy1, vy_min);
+ vy2 = __builtin_wasm_max_f32(vy2, vy_min);
+ vy3 = __builtin_wasm_max_f32(vy3, vy_min);
+
+ vy0 = __builtin_wasm_min_f32(vy0, vy_max);
+ vy1 = __builtin_wasm_min_f32(vy1, vy_max);
+ vy2 = __builtin_wasm_min_f32(vy2, vy_max);
+ vy3 = __builtin_wasm_min_f32(vy3, vy_max);
+
+ y[0] = vy0;
+ y[1] = vy1;
+ y[2] = vy2;
+ y[3] = vy3;
+ y += 4;
+ }
+ if XNN_UNLIKELY(n != 0) {
+ do {
+ const float va = *a++;
+ const float vb = *b++;
+ float vy = va * vb;
+ vy = __builtin_wasm_max_f32(vy, vy_min);
+ vy = __builtin_wasm_min_f32(vy, vy_max);
+ *y++ = vy;
+ n -= sizeof(float);
+ } while (n != 0);
+ }
+}
diff --git a/src/f32-vbinary/gen/vmulc-wasm-x1.c b/src/f32-vbinary/gen/vmulc-wasm-x1.c
new file mode 100644
index 0000000..dfbf606
--- /dev/null
+++ b/src/f32-vbinary/gen/vmulc-wasm-x1.c
@@ -0,0 +1,38 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-vbinary/vopc-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/common.h>
+#include <xnnpack/math.h>
+#include <xnnpack/vbinary.h>
+
+
+void xnn_f32_vmulc_ukernel__wasm_x1(
+ size_t n,
+ const float* a,
+ const float* b,
+ float* y,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(n != 0);
+ assert(n % sizeof(float) == 0);
+
+ const float vy_min = params->scalar.min;
+ const float vy_max = params->scalar.max;
+
+ const float vb = *b;
+ for (; n >= sizeof(float); n -= sizeof(float)) {
+ const float va = *a++;
+ float vy = va * vb;
+ vy = __builtin_wasm_max_f32(vy, vy_min);
+ vy = __builtin_wasm_min_f32(vy, vy_max);
+ *y++ = vy;
+ }
+}
diff --git a/src/f32-vbinary/gen/vmulc-wasm-x2.c b/src/f32-vbinary/gen/vmulc-wasm-x2.c
new file mode 100644
index 0000000..ce8570d
--- /dev/null
+++ b/src/f32-vbinary/gen/vmulc-wasm-x2.c
@@ -0,0 +1,56 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-vbinary/vopc-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/common.h>
+#include <xnnpack/math.h>
+#include <xnnpack/vbinary.h>
+
+
+void xnn_f32_vmulc_ukernel__wasm_x2(
+ size_t n,
+ const float* a,
+ const float* b,
+ float* y,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(n != 0);
+ assert(n % sizeof(float) == 0);
+
+ const float vy_min = params->scalar.min;
+ const float vy_max = params->scalar.max;
+
+ const float vb = *b;
+ for (; n >= 2 * sizeof(float); n -= 2 * sizeof(float)) {
+ const float va0 = a[0];
+ const float va1 = a[1];
+ a += 2;
+
+ float vy0 = va0 * vb;
+ float vy1 = va1 * vb;
+
+ vy0 = __builtin_wasm_max_f32(vy0, vy_min);
+ vy1 = __builtin_wasm_max_f32(vy1, vy_min);
+
+ vy0 = __builtin_wasm_min_f32(vy0, vy_max);
+ vy1 = __builtin_wasm_min_f32(vy1, vy_max);
+
+ y[0] = vy0;
+ y[1] = vy1;
+ y += 2;
+ }
+ if XNN_UNLIKELY(n != 0) {
+ const float va = *a;
+ float vy = va * vb;
+ vy = __builtin_wasm_max_f32(vy, vy_min);
+ vy = __builtin_wasm_min_f32(vy, vy_max);
+ *y = vy;
+ }
+}
diff --git a/src/f32-vbinary/gen/vmulc-wasm-x4.c b/src/f32-vbinary/gen/vmulc-wasm-x4.c
new file mode 100644
index 0000000..820838b
--- /dev/null
+++ b/src/f32-vbinary/gen/vmulc-wasm-x4.c
@@ -0,0 +1,69 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-vbinary/vopc-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/common.h>
+#include <xnnpack/math.h>
+#include <xnnpack/vbinary.h>
+
+
+void xnn_f32_vmulc_ukernel__wasm_x4(
+ size_t n,
+ const float* a,
+ const float* b,
+ float* y,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(n != 0);
+ assert(n % sizeof(float) == 0);
+
+ const float vy_min = params->scalar.min;
+ const float vy_max = params->scalar.max;
+
+ const float vb = *b;
+ for (; n >= 4 * sizeof(float); n -= 4 * sizeof(float)) {
+ const float va0 = a[0];
+ const float va1 = a[1];
+ const float va2 = a[2];
+ const float va3 = a[3];
+ a += 4;
+
+ float vy0 = va0 * vb;
+ float vy1 = va1 * vb;
+ float vy2 = va2 * vb;
+ float vy3 = va3 * vb;
+
+ vy0 = __builtin_wasm_max_f32(vy0, vy_min);
+ vy1 = __builtin_wasm_max_f32(vy1, vy_min);
+ vy2 = __builtin_wasm_max_f32(vy2, vy_min);
+ vy3 = __builtin_wasm_max_f32(vy3, vy_min);
+
+ vy0 = __builtin_wasm_min_f32(vy0, vy_max);
+ vy1 = __builtin_wasm_min_f32(vy1, vy_max);
+ vy2 = __builtin_wasm_min_f32(vy2, vy_max);
+ vy3 = __builtin_wasm_min_f32(vy3, vy_max);
+
+ y[0] = vy0;
+ y[1] = vy1;
+ y[2] = vy2;
+ y[3] = vy3;
+ y += 4;
+ }
+ if XNN_UNLIKELY(n != 0) {
+ do {
+ const float va = *a++;
+ float vy = va * vb;
+ vy = __builtin_wasm_max_f32(vy, vy_min);
+ vy = __builtin_wasm_min_f32(vy, vy_max);
+ *y++ = vy;
+ n -= sizeof(float);
+ } while (n != 0);
+ }
+}
diff --git a/src/f32-vbinary/gen/vrsubc-wasm-x1.c b/src/f32-vbinary/gen/vrsubc-wasm-x1.c
new file mode 100644
index 0000000..fc6ba71
--- /dev/null
+++ b/src/f32-vbinary/gen/vrsubc-wasm-x1.c
@@ -0,0 +1,38 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-vbinary/vopc-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/common.h>
+#include <xnnpack/math.h>
+#include <xnnpack/vbinary.h>
+
+
+void xnn_f32_vrsubc_ukernel__wasm_x1(
+ size_t n,
+ const float* a,
+ const float* b,
+ float* y,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(n != 0);
+ assert(n % sizeof(float) == 0);
+
+ const float vy_min = params->scalar.min;
+ const float vy_max = params->scalar.max;
+
+ const float vb = *b;
+ for (; n >= sizeof(float); n -= sizeof(float)) {
+ const float va = *a++;
+ float vy = vb - va;
+ vy = __builtin_wasm_max_f32(vy, vy_min);
+ vy = __builtin_wasm_min_f32(vy, vy_max);
+ *y++ = vy;
+ }
+}
diff --git a/src/f32-vbinary/gen/vrsubc-wasm-x2.c b/src/f32-vbinary/gen/vrsubc-wasm-x2.c
new file mode 100644
index 0000000..fec9c71
--- /dev/null
+++ b/src/f32-vbinary/gen/vrsubc-wasm-x2.c
@@ -0,0 +1,56 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-vbinary/vopc-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/common.h>
+#include <xnnpack/math.h>
+#include <xnnpack/vbinary.h>
+
+
+void xnn_f32_vrsubc_ukernel__wasm_x2(
+ size_t n,
+ const float* a,
+ const float* b,
+ float* y,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(n != 0);
+ assert(n % sizeof(float) == 0);
+
+ const float vy_min = params->scalar.min;
+ const float vy_max = params->scalar.max;
+
+ const float vb = *b;
+ for (; n >= 2 * sizeof(float); n -= 2 * sizeof(float)) {
+ const float va0 = a[0];
+ const float va1 = a[1];
+ a += 2;
+
+ float vy0 = vb - va0;
+ float vy1 = vb - va1;
+
+ vy0 = __builtin_wasm_max_f32(vy0, vy_min);
+ vy1 = __builtin_wasm_max_f32(vy1, vy_min);
+
+ vy0 = __builtin_wasm_min_f32(vy0, vy_max);
+ vy1 = __builtin_wasm_min_f32(vy1, vy_max);
+
+ y[0] = vy0;
+ y[1] = vy1;
+ y += 2;
+ }
+ if XNN_UNLIKELY(n != 0) {
+ const float va = *a;
+ float vy = vb - va;
+ vy = __builtin_wasm_max_f32(vy, vy_min);
+ vy = __builtin_wasm_min_f32(vy, vy_max);
+ *y = vy;
+ }
+}
diff --git a/src/f32-vbinary/gen/vrsubc-wasm-x4.c b/src/f32-vbinary/gen/vrsubc-wasm-x4.c
new file mode 100644
index 0000000..47aa49b
--- /dev/null
+++ b/src/f32-vbinary/gen/vrsubc-wasm-x4.c
@@ -0,0 +1,69 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-vbinary/vopc-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/common.h>
+#include <xnnpack/math.h>
+#include <xnnpack/vbinary.h>
+
+
+void xnn_f32_vrsubc_ukernel__wasm_x4(
+ size_t n,
+ const float* a,
+ const float* b,
+ float* y,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(n != 0);
+ assert(n % sizeof(float) == 0);
+
+ const float vy_min = params->scalar.min;
+ const float vy_max = params->scalar.max;
+
+ const float vb = *b;
+ for (; n >= 4 * sizeof(float); n -= 4 * sizeof(float)) {
+ const float va0 = a[0];
+ const float va1 = a[1];
+ const float va2 = a[2];
+ const float va3 = a[3];
+ a += 4;
+
+ float vy0 = vb - va0;
+ float vy1 = vb - va1;
+ float vy2 = vb - va2;
+ float vy3 = vb - va3;
+
+ vy0 = __builtin_wasm_max_f32(vy0, vy_min);
+ vy1 = __builtin_wasm_max_f32(vy1, vy_min);
+ vy2 = __builtin_wasm_max_f32(vy2, vy_min);
+ vy3 = __builtin_wasm_max_f32(vy3, vy_min);
+
+ vy0 = __builtin_wasm_min_f32(vy0, vy_max);
+ vy1 = __builtin_wasm_min_f32(vy1, vy_max);
+ vy2 = __builtin_wasm_min_f32(vy2, vy_max);
+ vy3 = __builtin_wasm_min_f32(vy3, vy_max);
+
+ y[0] = vy0;
+ y[1] = vy1;
+ y[2] = vy2;
+ y[3] = vy3;
+ y += 4;
+ }
+ if XNN_UNLIKELY(n != 0) {
+ do {
+ const float va = *a++;
+ float vy = vb - va;
+ vy = __builtin_wasm_max_f32(vy, vy_min);
+ vy = __builtin_wasm_min_f32(vy, vy_max);
+ *y++ = vy;
+ n -= sizeof(float);
+ } while (n != 0);
+ }
+}
diff --git a/src/f32-vbinary/gen/vsub-wasm-x1.c b/src/f32-vbinary/gen/vsub-wasm-x1.c
new file mode 100644
index 0000000..afd215f
--- /dev/null
+++ b/src/f32-vbinary/gen/vsub-wasm-x1.c
@@ -0,0 +1,38 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-vbinary/vop-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/common.h>
+#include <xnnpack/math.h>
+#include <xnnpack/vbinary.h>
+
+
+void xnn_f32_vsub_ukernel__wasm_x1(
+ size_t n,
+ const float* a,
+ const float* b,
+ float* y,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(n != 0);
+ assert(n % sizeof(float) == 0);
+
+ const float vy_min = params->scalar.min;
+ const float vy_max = params->scalar.max;
+
+ for (; n >= sizeof(float); n -= sizeof(float)) {
+ const float va = *a++;
+ const float vb = *b++;
+ float vy = va - vb;
+ vy = __builtin_wasm_max_f32(vy, vy_min);
+ vy = __builtin_wasm_min_f32(vy, vy_max);
+ *y++ = vy;
+ }
+}
diff --git a/src/f32-vbinary/gen/vsub-wasm-x2.c b/src/f32-vbinary/gen/vsub-wasm-x2.c
new file mode 100644
index 0000000..7b5da3d
--- /dev/null
+++ b/src/f32-vbinary/gen/vsub-wasm-x2.c
@@ -0,0 +1,60 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-vbinary/vop-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/common.h>
+#include <xnnpack/math.h>
+#include <xnnpack/vbinary.h>
+
+
+void xnn_f32_vsub_ukernel__wasm_x2(
+ size_t n,
+ const float* a,
+ const float* b,
+ float* y,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(n != 0);
+ assert(n % sizeof(float) == 0);
+
+ const float vy_min = params->scalar.min;
+ const float vy_max = params->scalar.max;
+
+ for (; n >= 2 * sizeof(float); n -= 2 * sizeof(float)) {
+ const float va0 = a[0];
+ const float va1 = a[1];
+ a += 2;
+
+ const float vb0 = b[0];
+ const float vb1 = b[1];
+ b += 2;
+
+ float vy0 = va0 - vb0;
+ float vy1 = va1 - vb1;
+
+ vy0 = __builtin_wasm_max_f32(vy0, vy_min);
+ vy1 = __builtin_wasm_max_f32(vy1, vy_min);
+
+ vy0 = __builtin_wasm_min_f32(vy0, vy_max);
+ vy1 = __builtin_wasm_min_f32(vy1, vy_max);
+
+ y[0] = vy0;
+ y[1] = vy1;
+ y += 2;
+ }
+ if XNN_UNLIKELY(n != 0) {
+ const float va = *a;
+ const float vb = *b;
+ float vy = va - vb;
+ vy = __builtin_wasm_max_f32(vy, vy_min);
+ vy = __builtin_wasm_min_f32(vy, vy_max);
+ *y = vy;
+ }
+}
diff --git a/src/f32-vbinary/gen/vsub-wasm-x4.c b/src/f32-vbinary/gen/vsub-wasm-x4.c
new file mode 100644
index 0000000..64a4e14
--- /dev/null
+++ b/src/f32-vbinary/gen/vsub-wasm-x4.c
@@ -0,0 +1,75 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-vbinary/vop-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/common.h>
+#include <xnnpack/math.h>
+#include <xnnpack/vbinary.h>
+
+
+void xnn_f32_vsub_ukernel__wasm_x4(
+ size_t n,
+ const float* a,
+ const float* b,
+ float* y,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(n != 0);
+ assert(n % sizeof(float) == 0);
+
+ const float vy_min = params->scalar.min;
+ const float vy_max = params->scalar.max;
+
+ for (; n >= 4 * sizeof(float); n -= 4 * sizeof(float)) {
+ const float va0 = a[0];
+ const float va1 = a[1];
+ const float va2 = a[2];
+ const float va3 = a[3];
+ a += 4;
+
+ const float vb0 = b[0];
+ const float vb1 = b[1];
+ const float vb2 = b[2];
+ const float vb3 = b[3];
+ b += 4;
+
+ float vy0 = va0 - vb0;
+ float vy1 = va1 - vb1;
+ float vy2 = va2 - vb2;
+ float vy3 = va3 - vb3;
+
+ vy0 = __builtin_wasm_max_f32(vy0, vy_min);
+ vy1 = __builtin_wasm_max_f32(vy1, vy_min);
+ vy2 = __builtin_wasm_max_f32(vy2, vy_min);
+ vy3 = __builtin_wasm_max_f32(vy3, vy_min);
+
+ vy0 = __builtin_wasm_min_f32(vy0, vy_max);
+ vy1 = __builtin_wasm_min_f32(vy1, vy_max);
+ vy2 = __builtin_wasm_min_f32(vy2, vy_max);
+ vy3 = __builtin_wasm_min_f32(vy3, vy_max);
+
+ y[0] = vy0;
+ y[1] = vy1;
+ y[2] = vy2;
+ y[3] = vy3;
+ y += 4;
+ }
+ if XNN_UNLIKELY(n != 0) {
+ do {
+ const float va = *a++;
+ const float vb = *b++;
+ float vy = va - vb;
+ vy = __builtin_wasm_max_f32(vy, vy_min);
+ vy = __builtin_wasm_min_f32(vy, vy_max);
+ *y++ = vy;
+ n -= sizeof(float);
+ } while (n != 0);
+ }
+}
diff --git a/src/f32-vbinary/gen/vsubc-wasm-x1.c b/src/f32-vbinary/gen/vsubc-wasm-x1.c
new file mode 100644
index 0000000..27ee045
--- /dev/null
+++ b/src/f32-vbinary/gen/vsubc-wasm-x1.c
@@ -0,0 +1,38 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-vbinary/vopc-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/common.h>
+#include <xnnpack/math.h>
+#include <xnnpack/vbinary.h>
+
+
+void xnn_f32_vsubc_ukernel__wasm_x1(
+ size_t n,
+ const float* a,
+ const float* b,
+ float* y,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(n != 0);
+ assert(n % sizeof(float) == 0);
+
+ const float vy_min = params->scalar.min;
+ const float vy_max = params->scalar.max;
+
+ const float vb = *b;
+ for (; n >= sizeof(float); n -= sizeof(float)) {
+ const float va = *a++;
+ float vy = va - vb;
+ vy = __builtin_wasm_max_f32(vy, vy_min);
+ vy = __builtin_wasm_min_f32(vy, vy_max);
+ *y++ = vy;
+ }
+}
diff --git a/src/f32-vbinary/gen/vsubc-wasm-x2.c b/src/f32-vbinary/gen/vsubc-wasm-x2.c
new file mode 100644
index 0000000..9ffd026
--- /dev/null
+++ b/src/f32-vbinary/gen/vsubc-wasm-x2.c
@@ -0,0 +1,56 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-vbinary/vopc-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/common.h>
+#include <xnnpack/math.h>
+#include <xnnpack/vbinary.h>
+
+
+void xnn_f32_vsubc_ukernel__wasm_x2(
+ size_t n,
+ const float* a,
+ const float* b,
+ float* y,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(n != 0);
+ assert(n % sizeof(float) == 0);
+
+ const float vy_min = params->scalar.min;
+ const float vy_max = params->scalar.max;
+
+ const float vb = *b;
+ for (; n >= 2 * sizeof(float); n -= 2 * sizeof(float)) {
+ const float va0 = a[0];
+ const float va1 = a[1];
+ a += 2;
+
+ float vy0 = va0 - vb;
+ float vy1 = va1 - vb;
+
+ vy0 = __builtin_wasm_max_f32(vy0, vy_min);
+ vy1 = __builtin_wasm_max_f32(vy1, vy_min);
+
+ vy0 = __builtin_wasm_min_f32(vy0, vy_max);
+ vy1 = __builtin_wasm_min_f32(vy1, vy_max);
+
+ y[0] = vy0;
+ y[1] = vy1;
+ y += 2;
+ }
+ if XNN_UNLIKELY(n != 0) {
+ const float va = *a;
+ float vy = va - vb;
+ vy = __builtin_wasm_max_f32(vy, vy_min);
+ vy = __builtin_wasm_min_f32(vy, vy_max);
+ *y = vy;
+ }
+}
diff --git a/src/f32-vbinary/gen/vsubc-wasm-x4.c b/src/f32-vbinary/gen/vsubc-wasm-x4.c
new file mode 100644
index 0000000..1a02d0a
--- /dev/null
+++ b/src/f32-vbinary/gen/vsubc-wasm-x4.c
@@ -0,0 +1,69 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-vbinary/vopc-scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/common.h>
+#include <xnnpack/math.h>
+#include <xnnpack/vbinary.h>
+
+
+void xnn_f32_vsubc_ukernel__wasm_x4(
+ size_t n,
+ const float* a,
+ const float* b,
+ float* y,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(n != 0);
+ assert(n % sizeof(float) == 0);
+
+ const float vy_min = params->scalar.min;
+ const float vy_max = params->scalar.max;
+
+ const float vb = *b;
+ for (; n >= 4 * sizeof(float); n -= 4 * sizeof(float)) {
+ const float va0 = a[0];
+ const float va1 = a[1];
+ const float va2 = a[2];
+ const float va3 = a[3];
+ a += 4;
+
+ float vy0 = va0 - vb;
+ float vy1 = va1 - vb;
+ float vy2 = va2 - vb;
+ float vy3 = va3 - vb;
+
+ vy0 = __builtin_wasm_max_f32(vy0, vy_min);
+ vy1 = __builtin_wasm_max_f32(vy1, vy_min);
+ vy2 = __builtin_wasm_max_f32(vy2, vy_min);
+ vy3 = __builtin_wasm_max_f32(vy3, vy_min);
+
+ vy0 = __builtin_wasm_min_f32(vy0, vy_max);
+ vy1 = __builtin_wasm_min_f32(vy1, vy_max);
+ vy2 = __builtin_wasm_min_f32(vy2, vy_max);
+ vy3 = __builtin_wasm_min_f32(vy3, vy_max);
+
+ y[0] = vy0;
+ y[1] = vy1;
+ y[2] = vy2;
+ y[3] = vy3;
+ y += 4;
+ }
+ if XNN_UNLIKELY(n != 0) {
+ do {
+ const float va = *a++;
+ float vy = va - vb;
+ vy = __builtin_wasm_max_f32(vy, vy_min);
+ vy = __builtin_wasm_min_f32(vy, vy_max);
+ *y++ = vy;
+ n -= sizeof(float);
+ } while (n != 0);
+ }
+}
diff --git a/src/f32-vbinary/vop-scalar.c.in b/src/f32-vbinary/vop-scalar.c.in
index 633218a..5ee1eae 100644
--- a/src/f32-vbinary/vop-scalar.c.in
+++ b/src/f32-vbinary/vop-scalar.c.in
@@ -13,12 +13,14 @@
#include <xnnpack/vbinary.h>
+$MIN_F32 = "__builtin_wasm_min_f32" if WASM else "math_min_f32"
+$MAX_F32 = "__builtin_wasm_max_f32" if WASM else "math_max_f32"
$OP_FUNC = {
$ "ADD": lambda x, y: "%s + %s" % (x, y),
$ "MUL": lambda x, y: "%s * %s" % (x, y),
$ "SUB": lambda x, y: "%s - %s" % (x, y),
$}[OP]
-void xnn_f32_v${OP.lower()}_ukernel__scalar_x${BATCH_TILE}(
+void xnn_f32_v${OP.lower()}_ukernel__${"wasm" if WASM else "scalar"}_x${BATCH_TILE}(
size_t n,
const float* a,
const float* b,
@@ -45,10 +47,10 @@
float vy${ABC[N]} = ${OP_FUNC("va" + ABC[N], "vb" + ABC[N])};
$for N in range(BATCH_TILE):
- vy${ABC[N]} = math_max_f32(vy${ABC[N]}, vy_min);
+ vy${ABC[N]} = ${MAX_F32}(vy${ABC[N]}, vy_min);
$for N in range(BATCH_TILE):
- vy${ABC[N]} = math_min_f32(vy${ABC[N]}, vy_max);
+ vy${ABC[N]} = ${MIN_F32}(vy${ABC[N]}, vy_max);
$for N in range(BATCH_TILE):
y[${N}] = vy${ABC[N]};
@@ -60,8 +62,8 @@
const float va = *a++;
const float vb = *b++;
float vy = ${OP_FUNC("va", "vb")};
- vy = math_max_f32(vy, vy_min);
- vy = math_min_f32(vy, vy_max);
+ vy = ${MAX_F32}(vy, vy_min);
+ vy = ${MIN_F32}(vy, vy_max);
*y++ = vy;
n -= sizeof(float);
} while (n != 0);
@@ -69,8 +71,8 @@
const float va = *a;
const float vb = *b;
float vy = ${OP_FUNC("va", "vb")};
- vy = math_max_f32(vy, vy_min);
- vy = math_min_f32(vy, vy_max);
+ vy = ${MAX_F32}(vy, vy_min);
+ vy = ${MIN_F32}(vy, vy_max);
*y = vy;
}
$else:
@@ -78,8 +80,8 @@
const float va = *a++;
const float vb = *b++;
float vy = ${OP_FUNC("va", "vb")};
- vy = math_max_f32(vy, vy_min);
- vy = math_min_f32(vy, vy_max);
+ vy = ${MAX_F32}(vy, vy_min);
+ vy = ${MIN_F32}(vy, vy_max);
*y++ = vy;
}
}
diff --git a/src/f32-vbinary/vopc-scalar.c.in b/src/f32-vbinary/vopc-scalar.c.in
index 88fb010..15d8e36 100644
--- a/src/f32-vbinary/vopc-scalar.c.in
+++ b/src/f32-vbinary/vopc-scalar.c.in
@@ -13,13 +13,15 @@
#include <xnnpack/vbinary.h>
+$MIN_F32 = "__builtin_wasm_min_f32" if WASM else "math_min_f32"
+$MAX_F32 = "__builtin_wasm_max_f32" if WASM else "math_max_f32"
$OP_FUNC = {
$ "ADD": lambda x: "%s + vb" % x,
$ "MUL": lambda x: "%s * vb" % x,
$ "SUB": lambda x: "%s - vb" % x,
$ "RSUB": lambda x: "vb - %s" % x,
$}[OP]
-void xnn_f32_v${OP.lower()}c_ukernel__scalar_x${BATCH_TILE}(
+void xnn_f32_v${OP.lower()}c_ukernel__${"wasm" if WASM else "scalar"}_x${BATCH_TILE}(
size_t n,
const float* a,
const float* b,
@@ -43,10 +45,10 @@
float vy${ABC[N]} = ${OP_FUNC("va" + ABC[N])};
$for N in range(BATCH_TILE):
- vy${ABC[N]} = math_max_f32(vy${ABC[N]}, vy_min);
+ vy${ABC[N]} = ${MAX_F32}(vy${ABC[N]}, vy_min);
$for N in range(BATCH_TILE):
- vy${ABC[N]} = math_min_f32(vy${ABC[N]}, vy_max);
+ vy${ABC[N]} = ${MIN_F32}(vy${ABC[N]}, vy_max);
$for N in range(BATCH_TILE):
y[${N}] = vy${ABC[N]};
@@ -57,24 +59,24 @@
do {
const float va = *a++;
float vy = ${OP_FUNC("va")};
- vy = math_max_f32(vy, vy_min);
- vy = math_min_f32(vy, vy_max);
+ vy = ${MAX_F32}(vy, vy_min);
+ vy = ${MIN_F32}(vy, vy_max);
*y++ = vy;
n -= sizeof(float);
} while (n != 0);
$else:
const float va = *a;
float vy = ${OP_FUNC("va")};
- vy = math_max_f32(vy, vy_min);
- vy = math_min_f32(vy, vy_max);
+ vy = ${MAX_F32}(vy, vy_min);
+ vy = ${MIN_F32}(vy, vy_max);
*y = vy;
}
$else:
for (; n >= sizeof(float); n -= sizeof(float)) {
const float va = *a++;
float vy = ${OP_FUNC("va")};
- vy = math_max_f32(vy, vy_min);
- vy = math_min_f32(vy, vy_max);
+ vy = ${MAX_F32}(vy, vy_min);
+ vy = ${MIN_F32}(vy, vy_max);
*y++ = vy;
}
}
diff --git a/src/f32-vmulcaddc/gen/c1-wasm-2x.c b/src/f32-vmulcaddc/gen/c1-wasm-2x.c
new file mode 100644
index 0000000..16e131a
--- /dev/null
+++ b/src/f32-vmulcaddc/gen/c1-wasm-2x.c
@@ -0,0 +1,80 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-vmulcaddc/scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/math.h>
+#include <xnnpack/vmulcaddc.h>
+
+
+void xnn_f32_vmulcaddc_ukernel_c1__wasm_2x(
+ size_t rows,
+ size_t channels,
+ const float*restrict input,
+ size_t input_stride,
+ const float*restrict weights,
+ float*restrict output,
+ size_t output_stride,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(rows != 0);
+ assert(channels != 0);
+ assert(channels % sizeof(float) == 0);
+
+ const size_t input_increment = input_stride * 2 - channels;
+ const size_t output_increment = output_stride * 2 - channels;
+
+ const float* i0 = input;
+ float* o0 = output;
+ const float* i1 = (const float*) ((uintptr_t) i0 + input_stride);
+ float* o1 = (float*) ((uintptr_t) o0 + output_stride);
+ if XNN_UNPREDICTABLE(rows < 2) {
+ i1 = i0;
+ o1 = o0;
+ }
+
+ const float vmin = params->scalar.min;
+ const float vmax = params->scalar.max;
+ do {
+ const float* w = weights;
+ size_t c = channels;
+ do {
+ const float vscale = w[0];
+
+ float vacc0 = *i0++;
+ float vacc1 = *i1++;
+
+ const float vbias = w[1];
+
+ vacc0 = vacc0 * vscale + vbias;
+ vacc1 = vacc1 * vscale + vbias;
+
+ vacc0 = __builtin_wasm_max_f32(vacc0, vmin);
+ vacc1 = __builtin_wasm_max_f32(vacc1, vmin);
+
+ vacc0 = __builtin_wasm_min_f32(vacc0, vmax);
+ vacc1 = __builtin_wasm_min_f32(vacc1, vmax);
+
+ *o0++ = vacc0;
+ *o1++ = vacc1;
+
+ w += 2;
+ c -= sizeof(float);
+ } while (c != 0);
+ i0 = (const float*) ((uintptr_t) i0 + input_increment);
+ o0 = (float*) ((uintptr_t) o0 + output_increment);
+ i1 = (const float*) ((uintptr_t) i1 + input_increment);
+ o1 = (float*) ((uintptr_t) o1 + output_increment);
+ if XNN_UNPREDICTABLE(rows < 4) {
+ i1 = i0;
+ o1 = o0;
+ }
+ rows = doz(rows, 2);
+ } while (rows != 0);
+}
diff --git a/src/f32-vmulcaddc/gen/c2-wasm-2x.c b/src/f32-vmulcaddc/gen/c2-wasm-2x.c
new file mode 100644
index 0000000..b8eab2f
--- /dev/null
+++ b/src/f32-vmulcaddc/gen/c2-wasm-2x.c
@@ -0,0 +1,119 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-vmulcaddc/scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/math.h>
+#include <xnnpack/vmulcaddc.h>
+
+
+void xnn_f32_vmulcaddc_ukernel_c2__wasm_2x(
+ size_t rows,
+ size_t channels,
+ const float*restrict input,
+ size_t input_stride,
+ const float*restrict weights,
+ float*restrict output,
+ size_t output_stride,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(rows != 0);
+ assert(channels != 0);
+ assert(channels % sizeof(float) == 0);
+
+ const size_t input_increment = input_stride * 2 - channels;
+ const size_t output_increment = output_stride * 2 - channels;
+
+ const float* i0 = input;
+ float* o0 = output;
+ const float* i1 = (const float*) ((uintptr_t) i0 + input_stride);
+ float* o1 = (float*) ((uintptr_t) o0 + output_stride);
+ if XNN_UNPREDICTABLE(rows < 2) {
+ i1 = i0;
+ o1 = o0;
+ }
+
+ const float vmin = params->scalar.min;
+ const float vmax = params->scalar.max;
+ do {
+ const float* w = weights;
+ size_t c = channels;
+ for (; c >= 2 * sizeof(float); c -= 2 * sizeof(float)) {
+ const float vscale0 = w[0];
+ const float vscale1 = w[1];
+
+ float vacc0x0 = i0[0];
+ float vacc0x1 = i0[1];
+ i0 += 2;
+ float vacc1x0 = i1[0];
+ float vacc1x1 = i1[1];
+ i1 += 2;
+
+ const float vbias0 = w[2];
+ const float vbias1 = w[3];
+
+ vacc0x0 = vacc0x0 * vscale0 + vbias0;
+ vacc0x1 = vacc0x1 * vscale1 + vbias1;
+ vacc1x0 = vacc1x0 * vscale0 + vbias0;
+ vacc1x1 = vacc1x1 * vscale1 + vbias1;
+
+ vacc0x0 = __builtin_wasm_max_f32(vacc0x0, vmin);
+ vacc0x1 = __builtin_wasm_max_f32(vacc0x1, vmin);
+ vacc1x0 = __builtin_wasm_max_f32(vacc1x0, vmin);
+ vacc1x1 = __builtin_wasm_max_f32(vacc1x1, vmin);
+
+ vacc0x0 = __builtin_wasm_min_f32(vacc0x0, vmax);
+ vacc0x1 = __builtin_wasm_min_f32(vacc0x1, vmax);
+ vacc1x0 = __builtin_wasm_min_f32(vacc1x0, vmax);
+ vacc1x1 = __builtin_wasm_min_f32(vacc1x1, vmax);
+
+ o0[0] = vacc0x0;
+ o0[1] = vacc0x1;
+ o0 += 2;
+ o1[0] = vacc1x0;
+ o1[1] = vacc1x1;
+ o1 += 2;
+
+ w += 4;
+ }
+ if XNN_UNLIKELY(c != 0) {
+ do {
+ const float vscale = *w++;
+
+ float vacc0 = *i0++;
+ float vacc1 = *i1++;
+
+ const float vbias = w[1];
+
+ vacc0 = vacc0 * vscale + vbias;
+ vacc1 = vacc1 * vscale + vbias;
+
+ vacc0 = __builtin_wasm_max_f32(vacc0, vmin);
+ vacc1 = __builtin_wasm_max_f32(vacc1, vmin);
+
+ vacc0 = __builtin_wasm_min_f32(vacc0, vmax);
+ vacc1 = __builtin_wasm_min_f32(vacc1, vmax);
+
+ *o0++ = vacc0;
+ *o1++ = vacc1;
+
+ c -= sizeof(float);
+ } while (c != 0);
+ }
+ i0 = (const float*) ((uintptr_t) i0 + input_increment);
+ o0 = (float*) ((uintptr_t) o0 + output_increment);
+ i1 = (const float*) ((uintptr_t) i1 + input_increment);
+ o1 = (float*) ((uintptr_t) o1 + output_increment);
+ if XNN_UNPREDICTABLE(rows < 4) {
+ i1 = i0;
+ o1 = o0;
+ }
+ rows = doz(rows, 2);
+ } while (rows != 0);
+}
diff --git a/src/f32-vmulcaddc/gen/c4-wasm-2x.c b/src/f32-vmulcaddc/gen/c4-wasm-2x.c
new file mode 100644
index 0000000..1b45e19
--- /dev/null
+++ b/src/f32-vmulcaddc/gen/c4-wasm-2x.c
@@ -0,0 +1,143 @@
+// Auto-generated file. Do not edit!
+// Template: src/f32-vmulcaddc/scalar.c.in
+// Generator: tools/xngen
+//
+// Copyright 2019 Google LLC
+//
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree.
+
+#include <assert.h>
+
+#include <xnnpack/math.h>
+#include <xnnpack/vmulcaddc.h>
+
+
+void xnn_f32_vmulcaddc_ukernel_c4__wasm_2x(
+ size_t rows,
+ size_t channels,
+ const float*restrict input,
+ size_t input_stride,
+ const float*restrict weights,
+ float*restrict output,
+ size_t output_stride,
+ const union xnn_f32_output_params params[restrict static 1])
+{
+ assert(rows != 0);
+ assert(channels != 0);
+ assert(channels % sizeof(float) == 0);
+
+ const size_t input_increment = input_stride * 2 - channels;
+ const size_t output_increment = output_stride * 2 - channels;
+
+ const float* i0 = input;
+ float* o0 = output;
+ const float* i1 = (const float*) ((uintptr_t) i0 + input_stride);
+ float* o1 = (float*) ((uintptr_t) o0 + output_stride);
+ if XNN_UNPREDICTABLE(rows < 2) {
+ i1 = i0;
+ o1 = o0;
+ }
+
+ const float vmin = params->scalar.min;
+ const float vmax = params->scalar.max;
+ do {
+ const float* w = weights;
+ size_t c = channels;
+ for (; c >= 4 * sizeof(float); c -= 4 * sizeof(float)) {
+ const float vscale0 = w[0];
+ const float vscale1 = w[1];
+ const float vscale2 = w[2];
+ const float vscale3 = w[3];
+
+ float vacc0x0 = i0[0];
+ float vacc0x1 = i0[1];
+ float vacc0x2 = i0[2];
+ float vacc0x3 = i0[3];
+ i0 += 4;
+ float vacc1x0 = i1[0];
+ float vacc1x1 = i1[1];
+ float vacc1x2 = i1[2];
+ float vacc1x3 = i1[3];
+ i1 += 4;
+
+ const float vbias0 = w[4];
+ const float vbias1 = w[5];
+ const float vbias2 = w[6];
+ const float vbias3 = w[7];
+
+ vacc0x0 = vacc0x0 * vscale0 + vbias0;
+ vacc0x1 = vacc0x1 * vscale1 + vbias1;
+ vacc0x2 = vacc0x2 * vscale2 + vbias2;
+ vacc0x3 = vacc0x3 * vscale3 + vbias3;
+ vacc1x0 = vacc1x0 * vscale0 + vbias0;
+ vacc1x1 = vacc1x1 * vscale1 + vbias1;
+ vacc1x2 = vacc1x2 * vscale2 + vbias2;
+ vacc1x3 = vacc1x3 * vscale3 + vbias3;
+
+ vacc0x0 = __builtin_wasm_max_f32(vacc0x0, vmin);
+ vacc0x1 = __builtin_wasm_max_f32(vacc0x1, vmin);
+ vacc0x2 = __builtin_wasm_max_f32(vacc0x2, vmin);
+ vacc0x3 = __builtin_wasm_max_f32(vacc0x3, vmin);
+ vacc1x0 = __builtin_wasm_max_f32(vacc1x0, vmin);
+ vacc1x1 = __builtin_wasm_max_f32(vacc1x1, vmin);
+ vacc1x2 = __builtin_wasm_max_f32(vacc1x2, vmin);
+ vacc1x3 = __builtin_wasm_max_f32(vacc1x3, vmin);
+
+ vacc0x0 = __builtin_wasm_min_f32(vacc0x0, vmax);
+ vacc0x1 = __builtin_wasm_min_f32(vacc0x1, vmax);
+ vacc0x2 = __builtin_wasm_min_f32(vacc0x2, vmax);
+ vacc0x3 = __builtin_wasm_min_f32(vacc0x3, vmax);
+ vacc1x0 = __builtin_wasm_min_f32(vacc1x0, vmax);
+ vacc1x1 = __builtin_wasm_min_f32(vacc1x1, vmax);
+ vacc1x2 = __builtin_wasm_min_f32(vacc1x2, vmax);
+ vacc1x3 = __builtin_wasm_min_f32(vacc1x3, vmax);
+
+ o0[0] = vacc0x0;
+ o0[1] = vacc0x1;
+ o0[2] = vacc0x2;
+ o0[3] = vacc0x3;
+ o0 += 4;
+ o1[0] = vacc1x0;
+ o1[1] = vacc1x1;
+ o1[2] = vacc1x2;
+ o1[3] = vacc1x3;
+ o1 += 4;
+
+ w += 8;
+ }
+ if XNN_UNLIKELY(c != 0) {
+ do {
+ const float vscale = *w++;
+
+ float vacc0 = *i0++;
+ float vacc1 = *i1++;
+
+ const float vbias = w[3];
+
+ vacc0 = vacc0 * vscale + vbias;
+ vacc1 = vacc1 * vscale + vbias;
+
+ vacc0 = __builtin_wasm_max_f32(vacc0, vmin);
+ vacc1 = __builtin_wasm_max_f32(vacc1, vmin);
+
+ vacc0 = __builtin_wasm_min_f32(vacc0, vmax);
+ vacc1 = __builtin_wasm_min_f32(vacc1, vmax);
+
+ *o0++ = vacc0;
+ *o1++ = vacc1;
+
+ c -= sizeof(float);
+ } while (c != 0);
+ }
+ i0 = (const float*) ((uintptr_t) i0 + input_increment);
+ o0 = (float*) ((uintptr_t) o0 + output_increment);
+ i1 = (const float*) ((uintptr_t) i1 + input_increment);
+ o1 = (float*) ((uintptr_t) o1 + output_increment);
+ if XNN_UNPREDICTABLE(rows < 4) {
+ i1 = i0;
+ o1 = o0;
+ }
+ rows = doz(rows, 2);
+ } while (rows != 0);
+}
diff --git a/src/f32-vmulcaddc/scalar.c.in b/src/f32-vmulcaddc/scalar.c.in
index f25f500..fccad73 100644
--- a/src/f32-vmulcaddc/scalar.c.in
+++ b/src/f32-vmulcaddc/scalar.c.in
@@ -12,7 +12,9 @@
#include <xnnpack/vmulcaddc.h>
-void xnn_f32_vmulcaddc_ukernel_c${CHANNEL_TILE}__scalar_${ROW_TILE}x(
+$MIN_F32 = "__builtin_wasm_min_f32" if WASM else "math_min_f32"
+$MAX_F32 = "__builtin_wasm_max_f32" if WASM else "math_max_f32"
+void xnn_f32_vmulcaddc_ukernel_c${CHANNEL_TILE}__${"wasm" if WASM else "scalar"}_${ROW_TILE}x(
size_t rows,
size_t channels,
const float*restrict input,
@@ -69,11 +71,11 @@
$for M in range(ROW_TILE):
$for C in range(CHANNEL_TILE):
- vacc${M}x${ABC[C]} = math_max_f32(vacc${M}x${ABC[C]}, vmin);
+ vacc${M}x${ABC[C]} = ${MAX_F32}(vacc${M}x${ABC[C]}, vmin);
$for M in range(ROW_TILE):
$for C in range(CHANNEL_TILE):
- vacc${M}x${ABC[C]} = math_min_f32(vacc${M}x${ABC[C]}, vmax);
+ vacc${M}x${ABC[C]} = ${MIN_F32}(vacc${M}x${ABC[C]}, vmax);
$for M in range(ROW_TILE):
$for C in range(CHANNEL_TILE):
@@ -95,10 +97,10 @@
vacc${M} = vacc${M} * vscale + vbias;
$for M in range(ROW_TILE):
- vacc${M} = math_max_f32(vacc${M}, vmin);
+ vacc${M} = ${MAX_F32}(vacc${M}, vmin);
$for M in range(ROW_TILE):
- vacc${M} = math_min_f32(vacc${M}, vmax);
+ vacc${M} = ${MIN_F32}(vacc${M}, vmax);
$for M in range(ROW_TILE):
*o${M}++ = vacc${M};
@@ -119,10 +121,10 @@
vacc${M} = vacc${M} * vscale + vbias;
$for M in range(ROW_TILE):
- vacc${M} = math_max_f32(vacc${M}, vmin);
+ vacc${M} = ${MAX_F32}(vacc${M}, vmin);
$for M in range(ROW_TILE):
- vacc${M} = math_min_f32(vacc${M}, vmax);
+ vacc${M} = ${MIN_F32}(vacc${M}, vmax);
$for M in range(ROW_TILE):
*o${M}++ = vacc${M};
diff --git a/src/init.c b/src/init.c
index 5c32056..e189b8b 100644
--- a/src/init.c
+++ b/src/init.c
@@ -1134,61 +1134,61 @@
xnn_params.f32.gemm = (struct gemm_parameters) {
.gemm = (xnn_gemm_ukernel_function) xnn_f32_gemm_ukernel_2x4__scalar,
.igemm = (xnn_igemm_ukernel_function) xnn_f32_igemm_ukernel_2x4__scalar,
- .gemm1 = (xnn_gemm_ukernel_function) xnn_f32_gemm_ukernel_1x4__scalar,
- .igemm1 = (xnn_igemm_ukernel_function) xnn_f32_igemm_ukernel_1x4__scalar,
+ .gemm1 = (xnn_gemm_ukernel_function) xnn_f32_gemm_ukernel_1x4__wasm,
+ .igemm1 = (xnn_igemm_ukernel_function) xnn_f32_igemm_ukernel_1x4__wasm,
.mr = 2,
.nr = 4,
};
} else {
xnn_params.f32.gemm = (struct gemm_parameters) {
- .gemm = (xnn_gemm_ukernel_function) xnn_f32_gemm_ukernel_4x4__scalar,
- .igemm = (xnn_igemm_ukernel_function) xnn_f32_igemm_ukernel_4x4__scalar,
- .gemm1 = (xnn_gemm_ukernel_function) xnn_f32_gemm_ukernel_1x4__scalar,
- .igemm1 = (xnn_igemm_ukernel_function) xnn_f32_igemm_ukernel_1x4__scalar,
+ .gemm = (xnn_gemm_ukernel_function) xnn_f32_gemm_ukernel_4x4__wasm,
+ .igemm = (xnn_igemm_ukernel_function) xnn_f32_igemm_ukernel_4x4__wasm,
+ .gemm1 = (xnn_gemm_ukernel_function) xnn_f32_gemm_ukernel_1x4__wasm,
+ .igemm1 = (xnn_igemm_ukernel_function) xnn_f32_igemm_ukernel_1x4__wasm,
.mr = 4,
.nr = 4,
};
}
xnn_params.f32.gemm2 = (struct gemm_parameters) {
.gemm = NULL,
- .igemm = (xnn_igemm_ukernel_function) xnn_f32_igemm_ukernel_4x2__scalar,
+ .igemm = (xnn_igemm_ukernel_function) xnn_f32_igemm_ukernel_4x2__wasm,
.mr = 4,
.nr = 2,
};
xnn_params.f32.dwconv[0] = (struct dwconv_parameters) {
- .up = (xnn_dwconv_up_ukernel_function) xnn_f32_dwconv_ukernel_up1x4__scalar_acc2,
+ .up = (xnn_dwconv_up_ukernel_function) xnn_f32_dwconv_ukernel_up1x4__wasm_acc2,
.cr = 1,
.mr = 4,
};
xnn_params.f32.dwconv[1] = (struct dwconv_parameters) {
- .up = (xnn_dwconv_up_ukernel_function) xnn_f32_dwconv_ukernel_up1x9__scalar_acc2,
+ .up = (xnn_dwconv_up_ukernel_function) xnn_f32_dwconv_ukernel_up1x9__wasm_acc2,
.cr = 1,
.mr = 9,
};
xnn_params.f32.dwconv[2] = (struct dwconv_parameters) {
- .up = (xnn_dwconv_up_ukernel_function) xnn_f32_dwconv_ukernel_up1x25__scalar_acc2,
+ .up = (xnn_dwconv_up_ukernel_function) xnn_f32_dwconv_ukernel_up1x25__wasm_acc2,
.cr = 1,
.mr = 25,
};
xnn_params.f32.avgpool = (struct avgpool_parameters) {
- .up = (xnn_avgpool_up_ukernel_function) xnn_f32_avgpool_ukernel_up9__scalar,
- .mp = (xnn_avgpool_mp_ukernel_function) xnn_f32_avgpool_ukernel_mp9p8q__scalar,
+ .up = (xnn_avgpool_up_ukernel_function) xnn_f32_avgpool_ukernel_up9__wasm,
+ .mp = (xnn_avgpool_mp_ukernel_function) xnn_f32_avgpool_ukernel_mp9p8q__wasm,
.mr = 9,
.qr = 8,
};
xnn_params.f32.pavgpool = (struct pavgpool_parameters) {
- .up = (xnn_pavgpool_up_ukernel_function) xnn_f32_pavgpool_ukernel_up9__scalar,
- .mp = (xnn_pavgpool_mp_ukernel_function) xnn_f32_pavgpool_ukernel_mp9p8q__scalar,
+ .up = (xnn_pavgpool_up_ukernel_function) xnn_f32_pavgpool_ukernel_up9__wasm,
+ .mp = (xnn_pavgpool_mp_ukernel_function) xnn_f32_pavgpool_ukernel_mp9p8q__wasm,
.mr = 9,
.qr = 8,
};
xnn_params.f32.gavgpool = (struct gavgpool_parameters) {
- .up = (xnn_gavgpool_up_ukernel_function) xnn_f32_gavgpool_ukernel_up7__scalar,
- .mp = (xnn_gavgpool_mp_ukernel_function) xnn_f32_gavgpool_ukernel_mp7p7q__scalar,
+ .up = (xnn_gavgpool_up_ukernel_function) xnn_f32_gavgpool_ukernel_up7__wasm,
+ .mp = (xnn_gavgpool_mp_ukernel_function) xnn_f32_gavgpool_ukernel_mp7p7q__wasm,
.mr = 7,
};
xnn_params.f32.maxpool = (struct maxpool_parameters) {
- .ukernel = (xnn_maxpool_ukernel_function) xnn_f32_maxpool_ukernel_9p8x__scalar_c1,
+ .ukernel = (xnn_maxpool_ukernel_function) xnn_f32_maxpool_ukernel_9p8x__wasm_c1,
.mr = 9,
.qr = 8,
};
@@ -1210,33 +1210,33 @@
.pixel_tile = 1,
.channel_tile = 2,
};
- xnn_params.f32.clamp = (xnn_univector_ukernel_function) xnn_f32_clamp_ukernel__scalar;
- xnn_params.f32.hswish = (xnn_univector_ukernel_function) xnn_f32_hswish_ukernel__scalar;
+ xnn_params.f32.clamp = (xnn_univector_ukernel_function) xnn_f32_clamp_ukernel__wasm;
+ xnn_params.f32.hswish = (xnn_univector_ukernel_function) xnn_f32_hswish_ukernel__wasm;
xnn_params.f32.prelu = (struct prelu_parameters) {
- .ukernel = (xnn_prelu_ukernel_function) xnn_f32_prelu_ukernel__scalar_2x4,
+ .ukernel = (xnn_prelu_ukernel_function) xnn_f32_prelu_ukernel__wasm_2x4,
.row_tile = 4,
.channel_tile = 4,
};
xnn_params.f32.vadd = (struct vbinary_parameters) {
- .op_ukernel = (xnn_vbinary_ukernel_function) xnn_f32_vadd_ukernel__scalar_x4,
- .opc_ukernel = (xnn_vbinary_ukernel_function) xnn_f32_vaddc_ukernel__scalar_x4,
- .ropc_ukernel = (xnn_vbinary_ukernel_function) xnn_f32_vaddc_ukernel__scalar_x4,
+ .op_ukernel = (xnn_vbinary_ukernel_function) xnn_f32_vadd_ukernel__wasm_x4,
+ .opc_ukernel = (xnn_vbinary_ukernel_function) xnn_f32_vaddc_ukernel__wasm_x4,
+ .ropc_ukernel = (xnn_vbinary_ukernel_function) xnn_f32_vaddc_ukernel__wasm_x4,
.element_tile = 8,
};
xnn_params.f32.vmul = (struct vbinary_parameters) {
- .op_ukernel = (xnn_vbinary_ukernel_function) xnn_f32_vmul_ukernel__scalar_x4,
- .opc_ukernel = (xnn_vbinary_ukernel_function) xnn_f32_vmulc_ukernel__scalar_x4,
- .ropc_ukernel = (xnn_vbinary_ukernel_function) xnn_f32_vmulc_ukernel__scalar_x4,
+ .op_ukernel = (xnn_vbinary_ukernel_function) xnn_f32_vmul_ukernel__wasm_x4,
+ .opc_ukernel = (xnn_vbinary_ukernel_function) xnn_f32_vmulc_ukernel__wasm_x4,
+ .ropc_ukernel = (xnn_vbinary_ukernel_function) xnn_f32_vmulc_ukernel__wasm_x4,
.element_tile = 8,
};
xnn_params.f32.vsub = (struct vbinary_parameters) {
- .op_ukernel = (xnn_vbinary_ukernel_function) xnn_f32_vsub_ukernel__scalar_x4,
- .opc_ukernel = (xnn_vbinary_ukernel_function) xnn_f32_vsubc_ukernel__scalar_x4,
- .ropc_ukernel = (xnn_vbinary_ukernel_function) xnn_f32_vrsubc_ukernel__scalar_x4,
+ .op_ukernel = (xnn_vbinary_ukernel_function) xnn_f32_vsub_ukernel__wasm_x4,
+ .opc_ukernel = (xnn_vbinary_ukernel_function) xnn_f32_vsubc_ukernel__wasm_x4,
+ .ropc_ukernel = (xnn_vbinary_ukernel_function) xnn_f32_vrsubc_ukernel__wasm_x4,
.element_tile = 8,
};
xnn_params.f32.vmulcaddc = (struct vmulcaddc_parameters) {
- .ukernel = (xnn_vmulcaddc_ukernel_function) xnn_f32_vmulcaddc_ukernel_c1__scalar_2x,
+ .ukernel = (xnn_vmulcaddc_ukernel_function) xnn_f32_vmulcaddc_ukernel_c1__wasm_2x,
.channel_tile = 1,
.row_tile = 2,
};
diff --git a/src/xnnpack/avgpool.h b/src/xnnpack/avgpool.h
index d838fb5..bea28ac 100644
--- a/src/xnnpack/avgpool.h
+++ b/src/xnnpack/avgpool.h
@@ -33,9 +33,10 @@
const union xnn_f32_avgpool_params* params);
DECLARE_F32_AVGPOOL_MULTIPASS_UKERNEL_FUNCTION(xnn_f32_avgpool_ukernel_mp9p8q__neon)
-DECLARE_F32_AVGPOOL_MULTIPASS_UKERNEL_FUNCTION(xnn_f32_avgpool_ukernel_mp9p8q__psimd)
-DECLARE_F32_AVGPOOL_MULTIPASS_UKERNEL_FUNCTION(xnn_f32_avgpool_ukernel_mp9p8q__scalar)
DECLARE_F32_AVGPOOL_MULTIPASS_UKERNEL_FUNCTION(xnn_f32_avgpool_ukernel_mp9p8q__sse)
+DECLARE_F32_AVGPOOL_MULTIPASS_UKERNEL_FUNCTION(xnn_f32_avgpool_ukernel_mp9p8q__psimd)
+DECLARE_F32_AVGPOOL_MULTIPASS_UKERNEL_FUNCTION(xnn_f32_avgpool_ukernel_mp9p8q__wasm)
+DECLARE_F32_AVGPOOL_MULTIPASS_UKERNEL_FUNCTION(xnn_f32_avgpool_ukernel_mp9p8q__scalar)
#define DECLARE_F32_AVGPOOL_UNIPASS_UKERNEL_FUNCTION(fn_name) \
@@ -51,9 +52,10 @@
const union xnn_f32_avgpool_params* params);
DECLARE_F32_AVGPOOL_UNIPASS_UKERNEL_FUNCTION(xnn_f32_avgpool_ukernel_up9__neon)
-DECLARE_F32_AVGPOOL_UNIPASS_UKERNEL_FUNCTION(xnn_f32_avgpool_ukernel_up9__psimd)
-DECLARE_F32_AVGPOOL_UNIPASS_UKERNEL_FUNCTION(xnn_f32_avgpool_ukernel_up9__scalar)
DECLARE_F32_AVGPOOL_UNIPASS_UKERNEL_FUNCTION(xnn_f32_avgpool_ukernel_up9__sse)
+DECLARE_F32_AVGPOOL_UNIPASS_UKERNEL_FUNCTION(xnn_f32_avgpool_ukernel_up9__psimd)
+DECLARE_F32_AVGPOOL_UNIPASS_UKERNEL_FUNCTION(xnn_f32_avgpool_ukernel_up9__wasm)
+DECLARE_F32_AVGPOOL_UNIPASS_UKERNEL_FUNCTION(xnn_f32_avgpool_ukernel_up9__scalar)
#define DECLARE_Q8_AVGPOOL_MULTIPASS_UKERNEL_FUNCTION(fn_name) \
diff --git a/src/xnnpack/clamp.h b/src/xnnpack/clamp.h
index 7a9c67b..ef7a4b6 100644
--- a/src/xnnpack/clamp.h
+++ b/src/xnnpack/clamp.h
@@ -31,6 +31,7 @@
DECLARE_F32_CLAMP_UKERNEL_FUNCTION(xnn_f32_clamp_ukernel__avx)
DECLARE_F32_CLAMP_UKERNEL_FUNCTION(xnn_f32_clamp_ukernel__avx512f)
DECLARE_F32_CLAMP_UKERNEL_FUNCTION(xnn_f32_clamp_ukernel__psimd)
+DECLARE_F32_CLAMP_UKERNEL_FUNCTION(xnn_f32_clamp_ukernel__wasm)
DECLARE_F32_CLAMP_UKERNEL_FUNCTION(xnn_f32_clamp_ukernel__scalar)
diff --git a/src/xnnpack/dwconv.h b/src/xnnpack/dwconv.h
index 45069b9..6c77827 100644
--- a/src/xnnpack/dwconv.h
+++ b/src/xnnpack/dwconv.h
@@ -29,10 +29,6 @@
size_t output_increment, \
const union xnn_f32_output_params* params);
-DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up1x4__scalar)
-DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up1x4__scalar_acc2)
-DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up2x4__scalar)
-DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up2x4__scalar_acc2)
DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up4x4__psimd)
DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up4x4__psimd_acc2)
DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up8x4__psimd)
@@ -53,11 +49,15 @@
DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up16x4__avx512f_acc2)
DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up32x4__avx512f)
DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up32x4__avx512f_acc2)
+DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up1x4__wasm)
+DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up1x4__wasm_acc2)
+DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up2x4__wasm)
+DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up2x4__wasm_acc2)
+DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up1x4__scalar)
+DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up1x4__scalar_acc2)
+DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up2x4__scalar)
+DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up2x4__scalar_acc2)
-DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up1x9__scalar)
-DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up1x9__scalar_acc2)
-DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up2x9__scalar)
-DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up2x9__scalar_acc2)
DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up4x9__neon)
DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up4x9__neon_acc2)
DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up8x9__neon)
@@ -88,11 +88,15 @@
DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up16x9__avx512f_acc2)
DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up32x9__avx512f)
DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up32x9__avx512f_acc2)
+DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up1x9__wasm)
+DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up1x9__wasm_acc2)
+DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up2x9__wasm)
+DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up2x9__wasm_acc2)
+DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up1x9__scalar)
+DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up1x9__scalar_acc2)
+DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up2x9__scalar)
+DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up2x9__scalar_acc2)
-DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up1x25__scalar)
-DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up1x25__scalar_acc2)
-DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up2x25__scalar)
-DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up2x25__scalar_acc2)
DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up4x25__psimd)
DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up4x25__psimd_acc2)
DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up8x25__psimd)
@@ -113,6 +117,14 @@
DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up16x25__avx512f_acc2)
DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up32x25__avx512f)
DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up32x25__avx512f_acc2)
+DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up1x25__wasm)
+DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up1x25__wasm_acc2)
+DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up2x25__wasm)
+DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up2x25__wasm_acc2)
+DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up1x25__scalar)
+DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up1x25__scalar_acc2)
+DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up2x25__scalar)
+DECLARE_F32_DWCONV_UNIPASS_UKERNEL_FUNCTION(xnn_f32_dwconv_ukernel_up2x25__scalar_acc2)
#define DECLARE_Q8_DWCONV_UNIPASS_UKERNEL_FUNCTION(fn_name) \
diff --git a/src/xnnpack/gavgpool.h b/src/xnnpack/gavgpool.h
index ebfaa28..b8b5285 100644
--- a/src/xnnpack/gavgpool.h
+++ b/src/xnnpack/gavgpool.h
@@ -31,9 +31,10 @@
const union xnn_f32_avgpool_params* params);
DECLARE_F32_GAVGPOOL_MULTIPASS_UKERNEL_FUNCTION(xnn_f32_gavgpool_ukernel_mp7p7q__neon)
-DECLARE_F32_GAVGPOOL_MULTIPASS_UKERNEL_FUNCTION(xnn_f32_gavgpool_ukernel_mp7p7q__psimd)
-DECLARE_F32_GAVGPOOL_MULTIPASS_UKERNEL_FUNCTION(xnn_f32_gavgpool_ukernel_mp7p7q__scalar)
DECLARE_F32_GAVGPOOL_MULTIPASS_UKERNEL_FUNCTION(xnn_f32_gavgpool_ukernel_mp7p7q__sse)
+DECLARE_F32_GAVGPOOL_MULTIPASS_UKERNEL_FUNCTION(xnn_f32_gavgpool_ukernel_mp7p7q__psimd)
+DECLARE_F32_GAVGPOOL_MULTIPASS_UKERNEL_FUNCTION(xnn_f32_gavgpool_ukernel_mp7p7q__wasm)
+DECLARE_F32_GAVGPOOL_MULTIPASS_UKERNEL_FUNCTION(xnn_f32_gavgpool_ukernel_mp7p7q__scalar)
#define DECLARE_F32_GAVGPOOL_UNIPASS_UKERNEL_FUNCTION(fn_name) \
@@ -47,9 +48,10 @@
const union xnn_f32_avgpool_params* params);
DECLARE_F32_GAVGPOOL_UNIPASS_UKERNEL_FUNCTION(xnn_f32_gavgpool_ukernel_up7__neon)
-DECLARE_F32_GAVGPOOL_UNIPASS_UKERNEL_FUNCTION(xnn_f32_gavgpool_ukernel_up7__psimd)
-DECLARE_F32_GAVGPOOL_UNIPASS_UKERNEL_FUNCTION(xnn_f32_gavgpool_ukernel_up7__scalar)
DECLARE_F32_GAVGPOOL_UNIPASS_UKERNEL_FUNCTION(xnn_f32_gavgpool_ukernel_up7__sse)
+DECLARE_F32_GAVGPOOL_UNIPASS_UKERNEL_FUNCTION(xnn_f32_gavgpool_ukernel_up7__psimd)
+DECLARE_F32_GAVGPOOL_UNIPASS_UKERNEL_FUNCTION(xnn_f32_gavgpool_ukernel_up7__wasm)
+DECLARE_F32_GAVGPOOL_UNIPASS_UKERNEL_FUNCTION(xnn_f32_gavgpool_ukernel_up7__scalar)
#define DECLARE_Q8_GAVGPOOL_MULTIPASS_UKERNEL_FUNCTION(fn_name) \
XNN_INTERNAL void fn_name( \
diff --git a/src/xnnpack/gemm.h b/src/xnnpack/gemm.h
index 88a9d8b..2688f42 100644
--- a/src/xnnpack/gemm.h
+++ b/src/xnnpack/gemm.h
@@ -34,7 +34,6 @@
DECLARE_F32_GEMM_UKERNEL_FUNCTION(xnn_f32_gemm_ukernel_1x12__aarch64_neonfma_cortex_a53)
DECLARE_F32_GEMM_UKERNEL_FUNCTION(xnn_f32_gemm_ukernel_1x16__avx512f_broadcast)
-DECLARE_F32_GEMM_UKERNEL_FUNCTION(xnn_f32_gemm_ukernel_1x4__scalar)
DECLARE_F32_GEMM_UKERNEL_FUNCTION(xnn_f32_gemm_ukernel_1x8__aarch64_neonfma_cortex_a53)
DECLARE_F32_GEMM_UKERNEL_FUNCTION(xnn_f32_gemm_ukernel_1x8__aarch64_neonfma_cortex_a57)
DECLARE_F32_GEMM_UKERNEL_FUNCTION(xnn_f32_gemm_ukernel_1x8__aarch64_neonfma_cortex_a75)
@@ -52,13 +51,10 @@
DECLARE_F32_GEMM_UKERNEL_FUNCTION(xnn_f32_gemm_ukernel_1x8s4__neonfma)
DECLARE_F32_GEMM_UKERNEL_FUNCTION(xnn_f32_gemm_ukernel_1x8s4__psimd)
DECLARE_F32_GEMM_UKERNEL_FUNCTION(xnn_f32_gemm_ukernel_1x8s4__sse)
-DECLARE_F32_GEMM_UKERNEL_FUNCTION(xnn_f32_gemm_ukernel_2x4__scalar)
DECLARE_F32_GEMM_UKERNEL_FUNCTION(xnn_f32_gemm_ukernel_4x12__aarch64_neonfma_cortex_a53)
DECLARE_F32_GEMM_UKERNEL_FUNCTION(xnn_f32_gemm_ukernel_4x16__avx512f_broadcast)
DECLARE_F32_GEMM_UKERNEL_FUNCTION(xnn_f32_gemm_ukernel_4x2__neon_lane_ld64)
DECLARE_F32_GEMM_UKERNEL_FUNCTION(xnn_f32_gemm_ukernel_4x2__neonfma_lane_ld64)
-DECLARE_F32_GEMM_UKERNEL_FUNCTION(xnn_f32_gemm_ukernel_4x2__scalar)
-DECLARE_F32_GEMM_UKERNEL_FUNCTION(xnn_f32_gemm_ukernel_4x4__scalar)
DECLARE_F32_GEMM_UKERNEL_FUNCTION(xnn_f32_gemm_ukernel_4x8__aarch64_neonfma_cortex_a53)
DECLARE_F32_GEMM_UKERNEL_FUNCTION(xnn_f32_gemm_ukernel_4x8__aarch64_neonfma_cortex_a57)
DECLARE_F32_GEMM_UKERNEL_FUNCTION(xnn_f32_gemm_ukernel_4x8__aarch64_neonfma_cortex_a75)
@@ -119,6 +115,16 @@
DECLARE_F32_GEMM_UKERNEL_FUNCTION(xnn_f32_gemm_ukernel_8x8s4__neon)
DECLARE_F32_GEMM_UKERNEL_FUNCTION(xnn_f32_gemm_ukernel_8x8s4__neonfma)
+DECLARE_F32_GEMM_UKERNEL_FUNCTION(xnn_f32_gemm_ukernel_1x4__wasm)
+DECLARE_F32_GEMM_UKERNEL_FUNCTION(xnn_f32_gemm_ukernel_2x4__wasm)
+DECLARE_F32_GEMM_UKERNEL_FUNCTION(xnn_f32_gemm_ukernel_4x2__wasm)
+DECLARE_F32_GEMM_UKERNEL_FUNCTION(xnn_f32_gemm_ukernel_4x4__wasm)
+
+DECLARE_F32_GEMM_UKERNEL_FUNCTION(xnn_f32_gemm_ukernel_1x4__scalar)
+DECLARE_F32_GEMM_UKERNEL_FUNCTION(xnn_f32_gemm_ukernel_2x4__scalar)
+DECLARE_F32_GEMM_UKERNEL_FUNCTION(xnn_f32_gemm_ukernel_4x2__scalar)
+DECLARE_F32_GEMM_UKERNEL_FUNCTION(xnn_f32_gemm_ukernel_4x4__scalar)
+
#define DECLARE_F32_GEMMINC_UKERNEL_FUNCTION(fn_name) \
XNN_INTERNAL void fn_name( \
size_t mr, \
@@ -135,7 +141,6 @@
DECLARE_F32_GEMMINC_UKERNEL_FUNCTION(xnn_f32_gemminc_ukernel_1x12__aarch64_neonfma_cortex_a53)
DECLARE_F32_GEMMINC_UKERNEL_FUNCTION(xnn_f32_gemminc_ukernel_1x16__avx512f_broadcast)
-DECLARE_F32_GEMMINC_UKERNEL_FUNCTION(xnn_f32_gemminc_ukernel_1x4__scalar)
DECLARE_F32_GEMMINC_UKERNEL_FUNCTION(xnn_f32_gemminc_ukernel_1x8__aarch64_neonfma_cortex_a53)
DECLARE_F32_GEMMINC_UKERNEL_FUNCTION(xnn_f32_gemminc_ukernel_1x8__aarch64_neonfma_cortex_a57)
DECLARE_F32_GEMMINC_UKERNEL_FUNCTION(xnn_f32_gemminc_ukernel_1x8__aarch64_neonfma_cortex_a75)
@@ -153,13 +158,10 @@
DECLARE_F32_GEMMINC_UKERNEL_FUNCTION(xnn_f32_gemminc_ukernel_1x8s4__neonfma)
DECLARE_F32_GEMMINC_UKERNEL_FUNCTION(xnn_f32_gemminc_ukernel_1x8s4__psimd)
DECLARE_F32_GEMMINC_UKERNEL_FUNCTION(xnn_f32_gemminc_ukernel_1x8s4__sse)
-DECLARE_F32_GEMMINC_UKERNEL_FUNCTION(xnn_f32_gemminc_ukernel_2x4__scalar)
DECLARE_F32_GEMMINC_UKERNEL_FUNCTION(xnn_f32_gemminc_ukernel_4x12__aarch64_neonfma_cortex_a53)
DECLARE_F32_GEMMINC_UKERNEL_FUNCTION(xnn_f32_gemminc_ukernel_4x16__avx512f_broadcast)
DECLARE_F32_GEMMINC_UKERNEL_FUNCTION(xnn_f32_gemminc_ukernel_4x2__neon_lane_ld64)
DECLARE_F32_GEMMINC_UKERNEL_FUNCTION(xnn_f32_gemminc_ukernel_4x2__neonfma_lane_ld64)
-DECLARE_F32_GEMMINC_UKERNEL_FUNCTION(xnn_f32_gemminc_ukernel_4x2__scalar)
-DECLARE_F32_GEMMINC_UKERNEL_FUNCTION(xnn_f32_gemminc_ukernel_4x4__scalar)
DECLARE_F32_GEMMINC_UKERNEL_FUNCTION(xnn_f32_gemminc_ukernel_4x8__aarch64_neonfma_cortex_a53)
DECLARE_F32_GEMMINC_UKERNEL_FUNCTION(xnn_f32_gemminc_ukernel_4x8__aarch64_neonfma_cortex_a57)
DECLARE_F32_GEMMINC_UKERNEL_FUNCTION(xnn_f32_gemminc_ukernel_4x8__aarch64_neonfma_cortex_a75)
@@ -219,6 +221,16 @@
DECLARE_F32_GEMMINC_UKERNEL_FUNCTION(xnn_f32_gemminc_ukernel_8x8s4__neon)
DECLARE_F32_GEMMINC_UKERNEL_FUNCTION(xnn_f32_gemminc_ukernel_8x8s4__neonfma)
+DECLARE_F32_GEMMINC_UKERNEL_FUNCTION(xnn_f32_gemminc_ukernel_1x4__wasm)
+DECLARE_F32_GEMMINC_UKERNEL_FUNCTION(xnn_f32_gemminc_ukernel_2x4__wasm)
+DECLARE_F32_GEMMINC_UKERNEL_FUNCTION(xnn_f32_gemminc_ukernel_4x2__wasm)
+DECLARE_F32_GEMMINC_UKERNEL_FUNCTION(xnn_f32_gemminc_ukernel_4x4__wasm)
+
+DECLARE_F32_GEMMINC_UKERNEL_FUNCTION(xnn_f32_gemminc_ukernel_1x4__scalar)
+DECLARE_F32_GEMMINC_UKERNEL_FUNCTION(xnn_f32_gemminc_ukernel_2x4__scalar)
+DECLARE_F32_GEMMINC_UKERNEL_FUNCTION(xnn_f32_gemminc_ukernel_4x2__scalar)
+DECLARE_F32_GEMMINC_UKERNEL_FUNCTION(xnn_f32_gemminc_ukernel_4x4__scalar)
+
#define DECLARE_F16_GEMM_UKERNEL_FUNCTION(fn_name) \
void fn_name( \
size_t mr, \
diff --git a/src/xnnpack/hswish.h b/src/xnnpack/hswish.h
index eda1a1f..d80595c 100644
--- a/src/xnnpack/hswish.h
+++ b/src/xnnpack/hswish.h
@@ -23,10 +23,11 @@
float* y, \
const union xnn_f32_hswish_params* params);
-DECLARE_F32_HSWISH_UKERNEL_FUNCTION(xnn_f32_hswish_ukernel__psimd)
DECLARE_F32_HSWISH_UKERNEL_FUNCTION(xnn_f32_hswish_ukernel__neon)
DECLARE_F32_HSWISH_UKERNEL_FUNCTION(xnn_f32_hswish_ukernel__neonfma)
DECLARE_F32_HSWISH_UKERNEL_FUNCTION(xnn_f32_hswish_ukernel__sse)
+DECLARE_F32_HSWISH_UKERNEL_FUNCTION(xnn_f32_hswish_ukernel__psimd)
+DECLARE_F32_HSWISH_UKERNEL_FUNCTION(xnn_f32_hswish_ukernel__wasm)
DECLARE_F32_HSWISH_UKERNEL_FUNCTION(xnn_f32_hswish_ukernel__scalar)
diff --git a/src/xnnpack/igemm.h b/src/xnnpack/igemm.h
index 96167cd..2c7b64d 100644
--- a/src/xnnpack/igemm.h
+++ b/src/xnnpack/igemm.h
@@ -36,7 +36,6 @@
DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_1x12__aarch64_neonfma_cortex_a53)
DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_1x16__avx512f_broadcast)
-DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_1x4__scalar)
DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_1x8__aarch64_neonfma_cortex_a53)
DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_1x8__aarch64_neonfma_cortex_a57)
DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_1x8__aarch64_neonfma_cortex_a75)
@@ -54,17 +53,14 @@
DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_1x8s4__neonfma)
DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_1x8s4__psimd)
DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_1x8s4__sse)
-DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_2x4__scalar)
DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_4x12__aarch64_neonfma_cortex_a53)
DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_4x16__avx512f_broadcast)
DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_4x2__neon_lane_ld64)
DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_4x2__neonfma_lane_ld64)
-DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_4x2__scalar)
DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_4x2c4__psimd)
DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_4x2c4__sse)
DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_4x4__neon_lane_ld64)
DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_4x4__neonfma_lane_ld64)
-DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_4x4__scalar)
DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_4x8__aarch64_neonfma_cortex_a53)
DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_4x8__aarch64_neonfma_cortex_a75)
DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_4x8__avx_broadcast)
@@ -117,6 +113,16 @@
DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_8x8s4__neon)
DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_8x8s4__neonfma)
+DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_1x4__wasm)
+DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_2x4__wasm)
+DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_4x2__wasm)
+DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_4x4__wasm)
+
+DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_1x4__scalar)
+DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_2x4__scalar)
+DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_4x2__scalar)
+DECLARE_F32_IGEMM_UKERNEL_FUNCTION(xnn_f32_igemm_ukernel_4x4__scalar)
+
#define DECLARE_Q8_IGEMM_UKERNEL_FUNCTION(fn_name) \
XNN_INTERNAL void fn_name( \
size_t mr, \
diff --git a/src/xnnpack/math.h b/src/xnnpack/math.h
index 69eda29..a1e1253 100644
--- a/src/xnnpack/math.h
+++ b/src/xnnpack/math.h
@@ -60,17 +60,9 @@
}
inline static float math_min_f32(float a, float b) {
- #if defined(__wasm__)
- return __builtin_wasm_min_f32(a, b);
- #else
- return XNN_UNPREDICTABLE(b < a) ? b : a;
- #endif
+ return XNN_UNPREDICTABLE(b < a) ? b : a;
}
inline static float math_max_f32(float a, float b) {
- #if defined(__wasm__)
- return __builtin_wasm_max_f32(a, b);
- #else
- return XNN_UNPREDICTABLE(b < a) ? a : b;
- #endif
+ return XNN_UNPREDICTABLE(b < a) ? a : b;
}
diff --git a/src/xnnpack/maxpool.h b/src/xnnpack/maxpool.h
index 6013cba..697d4eb 100644
--- a/src/xnnpack/maxpool.h
+++ b/src/xnnpack/maxpool.h
@@ -31,8 +31,9 @@
size_t output_increment, \
const union xnn_f32_output_params* params);
-DECLARE_F32_MAXPOOL_UKERNEL_FUNCTION(xnn_f32_maxpool_ukernel_9p8x__psimd_c4)
DECLARE_F32_MAXPOOL_UKERNEL_FUNCTION(xnn_f32_maxpool_ukernel_9p8x__sse_c4)
+DECLARE_F32_MAXPOOL_UKERNEL_FUNCTION(xnn_f32_maxpool_ukernel_9p8x__psimd_c4)
+DECLARE_F32_MAXPOOL_UKERNEL_FUNCTION(xnn_f32_maxpool_ukernel_9p8x__wasm_c1)
DECLARE_F32_MAXPOOL_UKERNEL_FUNCTION(xnn_f32_maxpool_ukernel_9p8x__scalar_c1)
diff --git a/src/xnnpack/pavgpool.h b/src/xnnpack/pavgpool.h
index 3be16d3..5caa61c 100644
--- a/src/xnnpack/pavgpool.h
+++ b/src/xnnpack/pavgpool.h
@@ -31,9 +31,10 @@
const union xnn_f32_output_params* params);
DECLARE_F32_PAVGPOOL_MULTIPASS_UKERNEL_FUNCTION(xnn_f32_pavgpool_ukernel_mp9p8q__neon)
-DECLARE_F32_PAVGPOOL_MULTIPASS_UKERNEL_FUNCTION(xnn_f32_pavgpool_ukernel_mp9p8q__psimd)
-DECLARE_F32_PAVGPOOL_MULTIPASS_UKERNEL_FUNCTION(xnn_f32_pavgpool_ukernel_mp9p8q__scalar)
DECLARE_F32_PAVGPOOL_MULTIPASS_UKERNEL_FUNCTION(xnn_f32_pavgpool_ukernel_mp9p8q__sse)
+DECLARE_F32_PAVGPOOL_MULTIPASS_UKERNEL_FUNCTION(xnn_f32_pavgpool_ukernel_mp9p8q__psimd)
+DECLARE_F32_PAVGPOOL_MULTIPASS_UKERNEL_FUNCTION(xnn_f32_pavgpool_ukernel_mp9p8q__wasm)
+DECLARE_F32_PAVGPOOL_MULTIPASS_UKERNEL_FUNCTION(xnn_f32_pavgpool_ukernel_mp9p8q__scalar)
#define DECLARE_F32_PAVGPOOL_UNIPASS_UKERNEL_FUNCTION(fn_name) \
@@ -50,9 +51,10 @@
const union xnn_f32_output_params* params);
DECLARE_F32_PAVGPOOL_UNIPASS_UKERNEL_FUNCTION(xnn_f32_pavgpool_ukernel_up9__neon)
-DECLARE_F32_PAVGPOOL_UNIPASS_UKERNEL_FUNCTION(xnn_f32_pavgpool_ukernel_up9__psimd)
-DECLARE_F32_PAVGPOOL_UNIPASS_UKERNEL_FUNCTION(xnn_f32_pavgpool_ukernel_up9__scalar)
DECLARE_F32_PAVGPOOL_UNIPASS_UKERNEL_FUNCTION(xnn_f32_pavgpool_ukernel_up9__sse)
+DECLARE_F32_PAVGPOOL_UNIPASS_UKERNEL_FUNCTION(xnn_f32_pavgpool_ukernel_up9__psimd)
+DECLARE_F32_PAVGPOOL_UNIPASS_UKERNEL_FUNCTION(xnn_f32_pavgpool_ukernel_up9__wasm)
+DECLARE_F32_PAVGPOOL_UNIPASS_UKERNEL_FUNCTION(xnn_f32_pavgpool_ukernel_up9__scalar)
#ifdef __cplusplus
diff --git a/src/xnnpack/prelu.h b/src/xnnpack/prelu.h
index a0fefab..8606b25 100644
--- a/src/xnnpack/prelu.h
+++ b/src/xnnpack/prelu.h
@@ -27,17 +27,24 @@
size_t output_stride, \
const union xnn_f32_output_params* params);
-DECLARE_F32_PRELU_UKERNEL_FUNCTION(xnn_f32_prelu_ukernel__scalar_2x1)
-DECLARE_F32_PRELU_UKERNEL_FUNCTION(xnn_f32_prelu_ukernel__scalar_2x4)
DECLARE_F32_PRELU_UKERNEL_FUNCTION(xnn_f32_prelu_ukernel__neon_2x4)
DECLARE_F32_PRELU_UKERNEL_FUNCTION(xnn_f32_prelu_ukernel__neon_2x8)
-DECLARE_F32_PRELU_UKERNEL_FUNCTION(xnn_f32_prelu_ukernel__psimd_2x4)
-DECLARE_F32_PRELU_UKERNEL_FUNCTION(xnn_f32_prelu_ukernel__psimd_2x8)
+
DECLARE_F32_PRELU_UKERNEL_FUNCTION(xnn_f32_prelu_ukernel__sse2_2x4)
DECLARE_F32_PRELU_UKERNEL_FUNCTION(xnn_f32_prelu_ukernel__sse2_2x8)
+
DECLARE_F32_PRELU_UKERNEL_FUNCTION(xnn_f32_prelu_ukernel__sse41_2x4)
DECLARE_F32_PRELU_UKERNEL_FUNCTION(xnn_f32_prelu_ukernel__sse41_2x8)
+DECLARE_F32_PRELU_UKERNEL_FUNCTION(xnn_f32_prelu_ukernel__psimd_2x4)
+DECLARE_F32_PRELU_UKERNEL_FUNCTION(xnn_f32_prelu_ukernel__psimd_2x8)
+
+DECLARE_F32_PRELU_UKERNEL_FUNCTION(xnn_f32_prelu_ukernel__wasm_2x1)
+DECLARE_F32_PRELU_UKERNEL_FUNCTION(xnn_f32_prelu_ukernel__wasm_2x4)
+
+DECLARE_F32_PRELU_UKERNEL_FUNCTION(xnn_f32_prelu_ukernel__scalar_2x1)
+DECLARE_F32_PRELU_UKERNEL_FUNCTION(xnn_f32_prelu_ukernel__scalar_2x4)
+
#ifdef __cplusplus
} // extern "C"
diff --git a/src/xnnpack/vbinary.h b/src/xnnpack/vbinary.h
index 1a7ada3..0a405a3 100644
--- a/src/xnnpack/vbinary.h
+++ b/src/xnnpack/vbinary.h
@@ -29,73 +29,94 @@
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vadd_ukernel__neon_x4)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vadd_ukernel__neon_x8)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vadd_ukernel__sse_x4)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vadd_ukernel__sse_x8)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vadd_ukernel__psimd_x4)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vadd_ukernel__psimd_x8)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vadd_ukernel__wasm_x1)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vadd_ukernel__wasm_x2)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vadd_ukernel__wasm_x4)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vadd_ukernel__scalar_x1)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vadd_ukernel__scalar_x2)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vadd_ukernel__scalar_x4)
-DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vadd_ukernel__sse_x4)
-DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vadd_ukernel__sse_x8)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vmul_ukernel__neon_x4)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vmul_ukernel__neon_x8)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vmul_ukernel__sse_x4)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vmul_ukernel__sse_x8)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vmul_ukernel__psimd_x4)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vmul_ukernel__psimd_x8)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vmul_ukernel__wasm_x1)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vmul_ukernel__wasm_x2)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vmul_ukernel__wasm_x4)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vmul_ukernel__scalar_x1)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vmul_ukernel__scalar_x2)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vmul_ukernel__scalar_x4)
-DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vmul_ukernel__sse_x4)
-DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vmul_ukernel__sse_x8)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vsub_ukernel__neon_x4)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vsub_ukernel__neon_x8)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vsub_ukernel__sse_x4)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vsub_ukernel__sse_x8)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vsub_ukernel__psimd_x4)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vsub_ukernel__psimd_x8)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vsub_ukernel__wasm_x1)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vsub_ukernel__wasm_x2)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vsub_ukernel__wasm_x4)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vsub_ukernel__scalar_x1)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vsub_ukernel__scalar_x2)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vsub_ukernel__scalar_x4)
-DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vsub_ukernel__sse_x4)
-DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vsub_ukernel__sse_x8)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vaddc_ukernel__neon_x4)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vaddc_ukernel__neon_x8)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vaddc_ukernel__sse_x4)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vaddc_ukernel__sse_x8)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vaddc_ukernel__psimd_x4)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vaddc_ukernel__psimd_x8)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vaddc_ukernel__wasm_x1)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vaddc_ukernel__wasm_x2)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vaddc_ukernel__wasm_x4)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vaddc_ukernel__scalar_x1)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vaddc_ukernel__scalar_x2)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vaddc_ukernel__scalar_x4)
-DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vaddc_ukernel__sse_x4)
-DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vaddc_ukernel__sse_x8)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vmulc_ukernel__neon_x4)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vmulc_ukernel__neon_x8)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vmulc_ukernel__psimd_x4)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vmulc_ukernel__psimd_x8)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vmulc_ukernel__sse_x4)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vmulc_ukernel__sse_x8)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vmulc_ukernel__wasm_x1)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vmulc_ukernel__wasm_x2)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vmulc_ukernel__wasm_x4)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vmulc_ukernel__scalar_x1)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vmulc_ukernel__scalar_x2)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vmulc_ukernel__scalar_x4)
-DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vmulc_ukernel__sse_x4)
-DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vmulc_ukernel__sse_x8)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vsubc_ukernel__neon_x4)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vsubc_ukernel__neon_x8)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vsubc_ukernel__sse_x4)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vsubc_ukernel__sse_x8)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vsubc_ukernel__psimd_x4)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vsubc_ukernel__psimd_x8)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vsubc_ukernel__wasm_x1)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vsubc_ukernel__wasm_x2)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vsubc_ukernel__wasm_x4)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vsubc_ukernel__scalar_x1)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vsubc_ukernel__scalar_x2)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vsubc_ukernel__scalar_x4)
-DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vsubc_ukernel__sse_x4)
-DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vsubc_ukernel__sse_x8)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vrsubc_ukernel__neon_x4)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vrsubc_ukernel__neon_x8)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vrsubc_ukernel__sse_x4)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vrsubc_ukernel__sse_x8)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vrsubc_ukernel__psimd_x4)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vrsubc_ukernel__psimd_x8)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vrsubc_ukernel__wasm_x1)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vrsubc_ukernel__wasm_x2)
+DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vrsubc_ukernel__wasm_x4)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vrsubc_ukernel__scalar_x1)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vrsubc_ukernel__scalar_x2)
DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vrsubc_ukernel__scalar_x4)
-DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vrsubc_ukernel__sse_x4)
-DECLARE_F32_VBINOP_UKERNEL_FUNCTION(xnn_f32_vrsubc_ukernel__sse_x8)
#ifdef __cplusplus
diff --git a/src/xnnpack/vmulcaddc.h b/src/xnnpack/vmulcaddc.h
index d659687..4e817e4 100644
--- a/src/xnnpack/vmulcaddc.h
+++ b/src/xnnpack/vmulcaddc.h
@@ -27,17 +27,25 @@
size_t y_stride, \
const union xnn_f32_output_params* params);
+DECLARE_F32_VMULCADDC_UKERNEL_FUNCTION(xnn_f32_vmulcaddc_ukernel_c4__neon_2x)
+DECLARE_F32_VMULCADDC_UKERNEL_FUNCTION(xnn_f32_vmulcaddc_ukernel_c8__neon_2x)
+
+DECLARE_F32_VMULCADDC_UKERNEL_FUNCTION(xnn_f32_vmulcaddc_ukernel_c4__neonfma_2x)
+DECLARE_F32_VMULCADDC_UKERNEL_FUNCTION(xnn_f32_vmulcaddc_ukernel_c8__neonfma_2x)
+
+DECLARE_F32_VMULCADDC_UKERNEL_FUNCTION(xnn_f32_vmulcaddc_ukernel_c4__psimd_2x)
+DECLARE_F32_VMULCADDC_UKERNEL_FUNCTION(xnn_f32_vmulcaddc_ukernel_c8__psimd_2x)
+
+DECLARE_F32_VMULCADDC_UKERNEL_FUNCTION(xnn_f32_vmulcaddc_ukernel_c4__sse_2x)
+DECLARE_F32_VMULCADDC_UKERNEL_FUNCTION(xnn_f32_vmulcaddc_ukernel_c8__sse_2x)
+
+DECLARE_F32_VMULCADDC_UKERNEL_FUNCTION(xnn_f32_vmulcaddc_ukernel_c1__wasm_2x)
+DECLARE_F32_VMULCADDC_UKERNEL_FUNCTION(xnn_f32_vmulcaddc_ukernel_c2__wasm_2x)
+DECLARE_F32_VMULCADDC_UKERNEL_FUNCTION(xnn_f32_vmulcaddc_ukernel_c4__wasm_2x)
+
DECLARE_F32_VMULCADDC_UKERNEL_FUNCTION(xnn_f32_vmulcaddc_ukernel_c1__scalar_2x)
DECLARE_F32_VMULCADDC_UKERNEL_FUNCTION(xnn_f32_vmulcaddc_ukernel_c2__scalar_2x)
DECLARE_F32_VMULCADDC_UKERNEL_FUNCTION(xnn_f32_vmulcaddc_ukernel_c4__scalar_2x)
-DECLARE_F32_VMULCADDC_UKERNEL_FUNCTION(xnn_f32_vmulcaddc_ukernel_c4__neon_2x)
-DECLARE_F32_VMULCADDC_UKERNEL_FUNCTION(xnn_f32_vmulcaddc_ukernel_c4__neonfma_2x)
-DECLARE_F32_VMULCADDC_UKERNEL_FUNCTION(xnn_f32_vmulcaddc_ukernel_c4__psimd_2x)
-DECLARE_F32_VMULCADDC_UKERNEL_FUNCTION(xnn_f32_vmulcaddc_ukernel_c4__sse_2x)
-DECLARE_F32_VMULCADDC_UKERNEL_FUNCTION(xnn_f32_vmulcaddc_ukernel_c8__neon_2x)
-DECLARE_F32_VMULCADDC_UKERNEL_FUNCTION(xnn_f32_vmulcaddc_ukernel_c8__neonfma_2x)
-DECLARE_F32_VMULCADDC_UKERNEL_FUNCTION(xnn_f32_vmulcaddc_ukernel_c8__psimd_2x)
-DECLARE_F32_VMULCADDC_UKERNEL_FUNCTION(xnn_f32_vmulcaddc_ukernel_c8__sse_2x)
#ifdef __cplusplus