Skip to content

Commit a38d392

Browse files
Wasm libc rt archive (#5328)
* Add math builtins to wasm compiler-rt, move memset/memcpy/memmove to compiler-rt * Move extra libc items into its own rt archive, wasm-libc-rt * Extract files_in_path function * Older comment was better * Use files_in_path in more places * Remove defaults
1 parent 1fd4e5d commit a38d392

File tree

6 files changed

+128
-38
lines changed

6 files changed

+128
-38
lines changed

emcc.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,12 +1104,7 @@ def check(input_file):
11041104
if shared.Settings.WASM_BACKEND:
11051105
options.js_opts = None
11061106
shared.Settings.BINARYEN = 1
1107-
# Static linking is tricky with LLVM, since e.g. memset might not be used from libc,
1108-
# but be used as an intrinsic, and codegen will generate a libc call from that intrinsic
1109-
# *after* static linking would have thought it is all in there. In asm.js this is not an
1110-
# issue as we do JS linking anyhow, and have asm.js-optimized versions of all the LLVM
1111-
# intrinsics. But for wasm, we need a better solution. For now, just pin stuff.
1112-
shared.Settings.EXPORTED_FUNCTIONS += ['_memcpy', '_memmove', '_memset']
1107+
11131108
# to bootstrap struct_info, we need binaryen
11141109
os.environ['EMCC_WASM_BACKEND_BINARYEN'] = '1'
11151110

emscripten.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1956,17 +1956,20 @@ def create_backend_args_wasm(infile, temp_s, settings):
19561956

19571957

19581958
def create_s2wasm_args(temp_s):
1959-
def compiler_rt_fail():
1960-
raise Exception('Expected wasm_compiler_rt.a to already be built')
1961-
compiler_rt_lib = shared.Cache.get('wasm_compiler_rt.a', compiler_rt_fail, 'a')
1959+
def wasm_rt_fail(archive_file):
1960+
def wrapped():
1961+
raise Exception('Expected {} to already be built'.format(archive_file))
1962+
return wrapped
1963+
compiler_rt_lib = shared.Cache.get('wasm_compiler_rt.a', wasm_rt_fail('wasm_compiler_rt.a'), 'a')
1964+
libc_rt_lib = shared.Cache.get('wasm_libc_rt.a', wasm_rt_fail('wasm_libc_rt.a'), 'a')
19621965

19631966
s2wasm_path = os.path.join(shared.Settings.BINARYEN_ROOT, 'bin', 's2wasm')
19641967

19651968
args = [s2wasm_path, temp_s, '--emscripten-glue']
19661969
args += ['--global-base=%d' % shared.Settings.GLOBAL_BASE]
19671970
args += ['--initial-memory=%d' % shared.Settings.TOTAL_MEMORY]
19681971
args += ['--allow-memory-growth'] if shared.Settings.ALLOW_MEMORY_GROWTH else []
1969-
args += ['-l', compiler_rt_lib]
1972+
args += ['-l', compiler_rt_lib, '-l', libc_rt_lib]
19701973
return args
19711974

19721975

tests/core/test_float_builtins.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include <stdio.h>
2+
#include <math.h>
3+
4+
int main() {
5+
float f1 = 0.1234f;
6+
float f2 = 0.5678f;
7+
double d1 = 1.0101;
8+
double d2 = 0.10101;
9+
printf(
10+
"%f\n%f\n%f\n%f\n",
11+
__builtin_fmaxf(f1, f2),
12+
__builtin_fminf(f1, f2),
13+
__builtin_fmax(d1, d2),
14+
__builtin_fmin(d1, d2)
15+
);
16+
return 0;
17+
}

tests/core/test_float_builtins.out

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
0.567800
2+
0.123400
3+
1.010100
4+
0.101010

tests/test_core.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1235,10 +1235,13 @@ def test_iswdigit(self):
12351235
def test_polymorph(self):
12361236
self.do_run_in_out_file_test('tests', 'core', 'test_polymorph')
12371237

1238-
@no_wasm_backend('no support for complex math division yet')
12391238
def test_complex(self):
12401239
self.do_run_in_out_file_test('tests', 'core', 'test_complex', force_c=True)
12411240

1241+
def test_float_builtins(self):
1242+
if not self.is_wasm_backend(): return self.skip('no __builtin_fmin support in JSBackend')
1243+
self.do_run_in_out_file_test('tests', 'core', 'test_float_builtins')
1244+
12421245
@no_wasm_backend("wasm backend doesn't add Runtime.setDynamicTop and crashes")
12431246
def test_segfault(self):
12441247
Settings.SAFE_HEAP = 1

tools/system_libs.py

Lines changed: 95 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ def run_commands(commands):
2727
# https://stackoverflow.com/questions/1408356/keyboard-interrupts-with-pythons-multiprocessing-pool, https://bugs.python.org/issue8296
2828
pool.map_async(call_process, commands, chunksize=1).get(maxint)
2929

30+
def files_in_path(path_components, filenames):
31+
srcdir = shared.path_from_root(*path_components)
32+
return [os.path.join(srcdir, f) for f in filenames]
33+
3034
def calculate(temp_files, in_temp, stdout_, stderr_, forced=[]):
3135
global stdout, stderr
3236
stdout = stdout_
@@ -124,16 +128,55 @@ def create_libc(libname):
124128

125129
def create_pthreads(libname):
126130
# Add pthread files.
127-
pthreads_files = [os.path.join('pthread', 'library_pthread.c')]
128-
pthreads_files += [shared.path_from_root('system', 'lib', 'libc', 'musl', 'src', 'thread', x) for x in ('pthread_attr_destroy.c', 'pthread_condattr_setpshared.c', 'pthread_mutex_lock.c', 'pthread_spin_destroy.c', 'pthread_attr_get.c', 'pthread_cond_broadcast.c', 'pthread_mutex_setprioceiling.c', 'pthread_spin_init.c', 'pthread_attr_init.c', 'pthread_cond_destroy.c', 'pthread_mutex_timedlock.c', 'pthread_spin_lock.c', 'pthread_attr_setdetachstate.c', 'pthread_cond_init.c', 'pthread_mutex_trylock.c', 'pthread_spin_trylock.c', 'pthread_attr_setguardsize.c', 'pthread_cond_signal.c', 'pthread_mutex_unlock.c', 'pthread_spin_unlock.c', 'pthread_attr_setinheritsched.c', 'pthread_cond_timedwait.c', 'pthread_once.c', 'sem_destroy.c', 'pthread_attr_setschedparam.c', 'pthread_cond_wait.c', 'pthread_rwlockattr_destroy.c', 'sem_getvalue.c', 'pthread_attr_setschedpolicy.c', 'pthread_equal.c', 'pthread_rwlockattr_init.c', 'sem_init.c', 'pthread_attr_setscope.c', 'pthread_getspecific.c', 'pthread_rwlockattr_setpshared.c', 'sem_open.c', 'pthread_attr_setstack.c', 'pthread_key_create.c', 'pthread_rwlock_destroy.c', 'sem_post.c', 'pthread_attr_setstacksize.c', 'pthread_mutexattr_destroy.c', 'pthread_rwlock_init.c', 'sem_timedwait.c', 'pthread_barrierattr_destroy.c', 'pthread_mutexattr_init.c', 'pthread_rwlock_rdlock.c', 'sem_trywait.c', 'pthread_barrierattr_init.c', 'pthread_mutexattr_setprotocol.c', 'pthread_rwlock_timedrdlock.c', 'sem_unlink.c', 'pthread_barrierattr_setpshared.c', 'pthread_mutexattr_setpshared.c', 'pthread_rwlock_timedwrlock.c', 'sem_wait.c', 'pthread_barrier_destroy.c', 'pthread_mutexattr_setrobust.c', 'pthread_rwlock_tryrdlock.c', '__timedwait.c', 'pthread_barrier_init.c', 'pthread_mutexattr_settype.c', 'pthread_rwlock_trywrlock.c', 'vmlock.c', 'pthread_barrier_wait.c', 'pthread_mutex_consistent.c', 'pthread_rwlock_unlock.c', '__wait.c', 'pthread_condattr_destroy.c', 'pthread_mutex_destroy.c', 'pthread_rwlock_wrlock.c', 'pthread_condattr_init.c', 'pthread_mutex_getprioceiling.c', 'pthread_setcanceltype.c', 'pthread_condattr_setclock.c', 'pthread_mutex_init.c', 'pthread_setspecific.c')]
131+
pthreads_files = files_in_path(
132+
path_components=['system', 'lib', 'libc', 'musl', 'src', 'thread'],
133+
filenames=[
134+
'pthread_attr_destroy.c', 'pthread_condattr_setpshared.c',
135+
'pthread_mutex_lock.c', 'pthread_spin_destroy.c', 'pthread_attr_get.c',
136+
'pthread_cond_broadcast.c', 'pthread_mutex_setprioceiling.c',
137+
'pthread_spin_init.c', 'pthread_attr_init.c', 'pthread_cond_destroy.c',
138+
'pthread_mutex_timedlock.c', 'pthread_spin_lock.c',
139+
'pthread_attr_setdetachstate.c', 'pthread_cond_init.c',
140+
'pthread_mutex_trylock.c', 'pthread_spin_trylock.c',
141+
'pthread_attr_setguardsize.c', 'pthread_cond_signal.c',
142+
'pthread_mutex_unlock.c', 'pthread_spin_unlock.c',
143+
'pthread_attr_setinheritsched.c', 'pthread_cond_timedwait.c',
144+
'pthread_once.c', 'sem_destroy.c', 'pthread_attr_setschedparam.c',
145+
'pthread_cond_wait.c', 'pthread_rwlockattr_destroy.c', 'sem_getvalue.c',
146+
'pthread_attr_setschedpolicy.c', 'pthread_equal.c', 'pthread_rwlockattr_init.c',
147+
'sem_init.c', 'pthread_attr_setscope.c', 'pthread_getspecific.c',
148+
'pthread_rwlockattr_setpshared.c', 'sem_open.c', 'pthread_attr_setstack.c',
149+
'pthread_key_create.c', 'pthread_rwlock_destroy.c', 'sem_post.c',
150+
'pthread_attr_setstacksize.c', 'pthread_mutexattr_destroy.c',
151+
'pthread_rwlock_init.c', 'sem_timedwait.c', 'pthread_barrierattr_destroy.c',
152+
'pthread_mutexattr_init.c', 'pthread_rwlock_rdlock.c', 'sem_trywait.c',
153+
'pthread_barrierattr_init.c', 'pthread_mutexattr_setprotocol.c',
154+
'pthread_rwlock_timedrdlock.c', 'sem_unlink.c',
155+
'pthread_barrierattr_setpshared.c', 'pthread_mutexattr_setpshared.c',
156+
'pthread_rwlock_timedwrlock.c', 'sem_wait.c', 'pthread_barrier_destroy.c',
157+
'pthread_mutexattr_setrobust.c', 'pthread_rwlock_tryrdlock.c',
158+
'__timedwait.c', 'pthread_barrier_init.c', 'pthread_mutexattr_settype.c',
159+
'pthread_rwlock_trywrlock.c', 'vmlock.c', 'pthread_barrier_wait.c',
160+
'pthread_mutex_consistent.c', 'pthread_rwlock_unlock.c', '__wait.c',
161+
'pthread_condattr_destroy.c', 'pthread_mutex_destroy.c',
162+
'pthread_rwlock_wrlock.c', 'pthread_condattr_init.c',
163+
'pthread_mutex_getprioceiling.c', 'pthread_setcanceltype.c',
164+
'pthread_condattr_setclock.c', 'pthread_mutex_init.c',
165+
'pthread_setspecific.c'
166+
])
167+
pthreads_files += [os.path.join('pthread', 'library_pthread.c')]
129168
return build_libc(libname, pthreads_files, ['-O2', '-s', 'USE_PTHREADS=1'])
130169

131170
def create_wasm_libc(libname):
132-
# in asm.js we just use Math.sin etc., which is good for code size. But wasm doesn't have such builtins, so
133-
# we need to bundle in more code
134-
# we also build in musl versions of things that we have hand-optimized asm.js for
135-
files = ([shared.path_from_root('system', 'lib', 'libc', 'musl', 'src', 'math', x) for x in ('cos.c', 'cosf.c', 'cosl.c', 'sin.c', 'sinf.c', 'sinl.c', 'tan.c', 'tanf.c', 'tanl.c', 'acos.c', 'acosf.c', 'acosl.c', 'asin.c', 'asinf.c', 'asinl.c', 'atan.c', 'atanf.c', 'atanl.c', 'atan2.c', 'atan2f.c', 'atan2l.c', 'exp.c', 'expf.c', 'expl.c', 'log.c', 'logf.c', 'logl.c', 'pow.c', 'powf.c', 'powl.c')] +
136-
[shared.path_from_root('system', 'lib', 'libc', 'musl', 'src', 'string', x) for x in ('memcpy.c', 'memset.c', 'memmove.c')])
171+
# in asm.js we just use Math.sin etc., which is good for code size. But
172+
# wasm doesn't have such builtins, so we need to bundle in more code
173+
files = files_in_path(
174+
path_components=['system', 'lib', 'libc', 'musl', 'src', 'math'],
175+
filenames=['cos.c', 'cosf.c', 'cosl.c', 'sin.c', 'sinf.c', 'sinl.c',
176+
'tan.c', 'tanf.c', 'tanl.c', 'acos.c', 'acosf.c', 'acosl.c',
177+
'asin.c', 'asinf.c', 'asinl.c', 'atan.c', 'atanf.c', 'atanl.c',
178+
'atan2.c', 'atan2f.c', 'atan2l.c', 'exp.c', 'expf.c', 'expl.c',
179+
'log.c', 'logf.c', 'logl.c', 'pow.c', 'powf.c', 'powl.c'])
137180

138181
return build_libc(libname, files, ['-O2'])
139182

@@ -169,7 +212,11 @@ def create_libcxx(libname):
169212
'utility.cpp',
170213
'valarray.cpp'
171214
]
172-
return build_libcxx(os.path.join('system', 'lib', 'libcxx'), libname, libcxx_files, ['-DLIBCXX_BUILDING_LIBCXXABI=1', '-Oz', '-I' + shared.path_from_root('system', 'lib', 'libcxxabi', 'include')], has_noexcept_version=True)
215+
libcxxabi_include = shared.path_from_root('system', 'lib', 'libcxxabi', 'include')
216+
return build_libcxx(
217+
os.path.join('system', 'lib', 'libcxx'), libname, libcxx_files,
218+
['-DLIBCXX_BUILDING_LIBCXXABI=1', '-Oz', '-I' + libcxxabi_include],
219+
has_noexcept_version=True)
173220

