aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xemcc6
-rw-r--r--src/analyzer.js74
-rw-r--r--src/compiler.js19
-rw-r--r--src/intertyper.js2
-rw-r--r--src/jsifier.js21
-rw-r--r--src/library.js6
-rw-r--r--src/parseTools.js46
-rw-r--r--src/postamble.js4
-rw-r--r--src/preamble.js2
-rw-r--r--src/shell.html5
-rw-r--r--src/shell.js19
-rw-r--r--tests/cases/legalizer_ta2.ll7
-rw-r--r--tests/cases/legalizer_ta2.txt1
-rw-r--r--tests/hello_world.js19
-rw-r--r--tests/hello_world_sdl.cpp3
-rwxr-xr-xtests/runner.py70
-rw-r--r--tools/js-optimizer.js33
-rw-r--r--tools/scons/site_scons/site_tools/emscripten/__init__.py3
-rw-r--r--tools/scons/site_scons/site_tools/emscripten/emscripten.py44
19 files changed, 279 insertions, 105 deletions
diff --git a/emcc b/emcc
index 346b420a..d015d85e 100755
--- a/emcc
+++ b/emcc
@@ -225,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
@@ -780,7 +780,9 @@ try:
if DEBUG: save_intermediate('eliminator')
# js optimizer pre-pass
- js_optimizer_queue += ['simplifyExpressionsPre', 'optimizeShiftsAggressive']
+ js_optimizer_queue += ['simplifyExpressionsPre']
+ if shared.Settings.RELOOP:
+ js_optimizer_queue += ['optimizeShiftsAggressive'] # aggressive shifts optimization requires loops, it breaks on switches
flush_js_optimizer_queue()
final = shared.Building.eliminator(final) # aggressive shifts optimization introduces some new variables, remove ones that we can
if DEBUG: save_intermediate('eliminator')
diff --git a/src/analyzer.js b/src/analyzer.js
index 9aa84650..8ded86f1 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -319,7 +319,8 @@ function analyzer(data, sidePass) {
continue;
}
case 'invoke': {
- // We can't add lines after this, since invoke already modifies control flow. So we handle this in invoke
+ legalizeFunctionParameters(value.params);
+ // We can't add lines after this, since invoke already modifies control flow. So we handle the return in invoke
i++;
continue;
}
@@ -1150,18 +1151,61 @@ function analyzer(data, sidePass) {
}
});
+ function operateOnLabels(line, func) {
+ function process(item, id) {
+ ['label', 'labelTrue', 'labelFalse', 'toLabel', 'unwindLabel', 'defaultLabel'].forEach(function(id) {
+ if (item[id]) {
+ func(item, id);
+ }
+ });
+ }
+ if (line.intertype in BRANCH_INVOKE) {
+ process(line);
+ } else if (line.intertype == 'switch') {
+ process(line);
+ line.switchLabels.forEach(process);
+ }
+ }
+
// Label analyzer
substrate.addActor('LabelAnalyzer', {
processItem: function(item) {
item.functions.forEach(function(func) {
func.labelsDict = {};
func.labelIds = {};
- func.labelIdCounter = 0;
+ func.labelIdsInverse = {};
+ func.labelIds[toNiceIdent('%0')] = 0;
+ func.labelIdsInverse[0] = toNiceIdent('%0');
+ func.labelIdCounter = 1;
func.labels.forEach(function(label) {
- func.labelsDict[label.ident] = label;
func.labelIds[label.ident] = func.labelIdCounter++;
+ func.labelIdsInverse[func.labelIdCounter-1] = label.ident;
+ });
+
+ // Minify label ids to numeric ids.
+ func.labels.forEach(function(label) {
+ label.ident = func.labelIds[label.ident];
+ label.lines.forEach(function(line) {
+ operateOnLabels(line, function(item, id) {
+ item[id] = func.labelIds[item[id]].toString(); // strings, because we will append as we process
+ });
+ });
+ });
+
+ func.labels.forEach(function(label) {
+ func.labelsDict[label.ident] = label;
+ });
+
+ // Correct phis
+ func.labels.forEach(function(label) {
+ label.lines.forEach(function(phi) {
+ if (phi.intertype == 'phi') {
+ for (var i = 0; i < phi.params.length; i++) {
+ phi.params[i].label = func.labelIds[phi.params[i].label];
+ }
+ }
+ });
});
- func.labelIds[toNiceIdent('%0')] = -1; // entry is always -1
func.lines.forEach(function(line) {
if (line.intertype == 'indirectbr') {
@@ -1190,7 +1234,7 @@ function analyzer(data, sidePass) {
if (line.intertype == 'call' && line.ident == setjmp) {
// Add a new label
var oldIdent = label.ident;
- var newIdent = oldIdent + '$$' + i;
+ var newIdent = func.labelIdCounter++;
if (!func.setjmpTable) func.setjmpTable = [];
func.setjmpTable.push([oldIdent, newIdent, line.assignTo]);
func.labels.splice(i+1, 0, {
@@ -1384,22 +1428,6 @@ function analyzer(data, sidePass) {
}
});
- function operateOnLabels(line, func) {
- function process(item, id) {
- ['label', 'labelTrue', 'labelFalse', 'toLabel', 'unwindLabel', 'defaultLabel'].forEach(function(id) {
- if (item[id]) {
- func(item, id);
- }
- });
- }
- if (line.intertype in BRANCH_INVOKE) {
- process(line);
- } else if (line.intertype == 'switch') {
- process(line);
- line.switchLabels.forEach(process);
- }
- }
-
//! @param toLabelId If false, just a dry run - useful to search for labels
function replaceLabels(line, labelIds, toLabelId) {
var ret = [];
@@ -1490,7 +1518,7 @@ function analyzer(data, sidePass) {
label.allOutLabels = [];
});
- // First, find allInLabels
+ // First, find allInLabels. TODO: use typed arrays here to optimize this for memory and speed
var more = true, nextModified, modified = set(getLabelIds(labels));
while (more) {
more = false;
@@ -1541,7 +1569,7 @@ function analyzer(data, sidePass) {
var idCounter = 0;
function makeBlockId(entries) {
idCounter++;
- return entries.join('$') + '$' + idCounter;
+ return '$_$' + idCounter;
}
// There are X main kinds of blocks:
diff --git a/src/compiler.js b/src/compiler.js
index 1876ee1c..134ac5bd 100644
--- a/src/compiler.js
+++ b/src/compiler.js
@@ -19,6 +19,7 @@ var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIR
if (ENVIRONMENT_IS_NODE) {
// Expose functionality in the same simple way that the shells work
+ // Note that we pollute the global namespace here, otherwise we break in node
print = function(x) {
process['stdout'].write(x + '\n');
};
@@ -37,12 +38,16 @@ if (ENVIRONMENT_IS_NODE) {
return ret;
};
+ load = function(f) {
+ globalEval(read(f));
+ };
+
arguments_ = process['argv'].slice(2);
} else if (ENVIRONMENT_IS_SHELL) {
// Polyfill over SpiderMonkey/V8 differences
if (!this['read']) {
- read = function(f) { snarf(f) };
+ this['read'] = function(f) { snarf(f) };
}
if (!this['arguments']) {
@@ -52,11 +57,11 @@ if (ENVIRONMENT_IS_NODE) {
}
} else if (ENVIRONMENT_IS_WEB) {
- print = printErr = function(x) {
+ this['print'] = printErr = function(x) {
console.log(x);
};
- read = function(url) {
+ this['read'] = function(url) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, false);
xhr.send(null);
@@ -69,7 +74,7 @@ if (ENVIRONMENT_IS_NODE) {
} else if (ENVIRONMENT_IS_WORKER) {
// We can do very little here...
- load = importScripts;
+ this['load'] = importScripts;
} else {
throw 'Unknown runtime environment. Where are we?';
@@ -80,17 +85,17 @@ function globalEval(x) {
}
if (typeof load == 'undefined' && typeof read != 'undefined') {
- load = function(f) {
+ this['load'] = function(f) {
globalEval(read(f));
};
}
if (typeof printErr === 'undefined') {
- printErr = function(){};
+ this['printErr'] = function(){};
}
if (typeof print === 'undefined') {
- print = printErr;
+ this['print'] = printErr;
}
// *** Environment setup code ***
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 b93cdf9a..b54aace3 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);
}
@@ -574,7 +574,7 @@ function JSify(data, functionsOnly, givenFunctions) {
if (block.type == 'emulated') {
if (block.labels.length > 1) {
if (block.entries.length == 1) {
- ret += indent + '__label__ = ' + getLabelId(block.entries[0]) + '; ' + (SHOW_LABELS ? '/* ' + block.entries[0] + ' */' : '') + '\n';
+ ret += indent + '__label__ = ' + getLabelId(block.entries[0]) + '; ' + (SHOW_LABELS ? '/* ' + getOriginalLabelId(block.entries[0]) + ' */' : '') + '\n';
} // otherwise, should have been set before!
if (func.setjmpTable) {
var setjmpTable = {};
@@ -591,7 +591,7 @@ function JSify(data, functionsOnly, givenFunctions) {
}
ret += 'switch(__label__) {\n';
ret += block.labels.map(function(label) {
- return indent + ' case ' + getLabelId(label.ident) + ': // ' + label.ident + '\n'
+ return indent + ' case ' + getLabelId(label.ident) + ': ' + (SHOW_LABELS ? '// ' + getOriginalLabelId(label.ident) : '') + '\n'
+ getLabelLines(label, indent + ' ');
}).join('\n');
ret += '\n' + indent + ' default: assert(0, "bad label: " + __label__);\n' + indent + '}';
@@ -770,11 +770,14 @@ function JSify(data, functionsOnly, givenFunctions) {
makeFuncLineActor('deleted', function(item) { return ';' });
- function getLabelId(label) {
+ function getOriginalLabelId(label) {
var funcData = Framework.currItem.funcData;
- var labelIds = funcData.labelIds;
- if (labelIds[label] !== undefined) return labelIds[label];
- return labelIds[label] = funcData.labelIdCounter++;
+ var labelIdsInverse = funcData.labelIdsInverse;
+ return labelIdsInverse[label];
+ }
+
+ function getLabelId(label) {
+ return label;
}
function makeBranch(label, lastLabel, labelIsVariable) {
@@ -788,7 +791,7 @@ function JSify(data, functionsOnly, givenFunctions) {
var trueLabel = parts[1] || '';
var oldLabel = parts[2] || '';
var labelSetting = oldLabel ? '__label__ = ' + getLabelId(oldLabel) + ';' +
- (SHOW_LABELS ? ' /* to: ' + cleanLabel(oldLabel) + ' */' : '') : ''; // TODO: optimize away the setting
+ (SHOW_LABELS ? ' /* to: ' + getOriginalLabelId(cleanLabel(oldLabel)) + ' */' : '') : ''; // TODO: optimize away the setting
if (label[1] == 'R') {
if (label[2] == 'N') { // BRNOL: break, no label setting
labelSetting = '';
@@ -808,7 +811,7 @@ function JSify(data, functionsOnly, givenFunctions) {
}
} else {
if (!labelIsVariable) label = getLabelId(label);
- return pre + '__label__ = ' + label + ';' + (SHOW_LABELS ? ' /* to: ' + cleanLabel(label) + ' */' : '') + ' break;';
+ return pre + '__label__ = ' + label + ';' + (SHOW_LABELS ? ' /* to: ' + getOriginalLabelId(cleanLabel(label)) + ' */' : '') + ' break;';
}
}
diff --git a/src/library.js b/src/library.js
index 817f87e2..74a8a0ac 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 41caeaad..520d278e 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -324,7 +324,7 @@ function parseParamTokens(params) {
ret.push({
intertype: 'value',
type: segment[0].text,
- ident: toNiceIdent(parseNumerical(segment[1].text))
+ ident: toNiceIdent(parseNumerical(segment[1].text, segment[0].text))
});
Types.needAnalysis[removeAllPointing(ret[ret.length-1].type)] = 0;
}
@@ -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');
}
}
@@ -701,8 +701,8 @@ function parseNumerical(value, type) {
// Hexadecimal double value, as the llvm docs say,
// "The one non-intuitive notation for constants is the hexadecimal form of floating point constants."
value = IEEEUnHex(value);
- } else if (type == 'i64' && USE_TYPED_ARRAYS == 2) {
- value = parseI64Constant(value);
+ } else if (USE_TYPED_ARRAYS == 2 && isIllegalType(type)) {
+ return value; // do not parseFloat etc., that can lead to loss of precision
} else if (value == 'null') {
// NULL *is* 0, in C/C++. No JS null! (null == 0 is false, etc.)
value = '0';
@@ -1114,7 +1114,7 @@ function makeCopyValues(dest, src, num, type, modifier, align, sep) {
var oldDest = dest, oldSrc = src;
dest = '$$dest';
src = '$$src';
- return 'for ($$src = ' + oldSrc + ', $$dest = ' + oldDest + ', $$stop = $$src + ' + num + '; $$src < $$stop; $$src++, $$dest++) {\n' +
+ return 'for (var $$src = ' + oldSrc + ', $$dest = ' + oldDest + ', $$stop = $$src + ' + num + '; $$src < $$stop; $$src++, $$dest++) {\n' +
unroll(type, 1) + ' }';
} else { // USE_TYPED_ARRAYS == 2
// If we don't know how to handle this at compile-time, or handling it is best done in a large amount of code, call memset
@@ -1453,7 +1453,7 @@ function finalizeLLVMParameter(param, noIndexizeFunctions) {
if (param.type == 'i64' && USE_TYPED_ARRAYS == 2) {
ret = parseI64Constant(ret);
}
- ret = parseNumerical(ret);
+ ret = parseNumerical(ret, param.type);
} else if (param.intertype == 'structvalue') {
ret = makeLLVMStruct(param.params.map(function(value) { return finalizeLLVMParameter(value, noIndexizeFunctions) }));
} else if (param.intertype === 'blockaddress') {
@@ -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/preamble.js b/src/preamble.js
index 45d2f4b2..98d12a43 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -583,7 +583,7 @@ var FUNCTION_TABLE; // XXX: In theory the indexes here can be equal to pointers
var PAGE_SIZE = 4096;
function alignMemoryPage(x) {
- return Math.ceil(x/PAGE_SIZE)*PAGE_SIZE;
+ return ((x+4095)>>12)<<12;
}
var HEAP;
diff --git a/src/shell.html b/src/shell.html
index 69217b18..a41086b9 100644
--- a/src/shell.html
+++ b/src/shell.html
@@ -19,7 +19,10 @@
print: (function() {
var element = document.getElementById('output');
return function(text) {
- element.innerHTML += text.replace('\n', '<br>', 'g') + '<br>';
+ 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/src/shell.js b/src/shell.js
index d67cc45a..bc527192 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -11,6 +11,7 @@ var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIR
if (ENVIRONMENT_IS_NODE) {
// Expose functionality in the same simple way that the shells work
+ // Note that we pollute the global namespace here, otherwise we break in node
print = function(x) {
process['stdout'].write(x + '\n');
};
@@ -29,12 +30,16 @@ if (ENVIRONMENT_IS_NODE) {
return ret;
};
+ load = function(f) {
+ globalEval(read(f));
+ };
+
arguments_ = process['argv'].slice(2);
} else if (ENVIRONMENT_IS_SHELL) {
// Polyfill over SpiderMonkey/V8 differences
if (!this['read']) {
- read = function(f) { snarf(f) };
+ this['read'] = function(f) { snarf(f) };
}
if (!this['arguments']) {
@@ -44,11 +49,11 @@ if (ENVIRONMENT_IS_NODE) {
}
} else if (ENVIRONMENT_IS_WEB) {
- print = printErr = function(x) {
+ this['print'] = printErr = function(x) {
console.log(x);
};
- read = function(url) {
+ this['read'] = function(url) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, false);
xhr.send(null);
@@ -61,7 +66,7 @@ if (ENVIRONMENT_IS_NODE) {
} else if (ENVIRONMENT_IS_WORKER) {
// We can do very little here...
- load = importScripts;
+ this['load'] = importScripts;
} else {
throw 'Unknown runtime environment. Where are we?';
@@ -72,17 +77,17 @@ function globalEval(x) {
}
if (typeof load == 'undefined' && typeof read != 'undefined') {
- load = function(f) {
+ this['load'] = function(f) {
globalEval(read(f));
};
}
if (typeof printErr === 'undefined') {
- printErr = function(){};
+ this['printErr'] = function(){};
}
if (typeof print === 'undefined') {
- print = printErr;
+ this['print'] = printErr;
}
// *** Environment setup code ***
diff --git a/tests/cases/legalizer_ta2.ll b/tests/cases/legalizer_ta2.ll
index ae6e9b0c..7e17c707 100644
--- a/tests/cases/legalizer_ta2.ll
+++ b/tests/cases/legalizer_ta2.ll
@@ -4,7 +4,10 @@ target triple = "i386-pc-linux-gnu"
@globaliz = global [300 x i8] zeroinitializer
-define i64 @retter() {
+define i64 @retter(i64 %x) {
+ store i104 0, i104* bitcast ([300 x i8]* @globaliz to i104*), align 4 ; wipe it out
+ store i64 %x, i64* bitcast ([300 x i8]* @globaliz to i64*), align 4
+ call i32 (i8*)* @puts(i8* bitcast ([300 x i8]* @globaliz to i8*))
ret i64 7017280452245743464
}
@@ -152,7 +155,7 @@ a40:
; invoke return value
- %inv64 = invoke i64 @retter()
+ %inv64 = invoke i64 @retter(i64 8174723217654970232)
to label %a100 unwind label %a111
a100:
diff --git a/tests/cases/legalizer_ta2.txt b/tests/cases/legalizer_ta2.txt
index 0075107d..796ee240 100644
--- a/tests/cases/legalizer_ta2.txt
+++ b/tests/cases/legalizer_ta2.txt
@@ -18,6 +18,7 @@ hello, wor
hello, worl
9
hello, war`d
+xwvutsrq
hgfedcba
hello, world
hello, w
diff --git a/tests/hello_world.js b/tests/hello_world.js
index e6fcf070..766e848e 100644
--- a/tests/hello_world.js
+++ b/tests/hello_world.js
@@ -8,6 +8,7 @@ var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIR
if (ENVIRONMENT_IS_NODE) {
// Expose functionality in the same simple way that the shells work
+ // Note that we pollute the global namespace here, otherwise we break in node
print = function(x) {
process['stdout'].write(x + '\n');
};
@@ -26,12 +27,16 @@ if (ENVIRONMENT_IS_NODE) {
return ret;
};
+ load = function(f) {
+ globalEval(read(f));
+ };
+
arguments_ = process['argv'].slice(2);
} else if (ENVIRONMENT_IS_SHELL) {
// Polyfill over SpiderMonkey/V8 differences
if (!this['read']) {
- read = function(f) { snarf(f) };
+ this['read'] = function(f) { snarf(f) };
}
if (!this['arguments']) {
@@ -41,11 +46,11 @@ if (ENVIRONMENT_IS_NODE) {
}
} else if (ENVIRONMENT_IS_WEB) {
- print = printErr = function(x) {
+ this['print'] = printErr = function(x) {
console.log(x);
};
- read = function(url) {
+ this['read'] = function(url) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, false);
xhr.send(null);
@@ -58,7 +63,7 @@ if (ENVIRONMENT_IS_NODE) {
} else if (ENVIRONMENT_IS_WORKER) {
// We can do very little here...
- load = importScripts;
+ this['load'] = importScripts;
} else {
throw 'Unknown runtime environment. Where are we?';
@@ -69,17 +74,17 @@ function globalEval(x) {
}
if (typeof load == 'undefined' && typeof read != 'undefined') {
- load = function(f) {
+ this['load'] = function(f) {
globalEval(read(f));
};
}
if (typeof printErr === 'undefined') {
- printErr = function(){};
+ this['printErr'] = function(){};
}
if (typeof print === 'undefined') {
- print = printErr;
+ this['print'] = printErr;
}
// *** Environment setup code ***
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 3b295ed2..e8bcb72e 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')
@@ -5851,7 +5920,6 @@ Options that are modifi