[bazel] Add support for enabling relaxed SIMD in wasm_cc_binary (#1728)
It would probably be more elegant to reuse the existing `simd` attribute
and change it's type from boolean into string enum (similar like it's
for `threads`), but that would be a breaking change so I decided to add
additional boolean acknowlidging that `simd=False`, `relaxed_simd=True`
makes no sense and will also enable `simd` as `relaxed_simd` implies
`simd`.
diff --git a/bazel/emscripten_toolchain/toolchain.bzl b/bazel/emscripten_toolchain/toolchain.bzl
index 4c11970..d447f07 100644
--- a/bazel/emscripten_toolchain/toolchain.bzl
+++ b/bazel/emscripten_toolchain/toolchain.bzl
@@ -440,13 +440,14 @@
name = "do_not_split_linking_cmdline",
),
- # Adds simd support, only available with the llvm backend.
+ # Adds simd support
feature(
name = "wasm_simd",
),
- # Adds relaxed-simd support, only available with the llvm backend.
+ # Adds relaxed-simd support
feature(
name = "wasm_relaxed_simd",
+ implies = ["wasm_simd"],
),
feature(
name = "precise_long_double_printf",
diff --git a/bazel/emscripten_toolchain/wasm_cc_binary.bzl b/bazel/emscripten_toolchain/wasm_cc_binary.bzl
index da84e64..d0f21b1 100644
--- a/bazel/emscripten_toolchain/wasm_cc_binary.bzl
+++ b/bazel/emscripten_toolchain/wasm_cc_binary.bzl
@@ -17,8 +17,10 @@
if attr.exit_runtime == True:
features.append("exit_runtime")
- if attr.simd:
+ if attr.simd != "off":
features.append("wasm_simd")
+ if attr.simd == "relaxed_simd":
+ features.append("wasm_relaxed_simd")
platform = "@emsdk//:platform_wasm"
if attr.standalone:
@@ -78,8 +80,10 @@
default = "_default",
values = ["_default", "emscripten", "off"],
),
- "simd": attr.bool(
- default = False,
+ "simd": attr.string(
+ default = "off",
+ values = ["off", "simd128", "relaxed_simd"],
+ doc = "Enable SIMD support via emscripten.",
),
"standalone": attr.bool(
default = False,
diff --git a/bazel/hello-world/BUILD b/bazel/hello-world/BUILD
index 07fbed5..061f4c1 100644
--- a/bazel/hello-world/BUILD
+++ b/bazel/hello-world/BUILD
@@ -19,5 +19,11 @@
wasm_cc_binary(
name = "hello-world-wasm-simd",
cc_target = ":hello-world-simd",
- simd = True,
+ simd = "simd128",
+)
+
+wasm_cc_binary(
+ name = "hello-world-wasm-relaxed-simd",
+ cc_target = ":hello-world-simd",
+ simd = "relaxed_simd",
)
diff --git a/bazel/hello-world/hello-world-simd.cc b/bazel/hello-world/hello-world-simd.cc
index 649adab..c876cc4 100644
--- a/bazel/hello-world/hello-world-simd.cc
+++ b/bazel/hello-world/hello-world-simd.cc
@@ -8,3 +8,42 @@
wasm_v128_store(&out[i], prod);
}
}
+
+#ifdef __wasm_relaxed_simd__
+
+float dot_product_accumulate(const float* A, const float* B, int len, float initial_sum) {
+ int i = 0;
+
+ // Initialize accumulator vector with the initial sum spread across all lanes
+ // We will sum these lanes at the end.
+ v128_t acc = wasm_f32x4_splat(initial_sum);
+
+ // Main loop: process 4 elements at a time
+ // Requires len to be at least 4. If len < 4, the loop is skipped.
+ for (; i + 4 <= len; i += 4) {
+ // Load 4 floats from A and B
+ v128_t va = wasm_v128_load(&A[i]);
+ v128_t vb = wasm_v128_load(&B[i]);
+
+ // Fused Multiply-Add: acc = (va * vb) + acc
+ // Uses relaxed rounding for performance
+ acc = __builtin_wasm_relaxed_madd_f32x4(va, vb, acc);
+ }
+
+ // Horizontal add: sum the 4 lanes of the accumulator
+ // acc = {s0, s1, s2, s3}
+ // sum = s0 + s1 + s2 + s3
+ v128_t sum1 = wasm_f32x4_add(acc, wasm_i32x4_shuffle(acc, acc, 1, 0, 3, 2)); // {s0+s1, s0+s1, s2+s3, s2+s3}
+ v128_t sum2 = wasm_f32x4_add(sum1, wasm_i32x4_shuffle(sum1, sum1, 2, 3, 0, 1)); // {total, total, total, total}
+
+ float result = wasm_f32x4_extract_lane(sum2, 0);
+
+ // Handle remaining elements (tail loop)
+ for (; i < len; i++) {
+ result += A[i] * B[i];
+ }
+
+ return result;
+}
+
+#endif
diff --git a/test/test_bazel.ps1 b/test/test_bazel.ps1
index 143c23c..dc0393a 100644
--- a/test/test_bazel.ps1
+++ b/test/test_bazel.ps1
@@ -8,6 +8,9 @@
bazel build //hello-world:hello-world-wasm-simd
if (-not $?) { Exit $LastExitCode }
+bazel build //hello-world:hello-world-wasm-relaxed-simd
+if (-not $?) { Exit $LastExitCode }
+
Set-Location test_external
bazel build //:hello-world-wasm
diff --git a/test/test_bazel.sh b/test/test_bazel.sh
index b2a198e..f4699fe 100755
--- a/test/test_bazel.sh
+++ b/test/test_bazel.sh
@@ -22,6 +22,7 @@
bazel build //hello-world:hello-world-wasm
bazel build //hello-world:hello-world-wasm-simd
+bazel build //hello-world:hello-world-wasm-relaxed-simd
pushd test_external
bazel build //:hello-world-wasm
diff --git a/test/test_bazel_mac.sh b/test/test_bazel_mac.sh
index 8be9f90..26a31c8 100755
--- a/test/test_bazel_mac.sh
+++ b/test/test_bazel_mac.sh
@@ -21,6 +21,7 @@
cd bazel
bazel build //hello-world:hello-world-wasm
bazel build //hello-world:hello-world-wasm-simd
+bazel build //hello-world:hello-world-wasm-relaxed-simd
cd test_external
bazel build //long_command_line:long_command_line_wasm