Skip to content

Commit dec6528

Browse files
[mypyc] librt base64: support pyodide via the NEON intrinsics (#20316)
Fixes the following error when building lib-rt with pyodide > ` /home/runner/work/librt/librt/.pyodide_build/pywasmcross_symlinks/cc -fno-strict-overflow -Wsign-compare -Wunreachable-code -DNDEBUG -g -O3 -Wall -O2 -g0 -fPIC -DPY_CALL_TRAMPOLINE -I. -Ibase64 -I/tmp/build-env-ftmn_jvi/include -I/home/runner/.cache/cibuildwheel/pyodide-build-0.30.7/0.27.7/xbuildenv/pyodide-root/cpython/installs/python-3.12.7/include/python3.12 -c base64/arch/avx/codec.c -o build/temp.emscripten_3_1_58_wasm32-cpython-312/base64/arch/avx/codec.o -O3 -mavx` > ` emcc: error: passing any of -msse, -msse2, -msse3, -mssse3, -msse4.1, -msse4.2, -msse4, -mavx, -mfpu=neon flags also requires passing -msimd128 (or -mrelaxed-simd)!` Instead of using emscripten's compatibility headers for X86 intrinsics, this PR has pyodide/emscripten use the NEON intrinsics as they better match the underlying SIMD capabilities in WASM. And it skips the "CPU detection" which would not work (nor make sense) in a WASM setting. Ideally a pure WASM implementation would be added to base64 and backported here as well. --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent c1fb129 commit dec6528

File tree

4 files changed

+60
-41
lines changed

4 files changed

+60
-41
lines changed

mypyc/build_setup.py

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import os
12
import platform
23
import sys
34

@@ -30,32 +31,41 @@
3031

3132
ccompiler.CCompiler.__spawn = ccompiler.CCompiler.spawn # type: ignore[attr-defined]
3233
X86_64 = platform.machine() in ("x86_64", "AMD64", "amd64")
34+
PYODIDE = "PYODIDE" in os.environ
3335

3436

3537
def spawn(self, cmd, **kwargs) -> None: # type: ignore[no-untyped-def]
36-
compiler_type: str = self.compiler_type
37-
extra_options = EXTRA_FLAGS_PER_COMPILER_TYPE_PER_PATH_COMPONENT[compiler_type]
38-
new_cmd = list(cmd)
39-
if X86_64 and extra_options is not None:
40-
# filenames are closer to the end of command line
38+
if PYODIDE:
39+
new_cmd = list(cmd)
4140
for argument in reversed(new_cmd):
42-
# Check if the matching argument contains a source filename.
4341
if not str(argument).endswith(".c"):
4442
continue
43+
if "base64/arch/" in str(argument):
44+
new_cmd.extend(["-msimd128"])
45+
else:
46+
compiler_type: str = self.compiler_type
47+
extra_options = EXTRA_FLAGS_PER_COMPILER_TYPE_PER_PATH_COMPONENT[compiler_type]
48+
new_cmd = list(cmd)
49+
if X86_64 and extra_options is not None:
50+
# filenames are closer to the end of command line
51+
for argument in reversed(new_cmd):
52+
# Check if the matching argument contains a source filename.
53+
if not str(argument).endswith(".c"):
54+
continue
4555

46-
for path in extra_options.keys():
47-
if path in str(argument):
48-
if compiler_type == "bcpp":
49-
compiler = new_cmd.pop()
50-
# Borland accepts a source file name at the end,
51-
# insert the options before it
52-
new_cmd.extend(extra_options[path])
53-
new_cmd.append(compiler)
54-
else:
55-
new_cmd.extend(extra_options[path])
56-
57-
# path component is found, no need to search any further
58-
break
56+
for path in extra_options.keys():
57+
if path in str(argument):
58+
if compiler_type == "bcpp":
59+
compiler = new_cmd.pop()
60+
# Borland accepts a source file name at the end,
61+
# insert the options before it
62+
new_cmd.extend(extra_options[path])
63+
new_cmd.append(compiler)
64+
else:
65+
new_cmd.extend(extra_options[path])
66+
67+
# path component is found, no need to search any further
68+
break
5969
self.__spawn(new_cmd, **kwargs)
6070

6171

mypyc/lib-rt/base64/arch/neon64/codec.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
#include <arm_neon.h>
1313

1414
// Only enable inline assembly on supported compilers.
15-
#if defined(__GNUC__) || defined(__clang__)
15+
#if !defined(__wasm__) && (defined(__GNUC__) || defined(__clang__))
1616
#define BASE64_NEON64_USE_ASM
1717
#endif
1818

mypyc/lib-rt/base64/config.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
#define BASE64_WITH_NEON32 0
1414
#define HAVE_NEON32 BASE64_WITH_NEON32
1515

16-
#if defined(__APPLE__) && defined(__aarch64__)
16+
#if (defined(__APPLE__) && defined(__aarch64__)) || (defined(__wasm__) && defined(__wasm_simd128__))
1717
#define BASE64_WITH_NEON64 1
1818
#else
1919
#define BASE64_WITH_NEON64 0

mypyc/lib-rt/setup.py

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -42,32 +42,41 @@
4242

4343
ccompiler.CCompiler.__spawn = ccompiler.CCompiler.spawn # type: ignore[attr-defined]
4444
X86_64 = platform.machine() in ("x86_64", "AMD64", "amd64")
45+
PYODIDE = "PYODIDE" in os.environ
4546

4647

4748
def spawn(self, cmd, **kwargs) -> None: # type: ignore[no-untyped-def]
48-
compiler_type: str = self.compiler_type
49-
extra_options = EXTRA_FLAGS_PER_COMPILER_TYPE_PER_PATH_COMPONENT[compiler_type]
50-
new_cmd = list(cmd)
51-
if X86_64 and extra_options is not None:
52-
# filenames are closer to the end of command line
49+
if PYODIDE:
50+
new_cmd = list(cmd)
5351
for argument in reversed(new_cmd):
54-
# Check if the matching argument contains a source filename.
5552
if not str(argument).endswith(".c"):
5653
continue
57-
58-
for path in extra_options.keys():
59-
if path in str(argument):
60-
if compiler_type == "bcpp":
61-
compiler = new_cmd.pop()
62-
# Borland accepts a source file name at the end,
63-
# insert the options before it
64-
new_cmd.extend(extra_options[path])
65-
new_cmd.append(compiler)
66-
else:
67-
new_cmd.extend(extra_options[path])
68-
69-
# path component is found, no need to search any further
70-
break
54+
if "base64/arch/" in str(argument):
55+
new_cmd.extend(["-msimd128"])
56+
else:
57+
compiler_type: str = self.compiler_type
58+
extra_options = EXTRA_FLAGS_PER_COMPILER_TYPE_PER_PATH_COMPONENT[compiler_type]
59+
new_cmd = list(cmd)
60+
if X86_64 and extra_options is not None:
61+
# filenames are closer to the end of command line
62+
for argument in reversed(new_cmd):
63+
# Check if the matching argument contains a source filename.
64+
if not str(argument).endswith(".c"):
65+
continue
66+
67+
for path in extra_options.keys():
68+
if path in str(argument):
69+
if compiler_type == "bcpp":
70+
compiler = new_cmd.pop()
71+
# Borland accepts a source file name at the end,
72+
# insert the options before it
73+
new_cmd.extend(extra_options[path])
74+
new_cmd.append(compiler)
75+
else:
76+
new_cmd.extend(extra_options[path])
77+
78+
# path component is found, no need to search any further
79+
break
7180
self.__spawn(new_cmd, **kwargs)
7281

7382

0 commit comments

Comments
 (0)