| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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 'nodes.dart'; | 5 import 'nodes.dart'; |
| 6 | 6 |
| 7 class HValidator extends HInstructionVisitor { | 7 class HValidator extends HInstructionVisitor { |
| 8 bool isValid = true; | 8 bool isValid = true; |
| 9 HGraph graph; | 9 HGraph graph; |
| 10 | 10 |
| 11 void visitGraph(HGraph visitee) { | 11 void visitGraph(HGraph visitee) { |
| 12 graph = visitee; | 12 graph = visitee; |
| 13 visitDominatorTree(visitee); | 13 visitDominatorTree(visitee); |
| 14 } | 14 } |
| 15 | 15 |
| 16 void markInvalid(String reason) { | 16 void markInvalid(String reason) { |
| 17 print(reason); | 17 print(reason); |
| 18 isValid = false; | 18 isValid = false; |
| 19 } | 19 } |
| 20 | 20 |
| 21 // Note that during construction of the Ssa graph the basic blocks are | 21 // Note that during construction of the Ssa graph the basic blocks are |
| 22 // not required to be valid yet. | 22 // not required to be valid yet. |
| 23 void visitBasicBlock(HBasicBlock block) { | 23 void visitBasicBlock(HBasicBlock block) { |
| 24 currentBlock = block; | 24 currentBlock = block; |
| 25 if (!isValid) return; // Don't need to continue if we are already invalid. | 25 if (!isValid) return; // Don't need to continue if we are already invalid. |
| 26 | 26 |
| 27 // Test that the last instruction is a branching instruction and that the | 27 // Test that the last instruction is a branching instruction and that the |
| 28 // basic block contains the branch-target. | 28 // basic block contains the branch-target. |
| 29 if (block.first == null || block.last == null) { | 29 if (block.first == null || block.last == null) { |
| 30 markInvalid("empty block"); | 30 markInvalid("empty block"); |
| 31 } | 31 } |
| 32 if (block.last is !HControlFlow) { | 32 if (block.last is! HControlFlow) { |
| 33 markInvalid("block ends with non-tail node."); | 33 markInvalid("block ends with non-tail node."); |
| 34 } | 34 } |
| 35 if (block.last is HIf && block.successors.length != 2) { | 35 if (block.last is HIf && block.successors.length != 2) { |
| 36 markInvalid("If node without two successors"); | 36 markInvalid("If node without two successors"); |
| 37 } | 37 } |
| 38 if (block.last is HConditionalBranch && block.successors.length != 2) { | 38 if (block.last is HConditionalBranch && block.successors.length != 2) { |
| 39 markInvalid("Conditional node without two successors"); | 39 markInvalid("Conditional node without two successors"); |
| 40 } | 40 } |
| 41 if (block.last is HLoopBranch) { | 41 if (block.last is HLoopBranch) { |
| 42 // Assert that the block we inserted to avoid critical edges satisfies | 42 // Assert that the block we inserted to avoid critical edges satisfies |
| 43 // our assumptions. That is, it must not contain any instructions | 43 // our assumptions. That is, it must not contain any instructions |
| 44 // (although it may contain phi-updates). | 44 // (although it may contain phi-updates). |
| 45 HBasicBlock avoidCriticalEdgeBlock = block.successors.last; | 45 HBasicBlock avoidCriticalEdgeBlock = block.successors.last; |
| 46 if (avoidCriticalEdgeBlock.first is! HGoto) { | 46 if (avoidCriticalEdgeBlock.first is! HGoto) { |
| 47 markInvalid("Critical edge block contains instructions"); | 47 markInvalid("Critical edge block contains instructions"); |
| 48 } | 48 } |
| 49 } | 49 } |
| 50 if (block.last is HGoto && block.successors.length != 1) { | 50 if (block.last is HGoto && block.successors.length != 1) { |
| 51 markInvalid("Goto node with not exactly one successor"); | 51 markInvalid("Goto node with not exactly one successor"); |
| 52 } | 52 } |
| 53 if (block.last is HJump && block.successors.length != 1) { | 53 if (block.last is HJump && block.successors.length != 1) { |
| 54 markInvalid("Break or continue node without one successor"); | 54 markInvalid("Break or continue node without one successor"); |
| 55 } | 55 } |
| 56 if ((block.last is HReturn || block.last is HThrow) && | 56 if ((block.last is HReturn || block.last is HThrow) && |
| 57 (block.successors.length != 1 || !block.successors[0].isExitBlock())) { | 57 (block.successors.length != 1 || !block.successors[0].isExitBlock())) { |
| 58 markInvalid("Return or throw node with > 1 successor " | 58 markInvalid("Return or throw node with > 1 successor " |
| 59 "or not going to exit-block"); | 59 "or not going to exit-block"); |
| 60 } | 60 } |
| 61 if (block.last is HExit && !block.successors.isEmpty) { | 61 if (block.last is HExit && !block.successors.isEmpty) { |
| 62 markInvalid("Exit block with successor"); | 62 markInvalid("Exit block with successor"); |
| 63 } | 63 } |
| 64 | 64 |
| 65 if (block.successors.isEmpty && !block.isExitBlock()) { | 65 if (block.successors.isEmpty && !block.isExitBlock()) { |
| 66 markInvalid("Non-exit block without successor"); | 66 markInvalid("Non-exit block without successor"); |
| 67 } | 67 } |
| 68 | 68 |
| 69 // Check that successors ids are always higher than the current one. | 69 // Check that successors ids are always higher than the current one. |
| 70 // TODO(floitsch): this is, of course, not true for back-branches. | 70 // TODO(floitsch): this is, of course, not true for back-branches. |
| 71 if (block.id == null) markInvalid("block without id"); | 71 if (block.id == null) markInvalid("block without id"); |
| 72 for (HBasicBlock successor in block.successors) { | 72 for (HBasicBlock successor in block.successors) { |
| 73 if (!isValid) break; | 73 if (!isValid) break; |
| 74 if (successor.id == null) markInvalid("successor without id"); | 74 if (successor.id == null) markInvalid("successor without id"); |
| 75 if (successor.id <= block.id && !successor.isLoopHeader()) { | 75 if (successor.id <= block.id && !successor.isLoopHeader()) { |
| 76 markInvalid("successor with lower id, but not a loop-header"); | 76 markInvalid("successor with lower id, but not a loop-header"); |
| 77 } | 77 } |
| 78 } | 78 } |
| 79 // Make sure we don't have a critical edge. | 79 // Make sure we don't have a critical edge. |
| 80 if (isValid && block.successors.length > 1 && | 80 if (isValid && |
| 81 block.last is! HTry && block.last is! HExitTry && | 81 block.successors.length > 1 && |
| 82 block.last is! HTry && |
| 83 block.last is! HExitTry && |
| 82 block.last is! HSwitch) { | 84 block.last is! HSwitch) { |
| 83 for (HBasicBlock successor in block.successors) { | 85 for (HBasicBlock successor in block.successors) { |
| 84 if (!isValid) break; | 86 if (!isValid) break; |
| 85 if (successor.predecessors.length >= 2) { | 87 if (successor.predecessors.length >= 2) { |
| 86 markInvalid("SSA graph contains critical edge."); | 88 markInvalid("SSA graph contains critical edge."); |
| 87 } | 89 } |
| 88 } | 90 } |
| 89 } | 91 } |
| 90 | 92 |
| 91 // Check that the entries in the dominated-list are sorted. | 93 // Check that the entries in the dominated-list are sorted. |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 124 if (!input.block.dominates(block)) { | 126 if (!input.block.dominates(block)) { |
| 125 markInvalid("Definition does not dominate use"); | 127 markInvalid("Definition does not dominate use"); |
| 126 } | 128 } |
| 127 } | 129 } |
| 128 }); | 130 }); |
| 129 | 131 |
| 130 super.visitBasicBlock(block); | 132 super.visitBasicBlock(block); |
| 131 } | 133 } |
| 132 | 134 |
| 133 /** Returns how often [instruction] is contained in [instructions]. */ | 135 /** Returns how often [instruction] is contained in [instructions]. */ |
| 134 static int countInstruction(List<HInstruction> instructions, | 136 static int countInstruction( |
| 135 HInstruction instruction) { | 137 List<HInstruction> instructions, HInstruction instruction) { |
| 136 int result = 0; | 138 int result = 0; |
| 137 for (int i = 0; i < instructions.length; i++) { | 139 for (int i = 0; i < instructions.length; i++) { |
| 138 if (identical(instructions[i], instruction)) result++; | 140 if (identical(instructions[i], instruction)) result++; |
| 139 } | 141 } |
| 140 return result; | 142 return result; |
| 141 } | 143 } |
| 142 | 144 |
| 143 /** | 145 /** |
| 144 * Returns true if the predicate returns true for every instruction in the | 146 * Returns true if the predicate returns true for every instruction in the |
| 145 * list. The argument to [f] is an instruction with the count of how often | 147 * list. The argument to [f] is an instruction with the count of how often |
| (...skipping 17 matching lines...) Expand all Loading... |
| 163 } | 165 } |
| 164 return true; | 166 return true; |
| 165 } | 167 } |
| 166 | 168 |
| 167 void visitInstruction(HInstruction instruction) { | 169 void visitInstruction(HInstruction instruction) { |
| 168 // Verifies that we are in the use list of our inputs. | 170 // Verifies that we are in the use list of our inputs. |
| 169 bool hasCorrectInputs() { | 171 bool hasCorrectInputs() { |
| 170 bool inBasicBlock = instruction.isInBasicBlock(); | 172 bool inBasicBlock = instruction.isInBasicBlock(); |
| 171 return everyInstruction(instruction.inputs, (input, count) { | 173 return everyInstruction(instruction.inputs, (input, count) { |
| 172 if (inBasicBlock) { | 174 if (inBasicBlock) { |
| 173 return input.isInBasicBlock() | 175 return input.isInBasicBlock() && |
| 174 && countInstruction(input.usedBy, instruction) == count; | 176 countInstruction(input.usedBy, instruction) == count; |
| 175 } else { | 177 } else { |
| 176 return countInstruction(input.usedBy, instruction) == 0; | 178 return countInstruction(input.usedBy, instruction) == 0; |
| 177 } | 179 } |
| 178 }); | 180 }); |
| 179 } | 181 } |
| 180 | 182 |
| 181 // Verifies that all our uses have us in their inputs. | 183 // Verifies that all our uses have us in their inputs. |
| 182 bool hasCorrectUses() { | 184 bool hasCorrectUses() { |
| 183 if (!instruction.isInBasicBlock()) return true; | 185 if (!instruction.isInBasicBlock()) return true; |
| 184 return everyInstruction(instruction.usedBy, (use, count) { | 186 return everyInstruction(instruction.usedBy, (use, count) { |
| 185 return use.isInBasicBlock() | 187 return use.isInBasicBlock() && |
| 186 && countInstruction(use.inputs, instruction) == count; | 188 countInstruction(use.inputs, instruction) == count; |
| 187 }); | 189 }); |
| 188 } | 190 } |
| 189 | 191 |
| 190 if (!identical(instruction.block, currentBlock)) { | 192 if (!identical(instruction.block, currentBlock)) { |
| 191 markInvalid("Instruction in wrong block"); | 193 markInvalid("Instruction in wrong block"); |
| 192 } | 194 } |
| 193 if (!hasCorrectInputs()) { | 195 if (!hasCorrectInputs()) { |
| 194 markInvalid("Incorrect inputs"); | 196 markInvalid("Incorrect inputs"); |
| 195 } | 197 } |
| 196 if (!hasCorrectUses()) { | 198 if (!hasCorrectUses()) { |
| 197 markInvalid("Incorrect uses"); | 199 markInvalid("Incorrect uses"); |
| 198 } | 200 } |
| 199 } | 201 } |
| 200 } | 202 } |
| OLD | NEW |