/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Common Public License (CPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/cpl1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.compilers.opt;
import org.jikesrvm.VM;
import org.jikesrvm.compilers.opt.ir.OPT_BasicBlock;
import org.jikesrvm.compilers.opt.ir.OPT_BasicBlockEnumeration;
import org.jikesrvm.compilers.opt.ir.OPT_IR;
import org.jikesrvm.compilers.opt.ir.OPT_Instruction;
import org.jikesrvm.compilers.opt.ir.OPT_InstructionEnumeration;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.BBEND;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LABEL;
import org.jikesrvm.compilers.opt.ir.Trap;
/**
* IR level independent driver for
* simple peephole optimizations of branches.
*/
public abstract class OPT_BranchOptimizationDriver extends OPT_CompilerPhase {
/**
* Optimization level at which phase should be performed.
*/
private final int level;
/**
* Optimization level at which phase should be performed.
*/
private final boolean simplify;
/**
* @param level the minimum optimization level at which the branch
* optimizations should be performed.
* @param simplify perform simplification prior to optimization?
*/
OPT_BranchOptimizationDriver(int level, boolean simplify) {
this.level = level;
this.simplify = simplify;
}
/**
* @param level the minimum optimization level at which the branch
* optimizations should be performed.
*/
OPT_BranchOptimizationDriver(int level) {
this.level = level;
this.simplify = false;
}
/** Interface */
public final boolean shouldPerform(OPT_Options options) {
return options.getOptLevel() >= level;
}
public final String getName() {
return "Branch Optimizations";
}
public final boolean printingEnabled(OPT_Options options, boolean before) {
return false;
}
/**
* This phase contains no per-compilation instance fields.
*/
public final OPT_CompilerPhase newExecution(OPT_IR ir) {
return this;
}
/**
* Perform peephole branch optimizations.
*
* @param ir the IR to optimize
*/
public final void perform(OPT_IR ir) {
perform(ir, true);
}
public final void perform(OPT_IR ir, boolean renumber) {
if (simplify) {
applySimplify(ir);
}
maximizeBasicBlocks(ir);
if (VM.BuildForIA32) {
// spans-bb information is used for CMOV insertion
OPT_DefUse.recomputeSpansBasicBlock(ir);
}
boolean didSomething = false;
boolean didSomethingThisTime = true;
while (didSomethingThisTime) {
didSomething |= applyPeepholeBranchOpts(ir);
didSomethingThisTime = removeUnreachableCode(ir);
didSomething |= didSomethingThisTime;
}
if (didSomething) {
maximizeBasicBlocks(ir);
}
ir.cfg.compactNodeNumbering();
if (ir.IRStage < OPT_IR.MIR) {
ir.pruneExceptionalOut();
}
}
/**
* Perform branch simplifications.
*
* @param ir the IR to optimize
* @return was something reduced
*/
private static boolean applySimplify(OPT_IR ir) {
boolean didSomething = false;
for (OPT_BasicBlockEnumeration e = ir.getBasicBlocks(); e.hasMoreElements();) {
OPT_BasicBlock bb = e.next();
didSomething |= OPT_BranchSimplifier.simplify(bb, ir);
}
return didSomething;
}
/**
* This pass performs peephole branch optimizations.
* See Muchnick ~p.590
*
* @param ir the IR to optimize
*/
protected boolean applyPeepholeBranchOpts(OPT_IR ir) {
boolean didSomething = false;
for (OPT_BasicBlockEnumeration e = ir.getBasicBlocks(); e.hasMoreElements();) {
OPT_BasicBlock bb = e.next();
if (!bb.isEmpty()) {
for (OPT_InstructionEnumeration ie = bb.enumerateBranchInstructions(); ie.hasMoreElements();) {
OPT_Instruction s = ie.next();
if (optimizeBranchInstruction(ir, s, bb)) {
didSomething = true;
// hack: we may have modified the instructions; start over
ie = bb.enumerateBranchInstructions();
}
}
}
}
return didSomething;
}
/**
* This method actually does the work of attempting to
* peephole optimize a branch instruction.
* @param ir the containing IR
* @param s the branch instruction to optimize
* @param bb the containing basic block
* @return true if an optimization was applied, false otherwise
*/
protected abstract boolean optimizeBranchInstruction(OPT_IR ir, OPT_Instruction s, OPT_BasicBlock bb);
/**
* Remove unreachable code
*
* @param ir the IR to optimize
* @return true if did something, false otherwise
*/
protected final boolean removeUnreachableCode(OPT_IR ir) {
boolean result = false;
// (1) All code in a basic block after an unconditional
// trap instruction is dead.
for (OPT_Instruction s = ir.firstInstructionInCodeOrder(); s != null; s = s.nextInstructionInCodeOrder()) {
if (Trap.conforms(s)) {
OPT_Instruction p = s.nextInstructionInCodeOrder();
if (p.operator() != BBEND) {
OPT_BasicBlock bb = s.getBasicBlock();
do {
OPT_Instruction q = p;
p = p.nextInstructionInCodeOrder();
q.remove();
} while (p.operator() != BBEND);
bb.recomputeNormalOut(ir);
result = true;
}
}
}
// (2) perform a Depth-first search of the control flow graph,
// and remove any nodes not reachable from entry.
OPT_BasicBlock entry = ir.cfg.entry();
ir.cfg.clearDFS();
entry.sortDFS();
for (OPT_SpaceEffGraphNode node = entry; node != null;) {
// save it now before removeFromCFGAndCodeOrder nulls it out!!!
OPT_SpaceEffGraphNode nextNode = node.getNext();
if (!node.dfsVisited()) {
OPT_BasicBlock bb = (OPT_BasicBlock) node;
ir.cfg.removeFromCFGAndCodeOrder(bb);
result = true;
}
node = nextNode;
}
return result;
}
/**
* Merge adjacent basic blocks
*
* @param ir the IR to optimize
*/
protected final void maximizeBasicBlocks(OPT_IR ir) {
for (OPT_BasicBlock currBB = ir.cfg.firstInCodeOrder(); currBB != null;) {
if (currBB.mergeFallThrough(ir)) {
// don't advance currBB; it may have a new trivial fallthrough to swallow
} else {
currBB = currBB.nextBasicBlockInCodeOrder();
}
}
}
// Helper functions
/**
* Given an instruction s, return the first LABEL instruction
* following s.
*/
protected final OPT_Instruction firstLabelFollowing(OPT_Instruction s) {
for (s = s.nextInstructionInCodeOrder(); s != null; s = s.nextInstructionInCodeOrder()) {
if (s.operator() == LABEL) {
return s;
}
}
return null;
}
/**
* Given an instruction s, return the first real (non-label) instruction
* following s
*/
protected final OPT_Instruction firstRealInstructionFollowing(OPT_Instruction s) {
for (s = s.nextInstructionInCodeOrder(); s != null; s = s.nextInstructionInCodeOrder()) {
if (s.operator() != LABEL && s.operator() != BBEND) {
return s;
}
}
return s;
}
}