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}