diff options
-rw-r--r-- | src/analyzer.js | 52 | ||||
-rw-r--r-- | src/jsifier.js | 13 | ||||
-rw-r--r-- | src/parseTools.js | 9 | ||||
-rw-r--r-- | tests/runner.py | 37 |
4 files changed, 77 insertions, 34 deletions
diff --git a/src/analyzer.js b/src/analyzer.js index ae40896d..f79217bd 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -443,7 +443,13 @@ function analyzer(data, givenTypes) { ret.push(item[id]); dprint('relooping', 'zz ' + id + ' replace ' + item[id] + ' with ' + toLabelId); if (toLabelId) { - item[id] = toLabelId + '|' + item[id]; + // replace wildcards in new value with old parts + var oldParts = item[id].split('|'); + var newParts = toLabelId.split('|'); + for (var i = 1; i < 3; i++) { + if (newParts[i] === '*') newParts[i] = oldParts[i]; + } + item[id] = newParts.join('|') + '|' + item[id]; } } }); @@ -640,6 +646,7 @@ function analyzer(data, givenTypes) { var ret = { type: 'reloop', id: blockId, + needBlockId: true, entries: entries, labels: labels }; @@ -767,6 +774,7 @@ function analyzer(data, givenTypes) { return { type: 'multiple', id: blockId, + needBlockId: true, entries: actualEntries, entryLabels: actualEntryLabels, labels: handlingNow, @@ -798,7 +806,7 @@ function analyzer(data, givenTypes) { if (!RELOOP) return finish(); // Find where each block will 'naturally' get to, just by the flow of code - function exploreBlock(block, endOfTheWorld) { // endoftheworld - where we will get, if we have nothing else to get to - 'fall off the face of the earth' + function exploreBlockEndings(block, endOfTheWorld) { // endoftheworld - where we will get, if we have nothing else to get to - 'fall off the face of the earth' if (!block) return; function singular(block) { @@ -814,9 +822,9 @@ function analyzer(data, givenTypes) { dprint('relooping', "// exploring block: " + block.type + ' : ' + block.entries); if (block.type == 'reloop') { - exploreBlock(block.inner, singular(block.inner)); + exploreBlockEndings(block.inner, singular(block.inner)); } else if (block.type == 'multiple') { - block.entryLabels.forEach(function(entryLabel) { exploreBlock(entryLabel.block, singular(block.next)) }); + block.entryLabels.forEach(function(entryLabel) { exploreBlockEndings(entryLabel.block, singular(block.next)) }); } else if (block.type === 'emulated' && block.next && block.next.type === 'multiple') { assert(block.labels.length == 1); var lastLine = block.labels[0].lines.slice(-1)[0]; @@ -828,7 +836,7 @@ function analyzer(data, givenTypes) { } } - exploreBlock(block.next, endOfTheWorld); + exploreBlockEndings(block.next, endOfTheWorld); if (block.next) { block.willGetTo = singular(block.next); @@ -840,12 +848,12 @@ function analyzer(data, givenTypes) { } // Remove unneeded label settings, if we set it to where we will get anyhow - function optimizeBlock(block) { + function optimizeBlockEndings(block) { if (!block) return; dprint('relooping', "// optimizing block: " + block.type + ' : ' + block.entries); - recurseBlock(block, optimizeBlock); + recurseBlock(block, optimizeBlockEndings); if (block.type === 'emulated' && block.willGetTo) { dprint('relooping', '// removing (trying): ' + block.willGetTo); @@ -873,11 +881,37 @@ function analyzer(data, givenTypes) { } } + // Checks whether we actually need labels. We return whether we have a loop nested inside us. + function optimizeOutUnneededLabels(block) { + if (!block) return false; + + dprint('relooping', "// optimizing (2) block: " + block.type + ' : ' + block.entries); + + var containLoop = sum(recurseBlock(block, optimizeOutUnneededLabels)) > 0; + + if (block.type === 'emulated') { + return containLoop; + } else if (block.type === 'multiple') { + // TODO: Apply the same optimization below for 'reloop', to looped multiples + return containLoop || !block.loopless; + } else if (block.type === 'reloop') { + if (!containLoop) { + block.needBlockId = false; + + replaceLabelLabels(block.labels, set('BCONT|' + block.id + '|*'), 'BCONT||*'); + replaceLabelLabels(block.labels, set('BREAK|' + block.id + '|*'), 'BREAK||*'); + } + return true; + } + assert(false); + } + // TODO: Parallelize item.functions.forEach(function(func) { dprint('relooping', "// loopOptimizing function: " + func.ident); - exploreBlock(func.block); - optimizeBlock(func.block); + exploreBlockEndings(func.block); + optimizeBlockEndings(func.block); + optimizeOutUnneededLabels(func.block); }); return finish(); } diff --git a/src/jsifier.js b/src/jsifier.js index 7efc407c..e93467c3 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -455,14 +455,14 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions, givenGlobalVaria } ret += '\n'; } else if (block.type == 'reloop') { - ret += indent + block.id + ': while(1) { ' + (SHOW_LABELS ? ' /* ' + block.entries + + ' */' : '') + '\n'; + ret += indent + (block.needBlockId ? block.id + ': ' : '') + 'while(1) { ' + (SHOW_LABELS ? ' /* ' + block.entries + + ' */' : '') + '\n'; ret += walkBlock(block.inner, indent + ' '); ret += indent + '}\n'; } else if (block.type == 'multiple') { var first = true; var multipleIdent = ''; if (!block.loopless) { - ret += indent + block.id + ':' + ' do { \n'; + ret += indent + (block.needBlockId ? block.id + ': ' : '') + 'do { \n'; multipleIdent = ' '; } var stolen = block.stolenCondition; @@ -630,9 +630,10 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions, givenGlobalVaria } if (label[0] == 'B') { var parts = label.split('|'); - var trueLabel = parts[1]; - var oldLabel = parts[2]; - var labelSetting = '__label__ = ' + getLabelId(oldLabel) + ';' + (SHOW_LABELS ? ' /* to: ' + cleanLabel(oldLabel) + ' */' : ''); // TODO: optimize away + var trueLabel = parts[1] || ''; + var oldLabel = parts[2] || ''; + var labelSetting = oldLabel ? '__label__ = ' + getLabelId(oldLabel) + ';' + + (SHOW_LABELS ? ' /* to: ' + cleanLabel(oldLabel) + ' */' : '') : ''; // TODO: optimize away the setting if (label[1] == 'R') { return pre + labelSetting + 'break ' + trueLabel + ';'; } else if (label[1] == 'C') { // CONT @@ -640,7 +641,7 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions, givenGlobalVaria } else if (label[1] == 'N') { // NOPP return pre + ';'; // Returning no text might confuse this parser } else if (label[1] == 'J') { // JSET - return pre + labelSetting; + return pre + labelSetting + ';'; } else { throw 'Invalid B-op in branch: ' + trueLabel + ',' + oldLabel; } diff --git a/src/parseTools.js b/src/parseTools.js index 52afcfe7..fed1ee7c 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -512,13 +512,14 @@ function calcAllocatedSize(type, TYPES) { // Flow blocks function recurseBlock(block, func) { + var ret = []; if (block.type == 'reloop') { - func(block.inner); + ret.push(func(block.inner)); } else if (block.type == 'multiple') { - block.entryLabels.forEach(function(entryLabel) { func(entryLabel.block) }); + block.entryLabels.forEach(function(entryLabel) { ret.push(func(entryLabel.block)) }); } - - func(block.next); + ret.push(func(block.next)); + return ret; } function getActualLabelId(labelId) { diff --git a/tests/runner.py b/tests/runner.py index 06418a29..900eede4 100644 --- a/tests/runner.py +++ b/tests/runner.py @@ -1577,6 +1577,8 @@ else: GUARD_MEMORY = SAFE_HEAP = CHECK_OVERFLOWS = CORRECT_OVERFLOWS = 0 LLVM_OPTS = 1 + USE_CLOSURE_COMPILER = 1 + TEST_REPS = 3 TOTAL_TESTS = 3 @@ -1598,28 +1600,33 @@ else: filename = os.path.join(dirname, 'src.cpp') self.build(src, dirname, filename, main_file=main_file) - # Optimize using closure compiler - try: - os.remove(filename + '.cc.js') - except: - pass - # Something like this: - # java -jar CLOSURE_COMPILER --compilation_level ADVANCED_OPTIMIZATIONS --formatting PRETTY_PRINT --variable_map_output_file src.cpp.o.js.vars --js src.cpp.o.js --js_output_file src.cpp.o.cc.js + final_filename = filename + '.o.js' + + if USE_CLOSURE_COMPILER: + # Optimize using closure compiler + try: + os.remove(filename + '.cc.js') + except: + pass + # Something like this: + # java -jar CLOSURE_COMPILER --compilation_level ADVANCED_OPTIMIZATIONS --formatting PRETTY_PRINT --variable_map_output_file src.cpp.o.js.vars --js src.cpp.o.js --js_output_file src.cpp.o.cc.js + + cc_output = Popen(['java', '-jar', CLOSURE_COMPILER, + '--compilation_level', 'SIMPLE_OPTIMIZATIONS', # XXX - ADVANCED clashes with our _STDIO object + '--formatting', 'PRETTY_PRINT', + '--variable_map_output_file', filename + '.vars', + '--js', filename + '.o.js', '--js_output_file', filename + '.cc.js'], stdout=PIPE, stderr=STDOUT).communicate()[0] + if 'ERROR' in cc_output: + raise Exception('Error in cc output: ' + cc_output) - cc_output = Popen(['java', '-jar', CLOSURE_COMPILER, - '--compilation_level', 'SIMPLE_OPTIMIZATIONS', # XXX - ADVANCED clashes with our _STDIO object - '--formatting', 'PRETTY_PRINT', - '--variable_map_output_file', filename + '.vars', - '--js', filename + '.o.js', '--js_output_file', filename + '.cc.js'], stdout=PIPE, stderr=STDOUT).communicate()[0] - if 'ERROR' in cc_output: - raise Exception('Error in cc output: ' + cc_output) + final_filename = filename + '.cc.js' # Run global total_times times = [] for i in range(TEST_REPS): start = time.time() - js_output = self.run_generated_code(JS_ENGINE, filename + '.cc.js', args, check_timeout=False) + js_output = self.run_generated_code(JS_ENGINE, final_filename, args, check_timeout=False) curr = time.time()-start times.append(curr) total_times[i] += curr |