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.controlflow;
014
015import java.util.Enumeration;
016import java.util.HashMap;
017import java.util.Map;
018
019import org.jikesrvm.VM;
020import org.jikesrvm.compilers.opt.OperationNotImplementedException;
021import org.jikesrvm.compilers.opt.ir.BasicBlock;
022import org.jikesrvm.compilers.opt.ir.ControlFlowGraph;
023import org.jikesrvm.compilers.opt.ir.IR;
024import org.jikesrvm.compilers.opt.util.Stack;
025
026/**
027 * Calculate dominators using Langauer and Tarjan's fastest algorithm.
028 * TOPLAS 1(1), July 1979.  This implementation uses path compression and
029 * results in a O(e * alpha(e,n)) complexity, where e is the number of
030 * edges in the CFG and n is the number of nodes.
031 * <p>
032 * Sources: TOPLAS article, Muchnick book
033 * <p>
034 * The current implementation (4/25/00) does not include the EXIT node
035 * in any solution despite the fact that it is part of the CFG (it has
036 * incoming edges).  This is to be compatible with the old code.
037 */
038public class LTDominators extends Stack<BasicBlock> {
039  static final boolean DEBUG = false;
040
041  /**
042   * Indicates whether we perform the algorithm over the CFG or
043   *  the reverse CFG, i.e., whether we are computing dominators or
044   *  post-dominators.
045   */
046  private final boolean forward;
047
048  /**
049   * a counter for assigning DFS numbers
050   */
051  protected int DFSCounter;
052
053  /**
054   * a mapping from DFS number to their basic blocks
055   */
056  private BasicBlock[] vertex;
057
058  /**
059   * a convenient place to locate the cfg to avoid passing it internally
060   */
061  private final ControlFlowGraph cfg;
062
063  private Map<BasicBlock, LTDominatorInfo> ltDominators;
064
065  private final IR ir;
066
067  /**
068   * The constructor, called by the perform method
069   * @param ir the governing IR
070   * @param forward Should we compute regular dominators, or post-dominators?
071   */
072  LTDominators(IR ir, boolean forward) {
073    this.ir = ir;
074    cfg = ir.cfg;               // save the cfg for easy access
075    this.forward = forward;     // save the forward flag
076  }
077
078  /**
079   * The entry point for this phase
080   * @param ir the IR
081   * @param forward Should we compute regular dominators, or post-dominators?
082   * @param unfactor Should we unfactor the CFG?
083   */
084  public static void perform(IR ir, boolean forward, boolean unfactor) {
085    if (ir.hasReachableExceptionHandlers()) {
086      if (unfactor) {
087        ir.unfactor();
088      } else {
089        throw new OperationNotImplementedException("IR with exception handlers");
090      }
091    }
092    LTDominators dom = new LTDominators(ir, forward);
093    ir.setLtDominators(dom);
094    dom.analyze(ir);
095  }
096
097  /**
098   * Compute approximate dominator/post dominator without unfactoring
099   * exception handlers.  Can only be used if what the client wants is
100   * approximate domination (ie, if it doesn't actually have to be correct...)
101   * @param ir the IR
102   * @param forward Should we compute regular dominators, or post-dominators?
103   */
104  public static void approximate(IR ir, boolean forward) {
105    LTDominators dom = new LTDominators(ir, forward);
106    ir.setLtDominators(dom);
107    dom.analyze(ir);
108  }
109
110  protected void analyze(IR ir) {
111    if (DEBUG) {
112      System.out.println("   Here's the CFG for method: " + ir.method.getName() + "\n" + ir.cfg);
113    }
114
115    // Step 1: Perform a DFS numbering
116    step1();
117
118    // Check to make sure all nodes were reached
119    checkReachability(ir);
120
121    // Step 2: the heart of the algorithm
122    step2();
123
124    // Step 3: adjust immediate dominators of nodes whoe current version of
125    //    the immediate dominators differs from the nodes with the depth-first
126    //    number of the node's semidominator.
127    step3();
128
129    if (DEBUG) {
130      printResults(ir);
131    }
132  }
133
134  /**
135   * Checks that all nodes were reached.
136   *
137   * @param ir the governing IR
138   */
139  private void checkReachability(IR ir) {
140    if (!forward) {
141      if (DFSCounter != cfg.numberOfNodes()) {
142        VM.sysWrite(" *** Warning ***\n CFG for method " +
143                    ir.method.getName() +
144                    " in class " +
145                    ir.method.getDeclaringClass() +
146                    " has unreachable nodes.\n");
147        VM.sysWrite(" Assuming pessimistic results in dominators computation\n" + " for unreachable nodes.\n");
148      }
149    }
150  }
151
152  /**
153   *  The goal of this step is to perform a DFS numbering on the CFG,
154   *  starting at the root.  The exit node is not included.
155   */
156  private void step1() {
157    // allocate the vertex array, one element for each basic block, starting
158    // at 1
159    int size = cfg.numberOfNodes() + 1;
160    vertex = new BasicBlock[size];
161    DFSCounter = 0;
162    if (DEBUG) {
163      System.out.println("Initializing blocks:");
164    }
165
166    int noRehashCapacity = (int) (size * 1.4f);
167    ltDominators = new HashMap<BasicBlock, LTDominatorInfo>(noRehashCapacity);
168
169    // Initialize each block with an empty set of predecessors and
170    // a 0 for a semidominator
171    for (Enumeration<BasicBlock> bbEnum = cfg.basicBlocks(); bbEnum.hasMoreElements();) {
172      BasicBlock block = bbEnum.nextElement();
173      // We don't compute a result for the exit node in the forward direction
174      if (!forward || !block.isExit()) {
175        ltDominators.put(block, new LTDominatorInfo(block));
176        if (DEBUG) {
177          printNextNodes(block);
178        }
179      }
180    }
181
182    DFS();
183
184    if (DEBUG) {
185      System.out.println("DFSCounter: " + DFSCounter + ", CFG Nodes: " + cfg.numberOfNodes());
186      printDFSNumbers();
187    }
188  }
189
190  private void DFS() {
191    DFS(getFirstNode());
192  }
193
194  /**
195   * Get the first node, either entry or exit
196   * depending on which way we are viewing the graph
197   * @return the entry node or exit node
198   */
199  private BasicBlock getFirstNode() {
200    if (forward) {
201      return cfg.entry();
202    } else {
203      return cfg.exit();
204    }
205  }
206
207  /**
208   * Print the "next" nodes (either out or in) for the passed block
209   * depending on which way we are viewing the graph
210   * @param block the basic block of interest
211   */
212  private void printNextNodes(BasicBlock block) {
213    if (forward) {
214      System.out.print(block + " Succs:");
215    } else {
216      System.out.print(block + " Preds:");
217    }
218    Enumeration<BasicBlock> e = getNextNodes(block);
219    while (e.hasMoreElements()) {
220      System.out.print(' ');
221      System.out.print(e.nextElement());
222    }
223    System.out.println();
224  }
225
226  /**
227   * @param block the basic block of interest
228   * @return an enumeration of the "next" nodes (either out or in) for the
229   * passed block depending on which way we are viewing the graph
230   */
231  private Enumeration<BasicBlock> getNextNodes(BasicBlock block) {
232    Enumeration<BasicBlock> bbEnum;
233    if (forward) {
234      bbEnum = block.getOut();
235    } else {
236      bbEnum = block.getIn();
237    }
238    return bbEnum;
239  }
240
241  /**
242   * @param block the basic block of interest
243   * @return an enumeration of the "prev" nodes (either in or out) for the
244   * passed block depending on which way we are viewing the graph
245   */
246  private Enumeration<BasicBlock> getPrevNodes(BasicBlock block) {
247    Enumeration<BasicBlock> bbEnum;
248    if (forward) {
249      bbEnum = block.getIn();
250    } else {
251      bbEnum = block.getOut();
252    }
253    return bbEnum;
254  }
255
256  /**
257   * The non-recursive depth-first numbering code called from Step 1.
258   * The recursive version was too costly on the toba benchmark on Linux/IA32.
259   * @param block the basic block to process
260   */
261  protected void DFS(BasicBlock block) {
262
263    // push node on to the emulated activation stack
264    push(block);
265
266    recurse:
267    while (!empty()) {
268
269      block = peek();
270      if (DEBUG) {
271        System.out.println(" Processing (peek)" + block);
272      }
273
274      if (block == null) {
275        if (DEBUG) {
276          System.out.println(" Popping");
277        }
278        pop();   // return
279        continue;
280      }
281
282      // The current Dominance Frontier and SSA code assumes the exit
283      // node will not be part of the (regular) dominator solution.
284      // To avoid this from happening we screen it out here for forward CFG
285      //
286      // However, it really shouldn't be in the CFG, if it isn't a node!
287      if (forward && block == cfg.exit()) {
288        if (DEBUG) {
289          System.out.println(" Popping");
290        }
291        pop();   // return
292        continue;
293      }
294
295      Enumeration<BasicBlock> e;
296      e = LTDominatorInfo.getInfo(block, ir).getEnum();
297
298      if (e == null) {
299        if (DEBUG) {
300          System.out.println(" Initial processing of " + block);
301        }
302
303        DFSCounter++;
304        LTDominatorInfo.getInfo(block, ir).setSemiDominator(DFSCounter);
305        vertex[DFSCounter] = block;
306        e = getNextNodes(block);
307      } else {
308        if (DEBUG) {
309          System.out.println(" Resuming processing of " + block);
310        }
311      }
312
313      while (e.hasMoreElements()) {
314        BasicBlock next = e.nextElement();
315
316        if (DEBUG) {
317          System.out.println("    Inspecting next node: " + next);
318        }
319
320        // We treat the exit node as not being in the CFG for forward direction
321        if (forward && next.isExit()) {
322          continue;  // inner loop
323        }
324        if (getSemi(next) == 0) {
325          LTDominatorInfo.getInfo(next, ir).setParent(block);
326
327          // simulate a recursive call
328          // save the enumeration state for resumption later
329          LTDominatorInfo.getInfo(block, ir).setEnum(e);
330
331          if (DEBUG) {
332            System.out.println(" Pushing" + next);
333          }
334          push(next);
335          continue recurse;
336        }
337      }           // while more nexts
338      // "Pop" from the emulated activiation stack
339      if (DEBUG) {
340        System.out.println(" Popping");
341      }
342      pop();
343    }  // while stack not empty loop
344  }
345
346  /**
347   *  This is the heart of the algorithm.  See sources for details.
348   */
349  private void step2() {
350    if (DEBUG) {
351      System.out.println(" ******* Beginning STEP 2 *******\n");
352    }
353
354    // Visit each node in reverse DFS order, except for the root, which
355    // has number 1
356    // for i=n downto 2
357    for (int i = DFSCounter; i > 1; i--) {
358      // block = vertex[i]
359      BasicBlock block = vertex[i];
360      LTDominatorInfo blockInfo = LTDominatorInfo.getInfo(block, ir);
361
362      if (DEBUG) {
363        System.out.println(" Processing: " + block + "\n");
364      }
365
366      // visit each predecessor
367      Enumeration<BasicBlock> e = getPrevNodes(block);
368      while (e.hasMoreElements()) {
369        BasicBlock prev = e.nextElement();
370        if (DEBUG) {
371          System.out.println("    Inspecting prev: " + prev);
372        }
373        BasicBlock u = EVAL(prev);
374        // if semi(u) < semi(block) then semi(block) = semi(u)
375        // u may be part of infinite loop and thus, is unreachable from the exit node.
376        // In this case, it will have a semi value of 0.  Thus, we screen for it here
377        if (getSemi(u) != 0 && getSemi(u) < getSemi(block)) {
378          blockInfo.setSemiDominator(getSemi(u));
379        }
380      }  // while prev
381
382      // add "block" to bucket(vertex(semi(block)));
383      LTDominatorInfo.getInfo(vertex[blockInfo.getSemiDominator()], ir).
384          addToBucket(block);
385
386      // LINK(parent(block), block)
387      LINK(blockInfo.getParent(), block);
388
389      // foreach block2 in bucket(parent(block)) do
390      java.util.Iterator<BasicBlock> bucketEnum = LTDominatorInfo.getInfo(getParent(block), ir).getBucketIterator();
391      while (bucketEnum.hasNext()) {
392        BasicBlock block2 = bucketEnum.next();
393
394        // u = EVAL(block2)
395        BasicBlock u = EVAL(block2);
396
397        // if semi(u) < semi(block2) then
398        //    dom(block2) = u
399        // else
400        //    dom(block2) = parent(block)
401        if (getSemi(u) < getSemi(block2)) {
402          LTDominatorInfo.getInfo(block2, ir).setDominator(u);
403        } else {
404          LTDominatorInfo.getInfo(block2, ir).setDominator(getParent(block));
405        }
406      }         // while bucket has more elements
407    }           // for DFSCounter .. 1
408  }             // method
409
410  /**
411   * This method inspects the passed block and returns the following:
412   * <ul>
413   *   <li>block, if block is a root of a tree in the forest
414   *   <li>any vertex, u != r such that r is the root of the tree
415   *       containing block and semi(u) is minimum on the path  r -&gt; v,
416   *       otherwise
417   * </ul>
418   * <p>
419   *
420   * See TOPLAS 1(1), July 1979, p 128 for details.
421   *
422   * @param block the block to evaluate
423   * @return the block as described above
424   */
425  private BasicBlock EVAL(BasicBlock block) {
426    if (DEBUG) {
427      System.out.println("  Evaling " + block);
428    }
429    if (getAncestor(block) == null) {
430      return getLabel(block);
431    } else {
432      compress(block);
433      if (getSemi(getLabel(getAncestor(block))) >= getSemi(getLabel(block))) {
434        return getLabel(block);
435      } else {
436        return getLabel(getAncestor(block));
437      }
438    }
439  }
440
441  /**
442   *  This recursive method performs the path compression
443   *  @param block the block of interest
444   */
445  private void compress(BasicBlock block) {
446    if (getAncestor(getAncestor(block)) != null) {
447      compress(getAncestor(block));
448      LTDominatorInfo blockInfo = LTDominatorInfo.getInfo(block, ir);
449      if (getSemi(getLabel(getAncestor(block))) < getSemi(getLabel(block))) {
450        blockInfo.setLabel(getLabel(getAncestor(block)));
451      }
452      blockInfo.setAncestor(getAncestor(getAncestor(block)));
453    }
454  }
455
456  /**
457   *  Adds edge (block1, block2) to the forest maintained as an auxiliary
458   *  data structure.  This implementation uses path compression and
459   *  results in a O(e * alpha(e,n)) complexity, where e is the number of
460   *  edges in the CFG and n is the number of nodes.
461   *
462   *  @param block1 a basic block corresponding to the source of the new edge
463   *  @param block2 a basic block corresponding to the source of the new edge
464   */
465  private void LINK(BasicBlock block1, BasicBlock block2) {
466    if (DEBUG) {
467      System.out.println("  Linking " + block1 + " with " + block2);
468    }
469    BasicBlock s = block2;
470    while (getSemi(getLabel(block2)) < getSemi(getLabel(getChild(s)))) {
471      if (getSize(s) + getSize(getChild(getChild(s))) >= 2 * getSize(getChild(s))) {
472        LTDominatorInfo.getInfo(getChild(s), ir).setAncestor(s);
473        LTDominatorInfo.getInfo(s, ir).setChild(getChild(getChild(s)));
474      } else {
475        LTDominatorInfo.getInfo(getChild(s), ir).setSize(getSize(s));
476        LTDominatorInfo.getInfo(s, ir).setAncestor(getChild(s));
477        s = getChild(s);
478      }
479    }
480    LTDominatorInfo.getInfo(s, ir).setLabel(getLabel(block2));
481    LTDominatorInfo.getInfo(block1, ir).setSize(getSize(block1) + getSize(block2));
482    if (getSize(block1) < 2 * getSize(block2)) {
483      BasicBlock tmp = s;
484      s = getChild(block1);
485      LTDominatorInfo.getInfo(block1, ir).setChild(tmp);
486    }
487    while (s != null) {
488      LTDominatorInfo.getInfo(s, ir).setAncestor(block1);
489      s = getChild(s);
490    }
491    if (DEBUG) {
492      System.out.println("  .... done");
493    }
494  }
495
496  /**
497   *  This final step sets the final dominator information.
498   */
499  private void step3() {
500    // Visit each node in DFS order, except for the root, which has number 1
501    for (int i = 2; i <= DFSCounter; i++) {
502      BasicBlock block = vertex[i];
503      // if dom(block) != vertex[semi(block)]
504      if (getDom(block) != vertex[getSemi(block)]) {
505        // dom(block) = dom(dom(block))
506        LTDominatorInfo.getInfo(block, ir).setDominator(getDom(getDom(block)));
507      }
508    }
509  }
510
511  //
512  // The following methods are simple helper methods to increase the
513  // readability of the code.
514  //
515
516  /**
517   * @param block the block whose dominator is of interest
518   * @return the dominator for the passed block
519   */
520  private BasicBlock getDom(BasicBlock block) {
521    return LTDominatorInfo.getInfo(block, ir).getDominator();
522  }
523
524  /**
525   * @param block the block whose parent is of interest
526   * @return the parent for the passed block
527   */
528  private BasicBlock getParent(BasicBlock block) {
529    return LTDominatorInfo.getInfo(block, ir).getParent();
530  }
531
532  /**
533   * @param block the block whose ancestor is of interest
534   * @return the ancestor for the passed block
535   */
536  private BasicBlock getAncestor(BasicBlock block) {
537    return LTDominatorInfo.getInfo(block, ir).getAncestor();
538  }
539
540  /**
541   * @param block the block whose label is of interest
542   * @return the label for the passed block or {@code null} if the block is
543   *  {@code null}
544   */
545  private BasicBlock getLabel(BasicBlock block) {
546    if (block == null) {
547      return null;
548    }
549    return LTDominatorInfo.getInfo(block, ir).getLabel();
550  }
551
552  /**
553   * @param block the block whose semidominator is of interest
554   * @return the semidominator for the passed block
555   */
556  private int getSemi(BasicBlock block) {
557    if (block == null) {
558      return 0;
559    }
560    return LTDominatorInfo.getInfo(block, ir).getSemiDominator();
561  }
562
563  /**
564   * @param block block the block whose size is of interest
565   * @return the size of the block or 0 if the block is {@code null}
566   */
567  private int getSize(BasicBlock block) {
568    if (block == null) {
569      return 0;
570    }
571    return LTDominatorInfo.getInfo(block, ir).getSize();
572  }
573
574  /**
575   * @param block the block whose child is of interest
576   * @return the child node
577   */
578  private BasicBlock getChild(BasicBlock block) {
579    return LTDominatorInfo.getInfo(block, ir).getChild();
580  }
581
582  /**
583   * Print the nodes that dominate each basic block
584   * @param ir the IR
585   */
586  private void printResults(IR ir) {
587    if (forward) {
588      System.out.println("Results of dominators computation for method " + ir.method.getName() + "\n");
589      System.out.println("   Here's the CFG:");
590      System.out.println(ir.cfg);
591      System.out.println("\n\n  Here's the Dominator Info:");
592    } else {
593      System.out.println("Results of Post-Dominators computation for method " + ir.method.getName() + "\n");
594      System.out.println("   Here's the CFG:");
595      System.out.println(ir.cfg);
596      System.out.println("\n\n  Here's the Post-Dominator Info:");
597    }
598
599    for (Enumeration<BasicBlock> bbEnum = cfg.basicBlocks(); bbEnum.hasMoreElements();) {
600      BasicBlock block = bbEnum.nextElement();
601      // We don't compute a result for the exit node for forward direction
602      if (!forward || !block.isExit()) {
603        System.out.println("Dominators of " + block + ":" + LTDominatorInfo.getInfo(block, ir).dominators(block, ir));
604      }
605    }
606    System.out.println('\n');
607  }
608
609  /**
610   *  Print the result of the DFS numbering performed in Step 1
611   */
612  private void printDFSNumbers() {
613    for (Enumeration<BasicBlock> bbEnum = cfg.basicBlocks(); bbEnum.hasMoreElements();) {
614      BasicBlock block = bbEnum.nextElement();
615      // We don't compute a result for the exit node for forward direction
616      if (forward && block.isExit()) {
617        continue;
618      }
619      LTDominatorInfo info = ir.getLtDominators().getInfo(block);
620      System.out.println(" " + block + " " + info);
621    }
622    // Visit each node in reverse DFS order, except for the root, which
623    // has number 1
624    for (int i = 1; i <= DFSCounter; i++) {
625      System.out.println(" Vertex: " + i + " " + vertex[i]);
626    }
627  }
628
629  LTDominatorInfo getInfo(BasicBlock bb) {
630    return ltDominators.get(bb);
631  }
632
633}