diff options
author | Alon Zakai <alonzakai@gmail.com> | 2013-03-15 18:21:34 -0700 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2013-03-15 18:21:34 -0700 |
commit | b22f6fbbbebb5df55ceb8fdc9f7c4d111c902c5e (patch) | |
tree | c568136b2cf95d897d128b362720602a3b401244 /tests/runner.py | |
parent | 8c9a37a40a164dba330390af2eabf5ad05625001 (diff) | |
parent | 27d1a249622d33ab8aff2814d13569507336873b (diff) |
Merge branch 'incoming'
Diffstat (limited to 'tests/runner.py')
-rwxr-xr-x | tests/runner.py | 643 |
1 files changed, 545 insertions, 98 deletions
diff --git a/tests/runner.py b/tests/runner.py index e631b025..7f46dbfb 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -445,7 +445,7 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv) and 'brows if len(sys.argv) == 2 and 'ALL.' in sys.argv[1]: ignore, test = sys.argv[1].split('.') print 'Running all test modes on test "%s"' % test - sys.argv = [sys.argv[0], 'default.'+test, 'o1.'+test, 'o2.'+test, 'asm2.'+test, 's_0_0.'+test, 's_0_1.'+test, 's_0_1_q1.'+test, 's_1_0.'+test, 's_1_1.'+test, 's_1_1_q1.'+test] + sys.argv = [sys.argv[0], 'default.'+test, 'o1.'+test, 'o2.'+test, 'asm2.'+test, 'asm2g.'+test, 's_0_0.'+test, 's_0_1.'+test, 's_1_0.'+test, 's_1_1.'+test] 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. @@ -829,11 +829,14 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv) and 'brows int add_low = add; int add_high = add >> 32; printf("*%lld,%lld,%u,%u*\n", mul, add, add_low, add_high); + int64 x = sec + (usec << 25); + x >>= argc*3; + printf("*%llu*\n", x); return 0; } ''' - self.do_run(src, '*1329409676000000,1329412005509675,3663280683,309527*\n') + self.do_run(src, '*1329409676000000,1329412005509675,3663280683,309527*\n*9770671914067409*\n') def test_i64_cmp(self): if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2') @@ -1003,12 +1006,6 @@ m_divisor is 1091269979 ''' self.do_run(src, open(path_from_root('tests', 'i64_precise.txt')).read()) - # Verify that without precision, we do not include the precision code - Settings.PRECISE_I64_MATH = 0 - self.do_run(src, 'unsigned') - code = open(os.path.join(self.get_dir(), 'src.cpp.o.js')).read() - assert 'goog.math.Long' not in code, 'i64 precise math should not have been included if not asked for' - # Verify that even if we ask for precision, if it is not needed it is not included Settings.PRECISE_I64_MATH = 1 src = ''' @@ -1054,6 +1051,19 @@ m_divisor is 1091269979 } ''', 'c = 4ca38a6bd2973f97') + def test_i64_llabs(self): + if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2') + Settings.PRECISE_I64_MATH = 2 + self.do_run(r''' + #include <stdio.h> + #include <stdlib.h> + + int main(int argc, char ** argv) { + printf("%lld,%lld\n", llabs(-576460752303423489), llabs(576460752303423489)); + return 0; + } + ''', '576460752303423489,576460752303423489') + def test_i64_zextneg(self): if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2') @@ -1240,6 +1250,8 @@ m_divisor is 1091269979 extern int64_t llvm_ctlz_i64(int64_t x); extern int32_t llvm_cttz_i32(int32_t x); extern int64_t llvm_cttz_i64(int64_t x); + extern int32_t llvm_ctpop_i32(int32_t x); + extern int64_t llvm_ctpop_i64(int64_t x); extern int llvm_expect_i32(int x, int y); } @@ -1256,6 +1268,7 @@ m_divisor is 1091269979 printf("%d,%d\n", (int)llvm_ctlz_i64(((int64_t)1) << 40), llvm_ctlz_i32(1<<10)); printf("%d,%d\n", (int)llvm_cttz_i64(((int64_t)1) << 40), llvm_cttz_i32(1<<10)); + printf("%d,%d\n", (int)llvm_ctpop_i64((0x3101ULL << 32) | 1), llvm_ctpop_i32(0x3101)); printf("%d\n", llvm_expect_i32(x % 27, 3)); @@ -1272,6 +1285,7 @@ c8,ef c5,de,15,8a 23,21 40,10 +5,4 13 72057594037927936 ''') @@ -1873,13 +1887,34 @@ Succeeded! printf("%s\\n", strdup_val); free(strdup_val); + { + char *one = "one 1 ONE !"; + char *two = "two 2 TWO ?"; + char three[1024]; + memset(three, '.', 1024); + three[50] = 0; + strncpy(three + argc, one + (argc/2), argc+1); + strncpy(three + argc*3, two + (argc/3), argc+2); + printf("waka %s\\n", three); + } + + { + char *one = "string number one top notch"; + char *two = "fa la sa ho fi FI FO FUM WHEN WHERE WHY HOW WHO"; + char three[1000]; + strcpy(three, &one[argc*2]); + strcat(three, &two[argc*3]); + printf("cat |%s|\\n", three); + } + return 0; } ''' for named in (0, 1): print named Settings.NAMED_GLOBALS = named - self.do_run(src, '4:10,177,543,def\n4\nwowie\ntoo\n76\n5\n(null)\n/* a comment */\n// another\ntest\n', ['wowie', 'too', '74']) + self.do_run(src, '''4:10,177,543,def\n4\nwowie\ntoo\n76\n5\n(null)\n/* a comment */\n// another\ntest\nwaka ....e 1 O...wo 2 T................................ +cat |umber one top notchfi FI FO FUM WHEN WHERE WHY HOW WHO|''', ['wowie', 'too', '74']) if self.emcc_args == []: gen = open(self.in_dir('src.cpp.o.js')).read() assert ('var __str1;' in gen) == named @@ -4100,10 +4135,12 @@ The current type of b is: 9 #define CONSTRLEN 32 + char * (*func)(char *, const char *) = NULL; + void conoutfv(const char *fmt) { static char buf[CONSTRLEN]; - strcpy(buf, fmt); + func(buf, fmt); // call by function pointer to make sure we test strcpy here puts(buf); } @@ -4125,6 +4162,7 @@ The current type of b is: 9 }; int main() { + func = &strcpy; conoutfv("*staticccz*"); printf("*%.2f,%.2f,%.2f*\\n", S::getIdentity().x, S::getIdentity().y, S::getIdentity().z); return 0; @@ -4253,6 +4291,143 @@ The current type of b is: 9 ''' self.do_run(src, 'ok.'); + def test_getopt(self): + if self.emcc_args is None: return self.skip('needs emcc for libc') + + src = ''' + #pragma clang diagnostic ignored "-Winvalid-pp-token" + #include <unistd.h> + #include <stdlib.h> + #include <stdio.h> + + int + main(int argc, char *argv[]) + { + int flags, opt; + int nsecs, tfnd; + + nsecs = 0; + tfnd = 0; + flags = 0; + while ((opt = getopt(argc, argv, "nt:")) != -1) { + switch (opt) { + case 'n': + flags = 1; + break; + case 't': + nsecs = atoi(optarg); + tfnd = 1; + break; + default: /* '?' */ + fprintf(stderr, "Usage: %s [-t nsecs] [-n] name\\n", + argv[0]); + exit(EXIT_FAILURE); + } + } + + printf("flags=%d; tfnd=%d; optind=%d\\n", flags, tfnd, optind); + + if (optind >= argc) { + fprintf(stderr, "Expected argument after options\\n"); + exit(EXIT_FAILURE); + } + + printf("name argument = %s\\n", argv[optind]); + + /* Other code omitted */ + + exit(EXIT_SUCCESS); + } + ''' + self.do_run(src, 'flags=1; tfnd=1; optind=4\nname argument = foobar', args=['-t', '12', '-n', 'foobar']) + + def test_getopt_long(self): + if self.emcc_args is None: return self.skip('needs emcc for libc') + + src = ''' + #pragma clang diagnostic ignored "-Winvalid-pp-token" + #pragma clang diagnostic ignored "-Wdeprecated-writable-strings" + #include <stdio.h> /* for printf */ + #include <stdlib.h> /* for exit */ + #include <getopt.h> + + int + main(int argc, char **argv) + { + int c; + int digit_optind = 0; + + while (1) { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = { + {"add", required_argument, 0, 0 }, + {"append", no_argument, 0, 0 }, + {"delete", required_argument, 0, 0 }, + {"verbose", no_argument, 0, 0 }, + {"create", required_argument, 0, 'c'}, + {"file", required_argument, 0, 0 }, + {0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "abc:d:012", + long_options, &option_index); + if (c == -1) + break; + + switch (c) { + case 0: + printf("option %s", long_options[option_index].name); + if (optarg) + printf(" with arg %s", optarg); + printf("\\n"); + break; + + case '0': + case '1': + case '2': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf("digits occur in two different argv-elements.\\n"); + digit_optind = this_option_optind; + printf("option %c\\n", c); + break; + + case 'a': + printf("option a\\n"); + break; + + case 'b': + printf("option b\\n"); + break; + + case 'c': + printf("option c with value '%s'\\n", optarg); + break; + + case 'd': + printf("option d with value '%s'\\n", optarg); + break; + + case '?': + break; + + default: + printf("?? getopt returned character code 0%o ??\\n", c); + } + } + + if (optind < argc) { + printf("non-option ARGV-elements: "); + while (optind < argc) + printf("%s ", argv[optind++]); + printf("\\n"); + } + + exit(EXIT_SUCCESS); + } + ''' + self.do_run(src, 'option file with arg foobar\noption b', args=['--file', 'foobar', '-b']) + def test_memmove(self): src = ''' #include <stdio.h> @@ -4875,6 +5050,8 @@ def process(filename): self.do_run(src, re.sub(r'(^|\n)\s+', r'\1', expected)) def test_strtod(self): + if self.emcc_args is None: return self.skip('needs emcc for libc') + src = r''' #include <stdio.h> #include <stdlib.h> @@ -4908,6 +5085,9 @@ def process(filename): printf("%g\n", strtod(str, &endptr)); printf("%d\n", endptr - str); printf("%g\n", strtod("84e+420", &endptr)); + + printf("%.12f\n", strtod("1.2345678900000000e+08", NULL)); + return 0; } ''' @@ -4935,6 +5115,7 @@ def process(filename): 1.234e+57 10 inf + 123456789.000000000000 ''' self.do_run(src, re.sub(r'\n\s+', '\n', expected)) @@ -5214,6 +5395,8 @@ at function.:blag ''') def test_sscanf(self): + if self.emcc_args is None: return self.skip('needs emcc for libc') + src = r''' #include <stdio.h> #include <string.h> @@ -5894,6 +6077,8 @@ def process(filename): self.do_run(src, re.sub('(^|\n)\s+', '\\1', expected), post_build=add_pre_run_and_checks) def test_utf(self): + if self.emcc_args and 'UTF_STRING_SUPPORT=0' in self.emcc_args: return self.skip('need utf support') + self.banned_js_engines = [SPIDERMONKEY_ENGINE] # only node handles utf well Settings.EXPORTED_FUNCTIONS = ['_main', '_malloc'] @@ -6311,6 +6496,90 @@ PORT: 3979 expected = open(path_from_root('tests', 'ctype', 'output.txt'), 'r').read() self.do_run(src, expected) + def test_strcasecmp(self): + src = r''' + #include <stdio.h> + #include <strings.h> + int sign(int x) { + if (x < 0) return -1; + if (x > 0) return 1; + return 0; + } + int main() { + printf("*\n"); + + printf("%d\n", sign(strcasecmp("hello", "hello"))); + printf("%d\n", sign(strcasecmp("hello1", "hello"))); + printf("%d\n", sign(strcasecmp("hello", "hello1"))); + printf("%d\n", sign(strcasecmp("hello1", "hello1"))); + printf("%d\n", sign(strcasecmp("iello", "hello"))); + printf("%d\n", sign(strcasecmp("hello", "iello"))); + printf("%d\n", sign(strcasecmp("A", "hello"))); + printf("%d\n", sign(strcasecmp("Z", "hello"))); + printf("%d\n", sign(strcasecmp("a", "hello"))); + printf("%d\n", sign(strcasecmp("z", "hello"))); + printf("%d\n", sign(strcasecmp("hello", "a"))); + printf("%d\n", sign(strcasecmp("hello", "z"))); + + printf("%d\n", sign(strcasecmp("Hello", "hello"))); + printf("%d\n", sign(strcasecmp("Hello1", "hello"))); + printf("%d\n", sign(strcasecmp("Hello", "hello1"))); + printf("%d\n", sign(strcasecmp("Hello1", "hello1"))); + printf("%d\n", sign(strcasecmp("Iello", "hello"))); + printf("%d\n", sign(strcasecmp("Hello", "iello"))); + printf("%d\n", sign(strcasecmp("A", "hello"))); + printf("%d\n", sign(strcasecmp("Z", "hello"))); + printf("%d\n", sign(strcasecmp("a", "hello"))); + printf("%d\n", sign(strcasecmp("z", "hello"))); + printf("%d\n", sign(strcasecmp("Hello", "a"))); + printf("%d\n", sign(strcasecmp("Hello", "z"))); + + printf("%d\n", sign(strcasecmp("hello", "Hello"))); + printf("%d\n", sign(strcasecmp("hello1", "Hello"))); + printf("%d\n", sign(strcasecmp("hello", "Hello1"))); + printf("%d\n", sign(strcasecmp("hello1", "Hello1"))); + printf("%d\n", sign(strcasecmp("iello", "Hello"))); + printf("%d\n", sign(strcasecmp("hello", "Iello"))); + printf("%d\n", sign(strcasecmp("A", "Hello"))); + printf("%d\n", sign(strcasecmp("Z", "Hello"))); + printf("%d\n", sign(strcasecmp("a", "Hello"))); + printf("%d\n", sign(strcasecmp("z", "Hello"))); + printf("%d\n", sign(strcasecmp("hello", "a"))); + printf("%d\n", sign(strcasecmp("hello", "z"))); + + printf("%d\n", sign(strcasecmp("Hello", "Hello"))); + printf("%d\n", sign(strcasecmp("Hello1", "Hello"))); + printf("%d\n", sign(strcasecmp("Hello", "Hello1"))); + printf("%d\n", sign(strcasecmp("Hello1", "Hello1"))); + printf("%d\n", sign(strcasecmp("Iello", "Hello"))); + printf("%d\n", sign(strcasecmp("Hello", "Iello"))); + printf("%d\n", sign(strcasecmp("A", "Hello"))); + printf("%d\n", sign(strcasecmp("Z", "Hello"))); + printf("%d\n", sign(strcasecmp("a", "Hello"))); + printf("%d\n", sign(strcasecmp("z", "Hello"))); + printf("%d\n", sign(strcasecmp("Hello", "a"))); + printf("%d\n", sign(strcasecmp("Hello", "z"))); + + printf("%d\n", sign(strncasecmp("hello", "hello", 3))); + printf("%d\n", sign(strncasecmp("hello1", "hello", 3))); + printf("%d\n", sign(strncasecmp("hello", "hello1", 3))); + printf("%d\n", sign(strncasecmp("hello1", "hello1", 3))); + printf("%d\n", sign(strncasecmp("iello", "hello", 3))); + printf("%d\n", sign(strncasecmp("hello", "iello", 3))); + printf("%d\n", sign(strncasecmp("A", "hello", 3))); + printf("%d\n", sign(strncasecmp("Z", "hello", 3))); + printf("%d\n", sign(strncasecmp("a", "hello", 3))); + printf("%d\n", sign(strncasecmp("z", "hello", 3))); + printf("%d\n", sign(strncasecmp("hello", "a", 3))); + printf("%d\n", sign(strncasecmp("hello", "z", 3))); + + printf("*\n"); + + return 0; + } + ''' + self.do_run(src, '''*\n0\n1\n-1\n0\n1\n-1\n-1\n1\n-1\n1\n1\n-1\n0\n1\n-1\n0\n1\n-1\n-1\n1\n-1\n1\n1\n-1\n0\n1\n-1\n0\n1\n-1\n-1\n1\n-1\n1\n1\n-1\n0\n1\n-1\n0\n1\n-1\n-1\n1\n-1\n1\n1\n-1\n0\n0\n0\n0\n1\n-1\n-1\n1\n-1\n1\n1\n-1\n*\n''') + def test_atomic(self): src = ''' #include <stdio.h> @@ -6985,6 +7254,9 @@ def process(filename): Settings.DISABLE_EXCEPTION_CATCHING = 1 Settings.FAST_MEMORY = 4*1024*1024 Settings.EXPORTED_FUNCTIONS += ['_sqlite3_open', '_sqlite3_close', '_sqlite3_exec', '_sqlite3_free', '_callback']; + if Settings.ASM_JS == 1 and '-g' in self.emcc_args: + print "disabling inlining" # without registerize (which -g disables), we generate huge amounts of code + Settings.INLINING_LIMIT = 50 self.do_run(r''' #define SQLITE_DISABLE_LFS @@ -7086,6 +7358,8 @@ def process(filename): #, build_ll_hook=self.do_autodebug) def test_openjpeg(self): + if self.emcc_args is None: return self.skip('needs libc for getopt') + if Settings.USE_TYPED_ARRAYS == 2: Settings.CORRECT_SIGNS = 1 else: @@ -7114,7 +7388,6 @@ def process(filename): [os.path.sep.join('codec/CMakeFiles/j2k_to_image.dir/index.c.o'.split('/')), os.path.sep.join('codec/CMakeFiles/j2k_to_image.dir/convert.c.o'.split('/')), os.path.sep.join('codec/CMakeFiles/j2k_to_image.dir/__/common/color.c.o'.split('/')), - os.path.sep.join('codec/CMakeFiles/j2k_to_image.dir/__/common/getopt.c.o'.split('/')), os.path.join('bin', self.get_shared_library_name('libopenjpeg.so.1.4.0'))], configure=['cmake', '.'], #configure_args=['--enable-tiff=no', '--enable-jp3d=no', '--enable-png=no'], @@ -7156,6 +7429,8 @@ def process(filename): return output + self.emcc_args += ['--minify', '0'] # to compare the versions + def do_test(): self.do_run(open(path_from_root('tests', 'openjpeg', 'codec', 'j2k_to_image.c'), 'r').read(), 'Successfully generated', # The real test for valid output is in image_compare @@ -7504,6 +7779,114 @@ def process(filename): self.do_run(src, '*\nnumber,5\nnumber,3.14\nstring,hello world\n12\nundefined\n14.56\nundefined\ncheez\nundefined\narr-ay\nundefined\nmore\nnumber,10\n650\nnumber,21\n*\natr\n10\nbret\n53\n*\nstack is ok.\n', post_build=post) + def test_pgo(self): + if Settings.ASM_JS: return self.skip('PGO does not work in asm mode') + + def run_all(name, src): + print name + def test(expected, args=[], no_build=False): + self.do_run(src, expected, args=args, no_build=no_build) + return open(self.in_dir('src.cpp.o.js')).read() + + # Sanity check that it works and the dead function is emitted + js = test('*9*') + assert 'function _unused(' in js + + # Run with PGO, see that unused is true to its name + Settings.PGO = 1 + test("*9*\n-s DEAD_FUNCTIONS='[\"_unused\"]'") + Settings.PGO = 0 + + # Kill off the dead function, still works and it is not emitted + Settings.DEAD_FUNCTIONS = ['_unused'] + js = test('*9*') + assert 'function _unused(' not in js + Settings.DEAD_FUNCTIONS = [] + + # Run the same code with argc that uses the dead function, see abort + test(('abort', 'is not a function'), args=['a', 'b'], no_build=True) + + # Normal stuff + run_all('normal', r''' + #include <stdio.h> + extern "C" { + int used(int x) { + if (x == 0) return -1; + return used(x/3) + used(x/17) + x%5; + } + int unused(int x) { + if (x == 0) return -1; + return unused(x/4) + unused(x/23) + x%7; + } + } + int main(int argc, char **argv) { + printf("*%d*\n", argc == 3 ? unused(argv[0][0] + 1024) : used(argc + 1555)); + return 0; + } + ''') + + # Call by function pointer + run_all('function pointers', r''' + #include <stdio.h> + extern "C" { + int used(int x) { + if (x == 0) return -1; + return used(x/3) + used(x/17) + x%5; + } + int unused(int x) { + if (x == 0) return -1; + return unused(x/4) + unused(x/23) + x%7; + } + } + typedef int (*ii)(int); + int main(int argc, char **argv) { + ii pointers[256]; + for (int i = 0; i < 256; i++) { + pointers[i] = (i == 3) ? unused : used; + } + printf("*%d*\n", pointers[argc](argc + 1555)); + return 0; + } + ''') + + def test_asm_pgo(self): + if not Settings.ASM_JS: return self.skip('this is a test for PGO for asm (NB: not *in* asm)') + + src = open(path_from_root('tests', 'hello_libcxx.cpp')).read() + output = 'hello, world!' + + self.do_run(src, output) + shutil.move(self.in_dir('src.cpp.o.js'), self.in_dir('normal.js')) + + self.emcc_args = map(lambda x: 'ASM_JS=0' if x == 'ASM_JS=1' else x, self.emcc_args) + Settings.PGO = 1 + self.do_run(src, output) + Settings.PGO = 0 + self.emcc_args = map(lambda x: 'ASM_JS=1' if x == 'ASM_JS=0' else x, self.emcc_args) + + shutil.move(self.in_dir('src.cpp.o.js'), self.in_dir('pgo.js')) + pgo_output = run_js(self.in_dir('pgo.js')).split('\n')[1] + open('pgo_data', 'w').write(pgo_output) + + # with response file + + self.emcc_args += ['@pgo_data'] + self.do_run(src, output) + self.emcc_args.pop() + shutil.move(self.in_dir('src.cpp.o.js'), self.in_dir('pgoed.js')) + + before = len(open('normal.js').read()) + after = len(open('pgoed.js').read()) + assert after < 0.66 * before, [before, after] # expect a big size reduction + + # with response in settings element itself + + open('dead_funcs', 'w').write(pgo_output[pgo_output.find('['):-1]) + self.emcc_args += ['-s', 'DEAD_FUNCTIONS=@' + self.in_dir('dead_funcs')] + self.do_run(src, output) + shutil.move(self.in_dir('src.cpp.o.js'), self.in_dir('pgoed2.js')) + assert open('pgoed.js').read() == open('pgoed2.js').read() + def test_scriptaclass(self): if self.emcc_args is None: return self.skip('requires emcc') if Settings.ASM_JS: return self.skip('asm does not bindings generator yet') @@ -8369,13 +8752,11 @@ TT = %s exec('o2 = make_run("o2", compiler=CLANG, emcc_args=["-O2"])') # asm.js - #exec('asm = make_run("asm", compiler=CLANG, emcc_args=["-O0", "-s", "ASM_JS=1"])') exec('asm2 = make_run("asm2", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=1"])') + exec('asm2g = make_run("asm2g", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=1", "-g", "-s", "ASSERTIONS=1", "-s", "UTF_STRING_SUPPORT=0"])') # Make custom runs with various options for compiler, quantum, embetter, typed_arrays, llvm_opts in [ - (CLANG, 1, 1, 0, 0), - (CLANG, 1, 1, 1, 1), (CLANG, 4, 0, 0, 0), (CLANG, 4, 0, 0, 1), (CLANG, 4, 1, 1, 0), @@ -8510,6 +8891,7 @@ Options that are modified or new in %s include: (['-o', 'something.js', '-O2'], 2, None, 0, 1), (['-o', 'something.js', '-O2', '--closure', '0'], 2, None, 0, 0), (['-o', 'something.js', '-O2', '-g'], 2, None, 0, 0), + (['-o', 'something.js', '-Os'], 2, None, 0, 1), (['-o', 'something.js', '-O3'], 3, None, 1, 1), (['-o', 'something.js', '-O3', '--closure', '0'], 3, None, 0, 0), # and, test compiling to bitcode first @@ -8542,7 +8924,8 @@ Options that are modified or new in %s include: assert 'SAFE_HEAP' not in generated, 'safe heap should not be used by default' assert ': while(' not in generated, 'when relooping we also js-optimize, so there should be no labelled whiles' if closure: - assert 'Module._main=' in generated, 'closure compiler should have been run (and output should be minified)' + if opt_level <= 1: assert 'Module._main =' in generated, 'closure compiler should have been run' + elif opt_level >= 2: assert 'Module._main=' in generated, 'closure compiler should have been run (and output should be minified)' else: # closure has not been run, we can do some additional checks. TODO: figure out how to do these even with closure assert 'Module._main = ' not in generated, 'closure compiler should not have been run' @@ -8551,16 +8934,19 @@ Options that are modified or new in %s include: assert ('assert(STACKTOP < STACK_MAX' in generated) == (opt_level == 0), 'assertions should be in opt == 0' assert 'var $i;' in generated or 'var $i_0' in generated or 'var $storemerge3;' in generated or 'var $storemerge4;' in generated or 'var $i_04;' in generated, 'micro opts should always be on' if opt_level >= 2: - assert re.search('HEAP8\[\$?\w+ \+ \(+\$?\w+ ', generated) or re.search('HEAP8\[HEAP32\[', generated), 'eliminator should create compound expressions, and fewer one-time vars' # also in -O1, but easier to test in -O2 + assert re.search('HEAP8\[\$?\w+ ?\+ ?\(+\$?\w+ ?', generated) or re.search('HEAP8\[HEAP32\[', generated), 'eliminator should create compound expressions, and fewer one-time vars' # also in -O1, but easier to test in -O2 assert ('_puts(' in generated) == (opt_level >= 1), 'with opt >= 1, llvm opts are run and they should optimize printf to puts' - assert 'function _main() {' in generated, 'Should be unminified, including whitespace' + if opt_level <= 1 or '-g' in params: assert 'function _main() {' in generated, 'Should be unminified, including whitespace' + elif opt_level >= 2: assert 'function _main(){' in generated, 'Should be whitespace-minified' # emcc -s RELOOP=1 src.cpp ==> should pass -s to emscripten.py. --typed-arrays is a convenient alias for -s USE_TYPED_ARRAYS for params, test, text in [ - (['-s', 'ASM_JS=1', '-O2'], lambda generated: 'var i1 = 0' in generated, 'registerize is run by default in -O2'), - (['-s', 'ASM_JS=1', '-O2', '-g'], lambda generated: 'var i1 = 0' not in generated, 'registerize is cancelled by -g'), + (['-s', 'ASM_JS=1', '-O2'], lambda generated: 'var b=0' in generated and not 'function _main' in generated, 'registerize/minify is run by default in -O2'), + (['-s', 'ASM_JS=1', '-O2', '--minify', '0'], lambda generated: 'var b = 0' in generated and not 'function _main' in generated, 'minify is cancelled, but not registerize'), + (['-s', 'ASM_JS=1', '-O2', '-g'], lambda generated: 'var b=0' not in generated and 'var b = 0' not in generated and 'function _main' in generated, 'registerize/minify is cancelled by -g'), (['-s', 'INLINING_LIMIT=0'], lambda generated: 'function _dump' in generated, 'no inlining without opts'), (['-O3', '-s', 'INLINING_LIMIT=0', '--closure', '0'], lambda generated: 'function _dump' not in generated, 'lto/inlining'), + (['-Os', '--llvm-lto', '1'], lambda generated: 'function _dump' in generated, '-Os disables inlining'), (['-s', 'USE_TYPED_ARRAYS=0'], lambda generated: 'new Int32Array' not in generated, 'disable typed arrays'), (['-s', 'USE_TYPED_ARRAYS=1'], lambda generated: 'IHEAPU = ' in generated, 'typed arrays 1 selected'), ([], lambda generated: 'Module["_dump"]' not in generated, 'dump is not exported by default'), @@ -8716,14 +9102,6 @@ f.close() process.communicate() assert process.returncode is 0, 'User should be able to specify custom -std= on the command line!' - def test_Os(self): - for opt in ['s', '0']: - output = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.c'), '-O' + opt], stdout=PIPE, stderr=PIPE).communicate() - assert len(output[0]) == 0, output[0] - assert ('emcc: warning: -Os is ignored (use -O0, -O1, -O2)' in output[1]) == (opt == 's'), 'warn on -Os when necessary' - assert os.path.exists('a.out.js'), '\n'.join(output) - self.assertContained('hello, world!', run_js('a.out.js')) - def test_catch_undef(self): open(os.path.join(self.get_dir(), 'test.cpp'), 'w').write(r''' #include <vector> @@ -8741,7 +9119,7 @@ f.close() return 0; } ''') - Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'test.cpp'), '-fcatch-undefined-behavior']).communicate() + Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'test.cpp'), '-fsanitize=undefined']).communicate() self.assertContained('hello, world!', run_js(os.path.join(self.get_dir(), 'a.out.js'))) def test_unaligned_memory(self): @@ -8780,6 +9158,32 @@ f.close() Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'test.cpp'), '-s', 'UNALIGNED_MEMORY=1']).communicate() self.assertContained('testString = Hello, World!', run_js(os.path.join(self.get_dir(), 'a.out.js'))) + def test_asm_minify(self): + def test(args): + Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_loop_malloc.cpp')] + args).communicate() + self.assertContained('hello, world!', run_js(self.in_dir('a.out.js'))) + return open(self.in_dir('a.out.js')).read() + + src = test([]) + assert 'function _malloc' in src + + src = test(['-O2', '-s', 'ASM_JS=1']) + normal_size = len(src) + print 'normal', normal_size + assert 'function _malloc' not in src + + src = test(['-O2', '-s', 'ASM_JS=1', '--minify', '0']) + unminified_size = len(src) + print 'unminified', unminified_size + assert unminified_size > normal_size + assert 'function _malloc' not in src + + src = test(['-O2', '-s', 'ASM_JS=1', '-g']) + debug_size = len(src) + print 'debug', debug_size + assert debug_size > unminified_size + assert 'function _malloc' in src + def test_l_link(self): # Linking with -lLIBNAME and -L/DIRNAME should work @@ -9462,6 +9866,22 @@ f.close() Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--pre-js', 'pre.js', '--pre-js', 'pre2.js']).communicate() self.assertContained('prepre\npre-run\nhello from main\n', run_js(os.path.join(self.get_dir(), 'a.out.js'))) + def test_save_bc(self): + for save in [0, 1]: + self.clear() + Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_loop_malloc.cpp')] + ([] if not save else ['--save-bc', self.in_dir('my_bitcode.bc')])).communicate() + assert 'hello, world!' in run_js(self.in_dir('a.out.js')) + assert os.path.exists(self.in_dir('my_bitcode.bc')) == save + if save: + try_delete('a.out.js') + Building.llvm_dis(self.in_dir('my_bitcode.bc'), self.in_dir('my_ll.ll')) + try: + os.environ['EMCC_LEAVE_INPUTS_RAW'] = '1' + Popen([PYTHON, EMCC, 'my_ll.ll', '-o', 'two.js']).communicate() + assert 'hello, world!' in run_js(self.in_dir('two.js')) + finally: + del os.environ['EMCC_LEAVE_INPUTS_RAW'] + def test_fix_closure(self): input = path_from_root('tests', 'test-fix-closure.js') expected = path_from_root('tests', 'test-fix-closure.out.js') @@ -9492,6 +9912,8 @@ f.close() ['asm', 'eliminate']), (path_from_root('tools', 'test-js-optimizer-asm-regs.js'), open(path_from_root('tools', 'test-js-optimizer-asm-regs-output.js')).read(), ['asm', 'registerize']), + (path_from_root('tools', 'test-js-optimizer-asm-regs-min.js'), open(path_from_root('tools', 'test-js-optimizer-asm-regs-min-output.js')).read(), + ['asm', 'registerize']), (path_from_root('tools', 'test-js-optimizer-asm-pre.js'), open(path_from_root('tools', 'test-js-optimizer-asm-pre-output.js')).read(), ['asm', 'simplifyExpressionsPre']), (path_from_root('tools', 'test-js-optimizer-asm-last.js'), open(path_from_root('tools', 'test-js-optimizer-asm-last-output.js')).read(), @@ -10486,6 +10908,15 @@ elif 'browser' in str(sys.argv): Popen([PYTHON, EMCC, '-O2', '--minify', '0', os.path.join(self.get_dir(), 'sdl_audio.c'), '--preload-file', 'sound.ogg', '--preload-file', 'sound2.wav', '--preload-file', 'bad.ogg', '-o', 'page.html', '-s', 'EXPORTED_FUNCTIONS=["_main", "_play", "_play2"]']).communicate() self.run_browser('page.html', '', '/report_result?1') + def test_sdl_audio_mix(self): + shutil.copyfile(path_from_root('tests', 'sounds', 'pluck.ogg'), os.path.join(self.get_dir(), 'sound.ogg')) + shutil.copyfile(path_from_root('tests', 'sounds', 'the_entertainer.ogg'), os.path.join(self.get_dir(), 'music.ogg')) + open(os.path.join(self.get_dir(), 'sdl_audio_mix.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_audio_mix.c')).read())) + + # use closure to check for a possible bug with closure minifying away newer Audio() attributes + Popen([PYTHON, EMCC, '-O2', '--minify', '0', os.path.join(self.get_dir(), 'sdl_audio_mix.c'), '--preload-file', 'sound.ogg', '--preload-file', 'music.ogg', '-o', 'page.html']).communicate() + self.run_browser('page.html', '', '/report_result?1') + def test_sdl_audio_quickload(self): open(os.path.join(self.get_dir(), 'sdl_audio_quickload.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_audio_quickload.c')).read())) @@ -10555,6 +10986,13 @@ elif 'browser' in str(sys.argv): Popen([PYTHON, EMCC, path_from_root('tests', 'sdl_fog_linear.c'), '-o', 'something.html', '--pre-js', 'reftest.js', '--preload-file', 'screenshot.png', '-s', 'GL_TESTING=1']).communicate() self.run_browser('something.html', 'You should see an image with fog.', '/report_result?0') + def test_openal_playback(self): + shutil.copyfile(path_from_root('tests', 'sounds', 'audio.wav'), os.path.join(self.get_dir(), 'audio.wav')) + open(os.path.join(self.get_dir(), 'openal_playback.cpp'), 'w').write(self.with_report_result(open(path_from_root('tests', 'openal_playback.cpp')).read())) + + Popen([PYTHON, EMCC, '-O2', os.path.join(self.get_dir(), 'openal_playback.cpp'), '--preload-file', 'audio.wav', '-o', 'page.html']).communicate() + self.run_browser('page.html', '', '/report_result?1') + def test_worker(self): # Test running in a web worker output = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_worker.cpp'), '-o', 'worker.js'], stdout=PIPE, stderr=PIPE).communicate() @@ -10698,14 +11136,19 @@ elif 'browser' in str(sys.argv): self.run_browser('something.html', 'You should see animating gears.', '/report_result?0') def test_glgears_animation(self): - for emulation in [0, 1]: - print emulation - Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_gles.c'), '-o', 'something.html', - '-DHAVE_BUILTIN_SINCOS', '-s', 'GL_TESTING=1', - '--shell-file', path_from_root('tests', 'hello_world_gles_shell.html')] + - (['-s', 'FORCE_GL_EMULATION=1'] if emulation else [])).communicate() - self.run_browser('something.html', 'You should see animating gears.', '/report_gl_result?true') - assert ('var GLEmulation' in open(self.in_dir('something.html')).read()) == emulation, "emulation code should be added when asked for" + es2_suffix = ['', '_full', '_full_944'] + for full_es2 in [0, 1, 2]: + for emulation in [0, 1]: + if full_es2 and emulation: continue + print full_es2, emulation + Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_gles%s.c' % es2_suffix[full_es2]), '-o', 'something.html', + '-DHAVE_BUILTIN_SINCOS', '-s', 'GL_TESTING=1', + '--shell-file', path_from_root('tests', 'hello_world_gles_shell.html')] + + (['-s', 'FORCE_GL_EMULATION=1'] if emulation else []) + + (['-s', 'FULL_ES2=1'] if full_es2 else []), + ).communicate() + self.run_browser('something.html', 'You should see animating gears.', '/report_gl_result?true') + assert ('var GLEmulation' in open(self.in_dir('something.html')).read()) == emulation, "emulation code should be added when asked for" def test_glgears_bad(self): # Make sure that OpenGL ES is not available if typed arrays are not used @@ -11282,7 +11725,7 @@ elif 'benchmark' in str(sys.argv): try_delete(final_filename) output = Popen([PYTHON, EMCC, filename, #'-O3', '-O2', '-s', 'INLINING_LIMIT=0', '-s', 'DOUBLE_MODE=0', '-s', 'PRECISE_I64_MATH=0',# '-s', 'EXPLICIT_ZEXT=1', - '-s', 'ASM_JS=1', '-s', 'USE_MATH_IMUL=1', + '-s', 'ASM_JS=1', '-s', 'USE_MATH_IMUL=1', '--llvm-lto', '1', '-s', 'TOTAL_MEMORY=128*1024*1024', '-s', 'FAST_MEMORY=10*1024*1024', '-o', final_filename] + shared_args + emcc_args, stdout=PIPE, stderr=self.stderr_redirect).communicate() assert os.path.exists(final_filename), 'Failed to compile file: ' + output[0] @@ -11297,7 +11740,8 @@ elif 'benchmark' in str(sys.argv): start = time.time() js_output = run_js(final_filename, engine=JS_ENGINE, args=args, stderr=PIPE, full_output=True) if i == 0 and 'Successfully compiled asm.js code' in js_output: - print "[%s was asm.js'ified]" % name + if 'asm.js link error' not in js_output: + print "[%s was asm.js'ified]" % name curr = time.time()-start times.append(curr) total_times[tests_done] += curr @@ -11873,66 +12317,69 @@ fi EMCC_CACHE = Cache.dirname - restore() - - Cache.erase() - assert not os.path.exists(EMCC_CACHE) + for compiler in [EMCC, EMXX]: + print compiler - try: - os.environ['EMCC_DEBUG'] ='1' - self.working_dir = os.path.join(TEMP_DIR, 'emscripten_temp') + restore() - # Building a file that doesn't need cached stuff should not trigger cache generation - output = self.do([EMCC, path_from_root('tests', 'hello_world.cpp')]) - assert INCLUDING_MESSAGE.replace('X', 'libc') not in output - assert BUILDING_MESSAGE.replace('X', 'libc') not in output - self.assertContained('hello, world!', run_js('a.out.js')) + Cache.erase() assert not os.path.exists(EMCC_CACHE) - try_delete('a.out.js') - - basebc_name = os.path.join(TEMP_DIR, 'emscripten_temp', 'emcc-0-basebc.bc') - dcebc_name1 = os.path.join(TEMP_DIR, 'emscripten_temp', 'emcc-1-linktime.bc') - dcebc_name2 = os.path.join(TEMP_DIR, 'emscripten_temp', 'emcc-2-linktime.bc') - ll_names = [os.path.join(TEMP_DIR, 'emscripten_temp', 'emcc-X-ll.ll').replace('X', str(x)) for x in range(2,5)] |