diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/analyzer.js | 5 | ||||
-rw-r--r-- | src/compiler.js | 1 | ||||
-rw-r--r-- | src/intertyper.js | 23 | ||||
-rw-r--r-- | src/jsifier.js | 18 | ||||
-rw-r--r-- | src/library_gl.js | 12 | ||||
-rw-r--r-- | src/modules.js | 4 | ||||
-rw-r--r-- | src/preamble.js | 17 | ||||
-rw-r--r-- | src/runtime.js | 2 | ||||
-rw-r--r-- | src/settings.js | 8 |
9 files changed, 65 insertions, 25 deletions
diff --git a/src/analyzer.js b/src/analyzer.js index 209e3140..926ac9d3 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -231,9 +231,10 @@ function analyzer(data, sidePass) { } if (isIllegalType(item.valueType) || isIllegalType(item.type)) { isIllegal = true; - } - if ((item.intertype == 'load' || item.intertype == 'store') && isStructType(item.valueType)) { + } else if ((item.intertype == 'load' || item.intertype == 'store') && isStructType(item.valueType)) { isIllegal = true; // storing an entire structure is illegal + } else if (item.intertype == 'mathop' && item.op == 'trunc' && isIllegalType(item.params[1].ident)) { // trunc stores target value in second ident + isIllegal = true; } }); if (!isIllegal) { diff --git a/src/compiler.js b/src/compiler.js index 3047daf1..447d34b7 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -163,6 +163,7 @@ if (SAFE_HEAP >= 2) { EXPORTED_FUNCTIONS = set(EXPORTED_FUNCTIONS); EXPORTED_GLOBALS = set(EXPORTED_GLOBALS); EXCEPTION_CATCHING_WHITELIST = set(EXCEPTION_CATCHING_WHITELIST); +DEAD_FUNCTIONS = set(DEAD_FUNCTIONS); RUNTIME_DEBUG = LIBRARY_DEBUG || GL_DEBUG; diff --git a/src/intertyper.js b/src/intertyper.js index 2103ecfa..57e3011d 100644 --- a/src/intertyper.js +++ b/src/intertyper.js @@ -122,16 +122,19 @@ function intertyper(data, sidePass, baseLineNums) { SKIP_STACK_IN_SMALL = 0; } - unparsedBundles.push({ - intertype: 'unparsedFunction', - // We need this early, to know basic function info - ident, params, varargs - ident: toNiceIdent(func.ident), - params: func.params, - returnType: func.returnType, - hasVarArgs: func.hasVarArgs, - lineNum: currFunctionLineNum, - lines: currFunctionLines - }); + var ident = toNiceIdent(func.ident); + if (!(ident in DEAD_FUNCTIONS)) { + unparsedBundles.push({ + intertype: 'unparsedFunction', + // We need this early, to know basic function info - ident, params, varargs + ident: ident, + params: func.params, + returnType: func.returnType, + hasVarArgs: func.hasVarArgs, + lineNum: currFunctionLineNum, + lines: currFunctionLines + }); + } currFunctionLines = []; } } diff --git a/src/jsifier.js b/src/jsifier.js index ff58ece2..1662d249 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -600,6 +600,10 @@ function JSify(data, functionsOnly, givenFunctions) { func.JS += 'function ' + func.ident + '(' + paramIdents.join(', ') + ') {\n'; + if (PGO) { + func.JS += ' PGOMonitor.called["' + func.ident + '"] = 1;\n'; + } + if (ASM_JS) { // spell out argument types func.params.forEach(function(param) { @@ -1587,11 +1591,17 @@ function JSify(data, functionsOnly, givenFunctions) { var shellParts = read(shellFile).split('{{BODY}}'); print(shellParts[1]); - // Print out some useful metadata (for additional optimizations later, like the eliminator) - if (EMIT_GENERATED_FUNCTIONS) { - print('// EMSCRIPTEN_GENERATED_FUNCTIONS: ' + JSON.stringify(keys(Functions.implementedFunctions).filter(function(func) { + // Print out some useful metadata + if (EMIT_GENERATED_FUNCTIONS || PGO) { + var generatedFunctions = JSON.stringify(keys(Functions.implementedFunctions).filter(function(func) { return IGNORED_FUNCTIONS.indexOf(func.ident) < 0; - })) + '\n'); + })); + if (PGO) { + print('PGOMonitor.allGenerated = ' + generatedFunctions + ';\nremoveRunDependency("pgo");\n'); + } + if (EMIT_GENERATED_FUNCTIONS) { + print('// EMSCRIPTEN_GENERATED_FUNCTIONS: ' + generatedFunctions + '\n'); + } } PassManager.serialize(); diff --git a/src/library_gl.js b/src/library_gl.js index c6007809..b978e931 100644 --- a/src/library_gl.js +++ b/src/library_gl.js @@ -291,9 +291,9 @@ var LibraryGL = { } while (used.indexOf(buf) >= 0); used.push(buf); Module.ctx.bindBuffer(Module.ctx.ARRAY_BUFFER, buf); - Module.ctx.bufferData(Module.ctx.ARRAY_BUFFER, - HEAPU8.subarray(cb.ptr, cb.ptr + size), - Module.ctx.DYNAMIC_DRAW); + Module.ctx.bufferSubData(Module.ctx.ARRAY_BUFFER, + 0, + HEAPU8.subarray(cb.ptr, cb.ptr + size)); Module.ctx.vertexAttribPointer(i, cb.size, cb.type, cb.normalized, cb.stride, 0); } }, @@ -2939,9 +2939,9 @@ var LibraryGL = { var size = GL.calcBufLength(1, type, 0, count); buf = GL.tempIndexBuffers[GL.tempBufferIndexLookup[size]]; Module.ctx.bindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, buf); - Module.ctx.bufferData(Module.ctx.ELEMENT_ARRAY_BUFFER, - HEAPU8.subarray(indices, indices + size), - Module.ctx.DYNAMIC_DRAW); + Module.ctx.bufferSubData(Module.ctx.ELEMENT_ARRAY_BUFFER, + 0, + HEAPU8.subarray(indices, indices + size)); // the index is now 0 indices = 0; } diff --git a/src/modules.js b/src/modules.js index 797d4d83..65b8d437 100644 --- a/src/modules.js +++ b/src/modules.js @@ -291,7 +291,7 @@ var Functions = { var sig = ASM_JS ? Functions.implementedFunctions[ident] || Functions.unimplementedFunctions[ident] || LibraryManager.library[ident.substr(1) + '__sig'] : 'x'; assert(sig, ident); if (!tables[sig]) tables[sig] = emptyTable(sig); // TODO: make them compact - tables[sig][this.indexedFunctions[ident]] = ident; + tables[sig][this.indexedFunctions[ident]] = ident in DEAD_FUNCTIONS ? '0' : ident; } var generated = false; var wrapped = {}; @@ -315,7 +315,7 @@ var Functions = { } if (ASM_JS) { var curr = table[i]; - if (curr && !Functions.implementedFunctions[curr]) { + if (curr && curr != '0' && !Functions.implementedFunctions[curr]) { // This is a library function, we can't just put it in the function table, need a wrapper if (!wrapped[curr]) { var args = '', arg_coercions = '', call = curr + '(', retPre = '', retPost = ''; diff --git a/src/preamble.js b/src/preamble.js index 9bc68d8f..7538b19c 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -848,5 +848,22 @@ Module['removeRunDependency'] = removeRunDependency; Module["preloadedImages"] = {}; // maps url to image data Module["preloadedAudios"] = {}; // maps url to audio data +#if PGO +var PGOMonitor = { + called: {}, + dump: function() { + var dead = []; + for (var i = 0; i < this.allGenerated.length; i++) { + var func = this.allGenerated[i]; + if (!this.called[func]) dead.push(func); + } + Module.print('-s DEAD_FUNCTIONS=\'' + JSON.stringify(dead) + '\'\n'); + } +}; +__ATEXIT__.push({ func: function() { PGOMonitor.dump() } }); +if (!Module.preRun) Module.preRun = []; +Module.preRun.push(function() { addRunDependency('pgo') }); +#endif + // === Body === diff --git a/src/runtime.js b/src/runtime.js index dc604a8d..8352ade1 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -87,7 +87,7 @@ var RuntimeGenerator = { }; function unInline(name_, params) { - var src = '(function ' + name_ + '(' + params + ') { var ret = ' + RuntimeGenerator[name_].apply(null, params) + '; return ret; })'; + var src = '(function(' + params + ') { var ret = ' + RuntimeGenerator[name_].apply(null, params) + '; return ret; })'; var ret = eval(src); return ret; } diff --git a/src/settings.js b/src/settings.js index 440d5094..101c403c 100644 --- a/src/settings.js +++ b/src/settings.js @@ -332,6 +332,14 @@ var ASM_JS = 0; // If 1, generate code in asm.js format. XXX This is highly expe // and will not work on most codebases yet. It is NOT recommended that you // try this yet. +var PGO = 0; // Enables profile-guided optimization in the form of runtime checks for + // which functions are actually called. Emits a list during shutdown that you + // can pass to DEAD_FUNCTIONS (you can also emit the list manually by + // calling PGOMonitor.dump()); +var DEAD_FUNCTIONS = []; // A list of functions that no code will be emitted for, and + // a runtime abort will happen if they are called + // TODO: options to lazily load such functions + var EXPLICIT_ZEXT = 0; // If 1, generate an explicit conversion of zext i1 to i32, using ?: var NECESSARY_BLOCKADDRS = []; // List of (function, block) for all block addresses that are taken. |