Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wasm-only memset #5245

Closed
wants to merge 9 commits into from
45 changes: 25 additions & 20 deletions emcc.py
Expand Up @@ -1090,12 +1090,6 @@ def check(input_file):
if shared.Settings.WASM:
shared.Settings.BINARYEN = 1 # these are synonyms

# When only targeting wasm, the .asm.js file is not executable, so is treated as an intermediate build file that can be cleaned up.
if shared.Building.is_wasm_only():
asm_target = asm_target.replace('.asm.js', '.temp.asm.js')
if not DEBUG:
misc_temp_files.note(asm_target)

assert shared.Settings.TOTAL_MEMORY >= 16*1024*1024, 'TOTAL_MEMORY must be at least 16MB, was ' + str(shared.Settings.TOTAL_MEMORY)
if shared.Settings.BINARYEN:
assert shared.Settings.TOTAL_MEMORY % 65536 == 0, 'For wasm, TOTAL_MEMORY must be a multiple of 64KB, was ' + str(shared.Settings.TOTAL_MEMORY)
Expand Down Expand Up @@ -1147,16 +1141,6 @@ def check(input_file):
# * if we also supported js mem inits we'd have 4 modes
# * and js mem inits are useful for avoiding a side file, but the wasm module avoids that anyhow
options.memory_init_file = True
# async compilation requires wasm-only mode, and also not interpreting (the interpreter needs sync input)
if shared.Settings.BINARYEN_ASYNC_COMPILATION == 1 and shared.Building.is_wasm_only() and 'interpret' not in shared.Settings.BINARYEN_METHOD:
# async compilation requires a swappable module - we swap it in when it's ready
shared.Settings.SWAPPABLE_ASM_MODULE = 1
else:
# if not wasm-only, we can't do async compilation as the build can run in other
# modes than wasm (like asm.js) which may not support an async step
shared.Settings.BINARYEN_ASYNC_COMPILATION = 0
if 'BINARYEN_ASYNC_COMPILATION=1' in settings_changes:
logging.warning('BINARYEN_ASYNC_COMPILATION requested, but disabled since not in wasm-only mode')

# wasm outputs are only possible with a side wasm
if target.endswith(WASM_ENDINGS):
Expand Down Expand Up @@ -1217,7 +1201,28 @@ def check(input_file):
newargs.append('-disable-llvm-optzns')

if not shared.Settings.LEGALIZE_JS_FFI:
assert shared.Building.is_wasm_only(), 'LEGALIZE_JS_FFI incompatible with RUNNING_JS_OPTS and non-wasm BINARYEN_METHOD.'
assert shared.Settings.WASM_ONLY, 'LEGALIZE_JS_FFI incompatible with RUNNING_JS_OPTS and non-wasm BINARYEN_METHOD.'

if shared.Settings.BINARYEN:
# determine wasm-only mode, now that all settings are settled on
shared.Settings.WASM_ONLY = shared.Building.is_wasm_only()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, so we add a WASM_ONLY flag that we assert gets set when we unset LEGALIZE_JS_FFI, but then we clobber it with our autodetected shared.Building.is_wasm_only() regardless?

We've promoted WASM_ONLY to a Setting so it's available to the js compiler, not because it's something users should be setting. Because of that I think we should move this to before the assert, and just always have it autodetected. Maybe add a note to settings.js, saying we ignore this if you try to set it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

emcc.py order was a little wrong, thanks, fixed.

And clarified in settings.js what is internal use only.


# When only targeting wasm, the .asm.js file is not executable, so is treated as an intermediate build file that can be cleaned up.
if shared.Settings.WASM_ONLY:
asm_target = asm_target.replace('.asm.js', '.temp.asm.js')
if not DEBUG:
misc_temp_files.note(asm_target)

