diff options
-rwxr-xr-x | emcc | 9 | ||||
-rw-r--r-- | src/intertyper.js | 13 | ||||
-rw-r--r-- | src/jsifier.js | 70 | ||||
-rw-r--r-- | src/library.js | 8 | ||||
-rw-r--r-- | src/library_gl.js | 3 | ||||
-rw-r--r-- | src/modules.js | 8 | ||||
-rw-r--r-- | src/parseTools.js | 52 | ||||
-rw-r--r-- | src/preamble.js | 22 | ||||
-rw-r--r-- | src/preamble_sharedlib.js | 1 | ||||
-rw-r--r-- | src/settings.js | 4 | ||||
-rw-r--r-- | src/utility.js | 8 | ||||
-rw-r--r-- | tests/cases/gepoverflow.txt | 2 | ||||
-rw-r--r-- | tests/cases/subnums.ll | 2 | ||||
-rw-r--r-- | tests/gl_subdata.cpp | 141 | ||||
-rwxr-xr-x | tests/runner.py | 103 | ||||
-rw-r--r-- | tools/shared.py | 4 |
16 files changed, 376 insertions, 74 deletions
@@ -335,7 +335,11 @@ Options that are modified or new in %s include: builds - where you are compiling a large program but only modified a small part of it - to be much faster (at the cost of more disk - IO for cache accesses). + IO for cache accesses). Note that you need + to enable --jcache for both loading and saving + of data, so you must enable it on a full build + for a later incremental build (where you also + enable it) to be sped up. --clear-cache Manually clears the cache of compiled emscripten system libraries (libc++, @@ -772,7 +776,8 @@ try: else: print >> sys.stderr, 'emcc: %s: warning: Not valid LLVM bitcode' % arg else: - print >> sys.stderr, 'emcc: %s: warning: No such file or directory' % arg + print >> sys.stderr, 'emcc: %s: error: No such file or directory' % arg + exit(1) elif arg.startswith('-L'): lib_dirs.append(arg[2:]) newargs[i] = '' diff --git a/src/intertyper.js b/src/intertyper.js index 8e7bb418..7db1a2fe 100644 --- a/src/intertyper.js +++ b/src/intertyper.js @@ -73,13 +73,11 @@ function intertyper(data, sidePass, baseLineNums) { if (!testType) { var global = /([@%\w\d\.\" $-]+) = .*/.exec(line); var globalIdent = toNiceIdent(global[1]); - var testAlias = /[@%\w\d\.\" $-]+ = alias .*/.exec(line); - var testString = /[@%\w\d\.\" $-]+ = [\w ]+ \[\d+ x i8] c".*/.exec(line); + var testAlias = /[@%\w\d\.\" $-]+ = (hidden )?alias .*/.exec(line); Variables.globals[globalIdent] = { name: globalIdent, alias: !!testAlias, - impl: VAR_EMULATED, - isString : !!testString + impl: VAR_EMULATED }; unparsedGlobals.lines.push(line); } else { @@ -459,6 +457,9 @@ function intertyper(data, sidePass, baseLineNums) { }; ret.type = ret.value.type; Types.needAnalysis[ret.type] = 0; + if (!NAMED_GLOBALS) { + Variables.globals[ret.ident].type = ret.type; + } return [ret]; } if (item.tokens[2].text == 'type') { @@ -509,6 +510,10 @@ function intertyper(data, sidePass, baseLineNums) { private_: private_, lineNum: item.lineNum }; + if (!NAMED_GLOBALS) { + Variables.globals[ret.ident].type = ret.type; + Variables.globals[ret.ident].external = external; + } Types.needAnalysis[ret.type] = 0; if (ident == '@llvm.global_ctors') { ret.ctors = []; diff --git a/src/jsifier.js b/src/jsifier.js index 595e057c..ce094e1e 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -217,7 +217,7 @@ function JSify(data, functionsOnly, givenFunctions) { throw 'Invalid segment: ' + dump(segment); } assert(segment.type, 'Missing type for constant segment!'); - return indexizeFunctions(ret, segment.type); + return makeGlobalUse(indexizeFunctions(ret, segment.type)); }; return tokens.map(handleSegment) } @@ -226,7 +226,7 @@ function JSify(data, functionsOnly, givenFunctions) { if (value.intertype in PARSABLE_LLVM_FUNCTIONS) { return [finalizeLLVMFunctionCall(value)]; } else if (Runtime.isNumberType(type) || pointingLevels(type) >= 1) { - return indexizeFunctions(parseNumerical(value.value), type); + return makeGlobalUse(indexizeFunctions(parseNumerical(value.value), type)); } else if (value.intertype === 'emptystruct') { return makeEmptyStruct(type); } else if (value.intertype === 'string') { @@ -250,7 +250,7 @@ function JSify(data, functionsOnly, givenFunctions) { processItem: function(item) { function needsPostSet(value) { return value[0] in UNDERSCORE_OPENPARENS || value.substr(0, 14) === 'CHECK_OVERFLOW' - || value.substr(0, 13) === 'STRING_TABLE.'; + || value.substr(0, 6) === 'GLOBAL'; } item.intertype = 'GlobalVariableStub'; @@ -262,16 +262,17 @@ function JSify(data, functionsOnly, givenFunctions) { '\n]);\n'; return ret; } else { + var constant = null; + var allocator = (BUILD_AS_SHARED_LIB && !item.external) ? 'ALLOC_NORMAL' : 'ALLOC_STATIC'; + var index = null; if (item.external && BUILD_AS_SHARED_LIB) { // External variables in shared libraries should not be declared as // they would shadow similarly-named globals in the parent. item.JS = ''; } else { - if (!(item.ident in Variables.globals) || !Variables.globals[item.ident].isString) { - item.JS = 'var ' + item.ident + ';'; - } + item.JS = makeGlobalDef(item.ident); } - var constant = null; + if (item.external) { // Import external global variables from the library if available. var shortident = item.ident.slice(1); @@ -286,7 +287,7 @@ function JSify(data, functionsOnly, givenFunctions) { padding = makeEmptyStruct(item.type); } var padded = val.concat(padding.slice(val.length)); - var js = item.ident + '=' + makePointer(JSON.stringify(padded), null, 'ALLOC_STATIC', item.type) + ';' + var js = item.ident + '=' + makePointer(JSON.stringify(padded), null, allocator, item.type, index) + ';' if (LibraryManager.library[shortident + '__postset']) { js += '\n' + LibraryManager.library[shortident + '__postset']; } @@ -297,6 +298,10 @@ function JSify(data, functionsOnly, givenFunctions) { } return ret; } else { + if (!NAMED_GLOBALS && isIndexableGlobal(item.ident)) { + index = makeGlobalUse(item.ident); // index !== null indicates we are indexing this + allocator = 'ALLOC_NONE'; + } constant = parseConst(item.value, item.type, item.ident); if (typeof constant === 'string' && constant[0] != '[') { constant = [constant]; // A single item. We may need a postset for it. @@ -307,7 +312,7 @@ function JSify(data, functionsOnly, givenFunctions) { if (needsPostSet(value)) { // ident, or expression containing an ident ret.push({ intertype: 'GlobalVariablePostSet', - JS: makeSetValue(item.ident, i, value, 'i32', false, true) + ';' // ignore=true, since e.g. rtti and statics cause lots of safe_heap errors + JS: makeSetValue(makeGlobalUse(item.ident), i, value, 'i32', false, true) + ';' // ignore=true, since e.g. rtti and statics cause lots of safe_heap errors }); constant[i] = '0'; } @@ -316,21 +321,17 @@ function JSify(data, functionsOnly, givenFunctions) { } // NOTE: This is the only place that could potentially create static // allocations in a shared library. - constant = makePointer(constant, null, BUILD_AS_SHARED_LIB ? 'ALLOC_NORMAL' : 'ALLOC_STATIC', item.type); - + constant = makePointer(constant, null, allocator, item.type, index); var js; - // Strings are held in STRING_TABLE, to not clutter up the main namespace (in some cases we have - // many many strings, possibly exceeding the js engine limit on global vars). - if (Variables.globals[item.ident].isString) { - js = 'STRING_TABLE.' + item.ident + '=' + constant + ';'; - } else { - js = item.ident + '=' + constant + ';'; - } + js = (index !== null ? '' : item.ident + '=') + constant + ';'; // \n Module.print("' + item.ident + ' :" + ' + makeGlobalUse(item.ident) + ');'; // Special case: class vtables. We make sure they are null-terminated, to allow easy runtime operations if (item.ident.substr(0, 5) == '__ZTV') { - js += '\n' + makePointer('[0]', null, BUILD_AS_SHARED_LIB ? 'ALLOC_NORMAL' : 'ALLOC_STATIC', ['void*']) + ';'; + if (index !== null) { + index = getFastValue(index, '+', Runtime.alignMemory(calcAllocatedSize(Variables.globals[item.ident].type))); + } + js += '\n' + makePointer('[0]', null, allocator, ['void*'], index) + ';'; } if (EXPORT_ALL || (item.ident in EXPORTED_GLOBALS)) { js += '\nModule["' + item.ident + '"] = ' + item.ident + ';'; @@ -821,7 +822,7 @@ function JSify(data, functionsOnly, givenFunctions) { break; case VAR_EMULATED: if (item.pointer.intertype == 'value') { - return makeSetValue(item.ident, 0, value, item.valueType, 0, 0, item.align) + ';'; + return makeSetValue(makeGlobalUse(item.ident), 0, value, item.valueType, 0, 0, item.align) + ';'; } else { return makeSetValue(0, finalizeLLVMParameter(item.pointer), value, item.valueType, 0, 0, item.align) + ';'; } @@ -1278,6 +1279,15 @@ function JSify(data, functionsOnly, givenFunctions) { // if (!mainPass) { + if (phase == 'pre' && !Variables.generatedGlobalBase) { + Variables.generatedGlobalBase = true; + if (Variables.nextIndexedOffset > 0) { + // Variables have been calculated, print out the base generation before we print them + print('var GLOBAL_BASE = STATICTOP;\n'); + print('STATICTOP += ' + Variables.nextIndexedOffset + ';\n'); + print('assert(STATICTOP < TOTAL_MEMORY);\n'); + } + } var generated = itemsDict.function.concat(itemsDict.type).concat(itemsDict.GlobalVariableStub).concat(itemsDict.GlobalVariable).concat(itemsDict.GlobalVariablePostSet); if (!DEBUG_MEMORY) print(generated.map(function(item) { return item.JS }).join('\n')); return; @@ -1286,7 +1296,23 @@ function JSify(data, functionsOnly, givenFunctions) { // Print out global variables and postsets TODO: batching if (phase == 'pre') { legalizedI64s = false; - JSify(analyzer(intertyper(data.unparsedGlobalss[0].lines, true), true), true, Functions); + + var globalsData = analyzer(intertyper(data.unparsedGlobalss[0].lines, true), true); + + if (!NAMED_GLOBALS) { + sortGlobals(globalsData.globalVariables).forEach(function(g) { + var ident = g.ident; + if (!isIndexableGlobal(ident)) return; + Variables.indexedGlobals[ident] = Variables.nextIndexedOffset; + Variables.nextIndexedOffset += Runtime.alignMemory(calcAllocatedSize(Variables.globals[ident].type)); + if (ident.substr(0, 5) == '__ZTV') { // leave room for null-terminating the vtable + Variables.nextIndexedOffset += Runtime.getNativeTypeSize('i32'); + } + }); + } + + JSify(globalsData, true, Functions); + globalsData = null; data.unparsedGlobalss = null; var generated = itemsDict.functionStub.concat(itemsDict.GlobalVariablePostSet); @@ -1350,7 +1376,7 @@ function JSify(data, functionsOnly, givenFunctions) { substrate.addItems(data.functionStubs, 'FunctionStub'); assert(data.functions.length == 0); } else { - substrate.addItems(values(data.globalVariables), 'GlobalVariable'); + substrate.addItems(sortGlobals(data.globalVariables), 'GlobalVariable'); substrate.addItems(data.aliass, 'Alias'); substrate.addItems(data.functions, 'FunctionSplitter'); } diff --git a/src/library.js b/src/library.js index 12ac0ed0..5a8a9ae7 100644 --- a/src/library.js +++ b/src/library.js @@ -2461,6 +2461,7 @@ LibraryManager.library = { for (var formatIndex = 0; formatIndex < format.length;) { if (format[formatIndex] === '%' && format[formatIndex+1] == 'n') { var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}}; + argIndex += Runtime.getNativeFieldSize('void*'); {{{ makeSetValue('argPtr', 0, 'soFar', 'i32') }}}; formatIndex += 2; continue; @@ -3484,11 +3485,11 @@ LibraryManager.library = { // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html var result = __formatString(format, varargs); var limit = (n === undefined) ? result.length - : Math.min(result.length, n - 1); + : Math.min(result.length, Math.max(n - 1, 0)); for (var i = 0; i < limit; i++) { {{{ makeSetValue('s', 'i', 'result[i]', 'i8') }}}; } - {{{ makeSetValue('s', 'i', '0', 'i8') }}}; + if (limit < n || (n === undefined)) {{{ makeSetValue('s', 'i', '0', 'i8') }}}; return result.length; }, fprintf__deps: ['fwrite', '_formatString'], @@ -3738,6 +3739,7 @@ LibraryManager.library = { strtod_l: 'strtod', // no locale support yet strtold: 'strtod', // XXX add real support for long double strtold_l: 'strtold', // no locale support yet + strtof: 'strtod', // use stdtod to handle strtof _parseInt__deps: ['isspace', '__setErrNo', '$ERRNO_CODES'], _parseInt: function(str, endptr, base, min, max, bits, unsign) { @@ -5363,7 +5365,7 @@ LibraryManager.library = { }, fmaxf: 'fmax', fmin: function(x, y) { - return isNaN(x) ? y : isNaN(y) ? x : Math.max(x, y); + return isNaN(x) ? y : isNaN(y) ? x : Math.min(x, y); }, fminf: 'fmin', fma: function(x, y, z) { diff --git a/src/library_gl.js b/src/library_gl.js index 4d83572e..b4098813 100644 --- a/src/library_gl.js +++ b/src/library_gl.js @@ -454,8 +454,7 @@ var LibraryGL = { }, glBufferSubData: function(target, offset, size, data) { - var floatArray = {{{ makeHEAPView('F32', 'data', 'data+size') }}}; - Module.ctx.bufferSubData(target, offset, floatArray); + Module.ctx.bufferSubData(target, offset, HEAPU8.subarray(data, data+size)); }, glIsBuffer: function(buffer) { diff --git a/src/modules.js b/src/modules.js index 9ef87691..fd0ec35e 100644 --- a/src/modules.js +++ b/src/modules.js @@ -174,7 +174,10 @@ var PreProcessor = { }; var Variables = { - globals: {} + globals: {}, + indexedGlobals: {}, // for indexed globals, ident ==> index + // Used in calculation of indexed globals + nextIndexedOffset: 0 }; var Types = { @@ -263,6 +266,7 @@ var Functions = { var LibraryManager = { library: null, + loaded: false, load: function() { assert(!this.library); @@ -271,6 +275,8 @@ var LibraryManager = { for (var i = 0; i < libraries.length; i++) { eval(processMacros(preprocess(read(libraries[i])))); } + + this.loaded = true; }, // Given an ident, see if it is an alias for something, and so forth, returning diff --git a/src/parseTools.js b/src/parseTools.js index c70b511a..7387bf31 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -356,6 +356,40 @@ function hasVarArgs(params) { return false; } +var UNINDEXABLE_GLOBALS = set( + '_llvm_global_ctors' // special-cased +); + +function noticePtr(ptr) { + if (!NAMED_GLOBALS && !LibraryManager.loaded) UNINDEXABLE_GLOBALS[ptr] = 1; // we cannot index globals referred to in the library, since they are used there by name +} + +function isIndexableGlobal(ident) { + if (!(ident in Variables.globals)) return false; + if (ident in UNINDEXABLE_GLOBALS) return false; + var data = Variables.globals[ident]; + return !data.alias && !data.external; +} + +function makeGlobalDef(ident) { + if (!NAMED_GLOBALS && isIndexableGlobal(ident)) return ''; + return 'var ' + ident + ';'; // TODO: add option for namespacing or offsetting to allow reducing the number of globals +} + +function makeGlobalUse(ident) { + if (!NAMED_GLOBALS && isIndexableGlobal(ident)) return '(' + getFastValue('GLOBAL_BASE', '+', Variables.indexedGlobals[ident]) + ')'; + return ident; // TODO: add option for namespacing or offsetting to allow reducing the number of globals +} + +function sortGlobals(globals) { + var ks = keys(globals); + ks.sort(); + var inv = invertArray(ks); + return values(globals).sort(function(a, b) { + return inv[b.ident] - inv[a.ident]; + }); +} + function finalizeParam(param) { if (param.intertype in PARSABLE_LLVM_FUNCTIONS) { return finalizeLLVMFunctionCall(param); @@ -368,10 +402,9 @@ function finalizeParam(param) { return parseI64Constant(param.ident); } var ret = toNiceIdent(param.ident); - if (ret in Variables.globals && Variables.globals[ret].isString) { - ret = "STRING_TABLE." + ret; + if (ret in Variables.globals) { + ret = makeGlobalUse(ret); } - return ret; } } @@ -907,6 +940,7 @@ function getHeapOffset(offset, type) { // See makeSetValue function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSafe) { + noticePtr(ptr); if (UNALIGNED_MEMORY) align = 1; if (isStructType(type)) { var typeData = Types.types[type]; @@ -987,6 +1021,7 @@ function indexizeFunctions(value, type) { //! which means we should write to all slabs, ignore type differences if any on reads, etc. //! @param noNeedFirst Whether to ignore the offset in the pointer itself. function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, sep, forcedAlign) { + noticePtr(ptr); if (UNALIGNED_MEMORY && !forcedAlign) align = 1; sep = sep || ';'; if (isStructType(type)) { @@ -1058,6 +1093,7 @@ var SEEK_OPTIMAL_ALIGN_MIN = 20; var UNROLL_LOOP_MAX = 8; function makeSetValues(ptr, pos, value, type, num, align) { + noticePtr(ptr); function unroll(type, num, jump, value$) { jump = jump || 1; value$ = value$ || value; @@ -1107,6 +1143,8 @@ function makeSetValues(ptr, pos, value, type, num, align) { var TYPED_ARRAY_SET_MIN = Infinity; // .set() as memcpy seems to just slow us down function makeCopyValues(dest, src, num, type, modifier, align, sep) { + noticePtr(dest); + noticePtr(src); sep = sep || ';'; function unroll(type, num, jump) { jump = jump || 1; @@ -1260,7 +1298,7 @@ function makeGetPos(ptr) { var IHEAP_FHEAP = set('IHEAP', 'IHEAPU', 'FHEAP'); -function makePointer(slab, pos, allocator, type) { +function makePointer(slab, pos, allocator, type, ptr) { assert(type, 'makePointer requires type info'); if (slab.substr(0, 4) === 'HEAP' || (USE_TYPED_ARRAYS == 1 && slab in IHEAP_FHEAP)) return pos; var types = generateStructTypes(type); @@ -1290,7 +1328,7 @@ function makePointer(slab, pos, allocator, type) { types = de[0]; } } - return 'allocate(' + slab + ', ' + JSON.stringify(types) + (allocator ? ', ' + allocator : '') + ')'; + return 'allocate(' + slab + ', ' + JSON.stringify(types) + (allocator ? ', ' + allocator : '') + (allocator == 'ALLOC_NONE' ? ', ' + ptr : '') + ')'; } function makeGetSlabs(ptr, type, allowMultiple, unsigned) { @@ -1472,8 +1510,8 @@ function finalizeLLVMParameter(param, noIndexizeFunctions) { } } else if (param.intertype == 'value') { ret = param.ident; - if (ret in Variables.globals && Variables.globals[ret].isString) { - ret = "STRING_TABLE." + ret; + if (ret in Variables.globals) { + ret = makeGlobalUse(ret); } if (param.type == 'i64' && USE_TYPED_ARRAYS == 2) { ret = parseI64Constant(ret); diff --git a/src/preamble.js b/src/preamble.js index 1c66797b..9342bf2b 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -472,9 +472,11 @@ Module['getValue'] = getValue; var ALLOC_NORMAL = 0; // Tries to use _malloc() var ALLOC_STACK = 1; // Lives for the duration of the current function call var ALLOC_STATIC = 2; // Cannot be freed +var ALLOC_NONE = 3; // Do not allocate Module['ALLOC_NORMAL'] = ALLOC_NORMAL; Module['ALLOC_STACK'] = ALLOC_STACK; Module['ALLOC_STATIC'] = ALLOC_STATIC; +Module['ALLOC_NONE'] = ALLOC_NONE; // allocate(): This is for internal use. You can use it yourself as well, but the interface // is a little tricky (see docs right below). The reason is that it is optimized @@ -489,7 +491,7 @@ Module['ALLOC_STATIC'] = ALLOC_STATIC; // is initial data - if @slab is a number, then this does not matter at all and is // ignored. // @allocator: How to allocate memory, see ALLOC_* -function allocate(slab, types, allocator) { +function allocate(slab, types, allocator, ptr) { var zeroinit, size; if (typeof slab === 'number') { zeroinit = true; @@ -501,7 +503,12 @@ function allocate(slab, types, allocator) { var singleType = typeof types === 'string' ? types : null; - var ret = [_malloc, Runtime.stackAlloc, Runtime.staticAlloc][allocator === undefined ? ALLOC_STATIC : allocator](Math.max(size, singleType ? 1 : types.length)); + var ret; + if (allocator == ALLOC_NONE) { + ret = ptr; + } else { + ret = [_malloc, Runtime.stackAlloc, Runtime.staticAlloc][allocator === undefined ? ALLOC_STATIC : allocator](Math.max(size, singleType ? 1 : types.length)); + } if (zeroinit) { _memset(ret, 0, size); @@ -544,6 +551,9 @@ function Pointer_stringify(ptr, /* optional */ length) { var i = 0; var t; while (1) { +#if ASSERTIONS + assert(i < TOTAL_MEMORY); +#endif t = {{{ makeGetValue('ptr', 'i', 'i8', 0, 1) }}}; if (nullTerminated && t == 0) break; ret += utf8.processCChar(t); @@ -750,7 +760,11 @@ function exitRuntime() { function String_len(ptr) { var i = ptr; - while ({{{ makeGetValue('i++', '0', 'i8') }}}) {}; // Note: should be |!= 0|, technically. But this helps catch bugs with undefineds + while ({{{ makeGetValue('i++', '0', 'i8') }}}) { // Note: should be |!= 0|, technically. But this helps catch bugs with undefineds +#if ASSERTIONS + assert(i < TOTAL_MEMORY); +#endif + } return i - ptr - 1; } Module['String_len'] = String_len; @@ -806,8 +820,6 @@ function writeArrayToMemory(array, buffer) { } Module['writeArrayToMemory'] = writeArrayToMemory; -var STRING_TABLE = []; - {{{ unSign }}} {{{ reSign }}} diff --git a/src/preamble_sharedlib.js b/src/preamble_sharedlib.js index af204e2f..2a071f6b 100644 --- a/src/preamble_sharedlib.js +++ b/src/preamble_sharedlib.js @@ -16,7 +16,6 @@ function callRuntimeCallbacks(callbacks) { } var __ATINIT__ = []; // functions called during startup -var STRING_TABLE = []; function initRuntime() { callRuntimeCallbacks(__ATINIT__); diff --git a/src/settings.js b/src/settings.js index 5dc1e2eb..1d8805a8 100644 --- a/src/settings.js +++ b/src/settings.js @@ -194,6 +194,10 @@ var PGO = 0; // Profile-guided optimization. // All CORRECT_* options default to 1 with PGO builds. // See https://github.com/kripken/emscripten/wiki/Optimizing-Code for more info +var NAMED_GLOBALS = 1; // If 1, we use global variables for globals. Otherwise + // they are referred to by a base plus an offset (called an indexed global), + // saving global variables but adding runtime overhead. + var PROFILE = 0; // Enables runtime profiling. See test_profiling for a usage example. var EXPORT_ALL = 0; // If true, we export all the symbols diff --git a/src/utility.js b/src/utility.js index f3ece90b..84b50ce9 100644 --- a/src/utility.js +++ b/src/utility.js @@ -282,6 +282,14 @@ function setIntersect(x, y) { return ret; } +function invertArray(x) { + var ret = {}; + for (var i = 0; i < x.length; i++) { + ret[x[i]] = i; + } + return ret; +} + function copy(x) { return JSON.parse(JSON.stringify(x)); } diff --git a/tests/cases/gepoverflow.txt b/tests/cases/gepoverflow.txt index bd3091fd..e01c78dd 100644 --- a/tests/cases/gepoverflow.txt +++ b/tests/cases/gepoverflow.txt @@ -1,2 +1,2 @@ -*5246498,5247068* +*5246470,5247040* *-514,56* diff --git a/tests/cases/subnums.ll b/tests/cases/subnums.ll index 981a1592..dc2af1c7 100644 --- a/tests/cases/subnums.ll +++ b/tests/cases/subnums.ll @@ -2,7 +2,7 @@ target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S128" target triple = "i386-pc-linux-gnu" -@.str = private unnamed_addr constant [15 x i8] c"hello, world! %d\0A\00", align 1 ; [#uses=1 type=[18 x i8]*] +@.str = private unnamed_addr constant [18 x i8] c"hello, world! %d\0A\00", align 1 ; [#uses=1 type=[18 x i8]*] ; [#uses=0] define i32 @main() { diff --git a/tests/gl_subdata.cpp b/tests/gl_subdata.cpp new file mode 100644 index 00000000..d159b2b2 --- /dev/null +++ b/tests/gl_subdata.cpp @@ -0,0 +1,141 @@ +#define GL_GLEXT_PROTOTYPES +#define EGL_EGLEXT_PROTOTYPES +#include <cmath> +#include <iostream> +#include <vector> +extern "C" { +#include <GL/gl.h> +#include <GL/glut.h> +} +static const char vertex_shader[] = + "#ifdef GL_ES\n" + "precision highp float;\n" + "#endif\n" + "attribute float indices;\n" + "uniform sampler2D nodeInfo;\n" + "varying vec4 color;" + "\n" + "void main(void)\n" + "{\n" + " float s = (indices + 0.5) / 512.; \n" + " vec4 v = texture2D(nodeInfo, vec2( s, 0.5));\n" + " gl_Position = vec4(v.x, v.y, 0.5, 1.);\n" + " gl_PointSize = v.z;\n" + " color = vec4(0.5 + v.w/2., 0.5 + 0.5 * v.w/2., 0.5, 1);\n" + "}\n"; +static const char fragment_shader[] = + "#ifdef GL_ES\n" + "precision highp float;\n" + "#endif\n" + "\n" + "varying vec4 color;\n" + "void main(void)\n" + "{\n" + " float dst = distance(vec2(0.5, 0.5), gl_PointCoord); \n" + " gl_FragColor = color;\n" + " if ( dst > 0.3) {" + " gl_FragColor = vec4(0., 0., 0.5, 0.2);\n" + "}\n" + "if ( dst > 0.5) discard;\n" + "}"; +struct NodeInfo { //structure that we want to transmit to our shaders + float x; + float y; + float s; + float c; +}; +GLuint nodeTexture; //texture id used to bind +GLuint nodeSamplerLocation; //shader sampler address +GLuint indicesAttributeLocation; //shader attribute address +GLuint indicesVBO; //Vertex Buffer Object Id; +const int nbNodes = 512; +NodeInfo data[nbNodes]; //our data that will be transmitted using float texture. +double alpha = 0; //use to make a simple funny effect; +static void updateFloatTexture() { + int count = 0; + for (float x=0; x < nbNodes; ++x ) { + data[count].x = 0.2*pow(cos(alpha), 3) + (sin(alpha)*3. + 3.5) * x/nbNodes * cos(alpha + x/nbNodes * 16. * M_PI); + data[count].y = 0.2*pow(sin(alpha), 3) + (sin(alpha)*3. + 3.5) * x/nbNodes * sin(alpha + x/nbNodes * 16. * M_PI); + data[count].s = (16. + 16. * cos(alpha + x/nbNodes * 32. * M_PI)) + 8.;// * fmod(x/nbNodes + alpha, 1.) + 5.; + data[count].c = 0.5 + 0.5 * sin(alpha + x/nbNodes * 32. * M_PI); + ++count; + } + glBindTexture(GL_TEXTURE_2D, nodeTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, nbNodes, 1, 0, GL_RGBA, GL_FLOAT, data); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glBindTexture(GL_TEXTURE_2D, NULL); + alpha -= 0.001; +} +static void glut_draw_callback(void) { + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glClearColor(1., 1., 1., 0.); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glActiveTexture(GL_TEXTURE0); + updateFloatTexture(); //we change the texture each time to create the effect (it is just for the test) + glBindTexture(GL_TEXTURE_2D, nodeTexture); + glUniform1i(nodeSamplerLocation, GL_TEXTURE0); + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, indicesVBO); + glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0, NULL); + glDrawArrays(GL_POINTS, 0, nbNodes); + glutSwapBuffers(); +} +GLuint createShader(const char source[], int type) { + char msg[512]; + GLuint shader = glCreateShader(type); + glShaderSource(shader, 1, (const GLchar**)(&source), NULL); + glCompileShader(shader); + glGetShaderInfoLog(shader, sizeof msg, NULL, msg); + std::cout << "Shader info: " << msg << std::endl; + return shader; +} +static void gl_init(void) { + GLuint program = glCreateProgram(); + glAttachShader(program, createShader(vertex_shader , GL_VERTEX_SHADER)); + glAttachShader(program, createShader(fragment_shader, GL_FRAGMENT_SHADER)); + glLinkProgram(program); + char msg[512]; + glGetProgramInfoLog(program, sizeof msg, NULL, msg); + std::cout << "info: " << msg << std::endl; + glUseProgram(program); + std::vector<float> elements(nbNodes); + int count = 0; + for (float x=0; x < nbNodes; ++x ) { + elements[count] = count; + ++count; + } + /*Create one texture to store all the needed information */ + glGenTextures(1, &nodeTexture); + /* Store the vertices in a vertex buffer object (VBO) */ + glGenBuffers(1, &indicesVBO); + glBindBuffer(GL_ARRAY_BUFFER, indicesVBO); + float zeroes[nbNodes]; + memset(zeroes, 0, sizeof(zeroes)); + glBufferData(GL_ARRAY_BUFFER, elements.size() * sizeof(float), zeroes, GL_STATIC_DRAW); + for (int x = 0; x < nbNodes; x++) { + glBufferSubData(GL_ARRAY_BUFFER, x * sizeof(float), elements.size() * sizeof(float), &elements[x]); + } + /* Get the locations of the uniforms so we can access them */ + nodeSamplerLocation = glGetUniformLocation(program, "nodeInfo"); + glBindAttribLocation(program, 0, "indices"); + //Enable glPoint size in shader, always enable in Open Gl ES 2. + glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); + glEnable(GL_POINT_SPRITE); +} +int main(int argc, char *argv[]) { + glutInit(&argc, argv); + glutInitWindowSize(640, 480); + glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); + glutCreateWindow("Simple FLOAT Texture Test"); + /* Set up glut callback functions */ + glutDisplayFunc(glut_draw_callback ); + gl_init(); + glutMainLoop(); + return 0; +} + + diff --git a/tests/runner.py b/tests/runner.py index a4bc4944..cef14e95 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -279,10 +279,18 @@ process(sys.argv[1]) return ret def build_native(self, filename): - Popen([CLANG, '-O2', filename, '-o', filename+'.native'], stdout=PIPE).communicate()[0] + process = Popen([CLANG, '-O2', filename, '-o', filename+'.native'], stdout=PIPE); + 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) + print "Output: " + output[0] def run_native(self, filename, args): - Popen([filename+'.native'] + args, stdout=PIPE).communicate()[0] + process = Popen([filename+'.native'] + args, stdout=PIPE); + output = process.communicate() + 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] def assertIdentical(self, values, y): if type(values) not in [list, tuple]: values = [values] @@ -1368,6 +1376,7 @@ c5,de,15,8a def test_floatvars(self): src = ''' #include <stdio.h> + #include <math.h> int main() { float x = 1.234, y = 3.5, q = 0.00000001; @@ -1375,6 +1384,8 @@ c5,de,15,8a int z = x < y; printf("*%d,%d,%.1f,%d,%.4f,%.2f*\\n", z, int(y), y, (int)x, x, q); + printf("%.2f, %.2f, %.2f, %.2f\\n", fmin(0.5, 3.3), fmin(NAN, 3.3), fmax(0.5, 3.3), fmax(NAN, 3.3)); + /* // Rounding behavior float fs[6] = { -2.75, -2.50, -2.25, 2.25, 2.50, 2.75 }; @@ -1386,7 +1397,7 @@ c5,de,15,8a return 0; } ''' - self.do_run(src, '*1,10,10.5,1,1.2340,0.00*') + self.do_run(src, '*1,10,10.5,1,1.2340,0.00*\n0.50, 3.30, 3.30, 3.30\n') def test_globaldoubles(self): src = r''' @@ -1642,7 +1653,15 @@ c5,de,15,8a return 0; } ''' - 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']) + for named, expected in [(0, 100), (1, 0)]: + 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']) + if self.emcc_args == []: + gen = open(self.in_dir('src.cpp.o.js')).read() + count = gen.count('GLOBAL_BASE') + assert count == expected + print ' counted' def test_strcmp_uni(self): src = ''' @@ -1932,7 +1951,7 @@ c5,de,15,8a TEST(C4__); TEST(C4_2); TEST(C__z); - return 1; + return 0; } ''' if Settings.QUANTUM_SIZE == 1: @@ -1947,7 +1966,7 @@ c5,de,15,8a int main() { assert(1 == true); // pass assert(1 == false); // fail - return 1; + return 0; |