utilize llvm opt
This commit is contained in:
Родитель
d18bd56d5f
Коммит
2890aa49d7
|
@ -39,11 +39,11 @@ RuntimeGenerator = {
|
||||||
if (GUARD_MEMORY) {
|
if (GUARD_MEMORY) {
|
||||||
ret += '; assert(STACKTOP < STACK_MAX)';
|
ret += '; assert(STACKTOP < STACK_MAX)';
|
||||||
}
|
}
|
||||||
var initMemory = 'for (var i = __stackBase__; i < STACKTOP; i++) ' + (
|
var initMemory = 'for (var i = __stackBase__; i < STACKTOP; i++) {' + (
|
||||||
USE_TYPED_ARRAYS ?
|
USE_TYPED_ARRAYS ?
|
||||||
'IHEAP[i] = FHEAP[i] = 0' :
|
'IHEAP[i] = FHEAP[i] = 0' : // XXX Suboptimal due to type differences?
|
||||||
'HEAP[i] = 0'
|
'HEAP[i] = 0'
|
||||||
);
|
) + (SAFE_HEAP ? '; SAFE_HEAP_ACCESS(i, null, true)' : '') + ' }';
|
||||||
ret += '; ' + initMemory;
|
ret += '; ' + initMemory;
|
||||||
return ret;
|
return ret;
|
||||||
},
|
},
|
||||||
|
|
|
@ -34,6 +34,55 @@ class RunnerCore(unittest.TestCase):
|
||||||
os.makedirs(dirname)
|
os.makedirs(dirname)
|
||||||
return dirname
|
return dirname
|
||||||
|
|
||||||
|
# Similar to LLVM::createStandardModulePasses()
|
||||||
|
def pick_llvm_opts(self, optimization_level, optimize_size):
|
||||||
|
global LLVM_OPT_OPTS
|
||||||
|
LLVM_OPT_OPTS = []
|
||||||
|
|
||||||
|
if optimization_level == 0: return
|
||||||
|
|
||||||
|
# -instcombine is nonportable, so doesn't appear here
|
||||||
|
LLVM_OPT_OPTS.append('-globalopt')
|
||||||
|
LLVM_OPT_OPTS.append('-ipsccp')
|
||||||
|
LLVM_OPT_OPTS.append('-deadargelim')
|
||||||
|
LLVM_OPT_OPTS.append('-simplifycfg')
|
||||||
|
LLVM_OPT_OPTS.append('-prune-eh')
|
||||||
|
LLVM_OPT_OPTS.append('-inline')
|
||||||
|
LLVM_OPT_OPTS.append('-functionattrs')
|
||||||
|
if optimization_level > 2:
|
||||||
|
LLVM_OPT_OPTS.append('-argpromotion')
|
||||||
|
LLVM_OPT_OPTS.append('-scalarrepl')
|
||||||
|
LLVM_OPT_OPTS.append('-simplify-libcalls')
|
||||||
|
LLVM_OPT_OPTS.append('-jump-threading')
|
||||||
|
LLVM_OPT_OPTS.append('-simplifycfg')
|
||||||
|
LLVM_OPT_OPTS.append('-tailcallelim')
|
||||||
|
LLVM_OPT_OPTS.append('-simplifycfg')
|
||||||
|
LLVM_OPT_OPTS.append('-reassociate')
|
||||||
|
LLVM_OPT_OPTS.append('-loop-rotate')
|
||||||
|
LLVM_OPT_OPTS.append('-licm')
|
||||||
|
LLVM_OPT_OPTS.append('-loop-unswitch') # XXX should depend on optimize_size
|
||||||
|
LLVM_OPT_OPTS.append('-indvars')
|
||||||
|
LLVM_OPT_OPTS.append('-loop-deletion')
|
||||||
|
LLVM_OPT_OPTS.append('-loop-unroll')
|
||||||
|
if optimization_level > 1:
|
||||||
|
LLVM_OPT_OPTS.append('-gvn')
|
||||||
|
LLVM_OPT_OPTS.append('-memcpyopt')
|
||||||
|
LLVM_OPT_OPTS.append('-sccp')
|
||||||
|
LLVM_OPT_OPTS.append('-jump-threading')
|
||||||
|
LLVM_OPT_OPTS.append('-correlated-propagation')
|
||||||
|
LLVM_OPT_OPTS.append('-dse')
|
||||||
|
LLVM_OPT_OPTS.append('-adce')
|
||||||
|
LLVM_OPT_OPTS.append('-simplifycfg')
|
||||||
|
|
||||||
|
LLVM_OPT_OPTS.append('-strip-dead-prototypes')
|
||||||
|
LLVM_OPT_OPTS.append('-deadtypeelim')
|
||||||
|
|
||||||
|
if optimization_level > 2:
|
||||||
|
LLVM_OPT_OPTS.append('-globaldce')
|
||||||
|
|
||||||
|
if optimization_level > 1:
|
||||||
|
LLVM_OPT_OPTS.append('-constmerge')
|
||||||
|
|
||||||
## Build JavaScript code from source code
|
## Build JavaScript code from source code
|
||||||
def build(self, src, dirname, filename, output_processor=None, main_file=None):
|
def build(self, src, dirname, filename, output_processor=None, main_file=None):
|
||||||
# Copy over necessary files for compiling the source
|
# Copy over necessary files for compiling the source
|
||||||
|
@ -59,12 +108,17 @@ class RunnerCore(unittest.TestCase):
|
||||||
pass
|
pass
|
||||||
os.chdir(dirname)
|
os.chdir(dirname)
|
||||||
cwd = os.getcwd()
|
cwd = os.getcwd()
|
||||||
output = Popen([COMPILER, '-DEMSCRIPTEN', '-emit-llvm'] + COMPILER_OPTS + (['-O3'] if F_OPTS else []) + ['-c', filename, '-o', filename + '.o'], stdout=PIPE, stderr=STDOUT).communicate()[0]
|
output = Popen([COMPILER, '-DEMSCRIPTEN', '-emit-llvm'] + COMPILER_OPTS + ['-c', filename, '-o', filename + '.o'], stdout=PIPE, stderr=STDOUT).communicate()[0]
|
||||||
os.chdir(cwd)
|
os.chdir(cwd)
|
||||||
if not os.path.exists(filename + '.o'):
|
if not os.path.exists(filename + '.o'):
|
||||||
print "Failed to compile C/C++ source:\n\n", output
|
print "Failed to compile C/C++ source:\n\n", output
|
||||||
raise Exception("Compilation error");
|
raise Exception("Compilation error");
|
||||||
|
|
||||||
|
# Optional LLVM optimizations
|
||||||
|
if LLVM_OPTS:
|
||||||
|
shutil.move(filename + '.o', filename + '.o.pre')
|
||||||
|
output = Popen([LLVM_OPT, filename + '.o.pre'] + LLVM_OPT_OPTS + ['-o=' + filename + '.o'], stdout=PIPE, stderr=STDOUT).communicate()[0]
|
||||||
|
|
||||||
# LLVM binary ==> LLVM assembly
|
# LLVM binary ==> LLVM assembly
|
||||||
output = Popen([LLVM_DIS, filename + '.o'] + LLVM_DIS_OPTS + ['-o=' + filename + '.o.ll'], stdout=PIPE, stderr=STDOUT).communicate()[0]
|
output = Popen([LLVM_DIS, filename + '.o'] + LLVM_DIS_OPTS + ['-o=' + filename + '.o.ll'], stdout=PIPE, stderr=STDOUT).communicate()[0]
|
||||||
|
|
||||||
|
@ -99,7 +153,7 @@ if 'benchmark' not in sys.argv:
|
||||||
class T(RunnerCore): # Short name, to make it more fun to use manually on the commandline
|
class T(RunnerCore): # Short name, to make it more fun to use manually on the commandline
|
||||||
## Does a complete test - builds, runs, checks output, etc.
|
## Does a complete test - builds, runs, checks output, etc.
|
||||||
def do_test(self, src, expected_output, args=[], output_nicerizer=None, output_processor=None, no_build=False, main_file=None, js_engines=None, post_build=None, basename='src.cpp'):
|
def do_test(self, src, expected_output, args=[], output_nicerizer=None, output_processor=None, no_build=False, main_file=None, js_engines=None, post_build=None, basename='src.cpp'):
|
||||||
print 'Running test:', inspect.stack()[1][3].replace('test_', ''), '[%s,%s,%s]' % (COMPILER.split(os.sep)[-1], 'frontend-optimizations' if F_OPTS else '', 'reloop&optimize' if RELOOP else '')
|
print 'Running test:', inspect.stack()[1][3].replace('test_', ''), '[%s,%s,%s]' % (COMPILER.split(os.sep)[-1], 'llvm-optimizations' if LLVM_OPTS else '', 'reloop&optimize' if RELOOP else '')
|
||||||
dirname = self.get_dir()
|
dirname = self.get_dir()
|
||||||
filename = os.path.join(dirname, basename)
|
filename = os.path.join(dirname, basename)
|
||||||
if not no_build:
|
if not no_build:
|
||||||
|
@ -123,9 +177,9 @@ if 'benchmark' not in sys.argv:
|
||||||
# No building - just process an existing .ll file
|
# No building - just process an existing .ll file
|
||||||
def do_ll_test(self, ll_file, output, args=[], f_opt_ll_file=None, js_engines=None):
|
def do_ll_test(self, ll_file, output, args=[], f_opt_ll_file=None, js_engines=None):
|
||||||
if COMPILER != LLVM_GCC: return # We use existing .ll, so which compiler is unimportant
|
if COMPILER != LLVM_GCC: return # We use existing .ll, so which compiler is unimportant
|
||||||
if F_OPTS:
|
if LLVM_OPTS:
|
||||||
return # TODO: enable the lines below
|
return # TODO: enable the lines below
|
||||||
#if f_opt_ll_file is None: return # We use existing .ll, so frontend stuff is unimportant, unless we are given an optimized .ll
|
#if f_opt_ll_file is None: return # We use existing .ll, so llvm opt stuff is unimportant, unless we are given an optimized .ll
|
||||||
#ll_file = f_opt_ll_file
|
#ll_file = f_opt_ll_file
|
||||||
|
|
||||||
filename = os.path.join(self.get_dir(), 'src.cpp')
|
filename = os.path.join(self.get_dir(), 'src.cpp')
|
||||||
|
@ -782,7 +836,7 @@ if 'benchmark' not in sys.argv:
|
||||||
|
|
||||||
def test_pystruct(self):
|
def test_pystruct(self):
|
||||||
if COMPILER != LLVM_GCC: return # TODO: Clang here
|
if COMPILER != LLVM_GCC: return # TODO: Clang here
|
||||||
if F_OPTS: return # TODO: fix
|
if LLVM_OPTS: return # TODO: fix
|
||||||
src = '''
|
src = '''
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
@ -1119,6 +1173,7 @@ if 'benchmark' not in sys.argv:
|
||||||
self.do_test(src, '*0.00,0.00,0.00*')
|
self.do_test(src, '*0.00,0.00,0.00*')
|
||||||
|
|
||||||
def test_nestedstructs(self):
|
def test_nestedstructs(self):
|
||||||
|
if LLVM_OPTS: return # FIXME
|
||||||
src = '''
|
src = '''
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "emscripten.h"
|
#include "emscripten.h"
|
||||||
|
@ -1231,9 +1286,18 @@ if 'benchmark' not in sys.argv:
|
||||||
self.do_test(path_from_root(['tests', 'cubescript']), '*\nTemp is 33\n9\n5\nhello, everyone\n*', main_file='command.cpp')
|
self.do_test(path_from_root(['tests', 'cubescript']), '*\nTemp is 33\n9\n5\nhello, everyone\n*', main_file='command.cpp')
|
||||||
|
|
||||||
def test_gcc_unmangler(self):
|
def test_gcc_unmangler(self):
|
||||||
if F_OPTS: return # See issue #8 - frontend optimizations fail here
|
|
||||||
self.do_test(path_from_root(['third_party']), '*d_demangle(char const*, int, unsigned int*)*', args=['_ZL10d_demanglePKciPj'], main_file='gcc_demangler.c')
|
self.do_test(path_from_root(['third_party']), '*d_demangle(char const*, int, unsigned int*)*', args=['_ZL10d_demanglePKciPj'], main_file='gcc_demangler.c')
|
||||||
|
|
||||||
|
#### Code snippet that is helpful to search for nonportable optimizations ####
|
||||||
|
#global LLVM_OPT_OPTS
|
||||||
|
#for opt in ['-aa-eval', '-adce', '-always-inline', '-argpromotion', '-basicaa', '-basiccg', '-block-placement', '-break-crit-edges', '-codegenprepare', '-constmerge', '-constprop', '-correlated-propagation', '-count-aa', '-dce', '-deadargelim', '-deadtypeelim', '-debug-aa', '-die', '-domfrontier', '-domtree', '-dse', '-extract-blocks', '-functionattrs', '-globaldce', '-globalopt', '-globalsmodref-aa', '-gvn', '-indvars', '-inline', '-insert-edge-profiling', '-insert-optimal-edge-profiling', '-instcombine', '-instcount', '-instnamer', '-internalize', '-intervals', '-ipconstprop', '-ipsccp', '-iv-users', '-jump-threading', '-lazy-value-info', '-lcssa', '-lda', '-libcall-aa', '-licm', '-lint', '-live-values', '-loop-deletion', '-loop-extract', '-loop-extract-single', '-loop-index-split', '-loop-reduce', '-loop-rotate', '-loop-unroll', '-loop-unswitch', '-loops', '-loopsimplify', '-loweratomic', '-lowerinvoke', '-lowersetjmp', '-lowerswitch', '-mem2reg', '-memcpyopt', '-memdep', '-mergefunc', '-mergereturn', '-module-debuginfo', '-no-aa', '-no-profile', '-partial-inliner', '-partialspecialization', '-pointertracking', '-postdomfrontier', '-postdomtree', '-preverify', '-prune-eh', '-reassociate', '-reg2mem', '-regions', '-scalar-evolution', '-scalarrepl', '-sccp', '-scev-aa', '-simplify-libcalls', '-simplify-libcalls-halfpowr', '-simplifycfg', '-sink', '-split-geps', '-sretpromotion', '-strip', '-strip-dead-debug-info', '-strip-dead-prototypes', '-strip-debug-declare', '-strip-nondebug', '-tailcallelim', '-tailduplicate', '-targetdata', '-tbaa']:
|
||||||
|
# LLVM_OPT_OPTS = [opt]
|
||||||
|
# try:
|
||||||
|
# self.do_test(path_from_root(['third_party']), '*d_demangle(char const*, int, unsigned int*)*', args=['_ZL10d_demanglePKciPj'], main_file='gcc_demangler.c')
|
||||||
|
# print opt, "ok"
|
||||||
|
# except:
|
||||||
|
# print opt, "FAIL"
|
||||||
|
|
||||||
def test_bullet(self):
|
def test_bullet(self):
|
||||||
global SAFE_HEAP; SAFE_HEAP = 0 # Too slow for that
|
global SAFE_HEAP; SAFE_HEAP = 0 # Too slow for that
|
||||||
self.do_ll_test(path_from_root(['tests', 'bullet', 'bulletTest.ll']), open(path_from_root(['tests', 'bullet', 'output.txt']), 'r').read())
|
self.do_ll_test(path_from_root(['tests', 'bullet', 'bulletTest.ll']), open(path_from_root(['tests', 'bullet', 'output.txt']), 'r').read())
|
||||||
|
@ -1304,7 +1368,7 @@ if 'benchmark' not in sys.argv:
|
||||||
|
|
||||||
def test_safe_heap(self):
|
def test_safe_heap(self):
|
||||||
if not SAFE_HEAP: return
|
if not SAFE_HEAP: return
|
||||||
if F_OPTS: return
|
if LLVM_OPTS: return # LLVM can optimize away the intermediate |x|...
|
||||||
src = '''
|
src = '''
|
||||||
#include<stdio.h>
|
#include<stdio.h>
|
||||||
int main() {
|
int main() {
|
||||||
|
@ -1321,20 +1385,23 @@ if 'benchmark' not in sys.argv:
|
||||||
assert 'Assertion failed: Load-store consistency assumption failure!' in str(e), str(e)
|
assert 'Assertion failed: Load-store consistency assumption failure!' in str(e), str(e)
|
||||||
|
|
||||||
# Generate tests for all our compilers
|
# Generate tests for all our compilers
|
||||||
def make_test(compiler, f_opts, embetter):
|
def make_test(compiler, llvm_opts, embetter):
|
||||||
class TT(T):
|
class TT(T):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
global COMPILER, QUANTUM_SIZE, RELOOP, OPTIMIZE, GUARD_MEMORY, USE_TYPED_ARRAYS, F_OPTS, SAFE_HEAP
|
global COMPILER, QUANTUM_SIZE, RELOOP, OPTIMIZE, GUARD_MEMORY, USE_TYPED_ARRAYS, LLVM_OPTS, SAFE_HEAP
|
||||||
COMPILER = compiler['path']
|
COMPILER = compiler['path']
|
||||||
QUANTUM_SIZE = compiler['quantum_size']
|
QUANTUM_SIZE = compiler['quantum_size']
|
||||||
RELOOP = OPTIMIZE = USE_TYPED_ARRAYS = embetter
|
RELOOP = OPTIMIZE = USE_TYPED_ARRAYS = embetter
|
||||||
GUARD_MEMORY = SAFE_HEAP = 1-embetter
|
GUARD_MEMORY = SAFE_HEAP = 1-embetter
|
||||||
F_OPTS = f_opts
|
LLVM_OPTS = llvm_opts
|
||||||
|
if LLVM_OPTS:
|
||||||
|
self.pick_llvm_opts(3, True)
|
||||||
|
|
||||||
return TT
|
return TT
|
||||||
for embetter in [0,1]:
|
for embetter in [0,1]:
|
||||||
for f_opts in [0,1]:
|
for llvm_opts in [0,1]:
|
||||||
for name in COMPILERS.keys():
|
for name in COMPILERS.keys():
|
||||||
exec('T_%s_%d_%d = make_test(COMPILERS["%s"],%d,%d)' % (name, f_opts, embetter, name, f_opts, embetter))
|
exec('T_%s_%d_%d = make_test(COMPILERS["%s"],%d,%d)' % (name, llvm_opts, embetter, name, llvm_opts, embetter))
|
||||||
del T # T is just a shape for the specific subclasses, we don't test it itself
|
del T # T is just a shape for the specific subclasses, we don't test it itself
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
@ -1351,7 +1418,7 @@ else:
|
||||||
QUANTUM_SIZE = 4
|
QUANTUM_SIZE = 4
|
||||||
RELOOP = OPTIMIZE = USE_TYPED_ARRAYS = 1
|
RELOOP = OPTIMIZE = USE_TYPED_ARRAYS = 1
|
||||||
GUARD_MEMORY = SAFE_HEAP = 0
|
GUARD_MEMORY = SAFE_HEAP = 0
|
||||||
F_OPTS = 1
|
LLVM_OPTS = 1
|
||||||
|
|
||||||
TEST_REPS = 10
|
TEST_REPS = 10
|
||||||
TOTAL_TESTS = 2
|
TOTAL_TESTS = 2
|
||||||
|
@ -1370,6 +1437,8 @@ else:
|
||||||
def do_benchmark(self, src, args=[], expected_output='FAIL', main_file=None):
|
def do_benchmark(self, src, args=[], expected_output='FAIL', main_file=None):
|
||||||
print 'Running benchmark:', inspect.stack()[1][3].replace('test_', '')
|
print 'Running benchmark:', inspect.stack()[1][3].replace('test_', '')
|
||||||
|
|
||||||
|
self.pick_llvm_opts(3, True)
|
||||||
|
|
||||||
dirname = self.get_dir()
|
dirname = self.get_dir()
|
||||||
filename = os.path.join(dirname, 'src.cpp')
|
filename = os.path.join(dirname, 'src.cpp')
|
||||||
self.build(src, dirname, filename, main_file=main_file)
|
self.build(src, dirname, filename, main_file=main_file)
|
||||||
|
|
|
@ -27,12 +27,14 @@ COMPILERS = {
|
||||||
COMPILER_OPTS = ['-m32'] # Need to build as 32bit arch, for now -
|
COMPILER_OPTS = ['-m32'] # Need to build as 32bit arch, for now -
|
||||||
# various errors on 64bit compilation
|
# various errors on 64bit compilation
|
||||||
|
|
||||||
|
LLVM_OPT=os.path.expanduser(os.path.join(LLVM_ROOT, 'opt'))
|
||||||
|
|
||||||
LLVM_DIS=os.path.expanduser(os.path.join(LLVM_ROOT, 'llvm-dis'))
|
LLVM_DIS=os.path.expanduser(os.path.join(LLVM_ROOT, 'llvm-dis'))
|
||||||
LLVM_DIS_OPTS = []
|
LLVM_DIS_OPTS = []
|
||||||
if '2.8' in LLVM_ROOT:
|
if '2.8' in LLVM_ROOT:
|
||||||
LLVM_DIS_OPTS += ['-show-annotations']
|
LLVM_DIS_OPTS += ['-show-annotations']
|
||||||
|
|
||||||
SPIDERMONKEY_ENGINE = [os.path.expanduser('~/Dev/tracemonkey/js/src/js'), '-m'] # No |-j| due to Mozilla bug XXX
|
SPIDERMONKEY_ENGINE = [os.path.expanduser('~/Dev/tracemonkey/js/src/js'), '-m', '-j', '-p']
|
||||||
V8_ENGINE = [os.path.expanduser('~/Dev/v8/d8')]
|
V8_ENGINE = [os.path.expanduser('~/Dev/v8/d8')]
|
||||||
|
|
||||||
# XXX Warning: Compiling the 'cubescript' test in SpiderMonkey can lead to an extreme amount of memory being
|
# XXX Warning: Compiling the 'cubescript' test in SpiderMonkey can lead to an extreme amount of memory being
|
||||||
|
|
Загрузка…
Ссылка в новой задаче