Chromium Code Reviews| 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 class BailoutInfo { | 5 class BailoutInfo { |
| 6 int instructionId; | 6 int instructionId; |
| 7 int bailoutId; | 7 int bailoutId; |
| 8 BailoutInfo(this.instructionId, this.bailoutId); | 8 BailoutInfo(this.instructionId, this.bailoutId); |
| 9 } | 9 } |
| 10 | 10 |
| 11 /** | 11 /** |
| 12 * Keeps track of the execution environment for instructions. An | 12 * Keeps track of the execution environment for instructions. An |
| 13 * execution environment contains the SSA instructions that are live. | 13 * execution environment contains the SSA instructions that are live. |
| 14 */ | 14 */ |
| 15 class Environment { | 15 class Environment { |
| 16 final Set<HInstruction> lives; | 16 final Set<HInstruction> lives; |
| 17 Environment() : lives = new Set<HInstruction>(); | 17 final Set<HBasicBlock> loopMarkers; |
| 18 Environment() : lives = new Set<HInstruction>(), | |
| 19 loopMarkers = new Set<HBasicBlock>(); | |
| 18 Environment.from(Environment other) | 20 Environment.from(Environment other) |
| 19 : lives = new Set<HInstruction>.from(other.lives); | 21 : lives = new Set<HInstruction>.from(other.lives), |
| 22 loopMarkers = new Set<HBasicBlock>.from(other.loopMarkers); | |
| 23 | |
| 24 Environment.forLoop(Environment other) | |
|
floitsch
2012/03/12 11:35:10
forLoopBody
ngeoffray
2012/03/12 11:53:24
Done.
| |
| 25 : lives = new Set<HInstruction>(), | |
| 26 loopMarkers = new Set<HBasicBlock>.from(other.loopMarkers); | |
| 20 | 27 |
| 21 void remove(HInstruction instruction) { | 28 void remove(HInstruction instruction) { |
| 22 lives.remove(instruction); | 29 lives.remove(instruction); |
| 23 } | 30 } |
| 24 | 31 |
| 25 void add(HInstruction instruction) { | 32 void add(HInstruction instruction) { |
| 26 if (!instruction.generateAtUseSite()) { | 33 if (!instruction.generateAtUseSite()) { |
| 27 lives.add(instruction); | 34 lives.add(instruction); |
| 28 } else { | 35 } else { |
| 29 for (int i = 0, len = instruction.inputs.length; i < len; i++) { | 36 for (int i = 0, len = instruction.inputs.length; i < len; i++) { |
| 30 add(instruction.inputs[i]); | 37 add(instruction.inputs[i]); |
| 31 } | 38 } |
| 32 } | 39 } |
| 33 } | 40 } |
| 34 | 41 |
| 42 void addLoopMarker(HBasicBlock block) { | |
| 43 loopMarkers.add(block); | |
| 44 } | |
| 45 | |
| 46 void removeLoopMarker(HBasicBlock block) { | |
| 47 loopMarkers.remove(block); | |
| 48 } | |
| 49 | |
| 35 void addAll(Environment other) { | 50 void addAll(Environment other) { |
| 36 lives.addAll(other.lives); | 51 lives.addAll(other.lives); |
| 52 loopMarkers.addAll(other.loopMarkers); | |
| 37 } | 53 } |
| 38 | 54 |
| 39 List<HInstruction> buildAndSetLast(HInstruction instruction) { | 55 List<HInstruction> buildAndSetLast(HInstruction instruction) { |
| 40 remove(instruction); | 56 remove(instruction); |
| 41 List<HInstruction> result = new List<HInstruction>.from(lives); | 57 List<HInstruction> result = new List<HInstruction>.from(lives); |
| 42 result.addLast(instruction); | 58 result.addLast(instruction); |
| 43 add(instruction); | 59 add(instruction); |
| 44 return result; | 60 return result; |
| 45 } | 61 } |
| 46 | 62 |
| 47 bool isEmpty() => lives.isEmpty(); | 63 bool isEmpty() => lives.isEmpty(); |
| 48 bool contains(HInstruction instruction) => lives.contains(instruction); | 64 bool contains(HInstruction instruction) => lives.contains(instruction); |
| 65 bool containsLoopMarker(HBasicBlock block) => loopMarkers.contains(block); | |
| 49 void clear() => lives.clear(); | 66 void clear() => lives.clear(); |
| 50 } | 67 } |
| 51 | 68 |
| 52 /** | 69 /** |
| 53 * Computes the environment for each SSA instruction: visits the graph | 70 * Computes the environment for each SSA instruction: visits the graph |
| 54 * in post-dominator order. Removes an instruction from the environment | 71 * in post-dominator order. Removes an instruction from the environment |
| 55 * and adds its inputs to the environment at the instruction's | 72 * and adds its inputs to the environment at the instruction's |
| 56 * definition. | 73 * definition. |
| 57 */ | 74 */ |
| 58 class SsaEnvironmentBuilder extends HBaseVisitor { | 75 class SsaEnvironmentBuilder extends HBaseVisitor { |
| 59 final Compiler compiler; | 76 final Compiler compiler; |
| 60 Environment environment; | 77 Environment environment; |
| 61 SubGraph subGraph; | 78 SubGraph subGraph; |
| 62 | 79 |
| 63 SsaEnvironmentBuilder(Compiler this.compiler); | 80 final Map<HInstruction, Environment> capturedEnvironments; |
| 81 | |
| 82 SsaEnvironmentBuilder(Compiler this.compiler) | |
| 83 : capturedEnvironments = new Map<HInstruction, Environment>(); | |
| 64 | 84 |
| 65 void visitGraph(HGraph graph) { | 85 void visitGraph(HGraph graph) { |
| 66 subGraph = new SubGraph(graph.entry, graph.exit); | 86 subGraph = new SubGraph(graph.entry, graph.exit); |
| 67 environment = new Environment(); | 87 environment = new Environment(); |
| 68 visitBasicBlock(graph.entry); | 88 visitBasicBlock(graph.entry); |
| 69 assert(environment.isEmpty()); | 89 assert(environment.isEmpty()); |
| 90 insertCapturedEnvironments(); | |
| 91 } | |
| 92 | |
| 93 abstract void insertCapturedEnvironments(); | |
| 94 abstract bool shouldCaptureEnvironment(HInstruction instruction); | |
| 95 | |
| 96 void maybeCaptureEnvironment(HInstruction instruction) { | |
| 97 if (shouldCaptureEnvironment(instruction)) { | |
| 98 capturedEnvironments[instruction] = new Environment.from(environment); | |
| 99 } | |
| 70 } | 100 } |
| 71 | 101 |
| 72 void visitSubGraph(SubGraph newSubGraph) { | 102 void visitSubGraph(SubGraph newSubGraph) { |
| 73 SubGraph oldSubGraph = subGraph; | 103 SubGraph oldSubGraph = subGraph; |
| 74 subGraph = newSubGraph; | 104 subGraph = newSubGraph; |
| 75 visitBasicBlock(subGraph.start); | 105 visitBasicBlock(subGraph.start); |
| 76 subGraph = oldSubGraph; | 106 subGraph = oldSubGraph; |
| 77 } | 107 } |
| 78 | 108 |
| 79 void visitBasicBlock(HBasicBlock block) { | 109 void visitBasicBlock(HBasicBlock block) { |
| 80 if (!subGraph.contains(block)) return; | 110 if (!subGraph.contains(block)) return; |
| 81 block.last.accept(this); | 111 block.last.accept(this); |
| 82 | 112 |
| 83 HInstruction instruction = block.last.previous; | 113 HInstruction instruction = block.last.previous; |
| 84 while (instruction != null) { | 114 while (instruction != null) { |
| 85 HInstruction previous = instruction.previous; | 115 HInstruction previous = instruction.previous; |
| 86 instruction.accept(this); | 116 instruction.accept(this); |
| 87 instruction = previous; | 117 instruction = previous; |
| 88 } | 118 } |
| 89 | 119 |
| 90 for (HPhi phi = block.phis.first; phi != null; phi = phi.next) { | 120 for (HPhi phi = block.phis.first; phi != null; phi = phi.next) { |
| 91 phi.accept(this); | 121 phi.accept(this); |
| 92 } | 122 } |
| 123 | |
| 124 if (block.isLoopHeader()) { | |
|
floitsch
2012/03/12 11:35:10
Add a comment, maybe even with an example.
ngeoffray
2012/03/12 11:53:24
Done.
| |
| 125 environment.removeLoopMarker(block); | |
| 126 capturedEnvironments.forEach((instruction, env) { | |
| 127 if (env.containsLoopMarker(block)) { | |
| 128 env.removeLoopMarker(block); | |
| 129 env.addAll(environment); | |
| 130 } | |
| 131 }); | |
| 132 } | |
| 93 } | 133 } |
| 94 | 134 |
| 95 void visitPhi(HPhi phi) { | 135 void visitPhi(HPhi phi) { |
| 136 maybeCaptureEnvironment(phi); | |
| 96 environment.remove(phi); | 137 environment.remove(phi); |
| 97 // If the block is a loop header, we insert the incoming values of | 138 // If the block is a loop header, we insert the incoming values of |
| 98 // the phis, and remove the loop values. | 139 // the phis, and remove the loop values. |
| 99 // If the block is not a loop header, the phi will be handled by | 140 // If the block is not a loop header, the phi will be handled by |
| 100 // the control flow instruction. | 141 // the control flow instruction. |
| 101 if (phi.block.isLoopHeader()) { | 142 if (phi.block.isLoopHeader()) { |
| 102 environment.add(phi.inputs[0]); | 143 environment.add(phi.inputs[0]); |
| 103 for (int i = 1, len = phi.inputs.length; i < len; i++) { | 144 for (int i = 1, len = phi.inputs.length; i < len; i++) { |
| 104 environment.remove(phi.inputs[i]); | 145 environment.remove(phi.inputs[i]); |
| 105 } | 146 } |
| 106 } | 147 } |
| 107 } | 148 } |
| 108 | 149 |
| 109 void visitInstruction(HInstruction instruction) { | 150 void visitInstruction(HInstruction instruction) { |
| 151 maybeCaptureEnvironment(instruction); | |
| 110 environment.remove(instruction); | 152 environment.remove(instruction); |
| 111 for (int i = 0, len = instruction.inputs.length; i < len; i++) { | 153 for (int i = 0, len = instruction.inputs.length; i < len; i++) { |
| 112 environment.add(instruction.inputs[i]); | 154 environment.add(instruction.inputs[i]); |
| 113 } | 155 } |
| 114 } | 156 } |
| 115 | 157 |
| 116 void visitIf(HIf instruction) { | 158 void visitIf(HIf instruction) { |
| 117 HIfBlockInformation info = instruction.blockInformation; | 159 HIfBlockInformation info = instruction.blockInformation; |
| 118 HBasicBlock joinBlock = info.joinBlock; | 160 HBasicBlock joinBlock = info.joinBlock; |
| 119 | 161 |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 186 | 228 |
| 187 void visitBreak(HBreak breakInstruction) { | 229 void visitBreak(HBreak breakInstruction) { |
| 188 unimplemented(); | 230 unimplemented(); |
| 189 } | 231 } |
| 190 | 232 |
| 191 void visitLoopBranch(HLoopBranch branch) { | 233 void visitLoopBranch(HLoopBranch branch) { |
| 192 HBasicBlock block = branch.block; | 234 HBasicBlock block = branch.block; |
| 193 | 235 |
| 194 // Visit the code after the loop. | 236 // Visit the code after the loop. |
| 195 visitBasicBlock(block.successors[1]); | 237 visitBasicBlock(block.successors[1]); |
| 196 // TODO(ngeoffray): Remove the instructions of the loop-exit from | |
| 197 // the environment. | |
| 198 | 238 |
| 239 Environment joinEnvironment = environment; | |
| 240 | |
| 241 // When visiting the loop body, we don't require the live | |
| 242 // instructions after the loop body to be in the environment. They | |
| 243 // will be either recomputed in the loop header, or inserted | |
| 244 // with the loop marker. | |
|
floitsch
2012/03/12 11:35:10
However we need the current environment to transfe
ngeoffray
2012/03/12 11:53:24
Done.
| |
| 245 environment = new Environment.forLoop(environment); | |
| 246 | |
| 247 // Put the loop phis in the environment. | |
| 199 HBasicBlock header = block.isLoopHeader() ? block : block.parentLoopHeader; | 248 HBasicBlock header = block.isLoopHeader() ? block : block.parentLoopHeader; |
| 200 // Put the loop phis in the environment. | |
| 201 for (HPhi phi = header.phis.first; phi != null; phi = phi.next) { | 249 for (HPhi phi = header.phis.first; phi != null; phi = phi.next) { |
| 202 for (int i = 1, len = phi.inputs.length; i < len; i++) { | 250 for (int i = 1, len = phi.inputs.length; i < len; i++) { |
| 203 environment.add(phi.inputs[i]); | 251 environment.add(phi.inputs[i]); |
| 204 } | 252 } |
| 205 } | 253 } |
| 206 | 254 |
| 255 // Add the loop marker | |
| 256 environment.addLoopMarker(header); | |
| 257 | |
| 207 if (!branch.isDoWhile()) { | 258 if (!branch.isDoWhile()) { |
| 208 assert(block.successors[0] == block.dominatedBlocks[0]); | 259 assert(block.successors[0] == block.dominatedBlocks[0]); |
| 209 visitBasicBlock(block.successors[0]); | 260 visitBasicBlock(block.successors[0]); |
| 210 } | 261 } |
| 262 | |
| 263 // We merge the environment required by the code after the loop, | |
| 264 // and the code inside the loop. | |
| 265 environment.addAll(joinEnvironment); | |
| 211 } | 266 } |
| 212 | 267 |
| 213 // Deal with all kinds of control flow instructions. In case we add | 268 // Deal with all kinds of control flow instructions. In case we add |
| 214 // a new one, we will hit an internal error. | 269 // a new one, we will hit an internal error. |
| 215 void visitExit(HExit exit) {} | 270 void visitExit(HExit exit) {} |
| 216 | 271 |
| 217 void visitReturn(HReturn instruction) { | 272 void visitReturn(HReturn instruction) { |
| 218 environment.clear(); | 273 environment.clear(); |
| 219 visitInstruction(instruction); | 274 visitInstruction(instruction); |
| 220 } | 275 } |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 233 /** | 288 /** |
| 234 * Visits the graph and replaces guards with guards that capture the | 289 * Visits the graph and replaces guards with guards that capture the |
| 235 * environment. | 290 * environment. |
| 236 */ | 291 */ |
| 237 class SsaTypeGuardBuilder extends SsaEnvironmentBuilder implements OptimizationP hase { | 292 class SsaTypeGuardBuilder extends SsaEnvironmentBuilder implements OptimizationP hase { |
| 238 | 293 |
| 239 final String name = 'SsaTypeGuardBuilder'; | 294 final String name = 'SsaTypeGuardBuilder'; |
| 240 | 295 |
| 241 SsaTypeGuardBuilder(Compiler compiler) : super(compiler); | 296 SsaTypeGuardBuilder(Compiler compiler) : super(compiler); |
| 242 | 297 |
| 243 void tryInsertTypeGuard(HInstruction instruction, | 298 bool shouldCaptureEnvironment(HInstruction instruction) { |
| 244 HInstruction insertionPoint) { | 299 return instruction.type.isKnown() && !instruction.hasExpectedType(); |
| 245 // If we found a type for the instruction, but the instruction | 300 } |
| 246 // does not know if it produces that type, add a type guard. | 301 |
| 247 if (instruction.type.isKnown() && !instruction.hasExpectedType()) { | 302 void insertCapturedEnvironments() { |
| 248 // The type guard expects the guarded instruction to be at the | 303 capturedEnvironments.forEach((HInstruction instruction, Environment env) { |
| 249 // end of the inputs. | 304 List<HInstruction> inputs = env.buildAndSetLast(instruction); |
| 250 List<HInstruction> inputs = environment.buildAndSetLast(instruction); | |
| 251 HTypeGuard guard = | 305 HTypeGuard guard = |
| 252 new HTypeGuard(instruction.type, inputs, instruction.id); | 306 new HTypeGuard(instruction.type, inputs, instruction.id); |
| 253 // Remove the instruction's type, the guard is now holding that | 307 // Remove the instruction's type, the guard is now holding that |
| 254 // type. | 308 // type. |
| 255 instruction.type = HType.UNKNOWN; | 309 instruction.type = HType.UNKNOWN; |
| 256 instruction.block.rewrite(instruction, guard); | 310 instruction.block.rewrite(instruction, guard); |
| 311 HInstruction insertionPoint = (instruction is HPhi) | |
| 312 ? phi.block.first | |
| 313 : instruction.next; | |
| 257 insertionPoint.block.addBefore(insertionPoint, guard); | 314 insertionPoint.block.addBefore(insertionPoint, guard); |
| 258 } | 315 }); |
| 259 } | |
| 260 | |
| 261 | |
| 262 void visitInstruction(HInstruction instruction) { | |
| 263 tryInsertTypeGuard(instruction, instruction.next); | |
| 264 super.visitInstruction(instruction); | |
| 265 } | |
| 266 | |
| 267 void visitPhi(HPhi phi) { | |
| 268 tryInsertTypeGuard(phi, phi.block.first); | |
| 269 super.visitPhi(phi); | |
| 270 } | 316 } |
| 271 } | 317 } |
| 272 | 318 |
| 273 /* | 319 /* |
| 274 * Visits the graph and inserts [HBailoutTarget] instructions where | 320 * Visits the graph and inserts [HBailoutTarget] instructions where |
| 275 * the optimized version had [HTypeGuard] instructions. | 321 * the optimized version had [HTypeGuard] instructions. |
| 276 */ | 322 */ |
| 277 class SsaBailoutBuilder extends SsaEnvironmentBuilder implements OptimizationPha se { | 323 class SsaBailoutBuilder extends SsaEnvironmentBuilder implements OptimizationPha se { |
| 278 final Map<int, BailoutInfo> bailouts; | 324 final Map<int, BailoutInfo> bailouts; |
| 279 final String name = 'SsaBailoutBuilder'; | 325 final String name = 'SsaBailoutBuilder'; |
| 280 | 326 |
| 281 SsaBailoutBuilder(Compiler compiler, this.bailouts) : super(compiler); | 327 SsaBailoutBuilder(Compiler compiler, this.bailouts) : super(compiler); |
| 282 | 328 |
| 283 void checkBailout(HInstruction instruction, HInstruction insertionPoint) { | 329 bool shouldCaptureEnvironment(HInstruction instruction) { |
| 284 BailoutInfo info = bailouts[instruction.id]; | 330 return bailouts[instruction.id] != null; |
| 285 if (info != null) { | |
| 286 List<HInstruction> inputs = environment.buildAndSetLast(instruction); | |
| 287 HBailoutTarget bailout = new HBailoutTarget(info.bailoutId, inputs); | |
| 288 instruction.block.addBefore(insertionPoint, bailout); | |
| 289 } | |
| 290 } | 331 } |
| 291 | 332 |
| 292 void visitInstruction(HInstruction instruction) { | 333 void insertCapturedEnvironments() { |
| 293 checkBailout(instruction, instruction.next); | 334 capturedEnvironments.forEach((HInstruction instruction, Environment env) { |
| 294 super.visitInstruction(instruction); | 335 BailoutInfo info = bailouts[instruction.id]; |
| 295 } | 336 List<HInstruction> inputs = env.buildAndSetLast(instruction); |
| 296 | 337 HBailoutTarget bailout = new HBailoutTarget(info.bailoutId, inputs); |
| 297 void visitPhi(HPhi phi) { | 338 HInstruction insertionPoint = (instruction is HPhi) |
| 298 checkBailout(phi, phi.block.first); | 339 ? phi.block.first |
| 299 super.visitPhi(phi); | 340 : instruction.next; |
| 341 instruction.block.addBefore(insertionPoint, bailout); | |
| 342 }); | |
| 300 } | 343 } |
| 301 } | 344 } |
| 302 | 345 |
| 303 /** | 346 /** |
| 304 * Propagates bailout information to blocks that need it. This visitor | 347 * Propagates bailout information to blocks that need it. This visitor |
| 305 * is run before codegen, to know which blocks have to deal with | 348 * is run before codegen, to know which blocks have to deal with |
| 306 * bailouts. | 349 * bailouts. |
| 307 */ | 350 */ |
| 308 class SsaBailoutPropagator extends HBaseVisitor { | 351 class SsaBailoutPropagator extends HBaseVisitor { |
| 309 final Compiler compiler; | 352 final Compiler compiler; |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 364 compiler.internalError('Control flow instructions already dealt with.', | 407 compiler.internalError('Control flow instructions already dealt with.', |
| 365 instruction: instruction); | 408 instruction: instruction); |
| 366 } | 409 } |
| 367 | 410 |
| 368 visitBailoutTarget(HBailoutTarget target) { | 411 visitBailoutTarget(HBailoutTarget target) { |
| 369 blocks.forEach((HBasicBlock block) { | 412 blocks.forEach((HBasicBlock block) { |
| 370 block.bailouts.add(target); | 413 block.bailouts.add(target); |
| 371 }); | 414 }); |
| 372 } | 415 } |
| 373 } | 416 } |
| OLD | NEW |