aboutsummaryrefslogtreecommitdiff
path: root/tests/test_core.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_core.py')
-rw-r--r--tests/test_core.py10074
1 files changed, 10074 insertions, 0 deletions
diff --git a/tests/test_core.py b/tests/test_core.py
new file mode 100644
index 00000000..31db6ca5
--- /dev/null
+++ b/tests/test_core.py
@@ -0,0 +1,10074 @@
+# coding=utf-8
+
+import glob, hashlib, os, re, shutil, subprocess, sys
+import tools.shared
+from tools.shared import *
+from runner import RunnerCore, path_from_root, checked_sanity, test_modes
+
+class T(RunnerCore): # Short name, to make it more fun to use manually on the commandline
+ 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>
+ int main()
+ {
+ printf("hello, world!\\n");
+ return 0;
+ }
+ '''
+ 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;
+ int *far;
+ int main()
+ {
+ int x = 5;
+ int y = x+17;
+ int z = (y-1)/2; // Should stay an integer after division!
+ y += 1;
+ int w = x*3+4;
+ int k = w < 15 ? 99 : 101;
+ far = &k;
+ *far += global;
+ int i = k > 100; // Should be an int, not a bool!
+ int j = i << 6;
+ j >>= 1;
+ j = j ^ 5;
+ int h = 1;
+ h |= 0;
+ int p = h;
+ p &= 0;
+ printf("*%d,%d,%d,%d,%d,%d,%d,%d,%d*\\n", x, y, z, w, k, i, j, h, p);
+
+ long hash = -1;
+ size_t perturb;
+ int ii = 0;
+ for (perturb = hash; ; perturb >>= 5) {
+ printf("%d:%d", ii, perturb);
+ ii++;
+ if (ii == 9) break;
+ printf(",");
+ }
+ printf("*\\n");
+ printf("*%.1d,%.2d*\\n", 56, 9);
+
+ // Fixed-point math on 64-bit ints. Tricky to support since we have no 64-bit shifts in JS
+ {
+ struct Fixed {
+ static int Mult(int a, int b) {
+ return ((long long)a * (long long)b) >> 16;
+ }
+ };
+ printf("fixed:%d\\n", Fixed::Mult(150000, 140000));
+ }
+
+ printf("*%ld*%p\\n", (long)21, &hash); // The %p should not enter an infinite loop!
+ return 0;
+ }
+ '''
+ self.do_run(src, '*5,23,10,19,121,1,37,1,0*\n0:-1,1:134217727,2:4194303,3:131071,4:4095,5:127,6:3,7:0,8:0*\n*56,09*\nfixed:320434\n*21*')
+
+ def test_sintvars(self):
+ Settings.CORRECT_SIGNS = 1 # Relevant to this test
+ src = '''
+ #include <stdio.h>
+ struct S {
+ char *match_start;
+ char *strstart;
+ };
+ int main()
+ {
+ struct S _s;
+ struct S *s = &_s;
+ unsigned short int sh;
+
+ s->match_start = (char*)32522;
+ s->strstart = (char*)(32780);
+ printf("*%d,%d,%d*\\n", (int)s->strstart, (int)s->match_start, (int)(s->strstart - s->match_start));
+ sh = s->strstart - s->match_start;
+ printf("*%d,%d*\\n", sh, sh>>7);
+
+ s->match_start = (char*)32999;
+ s->strstart = (char*)(32780);
+ printf("*%d,%d,%d*\\n", (int)s->strstart, (int)s->match_start, (int)(s->strstart - s->match_start));
+ sh = s->strstart - s->match_start;
+ printf("*%d,%d*\\n", sh, sh>>7);
+ }
+ '''
+ output = '*32780,32522,258*\n*258,2*\n*32780,32999,-219*\n*65317,510*'
+ Settings.CORRECT_OVERFLOWS = 0 # We should not need overflow correction to get this right
+ self.do_run(src, output, force_c=True)
+
+ def test_i64(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('i64 mode 1 requires ta2')
+
+ src = '''
+ #include <stdio.h>
+ int main()
+ {
+ long long a = 0x2b00505c10;
+ long long b = a >> 29;
+ long long c = a >> 32;
+ long long d = a >> 34;
+ printf("*%Ld,%Ld,%Ld,%Ld*\\n", a, b, c, d);
+ unsigned long long ua = 0x2b00505c10;
+ unsigned long long ub = ua >> 29;
+ unsigned long long uc = ua >> 32;
+ unsigned long long ud = ua >> 34;
+ printf("*%Ld,%Ld,%Ld,%Ld*\\n", ua, ub, uc, ud);
+
+ long long x = 0x0000def123450789ULL; // any bigger than this, and we
+ long long y = 0x00020ef123456089ULL; // start to run into the double precision limit!
+ printf("*%Ld,%Ld,%Ld,%Ld,%Ld*\\n", x, y, x | y, x & y, x ^ y, x >> 2, y << 2);
+
+ printf("*");
+ long long z = 13;
+ int n = 0;
+ while (z > 1) {
+ printf("%.2f,", (float)z); // these must be integers!
+ z = z >> 1;
+ n++;
+ }
+ printf("*%d*\\n", n);
+ return 0;
+ }
+ '''
+ self.do_run(src, '*184688860176,344,43,10*\n*184688860176,344,43,10*\n*245127260211081,579378795077769,808077213656969,16428841631881,791648372025088*\n*13.00,6.00,3.00,*3*')
+
+ src = r'''
+ #include <time.h>
+ #include <stdio.h>
+ #include <stdint.h>
+
+ int64_t returner1() { return 0x0000def123450789ULL; }
+ int64_t returner2(int test) {
+ while (test > 10) test /= 2; // confuse the compiler so it doesn't eliminate this function
+ return test > 5 ? 0x0000def123450123ULL : 0ULL;
+ }
+
+ void modifier1(int64_t t) {
+ t |= 12;
+ printf("m1: %Ld\n", t);
+ }
+ void modifier2(int64_t &t) {
+ t |= 12;
+ }
+
+ int truthy() {
+ int x = time(0);
+ while (x > 10) {
+ x |= 7;
+ x /= 2;
+ }
+ return x < 3;
+ }
+
+ struct IUB {
+ int c;
+ long long d;
+ };
+
+ IUB iub[] = {
+ { 55, 17179869201 },
+ { 122, 25769803837 },
+ };
+
+ int main(int argc, char **argv)
+ {
+ int64_t x1 = 0x1234def123450789ULL;
+ int64_t x2 = 0x1234def123450788ULL;
+ int64_t x3 = 0x1234def123450789ULL;
+ printf("*%Ld\n%d,%d,%d,%d,%d\n%d,%d,%d,%d,%d*\n", x1, x1==x2, x1<x2, x1<=x2, x1>x2, x1>=x2, // note: some rounding in the printing!
+ x1==x3, x1<x3, x1<=x3, x1>x3, x1>=x3);
+ printf("*%Ld*\n", returner1());
+ printf("*%Ld*\n", returner2(30));
+
+ uint64_t maxx = -1ULL;
+ printf("*%Lu*\n*%Lu*\n", maxx, maxx >> 5);
+
+ // Make sure params are not modified if they shouldn't be
+ int64_t t = 123;
+ modifier1(t);
+ printf("*%Ld*\n", t);
+ modifier2(t);
+ printf("*%Ld*\n", t);
+
+ // global structs with i64s
+ printf("*%d,%Ld*\n*%d,%Ld*\n", iub[0].c, iub[0].d, iub[1].c, iub[1].d);
+
+ // Bitshifts
+ {
+ int64_t a = -1;
+ int64_t b = a >> 29;
+ int64_t c = a >> 32;
+ int64_t d = a >> 34;
+ printf("*%Ld,%Ld,%Ld,%Ld*\n", a, b, c, d);
+ uint64_t ua = -1;
+ int64_t ub = ua >> 29;
+ int64_t uc = ua >> 32;
+ int64_t ud = ua >> 34;
+ printf("*%Ld,%Ld,%Ld,%Ld*\n", ua, ub, uc, ud);
+ }
+
+ // Nonconstant bitshifts
+ {
+ int64_t a = -1;
+ int64_t b = a >> (29 - argc + 1);
+ int64_t c = a >> (32 - argc + 1);
+ int64_t d = a >> (34 - argc + 1);
+ printf("*%Ld,%Ld,%Ld,%Ld*\n", a, b, c, d);
+ uint64_t ua = -1;
+ int64_t ub = ua >> (29 - argc + 1);
+ int64_t uc = ua >> (32 - argc + 1);
+ int64_t ud = ua >> (34 - argc + 1);
+ printf("*%Ld,%Ld,%Ld,%Ld*\n", ua, ub, uc, ud);
+ }
+
+ // Math mixtures with doubles
+ {
+ uint64_t a = 5;
+ double b = 6.8;
+ uint64_t c = a * b;
+ 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.
+ int64_t a = 0x1234def123450789ULL;
+ a--; if (truthy()) a--; // confuse optimizer
+ int64_t b = 0x1234000000450789ULL;
+ 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;
+ }
+ '''
+ self.do_run(src, '*1311918518731868041\n' +
+ '0,0,0,1,1\n' +
+ '1,0,1,0,1*\n' +
+ '*245127260211081*\n' +
+ '*245127260209443*\n' +
+ '*18446744073709551615*\n' +
+ '*576460752303423487*\n' +
+ 'm1: 127\n' +
+ '*123*\n' +
+ '*127*\n' +
+ '*55,17179869201*\n' +
+ '*122,25769803837*\n' +
+ '*-1,-1,-1,-1*\n' +
+ '*-1,34359738367,4294967295,1073741823*\n' +
+ '*-1,-1,-1,-1*\n' +
+ '*-1,34359738367,4294967295,1073741823*\n' +
+ '*prod:34*\n' +
+ '*524718382041609,49025451137,787151111239120,52476740749274*\n' +
+ '*ffff210edd000002,91990876ea283be,f6e5210edcdd7c45,1234000000450765*\n' +
+ '*def122fffffe,91adef1232283bb,f6e66f78915d7c42,1234def123450763*\n')
+
+ src = r'''
+ #include <stdio.h>
+ #include <limits>
+
+ int main()
+ {
+ long long i,j,k;
+
+ i = 0;
+ j = -1,
+ k = 1;
+
+ printf( "*\n" );
+ printf( "%s\n", i > j ? "Ok": "Fail" );
+ printf( "%s\n", k > i ? "Ok": "Fail" );
+ printf( "%s\n", k > j ? "Ok": "Fail" );
+ printf( "%s\n", i < j ? "Fail": "Ok" );
+ printf( "%s\n", k < i ? "Fail": "Ok" );
+ printf( "%s\n", k < j ? "Fail": "Ok" );
+ printf( "%s\n", (i-j) >= k ? "Ok": "Fail" );
+ printf( "%s\n", (i-j) <= k ? "Ok": "Fail" );
+ printf( "%s\n", i > std::numeric_limits<long long>::min() ? "Ok": "Fail" );
+ printf( "%s\n", i < std::numeric_limits<long long>::max() ? "Ok": "Fail" );
+ printf( "*\n" );
+ }
+ '''
+
+ self.do_run(src, '*\nOk\nOk\nOk\nOk\nOk\nOk\nOk\nOk\nOk\nOk\n*')
+
+ # stuff that also needs sign corrections
+
+ Settings.CORRECT_SIGNS = 1
+
+ src = r'''
+ #include <stdio.h>
+ #include <stdint.h>
+
+ int main()
+ {
+ // i32 vs i64
+ int32_t small = -1;
+ int64_t large = -1;
+ printf("*%d*\n", small == large);
+ small++;
+ printf("*%d*\n", small == large);
+ uint32_t usmall = -1;
+ uint64_t ularge = -1;
+ printf("*%d*\n", usmall == ularge);
+ return 0;
+ }
+ '''
+
+ self.do_run(src, '*1*\n*0*\n*0*\n')
+
+ def test_i64_b(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
+
+ src = r'''
+ #include <stdio.h>
+ #include <sys/time.h>
+
+ typedef long long int64;
+
+ #define PRMJ_USEC_PER_SEC 1000000L
+
+ int main(int argc, char * argv[]) {
+ int64 sec = 1329409675 + argc;
+ int64 usec = 2329509675;
+ int64 mul = int64(sec) * PRMJ_USEC_PER_SEC;
+ int64 add = mul + int64(usec);
+ 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*9770671914067409*\n')
+
+ def test_i64_cmp(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
+
+ src = r'''
+ #include <stdio.h>
+
+ typedef long long int64;
+
+ bool compare(int64 val) {
+ return val == -12;
+ }
+
+ bool compare2(int64 val) {
+ return val < -12;
+ }
+
+ int main(int argc, char * argv[]) {
+ printf("*%d,%d,%d,%d,%d,%d*\n", argc, compare(argc-1-12), compare(1000+argc), compare2(argc-1-10), compare2(argc-1-14), compare2(argc+1000));
+ return 0;
+ }
+ '''
+
+ self.do_run(src, '*1,1,0,0,1,0*\n')
+
+ def test_i64_cmp2(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
+
+ src = r'''
+ #include <inttypes.h>
+ #include <stdio.h>
+
+ typedef int32_t INT32;
+ typedef int64_t INT64;
+ typedef uint8_t UINT8;
+
+ void interface_clock_changed()
+ {
+ 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;
+
+ printf("m_divisor is %i\n",m_divisor);
+ }
+
+ int main() {
+ interface_clock_changed();
+ return 0;
+ }
+ '''
+ self.do_run(src, '''m_divshift is 1, on 279365114840 >?= 2147483648
+m_divshift is 2, on 139682557420 >?= 2147483648
+m_divshift is 3, on 69841278710 >?= 2147483648
+m_divshift is 4, on 34920639355 >?= 2147483648
+m_divshift is 5, on 17460319677 >?= 2147483648
+m_divshift is 6, on 8730159838 >?= 2147483648
+m_divshift is 7, on 4365079919 >?= 2147483648
+m_divshift is 8, on 2182539959 >?= 2147483648
+m_divisor is 1091269979
+''')
+
+ def test_i64_double(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
+
+
+ src = r'''
+ #include <stdio.h>
+
+ typedef long long int64;
+ #define JSDOUBLE_HI32_SIGNBIT 0x80000000
+
+ bool JSDOUBLE_IS_NEGZERO(double d)
+ {
+ union {
+ struct {
+ unsigned int lo, hi;
+ } s;
+ double d;
+ } x;
+ if (d != 0)
+ return false;
+ x.d = d;
+ return (x.s.hi & JSDOUBLE_HI32_SIGNBIT) != 0;
+ }
+
+ bool JSINT64_IS_NEGZERO(int64 l)
+ {
+ union {
+ int64 i;
+ double d;
+ } x;
+ if (l != 0)
+ return false;
+ x.i = l;
+ return x.d == -0;
+ }
+
+ int main(int argc, char * argv[]) {
+ printf("*%d,%d,%d,%d*\n", JSDOUBLE_IS_NEGZERO(0), JSDOUBLE_IS_NEGZERO(-0), JSDOUBLE_IS_NEGZERO(-1), JSDOUBLE_IS_NEGZERO(+1));
+ printf("*%d,%d,%d,%d*\n", JSINT64_IS_NEGZERO(0), JSINT64_IS_NEGZERO(-0), JSINT64_IS_NEGZERO(-1), JSINT64_IS_NEGZERO(+1));
+ return 0;
+ }
+ '''
+ self.do_run(src, '*0,0,0,0*\n*1,1,0,0*\n') # same as gcc
+
+ def test_i64_umul(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
+
+ src = r'''
+ #include <inttypes.h>
+ #include <stdio.h>
+
+ typedef uint32_t UINT32;
+ typedef uint64_t UINT64;
+
+ int main() {
+ volatile UINT32 testu32a = 2375724032U;
+ UINT32 bigu32 = 0xffffffffU;
+ volatile UINT64 testu64a = 14746250828952703000U;
+
+ while ((UINT64)testu32a * (UINT64)bigu32 < testu64a) {
+ printf("testu64a is %llu\n", testu64a);
+ testu64a /= 2;
+ }
+
+ return 0;
+ }
+ '''
+ self.do_run(src, 'testu64a is 14746250828952703000\n')
+
+ def test_i64_precise(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
+
+ src = r'''
+ #include <inttypes.h>
+ #include <stdio.h>
+
+ int main() {
+ uint64_t x = 0, y = 0;
+ for (int i = 0; i < 64; i++) {
+ x += 1ULL << i;
+ y += x;
+ x /= 3;
+ y *= 5;
+ printf("unsigned %d: %llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu\n", i, x, y, x+y, x-y, x*y, y ? x/y : 0, x ? y/x : 0, y ? x%y : 0, x ? y%x : 0);
+ }
+ int64_t x2 = 0, y2 = 0;
+ for (int i = 0; i < 64; i++) {
+ x2 += 1LL << i;
+ y2 += x2;
+ x2 /= 3 * (i % 7 ? -1 : 1);
+ y2 *= 5 * (i % 2 ? -1 : 1);
+ printf("signed %d: %lld,%lld,%lld,%lld,%lld,%lld,%lld,%lld,%lld\n", i, x2, y2, x2+y2, x2-y2, x2*y2, y2 ? x2/y2 : 0, x2 ? y2/x2 : 0, y2 ? x2%y2 : 0, x2 ? y2%x2 : 0);
+ }
+ return 0;
+ }
+ '''
+ self.do_run(src, open(path_from_root('tests', 'i64_precise.txt')).read())
+
+ # Verify that even if we ask for precision, if it is not needed it is not included
+ Settings.PRECISE_I64_MATH = 1
+ src = '''
+ #include <inttypes.h>
+ #include <stdio.h>
+
+ int main(int argc, char **argv) {
+ uint64_t x = 2125299906845564, y = 1225891506842664;
+ if (argc == 12) {
+ x = x >> 1;
+ y = y >> 1;
+ }
+ x = x & 12ULL;
+ y = y | 12ULL;
+ x = x ^ y;
+ x <<= 2;
+ y >>= 3;
+ printf("*%llu, %llu*\\n", x, y);
+ }
+ '''
+ self.do_run(src, '*4903566027370624, 153236438355333*')
+ 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 actually used'
+
+ # But if we force it to be included, it is. First, a case where we don't need it
+ Settings.PRECISE_I64_MATH = 2
+ self.do_run(open(path_from_root('tests', 'hello_world.c')).read(), 'hello')
+ code = open(os.path.join(self.get_dir(), 'src.cpp.o.js')).read()
+ assert 'goog.math.Long' in code, 'i64 precise math should be included if forced'
+
+ # and now one where we do
+ self.do_run(r'''
+ #include <stdio.h>
+
+ int main( int argc, char ** argv )
+ {
+ unsigned long a = 0x60DD1695U;
+ unsigned long b = 0xCA8C4E7BU;
+ unsigned long long c = (unsigned long long)a * b;
+ printf( "c = %016llx\n", c );
+
+ return 0;
+ }
+ ''', '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')
+
+ src = r'''
+ #include <stdint.h>
+ #include <stdio.h>
+
+ int main(int argc, char *argv[])
+ {
+ uint8_t byte = 0x80;
+ uint16_t two = byte;
+ uint32_t four = byte;
+ uint64_t eight = byte;
+
+ printf("value: %d,%d,%d,%lld.\n", byte, two, four, eight);
+
+ return 0;
+ }
+ '''
+ self.do_run(src, 'value: 128,128,128,128.')
+
+ def test_i64_7z(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
+
+ src = r'''
+ #include <stdint.h>
+ #include <stdio.h>
+ uint64_t a, b;
+ int main(int argc, char *argv[])
+ {
+ 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;
+ }
+ printf("zero %lld, %lld", a, b);
+ return 0;
+ }
+ '''
+ self.do_run(src, 'zero 2, 104', ['hallo'])
+
+ def test_i64_i16(self):
+ 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);
+ if(x>0)
+ printf(">0\n");
+ else
+ printf("<=0\n");
+ }
+ '''
+ self.do_run(src, '<=0')
+
+ def test_i64_qdouble(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
+
+ src = r'''
+ #include <stdio.h>
+ typedef long long qint64; /* 64 bit signed */
+ typedef double qreal;
+
+
+ int main(int argc, char **argv)
+ {
+ qreal c = 111;
+ qint64 d = -111 + (argc - 1);
+ c += d;
+ if (c < -1 || c > 1)
+ {
+ printf("Failed!\n");
+ }
+ else
+ {
+ printf("Succeeded!\n");
+ }
+ };
+ '''
+ 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')
+
+ src = r'''
+ #include <stdio.h>
+
+ int main(int argc, char **argv) {
+ unsigned long d1 = 0x847c9b5d;
+ unsigned long q = 0x549530e1;
+ if (argc > 1000) { q += argc; d1 -= argc; } // confuse optimizer
+ printf("%lu\n", d1*q);
+ return 0;
+ }
+ '''
+ 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
+
+ src = r'''
+ #include <stdio.h>
+
+ int test(unsigned short a, unsigned short b) {
+ unsigned short result = a;
+ result += b;
+ if (result < b) printf("C!");
+ return result;
+ }
+
+ int main(void) {
+ printf(",%d,", test(0, 0));
+ printf(",%d,", test(1, 1));
+ printf(",%d,", test(65535, 1));
+ printf(",%d,", test(1, 65535));
+ printf(",%d,", test(32768, 32767));
+ printf(",%d,", test(32768, 32768));
+ return 0;
+ }
+ '''
+ 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>
+
+ extern "C" {
+ extern unsigned short llvm_bswap_i16(unsigned short x);
+ 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);
+ }
+
+ int main(void) {
+ unsigned short x = 0xc8ef;
+ printf("%x,%x\n", x&0xff, x >> 8);
+ x = llvm_bswap_i16(x);
+ printf("%x,%x\n", x&0xff, x >> 8);
+
+ unsigned int y = 0xc5de158a;
+ printf("%x,%x,%x,%x\n", y&0xff, (y>>8)&0xff, (y>>16)&0xff, (y>>24)&0xff);
+ y = llvm_bswap_i32(y);
+ 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;
+ }
+ '''
+ self.do_run(src, '''ef,c8
+c8,ef
+8a,15,de,c5
+c5,de,15,8a
+23,21
+40,10
+5,4
+22
+13
+72057594037927936
+''')
+
+ def test_bswap64(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('needs ta2')
+
+ src = r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ #include <iostream>
+ #include <string>
+ #include <sstream>
+
+ typedef unsigned long long quint64;
+
+ using namespace std;
+
+ inline quint64 qbswap(quint64 source)
+ {
+ return 0
+ | ((source & quint64(0x00000000000000ffLL)) << 56)
+ | ((source & quint64(0x000000000000ff00LL)) << 40)
+ | ((source & quint64(0x0000000000ff0000LL)) << 24)
+ | ((source & quint64(0x00000000ff000000LL)) << 8)
+ | ((source & quint64(0x000000ff00000000LL)) >> 8)
+ | ((source & quint64(0x0000ff0000000000LL)) >> 24)
+ | ((source & quint64(0x00ff000000000000LL)) >> 40)
+ | ((source & quint64(0xff00000000000000LL)) >> 56);
+ }
+
+ int main()
+ {
+ quint64 v = strtoull("4433ffeeddccbb00", NULL, 16);
+ printf("%lld\n", v);
+
+ const string string64bitInt = "4433ffeeddccbb00";
+ stringstream s(string64bitInt);
+ quint64 int64bitInt = 0;
+ printf("1\n");
+ 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;
+ }
+
+ return 0;
+ }
+ '''
+ self.do_run(src, '''4914553019779824384
+1
+2
+bbccddeeff3344
+4433ffeeddccbb00
+4433ffeeddccbb00
+Succeeded!
+''')
+
+ def test_sha1(self):
+ if self.emcc_args == None: return self.skip('needs ta2')
+
+ self.do_run(open(path_from_root('tests', 'sha1.c')).read(), 'SHA1=15dd99a1991e0b3826fede3deffc1feba42278e6')
+
+ def test_cube2md5(self):
+ if self.emcc_args == None: return self.skip('needs emcc')
+ self.emcc_args += ['--embed-file', 'cube2md5.txt']
+ shutil.copyfile(path_from_root('tests', 'cube2md5.txt'), os.path.join(self.get_dir(), 'cube2md5.txt'))
+ self.do_run(open(path_from_root('tests', 'cube2md5.cpp')).read(), open(path_from_root('tests', 'cube2md5.ok')).read())
+
+ def test_cube2hash(self):
+
+ try:
+ old_chunk_size = os.environ.get('EMSCRIPT_MAX_CHUNK_SIZE') or ''
+ os.environ['EMSCRIPT_MAX_CHUNK_SIZE'] = '1' # test splitting out each function to a chunk in emscripten.py (21 functions here)
+
+ # 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),
+ includes=[path_from_root('tests', 'cube2hash')])
+
+ for text, output in [('fleefl', '892BDB6FD3F62E863D63DA55851700FDE3ACF30204798CE9'),
+ ('fleefl2', 'AA2CC5F96FC9D540CA24FDAF1F71E2942753DB83E8A81B61'),
+ ('64bitisslow', '64D8470573635EC354FEE7B7F87C566FCAF1EFB491041670')]:
+ self.do_run('', 'hash value: ' + output, [text], no_build=True)
+ finally:
+ os.environ['EMSCRIPT_MAX_CHUNK_SIZE'] = old_chunk_size
+
+ def test_unaligned(self):
+ if Settings.QUANTUM_SIZE == 1: return self.skip('No meaning to unaligned addresses in q1')
+
+ src = r'''
+ #include<stdio.h>
+
+ struct S {
+ double x;
+ int y;
+ };
+
+ int main() {
+ // the 64-bit value here will not be 8-byte aligned
+ S s0[3] = { {0x12a751f430142, 22}, {0x17a5c85bad144, 98}, {1, 1}};
+ char buffer[10*sizeof(S)];
+ int b = int(buffer);
+ S *s = (S*)(b + 4-b%8);
+ s[0] = s0[0];
+ s[1] = s0[1];
+ s[2] = s0[2];
+
+ printf("*%d : %d : %d\n", sizeof(S), ((unsigned int)&s[0]) % 8 != ((unsigned int)&s[1]) % 8,
+ ((unsigned int)&s[1]) - ((unsigned int)&s[0]));
+ s[0].x++;
+ s[0].y++;
+ s[1].x++;
+ s[1].y++;
+ printf("%.1f,%d,%.1f,%d\n", s[0].x, s[0].y, s[1].x, s[1].y);
+ return 0;
+ }
+ '''
+
+ # TODO: A version of this with int64s as well
+
+ 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
+
+ # Test for undefined behavior in C. This is not legitimate code, but does exist
+
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('No meaning to unaligned addresses without t2')
+
+ src = r'''
+ #include <stdio.h>
+
+ int main()
+ {
+ int x[10];
+ char *p = (char*)&x[0];
+ p++;
+ short *q = (short*)p;
+ *q = 300;
+ printf("*%d:%d*\n", *q, ((int)q)%2);
+ int *r = (int*)p;
+ *r = 515559;
+ printf("*%d*\n", *r);
+ long long *t = (long long*)p;
+ *t = 42949672960;
+ printf("*%Ld*\n", *t);
+ return 0;
+ }
+ '''
+
+ try:
+ self.do_run(src, '*300:1*\n*515559*\n*42949672960*\n')
+ 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)
+ {
+