diff options
Diffstat (limited to 'tests/runner.py')
-rwxr-xr-x | tests/runner.py | 4474 |
1 files changed, 3674 insertions, 800 deletions
diff --git a/tests/runner.py b/tests/runner.py index e4616f49..9db26947 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -72,12 +72,16 @@ except: # Core test runner class, shared between normal tests and benchmarks +checked_sanity = False + class RunnerCore(unittest.TestCase): save_dir = os.environ.get('EM_SAVE_DIR') save_JS = 0 stderr_redirect = STDOUT # This avoids cluttering the test runner output, which is stderr too, with compiler warnings etc. # Change this to None to get stderr reporting, for debugging purposes + env = {} + def skipme(self): # used by tests we ask on the commandline to be skipped, see right before call to unittest.main return self.skip('requested to be skipped') @@ -100,24 +104,18 @@ class RunnerCore(unittest.TestCase): for temp_file in os.listdir(TEMP_DIR): if temp_file.endswith('.ll'): self.has_prev_ll = True - + def tearDown(self): - if self.save_JS: - for name in os.listdir(self.get_dir()): - if name.endswith(('.o.js', '.cc.js')): - suff = '.'.join(name.split('.')[-2:]) - shutil.copy(os.path.join(self.get_dir(), name), - os.path.join(TEMP_DIR, self.id().replace('__main__.', '').replace('.test_', '.')+'.'+suff)) if not self.save_dir: # rmtree() fails on Windows if the current working directory is inside the tree. os.chdir(os.path.join(self.get_dir(), '..')) shutil.rmtree(self.get_dir()) # Make sure we don't leave stuff around - if not self.has_prev_ll: - for temp_file in os.listdir(TEMP_DIR): - assert not temp_file.endswith('.ll'), temp_file - # TODO assert not temp_file.startswith('emscripten_'), temp_file + #if not self.has_prev_ll: + # for temp_file in os.listdir(TEMP_DIR): + # assert not temp_file.endswith('.ll'), temp_file + # # TODO assert not temp_file.startswith('emscripten_'), temp_file def skip(self, why): print >> sys.stderr, '<skipping: %s> ' % why, @@ -140,6 +138,12 @@ class RunnerCore(unittest.TestCase): def get_stdout_path(self): return os.path.join(self.get_dir(), 'stdout') + def hardcode_arguments(self, filename, args): + # Hardcode in the arguments, so js is portable without manual commandlinearguments + if not args: return + js = open(filename).read() + open(filename, 'w').write(js.replace('run();', 'run(%s);' % str(args))) + def prep_ll_run(self, filename, ll_file, force_recompile=False, build_ll_hook=None): if ll_file.endswith(('.bc', '.o')): if ll_file != filename + '.o': @@ -238,7 +242,7 @@ process(sys.argv[1]) os.remove(f + '.o') except: pass - args = [Building.COMPILER, '-emit-llvm'] + COMPILER_OPTS + Building.COMPILER_TEST_OPTS + \ + args = [PYTHON, EMCC] + Building.COMPILER_TEST_OPTS + \ ['-I', dirname, '-I', os.path.join(dirname, 'include')] + \ map(lambda include: '-I' + include, includes) + \ ['-c', f, '-o', f + '.o'] @@ -263,7 +267,17 @@ process(sys.argv[1]) if output_processor is not None: output_processor(open(filename + '.o.js').read()) - def run_generated_code(self, engine, filename, args=[], check_timeout=True): + if self.emcc_args is not None and 'ASM_JS=1' in self.emcc_args: + if '--memory-init-file' in self.emcc_args: + memory_init_file = int(self.emcc_args[self.emcc_args.index('--memory-init-file')+1]) + else: + memory_init_file = 0 + if memory_init_file: + assert '/* memory initializer */' not in open(filename + '.o.js').read() + else: + assert 'memory initializer */' in open(filename + '.o.js').read() + + def run_generated_code(self, engine, filename, args=[], check_timeout=True, output_nicerizer=None): stdout = os.path.join(self.get_dir(), 'stdout') # use files, as PIPE can get too full and hang us stderr = os.path.join(self.get_dir(), 'stderr') try: @@ -274,12 +288,23 @@ process(sys.argv[1]) run_js(filename, engine, args, check_timeout, stdout=open(stdout, 'w'), stderr=open(stderr, 'w')) if cwd is not None: os.chdir(cwd) - ret = open(stdout, 'r').read() + open(stderr, 'r').read() + out = open(stdout, 'r').read() + err = open(stderr, 'r').read() + if engine == SPIDERMONKEY_ENGINE and Settings.ASM_JS: + if 'uccessfully compiled asm.js code' in err and 'asm.js link error' not in err: + print >> sys.stderr, "[was asm.js'ified]" + elif 'asm.js' in err: # if no asm.js error, then not an odin build + raise Exception("did NOT asm.js'ify") + if output_nicerizer: + ret = output_nicerizer(out, err) + else: + ret = out + err assert 'strict warning:' not in ret, 'We should pass all strict mode checks: ' + ret return ret - def build_native(self, filename): - process = Popen([CLANG, '-O2', '-fno-math-errno', filename, '-o', filename+'.native'], stdout=PIPE); + def build_native(self, filename, args=[]): + compiler = CLANG if filename.endswith('cpp') else CLANG_CC + process = Popen([compiler, '-O2', '-fno-math-errno', filename, '-o', filename+'.native'] + args, stdout=PIPE, stderr=self.stderr_redirect) output = process.communicate() if process.returncode is not 0: print >> sys.stderr, "Building native executable with command '%s' failed with a return code %d!" % (' '.join([CLANG, '-O2', filename, '-o', filename+'.native']), process.returncode) @@ -291,6 +316,7 @@ process(sys.argv[1]) if process.returncode is not 0: print >> sys.stderr, "Running native executable with command '%s' failed with a return code %d!" % (' '.join([filename+'.native'] + args), process.returncode) print "Output: " + output[0] + return output[0] def assertIdentical(self, values, y): if type(values) not in [list, tuple]: values = [values] @@ -329,17 +355,18 @@ process(sys.argv[1]) os.makedirs(ret) return ret - def get_library(self, name, generated_libs, configure=['sh', './configure'], configure_args=[], make=['make'], make_args=['-j', '2'], cache=True, env_init={}, cache_name_extra=''): + def get_library(self, name, generated_libs, configure=['sh', './configure'], configure_args=[], make=['make'], make_args=['-j', '2'], cache=True, env_init={}, cache_name_extra='', native=False): build_dir = self.get_build_dir() output_dir = self.get_dir() - cache_name = name + cache_name_extra + cache_name = name + cache_name_extra + (self.env.get('EMCC_LLVM_TARGET') or '') + if self.library_cache is not None: if cache and self.library_cache.get(cache_name): print >> sys.stderr, '<load %s from cache> ' % cache_name, generated_libs = [] for basename, contents in self.library_cache[cache_name]: - bc_file = os.path.join(build_dir, basename) + bc_file = os.path.join(build_dir, cache_name + '_' + basename) f = open(bc_file, 'wb') f.write(contents) f.close() @@ -349,7 +376,7 @@ process(sys.argv[1]) print >> sys.stderr, '<building and saving %s into cache> ' % cache_name, return Building.build_library(name, build_dir, output_dir, generated_libs, configure, configure_args, make, make_args, self.library_cache, cache_name, - copy_project=True, env_init=env_init) + copy_project=True, env_init=env_init, native=native) def clear(self, in_curr=False): for name in os.listdir(self.get_dir()): @@ -386,7 +413,7 @@ process(sys.argv[1]) int suppInt = 76; ''' - supp_name = os.path.join(self.get_dir(), 'supp.c') + supp_name = os.path.join(self.get_dir(), 'supp.cpp') open(supp_name, 'w').write(supp) main = r''' @@ -420,44 +447,52 @@ process(sys.argv[1]) sys.argv = map(lambda arg: arg if not arg.startswith('test_') else 'default.' + arg, sys.argv) +test_modes = ['default', 'o1', 'o2', 'asm1', 'asm2', 'asm2g', 'asm2x86', 's_0_0', 's_0_1', 's_1_0', 's_1_1'] + +test_index = 0 + if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv) and 'browser' not in str(sys.argv): # Tests print "Running Emscripten tests..." - if len(sys.argv) == 2 and 'ALL.' in sys.argv[1]: + if len(sys.argv) == 2 and sys.argv[1].startswith('ALL.'): 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]] + map(lambda mode: mode+'.'+test, test_modes) 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_run(self, src, expected_output, 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=[]): - if force_c or (main_file is not None and main_file[-2:]) == '.c': - basename = 'src.c' - Building.COMPILER = to_cc(Building.COMPILER) - - dirname = self.get_dir() - 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, extra_emscripten_args=extra_emscripten_args, post_build=post_build) - - # Run in both JavaScript engines, if optimizing - significant differences there (typed arrays) - if js_engines is None: - js_engines = JS_ENGINES - if Settings.USE_TYPED_ARRAYS: - js_engines = filter(lambda engine: engine != V8_ENGINE, js_engines) # V8 issue 1822 - js_engines = filter(lambda engine: engine not in self.banned_js_engines, js_engines) - if len(js_engines) == 0: return self.skip('No JS engine present to run this test with. Check %s and the paths therein.' % EM_CONFIG) - for engine in js_engines: - js_output = self.run_generated_code(engine, filename + '.o.js', args) - if output_nicerizer is not None: - js_output = output_nicerizer(js_output) - self.assertContained(expected_output, js_output.replace('\r\n', '\n')) - self.assertNotContained('ERROR', js_output) - - #shutil.rmtree(dirname) # TODO: leave no trace in memory. But for now nice for debugging + if force_c or (main_file is not None and main_file[-2:]) == '.c': + basename = 'src.c' + Building.COMPILER = to_cc(Building.COMPILER) + + dirname = self.get_dir() + 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, extra_emscripten_args=extra_emscripten_args, post_build=post_build) + + # Run in both JavaScript engines, if optimizing - significant differences there (typed arrays) + if js_engines is None: + js_engines = JS_ENGINES + if Settings.USE_TYPED_ARRAYS: + js_engines = filter(lambda engine: engine != V8_ENGINE, js_engines) # V8 issue 1822 + js_engines = filter(lambda engine: engine not in self.banned_js_engines, js_engines) + if len(js_engines) == 0: return self.skip('No JS engine present to run this test with. Check %s and the paths therein.' % EM_CONFIG) + for engine in js_engines: + js_output = self.run_generated_code(engine, filename + '.o.js', args, output_nicerizer=output_nicerizer) + self.assertContained(expected_output, js_output.replace('\r\n', '\n')) + self.assertNotContained('ERROR', js_output) + + #shutil.rmtree(dirname) # TODO: leave no trace in memory. But for now nice for debugging + + if self.save_JS: + global test_index + self.hardcode_arguments(filename + '.o.js', args) + shutil.copyfile(filename + '.o.js', os.path.join(TEMP_DIR, str(test_index) + '.js')) + test_index += 1 # No building - just process an existing .ll file (or .bc, which we turn into .ll) def do_ll_run(self, ll_file, expected_output=None, args=[], js_engines=None, output_nicerizer=None, post_build=None, force_recompile=False, build_ll_hook=None, extra_emscripten_args=[]): @@ -475,6 +510,9 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv) and 'brows output_nicerizer=output_nicerizer, post_build=None) # post_build was already done in ll_to_js, this do_run call is just to test the output + def is_le32(self): + return not ('i386-pc-linux-gnu' in COMPILER_OPTS or self.env.get('EMCC_LLVM_TARGET') == 'i386-pc-linux-gnu') + def test_hello_world(self): src = ''' #include <stdio.h> @@ -486,7 +524,11 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv) and 'brows ''' self.do_run(src, 'hello, world!') + assert 'EMSCRIPTEN_GENERATED_FUNCTIONS' not in open(self.in_dir('src.cpp.o.js')).read(), 'must not emit this unneeded internal thing' + def test_intvars(self): + if self.emcc_args == None: return self.skip('needs ta2') + src = ''' #include <stdio.h> int global = 20; @@ -700,7 +742,8 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv) and 'brows uint64_t a = 5; double b = 6.8; uint64_t c = a * b; - printf("*prod:%llu*\n*%d,%d,%d*\n", c, (int)&a, (int)&b, (int)&c); // printing addresses prevents optimizations + if (truthy()) printf("*%d,%d,%d*\n", (int)&a, (int)&b, (int)&c); // printing addresses prevents optimizations + printf("*prod:%llu*\n", c); } // Basic (rounded, for now) math. Just check compilation. @@ -710,6 +753,14 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv) and 'brows b++; if (truthy()) b--; // confuse optimizer printf("*%Ld,%Ld,%Ld,%Ld*\n", (a+b)/5000, (a-b)/5000, (a*3)/5000, (a/5)/5000); + a -= 17; if (truthy()) a += 5; // confuse optimizer + b -= 17; if (truthy()) b += 121; // confuse optimizer + printf("*%Lx,%Lx,%Lx,%Lx*\n", b - a, b - a/2, b/2 - a, b - 20); + + if (truthy()) a += 5/b; // confuse optimizer + if (truthy()) b += 121*(3+a/b); // confuse optimizer + printf("*%Lx,%Lx,%Lx,%Lx*\n", a - b, a - b/2, a/2 - b, a - 20); + return 0; } ''' @@ -729,7 +780,10 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv) and 'brows '*-1,34359738367,4294967295,1073741823*\n' + '*-1,-1,-1,-1*\n' + '*-1,34359738367,4294967295,1073741823*\n' + - '*prod:34*') + '*prod:34*\n' + + '*524718382041609,49025451137,787151111239120,52476740749274*\n' + + '*ffff210edd000002,91990876ea283be,f6e5210edcdd7c45,1234000000450765*\n' + + '*def122fffffe,91adef1232283bb,f6e66f78915d7c42,1234def123450763*\n') src = r''' #include <stdio.h> @@ -804,11 +858,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') @@ -847,26 +904,26 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv) and 'brows void interface_clock_changed() { - UINT8 m_divshift; - INT32 m_divisor; + UINT8 m_divshift; + INT32 m_divisor; - //INT64 attos = m_attoseconds_per_cycle; - INT64 attos = 279365114840; - m_divshift = 0; - while (attos >= (1UL << 31)) - { - m_divshift++; - printf("m_divshift is %i, on %Ld >?= %lu\n", m_divshift, attos, 1UL << 31); - attos >>= 1; - } - m_divisor = attos; + //INT64 attos = m_attoseconds_per_cycle; + INT64 attos = 279365114840; + m_divshift = 0; + while (attos >= (1UL << 31)) + { + m_divshift++; + printf("m_divshift is %i, on %Ld >?= %lu\n", m_divshift, attos, 1UL << 31); + attos >>= 1; + } + m_divisor = attos; - printf("m_divisor is %i\n",m_divisor); + printf("m_divisor is %i\n",m_divisor); } int main() { - interface_clock_changed(); - return 0; + interface_clock_changed(); + return 0; } ''' self.do_run(src, '''m_divshift is 1, on 279365114840 >?= 2147483648 @@ -940,8 +997,8 @@ m_divisor is 1091269979 volatile UINT64 testu64a = 14746250828952703000U; while ((UINT64)testu32a * (UINT64)bigu32 < testu64a) { - printf("testu64a is %llu\n", testu64a); - testu64a /= 2; + printf("testu64a is %llu\n", testu64a); + testu64a /= 2; } return 0; @@ -978,12 +1035,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 = ''' @@ -1029,6 +1080,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') @@ -1061,6 +1125,7 @@ m_divisor is 1091269979 { a = argc; b = argv[1][0]; + printf("%d,%d\n", a, b); if (a > a + b || a > a + b + 1) { printf("one %lld, %lld", a, b); return 0; @@ -1075,10 +1140,11 @@ m_divisor is 1091269979 if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2') src = r''' + #include <stdint.h> #include <stdio.h> int main(int argc, char ** argv){ int y=-133; - __int64_t x= ((__int64_t)((short)(y)))*(100 + argc); + int64_t x= ((int64_t)((short)(y)))*(100 + argc); if(x>0) printf(">0\n"); else @@ -1113,10 +1179,56 @@ m_divisor is 1091269979 ''' self.do_run(src, 'Succeeded!') + def test_i64_varargs(self): + if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2') + + src = r''' + #include <stdio.h> + #include <stdint.h> + #include <stdarg.h> + + int64_t ccv_cache_generate_signature(char *msg, int len, int64_t sig_start, ...) { + if (sig_start < 10123) + printf("%s\n", msg+len); + va_list v; + va_start(v, sig_start); + if (sig_start > 1413) + printf("%d\n", va_arg(v, int)); + else + printf("nada\n"); + va_end(v); + return len*sig_start*(msg[0]+1); + } + + int main(int argc, char **argv) + { + for (int i = 0; i < argc; i++) { + int64_t x; + if (i % 123123 == 0) + x = ccv_cache_generate_signature(argv[i], i+2, (int64_t)argc*argc, 54.111); + else + x = ccv_cache_generate_signature(argv[i], i+2, (int64_t)argc*argc, 13); + printf("%lld\n", x); + } + }; + ''' + self.do_run(src, '''in/this.program +nada +1536 +a +nada +5760 +fl +nada +6592 +sdfasdfasdf +nada +7840 +''', 'waka fleefl asdfasdfasdfasdf'.split(' ')) + def test_i32_mul_precise(self): if self.emcc_args == None: return self.skip('needs ta2') - self.emcc_args += ['-s', 'PRECISE_I32_MUL=1'] src = r''' #include <stdio.h> @@ -1130,6 +1242,51 @@ m_divisor is 1091269979 ''' self.do_run(src, '3217489085') + def test_i32_mul_semiprecise(self): + if Settings.ASM_JS: return self.skip('asm is always fully precise') + + Settings.PRECISE_I32_MUL = 0 # we want semiprecise here + + src = r''' + #include <stdio.h> + + typedef unsigned int uint; + + // from cube2, zlib licensed + + #define N (624) + #define M (397) + #define K (0x9908B0DFU) + + static uint state[N]; + static int next = N; + + void seedMT(uint seed) + { + state[0] = seed; + for(uint i = 1; i < N; i++) // if we do not do this precisely, at least we should coerce to int immediately, not wait + state[i] = seed = 1812433253U * (seed ^ (seed >> 30)) + i; + next = 0; + } + + int main() { + seedMT(5497); + for (int i = 0; i < 10; i++) printf("%d: %u\n", i, state[i]); + return 0; + } + ''' + self.do_run(src, '''0: 5497 +1: 2916432318 +2: 2502517762 +3: 3151524867 +4: 2323729668 +5: 2053478917 +6: 2409490438 +7: 848473607 +8: 691103752 +9: 3915535113 +''') + def test_i16_emcc_intrinsic(self): Settings.CORRECT_SIGNS = 1 # Relevant to this test @@ -1155,9 +1312,64 @@ m_divisor is 1091269979 ''' self.do_run(src, ',0,,2,C!,0,C!,0,,65535,C!,0,') + def test_negative_zero(self): + src = r''' + #include <stdio.h> + #include <math.h> + + int main() { + #define TEST(x, y) \ + printf("%.2f, %.2f ==> %.2f\n", x, y, copysign(x, y)); + TEST( 5.0f, 5.0f); + TEST( 5.0f, -5.0f); + TEST(-5.0f, 5.0f); + TEST(-5.0f, -5.0f); + TEST( 5.0f, 4.0f); + TEST( 5.0f, -4.0f); + TEST(-5.0f, 4.0f); + TEST(-5.0f, -4.0f); + TEST( 0.0f, 5.0f); + TEST( 0.0f, -5.0f); + TEST(-0.0f, 5.0f); + TEST(-0.0f, -5.0f); + TEST( 5.0f, 0.0f); + TEST( 5.0f, -0.0f); + TEST(-5.0f, 0.0f); + TEST(-5.0f, -0.0f); + TEST( 0.0f, 0.0f); + TEST( 0.0f, -0.0f); + TEST(-0.0f, 0.0f); + TEST(-0.0f, -0.0f); + return 0; + } + ''' + self.do_run(src, '''5.00, 5.00 ==> 5.00 +5.00, -5.00 ==> -5.00 +-5.00, 5.00 ==> 5.00 +-5.00, -5.00 ==> -5.00 +5.00, 4.00 ==> 5.00 +5.00, -4.00 ==> -5.00 +-5.00, 4.00 ==> 5.00 +-5.00, -4.00 ==> -5.00 +0.00, 5.00 ==> 0.00 +0.00, -5.00 ==> -0.00 +-0.00, 5.00 ==> 0.00 +-0.00, -5.00 ==> -0.00 +5.00, 0.00 ==> 5.00 +5.00, -0.00 ==> -5.00 +-5.00, 0.00 ==> 5.00 +-5.00, -0.00 ==> -5.00 +0.00, 0.00 ==> 0.00 +0.00, -0.00 ==> -0.00 +-0.00, 0.00 ==> 0.00 +-0.00, -0.00 ==> -0.00 +''') + def test_llvm_intrinsics(self): if self.emcc_args == None: return self.skip('needs ta2') + Settings.PRECISE_I64_MATH = 2 # for bswap64 + src = r''' #include <stdio.h> #include <sys/types.h> @@ -1167,6 +1379,10 @@ m_divisor is 1091269979 extern unsigned int llvm_bswap_i32(unsigned int x); extern int32_t llvm_ctlz_i32(int32_t x); 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); } @@ -1182,9 +1398,16 @@ m_divisor is 1091269979 printf("%x,%x,%x,%x\n", y&0xff, (y>>8)&0xff, (y>>16)&0xff, (y>>24)&0xff); 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", (int)llvm_ctpop_i32(-594093059)); printf("%d\n", llvm_expect_i32(x % 27, 3)); + int64_t a = 1; + a = __builtin_bswap64(a); + printf("%lld\n", a); + return 0; } ''' @@ -1193,7 +1416,11 @@ c8,ef 8a,15,de,c5 c5,de,15,8a 23,21 +40,10 +5,4 +22 13 +72057594037927936 ''') def test_bswap64(self): @@ -1207,7 +1434,7 @@ c5,de,15,8a #include <string> #include <sstream> - typedef unsigned long long quint64; + typedef unsigned long long quint64; using namespace std; @@ -1229,28 +1456,28 @@ c5,de,15,8a quint64 v = strtoull("4433ffeeddccbb00", NULL, 16); printf("%lld\n", v); - const string string64bitInt = "4433ffeeddccbb00"; - stringstream s(string64bitInt); - quint64 int64bitInt = 0; + const string string64bitInt = "4433ffeeddccbb00"; + stringstream s(string64bitInt); + quint64 int64bitInt = 0; printf("1\n"); - s >> hex >> int64bitInt; + s >> hex >> int64bitInt; printf("2\n"); - - stringstream out; - out << hex << qbswap(int64bitInt); - - cout << out.str() << endl; - cout << hex << int64bitInt << endl; - cout << string64bitInt << endl; - - if (out.str() != "bbccddeeff3344") - { - cout << "Failed!" << endl; - } - else - { - cout << "Succeeded!" << endl; - } + + stringstream out; + out << hex << qbswap(int64bitInt); + + cout << out.str() << endl; + cout << hex << int64bitInt << endl; + cout << string64bitInt << endl; + + if (out.str() != "bbccddeeff3344") + { + cout << "Failed!" << endl; + } + else + { + cout << "Succeeded!" << endl; + } return 0; } @@ -1284,7 +1511,7 @@ Succeeded! # A good test of i64 math if Settings.USE_TYPED_ARRAYS != 2: return self.skip('requires ta2 C-style memory aliasing') self.do_run('', 'Usage: hashstring <seed>', - libraries=self.get_library('cube2hash', ['cube2hash.bc'], configure=None), + libraries=self.get_library('cube2hash', ['cube2hash.bc'], configure=None), includes=[path_from_root('tests', 'cube2hash')]) for text, output in [('fleefl', '892BDB6FD3F62E863D63DA55851700FDE3ACF30204798CE9'), @@ -1327,7 +1554,11 @@ Succeeded! ''' # TODO: A version of this with int64s as well - self.do_run(src, '*12 : 1 : 12\n328157500735811.0,23,416012775903557.0,99\n') + + if self.is_le32(): + return self.skip('LLVM marks the reads of s as fully aligned, making this test invalid') + else: + self.do_run(src, '*12 : 1 : 12\n328157500735811.0,23,416012775903557.0,99\n') return # TODO: continue to the next part here @@ -1361,6 +1592,62 @@ Succeeded! except Exception, e: assert 'must be aligned' in str(e), e # expected to fail without emulation + def test_align64(self): + src = r''' + #include <stdio.h> + + // inspired by poppler + + enum Type { + A = 10, + B = 20 + }; + + struct Object { + Type type; + union { + int intg; + double real; + char *name; + }; + }; + + struct Principal { + double x; + Object a; + double y; + }; + + int main(int argc, char **argv) + { + int base = argc-1; + Object *o = NULL; + printf("%d,%d\n", sizeof(Object), sizeof(Principal)); + printf("%d,%d,%d,%d\n", (int)&o[base].type, (int)&o[base].intg, (int)&o[base].real, (int)&o[base].name); + printf("%d,%d,%d,%d\n", (int)&o[base+1].type, (int)&o[base+1].intg, (int)&o[base+1].real, (int)&o[base+1].name); + Principal p, q; + p.x = p.y = q.x = q.y = 0; + p.a.type = A; + p.a.real = 123.456; + *(&q.a) = p.a; + printf("%.2f,%d,%.2f,%.2f : %.2f,%d,%.2f,%.2f\n", p.x, p.a.type, p.a.real, p.y, q.x, q.a.type, q.a.real, q.y); + return 0; + } + ''' + + if self.is_le32(): + self.do_run(src, '''16,32 +0,8,8,8 +16,24,24,24 +0.00,10,123.46,0.00 : 0.00,10,123.46,0.00 +''') + else: + self.do_run(src, '''12,28 +0,4,4,4 +12,16,16,16 +0.00,10,123.46,0.00 : 0.00,10,123.46,0.00 +''') + def test_unsigned(self): Settings.CORRECT_SIGNS = 1 # We test for exactly this sort of thing here Settings.CHECK_SIGNS = 0 @@ -1486,8 +1773,12 @@ Succeeded! def test_floatvars(self): src = ''' #include <stdio.h> - #include <math.h> - int main() + + // headers test, see issue #1013 + #include<cfloat> + #include<cmath> + + int main(int argc, char **argv) { float x = 1.234, y = 3.5, q = 0.00000001; y *= 3; @@ -1496,6 +1787,8 @@ Succeeded! printf("%.2f, %.2f, %.2f, %.2f\\n", fmin(0.5, 3.3), fmin(NAN, 3.3), fmax(0.5, 3.3), fmax(NAN, 3.3)); + printf("small: %.10f\\n", argc * 0.000001); + /* // Rounding behavior float fs[6] = { -2.75, -2.50, -2.25, 2.25, 2.50, 2.75 }; @@ -1507,7 +1800,36 @@ Succeeded! return 0; } ''' - self.do_run(src, '*1,10,10.5,1,1.2340,0.00*\n0.50, 3.30, 3.30, 3.30\n') + self.do_run(src, '*1,10,10.5,1,1.2340,0.00*\n0.50, 3.30, 3.30, 3.30\nsmall: 0.0000010000\n') + + def test_isnan(self): + src = r''' + #include <stdio.h> + + int IsNaN(double x){ + int rc; /* The value return */ + volatile double y = x; + volatile double z = y; + rc = (y!=z); + return rc; + } + + int main() { + double tests[] = { 1.0, 3.333, 1.0/0.0, 0.0/0.0, -1.0/0.0, -0, 0, -123123123, 12.0E200 }; + for (int i = 0; i < sizeof(tests)/sizeof(double); i++) + printf("%d - %f - %d\n", i, tests[i], IsNaN(tests[i])); + } + ''' + self.do_run(src, '''0 - 1.000000 - 0 +1 - 3.333000 - 0 +2 - inf - 0 +3 - nan - 1 +4 - -inf - 0 +5 - 0.000000 - 0 +6 - 0.000000 - 0 +7 - -123123123.000000 - 0 +8 - 1.2e+201 - 0 +''') def test_globaldoubles(self): src = r''' @@ -1546,10 +1868,10 @@ Succeeded! int main() { printf("*%.2f,%.2f,%d", M_PI, -M_PI, (1/0.0) > 1e300); // could end up as infinity, or just a very very big number - printf(",%d", finite(NAN) != 0); - printf(",%d", finite(INFINITY) != 0); - printf(",%d", finite(-INFINITY) != 0); - printf(",%d", finite(12.3) != 0); + printf(",%d", isfinite(NAN) != 0); + printf(",%d", isfinite(INFINITY) != 0); + printf(",%d", isfinite(-INFINITY) != 0); + printf(",%d", isfinite(12.3) != 0); printf(",%d", isinf(NAN) != 0); printf(",%d", isinf(INFINITY) != 0); printf(",%d", isinf(-INFINITY) != 0); @@ -1594,6 +1916,47 @@ Succeeded! expected = open(path_from_root('tests', 'hyperbolic', 'output.txt'), 'r').read() self.do_run(src, expected) + def test_frexp(self): + src = ''' + #include <stdio.h> + #include <math.h> + #include <assert.h> + + static const double tol=1e-16; + + void test_value(double value) + { + int exponent; + double x=frexp(value, &exponent); + double expected=x*pow(2.0, exponent); + + printf("%f=%f*2^%d\\n", value, x, exponent); + + assert(fabs(expected-value)<tol); + assert(x==0 || (fabs(x)>=5e-1 && fabs(x)<1)); // x has a magnitude in the interval [1/2, 1) + } + + int main() + { + test_value(0); + test_value(100.1); + test_value(-100.1); + test_value(.5); + test_value(-.5); + test_value(1-1e-16); + test_value(-(1-1e-16)); + + return 0; + } + ''' + self.do_run(src, '''0.000000=0.000000*2^0 +100.100000=0.782031*2^7 +-100.100000=-0.782031*2^7 +0.500000=0.500000*2^0 +-0.500000=-0.500000*2^0 +1.000000=1.000000*2^0 +-1.000000=-1.000000*2^0''') + def test_getgep(self): # Generated code includes getelementptr (getelementptr, 0, 1), i.e., GEP as the first param to GEP src = ''' @@ -1709,6 +2072,8 @@ Succeeded! generated = open('src.cpp.o.js', 'r').read() def test_stack(self): + Settings.INLINING_LIMIT = 50 + src = ''' #include <stdio.h> int test(int i) { @@ -1760,17 +2125,39 @@ 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]); + char *four = strcat(three, &two[argc*3]); + printf("cat |%s|\\n", three); + printf("returned |%s|\\n", four); + } + 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| +returned |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 - assert (gen.count('ALLOC_NONE') < 8) == named def test_strcmp_uni(self): src = ''' @@ -1857,8 +2244,8 @@ Succeeded! } ''' expected = ''' - <Numerical argument out of domain> - <Resource temporarily unavailable> + <Math arg out of domain of func> + <No more processes> <34> <123> ''' @@ -1938,6 +2325,7 @@ Succeeded! self.do_run(self.gen_struct_src.replace('{{gen_struct}}', '(S*)malloc(sizeof(S))').replace('{{del_struct}}', 'free'), '*51,62*') def test_newstruct(self): + if self.emcc_args is None: return self.skip('requires emcc') self.do_run(self.gen_struct_src.replace('{{gen_struct}}', 'new S').replace('{{del_struct}}', 'delete'), '*51,62*') |