diff options
author | max99x <max99x@gmail.com> | 2011-07-08 08:33:45 +0300 |
---|---|---|
committer | max99x <max99x@gmail.com> | 2011-07-08 08:39:31 +0300 |
commit | 1bd1893888ebe52b6e7676becddbecc577f0e169 (patch) | |
tree | 00bc29bdf7a393b28aca2704c4de39c9ca538604 | |
parent | cfbdf063100f6c7c8405f582d03034d6d791f642 (diff) |
* Added support for automatically determining llvm-gcc/clang data layout in emscripten.py.
* Added a dlmalloc linking test.
* Fixed double-evaling of JSON in emscripten.py when --dlmalloc is passed.
-rwxr-xr-x | emscripten.py | 52 | ||||
-rw-r--r-- | tests/dlmalloc_test.c | 41 | ||||
-rw-r--r-- | tests/runner.py | 16 |
3 files changed, 94 insertions, 15 deletions
diff --git a/emscripten.py b/emscripten.py index fc0f63cc..c11f1cfd 100755 --- a/emscripten.py +++ b/emscripten.py @@ -9,7 +9,12 @@ import tempfile import tools.shared as shared +# Temporary files that should be deleted once teh program is finished. TEMP_FILES_TO_CLEAN = [] +# The data layout used by llvm-gcc (as opposed to clang). +GCC_DATA_LAYOUT = ('target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16' + '-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64' + '-v128:128:128-a0:0:64-f80:32:32-f128:128:128-n8:16:32"') def path_from_root(*target): @@ -98,21 +103,48 @@ def link(*objects): return out.name -def compile_malloc(): - """Compiles dlmalloc to LLVM bitcode and returns the path to the .bc file.""" +def compile_malloc(compiler): + """Compiles dlmalloc to LLVM bitcode. + + Args: + compiler: The compiler command to use, a path to either clang or llvm-gcc. + + Returns: + The path to the compiled dlmalloc as an LLVM bitcode (.bc) file. + """ src = path_from_root('src', 'dlmalloc.c') out = get_temp_file('.bc') - clang = shared.to_cc(shared.CLANG) - include_dir = '-I' + path_from_root('src', 'include') - command = [clang, '-c', '-g', '-emit-llvm', '-m32', '-o-', include_dir, src] + includes = '-I' + path_from_root('src', 'include') + command = [compiler, '-c', '-g', '-emit-llvm', '-m32', '-o-', includes, src] ret = subprocess.call(command, stdout=out) out.close() if ret != 0: raise RuntimeError('Could not compile dlmalloc.') return out.name +def determine_compiler(filepath): + """Determines whether a given file uses llvm-gcc or clang data layout. + + Args: + filepath: The .bc or .ll file containing the bitcode/assembly to test. + + Returns: + The path to the compiler, either llvm-gcc or clang. + """ + assembly = open(disassemble(filepath)).read() + is_gcc = GCC_DATA_LAYOUT in assembly + return shared.to_cc(shared.LLVM_GCC if is_gcc else shared.CLANG) + + def has_annotations(filepath): - """Tests whether an assembly file contains annotations.""" + """Tests whether an assembly file contains annotations. + + Args: + filepath: The .ll file containing the assembly to check. + + Returns: + Whether the provided file is valid assembly and has annotations. + """ return filepath.endswith('.ll') and '[#uses=' in open(filepath).read() @@ -139,7 +171,9 @@ def main(args): # Construct a final linked and disassembled file. if args.dlmalloc or args.optimize or not has_annotations(args.infile): args.infile = assemble(args.infile) - if args.dlmalloc: args.infile = link(args.infile, compile_malloc()) + if args.dlmalloc: + malloc = compile_malloc(determine_compiler(args.infile)) + args.infile = link(args.infile, malloc) if args.optimize: args.infile = optimize(args.infile) args.infile = disassemble(args.infile) @@ -151,10 +185,10 @@ def main(args): # Adjust sign correction for dlmalloc. if args.dlmalloc: - CORRECT_SIGNS = int(settings.get('CORRECT_SIGNS', 0)) + CORRECT_SIGNS = settings.get('CORRECT_SIGNS', 0) if CORRECT_SIGNS in (0, 2): path = path_from_root('src', 'dlmalloc.c') - old_lines = json.loads(settings.get('CORRECT_SIGNS_LINES', '[]')) + old_lines = settings.get('CORRECT_SIGNS_LINES', []) line_nums = [4816, 4191, 4246, 4199, 4205, 4235, 4227] lines = old_lines + [path + ':' + str(i) for i in line_nums] settings['CORRECT_SIGNS'] = 2 diff --git a/tests/dlmalloc_test.c b/tests/dlmalloc_test.c new file mode 100644 index 00000000..6fbc45ab --- /dev/null +++ b/tests/dlmalloc_test.c @@ -0,0 +1,41 @@ +// Emscripten tests + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> + +int main(int ac, char **av) { + int NUM = ac > 1 ? atoi(av[1]) : 0; + int REPS = ac > 2 ? atoi(av[2]) : 0; + int c1 = 0, c2 = 0; + for (int x = 0; x < REPS; x++) { + char* allocations[NUM]; + for (int i = 0; i < NUM/2; i++) { + allocations[i] = (char*)malloc((11*i)%1024 + x); + assert(allocations[i]); + if (i > 10 && i%4 == 1 && allocations[i-10]) { + free(allocations[i-10]); + allocations[i-10] = NULL; + } + } + for (int i = NUM/2; i < NUM; i++) { + allocations[i] = (char*)malloc(1024*(i+1)); + assert(allocations[i]); + if (i > 10 && i%4 != 1 && allocations[i-10]) { + free(allocations[i-10]); + allocations[i-10] = NULL; + } + } + char* first = allocations[0]; + for (int i = 0; i < NUM; i++) { + if (allocations[i]) { + free(allocations[i]); + } + } + char *last = (char*)malloc(512); // should be identical, as we free'd it all + char *newer = (char*)malloc(512); // should be different + c1 += first == last; + c2 += first == newer; + } + printf("*%d,%d*\n", c1, c2); +} diff --git a/tests/runner.py b/tests/runner.py index 84b358fd..04856b8b 100644 --- a/tests/runner.py +++ b/tests/runner.py @@ -120,7 +120,7 @@ class RunnerCore(unittest.TestCase): self.do_llvm_dis(filename) # Build JavaScript code from source code - def build(self, src, dirname, filename, output_processor=None, main_file=None, additional_files=[], libraries=[], includes=[], build_ll_hook=None): + def build(self, src, dirname, filename, output_processor=None, main_file=None, additional_files=[], libraries=[], includes=[], build_ll_hook=None, extra_emscripten_args=[]): # Copy over necessary files for compiling the source if main_file is None: f = open(filename, 'w') @@ -169,9 +169,9 @@ class RunnerCore(unittest.TestCase): # Finalize self.prep_ll_test(filename, filename + '.o', build_ll_hook=build_ll_hook) - self.do_emscripten(filename, output_processor) + self.do_emscripten(filename, output_processor, extra_args=extra_emscripten_args) - def do_emscripten(self, filename, output_processor=None, append_ext=True): + def do_emscripten(self, filename, output_processor=None, append_ext=True, extra_args=[]): # Run Emscripten exported_settings = {} for setting in ['QUANTUM_SIZE', 'RELOOP', 'OPTIMIZE', 'ASSERTIONS', 'USE_TYPED_ARRAYS', 'SAFE_HEAP', 'CHECK_OVERFLOWS', 'CORRECT_OVERFLOWS', 'CORRECT_SIGNS', 'CHECK_SIGNS', 'CORRECT_OVERFLOWS_LINES', 'CORRECT_SIGNS_LINES', 'CORRECT_ROUNDINGS', 'CORRECT_ROUNDINGS_LINES', 'INVOKE_RUN', 'SAFE_HEAP_LINES', 'INIT_STACK', 'AUTO_OPTIMIZE', 'EXPORTED_FUNCTIONS', 'EXPORTED_GLOBALS', 'BUILD_AS_SHARED_LIB', 'INCLUDE_FULL_LIBRARY']: @@ -181,7 +181,7 @@ class RunnerCore(unittest.TestCase): except: pass settings = ['%s=%s' % (k, json.dumps(v)) for k, v in exported_settings.items()] - compiler_output = timeout_run(Popen([EMSCRIPTEN, filename + ('.o.ll' if append_ext else ''), '-o', filename + '.o.js', '-s'] + settings, stdout=PIPE, stderr=STDOUT), TIMEOUT, 'Compiling') + compiler_output = timeout_run(Popen([EMSCRIPTEN, filename + ('.o.ll' if append_ext else ''), '-o', filename + '.o.js', '-s'] + settings + extra_args, stdout=PIPE, stderr=STDOUT), TIMEOUT, 'Compiling') # Detect compilation crashes and errors if compiler_output is not None and 'Traceback' in compiler_output and 'in test_' in compiler_output: print compiler_output; assert 0 @@ -234,7 +234,7 @@ if 'benchmark' not in sys.argv: 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. - def do_test(self, src, expected_output=None, args=[], output_nicerizer=None, output_processor=None, no_build=False, main_file=None, additional_files=[], js_engines=None, post_build=None, basename='src.cpp', libraries=[], includes=[], force_c=False, build_ll_hook=None): + def do_test(self, src, expected_output=None, args=[], output_nicerizer=None, output_processor=None, no_build=False, main_file=None, additional_files=[], js_engines=None, post_build=None, basename='src.cpp', libraries=[], includes=[], force_c=False, build_ll_hook=None, extra_emscripten_args=[]): #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 '') if force_c or (main_file is not None and main_file[-2:]) == '.c': basename = 'src.c' @@ -245,7 +245,7 @@ if 'benchmark' not in sys.argv: filename = os.path.join(dirname, basename) if not no_build: self.build(src, dirname, filename, main_file=main_file, additional_files=additional_files, libraries=libraries, includes=includes, - build_ll_hook=build_ll_hook) + build_ll_hook=build_ll_hook, extra_emscripten_args=extra_emscripten_args) if post_build is not None: post_build(filename + '.o.js') @@ -2683,6 +2683,10 @@ if 'benchmark' not in sys.argv: shutil.copy(filename + '.o.js', os.path.join(self.get_dir(), 'src.cpp.o.js')) self.do_test(None, 'test\n', no_build=True) + def test_dlmalloc_linked(self): + src = open(path_from_root('tests', 'dlmalloc_test.c'), 'r').read() + self.do_test(src, '*1,0*', ['200', '1'], extra_emscripten_args=['-m']) + def test_linespecific(self): global COMPILER_TEST_OPTS; COMPILER_TEST_OPTS = ['-g'] |