174221
# libcxxabi - just for dynamic_cast for now
175222
def create_libcxxabi(libname):
@@ -188,7 +235,10 @@ def create_libcxxabi(libname):
188235
'typeinfo.cpp',
189236
'private_typeinfo.cpp'
190237
]
191-
return build_libcxx(os.path.join('system', 'lib', 'libcxxabi', 'src'), libname, libcxxabi_files, ['-Oz', '-I' + shared.path_from_root('system', 'lib', 'libcxxabi', 'include')])
238+
libcxxabi_include = shared.path_from_root('system', 'lib', 'libcxxabi', 'include')
239+
return build_libcxx(
240+
os.path.join('system', 'lib', 'libcxxabi', 'src'), libname, libcxxabi_files,
241+
['-Oz', '-I' + libcxxabi_include])
192242

193243
# gl
194244
def create_gl(libname): # libname is ignored, this is just one .o file
@@ -197,9 +247,9 @@ def create_gl(libname): # libname is ignored, this is just one .o file
197247
return o
198248

199249
def create_compiler_rt(libname):
200-
srcdir = shared.path_from_root('system', 'lib', 'compiler-rt', 'lib', 'builtins')
201-
filenames = ['divdc3.c', 'divsc3.c', 'muldc3.c', 'mulsc3.c']
202-
files = (os.path.join(srcdir, f) for f in filenames)
250+
files = files_in_path(
251+
path_components=['system', 'lib', 'compiler-rt', 'lib', 'builtins'],
252+
filenames=['divdc3.c', 'divsc3.c', 'muldc3.c', 'mulsc3.c'])
203253

204254
o_s = []
205255
commands = []
@@ -237,20 +287,7 @@ def create_dlmalloc_split(libname):
237287
shared.Building.link([dlmalloc_o, split_malloc_o], lib)
238288
return lib
239289

240-
def create_wasm_compiler_rt(libname):
241-
srcdir = shared.path_from_root('system', 'lib', 'compiler-rt', 'lib', 'builtins')
242-
filenames = ['addtf3.c', 'ashlti3.c', 'ashrti3.c', 'atomic.c', 'comparetf2.c',
243-
'divtf3.c', 'divti3.c', 'udivmodti4.c',
244-
'extenddftf2.c', 'extendsftf2.c',
245-
'fixdfti.c', 'fixsfti.c', 'fixtfdi.c', 'fixtfsi.c', 'fixtfti.c',
246-
'fixunsdfti.c', 'fixunssfti.c', 'fixunstfdi.c', 'fixunstfsi.c', 'fixunstfti.c',
247-
'floatditf.c', 'floatsitf.c', 'floattidf.c', 'floattisf.c',
248-
'floatunditf.c', 'floatunsitf.c', 'floatuntidf.c', 'floatuntisf.c', 'lshrti3.c',
249-
'modti3.c', 'multf3.c', 'multi3.c', 'subtf3.c', 'udivti3.c', 'umodti3.c', 'ashrdi3.c',
250-
'ashldi3.c', 'fixdfdi.c', 'floatdidf.c', 'lshrdi3.c', 'moddi3.c',
251-
'trunctfdf2.c', 'trunctfsf2.c', 'umoddi3.c', 'fixunsdfdi.c', 'muldi3.c',
252-
'divdi3.c', 'divmoddi4.c', 'udivdi3.c', 'udivmoddi4.c']
253-
files = (os.path.join(srcdir, f) for f in filenames)
290+
def create_wasm_rt_lib(libname, files):
254291
o_s = []
255292
commands = []
256293
for src in files:
@@ -264,6 +301,36 @@ def create_wasm_compiler_rt(libname):
264301
run_commands([[shared.LLVM_AR, 'cr', '-format=gnu', lib] + o_s])
265302
return lib
266303

