| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library tree_ir.optimization.variable_merger; | 5 library tree_ir.optimization.variable_merger; |
| 6 | 6 |
| 7 import 'optimization.dart' show Pass; | 7 import 'optimization.dart' show Pass; |
| 8 import '../tree_ir_nodes.dart'; | 8 import '../tree_ir_nodes.dart'; |
| 9 import '../../elements/elements.dart' show Local, ParameterElement; | 9 import '../../elements/elements.dart' show Local, ParameterElement; |
| 10 | 10 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 27 } | 27 } |
| 28 | 28 |
| 29 /// Rewrites the given function. | 29 /// Rewrites the given function. |
| 30 /// This is called for the outermost function and inner functions. | 30 /// This is called for the outermost function and inner functions. |
| 31 void rewriteFunction(RootNode node) { | 31 void rewriteFunction(RootNode node) { |
| 32 node.forEachBody((Statement body) { | 32 node.forEachBody((Statement body) { |
| 33 BlockGraphBuilder builder = new BlockGraphBuilder(); | 33 BlockGraphBuilder builder = new BlockGraphBuilder(); |
| 34 builder.build(node.parameters, body); | 34 builder.build(node.parameters, body); |
| 35 _computeLiveness(builder.blocks); | 35 _computeLiveness(builder.blocks); |
| 36 Map<Variable, Variable> subst = | 36 Map<Variable, Variable> subst = |
| 37 _computeRegisterAllocation(builder.blocks); | 37 _computeRegisterAllocation(builder.blocks, node.parameters); |
| 38 new SubstituteVariables(subst).apply(node); | 38 new SubstituteVariables(subst).apply(node); |
| 39 }); | 39 }); |
| 40 } | 40 } |
| 41 } | 41 } |
| 42 | 42 |
| 43 /// A read or write access to a variable. | 43 /// A read or write access to a variable. |
| 44 class VariableAccess { | 44 class VariableAccess { |
| 45 Variable variable; | 45 Variable variable; |
| 46 bool isRead; | 46 bool isRead; |
| 47 bool get isWrite => !isRead; | 47 bool get isWrite => !isRead; |
| (...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 348 /// | 348 /// |
| 349 /// Constructs a register interference graph. This is an undirected graph of | 349 /// Constructs a register interference graph. This is an undirected graph of |
| 350 /// variables, with an edge between two variables if they cannot be merged | 350 /// variables, with an edge between two variables if they cannot be merged |
| 351 /// (because they are live simultaneously). | 351 /// (because they are live simultaneously). |
| 352 /// | 352 /// |
| 353 /// We then compute a graph coloring, where the color of a node denotes which | 353 /// We then compute a graph coloring, where the color of a node denotes which |
| 354 /// variable it will be substituted by. | 354 /// variable it will be substituted by. |
| 355 /// | 355 /// |
| 356 /// We never merge variables that originated from distinct source variables, | 356 /// We never merge variables that originated from distinct source variables, |
| 357 /// so we build a separate register interference graph for each source variable. | 357 /// so we build a separate register interference graph for each source variable. |
| 358 Map<Variable, Variable> _computeRegisterAllocation(List<Block> blocks) { | 358 Map<Variable, Variable> _computeRegisterAllocation(List<Block> blocks, |
| 359 List<Variable> parameters) { |
| 359 Map<Variable, Set<Variable>> interference = <Variable, Set<Variable>>{}; | 360 Map<Variable, Set<Variable>> interference = <Variable, Set<Variable>>{}; |
| 360 | 361 |
| 361 /// Group for the given variable. We attempt to merge variables in the same | 362 /// Group for the given variable. We attempt to merge variables in the same |
| 362 /// group. | 363 /// group. |
| 363 /// By default, variables are grouped based on their source variable, but | 364 /// By default, variables are grouped based on their source variable name, |
| 364 /// this can be disabled for testing purposes. | 365 /// but this can be disabled for testing purposes. |
| 365 Local group(Variable variable) { | 366 String group(Variable variable) { |
| 366 if (NO_PRESERVE_VARS) { | 367 if (NO_PRESERVE_VARS) return ''; |
| 367 // Parameters may not occur more than once in a parameter list, | 368 // Group variables based on the source variable's name, not its element, |
| 368 // so except for parameters, we try to merge all variables. | 369 // so if multiple locals are declared with the same name, they will |
| 369 return variable.element is ParameterElement ? variable.element : null; | 370 // map to the same (hoisted) variable in the output. |
| 370 } | 371 return variable.element == null ? '' : variable.element.name; |
| 371 return variable.element; | |
| 372 } | 372 } |
| 373 | 373 |
| 374 Set<Variable> empty = new Set<Variable>(); | 374 Set<Variable> empty = new Set<Variable>(); |
| 375 | 375 |
| 376 // At the assignment to a variable x, add an edge to every variable that is | 376 // At the assignment to a variable x, add an edge to every variable that is |
| 377 // live after the assignment (if it came from the same source variable). | 377 // live after the assignment (if it came from the same source variable). |
| 378 for (Block block in blocks) { | 378 for (Block block in blocks) { |
| 379 // Group the liveOut set by source variable. | 379 // Group the liveOut set by source variable. |
| 380 Map<Local, Set<Variable>> liveOut = <Local, Set<Variable>>{}; | 380 Map<String, Set<Variable>> liveOut = <String, Set<Variable>>{}; |
| 381 for (Variable variable in block.liveOut) { | 381 for (Variable variable in block.liveOut) { |
| 382 liveOut.putIfAbsent( | 382 liveOut.putIfAbsent( |
| 383 group(variable), | 383 group(variable), |
| 384 () => new Set<Variable>()).add(variable); | 384 () => new Set<Variable>()).add(variable); |
| 385 interference.putIfAbsent(variable, () => new Set<Variable>()); | 385 interference.putIfAbsent(variable, () => new Set<Variable>()); |
| 386 } | 386 } |
| 387 // Get variables that are live at the catch block. | 387 // Get variables that are live at the catch block. |
| 388 Set<Variable> liveCatch = block.catchBlock != null | 388 Set<Variable> liveCatch = block.catchBlock != null |
| 389 ? block.catchBlock.liveIn | 389 ? block.catchBlock.liveIn |
| 390 : empty; | 390 : empty; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 407 } | 407 } |
| 408 } | 408 } |
| 409 } | 409 } |
| 410 } | 410 } |
| 411 | 411 |
| 412 // Sort the variables by descending degree. | 412 // Sort the variables by descending degree. |
| 413 // The most constrained variables will be assigned a color first. | 413 // The most constrained variables will be assigned a color first. |
| 414 List<Variable> variables = interference.keys.toList(); | 414 List<Variable> variables = interference.keys.toList(); |
| 415 variables.sort((x, y) => interference[y].length - interference[x].length); | 415 variables.sort((x, y) => interference[y].length - interference[x].length); |
| 416 | 416 |
| 417 Map<Local, List<Variable>> registers = <Local, List<Variable>>{}; | 417 Map<String, List<Variable>> registers = <String, List<Variable>>{}; |
| 418 Map<Variable, Variable> subst = <Variable, Variable>{}; | 418 Map<Variable, Variable> subst = <Variable, Variable>{}; |
| 419 | 419 |
| 420 // Parameters are special in that they must have a ParameterElement and |
| 421 // cannot be merged with each other. Ensure that they are not substituted. |
| 422 // Other variables can still be substituted by a parameter. |
| 423 for (Variable parameter in parameters) { |
| 424 subst[parameter] = parameter; |
| 425 registers[group(parameter)] = <Variable>[parameter]; |
| 426 } |
| 427 |
| 420 for (Variable v1 in variables) { | 428 for (Variable v1 in variables) { |
| 429 // Parameters have already been assigned a substitute; skip those. |
| 430 if (subst.containsKey(v1)) continue; |
| 431 |
| 421 List<Variable> register = registers[group(v1)]; | 432 List<Variable> register = registers[group(v1)]; |
| 422 | 433 |
| 423 // Optimization: For the first variable in a group, allocate a new color | 434 // Optimization: For the first variable in a group, allocate a new color |
| 424 // without iterating over its interference edges. | 435 // without iterating over its interference edges. |
| 425 if (register == null) { | 436 if (register == null) { |
| 426 registers[group(v1)] = <Variable>[v1]; | 437 registers[group(v1)] = <Variable>[v1]; |
| 427 subst[v1] = v1; | 438 subst[v1] = v1; |
| 428 continue; | 439 continue; |
| 429 } | 440 } |
| 430 | 441 |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 529 // VariableDeclaration is only used for captured variables, which are never | 540 // VariableDeclaration is only used for captured variables, which are never |
| 530 // merged, so this is not strictly necessary. But it's nicer if this class | 541 // merged, so this is not strictly necessary. But it's nicer if this class |
| 531 // works for arbitrary substitution maps. | 542 // works for arbitrary substitution maps. |
| 532 node.variable = replaceWrite(node.variable); | 543 node.variable = replaceWrite(node.variable); |
| 533 node.value = visitExpression(node.value); | 544 node.value = visitExpression(node.value); |
| 534 node.next = visitStatement(node.next); | 545 node.next = visitStatement(node.next); |
| 535 return node; | 546 return node; |
| 536 } | 547 } |
| 537 | 548 |
| 538 } | 549 } |
| OLD | NEW |