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.ir;
014    
015    import java.util.Enumeration;
016    
017    import org.jikesrvm.VM;
018    import org.jikesrvm.compilers.opt.util.SortedGraphNode;
019    import org.jikesrvm.compilers.opt.util.SpaceEffGraph;
020    import 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     *
067     * @see BasicBlock
068     * @see IR
069     */
070    public final class ControlFlowGraph extends SpaceEffGraph {
071    
072      /**
073       * The distinguished exit node of the FCFG
074       */
075      private final BasicBlock _exitNode;
076    
077      /**
078       * Return the entry node of the FCFG.  All reachable nodes
079       * can be found by doing a forward traversal from this node.
080       *
081       * @return the entry node of the FCFG
082       */
083      public BasicBlock entry() {
084        return (BasicBlock) _firstNode;
085      }
086    
087      /**
088       * Return the "exit" node of the FCFG.  In a perfect world,
089       * we'd have the invariant that all nodes that are reachable in a
090       * forward traversal from cfgEntry() are exactly the same set of nodes
091       * as those that are reachable from cfgExit() via a reverse traversal,
092       * but that's currently not the case.  Not all forward reachable nodes can
093       * be found by going backwards from exit.  The issue is infinite loops
094       * (loops without normal exits).
095       *
096       * @return the exit node of the FCFG
097       */
098      public BasicBlock exit() {
099        return _exitNode;
100      }
101    
102      /**
103       * Return the first basic block with respect to
104       * the current code linearization order.
105       *
106       * @return the first basic block in the code order
107       */
108      public BasicBlock firstInCodeOrder() {
109        return (BasicBlock) _firstNode;
110      }
111    
112      /**
113       * Return the last basic block with respect to
114       * the current code linearization order.
115       *
116       * @return the last basic block in the code order
117       */
118      public BasicBlock lastInCodeOrder() {
119        return (BasicBlock) _lastNode;
120      }
121    
122      /**
123       * Return the node to start with for a topological traversal
124       * of the FCFG.
125       * Override {@link SpaceEffGraph#startNode(boolean)}
126       * to use entry and exit; we want topological traversals to be with
127       * respect to FCFG edges not the code linearization order
128       *
129       * @param forward  {@code true} for forward traversal, {@code false} for reverse
130       * @return the node to use as the start of a topological traversal
131       */
132      @Override
133      public SortedGraphNode startNode(boolean forward) {
134        if (forward) {
135          return entry();
136        } else {
137          return exit();
138        }
139      }
140    
141      /**
142       * Densely number (0...n) all nodes in the FCFG.
143       * Override {@link SpaceEffGraph#compactNodeNumbering()} to also
144       * number the exit node.
145       */
146      @Override
147      public void compactNodeNumbering() {
148        super.compactNodeNumbering();
149        exit().setNumber(numberOfNodes++);
150      }
151    
152      /**
153       * Builds the reverse topological order, i.e., the topsort order on the
154       * reverse graph.  (This is not the same as reversing the topsort order
155       * of the forward graph.)
156       *
157       * @return the first node in the reverse topological ordering
158       */
159      @Override
160      public SortedGraphNode buildRevTopSort() {
161        SortedGraphNode firstNode = super.buildRevTopSort();
162        if (firstNode != null) {
163    
164          // The CFG may have "end" nodes that are not reachable
165          // by all nodes.  For example, a program with an infinite loop will not
166          // have a path from the loop to the exit node.  Such nodes will not
167          // be in the reverseTopSort, but will be of interest.  Thus, we now
168          // look for such nodes and add them to the revTopSort.
169    
170          // We do this by visiting each basic block and checking to ensure
171          // that is marked with the sortMarker, if not we simply give it a
172          // number.
173    
174          int sortMarker = firstNode.getSortMarker();
175          int sortNumber = firstNode.getBackwardSortNumber() - 1;
176          for (BasicBlock block = firstInCodeOrder(); block != null; block = block.nextBasicBlockInCodeOrder()) {
177    
178            if (block.getSortMarker() != sortMarker) {
179              // found a block that wasn't on the Reverse Top List, add it.
180              // It is not clear where it should go, so since it is convenient
181              // to add at the front, we add it at the front!
182              block.setSortMarker(sortMarker);
183              block.setBackwardSortNumber(sortNumber--);
184    
185              // put block at the beginning of the list
186              block.setSortedNext(firstNode, false);
187              firstNode = block;
188            }
189          }
190        }
191        return firstNode;
192      }
193    
194      /**
195       * @param number starting value for assigning node numbers
196       */
197      public ControlFlowGraph(int number) {
198        _exitNode = BasicBlock.makeExit();
199        numberOfNodes = number;
200      }
201    
202      /**
203       * Add an FCFG edge from the given basic block to the exit node.
204       *
205       * @param bb basic block to link to the exit
206       */
207      public void linkToExit(BasicBlock bb) {
208        bb.insertOut(exit());
209      }
210    
211      /**
212       * Remove a basic block from both the CFG and code ordering
213       *
214       * @param bb the block to remove
215       */
216      public void removeFromCFGAndCodeOrder(BasicBlock bb) {
217        removeFromCFG(bb);
218        removeFromCodeOrder(bb);
219      }
220    
221      /**
222       * Remove a basic block from the FCFG, leaving the code ordering unchanged.
223       *
224       * @param bb the block to remove
225       */
226      public void removeFromCFG(BasicBlock bb) {
227        bb.deleteIn();
228        bb.deleteOut();
229      }
230    
231      /**
232       * Remove a basic block from the code ordering,
233       * leaving the FCFG unchanged.
234       *
235       * @param bb the block to remove
236       */
237      public void removeFromCodeOrder(BasicBlock bb) {
238        if (bb == _firstNode) {
239          _firstNode = bb.getNext();
240        }
241        if (bb == _lastNode) {
242          _lastNode = bb.getPrev();
243        }
244        bb.remove();
245      }
246    
247      /**
248       * Insert a block 'toAdd' not currently in the code ordering after
249       * a block 'old' that is currently in the code ordering.
250       * If necessary, _lastNode is updated.
251       * No impact on FCFG edges.
252       *
253       * @param old a block currently in the code ordering
254       * @param toAdd a block to add after old in the code ordering
255       */
256      public void insertAfterInCodeOrder(BasicBlock old, BasicBlock toAdd) {
257        if (IR.SANITY_CHECK) VM._assert(toAdd.next == null);
258        if (IR.SANITY_CHECK) VM._assert(toAdd.prev == null);
259        SpaceEffGraphNode oldNext = old.next;
260        if (oldNext == null) {
261          if (IR.SANITY_CHECK) VM._assert(_lastNode == old);
262          old.append(toAdd);
263          _lastNode = toAdd;
264        } else {
265          old.append(toAdd);
266          toAdd.append(oldNext);
267        }
268      }
269    
270      /**
271       * Insert a block 'toAdd' not currently in the code ordering before
272       * a block 'old' that is currently in the code ordering.
273       * If necessary, _firstNode is updated.
274       * No impact on FCFG edges.
275       *
276       * @param old a block currently in the code ordering
277       * @param toAdd a block to add before old in the code ordering
278       */
279      public void insertBeforeInCodeOrder(BasicBlock old, BasicBlock toAdd) {
280        if (IR.SANITY_CHECK) VM._assert(toAdd.next == null);
281        if (IR.SANITY_CHECK) VM._assert(toAdd.prev == null);
282        SpaceEffGraphNode oldPrev = old.prev;
283        if (oldPrev == null) {
284          if (IR.SANITY_CHECK) VM._assert(_firstNode == old);
285          _firstNode = toAdd;
286          toAdd.append(old);
287        } else {
288          oldPrev.append(toAdd);
289          toAdd.append(old);
290        }
291      }
292    
293      /**
294       * Add a block not currently in the code ordering to the end of the
295       * code ordering.
296       * No impact on FCFG edges.
297       *
298       * @param bb the block to add to the end of the code ordering
299       */
300      public void addLastInCodeOrder(BasicBlock bb) {
301        if (IR.SANITY_CHECK) VM._assert(bb.next == null);
302        if (IR.SANITY_CHECK) VM._assert(bb.prev == null);
303        if (_firstNode == null) {
304          _firstNode = bb;
305          _lastNode = bb;
306        } else {
307          _lastNode.append(bb);
308          _lastNode = bb;
309        }
310      }
311    
312      /**
313       * Make BB2 follow BB1 in the code ordering.
314       * If _lastNode == BB1, then update _lastNode appropriately
315       * No impact on FCFG edges.
316       *
317       * @param bb1 a basic block
318       * @param bb2 the basic block to follow bb1 in the code ordering
319       */
320      public void linkInCodeOrder(BasicBlock bb1, BasicBlock bb2) {
321        if (IR.SANITY_CHECK) VM._assert(bb1.next == null);
322        if (IR.SANITY_CHECK) VM._assert(bb2.prev == null);
323        bb1.append(bb2);
324        if (bb1 == _lastNode) {
325          _lastNode = bb2;
326        }
327      }
328    
329      /**
330       * Create a break in the code order between bb1 and bb2
331       * (bb1 and bb2 must be currently adjacent in the code order).
332       * No impact on FCFG edges.
333       *
334       * @param bb1 the first block
335       * @param bb2 the second block
336       */
337      public void breakCodeOrder(BasicBlock bb1, BasicBlock bb2) {
338        if (IR.SANITY_CHECK) VM._assert(bb1.next == bb2);
339        if (IR.SANITY_CHECK) VM._assert(bb2.prev == bb1);
340        bb1.next = null;
341        bb2.prev = null;
342      }
343    
344      /**
345       * Clear the code ordering information for the CFG.<p>
346       * NOTE: This method should only be called as part of a
347       *       whole scale recomputation of the code order, for example
348       *       by ReorderingPhase
349       */
350      public void clearCodeOrder() {
351        SpaceEffGraphNode cur = _firstNode;
352        if (cur == null) return;
353        while (true) {
354          SpaceEffGraphNode next = cur.next;
355          if (next == null) break;
356          cur.next = null;
357          next.prev = null;
358          cur = next;
359        }
360        _firstNode = null;
361        _lastNode = null;
362      }
363    
364      // Enumerate the nodes in the CFG, casting them to whatever concrete type
365      // the caller wants.
366      private static final class NodeEnumeration<T> implements Enumeration<T> {
367        private SpaceEffGraphNode _node;
368        private SpaceEffGraphNode _end;
369    
370        public NodeEnumeration(ControlFlowGraph cfg) {
371          _node = cfg.entry();
372          _end = cfg.exit();
373        }
374    
375        @Override
376        public boolean hasMoreElements() { return _node != null; }
377    
378        @Override
379        @SuppressWarnings("unchecked")
380        // We cast to whatever the concrete type of the graph is
381        public T nextElement() {
382          SpaceEffGraphNode n = _node;
383          _node = n.getNext();
384          if ((n != _end) && (_node == null)) {
385            _node = _end;
386          }
387          return (T) n;
388        }
389      }
390    
391      public Enumeration<BasicBlock> basicBlocks() { return new NodeEnumeration<BasicBlock>(this); }
392    }