| 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 | 9 |
| 10 /// Merges variables based on liveness and source variable information. | 10 /// Merges variables based on liveness and source variable information. |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 126 Block block = new Block(catchBlock); | 126 Block block = new Block(catchBlock); |
| 127 blocks.add(block); | 127 blocks.add(block); |
| 128 return block; | 128 return block; |
| 129 } | 129 } |
| 130 | 130 |
| 131 /// Starts a new block after the end of [block]. | 131 /// Starts a new block after the end of [block]. |
| 132 void branchFrom(Block block, {Block catchBlock}) { | 132 void branchFrom(Block block, {Block catchBlock}) { |
| 133 _currentBlock = newBlock(catchBlock: catchBlock)..predecessors.add(block); | 133 _currentBlock = newBlock(catchBlock: catchBlock)..predecessors.add(block); |
| 134 } | 134 } |
| 135 | 135 |
| 136 /// Starts a new block with the given blocks as predecessors. |
| 137 void joinFrom(Block block1, Block block2) { |
| 138 assert(block1.catchBlock == block2.catchBlock); |
| 139 _currentBlock = newBlock(catchBlock: block1.catchBlock); |
| 140 _currentBlock.predecessors.add(block1); |
| 141 _currentBlock.predecessors.add(block2); |
| 142 } |
| 143 |
| 136 /// Called when reading from [variable]. | 144 /// Called when reading from [variable]. |
| 137 /// | 145 /// |
| 138 /// Appends a read operation to the current basic block. | 146 /// Appends a read operation to the current basic block. |
| 139 void read(Variable variable) { | 147 void read(Variable variable) { |
| 140 if (variable.isCaptured) return; | 148 if (variable.isCaptured) return; |
| 141 if (_ignoredVariables.contains(variable)) return; | 149 if (_ignoredVariables.contains(variable)) return; |
| 142 _currentBlock.addRead(variable); | 150 _currentBlock.addRead(variable); |
| 143 } | 151 } |
| 144 | 152 |
| 145 /// Called when writing to [variable]. | 153 /// Called when writing to [variable]. |
| (...skipping 19 matching lines...) Expand all Loading... |
| 165 visitAssign(Assign node) { | 173 visitAssign(Assign node) { |
| 166 visitExpression(node.value); | 174 visitExpression(node.value); |
| 167 write(node.variable); | 175 write(node.variable); |
| 168 } | 176 } |
| 169 | 177 |
| 170 visitIf(If node) { | 178 visitIf(If node) { |
| 171 visitExpression(node.condition); | 179 visitExpression(node.condition); |
| 172 Block afterCondition = _currentBlock; | 180 Block afterCondition = _currentBlock; |
| 173 branchFrom(afterCondition); | 181 branchFrom(afterCondition); |
| 174 visitStatement(node.thenStatement); | 182 visitStatement(node.thenStatement); |
| 183 Block afterThen = _currentBlock; |
| 175 branchFrom(afterCondition); | 184 branchFrom(afterCondition); |
| 176 visitStatement(node.elseStatement); | 185 visitStatement(node.elseStatement); |
| 186 joinFrom(_currentBlock, afterThen); |
| 177 } | 187 } |
| 178 | 188 |
| 179 visitLabeledStatement(LabeledStatement node) { | 189 visitLabeledStatement(LabeledStatement node) { |
| 180 Block join = _jumpTarget[node.label] = newBlock(); | 190 Block join = _jumpTarget[node.label] = newBlock(); |
| 181 visitStatement(node.body); // visitBreak will add predecessors to join. | 191 visitStatement(node.body); // visitBreak will add predecessors to join. |
| 182 _currentBlock = join; | 192 _currentBlock = join; |
| 183 visitStatement(node.next); | 193 visitStatement(node.next); |
| 184 } | 194 } |
| 185 | 195 |
| 186 visitBreak(Break node) { | 196 visitBreak(Break node) { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 204 _currentBlock = join; | 214 _currentBlock = join; |
| 205 visitExpression(node.condition); | 215 visitExpression(node.condition); |
| 206 Block afterCondition = _currentBlock; | 216 Block afterCondition = _currentBlock; |
| 207 branchFrom(afterCondition); | 217 branchFrom(afterCondition); |
| 208 visitStatement(node.body); // visitContinue will add predecessors to join. | 218 visitStatement(node.body); // visitContinue will add predecessors to join. |
| 209 branchFrom(afterCondition); | 219 branchFrom(afterCondition); |
| 210 visitStatement(node.next); | 220 visitStatement(node.next); |
| 211 } | 221 } |
| 212 | 222 |
| 213 visitTry(Try node) { | 223 visitTry(Try node) { |
| 214 Block catchBlock = newBlock(); | 224 Block outerCatchBlock = _currentBlock.catchBlock; |
| 225 Block catchBlock = newBlock(catchBlock: outerCatchBlock); |
| 215 branchFrom(_currentBlock, catchBlock: catchBlock); | 226 branchFrom(_currentBlock, catchBlock: catchBlock); |
| 216 visitStatement(node.tryBody); | 227 visitStatement(node.tryBody); |
| 228 Block afterTry = _currentBlock; |
| 217 _currentBlock = catchBlock; | 229 _currentBlock = catchBlock; |
| 218 // Catch parameters cannot be hoisted to the top of the function, so to | 230 // Catch parameters cannot be hoisted to the top of the function, so to |
| 219 // avoid complications with scoping, we do not attempt to merge them. | 231 // avoid complications with scoping, we do not attempt to merge them. |
| 220 node.catchParameters.forEach(ignoreVariable); | 232 node.catchParameters.forEach(ignoreVariable); |
| 221 visitStatement(node.catchBody); | 233 visitStatement(node.catchBody); |
| 234 Block afterCatch = _currentBlock; |
| 235 _currentBlock = newBlock(catchBlock: outerCatchBlock); |
| 236 _currentBlock.predecessors.add(afterCatch); |
| 237 _currentBlock.predecessors.add(afterTry); |
| 222 } | 238 } |
| 223 | 239 |
| 224 visitConditional(Conditional node) { | 240 visitConditional(Conditional node) { |
| 225 visitExpression(node.condition); | 241 visitExpression(node.condition); |
| 226 Block afterCondition = _currentBlock; | 242 Block afterCondition = _currentBlock; |
| 227 branchFrom(afterCondition); | 243 branchFrom(afterCondition); |
| 228 visitExpression(node.thenExpression); | 244 visitExpression(node.thenExpression); |
| 245 Block afterThen = _currentBlock; |
| 229 branchFrom(afterCondition); | 246 branchFrom(afterCondition); |
| 230 visitExpression(node.elseExpression); | 247 visitExpression(node.elseExpression); |
| 248 joinFrom(_currentBlock, afterThen); |
| 231 } | 249 } |
| 232 | 250 |
| 233 visitLogicalOperator(LogicalOperator node) { | 251 visitLogicalOperator(LogicalOperator node) { |
| 234 visitExpression(node.left); | 252 visitExpression(node.left); |
| 235 Block afterCondition = _currentBlock; | 253 Block afterLeft = _currentBlock; |
| 236 branchFrom(afterCondition); | 254 branchFrom(afterLeft); |
| 237 visitExpression(node.right); | 255 visitExpression(node.right); |
| 256 joinFrom(_currentBlock, afterLeft); |
| 238 } | 257 } |
| 239 } | 258 } |
| 240 | 259 |
| 241 /// Computes liveness information of the given control-flow graph. | 260 /// Computes liveness information of the given control-flow graph. |
| 242 /// | 261 /// |
| 243 /// The results are stored in [Block.liveIn] and [Block.liveOut]. | 262 /// The results are stored in [Block.liveIn] and [Block.liveOut]. |
| 244 void _computeLiveness(List<Block> blocks) { | 263 void _computeLiveness(List<Block> blocks) { |
| 245 // We use a LIFO queue as worklist. Blocks are given in AST order, so by | 264 // We use a LIFO queue as worklist. Blocks are given in AST order, so by |
| 246 // inserting them in this order, we initially visit them backwards, which | 265 // inserting them in this order, we initially visit them backwards, which |
| 247 // is a good ordering. | 266 // is a good ordering. |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 317 pred.inWorklist = true; | 336 pred.inWorklist = true; |
| 318 } | 337 } |
| 319 } | 338 } |
| 320 } | 339 } |
| 321 } | 340 } |
| 322 } | 341 } |
| 323 | 342 |
| 324 /// For testing purposes, this flag can be passed to merge variables that | 343 /// For testing purposes, this flag can be passed to merge variables that |
| 325 /// originated from different source variables. | 344 /// originated from different source variables. |
| 326 /// | 345 /// |
| 327 /// Correctness should not depend on the fact that we only merge variable | 346 /// Correctness should not depend on the fact that we only merge variables |
| 328 /// originating from the same source variable. Setting this flag makes a bug | 347 /// originating from the same source variable. Setting this flag makes a bug |
| 329 /// more likely to provoke a test case failure. | 348 /// more likely to provoke a test case failure. |
| 330 const bool NO_PRESERVE_VARS = const bool.fromEnvironment('NO_PRESERVE_VARS'); | 349 const bool NO_PRESERVE_VARS = const bool.fromEnvironment('NO_PRESERVE_VARS'); |
| 331 | 350 |
| 332 /// Based on liveness information, computes a map of variable substitutions to | 351 /// Based on liveness information, computes a map of variable substitutions to |
| 333 /// merge variables. | 352 /// merge variables. |
| 334 /// | 353 /// |
| 335 /// Constructs a register interference graph. This is an undirected graph of | 354 /// Constructs a register interference graph. This is an undirected graph of |
| 336 /// variables, with an edge between two variables if they cannot be merged | 355 /// variables, with an edge between two variables if they cannot be merged |
| 337 /// (because they are live simultaneously). | 356 /// (because they are live simultaneously). |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 419 List<Variable> register = registers[group(v1)]; | 438 List<Variable> register = registers[group(v1)]; |
| 420 | 439 |
| 421 // Optimization: For the first variable in a group, allocate a new color | 440 // Optimization: For the first variable in a group, allocate a new color |
| 422 // without iterating over its interference edges. | 441 // without iterating over its interference edges. |
| 423 if (register == null) { | 442 if (register == null) { |
| 424 registers[group(v1)] = <Variable>[v1]; | 443 registers[group(v1)] = <Variable>[v1]; |
| 425 subst[v1] = v1; | 444 subst[v1] = v1; |
| 426 continue; | 445 continue; |
| 427 } | 446 } |
| 428 | 447 |
| 429 // Optimization: If there are no inteference edges for this variable, | 448 // Optimization: If there are no interference edges for this variable, |
| 430 // assign it the first color without copying the register list. | 449 // assign it the first color without copying the register list. |
| 431 Set<Variable> interferenceSet = interference[v1]; | 450 Set<Variable> interferenceSet = interference[v1]; |
| 432 if (interferenceSet.isEmpty) { | 451 if (interferenceSet.isEmpty) { |
| 433 subst[v1] = register[0]; | 452 subst[v1] = register[0]; |
| 434 continue; | 453 continue; |
| 435 } | 454 } |
| 436 | 455 |
| 437 // Find an unused color. | 456 // Find an unused color. |
| 438 Set<Variable> potential = new Set<Variable>.from(register); | 457 Set<Variable> potential = new Set<Variable>.from(register); |
| 439 for (Variable v2 in interferenceSet) { | 458 for (Variable v2 in interferenceSet) { |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 516 node.expression = visitExpression(node.expression); | 535 node.expression = visitExpression(node.expression); |
| 517 node.next = visitStatement(node.next); | 536 node.next = visitStatement(node.next); |
| 518 if (node.expression is VariableUse) { | 537 if (node.expression is VariableUse) { |
| 519 VariableUse use = node.expression; | 538 VariableUse use = node.expression; |
| 520 --use.variable.readCount; | 539 --use.variable.readCount; |
| 521 return node.next; | 540 return node.next; |
| 522 } | 541 } |
| 523 return node; | 542 return node; |
| 524 } | 543 } |
| 525 } | 544 } |
| OLD | NEW |