aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS3
-rwxr-xr-xemcc27
-rw-r--r--src/intertyper.js2
-rw-r--r--src/jsifier.js7
-rw-r--r--src/library.js6
-rw-r--r--src/parseTools.js36
-rw-r--r--src/postamble.js4
-rw-r--r--src/shell.html6
-rw-r--r--tests/hello_world_sdl.cpp3
-rwxr-xr-xtests/runner.py77
-rw-r--r--tools/scons/site_scons/site_tools/emscripten/__init__.py3
-rw-r--r--tools/scons/site_scons/site_tools/emscripten/emscripten.py44
12 files changed, 178 insertions, 40 deletions
diff --git a/AUTHORS b/AUTHORS
index c9b0d861..4b6ab060 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -14,5 +14,4 @@ under the licensing terms detailed in LICENSE.
* Julien Hamaide <julien.hamaide@gmail.com>
* Ehsan Akhgari <ehsan.akhgari@gmail.com> (copyright owned by Mozilla Foundation)
* Adrian Taylor <adrian@macrobug.com>
-
-
+* Richard Assar <richard.assar@gmail.com>
diff --git a/emcc b/emcc
index 630c2504..d015d85e 100755
--- a/emcc
+++ b/emcc
@@ -74,10 +74,19 @@ emcc can be influenced by a few environment variables:
EMMAKEN_COMPILER - The compiler to be used, if you don't want the default clang.
'''
-import os, sys, shutil, tempfile
-from subprocess import Popen, PIPE, STDOUT
+import os, sys, shutil, tempfile, subprocess
+from subprocess import PIPE, STDOUT
from tools import shared
+def execute(cmd, *args, **kw):
+ try:
+ return subprocess.Popen(cmd, *args, **kw).communicate() # let compiler frontend print directly, so colors are saved (PIPE kills that)
+ except:
+ if not isinstance(cmd, str):
+ cmd = ' '.join(cmd)
+ print >> sys.stderr, 'Invoking Process failed: <<< ' + cmd + ' >>>'
+ raise
+
# Mapping of emcc opt levels to llvm opt levels. We use llvm opt level 3 in emcc opt
# levels 2 and 3 (emcc 3 is unsafe opts, so unsuitable for the only level to get
# llvm opt level 3, and speed-wise emcc level 2 is already the slowest/most optimizing
@@ -216,7 +225,7 @@ be generated:
<name>.js JavaScript (default)
<name>.html HTML with embedded JavaScript
<name>.bc LLVM bitcode
- <name>.o LLVM bitcode
+ <name>.o LLVM bitcode (same as .bc)
The -c option (which tells gcc not to run the linker) will
cause LLVM bitcode to be generated, as %s only generates
@@ -517,7 +526,7 @@ try:
temp_files.append(output_file)
args = newargs + ['-emit-llvm', '-c', input_file, '-o', output_file]
if DEBUG: print >> sys.stderr, "emcc running:", call, ' '.join(args)
- Popen([call] + args).communicate() # let compiler frontend print directly, so colors are saved (PIPE kills that)
+ execute([call] + args) # let compiler frontend print directly, so colors are saved (PIPE kills that)
if not os.path.exists(output_file):
print >> sys.stderr, 'emcc: compiler frontend failed to generate LLVM bitcode, halting'
sys.exit(1)
@@ -560,7 +569,7 @@ try:
ld_args = temp_files + ['-b', specified_target]
#[arg.split('-Wl,')[1] for arg in filter(lambda arg: arg.startswith('-Wl,'), sys.argv)]
if DEBUG: print >> sys.stderr, 'emcc: link: ' + str(ld_args)
- Popen([shared.LLVM_LD, '-disable-opt'] + ld_args).communicate()
+ execute([shared.LLVM_LD, '-disable-opt'] + ld_args)
exit(0)
## Continue on to create JavaScript
@@ -578,9 +587,9 @@ try:
# dlmalloc
def create_dlmalloc():
if DEBUG: print >> sys.stderr, 'emcc: building dlmalloc for cache'
- Popen([shared.EMCC, shared.path_from_root('system', 'lib', 'dlmalloc.c'), '-g', '-o', in_temp('dlmalloc.o')], stdout=stdout, stderr=stderr).communicate()
+ execute([shared.EMCC, shared.path_from_root('system', 'lib', 'dlmalloc.c'), '-g', '-o', in_temp('dlmalloc.o')], stdout=stdout, stderr=stderr)
# we include the libc++ new stuff here, so that the common case of using just new/delete is quick to link
- Popen([shared.EMXX, shared.path_from_root('system', 'lib', 'libcxx', 'new.cpp'), '-g', '-o', in_temp('new.o')], stdout=stdout, stderr=stderr).communicate()
+ execute([shared.EMXX, shared.path_from_root('system', 'lib', 'libcxx', 'new.cpp'), '-g', '-o', in_temp('new.o')], stdout=stdout, stderr=stderr)
shared.Building.link([in_temp('dlmalloc.o'), in_temp('new.o')], in_temp('dlmalloc_full.o'))
return in_temp('dlmalloc_full.o')
def fix_dlmalloc():
@@ -702,7 +711,7 @@ try:
if AUTODEBUG:
if DEBUG: print >> sys.stderr, 'emcc: autodebug'
- Popen(['python', shared.AUTODEBUGGER, final, final + '.ad.ll']).communicate()[0]
+ execute(['python', shared.AUTODEBUGGER, final, final + '.ad.ll'])
final += '.ad.ll'
if DEBUG: save_intermediate('autodebug', 'll')
@@ -735,7 +744,7 @@ try:
shutil.copyfile(final, final + '.tr.js')
final += '.tr.js'
if DEBUG: print >> sys.stderr, 'emcc: applying transform: %s' % js_transform
- Popen(js_transform.split(' ') + [os.path.abspath(final)]).communicate()
+ execute(js_transform.split(' ') + [os.path.abspath(final)])
if DEBUG: save_intermediate('transformed')
# It is useful to run several js optimizer passes together, to save on unneeded unparsing/reparsing
diff --git a/src/intertyper.js b/src/intertyper.js
index bd7b70f9..c5a9583b 100644
--- a/src/intertyper.js
+++ b/src/intertyper.js
@@ -334,6 +334,8 @@ function intertyper(data, sidePass, baseLineNums) {
return 'Phi';
if (tokensLength >= 3 && token0Text == 'landingpad')
return 'Landingpad';
+ if (token0Text == 'fence')
+ return '/dev/null';
} else if (item.indent === 0) {
if ((tokensLength >= 1 && token0Text.substr(-1) == ':') ||
(tokensLength >= 3 && token1Text == '<label>'))
diff --git a/src/jsifier.js b/src/jsifier.js
index d4d57fc6..5ad1573b 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -229,7 +229,7 @@ function JSify(data, functionsOnly, givenFunctions) {
return makeEmptyStruct(type);
} else if (value.intertype === 'string') {
return JSON.stringify(parseLLVMString(value.text)) +
- ' /* ' + value.text.substr(0, 20).replace(/\*/g, '_') + ' */'; // make string safe for inclusion in comment
+ ' /* ' + value.text.substr(0, 20).replace(/[*<>]/g, '_') + ' */'; // make string safe for inclusion in comment
} else {
return alignStruct(handleSegments(value.contents), type);
}
@@ -921,13 +921,16 @@ function JSify(data, functionsOnly, givenFunctions) {
});
var ret = '';
var first = true;
+ var signedIdent = makeSignOp(item.ident, item.type, 're'); // we need to standardize for purpose of comparison
for (var targetLabel in targetLabels) {
if (!first) {
ret += 'else ';
} else {
first = false;
}
- ret += 'if (' + targetLabels[targetLabel].map(function(value) { return makeComparison(item.ident, value, item.type) }).join(' || ') + ') {\n';
+ ret += 'if (' + targetLabels[targetLabel].map(function(value) {
+ return makeComparison(signedIdent, makeSignOp(value, item.type, 're'), item.type)
+ }).join(' || ') + ') {\n';
ret += ' ' + getPhiSetsForLabel(phiSets, targetLabel) + makeBranch(targetLabel, item.currLabelId || null) + '\n';
ret += '}\n';
}
diff --git a/src/library.js b/src/library.js
index 9603e1a8..86897f11 100644
--- a/src/library.js
+++ b/src/library.js
@@ -5183,7 +5183,7 @@ LibraryManager.library = {
var dst = Number(start.getTimezoneOffset() != date.getTimezoneOffset());
{{{ makeSetValue('tmPtr', 'offsets.tm_isdst', 'dst', 'i32') }}}
- var timezone = date.toString().match(/\(([A-Z]+)\)/)[1];
+ var timezone = 'GMT'; // XXX do not rely on browser timezone info, it is very unpredictable | date.toString().match(/\(([A-Z]+)\)/)[1];
if (!(timezone in ___tm_timezones)) {
___tm_timezones[timezone] = allocate(intArrayFromString(timezone), 'i8', ALLOC_NORMAL);
}
@@ -5245,8 +5245,8 @@ LibraryManager.library = {
var summer = new Date(2000, 6, 1);
{{{ makeSetValue('__daylight', '0', 'Number(winter.getTimezoneOffset() != summer.getTimezoneOffset())', 'i32') }}}
- var winterName = winter.toString().match(/\(([A-Z]+)\)/)[1];
- var summerName = summer.toString().match(/\(([A-Z]+)\)/)[1];
+ var winterName = 'GMT'; // XXX do not rely on browser timezone info, it is very unpredictable | winter.toString().match(/\(([A-Z]+)\)/)[1];
+ var summerName = 'GMT'; // XXX do not rely on browser timezone info, it is very unpredictable | summer.toString().match(/\(([A-Z]+)\)/)[1];
var winterNamePtr = allocate(intArrayFromString(winterName), 'i8', ALLOC_NORMAL);
var summerNamePtr = allocate(intArrayFromString(summerName), 'i8', ALLOC_NORMAL);
__tzname = _malloc(2 * {{{ Runtime.QUANTUM_SIZE }}}); // glibc does not need the double __
diff --git a/src/parseTools.js b/src/parseTools.js
index ff578c0a..520d278e 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -559,12 +559,12 @@ function splitI64(value) {
return makeInlineCalculation(makeI64('VALUE>>>0', 'Math.min(Math.floor(VALUE/4294967296), 4294967295)'), value, 'tempBigIntP');
}
}
-function mergeI64(value) {
+function mergeI64(value, unsigned) {
assert(USE_TYPED_ARRAYS == 2);
if (legalizedI64s) {
- return RuntimeGenerator.makeBigInt(value + '$0', value + '$1');
+ return RuntimeGenerator.makeBigInt(value + '$0', value + '$1', unsigned);
} else {
- return makeInlineCalculation(RuntimeGenerator.makeBigInt('VALUE[0]', 'VALUE[1]'), value, 'tempI64');
+ return makeInlineCalculation(RuntimeGenerator.makeBigInt('VALUE[0]', 'VALUE[1]', unsigned), value, 'tempI64');
}
}
@@ -1672,22 +1672,22 @@ function processMathop(item) {
case 'fptoui': case 'fptosi': return finish(splitI64(idents[0]));
case 'icmp': {
switch (variant) {
- case 'uge': return high1 + ' >= ' + high2 + ' && (' + high1 + ' > ' + high2 + ' || ' +
- low1 + ' >= ' + low2 + ')';
+ case 'uge': return '(' + high1 + '>>>0) >= (' + high2 + '>>>0) && ((' + high1 + '>>>0) > (' + high2 + '>>>0) || ' +
+ '(' + low1 + '>>>0) >= (' + low2 + '>>>0))';
case 'sge': return '(' + high1 + '|0) >= (' + high2 + '|0) && ((' + high1 + '|0) > (' + high2 + '|0) || ' +
- '(' + low1 + '|0) >= (' + low2 + '|0))';
- case 'ule': return high1 + ' <= ' + high2 + ' && (' + high1 + ' < ' + high2 + ' || ' +
- low1 + ' <= ' + low2 + ')';
+ '(' + low1 + '>>>0) >= (' + low2 + '>>>0))';
+ case 'ule': return '(' + high1 + '>>>0) <= (' + high2 + '>>>0) && ((' + high1 + '>>>0) < (' + high2 + '>>>0) || ' +
+ '(' + low1 + '>>>0) <= (' + low2 + '>>>0))';
case 'sle': return '(' + high1 + '|0) <= (' + high2 + '|0) && ((' + high1 + '|0) < (' + high2 + '|0) || ' +
- '(' + low1 + '|0) <= (' + low2 + '|0))';
- case 'ugt': return high1 + ' > ' + high2 + ' || (' + high1 + ' == ' + high2 + ' && ' +
- low1 + ' > ' + low2 + ')';
+ '(' + low1 + '>>>0) <= (' + low2 + '>>>0))';
+ case 'ugt': return '(' + high1 + '>>>0) > (' + high2 + '>>>0) || ((' + high1 + '>>>0) == (' + high2 + '>>>0) && ' +
+ '(' + low1 + '>>>0) > (' + low2 + '>>>0))';
case 'sgt': return '(' + high1 + '|0) > (' + high2 + '|0) || ((' + high1 + '|0) == (' + high2 + '|0) && ' +
- '(' + low1 + '|0) > (' + low2 + '|0))';
- case 'ult': return high1 + ' < ' + high2 + ' || (' + high1 + ' == ' + high2 + ' && ' +
- low1 + ' < ' + low2 + ')';
+ '(' + low1 + '>>>0) > (' + low2 + '>>>0))';
+ case 'ult': return '(' + high1 + '>>>0) < (' + high2 + '>>>0) || ((' + high1 + '>>>0) == (' + high2 + '>>>0) && ' +
+ '(' + low1 + '>>>0) < (' + low2 + '>>>0))';
case 'slt': return '(' + high1 + '|0) < (' + high2 + '|0) || ((' + high1 + '|0) == (' + high2 + '|0) && ' +
- '(' + low1 + '|0) < (' + low2 + '|0))';
+ '(' + low1 + '>>>0) < (' + low2 + '>>>0))';
case 'ne': return low1 + ' != ' + low2 + ' || ' + high1 + ' != ' + high2 + '';
case 'eq': return low1 + ' == ' + low2 + ' && ' + high1 + ' == ' + high2 + '';
default: throw 'Unknown icmp variant: ' + variant;
@@ -1704,9 +1704,9 @@ function processMathop(item) {
// Dangerous, rounded operations. TODO: Fully emulate
case 'add': warnI64_1(); return finish(splitI64(mergeI64(idents[0]) + '+' + mergeI64(idents[1])));
case 'sub': warnI64_1(); return finish(splitI64(mergeI64(idents[0]) + '-' + mergeI64(idents[1])));
- case 'sdiv': case 'udiv': warnI64_1(); return finish(splitI64(makeRounding(mergeI64(idents[0]) + '/' + mergeI64(idents[1]), bits, op[0] === 's')));
- case 'mul': warnI64_1(); return finish(splitI64(mergeI64(idents[0]) + '*' + mergeI64(idents[1])));
- case 'urem': case 'srem': warnI64_1(); return finish(splitI64(mergeI64(idents[0]) + '%' + mergeI64(idents[1])));
+ case 'sdiv': case 'udiv': warnI64_1(); return finish(splitI64(makeRounding(mergeI64(idents[0], op[0] === 'u') + '/' + mergeI64(idents[1], op[0] === 'u'), bits, op[0] === 's')));
+ case 'mul': warnI64_1(); return finish(splitI64(mergeI64(idents[0], op[0] === 'u') + '*' + mergeI64(idents[1], op[0] === 'u')));
+ case 'urem': case 'srem': warnI64_1(); return finish(splitI64(mergeI64(idents[0], op[0] === 'u') + '%' + mergeI64(idents[1], op[0] === 'u')));
case 'bitcast': {
// Pointers are not 64-bit, so there is really only one possible type of bitcast here, int to float or vice versa
assert(USE_TYPED_ARRAYS == 2, 'Can only bitcast ints <-> floats with typed arrays mode 2');
diff --git a/src/postamble.js b/src/postamble.js
index 390f9f27..56f0aee1 100644
--- a/src/postamble.js
+++ b/src/postamble.js
@@ -37,7 +37,9 @@ function run(args) {
var ret = null;
if (Module['_main']) {
ret = Module.callMain(args);
- exitRuntime();
+ if (!Module['noExitRuntime']) {
+ exitRuntime();
+ }
}
return ret;
}
diff --git a/src/shell.html b/src/shell.html
index 69217b18..2f34ace3 100644
--- a/src/shell.html
+++ b/src/shell.html
@@ -19,7 +19,11 @@
print: (function() {
var element = document.getElementById('output');
return function(text) {
- element.innerHTML += text.replace('\n', '<br>', 'g') + '<br>';
+ text = text.replace(/&/g, "&amp;");
+ text = text.replace(/</g, "&lt;");
+ text = text.replace(/>/g, "&gt;");
+ text = text.replace('\n', '<br>', 'g');
+ element.innerHTML += text + '<br>';
};
})(),
canvas: document.getElementById('canvas')
diff --git a/tests/hello_world_sdl.cpp b/tests/hello_world_sdl.cpp
index df69b055..35aec303 100644
--- a/tests/hello_world_sdl.cpp
+++ b/tests/hello_world_sdl.cpp
@@ -20,7 +20,8 @@ int main() {
if (SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen);
SDL_Flip(screen);
- printf("you should see a colored cube.");
+ printf("you should see a colored cube.\n");
+ printf("and here is some text that should be HTML-friendly: amp: |&| double-quote: |\"| quote: |'| less-than, greater-than, html-like tags: |<cheez></cheez>|\nanother line.\n");
SDL_Quit();
diff --git a/tests/runner.py b/tests/runner.py
index 3e31127b..51b9e357 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -689,6 +689,51 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv):
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'''
@@ -731,6 +776,30 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv):
'''
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_unaligned(self):
if Settings.QUANTUM_SIZE == 1: return self.skip('No meaning to unaligned addresses in q1')
@@ -2229,18 +2298,20 @@ def process(filename):
case 'b':
case 'c':
return p-1;
- case 'd':
+ case 0xfffffff1:
return p+1;
}
return p;
}
int main( int argc, const char *argv[] ) {
- printf("*%d,%d,%d,%d,%d*\\n", switcher('a'), switcher('b'), switcher('c'), switcher('d'), switcher('e'));
+ unsigned int x = 0xfffffff1;
+ x >>= 0; // force it to be unsigned for purpose of checking our switch comparison in signed/unsigned
+ printf("*%d,%d,%d,%d,%d,%d*\\n", switcher('a'), switcher('b'), switcher('c'), switcher(x), switcher(-15), switcher('e'));
return 0;
}
'''
- self.do_run(src, '*96,97,98,101,101*')
+ self.do_run(src, '*96,97,98,-14,-14,101*')
def test_indirectbr(self):
src = '''
diff --git a/tools/scons/site_scons/site_tools/emscripten/__init__.py b/tools/scons/site_scons/site_tools/emscripten/__init__.py
new file mode 100644
index 00000000..8ae2288e
--- /dev/null
+++ b/tools/scons/site_scons/site_tools/emscripten/__init__.py
@@ -0,0 +1,3 @@
+#!/usr/bin/env python
+
+from emscripten import exists, generate
diff --git a/tools/scons/site_scons/site_tools/emscripten/emscripten.py b/tools/scons/site_scons/site_tools/emscripten/emscripten.py
new file mode 100644
index 00000000..cb14b58e
--- /dev/null
+++ b/tools/scons/site_scons/site_tools/emscripten/emscripten.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+import os
+
+def generate(env, emscripten_path=None, **kw):
+ """ SCons tool entry point """
+
+ if emscripten_path is None:
+ # Try to find emscripten
+ # Use same method as Emscripten's shared.py
+ EM_CONFIG = os.environ.get('EM_CONFIG')
+ if not EM_CONFIG:
+ EM_CONFIG = '~/.emscripten'
+
+ CONFIG_FILE = os.path.expanduser(EM_CONFIG)
+ try:
+ exec(open(CONFIG_FILE, 'r').read())
+ except Exception, e:
+ print >> sys.stderr, 'Error in evaluating %s (at %s): %s' % (EM_CONFIG, CONFIG_FILE, str(e))
+ sys.exit(1)
+
+ emscripten_path = EMSCRIPTEN_ROOT
+
+ try:
+ emscPath = emscripten_path.abspath
+ except:
+ emscPath = emscripten_path
+
+ env.Replace(CC = os.path.join(emscPath, "emcc" ))
+ env.Replace(CXX = os.path.join(emscPath, "em++" ))
+ env.Replace(LINK = os.path.join(emscPath, "emld" ))
+ # SHLINK and LDMODULE should use LINK so no
+ # need to change them here
+
+ env.Replace(AR = os.path.join(emscPath, "emar" ))
+ env.Replace(RANLIB = os.path.join(emscPath, "emranlib"))
+
+ env.Replace(OBJSUFFIX = [".js", ".bc", ".o"][2])
+ env.Replace(LIBSUFFIX = [".js", ".bc", ".o"][2])
+ env.Replace(PROGSUFFIX = [".html", ".js" ][1])
+
+def exists(env):
+ """ NOOP method required by SCons """
+ return 1