diff options
author | Alon Zakai <alonzakai@gmail.com> | 2011-11-07 18:24:19 -0800 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2011-11-07 18:24:19 -0800 |
commit | bcccdc948dc02db5a5b17ef722ddf3f688a8cc9e (patch) | |
tree | 6930d2959f292c63dac7f423d6da24131c66c29a /tools | |
parent | 6fe0acce5da7f625ecadc9718842aef08faabd57 (diff) |
expression optimizer in eliminator
Diffstat (limited to 'tools')
-rw-r--r-- | tools/eliminator/eliminator-test-output.js | 3 | ||||
-rw-r--r-- | tools/eliminator/eliminator-test.js | 5 | ||||
-rw-r--r-- | tools/eliminator/eliminator.coffee | 59 |
3 files changed, 55 insertions, 12 deletions
diff --git a/tools/eliminator/eliminator-test-output.js b/tools/eliminator/eliminator-test-output.js index b7a983cc..09a71d87 100644 --- a/tools/eliminator/eliminator-test-output.js +++ b/tools/eliminator/eliminator-test-output.js @@ -105,3 +105,6 @@ var anon = (function(x) { var $8 = $4 + 12; HEAP[$8] = $7; }); +function r($0) { + HEAP[$0 + 7] = 107; +} diff --git a/tools/eliminator/eliminator-test.js b/tools/eliminator/eliminator-test.js index 681b6cf7..2443d707 100644 --- a/tools/eliminator/eliminator-test.js +++ b/tools/eliminator/eliminator-test.js @@ -105,5 +105,8 @@ var anon = function(x) { var $8 = $4 + 12; HEAP[$8] = $7; } -// EMSCRIPTEN_GENERATED_FUNCTIONS: ["f", "g", "h", "py"] +function r($0) { + HEAP[$0 + 5 + 2] = 99+5+2+1; +} +// EMSCRIPTEN_GENERATED_FUNCTIONS: ["f", "g", "h", "py", "r"] diff --git a/tools/eliminator/eliminator.coffee b/tools/eliminator/eliminator.coffee index c6de8690..52ba50c6 100644 --- a/tools/eliminator/eliminator.coffee +++ b/tools/eliminator/eliminator.coffee @@ -23,6 +23,8 @@ fs = require 'fs' # Functions which have been generated by Emscripten. We optimize only those. generatedFunctions = [] GENERATED_FUNCTIONS_MARKER = '// EMSCRIPTEN_GENERATED_FUNCTIONS:' +isGenerated = (ident) -> + ident in generatedFunctions # Maximum number of uses to consider a variable not worth eliminating. MAX_USES = 3 @@ -83,8 +85,6 @@ traverse = (node, callback) -> # function/defun node and call run() to apply the optimization (in-place). class Eliminator constructor: (func) -> - @ident = func[1] - # The statements of the function to analyze. @body = func[3] @@ -112,9 +112,6 @@ class Eliminator # Runs the eliminator on a given function body updating the AST in-place. # @returns: The number of variables eliminated, or undefined if skipped. run: -> - # Our optimization does not account for closures. - if not @isGenerated() then return undefined - @calculateBasicVarStats() @analyzeInitialValues() @calculateTransitiveDependencies() @@ -133,10 +130,6 @@ class Eliminator return eliminated - # Determines if a function is Emscripten-generated. - isGenerated: -> - return @ident in generatedFunctions - # Runs the basic variable scan pass. Fills the following member variables: # isLocal # isSingleDef @@ -330,6 +323,44 @@ class Eliminator return undefined +# A class for optimizing expressions. We know that it is legitimate to collapse +# 5+7 in the generated code, as it will always be numerical, for example. +class ExpressionOptimizer + constructor: (node) -> + @node = node + + run: -> + traverse @node, (node, type) -> + if type is 'binary' and node[1] == '+' + names = [] + num = 0 + has_num = false + fail = false + traverse node, (subNode, subType) -> + if subType is 'binary' + if subNode[1] isnt '+' + fail = true + return false + return undefined + else if subType is 'name' + names.push subNode[1] + return undefined + else if subType is 'num' + num += subNode[1] + has_num = true + return undefined + else + fail = true + return false + if not fail and has_num + ret = ['num', num] + for name in names + ret = ['binary', '+', ['name', name], ret] + return ret + return undefined + + return undefined + # The main entry point. Reads JavaScript from stdin, runs the eliminator on each # function, then writes the optimized result to stdout. main = -> @@ -343,15 +374,21 @@ main = -> ast = uglify.parser.parse src - # Run the eliminator on all functions. + # Run on all functions. traverse ast, (node, type) -> - if type in ['defun', 'function'] + if type in ['defun', 'function'] and isGenerated node[1] + + # Run the eliminator process.stderr.write (node[1] || '(anonymous)') + '\n' eliminated = new Eliminator(node).run() if eliminated? process.stderr.write " Eliminated #{eliminated} vars.\n" + + # Run the expression optimizer + new ExpressionOptimizer(node[3]).run() else process.stderr.write ' Skipped.\n' + return undefined # Write out the optimized code. |