001/* 002 * This file is part of the Jikes RVM project (http://jikesrvm.org). 003 * 004 * This file is licensed to You under the Eclipse Public License (EPL); 005 * You may not use this file except in compliance with the License. You 006 * may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/eclipse-1.0.php 009 * 010 * See the COPYRIGHT.txt file distributed with this work for information 011 * regarding copyright ownership. 012 */ 013package org.jikesrvm.compilers.opt.lir2mir; 014 015import java.util.Enumeration; 016 017import org.jikesrvm.VM; 018import org.jikesrvm.compilers.opt.OptimizingCompilerException; 019import org.jikesrvm.compilers.opt.depgraph.DepGraph; 020import org.jikesrvm.compilers.opt.depgraph.DepGraphEdge; 021import org.jikesrvm.compilers.opt.depgraph.DepGraphNode; 022import org.jikesrvm.compilers.opt.ir.IR; 023import org.jikesrvm.compilers.opt.ir.Instruction; 024 025import static org.jikesrvm.compilers.opt.ir.Operators.CALL_opcode; 026import static org.jikesrvm.compilers.opt.ir.Operators.GUARD_COMBINE; 027import static org.jikesrvm.compilers.opt.ir.Operators.GUARD_COND_MOVE; 028import static org.jikesrvm.compilers.opt.ir.Operators.GUARD_MOVE; 029import static org.jikesrvm.compilers.opt.ir.Operators.IR_PROLOGUE; 030import static org.jikesrvm.compilers.opt.ir.Operators.OTHER_OPERAND_opcode; 031import static org.jikesrvm.compilers.opt.ir.Operators.RETURN_opcode; 032import static org.jikesrvm.compilers.opt.ir.Operators.SYSCALL_opcode; 033import static org.jikesrvm.compilers.opt.ir.Operators.YIELDPOINT_OSR_opcode; 034 035import org.jikesrvm.compilers.opt.ir.ResultCarrier; 036import org.jikesrvm.compilers.opt.ir.operand.AddressConstantOperand; 037import org.jikesrvm.compilers.opt.ir.operand.BranchOperand; 038import org.jikesrvm.compilers.opt.ir.operand.InlinedOsrTypeInfoOperand; 039import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand; 040import org.jikesrvm.compilers.opt.ir.operand.LongConstantOperand; 041import org.jikesrvm.compilers.opt.ir.operand.Operand; 042import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand; 043import org.jikesrvm.compilers.opt.util.SpaceEffGraphEdge; 044import org.jikesrvm.compilers.opt.util.SpaceEffGraphNode; 045 046/** 047 * This class contains methods for invoking BURS tree-pattern matching 048 * from the OPT Compiler. BURS is invoked on trees obtained from the 049 * dependence graph of a basic block. 050 * 051 * @see DepGraph 052 * @see BURS_StateCoder 053 * @see AbstractBURS_TreeNode 054 */ 055final class NormalBURS extends BURS { 056 057 private int numTreeRoots; 058 059 /** 060 * track problem nodes (nodes with outgoing non-reg-true edges) 061 */ 062 private SpaceEffGraphEdge[] problemEdges; 063 064 /** Number of problem edges */ 065 private int numProblemEdges = 0; 066 067 068 /** 069 * Create a BURS object for the given IR. 070 * 071 * @param ir the IR to translate from LIR to MIR. 072 */ 073 NormalBURS(IR ir) { 074 super(ir); 075 } 076 077 /** 078 * Build BURS trees for dependence graph dg, label the trees, and 079 * then generate MIR instructions based on the labelling. 080 * @param dg the dependence graph. 081 */ 082 public void invoke(NormalBURS_DepGraph dg) { 083 if (DEBUG) dg.printDepGraph(); 084 buildTrees(dg); 085 if (haveProblemEdges()) { 086 problemEdgePrep(); 087 handleProblemEdges(); 088 } 089 orderTrees(dg); 090 labelTrees(); 091 generateTrees(makeCoder()); 092 } 093 094 //////////////////////////////// 095 // Implementation 096 //////////////////////////////// 097 098 private NormalBURS_DepGraphNode castNode(SpaceEffGraphNode node) { 099 return (NormalBURS_DepGraphNode) node; 100 } 101 102 /** 103 * Stage 1: Complete the expression trees and identify tree roots. 104 * Complete BURS trees by adding leaf nodes as needed, and 105 * creating tree edges by calling insertChild1() or insertChild2() 106 * This step is also where we introduce intermediate tree nodes for 107 * any LIR instruction that has > 2 "real" operands e.g., a CALL. 108 * We also mark nodes that must be tree roots. 109 * 110 * @param dg The dependence graph. 111 */ 112 private void buildTrees(DepGraph dg) { 113 DepGraphNode bbNodes = (DepGraphNode) dg.firstNode(); 114 for (DepGraphNode n = bbNodes; n != null; n = (DepGraphNode) n.getNext()) { 115 // Initialize n.treeNode 116 AbstractBURS_TreeNode cur_parent = AbstractBURS_TreeNode.create(n); 117 castNode(n).setCurrentParent(cur_parent); 118 Instruction instr = n.instruction(); 119 // cur_parent = current parent node for var length IR instructions 120 // loop for USES of an instruction 121 for (Enumeration<Operand> uses = instr.getUses(); uses.hasMoreElements();) { 122 // Create tree edge for next use. 123 Operand op = uses.nextElement(); 124 if (op == null) continue; 125 126 // Set child = AbstractBURS_TreeNode for operand op 127 AbstractBURS_TreeNode child; 128 if (op instanceof RegisterOperand) { 129 RegisterOperand regOp = (RegisterOperand) op; 130 // ignore validation registers 131 if (regOp.getRegister().isValidation()) continue; 132 DepGraphEdge e = DepGraphEdge.findInputEdge(n, op); 133 if (e == null) { // operand is leaf 134 child = Register; 135 } else { 136 child = castNode(e.fromNode()).getCurrentParent(); 137 } 138 } else if (op instanceof IntConstantOperand) { 139 child = new BURS_IntConstantTreeNode(((IntConstantOperand) op).value); 140 } else if (op instanceof LongConstantOperand) { 141 child = LongConstant; 142 } else if (op instanceof AddressConstantOperand) { 143 child = AddressConstant; 144 } else if (op instanceof BranchOperand && instr.isCall()) { 145 child = BranchTarget; 146 } else if (op instanceof InlinedOsrTypeInfoOperand && instr.isYieldPoint()) { 147 child = NullTreeNode; 148 } else { 149 continue; 150 } 151 152 // Attach child as child of cur_parent in correct position 153 if (cur_parent.getChild1() == null) { 154 cur_parent.setChild1(child); 155 } else if (cur_parent.getChild2() == null) { 156 cur_parent.setChild2(child); 157 } else { 158 // Create auxiliary node so as to represent 159 // a instruction with arity > 2 in a binary tree. 160 AbstractBURS_TreeNode child1 = cur_parent.getChild2(); 161 AbstractBURS_TreeNode aux = AbstractBURS_TreeNode.create(OTHER_OPERAND_opcode); 162 cur_parent.setChild2(aux); 163 cur_parent = aux; 164 cur_parent.setChild1(child1); 165 cur_parent.setChild2(child); 166 } 167 } // for (uses = ...) 168 169 // patch for calls & return 170 switch (instr.getOpcode()) { 171 case CALL_opcode: 172 case SYSCALL_opcode: 173 case YIELDPOINT_OSR_opcode: 174 if (cur_parent.getChild2() == null) { 175 cur_parent.setChild2(NullTreeNode); 176 } 177 // fall through 178 case RETURN_opcode: 179 if (cur_parent.getChild1() == null) { 180 cur_parent.setChild1(NullTreeNode); 181 } 182 } 183 184 if (mustBeTreeRoot(n)) { 185 makeTreeRoot(castNode(n).getCurrentParent()); 186 } 187 } 188 } 189 190 /** 191 * Stage 1b: Do bookkeeping to make it easier to identify 192 * harmless problem edges. 193 */ 194 private void problemEdgePrep() { 195 for (int i = 0; i < numTreeRoots; i++) { 196 AbstractBURS_TreeNode n = treeRoots[i]; 197 problemEdgePrep(n, n.dg_node); 198 } 199 } 200 201 private void problemEdgePrep(AbstractBURS_TreeNode n, SpaceEffGraphNode root) { 202 AbstractBURS_TreeNode child1 = n.child1; 203 AbstractBURS_TreeNode child2 = n.child2; 204 if (child1 != null && !child1.isTreeRoot()) { 205 problemEdgePrep(child1, root); 206 } 207 if (child2 != null && !child2.isTreeRoot()) { 208 problemEdgePrep(child2, root); 209 } 210 if (n.dg_node != null) { 211 n.dg_node.nextSorted = root; 212 castNode(n.dg_node).setPredecessorCount(0); 213 } 214 } 215 216 /** 217 * Stage 1c: Mark src node of some problem edges as tree roots to avoid 218 * cyclic dependencies. 219 */ 220 private void handleProblemEdges() { 221 // Stage 1: Remove problem edges whose destination 222 // is the root of their own tree; these edges 223 // are trivially redundant with reg-true edges. 224 int remaining = 0; 225 for (int i = 0; i < numProblemEdges; i++) { 226 SpaceEffGraphEdge e = problemEdges[i]; 227 SpaceEffGraphNode src = e.fromNode(); 228 SpaceEffGraphNode dst = e.toNode(); 229 SpaceEffGraphNode srcRoot = src.nextSorted; 230 if (srcRoot != dst) { 231 // might still be trouble 232 problemEdges[remaining++] = e; 233 } 234 } 235 numProblemEdges = remaining; 236 if (numProblemEdges == 0) return; 237 238 // Still some edges that might introduce cycles. 239 int searchnum = 0; 240 for (int i = 0; i < numProblemEdges; i++) { 241 SpaceEffGraphEdge e = problemEdges[i]; 242 SpaceEffGraphNode src = e.fromNode(); 243 SpaceEffGraphNode dst = e.toNode(); 244 AbstractBURS_TreeNode n = castNode(src).getCurrentParent(); 245 if (n.isTreeRoot()) continue; // some other problem edge already forced it 246 SpaceEffGraphNode srcRoot = src.nextSorted; 247 SpaceEffGraphNode dstRoot = dst.nextSorted; 248 if (srcRoot == dstRoot && srcRoot != dst) { 249 // potential for intra-tree cycle 250 if (!trueEdgeRedundant(src, dst, srcRoot)) { 251 if (DEBUG) { 252 VM.sysWrite("Potential intra-tree cycle with edge " + e + " forcing " + n + " to be a tree root\n"); 253 } 254 makeTreeRoot(n); 255 problemEdgePrep(n, n.dg_node); 256 } 257 } else { 258 // potential for inter-tree cycle 259 if (reachableRoot(dstRoot, srcRoot, ++searchnum)) { 260 if (DEBUG) { 261 VM.sysWrite("Potential inter-tree cycle with edge " + e + " forcing " + n + " to be a tree root\n"); 262 } 263 makeTreeRoot(n); 264 problemEdgePrep(n, n.dg_node); 265 } 266 } 267 } 268 } 269 270 // routine to identify harmless intra-tree edges. 271 // if the edge is redundant wrt regTrue edges, then it 272 // can be ignored. 273 private boolean trueEdgeRedundant(SpaceEffGraphNode current, SpaceEffGraphNode goal, 274 SpaceEffGraphNode root) { 275 if (current == goal) return true; 276 if (current.nextSorted != root) return false; // don't cross tree boundaries 277 for (SpaceEffGraphEdge out = current.firstOutEdge(); out != null; out = out.getNextOut()) { 278 if (DepGraphEdge.isRegTrue(out) && trueEdgeRedundant(out.toNode(), goal, root)) { 279 return true; 280 } 281 } 282 return false; 283 } 284 285 // routine to identify harmless inter-tree edges. 286 // Is goal reachable via any edge in the current tree? 287 private boolean reachableRoot(SpaceEffGraphNode current, SpaceEffGraphNode goal, int searchnum) { 288 if (current == goal) return true; 289 if (castNode(current).getPredecessorCount() == searchnum) return false; 290 castNode(current).setPredecessorCount(searchnum); 291 AbstractBURS_TreeNode root = castNode(current).getCurrentParent(); 292 return reachableChild(root, goal, searchnum); 293 } 294 295 private boolean reachableChild(AbstractBURS_TreeNode n, SpaceEffGraphNode goal, int searchnum) { 296 SpaceEffGraphNode dgn = n.dg_node; 297 if (dgn != null) { 298 for (SpaceEffGraphEdge out = dgn.firstOutEdge(); out != null; out = out.getNextOut()) { 299 if (reachableRoot(out.toNode().nextSorted, goal, searchnum)) return true; 300 } 301 } 302 if (n.getChild1() != null && !n.getChild1().isTreeRoot() && reachableChild(n.getChild1(), goal, searchnum)) { 303 return true; 304 } 305 if (n.getChild2() != null && !n.getChild2().isTreeRoot() && reachableChild(n.getChild2(), goal, searchnum)) { 306 return true; 307 } 308 return false; 309 } 310 311 /** 312 * Stage 2: Construct topological ordering of tree roots based on the 313 * dependencies between nodes in the tree. 314 * 315 * @param dg The dependence graph. 316 */ 317 private void orderTrees(DepGraph dg) { 318 // Initialize tree root field for all nodes 319 for (int i = 0; i < numTreeRoots; i++) { 320 AbstractBURS_TreeNode n = treeRoots[i]; 321 castNode(n.dg_node).setPredecessorCount(0); 322 initTreeRootNode(n, n.dg_node); 323 } 324 325 // Initialize predCount[*] 326 for (SpaceEffGraphNode node = dg.firstNode(); node != null; node = node.getNext()) { 327 SpaceEffGraphNode n_treeRoot = node.nextSorted; 328 for (SpaceEffGraphEdge in = node.firstInEdge(); in != null; in = in.getNextIn()) { 329 SpaceEffGraphNode source_treeRoot = in.fromNode().nextSorted; 330 if (source_treeRoot != n_treeRoot) { 331 castNode(n_treeRoot).incPredecessorCount(); 332 } 333 } 334 } 335 if (DEBUG) { 336 for (int i = 0; i < numTreeRoots; i++) { 337 AbstractBURS_TreeNode n = treeRoots[i]; 338 VM.sysWrite(castNode(n.dg_node).getPredecessorCount() + ":" + n + "\n"); 339 } 340 } 341 } 342 343 /** 344 * Stage 3: Label the trees with their min cost cover. 345 */ 346 private void labelTrees() { 347 for (int i = 0; i < numTreeRoots; i++) { 348 AbstractBURS_TreeNode n = treeRoots[i]; 349 label(n); 350 mark(n, /* goalnt -stm_NT */ (byte)1); 351 } 352 } 353 354 /** 355 * Stage 4: Visit the tree roots in topological order and 356 * emit MIR instructions by calling BURS_StateCoder.code on each 357 * supernode in the tree. 358 * 359 * @param burs the BURS_StateCoder object. 360 */ 361 private void generateTrees(BURS_StateCoder burs) { 362 // Append tree roots with predCount = 0 to readySet 363 for (int i = 0; i < numTreeRoots; i++) { 364 AbstractBURS_TreeNode n = treeRoots[i]; 365 if (castNode(n.dg_node).getPredecessorCount() == 0) { 366 readySetInsert(n); 367 } 368 } 369 370 // Emit code for each tree root in readySet 371 while (readySetNotEmpty()) { 372 AbstractBURS_TreeNode k = readySetRemove(); 373 // Invoke burs.code on the supernodes of k in a post order walk of the 374 // tree (thus code for children is emited before code for the parent). 375 if (DEBUG) { 376 VM.sysWrite("PROCESSING TREE ROOTED AT " + k.dg_node + "\n"); 377 dumpTree(k); 378 } 379 numTreeRoots--; 380 generateTree(k, burs); 381 } 382 if (numTreeRoots != 0) { 383 throw new OptimizingCompilerException("BURS", "Not all tree roots were processed"); 384 } 385 } 386 387 // Generate code for a single tree root. 388 // Also process inter-tree dependencies from this tree to other trees. 389 private void generateTree(AbstractBURS_TreeNode k, BURS_StateCoder burs) { 390 AbstractBURS_TreeNode child1 = k.child1; 391 AbstractBURS_TreeNode child2 = k.child2; 392 if (child1 != null) { 393 if (child2 != null) { 394 // k has two children; use register labeling to 395 // determine order that minimizes register pressure 396 if (k.isSuperNodeRoot()) { 397 byte act = action(k.rule(k.getNonTerminal())); 398 if ((act & BURS_StateCoder.LEFT_CHILD_FIRST) != 0) { 399 // rule selected forces order of evaluation 400 generateTree(child1, burs); 401 generateTree(child2, burs); 402 } else if ((act & BURS_StateCoder.RIGHT_CHILD_FIRST) != 0) { 403 // rule selected forces order of evaluation 404 generateTree(child2, burs); 405 generateTree(child1, burs); 406 } else if (child2.numRegisters() > child1.numRegisters()) { 407 generateTree(child2, burs); 408 generateTree(child1, burs); 409 } else { 410 generateTree(child1, burs); 411 generateTree(child2, burs); 412 } 413 } else { 414 if (child2.numRegisters() > child1.numRegisters()) { 415 generateTree(child2, burs); 416 generateTree(child1, burs); 417 } else { 418 generateTree(child1, burs); 419 generateTree(child2, burs); 420 } 421 } 422 } else { 423 generateTree(child1, burs); 424 } 425 } else if (child2 != null) { 426 generateTree(child2, burs); 427 } 428 429 if (k.isSuperNodeRoot()) { 430 int nonterminal = k.getNonTerminal(); 431 int rule = k.rule(nonterminal); 432 burs.code(k, nonterminal, rule); 433 if (DEBUG) VM.sysWrite(k + " " + debug(rule) + "\n"); 434 } 435 436 DepGraphNode dgnode = k.dg_node; 437 if (dgnode != null) { 438 SpaceEffGraphNode source = dgnode.nextSorted; 439 for (SpaceEffGraphEdge out = dgnode.firstOutEdge(); out != null; out = out.getNextOut()) { 440 SpaceEffGraphNode dest = out.toNode().nextSorted; 441 if (source != dest) { 442 castNode(dest).decPredecessorCount(); 443 int count = castNode(dest).getPredecessorCount(); 444 if (DEBUG) VM.sysWrite(count + ": edge " + source + " to " + dest + "\n"); 445 if (count == 0) { 446 readySetInsert(castNode(dest).getCurrentParent()); 447 } 448 } 449 } 450 } 451 } 452 453 /** 454 * Checks if the given node needs to be a tree rode. 455 * If the node does not need to be a tree root right now 456 * but might later have to be marked as a tree 457 * root, then include in a set of problem nodes. 458 * 459 * @param n the dep graph node in question. 460 * @return {@code true} if node n must be a root of a BURS tree 461 * based only on its register true dependencies. 462 */ 463 private boolean mustBeTreeRoot(DepGraphNode n) { 464 // A "fan-out" node must be a root of a BURS tree. 465 // (A fan-out node is a node with > 1 outgoing register-true dependences) 466 SpaceEffGraphEdge trueDepEdge = null; 467 for (SpaceEffGraphEdge out = n.firstOutEdge(); out != null; out = out.getNextOut()) { 468 if (DepGraphEdge.isRegTrue(out)) { 469 if (trueDepEdge != null) return true; 470 trueDepEdge = out; 471 } 472 } 473 474 if (trueDepEdge == null) { 475 return true; // 0 outgoing register-true dependencies 476 } else { 477 // Exactly 1 true edge, since we would have bailed out of above 478 // loop if we'd found a second one. 479 // If the node produces a register value that is live on exit 480 // from the basic block then it must be the root of a BURS tree. 481 Instruction instr = n.instruction(); 482 if (instr.operator() == IR_PROLOGUE) return true; 483 RegisterOperand rop = ResultCarrier.getResult(instr); 484 if (rop.getRegister().spansBasicBlock()) return true; 485 SpaceEffGraphNode parent = trueDepEdge.toNode(); 486 // If our parent has a superset of our 487 // other out edges (ignoring trueDepEdge) 488 // then we don't have to worry about creating cycles 489 // by not forcing n to be a tree root. 490 for (SpaceEffGraphEdge out = n.firstOutEdge(); out != null; out = out.getNextOut()) { 491 if (out != trueDepEdge) { 492 boolean match = false; 493 for (SpaceEffGraphEdge out2 = parent.firstOutEdge(); out2 != null; out2 = out2.getNextOut()) { 494 if (out2.toNode() == out.toNode()) { 495 match = true; 496 break; 497 } 498 } 499 if (!match) { 500 // could be trouble. Remember for later processing. 501 rememberAsProblemEdge(out); 502 } 503 } 504 } 505 return false; 506 } 507 } 508 509 // NOTE: assumes n has exactly 1 reg true parent (ie it is in 510 // an expression tree and is not the tree root). 511 @SuppressWarnings("unused") 512 private SpaceEffGraphNode regTrueParent(SpaceEffGraphNode n) { 513 for (SpaceEffGraphEdge out = n.firstOutEdge(); out != null; out = out.getNextOut()) { 514 if (DepGraphEdge.isRegTrue(out)) { 515 return out.toNode(); 516 } 517 } 518 if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED); 519 return null; 520 } 521 522 /** 523 * Initialize nextSorted for nodes in tree rooted at t i.e. 524 * for all register true descendants of t up to but not including 525 * any new tree roots. 526 * 527 * @param t the BURS node 528 * @param treeRoot the dependence graph node that belongs to the BURS node 529 */ 530 private void initTreeRootNode(AbstractBURS_TreeNode t, SpaceEffGraphNode treeRoot) { 531 // Recurse 532 if (t.getChild1() != null) { 533 if (t.getChild1().isTreeRoot()) { 534 t.setChild1(Register); 535 } else { 536 initTreeRootNode(t.getChild1(), treeRoot); 537 } 538 } 539 if (t.getChild2() != null) { 540 if (t.getChild2().isTreeRoot()) { 541 t.setChild2(Register); 542 } else { 543 initTreeRootNode(t.getChild2(), treeRoot); 544 } 545 } 546 if (t.dg_node != null) { 547 t.dg_node.nextSorted = treeRoot; 548 if (DEBUG) VM.sysWrite(t.dg_node + " --> " + treeRoot + "\n"); 549 } 550 if (t.getChild1() != null || t.getChild2() != null) { 551 // label t as in section 9.10 of the dragon book 552 int lchild = (t.getChild1() != null) ? t.getChild1().numRegisters() : 0; 553 int rchild = (t.getChild2() != null) ? t.getChild2().numRegisters() : 0; 554 if (lchild == rchild) { 555 t.setNumRegisters(lchild + 1); 556 } else { 557 t.setNumRegisters(Math.max(lchild, rchild)); 558 } 559 if (DEBUG) VM.sysWrite("\tnum registers = " + t.numRegisters() + "\n"); 560 } 561 } 562 563 /** 564 * Set of all tree roots. 565 */ 566 private AbstractBURS_TreeNode[] treeRoots = new AbstractBURS_TreeNode[32]; 567 568 private void makeTreeRoot(AbstractBURS_TreeNode n) { 569 if (numTreeRoots == treeRoots.length) { 570 AbstractBURS_TreeNode[] tmp = new AbstractBURS_TreeNode[treeRoots.length * 2]; 571 for (int i = 0; i < treeRoots.length; i++) { 572 tmp[i] = treeRoots[i]; 573 } 574 treeRoots = tmp; 575 } 576 n.setTreeRoot(); 577 treeRoots[numTreeRoots++] = n; 578 } 579 580 /** 581 * A priority queue of ready tree nodes. 582 * Used to keep track of the tree roots that are ready to be 583 * emitted during code generation (since all of their 584 * predecessors have been emitted already). 585 * readySetRemove returns the node that uses the maximum 586 * number of registers. This is a heuristic that tends to 587 * reduce register pressure and enable coalescing by the 588 * register allocator. (Goal is to end live ranges 'early'). 589 */ 590 private AbstractBURS_TreeNode[] heap = new AbstractBURS_TreeNode[16]; 591 private int numElements = 0; 592 593 private void readySetInsert(AbstractBURS_TreeNode node) { 594 Instruction s = node.getInstruction(); 595 if (s.operator() == GUARD_COMBINE || 596 s.operator() == GUARD_COND_MOVE || 597 s.operator() == GUARD_MOVE || 598 !ResultCarrier.conforms(s)) { 599 // Adjust numRegisters to bias away from picking trees that 600 // are rooted in result carriers, since they start a new live 601 // range. We don't count guard operations as result carriers, since 602 // guard operations get wiped out before register allocation anyways. 603 node.setNumRegisters(node.numRegisters() + 2); 604 } 605 606 numElements++; 607 if (numElements == heap.length) { 608 AbstractBURS_TreeNode[] tmp = new AbstractBURS_TreeNode[heap.length * 2]; 609 for (int i = 0; i < heap.length; i++) { 610 tmp[i] = heap[i]; 611 } 612 heap = tmp; 613 } 614 615 // restore heap property 616 int current = numElements; 617 heap[current] = node; 618 for (int parent = current / 2; current > 1 && heap[current].numRegisters() > heap[parent].numRegisters(); current = 619 parent, parent = current / 2) { 620 swap(current, parent); 621 } 622 } 623 624 private boolean readySetNotEmpty() { 625 return numElements > 0; 626 } 627 628 private AbstractBURS_TreeNode readySetRemove() { 629 AbstractBURS_TreeNode ans = heap[1]; 630 heap[1] = heap[numElements--]; 631 heapify(1); 632 return ans; 633 } 634 635 private void heapify(int p) { 636 int l = p * 2; 637 int r = l + 1; 638 int max = p; 639 if (l <= numElements && heap[l].numRegisters() > heap[max].numRegisters()) { 640 max = l; 641 } 642 if (r <= numElements && heap[r].numRegisters() > heap[max].numRegisters()) { 643 max = r; 644 } 645 if (max != p) { 646 swap(p, max); 647 heapify(max); 648 } 649 } 650 651 private void swap(int x, int y) { 652 AbstractBURS_TreeNode t = heap[x]; 653 heap[x] = heap[y]; 654 heap[y] = t; 655 } 656 657 void rememberAsProblemEdge(SpaceEffGraphEdge e) { 658 if (problemEdges == null) { 659 problemEdges = new SpaceEffGraphEdge[8]; 660 } 661 if (numProblemEdges == problemEdges.length) { 662 SpaceEffGraphEdge[] tmp = new SpaceEffGraphEdge[problemEdges.length * 2]; 663 for (int i = 0; i < problemEdges.length; i++) { 664 tmp[i] = problemEdges[i]; 665 } 666 problemEdges = tmp; 667 } 668 problemEdges[numProblemEdges++] = e; 669 } 670 671 private boolean haveProblemEdges() { 672 return numProblemEdges > 0; 673 } 674 675}