diff options
Diffstat (limited to 'tools/shared.py')
-rw-r--r-- | tools/shared.py | 70 |
1 files changed, 59 insertions, 11 deletions
diff --git a/tools/shared.py b/tools/shared.py index aee7de27..6f6fa0d6 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -1,4 +1,4 @@ -import shutil, time, os, sys, json, tempfile +import shutil, time, os, sys, json, tempfile, copy from subprocess import Popen, PIPE, STDOUT __rootpath__ = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) @@ -298,6 +298,7 @@ class Settings: # Load the JS defaults into python settings = open(path_from_root('src', 'settings.js')).read().replace('var ', 'Settings.').replace('//', '#') exec settings in globals() + Settings.defaults = copy.copy(Settings.__dict__) # save the defaults for later comparisons # Apply additional settings. First -O, then -s for i in range(len(args)): @@ -315,7 +316,10 @@ class Settings: ret = [] for key, value in Settings.__dict__.iteritems(): if key == key.upper(): # this is a hack. all of our settings are ALL_CAPS, python internals are not - ret += ['-s', key + '=' + json.dumps(value)] + jsoned = json.dumps(value) + # Only add if it actually modifies a default + if jsoned != json.dumps(Settings.defaults[key]): + ret += ['-s', key + '=' + jsoned] return ret @classmethod @@ -378,19 +382,21 @@ class Building: Popen(args, stdout=stdout, stderr=stderr, env=env).communicate()[0] @staticmethod - def build_library(name, build_dir, output_dir, generated_libs, configure=['./configure'], configure_args=[], make=['make'], make_args=['-j', '2'], cache=None, cache_name=None, copy_project=False, env_init={}): + def build_library(name, build_dir, output_dir, generated_libs, configure=['./configure'], configure_args=[], make=['make'], make_args=['-j', '2'], cache=None, cache_name=None, copy_project=False, env_init={}, source_dir=None): ''' Build a library into a .bc file. We build the .bc file once and cache it for all our tests. (We cache in memory since the test directory is destroyed and recreated for each test. Note that we cache separately - for different compilers) ''' + for different compilers). + This cache is just during the test runner. There is a different concept of caching as well, see |Cache|. ''' if type(generated_libs) is not list: generated_libs = [generated_libs] + if source_dir is None: source_dir = path_from_root('tests', name) temp_dir = build_dir if copy_project: project_dir = os.path.join(temp_dir, name) if os.path.exists(project_dir): shutil.rmtree(project_dir) - shutil.copytree(path_from_root('tests', name), project_dir) # Useful in debugging sometimes to comment this out, and two lines above + shutil.copytree(source_dir, project_dir) # Useful in debugging sometimes to comment this out, and two lines above else: project_dir = build_dir try: @@ -437,10 +443,14 @@ class Building: output = Popen(['python', DFE, filename + '.o.ll.orig', filename + '.o.ll'], stdout=PIPE).communicate()[0] assert os.path.exists(filename + '.o.ll'), 'Failed to run ll optimizations' - # Optional LLVM optimizations + # LLVM optimizations + # @param opt Either an integer, in which case it is the optimization level (-O1, -O2, etc.), or a list of raw + # optimization passes passed to llvm opt @staticmethod - def llvm_opt(filename, level, safe=True): - output = Popen([LLVM_OPT, filename] + Building.pick_llvm_opts(level, safe) + ['-o=' + filename + '.opt.bc'], stdout=PIPE).communicate()[0] + def llvm_opt(filename, opts, safe=True): + if type(opts) is int: + opts = Building.pick_llvm_opts(opts, safe) + output = Popen([LLVM_OPT, filename] + opts + ['-o=' + filename + '.opt.bc'], stdout=PIPE).communicate()[0] assert os.path.exists(filename + '.opt.bc'), 'Failed to run llvm optimizations: ' + output shutil.move(filename + '.opt.bc', filename) @@ -488,13 +498,19 @@ class Building: class ret: defs = [] undefs = [] + commons = [] for line in output.split('\n'): if len(line) == 0: continue status, symbol = filter(lambda seg: len(seg) > 0, line.split(' ')) if status == 'U': ret.undefs.append(symbol) - else: + elif status != 'C': ret.defs.append(symbol) + else: + ret.commons.append(symbol) + ret.defs = set(ret.defs) + ret.undefs = set(ret.undefs) + ret.commons = set(ret.commons) return ret @staticmethod @@ -525,6 +541,10 @@ class Building: (which we do in do_ll_opts) - but even there we have issues (even in TA2) with instruction combining into i64s. In any case, the handpicked ones here should be safe and portable. They are also tuned for things that look useful. + + An easy way to see LLVM's standard list of passes is + + llvm-as < /dev/null | opt -std-compile-opts -disable-output -debug-pass=Arguments ''' opts = [] if optimization_level > 0: @@ -544,6 +564,9 @@ class Building: opts.append('-tbaa') opts.append('-basicaa') # makes fannkuch slow but primes fast + if not Settings.BUILD_AS_SHARED_LIB and not Settings.LINKABLE: + opts.append('-internalize') + opts.append('-globalopt') opts.append('-ipsccp') opts.append('-deadargelim') @@ -601,7 +624,8 @@ class Building: opts.append('-strip-dead-prototypes') - if optimization_level > 2: opts.append('-globaldce') + if not Settings.BUILD_AS_SHARED_LIB and not Settings.LINKABLE: + opts.append('-globaldce') if optimization_level > 1: opts.append('-constmerge') @@ -663,7 +687,7 @@ class Building: # if the file doesn't exist or doesn't have valid symbols, it isn't bitcode try: defs = Building.llvm_nm(filename, stderr=PIPE) - assert len(defs.defs + defs.undefs) > 0 + assert len(defs.defs) + len(defs.undefs) + len(defs.commons) > 0 except: return False # look for magic signature @@ -677,3 +701,27 @@ class Building: return False +# Permanent cache for dlmalloc and stdlibc++ +class Cache: + dirname = os.path.expanduser(os.path.join('~', '.emscripten_cache')) + + @staticmethod + def erase(): + try: + shutil.rmtree(Cache.dirname) + except: + pass + + # Request a cached file. If it isn't in the cache, it will be created with + # the given creator function + @staticmethod + def get(shortname, creator): + if not shortname.endswith('.bc'): shortname += '.bc' + cachename = os.path.join(Cache.dirname, shortname) + if os.path.exists(cachename): + return cachename + if not os.path.exists(Cache.dirname): + os.makedirs(Cache.dirname) + shutil.copyfile(creator(), cachename) + return cachename + |