# async compilation requires wasm-only mode, and also not interpreting (the interpreter needs sync input)
if shared.Settings.BINARYEN_ASYNC_COMPILATION == 1 and shared.Settings.WASM_ONLY and 'interpret' not in shared.Settings.BINARYEN_METHOD:
# async compilation requires a swappable module - we swap it in when it's ready
shared.Settings.SWAPPABLE_ASM_MODULE = 1
else:
# if not wasm-only, we can't do async compilation as the build can run in other
# modes than wasm (like asm.js) which may not support an async step
shared.Settings.BINARYEN_ASYNC_COMPILATION = 0
if 'BINARYEN_ASYNC_COMPILATION=1' in settings_changes:
logging.warning('BINARYEN_ASYNC_COMPILATION requested, but disabled since not in wasm-only mode')

shared.Settings.EMSCRIPTEN_VERSION = shared.EMSCRIPTEN_VERSION
shared.Settings.OPT_LEVEL = options.opt_level
Expand Down Expand Up @@ -2207,7 +2212,7 @@ def do_binaryen(final, target, asm_target, options, memfile, wasm_binary_target,
if not shared.Settings.WASM_BACKEND:
if DEBUG:
# save the asm.js input
shutil.copyfile(asm_target, os.path.join(emscripten_temp_dir, os.path.basename(asm_target)))
shared.safe_copy(asm_target, os.path.join(emscripten_temp_dir, os.path.basename(asm_target)))
cmd = [os.path.join(binaryen_bin, 'asm2wasm'), asm_target, '--total-memory=' + str(shared.Settings.TOTAL_MEMORY)]
if shared.Settings.BINARYEN_TRAP_MODE == 'js':
cmd += ['--emit-jsified-potential-traps']
Expand Down Expand Up @@ -2240,7 +2245,7 @@ def do_binaryen(final, target, asm_target, options, memfile, wasm_binary_target,
cmd += ['--mem-max=' + str(shared.Settings.BINARYEN_MEM_MAX)]
if shared.Settings.LEGALIZE_JS_FFI != 1:
cmd += ['--no-legalize-javascript-ffi']
if shared.Building.is_wasm_only():
if shared.Settings.WASM_ONLY:
cmd += ['--wasm-only'] # this asm.js is code not intended to run as asm.js, it is only ever going to be wasm, an can contain special fastcomp-wasm support
if options.debug_level >= 2 or options.profiling_funcs:
cmd += ['-g']
Expand Down Expand Up @@ -2275,7 +2280,7 @@ def do_binaryen(final, target, asm_target, options, memfile, wasm_binary_target,
log_time('asm2wasm')
if shared.Settings.BINARYEN_PASSES:
shutil.move(wasm_binary_target, wasm_binary_target + '.pre')
cmd = [os.path.join(binaryen_bin, 'wasm-opt'), wasm_binary_target + '.pre', '-o', wasm_binary_target] + map(lambda p: '--' + p, shared.Settings.BINARYEN_PASSES.split(','))
cmd = [os.path.join(binaryen_bin, 'wasm-opt'), wasm_binary_target + '.pre', '-o', wasm_binary_target] + map(lambda p: ('--' + p) if p[0] != '-' else p, shared.Settings.BINARYEN_PASSES.split(','))
logging.debug('wasm-opt on BINARYEN_PASSES: ' + ' '.join(cmd))
subprocess.check_call(cmd)
if not wrote_wasm_text and 'interpret-s-expr' in shared.Settings.BINARYEN_METHOD:
Expand Down
34 changes: 34 additions & 0 deletions src/library.js
Expand Up @@ -823,8 +823,12 @@ LibraryManager.library = {
if ((num|0) >=
#if SIMD
196608
#else
#if WASM_ONLY
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pattern seems to come up a fair bit. Might be worth extending the preprocessor to handle something like

#if SIMD
...
#elif WASM_ONLY
...
#endif

Wouldn't belong to this PR but might be worth doing.

16384
#else
8192
#endif
#endif
) {
return _emscripten_memcpy_big(dest|0, src|0, num|0)|0;
Expand All @@ -849,6 +853,16 @@ LibraryManager.library = {
SIMD_Int32x4_store(HEAPU8, dest+16, SIMD_Int32x4_load(HEAPU8, src+16));
SIMD_Int32x4_store(HEAPU8, dest+32, SIMD_Int32x4_load(HEAPU8, src+32));
SIMD_Int32x4_store(HEAPU8, dest+48, SIMD_Int32x4_load(HEAPU8, src+48));
#else
#if WASM_ONLY
store8(dest, load8(src, 4), 4);
store8(dest + 8 | 0, load8(src + 8 | 0, 4), 4);
store8(dest + 16 | 0, load8(src + 16 | 0, 4), 4);
store8(dest + 24 | 0, load8(src + 24 | 0, 4), 4);
store8(dest + 32 | 0, load8(src + 32 | 0, 4), 4);
store8(dest + 40 | 0, load8(src + 40 | 0, 4), 4);
store8(dest + 48 | 0, load8(src + 48 | 0, 4), 4);
store8(dest + 56 | 0, load8(src + 56 | 0, 4), 4);
#else
{{{ makeSetValueAsm('dest', 0, makeGetValueAsm('src', 0, 'i32'), 'i32') }}};
{{{ makeSetValueAsm('dest', 4, makeGetValueAsm('src', 4, 'i32'), 'i32') }}};
Expand All @@ -866,6 +880,7 @@ LibraryManager.library = {
{{{ makeSetValueAsm('dest', 52, makeGetValueAsm('src', 52, 'i32'), 'i32') }}};
{{{ makeSetValueAsm('dest', 56, makeGetValueAsm('src', 56, 'i32'), 'i32') }}};
{{{ makeSetValueAsm('dest', 60, makeGetValueAsm('src', 60, 'i32'), 'i32') }}};
#endif
#endif
dest = (dest+64)|0;
src = (src+64)|0;
Expand Down Expand Up @@ -939,6 +954,10 @@ LibraryManager.library = {
var end = 0, aligned_end = 0, block_aligned_end = 0, value4 = 0;
#if SIMD
var value16 = SIMD_Int32x4(0,0,0,0);
#else
#if WASM_ONLY
var value8 = i64();
#endif
#endif
end = (ptr + num)|0;

Expand All @@ -954,6 +973,10 @@ LibraryManager.library = {
value4 = value | (value << 8) | (value << 16) | (value << 24);
#if SIMD
value16 = SIMD_Int32x4_splat(value4);
#else
#if WASM_ONLY
value8 = i64_or(i64_zext(value4), i64_shl(i64_zext(value4), i64(32)));
#endif
#endif

while((ptr|0) <= (block_aligned_end|0)) {
Expand All @@ -962,6 +985,16 @@ LibraryManager.library = {
SIMD_Int32x4_store(HEAPU8, ptr+16, value16);
SIMD_Int32x4_store(HEAPU8, ptr+32, value16);
SIMD_Int32x4_store(HEAPU8, ptr+48, value16);
#else
#if WASM_ONLY
store8(ptr , value8, 4);
store8(ptr + 8 | 0, value8, 4);
store8(ptr + 16 | 0, value8, 4);
store8(ptr + 24 | 0, value8, 4);
store8(ptr + 32 | 0, value8, 4);
store8(ptr + 40 | 0, value8, 4);
store8(ptr + 48 | 0, value8, 4);
store8(ptr + 56 | 0, value8, 4);
#else
{{{ makeSetValueAsm('ptr', 0, 'value4', 'i32') }}};
{{{ makeSetValueAsm('ptr', 4, 'value4', 'i32') }}};
Expand All @@ -979,6 +1012,7 @@ LibraryManager.library = {
{{{ makeSetValueAsm('ptr', 52, 'value4', 'i32') }}};
{{{ makeSetValueAsm('ptr', 56, 'value4', 'i32') }}};
{{{ makeSetValueAsm('ptr', 60, 'value4', 'i32') }}};
#endif
#endif
ptr = (ptr + 64)|0;
}
Expand Down
2 changes: 2 additions & 0 deletions src/settings.js
Expand Up @@ -736,6 +736,8 @@ var WASM_BACKEND = 0; // Whether to use the WebAssembly backend that is in devel
// You should not set this yourself, instead set EMCC_WASM_BACKEND=1 in the
// environment.

var WASM_ONLY = 0; // Whether we are only targeting wasm (i.e., there is no fallback to asm.js)

// Ports

var USE_SDL = 1; // Specify the SDL version that is being linked against.
Expand Down