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.ir;
014
015import java.util.Enumeration;
016
017import org.jikesrvm.VM;
018import org.jikesrvm.compilers.opt.util.SortedGraphNode;
019import org.jikesrvm.compilers.opt.util.SpaceEffGraph;
020import org.jikesrvm.compilers.opt.util.SpaceEffGraphNode;
021
022/**
023 * The Factored Control Flow Graph (FCFG).
024 * <p>
025 * Like a standard control flow graph (CFG), the FCFG is composed
026 * of {@link BasicBlock basic blocks} which in turn contain
027 * {@link Instruction instructions}. The critical difference between
028 * a FCFG and a CFG is in the definition of basic blocks.  In the FCFG,
029 * a Potentially Excepting Instruction (PEI) does not necessarily end its
030 * basic block.  Therefore, although instructions within a FCFG basic block
031 * have the expected dominance relationships, they do <em>not</em> have the
032 * same post-dominance relationships as they would under the traditional
033 * basic block formulation used in a CFG.
034 * We chose to use an FCFG because doing so significantly reduces the
035 * number of basic blocks and control flow graph edges, thus reducing
036 * the time and space costs of representing the FCFG and also
037 * increasing the effectiveness of local (within a single basic block)
038 * analysis.  However, using an FCFG does complicate flow-sensitive
039 * global analaysis.  Many analyses can be easily extended to
040 * work on the FCFG.  For those analyses that cannot, we provide utilities
041 * ({@link IR#unfactor()}, {@link BasicBlock#unfactor(IR)})
042 * to effectively convert the FCFG into a CFG.
043 * For a more detailed description of the FCFG and its implications for
044 * program analysis see the PASTE'99 paper by Choi et al.
045 *   <a href="http://www.research.ibm.com/jalapeno/publication.html#paste99">
046 *   Efficient and Precise Modeling of Exceptions for the Analysis of Java Programs </a>
047 * <p>
048 * The nodes in the FCFG are components in two distinct
049 * orderings, the "main" one is the control flow relationship
050 * in which edges represent flow of control.
051 * The secondary ordering is a linearization of the blocks
052 * which represents the ordering of instructions in the generated code.
053 * Both of these relationships are represented using the fields inherited
054 * from {@link SpaceEffGraphNode}.
055 * The control flow edges are the primary relationship and are encoded by
056 * <code>In</code> and <code>Out</code> relations of
057 * {@link SpaceEffGraphNode} and the {@link #entry()} and {@link #exit()}
058 * functions of <code>ControlFlowGraph</code>.
059 * The linear order is secondary and is represented by the order of the
060 * nodes in the doubly linked list ({@link SpaceEffGraphNode#next} and
061 * {@link SpaceEffGraphNode#prev}) and the functions
062 * ({@link #firstInCodeOrder()}, {@link #lastInCodeOrder()})
063 * of <code>ControlFlowGraph</code>.
064 * Utility functions are provided here and in {@link SpaceEffGraphNode}
065 * to manipulate these orderings.
066 * <p>
067 * Note: Clients that add or remove nodes must call {@link #compactNodeNumbering()}
068 * after they are done with the modifications to ensure that subsequent compiler phases
069 * can use the node numbering to index lookaside data structures for basic blocks.
070 *
071 * @see BasicBlock
072 * @see IR
073 */
074public final class ControlFlowGraph extends SpaceEffGraph {
075
076  /**
077   * The distinguished exit node of the FCFG
078   */
079  private final BasicBlock _exitNode;
080
081  /**
082   * Return the entry node of the FCFG.  All reachable nodes
083   * can be found by doing a forward traversal from this node.
084   *
085   * @return the entry node of the FCFG
086   */
087  public BasicBlock entry() {
088    return (BasicBlock) _firstNode;
089  }
090
091  /**
092   * Return the "exit" node of the FCFG.  In a perfect world,
093   * we'd have the invariant that all nodes that are reachable in a
094   * forward traversal from cfgEntry() are exactly the same set of nodes
095   * as those that are reachable from cfgExit() via a reverse traversal,
096   * but that's currently not the case.  Not all forward reachable nodes can
097   * be found by going backwards from exit.  The issue is infinite loops
098   * (loops without normal exits).
099   *
100   * @return the exit node of the FCFG
101   */
102  public BasicBlock exit() {
103    return _exitNode;
104  }
105
106  /**
107   * Return the first basic block with respect to
108   * the current code linearization order.
109   *
110   * @return the first basic block in the code order
111   */
112  public BasicBlock firstInCodeOrder() {
113    return (BasicBlock) _firstNode;
114  }
115
116  /**
117   * Return the last basic block with respect to
118   * the current code linearization order.
119   *
120   * @return the last basic block in the code order
121   */
122  public BasicBlock lastInCodeOrder() {
123    return (BasicBlock) _lastNode;
124  }
125
126  /**
127   * Return the node to start with for a topological traversal
128   * of the FCFG.
129   * Override {@link SpaceEffGraph#startNode(boolean)}
130   * to use entry and exit; we want topological traversals to be with
131   * respect to FCFG edges not the code linearization order
132   *
133   * @param forward  {@code true} for forward traversal, {@code false} for reverse
134   * @return the node to use as the start of a topological traversal
135   */
136  @Override
137  public SortedGraphNode startNode(boolean forward) {
138    if (forward) {
139      return entry();
140    } else {
141      return exit();
142    }
143  }
144
145  /**
146   * Densely numbers (0...n) all nodes in the FCFG.
147   * <p>
148   * Note: clients must call this method after they are done with adding
149   * or removing nodes. This allows subsequent phases to save additional
150   * information about BasicBlocks in arrays by using the node number
151   * as index.
152   * <p>
153   * This method overrides {@link SpaceEffGraph#compactNodeNumbering()} to also
154   * number the exit node.
155   */
156  @Override
157  public void compactNodeNumbering() {
158    super.compactNodeNumbering();
159    exit().setNumber(numberOfNodes++);
160  }
161
162  /**
163   * Builds the reverse topological order, i.e., the topsort order on the
164   * reverse graph.  (This is not the same as reversing the topsort order
165   * of the forward graph.)
166   *
167   * @return the first node in the reverse topological ordering
168   */
169  @Override
170  public SortedGraphNode buildRevTopSort() {
171    SortedGraphNode firstNode = super.buildRevTopSort();
172    if (firstNode != null) {
173
174      // The CFG may have "end" nodes that are not reachable
175      // by all nodes.  For example, a program with an infinite loop will not
176      // have a path from the loop to the exit node.  Such nodes will not
177      // be in the reverseTopSort, but will be of interest.  Thus, we now
178      // look for such nodes and add them to the revTopSort.
179
180      // We do this by visiting each basic block and checking to ensure
181      // that is marked with the sortMarker, if not we simply give it a
182      // number.
183
184      int sortMarker = firstNode.getSortMarker();
185      int sortNumber = firstNode.getBackwardSortNumber() - 1;
186      for (BasicBlock block = firstInCodeOrder(); block != null; block = block.nextBasicBlockInCodeOrder()) {
187
188        if (block.getSortMarker() != sortMarker) {
189          // found a block that wasn't on the Reverse Top List, add it.
190          // It is not clear where it should go, so since it is convenient
191          // to add at the front, we add it at the front!
192          block.setSortMarker(sortMarker);
193          block.setBackwardSortNumber(sortNumber--);
194
195          // put block at the beginning of the list
196          block.setSortedNext(firstNode, false);
197          firstNode = block;
198        }
199      }
200    }
201    return firstNode;
202  }
203
204  /**
205   * @param number starting value for assigning node numbers
206   */
207  public ControlFlowGraph(int number) {
208    _exitNode = BasicBlock.makeExit();
209    numberOfNodes = number;
210  }
211
212  /**
213   * Add an FCFG edge from the given basic block to the exit node.
214   *
215   * @param bb basic block to link to the exit
216   */
217  public void linkToExit(BasicBlock bb) {
218    bb.insertOut(exit());
219  }
220
221  /**
222   * Remove a basic block from both the CFG and code ordering
223   *
224   * @param bb the block to remove
225   */
226  public void removeFromCFGAndCodeOrder(BasicBlock bb) {
227    removeFromCFG(bb);
228    removeFromCodeOrder(bb);
229  }
230
231  /**
232   * Remove a basic block from the FCFG, leaving the code ordering unchanged.
233   *
234   * @param bb the block to remove
235   */
236  public void removeFromCFG(BasicBlock bb) {
237    bb.deleteIn();
238    bb.deleteOut();
239  }
240
241  /**
242   * Remove a basic block from the code ordering,
243   * leaving the FCFG unchanged.
244   *
245   * @param bb the block to remove
246   */
247  public void removeFromCodeOrder(BasicBlock bb) {
248    if (bb == _firstNode) {
249      _firstNode = bb.getNext();
250    }
251    if (bb == _lastNode) {
252      _lastNode = bb.getPrev();
253    }
254    bb.remove();
255  }
256
257  /**
258   * Insert a block 'toAdd' not currently in the code ordering after
259   * a block 'old' that is currently in the code ordering.
260   * If necessary, _lastNode is updated.
261   * No impact on FCFG edges.
262   *
263   * @param old a block currently in the code ordering
264   * @param toAdd a block to add after old in the code ordering
265   */
266  public void insertAfterInCodeOrder(BasicBlock old, BasicBlock toAdd) {
267    if (IR.SANITY_CHECK) VM._assert(toAdd.next == null);
268    if (IR.SANITY_CHECK) VM._assert(toAdd.prev == null);
269    SpaceEffGraphNode oldNext = old.next;
270    if (oldNext == null) {
271      if (IR.SANITY_CHECK) VM._assert(_lastNode == old);
272      old.append(toAdd);
273      _lastNode = toAdd;
274    } else {
275      old.append(toAdd);
276      toAdd.append(oldNext);
277    }
278  }
279
280  /**
281   * Insert a block 'toAdd' not currently in the code ordering before
282   * a block 'old' that is currently in the code ordering.
283   * If necessary, _firstNode is updated.
284   * No impact on FCFG edges.
285   *
286   * @param old a block currently in the code ordering
287   * @param toAdd a block to add before old in the code ordering
288   */
289  public void insertBeforeInCodeOrder(BasicBlock old, BasicBlock toAdd) {
290    if (IR.SANITY_CHECK) VM._assert(toAdd.next == null);
291    if (IR.SANITY_CHECK) VM._assert(toAdd.prev == null);
292    SpaceEffGraphNode oldPrev = old.prev;
293    if (oldPrev == null) {
294      if (IR.SANITY_CHECK) VM._assert(_firstNode == old);
295      _firstNode = toAdd;
296      toAdd.append(old);
297    } else {
298      oldPrev.append(toAdd);
299      toAdd.append(old);
300    }
301  }
302
303  /**
304   * Add a block not currently in the code ordering to the end of the
305   * code ordering.
306   * No impact on FCFG edges.
307   *
308   * @param bb the block to add to the end of the code ordering
309   */
310  public void addLastInCodeOrder(BasicBlock bb) {
311    if (IR.SANITY_CHECK) VM._assert(bb.next == null);
312    if (IR.SANITY_CHECK) VM._assert(bb.prev == null);
313    if (_firstNode == null) {
314      _firstNode = bb;
315      _lastNode = bb;
316    } else {
317      _lastNode.append(bb);
318      _lastNode = bb;
319    }
320  }
321
322  /**
323   * Make BB2 follow BB1 in the code ordering.
324   * If _lastNode == BB1, then update _lastNode appropriately
325   * No impact on FCFG edges.
326   *
327   * @param bb1 a basic block
328   * @param bb2 the basic block to follow bb1 in the code ordering
329   */
330  public void linkInCodeOrder(BasicBlock bb1, BasicBlock bb2) {
331    if (IR.SANITY_CHECK) VM._assert(bb1.next == null);
332    if (IR.SANITY_CHECK) VM._assert(bb2.prev == null);
333    bb1.append(bb2);
334    if (bb1 == _lastNode) {
335      _lastNode = bb2;
336    }
337  }
338
339  /**
340   * Create a break in the code order between bb1 and bb2
341   * (bb1 and bb2 must be currently adjacent in the code order).
342   * No impact on FCFG edges.
343   *
344   * @param bb1 the first block
345   * @param bb2 the second block
346   */
347  public void breakCodeOrder(BasicBlock bb1, BasicBlock bb2) {
348    if (IR.SANITY_CHECK) VM._assert(bb1.next == bb2);
349    if (IR.SANITY_CHECK) VM._assert(bb2.prev == bb1);
350    bb1.next = null;
351    bb2.prev = null;
352  }
353
354  /**
355   * Clear the code ordering information for the CFG.<p>
356   * NOTE: This method should only be called as part of a
357   *       whole scale recomputation of the code order, for example
358   *       by ReorderingPhase
359   */
360  public void clearCodeOrder() {
361    SpaceEffGraphNode cur = _firstNode;
362    if (cur == null) return;
363    while (true) {
364      SpaceEffGraphNode next = cur.next;
365      if (next == null) break;
366      cur.next = null;
367      next.prev = null;
368      cur = next;
369    }
370    _firstNode = null;
371    _lastNode = null;
372  }
373
374  // Enumerate the nodes in the CFG, casting them to whatever concrete type
375  // the caller wants.
376  private static final class NodeEnumeration<T> implements Enumeration<T> {
377    private SpaceEffGraphNode _node;
378    private final SpaceEffGraphNode _end;
379
380    NodeEnumeration(ControlFlowGraph cfg) {
381      _node = cfg.entry();
382      _end = cfg.exit();
383    }
384
385    @Override
386    public boolean hasMoreElements() {
387      return _node != null;
388    }
389
390    @Override
391    @SuppressWarnings("unchecked")
392    // We cast to whatever the concrete type of the graph is
393    public T nextElement() {
394      SpaceEffGraphNode n = _node;
395      _node = n.getNext();
396      if ((n != _end) && (_node == null)) {
397        _node = _end;
398      }
399      return (T) n;
400    }
401  }
402
403  public Enumeration<BasicBlock> basicBlocks() {
404    return new NodeEnumeration<BasicBlock>(this);
405  }
406}