Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 /** | |
|
floitsch
2012/05/30 18:45:03
copyright.
ngeoffray
2012/05/31 08:12:46
Done.
| |
| 2 * The [LiveRange] class covers a range where an instruction is live. | |
| 3 */ | |
| 4 class LiveRange { | |
| 5 final int start; | |
| 6 // [end] is not final because it can be udpated due to loops. | |
|
kasperl
2012/05/31 05:26:03
udpated -> updated
ngeoffray
2012/05/31 08:12:46
Done.
| |
| 7 int end; | |
| 8 LiveRange(this.start, this.end) { | |
| 9 assert(start <= end); | |
| 10 } | |
| 11 | |
| 12 String toString() { | |
|
kasperl
2012/05/31 05:26:03
=>
ngeoffray
2012/05/31 08:12:46
Done.
| |
| 13 return '[$start $end['; | |
| 14 } | |
| 15 } | |
| 16 | |
| 17 /** | |
| 18 * The [LiveInterval] class contains the list of ranges where an | |
| 19 * instruction is live. | |
| 20 */ | |
| 21 class LiveInterval { | |
| 22 /** | |
| 23 * The id where there instruction is defined. | |
| 24 */ | |
| 25 int start; | |
| 26 final List<LiveRange> ranges; | |
| 27 LiveInterval() : ranges = <LiveRange>[]; | |
| 28 | |
| 29 /** | |
| 30 * Update all ranges that are contained in [start, end[ to have | |
|
floitsch
2012/05/30 18:45:03
This will probably confuse the doc-generator, and
kasperl
2012/05/31 05:26:03
to have die? to have died? to die?
ngeoffray
2012/05/31 08:12:46
to die.
ngeoffray
2012/05/31 08:12:46
Let's see how it complains :)
| |
| 31 * die at [end]. | |
|
floitsch
2012/05/30 18:45:03
"have die"?
either have "end", or just "to die"
ngeoffray
2012/05/31 08:12:46
Done.
| |
| 32 */ | |
| 33 void loopUpdate(int start, int end) { | |
| 34 for (LiveRange range in ranges) { | |
| 35 if (range.start >= start && range.end < end) { | |
|
floitsch
2012/05/30 18:45:03
minor, but personally I prefer start <= range.star
ngeoffray
2012/05/31 08:12:46
Done.
| |
| 36 range.end = end; | |
| 37 } | |
| 38 } | |
| 39 } | |
| 40 | |
| 41 /** | |
| 42 * Add a new range to this interval. | |
| 43 */ | |
| 44 void add(LiveRange interval) { | |
| 45 ranges.add(interval); | |
| 46 } | |
| 47 | |
| 48 /** | |
| 49 * Returns true if one of the ranges of this interval dies at [at]. | |
| 50 */ | |
| 51 bool diesAt(int at) { | |
| 52 for (LiveRange range in ranges) { | |
|
floitsch
2012/05/30 18:45:03
Haven't yet looked at the use-sites, but this look
ngeoffray
2012/05/31 08:12:46
An instruction doesn't have that many live ranges.
| |
| 53 if (range.end == at) return true; | |
| 54 } | |
| 55 return false; | |
| 56 } | |
| 57 | |
| 58 String toString() { | |
| 59 List<String> res = new List<String>(); | |
| 60 for (final interval in ranges) res.add(interval.toString()); | |
| 61 return '(${Strings.join(res, ', ')})'; | |
| 62 } | |
| 63 } | |
| 64 | |
| 65 /** | |
| 66 * The [LiveEnvironment] class contains the live-ins of a basic block. | |
|
floitsch
2012/05/30 18:45:03
please rename all "live-in"s with "live-interval"s
ngeoffray
2012/05/31 08:12:46
It's not containing the live-intervals, it's conta
| |
| 67 */ | |
| 68 class LiveEnvironment { | |
| 69 /** | |
|
kasperl
2012/05/31 05:26:03
It would be nice with some better explanations of
ngeoffray
2012/05/31 08:12:46
Done.
| |
| 70 * The id where the basic block starts. | |
| 71 */ | |
| 72 int startId; | |
| 73 | |
| 74 /** | |
| 75 * The id where the basic block ends. | |
| 76 */ | |
| 77 final int endId; | |
| 78 | |
| 79 /** | |
| 80 * List of loop markers that will be updated once the loop header is | |
|
kasperl
2012/05/31 05:26:03
Maybe explain what it marks (what's the int value
ngeoffray
2012/05/31 08:12:46
Done.
| |
| 81 * visited. All live-ins of the loop header will be merged into this | |
| 82 * environment. | |
| 83 */ | |
| 84 final Map<HBasicBlock, int> loopMarkers; | |
| 85 | |
| 86 /** | |
| 87 * The instructions that are live in this basic block. The values of | |
| 88 * the map contains the ids where the instructions die. | |
|
floitsch
2012/05/30 18:45:03
contain
ngeoffray
2012/05/31 08:12:46
Done.
| |
| 89 */ | |
| 90 final Map<HInstruction, int> lives; | |
|
floitsch
2012/05/30 18:45:03
could we rename this to "lastUsedAt" ?
kasperl
2012/05/31 05:26:03
lives -> liveUntil? How does this relate to the la
ngeoffray
2012/05/31 08:12:46
It's really a map of live instructions with the in
ngeoffray
2012/05/31 08:12:46
It will be used when adding a range to the live in
| |
| 91 | |
| 92 /** | |
| 93 * Map containing the live intervals of instructions. | |
| 94 */ | |
| 95 final Map<HInstruction, LiveInterval> liveIntervals; | |
| 96 | |
| 97 LiveEnvironment(this.liveIntervals, this.endId) | |
| 98 : lives = new Map<HInstruction, int>(), | |
| 99 loopMarkers = new Map<HBasicBlock, int>(); | |
| 100 | |
| 101 /** | |
| 102 * Remove an instruction from the liveIn set. This method also | |
| 103 * updates the live interval of [instruction] to contain the new | |
| 104 * range: [id, / id contained in [lives] /]. | |
| 105 */ | |
| 106 void remove(HInstruction instruction, int id) { | |
| 107 // Special case the HCheck instruction to have the same live | |
| 108 // interval as the instruction it is checking. | |
| 109 if (instruction is HCheck) { | |
| 110 HInstruction input = instruction.checkedInput; | |
| 111 while (input is HCheck) input = input.checkedInput; | |
| 112 liveIntervals.putIfAbsent(input, () => new LiveInterval()); | |
| 113 liveIntervals.putIfAbsent(instruction, () => liveIntervals[input]); | |
| 114 return; | |
| 115 } | |
| 116 LiveInterval range = liveIntervals.putIfAbsent( | |
| 117 instruction, () => new LiveInterval()); | |
| 118 int lastId = lives[instruction]; | |
| 119 // If [lastId] is null, then this instruction is bot being used. | |
|
floitsch
2012/05/30 18:45:03
not
kasperl
2012/05/31 05:26:03
is bot -> is not
ngeoffray
2012/05/31 08:12:46
Done.
ngeoffray
2012/05/31 08:12:46
Done.
| |
| 120 range.add(new LiveRange(id, lastId == null ? id : lastId)); | |
| 121 // The instruction is defined at [id]. | |
| 122 range.start = id; | |
| 123 lives.remove(instruction); | |
| 124 } | |
| 125 | |
| 126 /** | |
| 127 * Add [instruction] to the liveIn set. If the instruction is not | |
| 128 * already in the set, we save the id where it dies. | |
| 129 */ | |
| 130 void add(HInstruction instruction, int userId) { | |
| 131 // Special case the HCheck instruction to use the actual checked | |
| 132 // instruction. | |
| 133 while (instruction is HCheck) instruction = instruction.checkedInput; | |
| 134 lives.putIfAbsent(instruction, () => userId); | |
|
floitsch
2012/05/30 18:45:03
Add comment that reminds that we are visiting the
ngeoffray
2012/05/31 08:12:46
Done.
| |
| 135 } | |
| 136 | |
| 137 /** | |
| 138 * Merge this environment with [other]. Update the end id of | |
| 139 * instructions in case they are different between this and [other]. | |
| 140 */ | |
| 141 void mergeWith(LiveEnvironment other) { | |
| 142 other.lives.forEach((HInstruction instruction, int existingId) { | |
| 143 if (existingId == endId) return; | |
|
floitsch
2012/05/30 18:45:03
Add comment when this can happen.
ngeoffray
2012/05/31 08:12:46
Done.
| |
| 144 LiveInterval range = liveIntervals.putIfAbsent( | |
| 145 instruction, () => new LiveInterval()); | |
| 146 range.add(new LiveRange(other.startId, existingId)); | |
| 147 lives[instruction] = endId; | |
| 148 }); | |
| 149 other.loopMarkers.forEach((k, v) { loopMarkers[k] = v; }); | |
| 150 } | |
| 151 | |
| 152 void addLoopMarker(HBasicBlock header, int id) { | |
| 153 assert(!loopMarkers.containsKey(header)); | |
| 154 loopMarkers[header] = id; | |
| 155 } | |
| 156 | |
| 157 void removeLoopMarker(HBasicBlock header) { | |
| 158 assert(loopMarkers.containsKey(header)); | |
| 159 loopMarkers.remove(header); | |
| 160 } | |
| 161 | |
| 162 bool isEmpty() => lives.isEmpty() && loopMarkers.isEmpty(); | |
| 163 bool contains(HInstruction instruction) => lives.containsKey(instruction); | |
| 164 String toString() => lives.toString(); | |
| 165 } | |
| 166 | |
| 167 /** | |
| 168 * Builds the live intervals of each instruction. The algorithm visits | |
| 169 * the graph post-dominator tree to find the last uses of an | |
| 170 * instruction, and computes the liveIns of each basic block. | |
| 171 */ | |
| 172 class SsaLiveIntervalBuilder extends HBaseVisitor { | |
| 173 final Compiler compiler; | |
| 174 | |
| 175 /** | |
| 176 * A counter to assign start and end ids to live ranges. The initial | |
| 177 * value is not relevant. | |
| 178 */ | |
| 179 int counter = 0; | |
| 180 | |
| 181 /** | |
| 182 * The liveIns of basic blocks. | |
| 183 */ | |
| 184 final Map<HBasicBlock, LiveEnvironment> liveInstructions; | |
| 185 | |
| 186 /** | |
| 187 * The live intervals of instructions. | |
| 188 */ | |
| 189 final Map<HInstruction, LiveInterval> liveIntervals; | |
| 190 | |
| 191 SsaLiveIntervalBuilder(this.compiler) | |
| 192 : liveInstructions = new Map<HBasicBlock, LiveEnvironment>(), | |
| 193 liveIntervals = new Map<HInstruction, LiveInterval>(); | |
| 194 | |
| 195 void visitGraph(HGraph graph) { | |
| 196 visitPostDominatorTree(graph); | |
| 197 if (!liveInstructions[graph.entry].isEmpty()) { | |
| 198 compiler.internalError('LiveIntervalBuilder', | |
| 199 node: compiler.currentElement.parseNode(compiler)); | |
| 200 } | |
| 201 } | |
| 202 | |
| 203 void visitBasicBlock(HBasicBlock block) { | |
| 204 LiveEnvironment environment = new LiveEnvironment(liveIntervals, counter); | |
| 205 | |
| 206 // Add to the environment the live instructions of its successor, as well as | |
| 207 // the inputs of the phis of the successor that flow from this block. | |
| 208 for (int i = 0; i < block.successors.length; i++) { | |
| 209 HBasicBlock successor = block.successors[i]; | |
| 210 LiveEnvironment successorEnv = liveInstructions[successor]; | |
| 211 if (successorEnv !== null) { | |
| 212 environment.mergeWith(successorEnv); | |
| 213 } else { | |
| 214 environment.addLoopMarker(successor, counter); | |
| 215 } | |
| 216 | |
| 217 int index = successor.predecessors.indexOf(block); | |
| 218 for (HPhi phi = successor.phis.first; phi != null; phi = phi.next) { | |
| 219 environment.add(phi.inputs[index], counter); | |
| 220 } | |
| 221 } | |
| 222 | |
| 223 // Iterate over all instructions to remove an instruction from the | |
| 224 // environment and add its inputs. | |
| 225 HInstruction instruction = block.last; | |
| 226 while (instruction != null) { | |
| 227 environment.remove(instruction, counter); | |
| 228 for (int i = 0, len = instruction.inputs.length; i < len; i++) { | |
| 229 environment.add(instruction.inputs[i], counter); | |
| 230 } | |
| 231 instruction = instruction.previous; | |
| 232 counter--; | |
|
kasperl
2012/05/31 05:26:03
This is the only place you change counter? Hmm. Th
ngeoffray
2012/05/31 08:12:46
Changed the name to instructionId, and added a com
| |
| 233 } | |
| 234 | |
| 235 // We just remove the phis from the environment. The inputs of the | |
| 236 // phis will be put in the environment of the predecessors. | |
| 237 for (HPhi phi = block.phis.first; phi != null; phi = phi.next) { | |
| 238 environment.remove(phi, counter); | |
| 239 } | |
| 240 | |
| 241 // Save the liveInstructions of that block. | |
| 242 environment.startId = counter + 1; | |
| 243 liveInstructions[block] = environment; | |
| 244 | |
| 245 // If the block is a loop header, we can remove the loop marker, | |
| 246 // because it will just recompute the loop phis. | |
| 247 if (block.isLoopHeader()) { | |
| 248 updateLoopMarker(block); | |
| 249 } | |
| 250 } | |
| 251 | |
| 252 void updateLoopMarker(HBasicBlock header) { | |
| 253 LiveEnvironment env = liveInstructions[header]; | |
| 254 int lastId = env.loopMarkers[header]; | |
| 255 // Update all instructions that are liveIns in [header] to have a | |
| 256 // range that covers the loop. | |
| 257 env.lives.forEach((HInstruction instruction, int id) { | |
| 258 LiveInterval range = env.liveIntervals.putIfAbsent( | |
| 259 instruction, () => new LiveInterval()); | |
| 260 range.loopUpdate(env.startId, lastId); | |
| 261 env.lives[instruction] = lastId; | |
| 262 }); | |
| 263 | |
| 264 env.removeLoopMarker(header); | |
| 265 | |
| 266 // Update all liveIns set to contain the liveIns of [header]. | |
| 267 liveInstructions.forEach((HBasicBlock block, LiveEnvironment other) { | |
| 268 if (other.loopMarkers.containsKey(header)) { | |
| 269 env.lives.forEach((HInstruction instruction, int id) { | |
| 270 other.lives[instruction] = id; | |
| 271 }); | |
| 272 other.removeLoopMarker(header); | |
| 273 env.loopMarkers.forEach((k, v) { other.loopMarkers[k] = v; }); | |
| 274 } | |
| 275 }); | |
| 276 } | |
| 277 } | |
| 278 | |
| 279 /** | |
| 280 * Represents a copy from one instruction to another. The codegen | |
| 281 * also uses this class to represent a copy from one variable to | |
| 282 * another. | |
| 283 */ | |
| 284 class Copy { | |
|
Lasse Reichstein Nielsen
2012/05/31 08:24:56
Rename to "Copying" (or "Assignment" if that isn't
ngeoffray
2012/05/31 08:48:22
As discussed, kept the name :)
| |
| 285 var source; | |
|
floitsch
2012/05/30 18:45:03
final HInstruction ?
kasperl
2012/05/31 05:26:03
Types on source and destination? I'm pretty sure t
ngeoffray
2012/05/31 08:12:46
They are here, but will be String in codegen :) Th
ngeoffray
2012/05/31 08:12:46
Made it final, but not typed, as they can also be
| |
| 286 var destination; | |
| 287 Copy(this.source, this.destination); | |
| 288 String toString() => '$destination <- $source'; | |
| 289 } | |
| 290 | |
| 291 /** | |
| 292 * A copy handler contains the copies that a basic block needs to do | |
| 293 * after executing all its instructions. | |
| 294 */ | |
| 295 class CopyHandler { | |
| 296 /** | |
| 297 * The copies from an instruction to a phi of the successor. | |
| 298 */ | |
| 299 final List<Copy> copies; | |
| 300 | |
| 301 /** | |
| 302 * Trivial assignments from a constant to the phi of a successor. | |
|
Lasse Reichstein Nielsen
2012/05/31 08:24:56
How is this different from a copying? I.e., what m
ngeoffray
2012/05/31 08:48:22
Because the source does not need a name. Added a c
| |
| 303 */ | |
| 304 final List<Copy> assignments; | |
| 305 | |
| 306 CopyHandler() | |
| 307 : copies = new List<Copy>(), | |
| 308 assignments = new List<Copy>(); | |
| 309 | |
| 310 void addCopy(HInstruction source, HInstruction destination) { | |
| 311 copies.add(new Copy(source, destination)); | |
| 312 } | |
| 313 | |
| 314 void addAssignment(HInstruction source, HInstruction destination) { | |
| 315 assignments.add(new Copy(source, destination)); | |
| 316 } | |
| 317 | |
| 318 String toString() { | |
|
kasperl
2012/05/31 05:26:03
=>
ngeoffray
2012/05/31 08:12:46
Done.
| |
| 319 return 'Copies: $copies, assignments: $assignments'; | |
| 320 } | |
| 321 } | |
| 322 | |
| 323 /** | |
| 324 * Contains the mapping between instructions and their names for code | |
| 325 * generation, as well as the [CopyHandler] for each basic block. | |
| 326 */ | |
| 327 class VariableNames { | |
| 328 final Map<HInstruction, String> ownName; | |
| 329 final Map<HBasicBlock, CopyHandler> copies; | |
|
kasperl
2012/05/31 05:26:03
This really don't hold copies -- it holds handlers
ngeoffray
2012/05/31 08:12:46
Done.
| |
| 330 static final String SWAP_TEMP = 't0'; | |
|
Lasse Reichstein Nielsen
2012/05/31 08:24:56
How do we know this doesn't collide with anything?
ngeoffray
2012/05/31 08:48:22
Done. And added a TODO to deal with parameters.
| |
| 331 | |
| 332 VariableNames() | |
| 333 : ownName = new Map<HInstruction, String>(), | |
| 334 copies = new Map<HBasicBlock, CopyHandler>(); | |
| 335 | |
| 336 String getName(HInstruction instruction) { | |
| 337 return ownName[instruction]; | |
| 338 } | |
| 339 | |
| 340 CopyHandler getCopies(HBasicBlock block) { | |
|
kasperl
2012/05/31 05:26:03
I would probably call this getCopyHandler.
ngeoffray
2012/05/31 08:12:46
Done.
| |
| 341 return copies[block]; | |
| 342 } | |
| 343 | |
| 344 bool hasName(HInstruction instruction) => ownName.containsKey(instruction); | |
| 345 | |
| 346 void addCopy(HBasicBlock block, HInstruction source, HPhi destination) { | |
| 347 CopyHandler handler = | |
| 348 copies.putIfAbsent(block, () => new CopyHandler()); | |
| 349 handler.addCopy(source, destination); | |
| 350 } | |
| 351 | |
| 352 void addAssignment(HBasicBlock block, HInstruction source, HPhi destination) { | |
| 353 CopyHandler handler = | |
| 354 copies.putIfAbsent(block, () => new CopyHandler()); | |
| 355 handler.addAssignment(source, destination); | |
| 356 } | |
| 357 } | |
| 358 | |
| 359 /** | |
| 360 * Allocates variable names for instructions, making sure they don't | |
| 361 * collide. | |
|
floitsch
2012/05/30 18:45:03
Not that it matters, but this should fit on one li
ngeoffray
2012/05/31 08:12:46
Done.
| |
| 362 */ | |
| 363 class VariableNamer { | |
| 364 final VariableNames names; | |
| 365 final Set<String> usedNames; | |
| 366 | |
| 367 VariableNamer(LiveEnvironment environment, this.names) | |
| 368 : usedNames = new Set<String>() { | |
| 369 // [VariableNames.SWAP_TEMP] is being used when there is a cycle | |
| 370 // in a copy handler. Therefore we make sure no one will use it. | |
| 371 usedNames.add(VariableNames.SWAP_TEMP); | |
| 372 | |
| 373 // All liveIns instructions must have a name at this point, so we | |
| 374 // add them to the list of used names. | |
| 375 environment.lives.forEach((HInstruction instruction, int index) { | |
| 376 String name = names.getName(instruction); | |
| 377 if (name !== null) { | |
| 378 usedNames.add(name); | |
| 379 } | |
| 380 }); | |
| 381 } | |
| 382 | |
| 383 String allocateWithHint(String originalName) { | |
| 384 int i = 0; | |
| 385 String name = JsNames.getValid(originalName); | |
| 386 while (usedNames.contains(name)) { | |
| 387 name = JsNames.getValid('$originalName${i++}'); | |
| 388 } | |
| 389 return name; | |
| 390 } | |
| 391 | |
| 392 String allocateTemporary() { | |
| 393 int i = 1; | |
|
kasperl
2012/05/31 05:26:03
Add comment about not using t0 because it's SWAP_T
ngeoffray
2012/05/31 08:12:46
Done.
| |
| 394 String name = 't${i++}'; | |
| 395 while (usedNames.contains(name)) name = 't${i++}'; | |
| 396 return name; | |
| 397 } | |
| 398 | |
| 399 HPhi firstPhiUserWithElement(HInstruction instruction) { | |
| 400 for (HInstruction user in instruction.usedBy) { | |
| 401 if (user is HPhi && user.sourceElement !== null) { | |
| 402 return user; | |
| 403 } | |
| 404 } | |
| 405 return null; | |
| 406 } | |
| 407 | |
| 408 String allocateName(HInstruction instruction) { | |
| 409 String name; | |
| 410 if (instruction is HCheck) { | |
| 411 // Special case the check instruction to use the name of its | |
| 412 // checked instruction. | |
| 413 HCheck check = instruction; | |
| 414 name = names.ownName[check.checkedInput]; | |
| 415 // If the name is null, then the checked input is being | |
| 416 // generated at use site, and we don't need a name for the check | |
| 417 // instruction. | |
| 418 if (name == null) return; | |
| 419 } else if (instruction is HParameterValue) { | |
| 420 HParameterValue parameter = instruction; | |
| 421 name = allocateWithHint(parameter.element.name.slowToString()); | |
| 422 } else if (instruction.sourceElement !== null) { | |
| 423 name = allocateWithHint(instruction.sourceElement.name.slowToString()); | |
| 424 } else { | |
| 425 // We could not find an element for the instruction. If the | |
| 426 // instruction is used by a phi, try to use the name of the phi. | |
| 427 // Otherwise, just allocate a temporary name. | |
| 428 HPhi phi = firstPhiUserWithElement(instruction); | |
| 429 if (phi !== null) { | |
| 430 name = allocateWithHint(phi.sourceElement.name.slowToString()); | |
| 431 } else { | |
| 432 name = allocateTemporary(); | |
| 433 } | |
| 434 } | |
| 435 usedNames.add(name); | |
| 436 names.ownName[instruction] = name; | |
| 437 return name; | |
| 438 } | |
| 439 | |
| 440 void freeName(HInstruction instruction) { | |
|
floitsch
2012/05/30 18:45:03
Add comment: "Frees the [instruction]'s name so it
ngeoffray
2012/05/31 08:12:46
Done.
| |
| 441 String ownName = names.ownName[instruction]; | |
| 442 if (ownName != null) { | |
| 443 usedNames.remove(ownName); | |
| 444 } | |
| 445 } | |
| 446 } | |
| 447 | |
| 448 /** | |
| 449 * Visits all blocks in the graph, sets names to instructions, and | |
| 450 * creates the [CopyHandler] for each block. This class needs to have | |
| 451 * the liveIns set as well as all the live intervals of instructions. | |
| 452 * It visits the graph in dominator order, so that at each entry of a | |
| 453 * block, the instructions in its liveIns set have names. | |
| 454 * | |
| 455 * When visiting a block, it goes through all instructions. For each | |
| 456 * instruction, it frees the names of the inputs that die at that | |
| 457 * instruction, and allocates a name to the instruction. For each phi, | |
| 458 * it adds a copy to the CopyHandler of the corresponding predecessor. | |
| 459 */ | |
| 460 class SsaVariableAllocator extends HBaseVisitor { | |
| 461 | |
| 462 final Compiler compiler; | |
| 463 final Map<HBasicBlock, LiveEnvironment> liveInstructions; | |
| 464 final Map<HInstruction, LiveInterval> liveIntervals; | |
| 465 final Set<HInstruction> generateAtUseSite; | |
| 466 | |
| 467 final VariableNames names; | |
| 468 | |
| 469 SsaVariableAllocator(this.compiler, | |
| 470 this.liveInstructions, | |
| 471 this.liveIntervals, | |
| 472 this.generateAtUseSite) | |
| 473 : names = new VariableNames(); | |
| 474 | |
| 475 void visitGraph(HGraph graph) { | |
| 476 visitDominatorTree(graph); | |
| 477 } | |
| 478 | |
| 479 void visitBasicBlock(HBasicBlock block) { | |
| 480 VariableNamer namer = new VariableNamer(liveInstructions[block], names); | |
| 481 | |
| 482 block.forEachPhi((HPhi phi) { | |
| 483 handlePhi(phi, namer); | |
| 484 }); | |
| 485 | |
| 486 block.forEachInstruction((HInstruction instruction) { | |
| 487 handleInstruction(instruction, namer); | |
| 488 }); | |
| 489 } | |
| 490 | |
| 491 /** | |
| 492 * Returns whether [instruction] needs a name. Instructions that | |
| 493 * have no users or that are generated at use site does not need a name. | |
|
kasperl
2012/05/31 05:26:03
use site does -> use site do. Maybe change method
ngeoffray
2012/05/31 08:12:46
Done.
| |
| 494 */ | |
| 495 bool needsVariable(HInstruction instruction) { | |
| 496 if (instruction.usedBy.isEmpty()) return false; | |
| 497 // TODO(ngeoffray): We need a name for parameters, but we could | |
|
kasperl
2012/05/31 05:26:03
The TODO comment isn't easy to understand. The "we
ngeoffray
2012/05/31 08:12:46
The problem is that we're making parameters genera
| |
| 498 // allocate it before. | |
| 499 if (instruction is HParameterValue && instruction is !HThis) return true; | |
| 500 if (generateAtUseSite.contains(instruction)) return false; | |
| 501 return true; | |
| 502 } | |
| 503 | |
|
kasperl
2012/05/31 05:26:03
Too many newlines.
ngeoffray
2012/05/31 08:12:46
Done.
| |
| 504 | |
| 505 /** | |
| 506 * Retrurns whether [instruction] dies at the instruction [at]. | |
|
floitsch
2012/05/30 18:45:03
Returns
kasperl
2012/05/31 05:26:03
Retrurns -> Returns
ngeoffray
2012/05/31 08:12:46
Done.
ngeoffray
2012/05/31 08:12:46
Done.
| |
| 507 */ | |
| 508 bool diesAt(HInstruction instruction, HInstruction at) { | |
| 509 LiveInterval atRange = liveIntervals[at]; | |
|
kasperl
2012/05/31 05:26:03
You call them ranges in a few places, but the type
ngeoffray
2012/05/31 08:12:46
Done.
| |
| 510 LiveInterval instructionRange = liveIntervals[instruction]; | |
| 511 int start = atRange.start; | |
| 512 return instructionRange.diesAt(start); | |
| 513 } | |
| 514 | |
| 515 void handleInstruction(HInstruction instruction, VariableNamer namer) { | |
| 516 for (int i = 0, len = instruction.inputs.length; i < len; i++) { | |
| 517 HInstruction input = instruction.inputs[i]; | |
| 518 if (needsVariable(input) && diesAt(input, instruction)) { | |
|
kasperl
2012/05/31 05:26:03
Add a comment here. If we're the last use of somet
ngeoffray
2012/05/31 08:12:46
Done.
| |
| 519 namer.freeName(input); | |
| 520 } | |
| 521 } | |
| 522 | |
| 523 if (needsVariable(instruction)) { | |
| 524 namer.allocateName(instruction); | |
| 525 } | |
| 526 } | |
| 527 | |
| 528 void handlePhi(HPhi phi, VariableNamer namer) { | |
| 529 if (!needsVariable(phi)) return; | |
| 530 | |
| 531 for (int i = 0; i < phi.inputs.length; i++) { | |
| 532 HInstruction input = phi.inputs[i]; | |
| 533 HBasicBlock predecessor = phi.block.predecessors[i]; | |
| 534 if (!needsVariable(input)) { | |
| 535 names.addAssignment(predecessor, input, phi); | |
|
Lasse Reichstein Nielsen
2012/05/31 08:24:56
If it doesn't need a variable, what are we assigni
ngeoffray
2012/05/31 08:48:22
The instruction (eg a constant, or a generate at u
| |
| 536 } else { | |
| 537 names.addCopy(predecessor, input, phi); | |
| 538 } | |
| 539 } | |
| 540 | |
| 541 namer.allocateName(phi); | |
| 542 } | |
| 543 } | |
| OLD | NEW |