| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 import '../compiler.dart' show Compiler; | 5 import '../compiler.dart' show Compiler; |
| 6 import '../constants/values.dart'; | 6 import '../constants/values.dart'; |
| 7 import '../elements/elements.dart'; | 7 import '../elements/elements.dart'; |
| 8 import '../js_backend/js_backend.dart'; | 8 import '../js_backend/js_backend.dart'; |
| 9 import '../types/types.dart'; | 9 import '../types/types.dart'; |
| 10 import '../universe/selector.dart' show Selector; | 10 import '../universe/selector.dart' show Selector; |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 60 } | 60 } |
| 61 | 61 |
| 62 HInstruction visitInstruction(HInstruction node) { | 62 HInstruction visitInstruction(HInstruction node) { |
| 63 return node; | 63 return node; |
| 64 } | 64 } |
| 65 | 65 |
| 66 HInstruction visitIs(HIs node) { | 66 HInstruction visitIs(HIs node) { |
| 67 if (node.kind == HIs.RAW_CHECK) { | 67 if (node.kind == HIs.RAW_CHECK) { |
| 68 HInstruction interceptor = node.interceptor; | 68 HInstruction interceptor = node.interceptor; |
| 69 if (interceptor != null) { | 69 if (interceptor != null) { |
| 70 return new HIsViaInterceptor(node.typeExpression, interceptor, | 70 return new HIsViaInterceptor( |
| 71 backend.boolType); | 71 node.typeExpression, interceptor, backend.boolType); |
| 72 } | 72 } |
| 73 } | 73 } |
| 74 return node; | 74 return node; |
| 75 } | 75 } |
| 76 | 76 |
| 77 HInstruction visitIdentity(HIdentity node) { | 77 HInstruction visitIdentity(HIdentity node) { |
| 78 node.singleComparisonOp = simpleOp(node.left, node.right); | 78 node.singleComparisonOp = simpleOp(node.left, node.right); |
| 79 return node; | 79 return node; |
| 80 } | 80 } |
| 81 | 81 |
| 82 String simpleOp(HInstruction left, HInstruction right) { | 82 String simpleOp(HInstruction left, HInstruction right) { |
| 83 // Returns the single identity comparison (== or ===) or null if a more | 83 // Returns the single identity comparison (== or ===) or null if a more |
| 84 // complex expression is required. | 84 // complex expression is required. |
| 85 TypeMask leftType = left.instructionType; | 85 TypeMask leftType = left.instructionType; |
| 86 TypeMask rightType = right.instructionType; | 86 TypeMask rightType = right.instructionType; |
| 87 if (leftType.isNullable && rightType.isNullable) { | 87 if (leftType.isNullable && rightType.isNullable) { |
| 88 if (left.isConstantNull() || | 88 if (left.isConstantNull() || |
| 89 right.isConstantNull() || | 89 right.isConstantNull() || |
| 90 (left.isPrimitive(compiler) && | 90 (left.isPrimitive(compiler) && leftType == rightType)) { |
| 91 leftType == rightType)) { | |
| 92 return '=='; | 91 return '=='; |
| 93 } | 92 } |
| 94 return null; | 93 return null; |
| 95 } | 94 } |
| 96 return '==='; | 95 return '==='; |
| 97 } | 96 } |
| 98 | 97 |
| 99 HInstruction visitInvokeDynamic(HInvokeDynamic node) { | 98 HInstruction visitInvokeDynamic(HInvokeDynamic node) { |
| 100 if (node.isInterceptedCall) { | 99 if (node.isInterceptedCall) { |
| 101 // Calls of the form | 100 // Calls of the form |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 186 HInstruction left = binary.left; | 185 HInstruction left = binary.left; |
| 187 HInstruction right = binary.right; | 186 HInstruction right = binary.right; |
| 188 if (isMatchingRead(left)) { | 187 if (isMatchingRead(left)) { |
| 189 if (left.usedBy.length == 1) { | 188 if (left.usedBy.length == 1) { |
| 190 if (right is HConstant && right.constant.isOne) { | 189 if (right is HConstant && right.constant.isOne) { |
| 191 HInstruction rmw = new HReadModifyWrite.preOp( | 190 HInstruction rmw = new HReadModifyWrite.preOp( |
| 192 setter.element, incrementOp, receiver, op.instructionType); | 191 setter.element, incrementOp, receiver, op.instructionType); |
| 193 return replaceOp(rmw, left); | 192 return replaceOp(rmw, left); |
| 194 } else { | 193 } else { |
| 195 HInstruction rmw = new HReadModifyWrite.assignOp( | 194 HInstruction rmw = new HReadModifyWrite.assignOp( |
| 196 setter.element, | 195 setter.element, assignOp, receiver, right, op.instructionType); |
| 197 assignOp, | |
| 198 receiver, right, op.instructionType); | |
| 199 return replaceOp(rmw, left); | 196 return replaceOp(rmw, left); |
| 200 } | 197 } |
| 201 } else if (op.usedBy.length == 1 && | 198 } else if (op.usedBy.length == 1 && |
| 202 right is HConstant && | 199 right is HConstant && |
| 203 right.constant.isOne) { | 200 right.constant.isOne) { |
| 204 HInstruction rmw = new HReadModifyWrite.postOp( | 201 HInstruction rmw = new HReadModifyWrite.postOp( |
| 205 setter.element, incrementOp, receiver, op.instructionType); | 202 setter.element, incrementOp, receiver, op.instructionType); |
| 206 block.addAfter(left, rmw); | 203 block.addAfter(left, rmw); |
| 207 block.remove(setter); | 204 block.remove(setter); |
| 208 block.remove(op); | 205 block.remove(op); |
| 209 block.rewrite(left, rmw); | 206 block.rewrite(left, rmw); |
| 210 block.remove(left); | 207 block.remove(left); |
| 211 return null; | 208 return null; |
| 212 } | 209 } |
| 213 } | 210 } |
| 214 return noMatchingRead(); | 211 return noMatchingRead(); |
| 215 } | 212 } |
| 216 | 213 |
| 217 HInstruction simple(String assignOp, | 214 HInstruction simple( |
| 218 HInstruction left, HInstruction right) { | 215 String assignOp, HInstruction left, HInstruction right) { |
| 219 if (isMatchingRead(left)) { | 216 if (isMatchingRead(left)) { |
| 220 if (left.usedBy.length == 1) { | 217 if (left.usedBy.length == 1) { |
| 221 HInstruction rmw = new HReadModifyWrite.assignOp( | 218 HInstruction rmw = new HReadModifyWrite.assignOp( |
| 222 setter.element, | 219 setter.element, assignOp, receiver, right, op.instructionType); |
| 223 assignOp, | |
| 224 receiver, right, op.instructionType); | |
| 225 return replaceOp(rmw, left); | 220 return replaceOp(rmw, left); |
| 226 } | 221 } |
| 227 } | 222 } |
| 228 return noMatchingRead(); | 223 return noMatchingRead(); |
| 229 } | 224 } |
| 230 | 225 |
| 231 HInstruction simpleBinary(String assignOp) { | 226 HInstruction simpleBinary(String assignOp) { |
| 232 HInvokeBinary binary = op; | 227 HInvokeBinary binary = op; |
| 233 return simple(assignOp, binary.left, binary.right); | 228 return simple(assignOp, binary.left, binary.right); |
| 234 } | 229 } |
| (...skipping 19 matching lines...) Expand all Loading... |
| 254 | 249 |
| 255 return noMatchingRead(); | 250 return noMatchingRead(); |
| 256 } | 251 } |
| 257 } | 252 } |
| 258 | 253 |
| 259 /** | 254 /** |
| 260 * Remove [HTypeKnown] instructions from the graph, to make codegen | 255 * Remove [HTypeKnown] instructions from the graph, to make codegen |
| 261 * analysis easier. | 256 * analysis easier. |
| 262 */ | 257 */ |
| 263 class SsaTypeKnownRemover extends HBaseVisitor { | 258 class SsaTypeKnownRemover extends HBaseVisitor { |
| 264 | |
| 265 void visitGraph(HGraph graph) { | 259 void visitGraph(HGraph graph) { |
| 266 visitDominatorTree(graph); | 260 visitDominatorTree(graph); |
| 267 } | 261 } |
| 268 | 262 |
| 269 void visitBasicBlock(HBasicBlock block) { | 263 void visitBasicBlock(HBasicBlock block) { |
| 270 HInstruction instruction = block.first; | 264 HInstruction instruction = block.first; |
| 271 while (instruction != null) { | 265 while (instruction != null) { |
| 272 HInstruction next = instruction.next; | 266 HInstruction next = instruction.next; |
| 273 instruction.accept(this); | 267 instruction.accept(this); |
| 274 instruction = next; | 268 instruction = next; |
| 275 } | 269 } |
| 276 } | 270 } |
| 277 | 271 |
| 278 void visitTypeKnown(HTypeKnown instruction) { | 272 void visitTypeKnown(HTypeKnown instruction) { |
| 279 instruction.block.rewrite(instruction, instruction.checkedInput); | 273 instruction.block.rewrite(instruction, instruction.checkedInput); |
| 280 instruction.block.remove(instruction); | 274 instruction.block.remove(instruction); |
| 281 } | 275 } |
| 282 } | 276 } |
| 283 | 277 |
| 284 /** | 278 /** |
| 285 * Remove [HTypeConversion] instructions from the graph in '--trust-primitives' | 279 * Remove [HTypeConversion] instructions from the graph in '--trust-primitives' |
| 286 * mode. | 280 * mode. |
| 287 */ | 281 */ |
| 288 class SsaTrustedCheckRemover extends HBaseVisitor { | 282 class SsaTrustedCheckRemover extends HBaseVisitor { |
| 289 | |
| 290 Compiler compiler; | 283 Compiler compiler; |
| 291 SsaTrustedCheckRemover(this.compiler); | 284 SsaTrustedCheckRemover(this.compiler); |
| 292 | 285 |
| 293 void visitGraph(HGraph graph) { | 286 void visitGraph(HGraph graph) { |
| 294 if (!compiler.options.trustPrimitives) return; | 287 if (!compiler.options.trustPrimitives) return; |
| 295 visitDominatorTree(graph); | 288 visitDominatorTree(graph); |
| 296 } | 289 } |
| 297 | 290 |
| 298 void visitBasicBlock(HBasicBlock block) { | 291 void visitBasicBlock(HBasicBlock block) { |
| 299 HInstruction instruction = block.first; | 292 HInstruction instruction = block.first; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 347 JavaScriptBackend get backend => compiler.backend; | 340 JavaScriptBackend get backend => compiler.backend; |
| 348 | 341 |
| 349 void visitGraph(HGraph graph) { | 342 void visitGraph(HGraph graph) { |
| 350 visitDominatorTree(graph); | 343 visitDominatorTree(graph); |
| 351 } | 344 } |
| 352 | 345 |
| 353 void analyzeInputs(HInstruction user, int start) { | 346 void analyzeInputs(HInstruction user, int start) { |
| 354 List<HInstruction> inputs = user.inputs; | 347 List<HInstruction> inputs = user.inputs; |
| 355 for (int i = start; i < inputs.length; i++) { | 348 for (int i = start; i < inputs.length; i++) { |
| 356 HInstruction input = inputs[i]; | 349 HInstruction input = inputs[i]; |
| 357 if (!generateAtUseSite.contains(input) | 350 if (!generateAtUseSite.contains(input) && |
| 358 && !input.isCodeMotionInvariant() | 351 !input.isCodeMotionInvariant() && |
| 359 && input.usedBy.length == 1 | 352 input.usedBy.length == 1 && |
| 360 && input is !HPhi | 353 input is! HPhi && |
| 361 && input is !HLocalValue | 354 input is! HLocalValue && |
| 362 && !input.isJsStatement()) { | 355 !input.isJsStatement()) { |
| 363 if (input.isPure()) { | 356 if (input.isPure()) { |
| 364 // Only consider a pure input if it is in the same loop. | 357 // Only consider a pure input if it is in the same loop. |
| 365 // Otherwise, we might move GVN'ed instruction back into the | 358 // Otherwise, we might move GVN'ed instruction back into the |
| 366 // loop. | 359 // loop. |
| 367 if (user.hasSameLoopHeaderAs(input)) { | 360 if (user.hasSameLoopHeaderAs(input)) { |
| 368 // Move it closer to [user], so that instructions in | 361 // Move it closer to [user], so that instructions in |
| 369 // between do not prevent making it generate at use site. | 362 // between do not prevent making it generate at use site. |
| 370 input.moveBefore(user); | 363 input.moveBefore(user); |
| 371 pureInputs.add(input); | 364 pureInputs.add(input); |
| 372 // Previous computations done on [input] are now invalid | 365 // Previous computations done on [input] are now invalid |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 434 // does not require an expression with multiple uses (because of null / | 427 // does not require an expression with multiple uses (because of null / |
| 435 // undefined). | 428 // undefined). |
| 436 void visitIdentity(HIdentity instruction) { | 429 void visitIdentity(HIdentity instruction) { |
| 437 if (instruction.singleComparisonOp != null) { | 430 if (instruction.singleComparisonOp != null) { |
| 438 super.visitIdentity(instruction); | 431 super.visitIdentity(instruction); |
| 439 } | 432 } |
| 440 // Do nothing. | 433 // Do nothing. |
| 441 } | 434 } |
| 442 | 435 |
| 443 void visitTypeConversion(HTypeConversion instruction) { | 436 void visitTypeConversion(HTypeConversion instruction) { |
| 444 if (!instruction.isArgumentTypeCheck | 437 if (!instruction.isArgumentTypeCheck && !instruction.isReceiverTypeCheck) { |
| 445 && !instruction.isReceiverTypeCheck) { | |
| 446 assert(instruction.isCheckedModeCheck || instruction.isCastTypeCheck); | 438 assert(instruction.isCheckedModeCheck || instruction.isCastTypeCheck); |
| 447 // Checked mode checks and cast checks compile to code that | 439 // Checked mode checks and cast checks compile to code that |
| 448 // only use their input once, so we can safely visit them | 440 // only use their input once, so we can safely visit them |
| 449 // and try to merge the input. | 441 // and try to merge the input. |
| 450 visitInstruction(instruction); | 442 visitInstruction(instruction); |
| 451 } | 443 } |
| 452 } | 444 } |
| 453 | 445 |
| 454 void visitTypeKnown(HTypeKnown instruction) { | 446 void visitTypeKnown(HTypeKnown instruction) { |
| 455 // [HTypeKnown] instructions are removed before code generation. | 447 // [HTypeKnown] instructions are removed before code generation. |
| 456 assert(false); | 448 assert(false); |
| 457 } | 449 } |
| 458 | 450 |
| 459 void tryGenerateAtUseSite(HInstruction instruction) { | 451 void tryGenerateAtUseSite(HInstruction instruction) { |
| 460 if (instruction.isControlFlow()) return; | 452 if (instruction.isControlFlow()) return; |
| 461 markAsGenerateAtUseSite(instruction); | 453 markAsGenerateAtUseSite(instruction); |
| 462 } | 454 } |
| 463 | 455 |
| 464 bool isBlockSinglePredecessor(HBasicBlock block) { | 456 bool isBlockSinglePredecessor(HBasicBlock block) { |
| 465 return block.successors.length == 1 | 457 return block.successors.length == 1 && |
| 466 && block.successors[0].predecessors.length == 1; | 458 block.successors[0].predecessors.length == 1; |
| 467 } | 459 } |
| 468 | 460 |
| 469 void visitBasicBlock(HBasicBlock block) { | 461 void visitBasicBlock(HBasicBlock block) { |
| 470 // Compensate from not merging blocks: if the block is the | 462 // Compensate from not merging blocks: if the block is the |
| 471 // single predecessor of its single successor, let the successor | 463 // single predecessor of its single successor, let the successor |
| 472 // visit it. | 464 // visit it. |
| 473 if (isBlockSinglePredecessor(block)) return; | 465 if (isBlockSinglePredecessor(block)) return; |
| 474 | 466 |
| 475 tryMergingExpressions(block); | 467 tryMergingExpressions(block); |
| 476 } | 468 } |
| (...skipping 19 matching lines...) Expand all Loading... |
| 496 assert(nextInput.usedBy.length == 1); | 488 assert(nextInput.usedBy.length == 1); |
| 497 if (identical(nextInput, instruction)) { | 489 if (identical(nextInput, instruction)) { |
| 498 return true; | 490 return true; |
| 499 } | 491 } |
| 500 } | 492 } |
| 501 return false; | 493 return false; |
| 502 } | 494 } |
| 503 | 495 |
| 504 block.last.accept(this); | 496 block.last.accept(this); |
| 505 for (HInstruction instruction = block.last.previous; | 497 for (HInstruction instruction = block.last.previous; |
| 506 instruction != null; | 498 instruction != null; |
| 507 instruction = instruction.previous) { | 499 instruction = instruction.previous) { |
| 508 if (generateAtUseSite.contains(instruction)) { | 500 if (generateAtUseSite.contains(instruction)) { |
| 509 continue; | 501 continue; |
| 510 } | 502 } |
| 511 if (instruction.isCodeMotionInvariant()) { | 503 if (instruction.isCodeMotionInvariant()) { |
| 512 markAsGenerateAtUseSite(instruction); | 504 markAsGenerateAtUseSite(instruction); |
| 513 continue; | 505 continue; |
| 514 } | 506 } |
| 515 if (instruction.isPure()) { | 507 if (instruction.isPure()) { |
| 516 if (pureInputs.contains(instruction)) { | 508 if (pureInputs.contains(instruction)) { |
| 517 tryGenerateAtUseSite(instruction); | 509 tryGenerateAtUseSite(instruction); |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 578 // The current instruction is the next non-trivial | 570 // The current instruction is the next non-trivial |
| 579 // expected input. | 571 // expected input. |
| 580 tryGenerateAtUseSite(instruction); | 572 tryGenerateAtUseSite(instruction); |
| 581 } else { | 573 } else { |
| 582 assert(expectedInputs.isEmpty); | 574 assert(expectedInputs.isEmpty); |
| 583 } | 575 } |
| 584 instruction.accept(this); | 576 instruction.accept(this); |
| 585 } | 577 } |
| 586 } | 578 } |
| 587 | 579 |
| 588 if (block.predecessors.length == 1 | 580 if (block.predecessors.length == 1 && |
| 589 && isBlockSinglePredecessor(block.predecessors[0])) { | 581 isBlockSinglePredecessor(block.predecessors[0])) { |
| 590 assert(block.phis.isEmpty); | 582 assert(block.phis.isEmpty); |
| 591 tryMergingExpressions(block.predecessors[0]); | 583 tryMergingExpressions(block.predecessors[0]); |
| 592 } else { | 584 } else { |
| 593 expectedInputs = null; | 585 expectedInputs = null; |
| 594 pureInputs = null; | 586 pureInputs = null; |
| 595 } | 587 } |
| 596 } | 588 } |
| 597 } | 589 } |
| 598 | 590 |
| 599 /** | 591 /** |
| (...skipping 23 matching lines...) Expand all Loading... |
| 623 bool hasAnyStatement(HBasicBlock block, HInstruction instruction) { | 615 bool hasAnyStatement(HBasicBlock block, HInstruction instruction) { |
| 624 // If [instruction] is not in [block], then if the block is not | 616 // If [instruction] is not in [block], then if the block is not |
| 625 // empty, we know there will be a statement to emit. | 617 // empty, we know there will be a statement to emit. |
| 626 if (!identical(instruction.block, block)) { | 618 if (!identical(instruction.block, block)) { |
| 627 return !identical(block.last, block.first); | 619 return !identical(block.last, block.first); |
| 628 } | 620 } |
| 629 | 621 |
| 630 // If [instruction] is not the last instruction of the block | 622 // If [instruction] is not the last instruction of the block |
| 631 // before the control flow instruction, or the last instruction, | 623 // before the control flow instruction, or the last instruction, |
| 632 // then we will have to emit a statement for that last instruction. | 624 // then we will have to emit a statement for that last instruction. |
| 633 if (instruction != block.last | 625 if (instruction != block.last && |
| 634 && !identical(instruction, block.last.previous)) return true; | 626 !identical(instruction, block.last.previous)) return true; |
| 635 | 627 |
| 636 // If one of the instructions in the block until [instruction] is | 628 // If one of the instructions in the block until [instruction] is |
| 637 // not generated at use site, then we will have to emit a | 629 // not generated at use site, then we will have to emit a |
| 638 // statement for it. | 630 // statement for it. |
| 639 // TODO(ngeoffray): we could generate a comma separated | 631 // TODO(ngeoffray): we could generate a comma separated |
| 640 // list of expressions. | 632 // list of expressions. |
| 641 for (HInstruction temp = block.first; | 633 for (HInstruction temp = block.first; |
| 642 !identical(temp, instruction); | 634 !identical(temp, instruction); |
| 643 temp = temp.next) { | 635 temp = temp.next) { |
| 644 if (!generateAtUseSite.contains(temp)) return true; | 636 if (!generateAtUseSite.contains(temp)) return true; |
| 645 } | 637 } |
| 646 | 638 |
| 647 return false; | 639 return false; |
| 648 } | 640 } |
| 649 | 641 |
| 650 bool isSafeToGenerateAtUseSite(HInstruction user, HInstruction input) { | 642 bool isSafeToGenerateAtUseSite(HInstruction user, HInstruction input) { |
| 651 // HForeignNew evaluates arguments in order and passes them to a | 643 // HForeignNew evaluates arguments in order and passes them to a |
| 652 // constructor. | 644 // constructor. |
| 653 if (user is HForeignNew) return true; | 645 if (user is HForeignNew) return true; |
| 654 // A [HForeign] instruction uses operators and if we generate | 646 // A [HForeign] instruction uses operators and if we generate |
| 655 // [input] at use site, the precedence might be wrong. | 647 // [input] at use site, the precedence might be wrong. |
| 656 if (user is HForeign) return false; | 648 if (user is HForeign) return false; |
| 657 // A [HCheck] instruction with control flow uses its input | 649 // A [HCheck] instruction with control flow uses its input |
| 658 // multiple times, so we avoid generating it at use site. | 650 // multiple times, so we avoid generating it at use site. |
| 659 if (user is HCheck && user.isControlFlow()) return false; | 651 if (user is HCheck && user.isControlFlow()) return false; |
| 660 // A [HIs] instruction uses its input multiple times, so we | 652 // A [HIs] instruction uses its input multiple times, so we |
| 661 // avoid generating it at use site. | 653 // avoid generating it at use site. |
| 662 if (user is HIs) return false; | 654 if (user is HIs) return false; |
| 663 return true; | 655 return true; |
| 664 } | 656 } |
| 665 | 657 |
| 666 void visitBasicBlock(HBasicBlock block) { | 658 void visitBasicBlock(HBasicBlock block) { |
| 667 if (block.last is !HIf) return; | 659 if (block.last is! HIf) return; |
| 668 HIf startIf = block.last; | 660 HIf startIf = block.last; |
| 669 HBasicBlock end = startIf.joinBlock; | 661 HBasicBlock end = startIf.joinBlock; |
| 670 | 662 |
| 671 // We check that the structure is the following: | 663 // We check that the structure is the following: |
| 672 // If | 664 // If |
| 673 // / \ | 665 // / \ |
| 674 // / \ | 666 // / \ |
| 675 // 1 expr goto | 667 // 1 expr goto |
| 676 // goto / | 668 // goto / |
| 677 // \ / | 669 // \ / |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 747 | 739 |
| 748 // Find the next non-HGoto instruction following the phi. | 740 // Find the next non-HGoto instruction following the phi. |
| 749 HInstruction nextInstruction = phi.block.first; | 741 HInstruction nextInstruction = phi.block.first; |
| 750 while (nextInstruction is HGoto) { | 742 while (nextInstruction is HGoto) { |
| 751 nextInstruction = nextInstruction.block.successors[0].first; | 743 nextInstruction = nextInstruction.block.successors[0].first; |
| 752 } | 744 } |
| 753 | 745 |
| 754 // If the operation is only used by the first instruction | 746 // If the operation is only used by the first instruction |
| 755 // of its block and is safe to be generated at use site, mark it | 747 // of its block and is safe to be generated at use site, mark it |
| 756 // so. | 748 // so. |
| 757 if (phi.usedBy.length == 1 | 749 if (phi.usedBy.length == 1 && |
| 758 && phi.usedBy[0] == nextInstruction | 750 phi.usedBy[0] == nextInstruction && |
| 759 && isSafeToGenerateAtUseSite(phi.usedBy[0], phi)) { | 751 isSafeToGenerateAtUseSite(phi.usedBy[0], phi)) { |
| 760 markAsGenerateAtUseSite(phi); | 752 markAsGenerateAtUseSite(phi); |
| 761 } | 753 } |
| 762 | 754 |
| 763 if (identical(elseInput.block, elseBlock)) { | 755 if (identical(elseInput.block, elseBlock)) { |
| 764 assert(elseInput.usedBy.length == 1); | 756 assert(elseInput.usedBy.length == 1); |
| 765 markAsGenerateAtUseSite(elseInput); | 757 markAsGenerateAtUseSite(elseInput); |
| 766 } | 758 } |
| 767 | 759 |
| 768 // If [thenInput] is defined in the first predecessor, then it is only used | 760 // If [thenInput] is defined in the first predecessor, then it is only used |
| 769 // by [phi] and can be generated at use site. | 761 // by [phi] and can be generated at use site. |
| 770 if (identical(thenInput.block, end.predecessors[0])) { | 762 if (identical(thenInput.block, end.predecessors[0])) { |
| 771 assert(thenInput.usedBy.length == 1); | 763 assert(thenInput.usedBy.length == 1); |
| 772 markAsGenerateAtUseSite(thenInput); | 764 markAsGenerateAtUseSite(thenInput); |
| 773 } | 765 } |
| 774 } | 766 } |
| 775 } | 767 } |
| OLD | NEW |