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 static org.jikesrvm.compilers.opt.ir.Operators.BBEND;
016import static org.jikesrvm.compilers.opt.ir.Operators.LABEL;
017
018import java.util.Enumeration;
019
020import org.jikesrvm.VM;
021import org.jikesrvm.compilers.opt.DefUse;
022import org.jikesrvm.compilers.opt.OptOptions;
023import org.jikesrvm.compilers.opt.driver.CompilerPhase;
024import org.jikesrvm.compilers.opt.ir.BasicBlock;
025import org.jikesrvm.compilers.opt.ir.IR;
026import org.jikesrvm.compilers.opt.ir.Instruction;
027import org.jikesrvm.compilers.opt.ir.Trap;
028import org.jikesrvm.compilers.opt.util.SpaceEffGraphNode;
029
030/**
031 * IR level independent driver for
032 * simple peephole optimizations of branches.
033 */
034public abstract class BranchOptimizationDriver extends CompilerPhase {
035
036  /**
037   * Optimization level at which phase should be performed.
038   */
039  private final int level;
040
041  /**
042   * Optimization level at which phase should be performed.
043   */
044  private final boolean simplify;
045
046  /**
047   * @param level the minimum optimization level at which the branch
048   * optimizations should be performed.
049   * @param simplify perform simplification prior to optimization?
050   */
051  BranchOptimizationDriver(int level, boolean simplify) {
052    this.level = level;
053    this.simplify = simplify;
054  }
055
056  /**
057   * @param level the minimum optimization level at which the branch
058   * optimizations should be performed.
059   */
060  BranchOptimizationDriver(int level) {
061    this.level = level;
062    this.simplify = false;
063  }
064
065  /** Interface */
066  @Override
067  public final boolean shouldPerform(OptOptions options) {
068    return options.getOptLevel() >= level;
069  }
070
071  @Override
072  public final String getName() {
073    return "Branch Optimizations";
074  }
075
076  @Override
077  public final boolean printingEnabled(OptOptions options, boolean before) {
078    return false;
079  }
080
081  /**
082   * This phase contains no per-compilation instance fields.
083   */
084  @Override
085  public final CompilerPhase newExecution(IR ir) {
086    return this;
087  }
088
089  /**
090   * Perform peephole branch optimizations.
091   *
092   * @param ir the IR to optimize
093   */
094  @Override
095  public final void perform(IR ir) {
096    perform(ir, true);
097  }
098
099  public final void perform(IR ir, boolean renumber) {
100    if (simplify) {
101      applySimplify(ir);
102    }
103
104    maximizeBasicBlocks(ir);
105    if (VM.BuildForIA32) {
106      // spans-bb information is used for CMOV insertion
107      DefUse.recomputeSpansBasicBlock(ir);
108    }
109    boolean didSomething = false;
110    boolean didSomethingThisTime = true;
111    while (didSomethingThisTime) {
112      didSomething |= applyPeepholeBranchOpts(ir);
113      didSomethingThisTime = removeUnreachableCode(ir);
114      didSomething |= didSomethingThisTime;
115    }
116    if (didSomething) {
117      maximizeBasicBlocks(ir);
118    }
119
120    ir.cfg.compactNodeNumbering();
121
122    if (ir.IRStage < IR.MIR) {
123      ir.pruneExceptionalOut();
124    }
125  }
126
127  /**
128   * Perform branch simplifications.
129   *
130   * @param ir the IR to optimize
131   * @return was something reduced
132   */
133  private static boolean applySimplify(IR ir) {
134    boolean didSomething = false;
135    for (Enumeration<BasicBlock> e = ir.getBasicBlocks(); e.hasMoreElements();) {
136      BasicBlock bb = e.nextElement();
137      didSomething |= BranchSimplifier.simplify(bb, ir);
138    }
139    return didSomething;
140  }
141
142  /**
143   * This pass performs peephole branch optimizations.
144   * See Muchnick ~p.590
145   *
146   * @param ir the IR to optimize
147   * @return whether optimizations were applied
148   */
149  protected boolean applyPeepholeBranchOpts(IR ir) {
150    boolean didSomething = false;
151    for (Enumeration<BasicBlock> e = ir.getBasicBlocks(); e.hasMoreElements();) {
152      BasicBlock bb = e.nextElement();
153      if (!bb.isEmpty()) {
154        for (Enumeration<Instruction> ie = bb.enumerateBranchInstructions(); ie.hasMoreElements();) {
155          Instruction s = ie.nextElement();
156          if (optimizeBranchInstruction(ir, s, bb)) {
157            didSomething = true;
158            // hack: we may have modified the instructions; start over
159            ie = bb.enumerateBranchInstructions();
160          }
161        }
162      }
163    }
164    return didSomething;
165  }
166
167  /**
168   * This method actually does the work of attempting to
169   * peephole optimize a branch instruction.
170   * @param ir the containing IR
171   * @param s the branch instruction to optimize
172   * @param bb the containing basic block
173   * @return true if an optimization was applied, false otherwise
174   */
175  protected abstract boolean optimizeBranchInstruction(IR ir, Instruction s, BasicBlock bb);
176
177  /**
178   * Remove unreachable code
179   *
180   * @param ir the IR to optimize
181   * @return true if did something, false otherwise
182   */
183  protected final boolean removeUnreachableCode(IR ir) {
184    boolean result = false;
185
186    // (1) All code in a basic block after an unconditional
187    //     trap instruction is dead.
188    for (Instruction s = ir.firstInstructionInCodeOrder(); s != null; s = s.nextInstructionInCodeOrder()) {
189      if (Trap.conforms(s)) {
190        Instruction p = s.nextInstructionInCodeOrder();
191        if (p.operator() != BBEND) {
192          BasicBlock bb = s.getBasicBlock();
193          do {
194            Instruction q = p;
195            p = p.nextInstructionInCodeOrder();
196            q.remove();
197          } while (p.operator() != BBEND);
198          bb.recomputeNormalOut(ir);
199          result = true;
200        }
201      }
202    }
203
204    // (2) perform a Depth-first search of the control flow graph,
205    //     and remove any nodes not reachable from entry.
206    BasicBlock entry = ir.cfg.entry();
207    ir.cfg.clearDFS();
208    entry.sortDFS();
209    for (SpaceEffGraphNode node = entry; node != null;) {
210      // save it now before removeFromCFGAndCodeOrder nulls it out!!!
211      SpaceEffGraphNode nextNode = node.getNext();
212      if (!node.dfsVisited()) {
213        BasicBlock bb = (BasicBlock) node;
214        ir.cfg.removeFromCFGAndCodeOrder(bb);
215        result = true;
216      }
217      node = nextNode;
218    }
219    return result;
220  }
221
222  /**
223   * Merge adjacent basic blocks
224   *
225   * @param ir the IR to optimize
226   */
227  protected final void maximizeBasicBlocks(IR ir) {
228    for (BasicBlock currBB = ir.cfg.firstInCodeOrder(); currBB != null;) {
229      if (currBB.mergeFallThrough(ir)) {
230        // don't advance currBB; it may have a new trivial fallthrough to swallow
231      } else {
232        currBB = currBB.nextBasicBlockInCodeOrder();
233      }
234    }
235  }
236
237  // Helper functions
238
239  protected final Instruction firstLabelFollowing(Instruction s) {
240    for (s = s.nextInstructionInCodeOrder(); s != null; s = s.nextInstructionInCodeOrder()) {
241      if (s.operator() == LABEL) {
242        return s;
243      }
244    }
245    return null;
246  }
247
248  protected final Instruction firstRealInstructionFollowing(Instruction s) {
249    for (s = s.nextInstructionInCodeOrder(); s != null; s = s.nextInstructionInCodeOrder()) {
250      if (s.operator() != LABEL && s.operator() != BBEND) {
251        return s;
252      }
253    }
254    return s;
255  }
256}