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 part of ssa; | 5 part of ssa; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * The [LiveRange] class covers a range where an instruction is live. | 8 * The [LiveRange] class covers a range where an instruction is live. |
| 9 */ | 9 */ |
| 10 class LiveRange { | 10 class LiveRange { |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 22 * The [LiveInterval] class contains the list of ranges where an | 22 * The [LiveInterval] class contains the list of ranges where an |
| 23 * instruction is live. | 23 * instruction is live. |
| 24 */ | 24 */ |
| 25 class LiveInterval { | 25 class LiveInterval { |
| 26 /** | 26 /** |
| 27 * The id where the instruction is defined. | 27 * The id where the instruction is defined. |
| 28 */ | 28 */ |
| 29 int start; | 29 int start; |
| 30 final List<LiveRange> ranges; | 30 final List<LiveRange> ranges; |
| 31 LiveInterval() : ranges = <LiveRange>[]; | 31 LiveInterval() : ranges = <LiveRange>[]; |
| 32 LiveInterval.forCheck(this.start, LiveInterval checkedInterval) | |
| 33 : ranges = checkedInterval.ranges; | |
| 32 | 34 |
| 33 /** | 35 /** |
| 34 * Update all ranges that are contained in [from, to[ to | 36 * Update all ranges that are contained in [from, to[ to |
| 35 * die at [to]. | 37 * die at [to]. |
| 36 */ | 38 */ |
| 37 void loopUpdate(int from, int to) { | 39 void loopUpdate(int from, int to) { |
| 38 for (LiveRange range in ranges) { | 40 for (LiveRange range in ranges) { |
| 39 if (from <= range.start && range.end < to) { | 41 if (from <= range.start && range.end < to) { |
| 40 range.end = to; | 42 range.end = to; |
| 41 } | 43 } |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 107 LiveEnvironment(this.liveIntervals, this.endId) | 109 LiveEnvironment(this.liveIntervals, this.endId) |
| 108 : liveInstructions = new Map<HInstruction, int>(), | 110 : liveInstructions = new Map<HInstruction, int>(), |
| 109 loopMarkers = new Map<HBasicBlock, int>(); | 111 loopMarkers = new Map<HBasicBlock, int>(); |
| 110 | 112 |
| 111 /** | 113 /** |
| 112 * Remove an instruction from the liveIn set. This method also | 114 * Remove an instruction from the liveIn set. This method also |
| 113 * updates the live interval of [instruction] to contain the new | 115 * updates the live interval of [instruction] to contain the new |
| 114 * range: [id, / id contained in [liveInstructions] /]. | 116 * range: [id, / id contained in [liveInstructions] /]. |
| 115 */ | 117 */ |
| 116 void remove(HInstruction instruction, int id) { | 118 void remove(HInstruction instruction, int id) { |
| 117 // Special case the HCheck instruction to have the same live | 119 LiveInterval interval = liveIntervals.putIfAbsent( |
| 118 // interval as the instruction it is checking. | 120 instruction, () => new LiveInterval()); |
| 119 if (instruction is HCheck) { | 121 int lastId = liveInstructions[instruction]; |
| 120 var input = instruction.checkedInput; | 122 // If [lastId] is null, then this instruction is not being used. |
| 121 while (input is HCheck) input = input.checkedInput; | 123 interval.add(new LiveRange(id, lastId == null ? id : lastId)); |
| 122 liveIntervals.putIfAbsent(input, () => new LiveInterval()); | 124 // The instruction is defined at [id]. |
| 123 // Unconditionally force the live interval of the HCheck to | 125 interval.start = id; |
| 124 // be the live interval of the instruction it is checking. | |
| 125 liveIntervals[instruction] = liveIntervals[input]; | |
| 126 } else { | |
| 127 LiveInterval range = liveIntervals.putIfAbsent( | |
| 128 instruction, () => new LiveInterval()); | |
| 129 int lastId = liveInstructions[instruction]; | |
| 130 // If [lastId] is null, then this instruction is not being used. | |
| 131 range.add(new LiveRange(id, lastId == null ? id : lastId)); | |
| 132 // The instruction is defined at [id]. | |
| 133 range.start = id; | |
| 134 } | |
| 135 liveInstructions.remove(instruction); | 126 liveInstructions.remove(instruction); |
| 136 } | 127 } |
| 137 | 128 |
| 138 /** | 129 /** |
| 139 * Add [instruction] to the liveIn set. If the instruction is not | 130 * Add [instruction] to the liveIn set. If the instruction is not |
| 140 * already in the set, we save the id where it dies. | 131 * already in the set, we save the id where it dies. |
| 141 */ | 132 */ |
| 142 void add(HInstruction instruction, int userId) { | 133 void add(HInstruction instruction, int userId) { |
| 143 // Note that we are visiting the graph in post-dominator order, so | 134 // Note that we are visiting the graph in post-dominator order, so |
| 144 // the first time we see a variable is when it dies. | 135 // the first time we see a variable is when it dies. |
| 145 liveInstructions.putIfAbsent(instruction, () => userId); | 136 liveInstructions.putIfAbsent(instruction, () => userId); |
| 146 if (instruction is HCheck) { | |
| 147 // Special case the HCheck instruction to mark the actual | |
| 148 // checked instruction live. | |
| 149 var input = instruction.checkedInput; | |
| 150 while (input is HCheck) input = input.checkedInput; | |
| 151 liveInstructions.putIfAbsent(input, () => userId); | |
| 152 } | |
| 153 } | 137 } |
| 154 | 138 |
| 155 /** | 139 /** |
| 156 * Merge this environment with [other]. Update the end id of | 140 * Merge this environment with [other]. Update the end id of |
| 157 * instructions in case they are different between this and [other]. | 141 * instructions in case they are different between this and [other]. |
| 158 */ | 142 */ |
| 159 void mergeWith(LiveEnvironment other) { | 143 void mergeWith(LiveEnvironment other) { |
| 160 other.liveInstructions.forEach((HInstruction instruction, int existingId) { | 144 other.liveInstructions.forEach((HInstruction instruction, int existingId) { |
| 161 // If both environments have the same instruction id of where | 145 // If both environments have the same instruction id of where |
| 162 // [instruction] dies, there is no need to update the live | 146 // [instruction] dies, there is no need to update the live |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 227 } | 211 } |
| 228 } | 212 } |
| 229 | 213 |
| 230 void markInputsAsLiveInEnvironment(HInstruction instruction, | 214 void markInputsAsLiveInEnvironment(HInstruction instruction, |
| 231 LiveEnvironment environment) { | 215 LiveEnvironment environment) { |
| 232 for (int i = 0, len = instruction.inputs.length; i < len; i++) { | 216 for (int i = 0, len = instruction.inputs.length; i < len; i++) { |
| 233 markAsLiveInEnvironment(instruction.inputs[i], environment); | 217 markAsLiveInEnvironment(instruction.inputs[i], environment); |
| 234 } | 218 } |
| 235 } | 219 } |
| 236 | 220 |
| 221 HInstruction unwrap(instruction) { | |
| 222 do { | |
| 223 instruction = instruction.checkedInput; | |
| 224 } while (instruction is HCheck); | |
| 225 return instruction; | |
| 226 } | |
| 227 | |
| 237 void markAsLiveInEnvironment(HInstruction instruction, | 228 void markAsLiveInEnvironment(HInstruction instruction, |
| 238 LiveEnvironment environment) { | 229 LiveEnvironment environment) { |
| 239 if (environment.contains(instruction)) return; | 230 // The inputs of a [HPhi] are being handled at the entry of a |
|
ngeoffray
2013/04/16 14:58:02
The contains check here and the code line 151 were
| |
| 240 environment.add(instruction, instructionId); | 231 // block. |
| 241 // HPhis are treated specially. | |
| 242 if (generateAtUseSite.contains(instruction) && instruction is !HPhi) { | 232 if (generateAtUseSite.contains(instruction) && instruction is !HPhi) { |
| 243 markInputsAsLiveInEnvironment(instruction, environment); | 233 markInputsAsLiveInEnvironment(instruction, environment); |
| 234 } else { | |
| 235 environment.add(instruction, instructionId); | |
| 236 // Special case the HCheck instruction to mark the actual | |
| 237 // checked instruction live. The checked instruction and the | |
| 238 // [HCheck] will share the same live ranges. | |
| 239 if (instruction is HCheck) { | |
| 240 HInstruction checked = unwrap(instruction); | |
| 241 if (!generateAtUseSite.contains(checked)) { | |
| 242 environment.add(checked, instructionId); | |
| 243 } | |
| 244 } | |
| 245 } | |
| 246 } | |
| 247 | |
| 248 void removeFromEnvironment(HInstruction instruction, | |
| 249 LiveEnvironment environment) { | |
| 250 environment.remove(instruction, instructionId); | |
| 251 // Special case the HCheck instruction to have the same live | |
| 252 // interval as the instruction it is checking. | |
| 253 if (instruction is HCheck) { | |
| 254 HInstruction checked = unwrap(instruction); | |
| 255 if (!generateAtUseSite.contains(checked)) { | |
| 256 liveIntervals.putIfAbsent(checked, () => new LiveInterval()); | |
| 257 // Unconditionally force the live ranges of the HCheck to | |
| 258 // be the live ranges of the instruction it is checking. | |
| 259 liveIntervals[instruction] = | |
| 260 new LiveInterval.forCheck(instructionId, liveIntervals[checked]); | |
| 261 } | |
| 244 } | 262 } |
| 245 } | 263 } |
| 246 | 264 |
| 247 void visitBasicBlock(HBasicBlock block) { | 265 void visitBasicBlock(HBasicBlock block) { |
| 248 LiveEnvironment environment = | 266 LiveEnvironment environment = |
| 249 new LiveEnvironment(liveIntervals, instructionId); | 267 new LiveEnvironment(liveIntervals, instructionId); |
| 250 | 268 |
| 251 // Add to the environment the liveIn of its successor, as well as | 269 // Add to the environment the liveIn of its successor, as well as |
| 252 // the inputs of the phis of the successor that flow from this block. | 270 // the inputs of the phis of the successor that flow from this block. |
| 253 for (int i = 0; i < block.successors.length; i++) { | 271 for (int i = 0; i < block.successors.length; i++) { |
| 254 HBasicBlock successor = block.successors[i]; | 272 HBasicBlock successor = block.successors[i]; |
| 255 LiveEnvironment successorEnv = liveInstructions[successor]; | 273 LiveEnvironment successorEnv = liveInstructions[successor]; |
| 256 if (successorEnv != null) { | 274 if (successorEnv != null) { |
| 257 environment.mergeWith(successorEnv); | 275 environment.mergeWith(successorEnv); |
| 258 } else { | 276 } else { |
| 259 environment.addLoopMarker(successor, instructionId); | 277 environment.addLoopMarker(successor, instructionId); |
| 260 } | 278 } |
| 261 | 279 |
| 262 int index = successor.predecessors.indexOf(block); | 280 int index = successor.predecessors.indexOf(block); |
| 263 for (HPhi phi = successor.phis.first; phi != null; phi = phi.next) { | 281 for (HPhi phi = successor.phis.first; phi != null; phi = phi.next) { |
| 264 markAsLiveInEnvironment(phi.inputs[index], environment); | 282 markAsLiveInEnvironment(phi.inputs[index], environment); |
| 265 } | 283 } |
| 266 } | 284 } |
| 267 | 285 |
| 268 // Iterate over all instructions to remove an instruction from the | 286 // Iterate over all instructions to remove an instruction from the |
| 269 // environment and add its inputs. | 287 // environment and add its inputs. |
| 270 HInstruction instruction = block.last; | 288 HInstruction instruction = block.last; |
| 271 while (instruction != null) { | 289 while (instruction != null) { |
| 272 environment.remove(instruction, instructionId); | 290 if (!generateAtUseSite.contains(instruction)) { |
| 273 markInputsAsLiveInEnvironment(instruction, environment); | 291 removeFromEnvironment(instruction, environment); |
| 292 markInputsAsLiveInEnvironment(instruction, environment); | |
| 293 } | |
| 294 instructionId--; | |
| 274 instruction = instruction.previous; | 295 instruction = instruction.previous; |
| 275 instructionId--; | |
| 276 } | 296 } |
| 277 | 297 |
| 278 // We just remove the phis from the environment. The inputs of the | 298 // We just remove the phis from the environment. The inputs of the |
| 279 // phis will be put in the environment of the predecessors. | 299 // phis will be put in the environment of the predecessors. |
| 280 for (HPhi phi = block.phis.first; phi != null; phi = phi.next) { | 300 for (HPhi phi = block.phis.first; phi != null; phi = phi.next) { |
| 281 environment.remove(phi, instructionId); | 301 environment.remove(phi, instructionId); |
| 282 } | 302 } |
| 283 | 303 |
| 284 // Save the liveInstructions of that block. | 304 // Save the liveInstructions of that block. |
| 285 environment.startId = instructionId + 1; | 305 environment.startId = instructionId + 1; |
| (...skipping 306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 592 handlePhi(phi, namer); | 612 handlePhi(phi, namer); |
| 593 }); | 613 }); |
| 594 | 614 |
| 595 block.forEachInstruction((HInstruction instruction) { | 615 block.forEachInstruction((HInstruction instruction) { |
| 596 handleInstruction(instruction, namer); | 616 handleInstruction(instruction, namer); |
| 597 }); | 617 }); |
| 598 } | 618 } |
| 599 | 619 |
| 600 /** | 620 /** |
| 601 * Returns whether [instruction] needs a name. Instructions that | 621 * Returns whether [instruction] needs a name. Instructions that |
| 602 * have no users or that are generated at use site does not need a name. | 622 * have no users or that are generated at use site do not need a name. |
| 603 */ | 623 */ |
| 604 bool needsName(HInstruction instruction) { | 624 bool needsName(HInstruction instruction) { |
| 605 if (instruction is HThis) return false; | 625 if (instruction is HThis) return false; |
| 606 if (instruction is HParameterValue) return true; | 626 if (instruction is HParameterValue) return true; |
| 607 if (instruction.usedBy.isEmpty) return false; | 627 if (instruction.usedBy.isEmpty) return false; |
| 608 if (generateAtUseSite.contains(instruction)) return false; | 628 if (generateAtUseSite.contains(instruction)) return false; |
| 609 // A [HCheck] instruction that has control flow needs a name only if its | 629 // A [HCheck] instruction that has control flow needs a name only if its |
| 610 // checked input needs a name (e.g. a check [HConstant] does not | 630 // checked input needs a name (for example, a checked [HConstant] does not |
| 611 // need a name). | 631 // need a name). |
| 612 if (instruction is HCheck && instruction.isControlFlow()) { | 632 if (instruction is HCheck && instruction.isControlFlow()) { |
| 613 HCheck check = instruction; | 633 HCheck check = instruction; |
| 614 return needsName(instruction.checkedInput); | 634 return needsName(instruction.checkedInput); |
| 615 } | 635 } |
| 616 return true; | 636 return true; |
| 617 } | 637 } |
| 618 | 638 |
| 619 /** | 639 /** |
| 620 * Returns whether [instruction] dies at the instruction [at]. | 640 * Returns whether [instruction] dies at the instruction [at]. |
| 621 */ | 641 */ |
| 622 bool diesAt(HInstruction instruction, HInstruction at) { | 642 bool diesAt(HInstruction instruction, HInstruction at) { |
| 623 LiveInterval atInterval = liveIntervals[at]; | 643 LiveInterval atInterval = liveIntervals[at]; |
| 624 LiveInterval instructionInterval = liveIntervals[instruction]; | 644 LiveInterval instructionInterval = liveIntervals[instruction]; |
| 625 int start = atInterval.start; | 645 int start = atInterval.start; |
| 626 return instructionInterval.diesAt(start); | 646 return instructionInterval.diesAt(start); |
| 627 } | 647 } |
| 628 | 648 |
| 629 void freeUsedNamesAt(HInstruction instruction, | 649 void freeUsedNamesAt(HInstruction instruction, |
| 630 HInstruction at, | 650 HInstruction at, |
| 631 VariableNamer namer) { | 651 VariableNamer namer) { |
| 632 // TODO(ager): We cannot perform this check to free names for | |
| 633 // HCheck instructions because they are special cased to have the | |
| 634 // same live intervals as the instruction they are checking. This | |
| 635 // includes sharing the start id with the checked | |
| 636 // input. Therefore, for HCheck(checkedInput, otherInput) we would | |
| 637 // end up checking that otherInput dies not here, but at the | |
| 638 // location of checkedInput. We should preserve the start id for | |
| 639 // the check instruction. | |
| 640 if (at is HCheck) return; | |
| 641 if (needsName(instruction)) { | 652 if (needsName(instruction)) { |
| 642 if (diesAt(instruction, at)) { | 653 if (diesAt(instruction, at)) { |
| 643 namer.freeName(instruction); | 654 namer.freeName(instruction); |
| 644 } | 655 } |
| 645 } else if (generateAtUseSite.contains(instruction)) { | 656 } else if (generateAtUseSite.contains(instruction)) { |
| 646 // If the instruction is generated at use site, then all its | 657 // If the instruction is generated at use site, then all its |
| 647 // inputs may also die at [at]. | 658 // inputs may also die at [at]. |
| 648 for (int i = 0, len = instruction.inputs.length; i < len; i++) { | 659 for (int i = 0, len = instruction.inputs.length; i < len; i++) { |
| 649 HInstruction input = instruction.inputs[i]; | 660 HInstruction input = instruction.inputs[i]; |
| 650 freeUsedNamesAt(input, at, namer); | 661 freeUsedNamesAt(input, at, namer); |
| 651 } | 662 } |
| 652 } | 663 } |
| 653 } | 664 } |
| 654 | 665 |
| 655 void handleInstruction(HInstruction instruction, VariableNamer namer) { | 666 void handleInstruction(HInstruction instruction, VariableNamer namer) { |
| 667 if (generateAtUseSite.contains(instruction)) { | |
| 668 assert(!liveIntervals.containsKey(instruction)); | |
| 669 return; | |
| 670 } | |
| 671 | |
| 656 for (int i = 0, len = instruction.inputs.length; i < len; i++) { | 672 for (int i = 0, len = instruction.inputs.length; i < len; i++) { |
| 657 HInstruction input = instruction.inputs[i]; | 673 HInstruction input = instruction.inputs[i]; |
| 658 freeUsedNamesAt(input, instruction, namer); | 674 freeUsedNamesAt(input, instruction, namer); |
| 659 } | 675 } |
| 660 | 676 |
| 661 if (needsName(instruction)) { | 677 if (needsName(instruction)) { |
| 662 namer.allocateName(instruction); | 678 namer.allocateName(instruction); |
| 663 } | 679 } |
| 664 } | 680 } |
| 665 | 681 |
| 666 void handlePhi(HPhi phi, VariableNamer namer) { | 682 void handlePhi(HPhi phi, VariableNamer namer) { |
| 667 if (!needsName(phi)) return; | 683 if (!needsName(phi)) return; |
| 668 | 684 |
| 669 for (int i = 0; i < phi.inputs.length; i++) { | 685 for (int i = 0; i < phi.inputs.length; i++) { |
| 670 HInstruction input = phi.inputs[i]; | 686 HInstruction input = phi.inputs[i]; |
| 671 HBasicBlock predecessor = phi.block.predecessors[i]; | 687 HBasicBlock predecessor = phi.block.predecessors[i]; |
| 672 if (!needsName(input)) { | 688 if (!needsName(input)) { |
| 673 names.addAssignment(predecessor, input, phi); | 689 names.addAssignment(predecessor, input, phi); |
| 674 } else { | 690 } else { |
| 675 names.addCopy(predecessor, input, phi); | 691 names.addCopy(predecessor, input, phi); |
| 676 } | 692 } |
| 677 } | 693 } |
| 678 | 694 |
| 679 namer.allocateName(phi); | 695 namer.allocateName(phi); |
| 680 } | 696 } |
| 681 } | 697 } |
| OLD | NEW |