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 |