summaryrefslogtreecommitdiff
path: root/emcc
diff options
context:
space:
mode:
Diffstat (limited to 'emcc')
-rwxr-xr-xemcc120
1 files changed, 75 insertions, 45 deletions
diff --git a/emcc b/emcc
index 8bfa0942..7460da61 100755
--- a/emcc
+++ b/emcc
@@ -146,7 +146,7 @@ Options that are modified or new in %s include:
This is the recommended setting when you want a
reasonably optimized build that is generated as
- quickly as possible (it is much faster than -O2).
+ quickly as possible (it builds much faster than -O2).
(Note: for details on the affects of different
opt levels, see apply_opt_level() in
@@ -158,20 +158,11 @@ Options that are modified or new in %s include:
time in return for the smallest and fastest
output.
- -O3 As -O2, plus dangerous optimizations that may
- break the generated code! This adds
+ -O3 As -O2, plus additional optimizations that can
+ take a significant amount of compilation time.
- -s FORCE_ALIGNED_MEMORY=1
- -s DOUBLE_MODE=0
- -s PRECISE_I64_MATH=0
- --closure 1
- --llvm-lto 3
-
- This is not recommended at all. A better idea
- is to try each of these separately on top of
- -O2 to see what works. See the wiki and
- src/settings.js (for the -s options) for more
- information.
+ For tips on optimizing your code, see
+ https://github.com/kripken/emscripten/wiki/Optimizing-Code
-s OPTION=VALUE JavaScript code generation option passed
into the emscripten compiler. For the
@@ -267,8 +258,7 @@ Options that are modified or new in %s include:
code size and may in some cases increase
runtime speed (although the opposite can also
occur). Note that it takes time to run, and
- may require some changes to the code. This
- is run by default in -O3.
+ may require some changes to the code.
In asm.js mode, closure will only be used on the
'shell' code around the compiled code (the
@@ -781,6 +771,14 @@ def filename_type_ending(filename):
suffix = filename_type_suffix(filename)
return '' if not suffix else ('.' + suffix)
+# Log out times for emcc stages
+log_time_last = time.time()
+def log_time(name):
+ global log_time_last
+ now = time.time()
+ logging.debug('emcc step "%s" took %.2f seconds' % (name, now - log_time_last))
+ log_time_last = now
+
try:
call = CXX if use_cxx else CC
@@ -1029,9 +1027,7 @@ try:
if js_opts is None: js_opts = opt_level >= 2
if llvm_opts is None: llvm_opts = LLVM_OPT_LEVEL[opt_level]
- if llvm_lto is None and opt_level >= 3: llvm_lto = 3
if opt_level == 0: debug_level = 4
- if closure is None and opt_level == 3: closure = True
if llvm_lto is None and bind:
logging.debug('running lto for embind') # XXX this is a workaround for a pointer issue
@@ -1196,7 +1192,6 @@ try:
shared.Settings.ASM_JS = 1
assert shared.Settings.ALLOW_MEMORY_GROWTH == 0, 'memory growth not supported in fastcomp yet'
assert shared.Settings.UNALIGNED_MEMORY == 0, 'forced unaligned memory not supported in fastcomp'
- assert shared.Settings.SAFE_HEAP == 0, 'safe heap not supported in fastcomp yet'
assert shared.Settings.CHECK_HEAP_ALIGN == 0, 'check heap align not supported in fastcomp yet'
assert shared.Settings.SAFE_DYNCALLS == 0, 'safe dyncalls not supported in fastcomp'
assert shared.Settings.RESERVED_FUNCTION_POINTERS == 0, 'reserved function pointers not supported in fastcomp'
@@ -1230,6 +1225,13 @@ try:
shared.Settings.CORRECT_OVERFLOWS = 1
assert not shared.Settings.PGO, 'cannot run PGO in ASM_JS mode'
+ if shared.Settings.SAFE_HEAP and not js_opts:
+ logging.warning('asm.js+SAFE_HEAP requires js opts to be run (-O1 or above by default)')
+
+ if shared.Settings.ALLOW_MEMORY_GROWTH:
+ logging.error('Cannot enable ALLOW_MEMORY_GROWTH with asm.js, build with -s ASM_JS=0 if you need a growable heap');
+ sys.exit(1);
+
if shared.Settings.CORRECT_SIGNS >= 2 or shared.Settings.CORRECT_OVERFLOWS >= 2 or shared.Settings.CORRECT_ROUNDINGS >= 2:
debug_level = 4 # must keep debug info to do line-by-line operations
@@ -1295,6 +1297,8 @@ try:
temp_files = []
+ log_time('parse arguments and setup')
+
# First, generate LLVM bitcode. For each input file, we get base.o with bitcode
for input_file in input_files:
file_ending = filename_type_ending(input_file)
@@ -1334,6 +1338,8 @@ try:
logging.error(input_file + ': Unknown file suffix when compiling to LLVM bitcode!')
sys.exit(1)
+ log_time('bitcodeize inputs')
+
if not LEAVE_INPUTS_RAW:
assert len(temp_files) == len(input_files)
@@ -1380,6 +1386,8 @@ try:
shared.Building.link(temp_files, specified_target)
exit(0)
+ log_time('bitcodeize inputs')
+
## Continue on to create JavaScript
logging.debug('will generate JavaScript')
@@ -1440,15 +1448,6 @@ try:
libc_files = [
'dlmalloc.c',
os.path.join('libcxx', 'new.cpp'),
- os.path.join('libc', 'stdlib', 'getopt_long.c'),
- os.path.join('libc', 'gen', 'err.c'),
- os.path.join('libc', 'gen', 'errx.c'),
- os.path.join('libc', 'gen', 'warn.c'),
- os.path.join('libc', 'gen', 'warnx.c'),
- os.path.join('libc', 'gen', 'verr.c'),
- os.path.join('libc', 'gen', 'verrx.c'),
- os.path.join('libc', 'gen', 'vwarn.c'),
- os.path.join('libc', 'gen', 'vwarnx.c'),
]
musl_files = [
['internal', [
@@ -1462,6 +1461,7 @@ try:
['stdio', [
'__overflow.c',
'__toread.c',
+ '__towrite.c',
'__uflow.c',
]],
['stdlib', [
@@ -1511,6 +1511,9 @@ try:
['internal', [
'intscan.c',
]],
+ ['legacy', [
+ 'err.c',
+ ]],
['locale', [
'iconv.c',
'iswalnum_l.c',
@@ -1541,7 +1544,9 @@ try:
'wctype_l.c',
]],
['math', [
+ '__cos.c',
'__cosdf.c',
+ '__sin.c',
'__sindf.c',
'ilogb.c',
'ilogbf.c',
@@ -1563,6 +1568,10 @@ try:
'tgammaf.c',
'tgammal.c'
]],
+ ['misc', [
+ 'getopt.c',
+ 'getopt_long.c',
+ ]],
['multibyte', [
'btowc.c',
'mblen.c',
@@ -1581,6 +1590,7 @@ try:
'wctomb.c',
]],
['regex', [
+ 'fnmatch.c',
'regcomp.c',
'regerror.c',
'regexec.c',
@@ -1594,6 +1604,7 @@ try:
'vwprintf.c',
'wprintf.c',
'fputwc.c',
+ 'fputws.c',
]],
['stdlib', [
'ecvt.c',
@@ -1750,15 +1761,14 @@ try:
libfile = shared.Cache.get(name, create)
extra_files_to_link.append(libfile)
+ log_time('calculate system libraries')
+
# First, combine the bitcode files if there are several. We must also link if we have a singleton .a
if len(input_files) + len(extra_files_to_link) > 1 or \
(not LEAVE_INPUTS_RAW and not (suffix(temp_files[0]) in BITCODE_ENDINGS or suffix(temp_files[0]) in DYNAMICLIB_ENDINGS) and shared.Building.is_ar(temp_files[0])):
linker_inputs = temp_files + extra_files_to_link
logging.debug('linking: ' + str(linker_inputs))
- t0 = time.time()
shared.Building.link(linker_inputs, in_temp(target_basename + '.bc'), force_archive_contents = len(filter(lambda temp: not temp.endswith(STATICLIB_ENDINGS), temp_files)) == 0)
- t1 = time.time()
- logging.debug(' linking took %.2f seconds' % (t1 - t0))
final = in_temp(target_basename + '.bc')
else:
if not LEAVE_INPUTS_RAW:
@@ -1768,19 +1778,16 @@ try:
final = in_temp(input_files[0])
shutil.copyfile(input_files[0], final)
+ log_time('link')
+
if DEBUG:
logging.debug('saving intermediate processing steps to %s' % shared.EMSCRIPTEN_TEMP_DIR)
intermediate_counter = 0
- intermediate_time = None
def save_intermediate(name=None, suffix='js'):
- global intermediate_counter, intermediate_time
+ global intermediate_counter
shutil.copyfile(final, os.path.join(shared.EMSCRIPTEN_TEMP_DIR, 'emcc-%d%s.%s' % (intermediate_counter, '' if name is None else '-' + name, suffix)))
intermediate_counter += 1
- now = time.time()
- if intermediate_time:
- logging.debug(' step took %.2f seconds' % (now - intermediate_time))
- intermediate_time = now
if not LEAVE_INPUTS_RAW: save_intermediate('basebc', 'bc')
@@ -1841,6 +1848,8 @@ try:
final += '.adsimp.bc'
if DEBUG: save_intermediate('adsimp', 'bc')
+ log_time('post-link')
+
# Emscripten
logging.debug('LLVM => JS')
extra_args = [] if not js_libraries else ['--libraries', ','.join(map(os.path.abspath, js_libraries))]
@@ -1848,6 +1857,8 @@ try:
final = shared.Building.emscripten(final, append_ext=False, extra_args=extra_args)
if DEBUG: save_intermediate('original')
+ log_time('emscript (llvm=>js)')
+
# Embed and preload files
if len(preload_files) + len(embed_files) > 0:
logging.debug('setting up files')
@@ -1908,9 +1919,7 @@ try:
shared.try_delete(memfile)
def repl(m):
# handle chunking of the memory initializer
- s = re.sub('[\[\]\n\(\)\. ]', '', m.groups(0)[0])
- s = s.replace('concat', ',')
- if s[-1] == ',': s = s[:-1]
+ s = m.groups(0)[0]
open(memfile, 'wb').write(''.join(map(lambda x: chr(int(x or '0')), s.split(','))))
if DEBUG:
# Copy into temp dir as well, so can be run there too
@@ -1921,6 +1930,7 @@ try:
src = re.sub(shared.JS.memory_initializer_pattern, repl, open(final).read(), count=1)
open(final + '.mem.js', 'w').write(src)
final += '.mem.js'
+ src = None
js_transform_tempfiles[-1] = final # simple text substitution preserves comment line number mappings
if DEBUG:
if os.path.exists(memfile):
@@ -1928,6 +1938,17 @@ try:
logging.debug('wrote memory initialization to %s' % memfile)
else:
logging.debug('did not see memory initialization')
+ elif shared.Settings.USE_TYPED_ARRAYS == 2 and not shared.Settings.MAIN_MODULE and not shared.Settings.SIDE_MODULE:
+ # not writing a binary init, but we can at least optimize them by splitting them up
+ src = open(final).read()
+ src = shared.JS.optimize_initializer(src)
+ if src is not None:
+ logging.debug('optimizing memory initialization')
+ open(final + '.mem.js', 'w').write(src)
+ final += '.mem.js'
+ src = None
+
+ log_time('source transforms')
# It is useful to run several js optimizer passes together, to save on unneeded unparsing/reparsing
js_optimizer_queue = []
@@ -1989,15 +2010,20 @@ try:
if DEBUG: save_intermediate('closure')
if js_opts:
+ if shared.Settings.ASM_JS and shared.Settings.SAFE_HEAP: js_optimizer_queue += ['safeHeap']
+
if shared.Settings.OUTLINING_LIMIT > 0 and shared.Settings.ASM_JS:
js_optimizer_queue += ['outline']
js_optimizer_extra_info['sizeToOutline'] = shared.Settings.OUTLINING_LIMIT
if (not closure or shared.Settings.ASM_JS) and shared.Settings.RELOOP and debug_level < 3:
- js_optimizer_queue += ['registerize']
+ if shared.Settings.ASM_JS and opt_level >= 3 and shared.Settings.OUTLINING_LIMIT == 0:
+ js_optimizer_queue += ['registerizeHarder']
+ else:
+ js_optimizer_queue += ['registerize']
if opt_level > 0:
- if debug_level < 2 and shared.Settings.ASM_JS: js_optimizer_queue = map(lambda p: p if p != 'registerize' else 'registerizeAndMinify', js_optimizer_queue)
+ if debug_level < 2 and shared.Settings.ASM_JS: js_optimizer_queue += ['minifyNames']
if debug_level == 0: js_optimizer_queue += ['minifyWhitespace']
if closure and shared.Settings.ASM_JS:
@@ -2007,10 +2033,12 @@ try:
flush_js_optimizer_queue()
+ log_time('js opts')
+
# Remove some trivial whitespace # TODO: do not run when compress has already been done on all parts of the code
- src = open(final).read()
- src = re.sub(r'\n+[ \n]*\n+', '\n', src)
- open(final, 'w').write(src)
+ #src = open(final).read()
+ #src = re.sub(r'\n+[ \n]*\n+', '\n', src)
+ #open(final, 'w').write(src)
def generate_source_map(map_file_base_name, offset=0):
jsrun.run_js(shared.path_from_root('tools', 'source-maps', 'sourcemapper.js'),
@@ -2113,6 +2141,8 @@ try:
# copy final JS to output
shutil.move(final, target)
+ log_time('final emitting')
+
if DEBUG: logging.debug('total time: %.2f seconds' % (time.time() - start_time))
finally: