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