diff options
-rw-r--r-- | cmake/Platform/Emscripten.cmake | 4 | ||||
-rwxr-xr-x | emcc | 74 | ||||
-rwxr-xr-x | emscripten.py | 9 | ||||
-rw-r--r-- | src/analyzer.js | 29 | ||||
-rw-r--r-- | src/compiler.js | 7 | ||||
-rw-r--r-- | src/compiler_funcs.html | 28 | ||||
-rw-r--r-- | src/library_gl.js | 56 | ||||
-rw-r--r-- | src/parseTools.js | 56 | ||||
-rw-r--r-- | tools/tempfiles.py | 1 |
9 files changed, 207 insertions, 57 deletions
diff --git a/cmake/Platform/Emscripten.cmake b/cmake/Platform/Emscripten.cmake index 73f2c8ad..7c8e83fa 100644 --- a/cmake/Platform/Emscripten.cmake +++ b/cmake/Platform/Emscripten.cmake @@ -104,8 +104,8 @@ set(CMAKE_C_RESPONSE_FILE_LINK_FLAG "@") set(CMAKE_CXX_RESPONSE_FILE_LINK_FLAG "@") # Specify the program to use when building static libraries. Force Emscripten-related command line options to clang. -set(CMAKE_CXX_ARCHIVE_CREATE "${CMAKE_CXX_COMPILER} ${CMAKE_START_TEMP_FILE} -o <TARGET> -emit-llvm <LINK_FLAGS> <OBJECTS>${CMAKE_END_TEMP_FILE}") -set(CMAKE_C_ARCHIVE_CREATE "${CMAKE_C_COMPILER} ${CMAKE_START_TEMP_FILE} -o <TARGET> -emit-llvm <LINK_FLAGS> <OBJECTS>${CMAKE_END_TEMP_FILE}") +set(CMAKE_CXX_ARCHIVE_CREATE "${CMAKE_AR} rc <TARGET> ${CMAKE_START_TEMP_FILE} <LINK_FLAGS> <OBJECTS>${CMAKE_END_TEMP_FILE}") +set(CMAKE_C_ARCHIVE_CREATE "${CMAKE_AR} rc <TARGET> ${CMAKE_START_TEMP_FILE} <LINK_FLAGS> <OBJECTS>${CMAKE_END_TEMP_FILE}") # Set a global EMSCRIPTEN variable that can be used in client CMakeLists.txt to detect when building using Emscripten. # There seems to be some kind of bug with CMake, so you might need to define this manually on the command line with "-DEMSCRIPTEN=1". @@ -720,6 +720,13 @@ else: def in_temp(name): return os.path.join(temp_dir, os.path.basename(name)) +# Parses the essential suffix of a filename, discarding Unix-style version numbers in the name. For example for 'libz.so.1.2.8' returns '.so' +def filename_type_suffix(filename): + for i in reversed(filename.split('.')[1:]): + if not i.isdigit(): + return '.' + i + return '' + try: call = CXX if use_cxx else CC @@ -974,35 +981,45 @@ try: if i > 0: prev = newargs[i-1] - if prev in ['-MT', '-MF', '-MQ', '-D', '-U', '-o', '-x', '-Xpreprocessor', '-include', '-imacros', '-idirafter', '-iprefix', '-iwithprefix', '-iwithprefixbefore', '-isysroot', '-imultilib', '-A', '-isystem', '-iquote', '-install_name', '-I', '-L']: continue # ignore this gcc-style argument + if prev in ['-MT', '-MF', '-MQ', '-D', '-U', '-o', '-x', '-Xpreprocessor', '-include', '-imacros', '-idirafter', '-iprefix', '-iwithprefix', '-iwithprefixbefore', '-isysroot', '-imultilib', '-A', '-isystem', '-iquote', '-install_name', '-compatibility_version', '-current_version', '-I', '-L']: continue # ignore this gcc-style argument if (os.path.islink(arg) and os.path.realpath(arg).endswith(SOURCE_SUFFIXES + BITCODE_SUFFIXES + DYNAMICLIB_SUFFIXES + ASSEMBLY_SUFFIXES)): arg = os.path.realpath(arg) - if not arg.startswith('-') and (arg.endswith(SOURCE_SUFFIXES + BITCODE_SUFFIXES + DYNAMICLIB_SUFFIXES + ASSEMBLY_SUFFIXES) or shared.Building.is_ar(arg)): # we already removed -o <target>, so all these should be inputs - newargs[i] = '' - if os.path.exists(arg): - if arg.endswith(SOURCE_SUFFIXES): + if not arg.startswith('-'): + if not os.path.exists(arg): + logging.error(arg + ': No such file or directory') + exit(1) + + arg_suffix = filename_type_suffix(arg) + if arg_suffix.endswith(SOURCE_SUFFIXES + BITCODE_SUFFIXES + DYNAMICLIB_SUFFIXES + ASSEMBLY_SUFFIXES) or shared.Building.is_ar(arg): # we already removed -o <target>, so all these should be inputs + newargs[i] = '' + if arg_suffix.endswith(SOURCE_SUFFIXES): input_files.append(arg) has_source_inputs = True + elif arg_suffix.endswith(ASSEMBLY_SUFFIXES) or shared.Building.is_bitcode(arg): # this should be bitcode, make sure it is valid + input_files.append(arg) + elif arg_suffix.endswith(STATICLIB_SUFFIXES + DYNAMICLIB_SUFFIXES): + # if it's not, and it's a library, just add it to libs to find later + l = unsuffixed_basename(arg) + for prefix in LIB_PREFIXES: + if not prefix: continue + if l.startswith(prefix): + l = l[len(prefix):] + break + libs.append(l) + newargs[i] = '' else: - # this should be bitcode, make sure it is valid - if arg.endswith(ASSEMBLY_SUFFIXES) or shared.Building.is_bitcode(arg): - input_files.append(arg) - elif arg.endswith(STATICLIB_SUFFIXES + DYNAMICLIB_SUFFIXES): - # if it's not, and it's a library, just add it to libs to find later - l = unsuffixed_basename(arg) - for prefix in LIB_PREFIXES: - if not prefix: continue - if l.startswith(prefix): - l = l[len(prefix):] - break - libs.append(l) - newargs[i] = '' + logging.warning(arg + ' is not valid LLVM bitcode') + elif arg_suffix.endswith(STATICLIB_SUFFIXES): + if not shared.Building.is_ar(arg): + if shared.Building.is_bitcode(arg): + logging.error(arg + ': File has a suffix of a static library ' + str(STATICLIB_SUFFIXES) + ', but instead is an LLVM bitcode file! When linking LLVM bitcode files, use one of the suffixes ' + str(BITCODE_SUFFIXES)) else: - logging.warning(arg + ' is not valid LLVM bitcode') + logging.error(arg + ': Unknown format, not a static library!') + exit(1) else: - logging.error(arg + ': No such file or directory') + logging.error(arg + ": Input file has an unknown suffix, don't know what to do with it!") exit(1) elif arg.startswith('-L'): lib_dirs.append(arg[2:]) @@ -1151,13 +1168,14 @@ try: # First, generate LLVM bitcode. For each input file, we get base.o with bitcode for input_file in input_files: - if input_file.endswith(SOURCE_SUFFIXES): + file_suffix = filename_type_suffix(input_file) + if file_suffix.endswith(SOURCE_SUFFIXES): logging.debug('compiling source file: ' + input_file) input_file = shared.Building.preprocess(input_file, in_temp(uniquename(input_file))) output_file = in_temp(unsuffixed(uniquename(input_file)) + '.o') temp_files.append(output_file) args = newargs + ['-emit-llvm', '-c', input_file, '-o', output_file] - if input_file.endswith(CXX_SUFFIXES): + if file_suffix.endswith(CXX_SUFFIXES): args += shared.EMSDK_CXX_OPTS logging.debug("running: " + call + ' ' + ' '.join(args)) execute([call] + args) # let compiler frontend print directly, so colors are saved (PIPE kills that) @@ -1165,17 +1183,17 @@ try: logging.error('compiler frontend failed to generate LLVM bitcode, halting') sys.exit(1) else: # bitcode - if input_file.endswith(BITCODE_SUFFIXES): + if file_suffix.endswith(BITCODE_SUFFIXES): logging.debug('copying bitcode file: ' + input_file) temp_file = in_temp(unsuffixed(uniquename(input_file)) + '.o') shutil.copyfile(input_file, temp_file) temp_files.append(temp_file) - elif input_file.endswith(DYNAMICLIB_SUFFIXES) or shared.Building.is_ar(input_file): + elif file_suffix.endswith(DYNAMICLIB_SUFFIXES) or shared.Building.is_ar(input_file): logging.debug('copying library file: ' + input_file) temp_file = in_temp(uniquename(input_file)) shutil.copyfile(input_file, temp_file) temp_files.append(temp_file) - else: #.ll + elif file_suffix.endswith(ASSEMBLY_SUFFIXES): if not LEAVE_INPUTS_RAW: # Note that by assembling the .ll file, then disassembling it later, we will # remove annotations which is a good thing for compilation time @@ -1183,6 +1201,9 @@ try: temp_file = in_temp(unsuffixed(uniquename(input_file)) + '.o') shared.Building.llvm_as(input_file, temp_file) temp_files.append(temp_file) + else: + logging.error(input_file + ': Unknown file suffix when compiling to LLVM bitcode!') + sys.exit(1) if not LEAVE_INPUTS_RAW: assert len(temp_files) == len(input_files) @@ -1190,7 +1211,8 @@ try: # Optimize source files if llvm_opts > 0: for i, input_file in enumerate(input_files): - if input_file.endswith(SOURCE_SUFFIXES): + file_suffix = filename_type_suffix(input_file) + if file_suffix.endswith(SOURCE_SUFFIXES): temp_file = temp_files[i] logging.debug('optimizing %s with -O%d' % (input_file, llvm_opts)) shared.Building.llvm_opt(temp_file, llvm_opts) diff --git a/emscripten.py b/emscripten.py index 19e2160d..b95e03a7 100755 --- a/emscripten.py +++ b/emscripten.py @@ -58,6 +58,8 @@ def process_funcs((i, funcs, meta, settings_file, compiler, forwarded_file, libr f.write('\n') f.write(meta) f.close() + #print >> sys.stderr, 'running', str([settings_file, funcs_file, 'funcs', forwarded_file] + libraries).replace("'/", "'") # can use this in src/compiler_funcs.html arguments, + # # just copy temp dir to under this one out = jsrun.run_js( compiler, engine=compiler_engine, @@ -68,8 +70,6 @@ def process_funcs((i, funcs, meta, settings_file, compiler, forwarded_file, libr except KeyboardInterrupt: # Python 2.7 seems to lock up when a child process throws KeyboardInterrupt raise Exception() - finally: - tempfiles.try_delete(funcs_file) if DEBUG: print >> sys.stderr, '.' return out @@ -223,6 +223,8 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, funcs, chunk_size, jcache.get_cachename('emscript_files') if jcache else None) + #chunks = [chunks[0]] # pick specific chunks for debugging/profiling + funcs = None if jcache: @@ -251,7 +253,8 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, if DEBUG: print >> sys.stderr, ' emscript: phase 2 working on %d chunks %s (intended chunk size: %.2f MB, meta: %.2f MB, forwarded: %.2f MB, total: %.2f MB)' % (len(chunks), ('using %d cores' % cores) if len(chunks) > 1 else '', chunk_size/(1024*1024.), len(meta)/(1024*1024.), len(forwarded_data)/(1024*1024.), total_ll_size/(1024*1024.)) commands = [ - (i, chunk, meta, settings_file, compiler, forwarded_file, libraries, compiler_engine, temp_files, DEBUG) + (i, chunk, meta, settings_file, compiler, forwarded_file, libraries, compiler_engine,# + ['--prof'], + temp_files, DEBUG) for i, chunk in enumerate(chunks) ] diff --git a/src/analyzer.js b/src/analyzer.js index 750f2a4c..3fb20253 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -30,6 +30,8 @@ function analyzer(data, sidePass) { var item = { items: data }; var data = item; + var newTypes = {}; + // Gather // Single-liners ['globalVariable', 'functionStub', 'unparsedFunction', 'unparsedGlobals', 'unparsedTypes', 'alias'].forEach(function(intertype) { @@ -42,6 +44,7 @@ function analyzer(data, sidePass) { temp.splitOut.forEach(function(type) { //dprint('types', 'adding defined type: ' + type.name_); Types.types[type.name_] = type; + newTypes[type.name_] = 1; if (QUANTUM_SIZE === 1) { Types.fatTypes[type.name_] = copy(type); } @@ -897,7 +900,7 @@ function analyzer(data, sidePass) { }); } - function addTypeInternal(type, data) { + function addTypeInternal(type) { if (type.length == 1) return; if (Types.types[type]) return; if (['internal', 'hidden', 'inbounds', 'void'].indexOf(type) != -1) return; @@ -908,8 +911,9 @@ function analyzer(data, sidePass) { // to look at the underlying type - it was not defined explicitly // anywhere else. var nonPointing = removeAllPointing(type); + if (Types.types[nonPointing]) return; var check = /^\[(\d+)\ x\ (.*)\]$/.exec(nonPointing); - if (check && !Types.types[nonPointing]) { + if (check) { var num = parseInt(check[1]); num = Math.max(num, 1); // [0 x something] is used not for allocations and such of course, but // for indexing - for an |array of unknown length|, basically. So we @@ -917,7 +921,7 @@ function analyzer(data, sidePass) { // check that we never allocate with this (either as a child structure // in the analyzer, or in calcSize in alloca). var subType = check[2]; - addTypeInternal(subType, data); // needed for anonymous structure definitions (see below) + addTypeInternal(subType); // needed for anonymous structure definitions (see below) // Huge structural types are represented very inefficiently, both here and in generated JS. Best to avoid them - for example static char x[10*1024*1024]; is bad, while static char *x = malloc(10*1024*1024) is fine. if (num >= 10*1024*1024) warnOnce('warning: very large fixed-size structural type: ' + type + ' - can you reduce it? (compilation may be slow)'); @@ -926,6 +930,7 @@ function analyzer(data, sidePass) { fields: range(num).map(function() { return subType }), lineNum: '?' }; + newTypes[nonPointing] = 1; // Also add a |[0 x type]| type var zerod = '[0 x ' + subType + ']'; if (!Types.types[zerod]) { @@ -934,6 +939,7 @@ function analyzer(data, sidePass) { fields: [subType, subType], // Two, so we get the flatFactor right. We care about the flatFactor, not the size here lineNum: '?' }; + newTypes[zerod] = 1; } return; } @@ -964,6 +970,7 @@ function analyzer(data, sidePass) { packed: packed, lineNum: '?' }; + newTypes[type] = 1; return; } @@ -975,13 +982,14 @@ function analyzer(data, sidePass) { flatSize: 1, lineNum: '?' }; + newTypes[type] = 1; } - function addType(type, data) { - addTypeInternal(type, data); + function addType(type) { + addTypeInternal(type); if (QUANTUM_SIZE === 1) { Types.flipTypes(); - addTypeInternal(type, data); + addTypeInternal(type); Types.flipTypes(); } } @@ -992,7 +1000,7 @@ function analyzer(data, sidePass) { // which handles type definitions, and later. Doing so before the first side pass will result in // making bad guesses about types which are actually defined for (var type in Types.needAnalysis) { - if (type) addType(type, data); + if (type) addType(type); } Types.needAnalysis = {}; } @@ -1021,17 +1029,18 @@ function analyzer(data, sidePass) { var more = true; while (more) { more = false; - for (var typeName in types) { + for (var typeName in newTypes) { var type = types[typeName]; if (type.flatIndexes) continue; var ready = true; type.fields.forEach(function(field) { if (isStructType(field)) { if (!types[field]) { - addType(field, item); + addType(field); ready = false; } else { if (!types[field].flatIndexes) { + newTypes[field] = 1; ready = false; } } @@ -1058,6 +1067,8 @@ function analyzer(data, sidePass) { Runtime.QUANTUM_SIZE = trueQuantumSize; Types.flipTypes(); } + + newTypes = null; } // Variable analyzer diff --git a/src/compiler.js b/src/compiler.js index 4f16986c..77abd53b 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -215,7 +215,12 @@ load('analyzer.js'); load('jsifier.js'); if (phase == 'funcs' && RELOOP) { // XXX handle !singlePhase RelooperModule = { TOTAL_MEMORY: ceilPowerOfTwo(2*RELOOPER_BUFFER_SIZE) }; - load(RELOOPER); + try { + load(RELOOPER); + } catch(e) { + printErr('cannot find relooper at ' + RELOOPER + ', trying in current dir'); + load('relooper.js'); + } assert(typeof Relooper != 'undefined'); } globalEval(processMacros(preprocess(read('runtime.js')))); diff --git a/src/compiler_funcs.html b/src/compiler_funcs.html new file mode 100644 index 00000000..a769955b --- /dev/null +++ b/src/compiler_funcs.html @@ -0,0 +1,28 @@ +<html> +<body> +<h2>Run the emscripten compiler in a web page, just for laughs</h2> +Open the web console to see stderr output +<hr> +<pre id="output"></pre> +<script> + arguments = ['tmp/emscripten_temp/tmpgo4sBT.txt', 'tmp/emscripten_temp/tmph9FP9W.func_0.ll', 'funcs', 'tmp/emscripten_temp/tmp0Aj1Vk.json']; // copy from emscripten.py output + + var outputElement = document.getElementById('output'); + print = function(x) { + outputElement.innerHTML += 'output hidden, profiling mode'; + print = function(){}; + //outputElement.innerHTML += x; + }; + + // For generated code + var Module = { + print: function(x) { + throw 'what?' + } + }; +</script> +<script src="compiler.js"> +</script> +</body> +</html> + diff --git a/src/library_gl.js b/src/library_gl.js index a4d35aff..83e68777 100644 --- a/src/library_gl.js +++ b/src/library_gl.js @@ -310,6 +310,9 @@ var LibraryGL = { Module.ctx.bufferSubData(Module.ctx.ARRAY_BUFFER, 0, HEAPU8.subarray(cb.ptr, cb.ptr + size)); +#if GL_ASSERTIONS + GL.validateVertexAttribPointer(cb.size, cb.type, cb.stride, 0); +#endif Module.ctx.vertexAttribPointer(i, cb.size, cb.type, cb.normalized, cb.stride, 0); } }, @@ -331,6 +334,44 @@ var LibraryGL = { } } }, + // Validates that user obeys GL spec #6.4: http://www.khronos.org/registry/webgl/specs/latest/1.0/#6.4 + validateVertexAttribPointer: function(dimension, dataType, stride, offset) { + var sizeBytes = 1; + switch(dataType) { + case 0x1400 /* GL_BYTE */: + case 0x1401 /* GL_UNSIGNED_BYTE */: + sizeBytes = 1; + break; + case 0x1402 /* GL_SHORT */: + case 0x1403 /* GL_UNSIGNED_SHORT */: + sizeBytes = 2; + break; + case 0x1404 /* GL_INT */: + case 0x1405 /* GL_UNSIGNED_INT */: + case 0x1406 /* GL_FLOAT */: + sizeBytes = 4; + break; + case 0x140A /* GL_DOUBLE */: + sizeBytes = 8; + break; + default: + console.error('Invalid vertex attribute data type GLenum ' + dataType + ' passed to GL function!'); + } + if (dimension == 0x80E1 /* GL_BGRA */) { + console.error('WebGL does not support size=GL_BGRA in a call to glVertexAttribPointer! Please use size=4 and type=GL_UNSIGNED_BYTE instead!'); + } else if (dimension < 1 || dimension > 4) { + console.error('Invalid dimension='+dimension+' in call to glVertexAttribPointer, must be 1,2,3 or 4.'); + } + if (stride < 0 || stride > 255) { + console.error('Invalid stride='+stride+' in call to glVertexAttribPointer. Note that maximum supported stride in WebGL is 255!'); + } + if (offset % sizeBytes != 0) { + console.error('GL spec section 6.4 error: vertex attribute data offset of ' + offset + ' bytes should have been a multiple of the data type size that was used: GLenum ' + dataType + ' has size of ' + sizeBytes + ' bytes!'); + } + if (stride % sizeBytes != 0) { + console.error('GL spec section 6.4 error: vertex attribute data stride of ' + stride + ' bytes should have been a multiple of the data type size that was used: GLenum ' + dataType + ' has size of ' + sizeBytes + ' bytes!'); + } + }, #endif initExtensions: function() { @@ -3273,6 +3314,9 @@ var LibraryGL = { var clientAttributes = GL.immediate.clientAttributes; +#if GL_ASSERTIONS + GL.validateVertexAttribPointer(positionSize, positionType, GL.immediate.stride, clientAttributes[GL.immediate.VERTEX].offset); +#endif Module.ctx.vertexAttribPointer(this.positionLocation, positionSize, positionType, false, GL.immediate.stride, clientAttributes[GL.immediate.VERTEX].offset); Module.ctx.enableVertexAttribArray(this.positionLocation); @@ -3285,6 +3329,9 @@ var LibraryGL = { if (attribLoc === undefined || attribLoc < 0) continue; if (texUnitID < textureSizes.length && textureSizes[texUnitID]) { +#if GL_ASSERTIONS + GL.validateVertexAttribPointer(textureSizes[texUnitID], textureTypes[texUnitID], GL.immediate.stride, GL.immediate.clientAttributes[GL.immediate.TEXTURE0 + texUnitID].offset); +#endif Module.ctx.vertexAttribPointer(attribLoc, textureSizes[texUnitID], textureTypes[texUnitID], false, GL.immediate.stride, GL.immediate.clientAttributes[GL.immediate.TEXTURE0 + texUnitID].offset); Module.ctx.enableVertexAttribArray(attribLoc); @@ -3301,6 +3348,9 @@ var LibraryGL = { } } if (colorSize) { +#if GL_ASSERTIONS + GL.validateVertexAttribPointer(colorSize, colorType, GL.immediate.stride, clientAttributes[GL.immediate.COLOR].offset); +#endif Module.ctx.vertexAttribPointer(this.colorLocation, colorSize, colorType, true, GL.immediate.stride, clientAttributes[GL.immediate.COLOR].offset); Module.ctx.enableVertexAttribArray(this.colorLocation); @@ -3309,6 +3359,9 @@ var LibraryGL = { Module.ctx.vertexAttrib4fv(this.colorLocation, GL.immediate.clientColor); } if (this.hasNormal) { +#if GL_ASSERTIONS + GL.validateVertexAttribPointer(normalSize, normalType, GL.immediate.stride, clientAttributes[GL.immediate.NORMAL].offset); +#endif Module.ctx.vertexAttribPointer(this.normalLocation, normalSize, normalType, true, GL.immediate.stride, clientAttributes[GL.immediate.NORMAL].offset); Module.ctx.enableVertexAttribArray(this.normalLocation); @@ -4288,6 +4341,9 @@ var LibraryGL = { } cb.clientside = false; #endif +#if GL_ASSERTIONS + GL.validateVertexAttribPointer(size, type, stride, ptr); +#endif Module.ctx.vertexAttribPointer(index, size, type, normalized, stride, ptr); }, diff --git a/src/parseTools.js b/src/parseTools.js index 8ce83adf..7d5ca315 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -1473,17 +1473,38 @@ var TWO_TWENTY = Math.pow(2, 20); // Tries to do as much as possible at compile time. // Leaves overflows etc. unhandled, *except* for integer multiply, in order to be efficient with Math.imul function getFastValue(a, op, b, type) { - a = a.toString(); - b = b.toString(); + //return '(' + a + ')' + op + '(' + b + ')'; a = a == 'true' ? '1' : (a == 'false' ? '0' : a); b = b == 'true' ? '1' : (b == 'false' ? '0' : b); - if (isNumber(a) && isNumber(b)) { - if (op == 'pow') { - return Math.pow(a, b).toString(); - } else { - var value = eval(a + op + '(' + b + ')'); // parens protect us from "5 - -12" being seen as "5--12" which is "(5--)12" - if (op == '/' && type in Runtime.INT_TYPES) value = value|0; // avoid emitting floats - return value.toString(); + + var aNumber = null, bNumber = null; + if (typeof a === 'number') { + aNumber = a; + a = a.toString(); + } else if (isNumber(a)) aNumber = parseFloat(a); + if (typeof b === 'number') { + bNumber = b; + b = b.toString(); + } else if (isNumber(b)) bNumber = parseFloat(b); + + if (aNumber !== null && bNumber !== null) { + switch (op) { + case '+': return (aNumber + bNumber).toString(); + case '-': return (aNumber - bNumber).toString(); + case '*': return (aNumber * bNumber).toString(); + case '/': { + if (type in Runtime.INT_TYPES) { + return ((aNumber / bNumber)|0).toString(); + } else { + return (aNumber / bNumber).toString(); + } + } + case '%': return (aNumber % bNumber).toString(); + case '|': return (aNumber | bNumber).toString(); + case '>>>': return (aNumber >>> bNumber).toString(); + case '&': return (aNumber & bNumber).toString(); + case 'pow': return Math.pow(aNumber, bNumber).toString(); + default: throw 'need to implement getFastValue pn ' + op; } } if (op == 'pow') { @@ -1492,23 +1513,26 @@ function getFastValue(a, op, b, type) { } return 'Math.pow(' + a + ', ' + b + ')'; } - if (op in PLUS_MUL && isNumber(a)) { // if one of them is a number, keep it last + if (op in PLUS_MUL && aNumber !== null) { // if one of them is a number, keep it last var c = b; b = a; a = c; + var cNumber = bNumber; + bNumber = aNumber; + aNumber = cNumber; } if (op in MUL_DIV) { if (op == '*') { // We can't eliminate where a or b are 0 as that would break things for creating // a negative 0. - if ((a == 0 || b == 0) && !(type in Runtime.FLOAT_TYPES)) { + if ((aNumber == 0 || bNumber == 0) && !(type in Runtime.FLOAT_TYPES)) { return '0'; - } else if (a == 1) { + } else if (aNumber == 1) { return b; - } else if (b == 1) { + } else if (bNumber == 1) { return a; - } else if (isNumber(b) && type && isIntImplemented(type) && Runtime.getNativeTypeSize(type) <= 32) { - var shifts = Math.log(parseFloat(b))/Math.LN2; + } else if (bNumber !== null && type && isIntImplemented(type) && Runtime.getNativeTypeSize(type) <= 32) { + var shifts = Math.log(bNumber)/Math.LN2; if (shifts % 1 == 0) { return '(' + a + '<<' + shifts + ')'; } @@ -1517,7 +1541,7 @@ function getFastValue(a, op, b, type) { // if guaranteed small enough to not overflow into a double, do a normal multiply var bits = getBits(type) || 32; // default is 32-bit multiply for things like getelementptr indexes // Note that we can emit simple multiple in non-asm.js mode, but asm.js will not parse "16-bit" multiple, so must do imul there - if ((isNumber(a) && Math.abs(a) < TWO_TWENTY) || (isNumber(b) && Math.abs(b) < TWO_TWENTY) || (bits < 32 && !ASM_JS)) { + if ((aNumber !== null && Math.abs(a) < TWO_TWENTY) || (bNumber !== null && Math.abs(b) < TWO_TWENTY) || (bits < 32 && !ASM_JS)) { return '(((' + a + ')*(' + b + '))&' + ((Math.pow(2, bits)-1)|0) + ')'; // keep a non-eliminatable coercion directly on this } return '(Math.imul(' + a + ',' + b + ')|0)'; diff --git a/tools/tempfiles.py b/tools/tempfiles.py index 1721b2bb..27da1082 100644 --- a/tools/tempfiles.py +++ b/tools/tempfiles.py @@ -27,6 +27,7 @@ class TempFiles: def clean(self): if self.save_debug_files: + import sys print >> sys.stderr, 'not cleaning up temp files since in debug-save mode, see them in %s' % (self.tmp,) return for filename in self.to_clean: |