304+
def create_wasm_compiler_rt(libname):
305+
files = files_in_path(
306+
path_components=['system', 'lib', 'compiler-rt', 'lib', 'builtins'],
307+
filenames=['addtf3.c', 'ashlti3.c', 'ashrti3.c', 'atomic.c', 'comparetf2.c',
308+
'divtf3.c', 'divti3.c', 'udivmodti4.c',
309+
'extenddftf2.c', 'extendsftf2.c',
310+
'fixdfti.c', 'fixsfti.c', 'fixtfdi.c', 'fixtfsi.c', 'fixtfti.c',
311+
'fixunsdfti.c', 'fixunssfti.c', 'fixunstfdi.c', 'fixunstfsi.c', 'fixunstfti.c',
312+
'floatditf.c', 'floatsitf.c', 'floattidf.c', 'floattisf.c',
313+
'floatunditf.c', 'floatunsitf.c', 'floatuntidf.c', 'floatuntisf.c', 'lshrti3.c',
314+
'modti3.c', 'multf3.c', 'multi3.c', 'subtf3.c', 'udivti3.c', 'umodti3.c', 'ashrdi3.c',
315+
'ashldi3.c', 'fixdfdi.c', 'floatdidf.c', 'lshrdi3.c', 'moddi3.c',
316+
'trunctfdf2.c', 'trunctfsf2.c', 'umoddi3.c', 'fixunsdfdi.c', 'muldi3.c',
317+
'divdi3.c', 'divmoddi4.c', 'udivdi3.c', 'udivmoddi4.c'])
318+
return create_wasm_rt_lib(libname, files)
319+
320+
def create_wasm_libc_rt(libname):
321+
# Static linking is tricky with LLVM, since e.g. memset might not be used from libc,
322+
# but be used as an intrinsic, and codegen will generate a libc call from that intrinsic
323+
# *after* static linking would have thought it is all in there. In asm.js this is not an
324+
# issue as we do JS linking anyhow, and have asm.js-optimized versions of all the LLVM
325+
# intrinsics. But for wasm, we need a better solution. For now, make another archive
326+
# that gets included at the same time as compiler-rt.
327+
math_files = files_in_path(
328+
path_components=['system', 'lib', 'libc', 'musl', 'src', 'math'],
329+
filenames=['fmaxf.c', 'fminf.c', 'fmax.c', 'fmin.c'])
330+
string_files = files_in_path(
331+
path_components=['system', 'lib', 'libc', 'musl', 'src', 'string'],
332+
filenames=['memcpy.c', 'memset.c', 'memmove.c'])
333+
return create_wasm_rt_lib(libname, math_files + string_files)
267334

268335
# Setting this in the environment will avoid checking dependencies and make building big projects a little faster
269336
# 1 means include everything; otherwise it can be the name of a lib (libcxx, etc.)
@@ -411,7 +478,8 @@ def do_create():
411478
# Handle backend compiler_rt separately because it is not a bitcode system lib like the others.
412479
# Here, just ensure that it's in the cache.
413480
if shared.Settings.BINARYEN and shared.Settings.WASM_BACKEND:
414-
crt_file = shared.Cache.get('wasm_compiler_rt.a', lambda: create_wasm_compiler_rt('wasm_compiler_rt.a'), extension='a')
481+
shared.Cache.get('wasm_compiler_rt.a', lambda: create_wasm_compiler_rt('wasm_compiler_rt.a'), extension='a')
482+
shared.Cache.get('wasm_libc_rt.a', lambda: create_wasm_libc_rt('wasm_libc_rt.a'), extension='a')
415483

416484
for actual in ret:
417485
if os.path.basename(actual) == 'libcxxabi.bc':

0 commit comments

Comments
 (0)