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.depgraph;
014
015import static org.jikesrvm.compilers.opt.depgraph.DepGraphConstants.CONTROL;
016import static org.jikesrvm.compilers.opt.depgraph.DepGraphConstants.EXCEPTION_E;
017import static org.jikesrvm.compilers.opt.depgraph.DepGraphConstants.EXCEPTION_MS;
018import static org.jikesrvm.compilers.opt.depgraph.DepGraphConstants.EXCEPTION_R;
019import static org.jikesrvm.compilers.opt.depgraph.DepGraphConstants.GUARD_ANTI;
020import static org.jikesrvm.compilers.opt.depgraph.DepGraphConstants.GUARD_OUTPUT;
021import static org.jikesrvm.compilers.opt.depgraph.DepGraphConstants.GUARD_TRUE;
022import static org.jikesrvm.compilers.opt.depgraph.DepGraphConstants.MEM_ANTI;
023import static org.jikesrvm.compilers.opt.depgraph.DepGraphConstants.MEM_OUTPUT;
024import static org.jikesrvm.compilers.opt.depgraph.DepGraphConstants.MEM_READS_KILL;
025import static org.jikesrvm.compilers.opt.depgraph.DepGraphConstants.MEM_TRUE;
026import static org.jikesrvm.compilers.opt.depgraph.DepGraphConstants.REG_ANTI;
027import static org.jikesrvm.compilers.opt.depgraph.DepGraphConstants.REG_MAY_DEF;
028import static org.jikesrvm.compilers.opt.depgraph.DepGraphConstants.REG_OUTPUT;
029import static org.jikesrvm.compilers.opt.depgraph.DepGraphConstants.REG_TRUE;
030import static org.jikesrvm.compilers.opt.ir.Operators.GET_CAUGHT_EXCEPTION;
031import static org.jikesrvm.compilers.opt.ir.Operators.GET_TIME_BASE;
032import static org.jikesrvm.compilers.opt.ir.Operators.IR_PROLOGUE;
033import static org.jikesrvm.compilers.opt.ir.Operators.SET_CAUGHT_EXCEPTION;
034import static org.jikesrvm.compilers.opt.ir.Operators.UNINT_BEGIN;
035import static org.jikesrvm.compilers.opt.ir.Operators.UNINT_END;
036
037import java.util.Enumeration;
038
039import org.jikesrvm.compilers.opt.ir.BasicBlock;
040import org.jikesrvm.compilers.opt.ir.ExceptionHandlerBasicBlock;
041import org.jikesrvm.compilers.opt.ir.GenericPhysicalDefUse;
042import org.jikesrvm.compilers.opt.ir.IR;
043import org.jikesrvm.compilers.opt.ir.Instruction;
044import org.jikesrvm.compilers.opt.ir.LocationCarrier;
045import org.jikesrvm.compilers.opt.ir.Operator;
046import org.jikesrvm.compilers.opt.ir.Register;
047import org.jikesrvm.compilers.opt.ir.operand.LocationOperand;
048import org.jikesrvm.compilers.opt.ir.operand.Operand;
049import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
050import org.jikesrvm.compilers.opt.liveness.LiveSet;
051import org.jikesrvm.compilers.opt.util.SpaceEffGraph;
052
053/**
054 * Dependence Graph for a single basic block in the program.
055 */
056public class DepGraph extends SpaceEffGraph {
057
058  /**
059   * Set of variables that are live on entry to at least one catch block that
060   * is reachable via a PEI in currentBlock.
061   * This is an approximation of the more precise set, but can be done in
062   * linear time; doing the most precise thing (computing the set for
063   * every PEI and using each individual set to create the necessary
064   * dependences) is quadratic, and probably doesn't help very much anyways.
065   */
066  private final LiveSet handlerLiveSet;
067
068  /**
069   * The basic block we are processing
070   */
071  private final BasicBlock currentBlock;
072
073  /**
074   * The IR we are processing
075   */
076  private final IR ir;
077
078  private final DepGraphNode[] depGraphNodes;
079
080  /**
081   * Constructor (computes the dependence graph!).
082   *
083   * @param ir the IR to compute the dependence graph for
084   * @param start instruction to start computation from
085   * @param end instruction to end computation at
086   * @param currentBlock the basic block that the instructions are living in
087   */
088  public DepGraph(IR ir, Instruction start, Instruction end, BasicBlock currentBlock) {
089    this.currentBlock = currentBlock;
090    this.ir = ir;
091    this.depGraphNodes = new DepGraphNode[ir.regpool.getTotalNumberOfRegisters()];
092    handlerLiveSet = new LiveSet();
093    computeHandlerLiveSet();
094    createNodes(start, end);
095    computeForwardDependences(start, end);
096    computeBackwardDependences(start, end);
097    computeControlAndBarrierDependences(start, end);
098  }
099
100  private DepGraphNode getDepGraphNode(Register r) {
101    return depGraphNodes[r.number];
102  }
103
104  private void setDepGraphNodeForRegister(DepGraphNode dNode, Register r) {
105    depGraphNodes[r.number] = dNode;
106  }
107
108  private void clearDepGraphNodeForRegister(Register r) {
109    setDepGraphNodeForRegister(null, r);
110  }
111
112  /**
113   * Determine the set of variables live on entry to any handler
114   * block that is reachable from currentBlock
115   */
116  private void computeHandlerLiveSet() {
117    if (ir.getHandlerLivenessComputed() && currentBlock.hasExceptionHandlers()) {
118      Enumeration<BasicBlock> e = currentBlock.getExceptionalOut();
119      while (e.hasMoreElements()) {
120        ExceptionHandlerBasicBlock handlerBlock = (ExceptionHandlerBasicBlock) e.nextElement();
121        handlerLiveSet.add(handlerBlock.getLiveSet());
122      }
123    }
124  }
125
126  private void createNodes(Instruction start, Instruction end) {
127    for (Instruction p = start; ; p = p.nextInstructionInCodeOrder()) {
128      DepGraphNode pnode = createDepGraphNode(p);
129      addGraphNode(pnode);
130      if (p == end) {
131        break;
132      }
133    }
134  }
135
136  protected DepGraphNode createDepGraphNode(Instruction p) {
137    return new DepGraphNode(p);
138  }
139
140  /**
141   * Computes flow and output dependences by doing a forward
142   * traversal of the instructions from start to end.
143   *
144   * @param start start instruction
145   * @param end end instruction
146   */
147  private void computeForwardDependences(Instruction start, Instruction end) {
148    boolean readsKill = ir.options.READS_KILL;
149    DepGraphNode lastStoreNode = null;
150    DepGraphNode lastExceptionNode = null;
151    DepGraphNode lastLoadNode = null; // only used if reads kill
152
153    clearRegisters(start, end);
154
155    for (DepGraphNode pnode = (DepGraphNode) firstNode(); pnode != null; pnode =
156        (DepGraphNode) pnode.getNext()) {
157      Instruction p = pnode.instruction();
158
159      // (1) Add edges due to registers
160      int useMask = p.operator().implicitUses;
161      int defMask = p.operator().implicitDefs;
162      if (p.isTSPoint()) {
163        useMask |= GenericPhysicalDefUse.getMaskTSPUses();
164        defMask |= GenericPhysicalDefUse.getMaskTSPDefs();
165      }
166      for (Enumeration<Operand> uses = p.getUses(); uses.hasMoreElements();) {
167        computeForwardDependencesUse(uses.nextElement(), pnode, lastExceptionNode);
168      }
169      for (Enumeration<Register> uses = GenericPhysicalDefUse.enumerate(useMask, ir); uses.hasMoreElements();) {
170        Register r = uses.nextElement();
171        computeImplicitForwardDependencesUse(r, pnode);
172      }
173      for (Enumeration<Operand> defs = p.getDefs(); defs.hasMoreElements();) {
174        computeForwardDependencesDef(defs.nextElement(), pnode, lastExceptionNode);
175      }
176      for (Enumeration<Register> defs = GenericPhysicalDefUse.enumerate(defMask, ir); defs.hasMoreElements();) {
177        Register r = defs.nextElement();
178        computeImplicitForwardDependencesDef(r, pnode);
179      }
180
181      // (2) Add edges due to memory
182      boolean isStore = p.isImplicitStore();
183      boolean isLoad = p.isImplicitLoad();
184      if (isStore || isLoad) {
185        // If readsKill then add memory model memory dependence from prior load
186        // NOTE: In general alias relationships are not transitive and therefore
187        //       we cannot exit this loop early.
188        if (readsKill && isLoad) {
189          for (DepGraphNode lnode = lastLoadNode; lnode != null; lnode = (DepGraphNode) lnode.getPrev()) {
190            if (lnode.instruction().isImplicitLoad() &&
191                LocationOperand.mayBeAliased(getLocation(p), getLocation(lnode.instruction()))) {
192              lnode.insertOutEdge(pnode, MEM_READS_KILL);
193            }
194          }
195          lastLoadNode = pnode;
196        }
197        // Add output/flow memory dependence from prior potentially aliased stores.
198        // NOTE: In general alias relationships are not transitive and therefore
199        //       we cannot exit this loop early.
200        for (DepGraphNode snode = lastStoreNode; snode != null; snode = (DepGraphNode) snode.getPrev()) {
201          if (snode.instruction().isImplicitStore() &&
202              LocationOperand.mayBeAliased(getLocation(p), getLocation(snode.instruction()))) {
203            snode.insertOutEdge(pnode, isStore ? MEM_OUTPUT : MEM_TRUE);
204          }
205        }
206        if (isStore) {
207          lastStoreNode = pnode;
208          if (lastExceptionNode != null) {
209            lastExceptionNode.insertOutEdge(pnode, EXCEPTION_MS);
210          }
211        }
212      }
213
214      // (3) Add edges due to exception state/exceptional control flow.
215      if (p.isPEI()) {
216        if (lastExceptionNode != null) {
217          lastExceptionNode.insertOutEdge(pnode, EXCEPTION_E);
218        }
219        lastExceptionNode = pnode;
220      }
221    }
222  }
223
224  /**
225   * Computes anti dependences by doing a backwards
226   * traversal of the instructions from start to end.
227   *
228   * @param start start instruction
229   * @param end end instruction
230   */
231  private void computeBackwardDependences(Instruction start, Instruction end) {
232    clearRegisters(start, end);
233
234    DepGraphNode lastStoreNode = null;
235    DepGraphNode lastExceptionNode = null;
236    for (DepGraphNode pnode = (DepGraphNode) lastNode(); pnode != null; pnode =
237        (DepGraphNode) pnode.getPrev()) {
238      Instruction p = pnode.instruction();
239
240      // (1) Add edges due to registers
241      int useMask = p.operator().implicitUses;
242      int defMask = p.operator().implicitDefs;
243      if (p.isTSPoint()) {
244        useMask |= GenericPhysicalDefUse.getMaskTSPUses();
245        defMask |= GenericPhysicalDefUse.getMaskTSPDefs();
246      }
247      for (Enumeration<Operand> uses = p.getUses(); uses.hasMoreElements();) {
248        computeBackwardDependencesUse(uses.nextElement(), pnode, lastExceptionNode);
249      }
250      for (Enumeration<Register> uses = GenericPhysicalDefUse.enumerate(useMask, ir); uses.hasMoreElements();) {
251        Register r = uses.nextElement();
252        computeImplicitBackwardDependencesUse(r, pnode);
253      }
254      for (Enumeration<Operand> defs = p.getDefs(); defs.hasMoreElements();) {
255        computeBackwardDependencesDef(defs.nextElement(), pnode, lastExceptionNode);
256      }
257      for (Enumeration<Register> defs = GenericPhysicalDefUse.enumerate(defMask, ir); defs.hasMoreElements();) {
258        Register r = defs.nextElement();
259        computeImplicitBackwardDependencesDef(r, pnode);
260      }
261
262      // (2) Add edges due to memory
263      boolean isStore = p.isImplicitStore();
264      boolean isLoad = p.isImplicitLoad();
265      if (isStore) {
266        if (lastExceptionNode != null) {
267          pnode.insertOutEdge(lastExceptionNode, EXCEPTION_MS);
268        }
269        lastStoreNode = pnode;
270      } else if (isLoad) {
271        // NOTE: In general alias relationships are not transitive and therefore
272        //       we cannot exit this loop early.
273        for (DepGraphNode snode = lastStoreNode; snode != null; snode = (DepGraphNode) snode.getNext()) {
274          if (snode.instruction().isImplicitStore() &&
275              LocationOperand.mayBeAliased(getLocation(p), getLocation(snode.instruction()))) {
276            pnode.insertOutEdge(snode, MEM_ANTI);
277          }
278        }
279      }
280
281      if (p.isPEI()) {
282        lastExceptionNode = pnode;
283      }
284    }
285  }
286
287  /**
288   * Compute control and barrier (acquire/release) dependences
289   * in two passes (one forward, one reverse over the instructions
290   * from start to end.
291   *
292   * @param start start instruction
293   * @param end end instruction
294   */
295  private void computeControlAndBarrierDependences(Instruction start, Instruction end) {
296    // (1) In a forward pass, we add the following dependences:
297    //    a) No load instruction may rise above an acquire
298    //    b) No instruction may rise above an UNINT_BEGIN (conservative),
299    //       a yieldpoint (we placed the yieldpoints where we wanted them),
300    //       a GET_CAUGHT_EXCEPTION, or an IR_PROLOGUE.
301    //    c) No GC point may rise above an UNINT_END
302    DepGraphNode lastTotalBarrier = null;
303    DepGraphNode lastGCBarrier = null;
304    DepGraphNode lastAcquire = null;
305    for (DepGraphNode pnode = (DepGraphNode) firstNode(); pnode != null; pnode =
306        (DepGraphNode) pnode.getNext()) {
307      Instruction p = pnode.instruction();
308      if (lastTotalBarrier != null) {
309        lastTotalBarrier.insertOutEdge(pnode, CONTROL);
310      }
311      if (lastGCBarrier != null) {
312        lastGCBarrier.insertOutEdge(pnode, CONTROL);
313      }
314      if (lastAcquire != null && p.isImplicitLoad()) {
315        lastAcquire.insertOutEdge(pnode, CONTROL);
316      }
317      Operator pop = p.operator();
318      if (p.isYieldPoint() || pop == IR_PROLOGUE || pop == UNINT_BEGIN || pop == GET_TIME_BASE || pop == GET_CAUGHT_EXCEPTION) {
319        lastTotalBarrier = pnode;
320      }
321      if (pop == UNINT_END) {
322        lastGCBarrier = pnode;
323      }
324      if (p.isAcquire() || p.isDynamicLinkingPoint()) {
325        lastAcquire = pnode;
326      }
327    }
328
329    // (2) In a backward pass we add the following dependences:
330    //    a) No store instruction may sink below a release.
331    //    b) No instruction may sink below an UNINT_END (conservative),
332    //       a branch/return, a SET_CAUGHT_EXCEPTION, or a yieldpoint
333    //       (again want to pin yieldpoints).
334    //    c) No GC point may sink below an UNINT_BEGIN
335    lastTotalBarrier = null;
336    lastGCBarrier = null;
337    DepGraphNode lastRelease = null;
338    for (DepGraphNode pnode = (DepGraphNode) lastNode(); pnode != null; pnode =
339        (DepGraphNode) pnode.getPrev()) {
340      Instruction p = pnode.instruction();
341      if (lastTotalBarrier != null) {
342        pnode.insertOutEdge(lastTotalBarrier, CONTROL);
343      }
344      if (lastGCBarrier != null) {
345        pnode.insertOutEdge(lastGCBarrier, CONTROL);
346      }
347      if (lastRelease != null && p.isImplicitStore()) {
348        pnode.insertOutEdge(lastRelease, CONTROL);
349      }
350      Operator pop = p.operator();
351      if (p.isBranch() || p.isReturn() || p.isYieldPoint() || pop == UNINT_END || pop == GET_TIME_BASE || pop == SET_CAUGHT_EXCEPTION) {
352        lastTotalBarrier = pnode;
353      }
354      if (pop == UNINT_BEGIN) {
355        lastGCBarrier = pnode;
356      }
357      if (p.isRelease() || p.isDynamicLinkingPoint()) {
358        lastRelease = pnode;
359      }
360    }
361  }
362
363  /**
364   * Compute forward dependences from a given use to a given node.
365   * @param op source operand
366   * @param destNode destination node
367   * @param lastExceptionNode node representing the last PEI
368   */
369  private void computeForwardDependencesUse(Operand op, DepGraphNode destNode,
370                                            DepGraphNode lastExceptionNode) {
371    if (!(op instanceof RegisterOperand)) return;
372    RegisterOperand regOp = (RegisterOperand) op;
373    DepGraphNode sourceNode = getDepGraphNode(regOp.getRegister());
374
375    // if there is an element in the regTableDef[regNum] slot, set
376    // the flow dependence edge.
377    if (sourceNode != null) {
378      if (regOp.getRegister().isValidation()) {
379        sourceNode.insertOutEdge(destNode, GUARD_TRUE);
380      } else {
381        for (Enumeration<Register> e =
382            GenericPhysicalDefUse.enumerate(GenericPhysicalDefUse.getMaskTSPDefs(), ir); e.hasMoreElements();) {
383          Register r = e.nextElement();
384          if (regOp.getRegister() == r) {
385            sourceNode.insertOutEdge(destNode, REG_MAY_DEF);
386            return;
387          }
388        }
389        sourceNode.insertRegTrueOutEdge(destNode, regOp);
390      }
391    }
392  }
393
394  /**
395   * Compute forward dependences from a given def to a given node.
396   * @param op source operand
397   * @param destNode destination node
398   * @param lastExceptionNode node representing the last PEI
399   */
400  private void computeForwardDependencesDef(Operand op, DepGraphNode destNode,
401                                            DepGraphNode lastExceptionNode) {
402    if (!(op instanceof RegisterOperand)) return;
403    RegisterOperand regOp = (RegisterOperand)op;
404    DepGraphNode sourceNode = getDepGraphNode(regOp.getRegister());
405
406    if (sourceNode != null) {
407      // create output dependence edge from sourceNode to destNode.
408      int type = regOp.getRegister().isValidation() ? GUARD_OUTPUT : REG_OUTPUT;
409      sourceNode.insertOutEdge(destNode, type);
410    }
411
412    // pin the def below the previous exception node if the register
413    // being defined may be live in some reachable catch block
414    if (lastExceptionNode != null && regOp.getRegister().spansBasicBlock() && currentBlock.hasExceptionHandlers()) {
415      if (!ir.getHandlerLivenessComputed() || handlerLiveSet.contains(regOp.getRegister())) {
416        lastExceptionNode.insertOutEdge(destNode, EXCEPTION_R);
417      }
418    }
419
420    setDepGraphNodeForRegister(destNode, regOp.getRegister());
421  }
422
423  /**
424   * Compute backward dependences from a given use to a given node.
425   * @param op source operand
426   * @param destNode destination node
427   * @param lastExceptionNode node representing the last PEI
428   */
429  private void computeBackwardDependencesUse(Operand op, DepGraphNode destNode,
430                                             DepGraphNode lastExceptionNode) {
431    if (!(op instanceof RegisterOperand)) return;
432    RegisterOperand regOp = (RegisterOperand) op;
433    DepGraphNode sourceNode = getDepGraphNode(regOp.getRegister());
434    if (sourceNode != null) {
435      int type = regOp.getRegister().isValidation() ? GUARD_ANTI : REG_ANTI;
436      // create antidependence edge.
437      // NOTE: sourceNode contains the def and destNode contains the use.
438      destNode.insertOutEdge(sourceNode, type);
439    }
440  }
441
442  /**
443   * Compute backward dependences from a given def to a given node.
444   * @param op source operand
445   * @param destNode destination node
446   * @param lastExceptionNode node representing the last PEI
447   */
448  private void computeBackwardDependencesDef(Operand op, DepGraphNode destNode,
449                                             DepGraphNode lastExceptionNode) {
450    if (!(op instanceof RegisterOperand)) return;
451    RegisterOperand regOp = (RegisterOperand) op;
452
453    // pin the def above the next exception node if the register
454    // being defined may be live in some reachable catch block
455    if (lastExceptionNode != null && regOp.getRegister().spansBasicBlock() && currentBlock.hasExceptionHandlers()) {
456      if (!ir.getHandlerLivenessComputed() || handlerLiveSet.contains(regOp.getRegister())) {
457        destNode.insertOutEdge(lastExceptionNode, EXCEPTION_R);
458      }
459    }
460    setDepGraphNodeForRegister(destNode, regOp.getRegister());
461  }
462
463  /**
464   * Compute implicit forward dependences from a given register use
465   * to a given node.
466   * @param r source register
467   * @param destNode destination node
468   */
469  private void computeImplicitForwardDependencesUse(Register r, DepGraphNode destNode) {
470    DepGraphNode sourceNode = getDepGraphNode(r);
471    if (sourceNode != null) {
472      for (Enumeration<Register> e =
473          GenericPhysicalDefUse.enumerate(GenericPhysicalDefUse.getMaskTSPDefs(), ir); e.hasMoreElements();) {
474        Register r2 = e.nextElement();
475        if (r == r2) {
476          sourceNode.insertOutEdge(destNode, REG_MAY_DEF);
477          return;
478        }
479      }
480      sourceNode.insertOutEdge(destNode, REG_TRUE);
481    }
482  }
483
484  /**
485   * Compute implicit forward dependences from a given register def
486   * to a given node.
487   * @param r source register
488   * @param destNode destination node
489   */
490  private void computeImplicitForwardDependencesDef(Register r, DepGraphNode destNode) {
491    DepGraphNode sourceNode = getDepGraphNode(r);
492    if (sourceNode != null) {
493      sourceNode.insertOutEdge(destNode, REG_OUTPUT);
494    }
495    setDepGraphNodeForRegister(destNode, r);
496  }
497
498  /**
499   * Compute implicit backward dependences from a given register use
500   * to a given node.
501   * @param r source register
502   * @param destNode destination node
503   */
504  private void computeImplicitBackwardDependencesUse(Register r, DepGraphNode destNode) {
505    DepGraphNode sourceNode = getDepGraphNode(r);
506    if (sourceNode != null) {
507      // create antidependence edge.
508      // NOTE: sourceNode contains the def and destNode contains the use.
509      destNode.insertOutEdge(sourceNode, REG_ANTI);
510    }
511  }
512
513  /**
514   * Compute implicit backward dependences from a given register def
515   * to a given node.
516   * @param r source register
517   * @param destNode destination node
518   */
519  private void computeImplicitBackwardDependencesDef(Register r, DepGraphNode destNode) {
520    setDepGraphNodeForRegister(destNode, r);
521  }
522
523  /**
524   * Get the location of a given load or store instruction.
525   * @param s the instruction to get the location from.
526   *
527   * @return a location or {@code null}
528   */
529  private LocationOperand getLocation(Instruction s) {
530    // This extra conforms check wouldn't be necessary if the DepGraph
531    // code was distinguishing between explict load/stores which have
532    // locations and implicit load/stores which don't.
533    return LocationCarrier.conforms(s) ? LocationCarrier.getLocation(s) : null;
534  }
535
536  /**
537   * Initialize (clear) the dNode field in Register for all registers
538   * in this basic block by setting them to null.
539   * Handles both explicit and implict use/defs.
540   * @param start the first opt instruction in the region
541   * @param end   the last opt instruction in the region
542   */
543  private void clearRegisters(Instruction start, Instruction end) {
544    for (Instruction p = start; ; p = p.nextInstructionInCodeOrder()) {
545      for (Enumeration<Operand> ops = p.getOperands(); ops.hasMoreElements();) {
546        Operand op = ops.nextElement();
547        if (op instanceof RegisterOperand) {
548          RegisterOperand rOp = (RegisterOperand) op;
549          clearDepGraphNodeForRegister(rOp.getRegister());
550        }
551      }
552      if (p == end) break;
553    }
554    for (Enumeration<Register> e = GenericPhysicalDefUse.enumerateAllImplicitDefUses(ir); e.hasMoreElements();) {
555      Register r = e.nextElement();
556      clearDepGraphNodeForRegister(r);
557    }
558  }
559
560  /**
561   * Print the dependence graph to standard out.
562   */
563  public void printDepGraph() {
564    System.out.println(toString());
565    System.out.println("-----------------------------------");
566  }
567}