Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(50)

Side by Side Diff: sdk/lib/_internal/compiler/implementation/ssa/variable_allocator.dart

Issue 13877009: Fix variable allocator in the presence of HCheck instructions. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | tests/language/issue9687_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | tests/language/issue9687_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698