/*
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.c1x.opt;
import com.sun.c1x.*;
import com.oracle.max.criutils.*;
import com.sun.c1x.graph.*;
import com.sun.c1x.ir.*;
import com.sun.c1x.util.*;
import com.sun.c1x.value.*;
import com.sun.c1x.value.FrameState.PhiProcedure;
import com.sun.cri.ci.*;
/**
* This class removes simple diamonds where control flow joins and splits again immediately.
* This is quite special-cased for this scenario:
*
* boolean foo() {
* return abc < def;
* }
* void bar () {
* if (foo) {
* ...
* }
*/
public class DiamondEliminator implements BlockClosure {
final IR ir;
private boolean eliminated;
public DiamondEliminator(IR ir) {
this.ir = ir;
ir.startBlock.iteratePreOrder(this);
if (eliminated) {
new BlockMerger(ir);
}
}
public void apply(BlockBegin block) {
// check that we have two predecessors and that block ends with an If (which implies two successors)
if (!(block.numberOfPreds() == 2 && block.end() instanceof If)) {
return;
}
If curIf = (If) block.end();
BlockBegin leftPred = block.predAt(0);
BlockBegin rightPred = block.predAt(1);
// check that we compare a phi function with a constant
if (!(curIf.x() instanceof Phi
&& leftPred.end() instanceof Goto && rightPred.end() instanceof Goto
&& curIf.y() instanceof Constant
&& curIf.x().kind == CiKind.Int && curIf.y().kind == CiKind.Int)) {
return;
}
final Phi ifPhi = (Phi) curIf.x();
Constant ifCompare = (Constant) curIf.y();
// check that phi function belongs to our block, and block contains nothing but the constant (optional) and the if.
if (!(ifPhi.block() == block
&& (block.next() == curIf || (block.next() == ifCompare && ifCompare.next() == curIf))
&& (curIf.condition() == Condition.EQ || curIf.condition() == Condition.NE)
&& ifPhi.inputAt(0) instanceof Constant && ifPhi.inputAt(1) instanceof Constant
)) {
return;
}
// check that there is only one phi function in this block, and that if can be statically decided
boolean onlyPhi = block.stateBefore().forEachPhi(block, new PhiProcedure() {
public boolean doPhi(Phi phi) {
return phi == ifPhi;
}
});
int compare = ifCompare.value.asInt();
int left = ((Constant) ifPhi.inputAt(0)).value.asInt();
int right = ((Constant) ifPhi.inputAt(1)).value.asInt();
if (!(onlyPhi && left != right && (left == compare || right == compare))) {
return;
}
UsageChecker usageChecker = new UsageChecker();
if (usageChecker.findUsage(ir, ifPhi, block, curIf)) {
return;
}
BlockBegin leftSux;
BlockBegin rightSux;
if ((curIf.condition() == Condition.EQ && left == compare) || (curIf.condition() == Condition.NE && right == compare)) {
leftSux = block.suxAt(0);
rightSux = block.suxAt(1);
} else {
leftSux = block.suxAt(1);
rightSux = block.suxAt(0);
}
if (leftSux == rightSux) {
// corner case where the block substitution below would fail.
return;
}
if (C1XOptions.PrintHIR) {
TTY.println("Eliminating Block B" + block.blockID + ", phi " + ifPhi.id() + ", connecting blocks B" + leftPred.blockID + "->" + leftSux.blockID + " and " + rightPred.blockID + "->" + rightSux.blockID);
}
// connect leftPred with leftSux, and rightPred with rightSux. This eliminates the curIf and the ifPhi
Util.replaceAllInList(block, leftSux, leftPred.end().successors());
Util.replaceAllInList(block, rightSux, rightPred.end().successors());
Util.replaceAllInList(block, leftPred, leftSux.predecessors());
Util.replaceAllInList(block, rightPred, rightSux.predecessors());
leftPred.end().setStateAfter(block.end().stateAfter().copy());
rightPred.end().setStateAfter(block.end().stateAfter().copy());
eliminated = true;
}
private final class UsageChecker implements BlockClosure, ValueClosure {
public Value search;
public BlockBegin ignoreBlock;
public Value ignore;
public boolean found;
private BlockBegin curBlock;
private Value curValue;
public boolean findUsage(IR ir, Value search, BlockBegin ignoreBlock, Value ignore) {
this.search = search;
this.ignoreBlock = ignoreBlock;
this.ignore = ignore;
ir.startBlock.iterateAnyOrder(this, false);
return found;
}
public void apply(BlockBegin block) {
if (block != ignoreBlock) {
curBlock = block;
curValue = null;
block.stateBefore().forEachPhi(block, new PhiProcedure() {
public boolean doPhi(Phi phi) {
for (int i = 0; i < phi.inputCount(); i++) {
if (phi.inputAt(i) == search) {
found = true;
}
}
return true;
}
});
if (block.exceptionHandlerStates() != null) {
for (FrameState s : block.exceptionHandlerStates()) {
s.valuesDo(this);
}
}
for (Instruction n = block; n != null; n = n.next()) {
curValue = n;
if (n != ignore) {
n.allValuesDo(this);
}
}
}
}
public Value apply(Value v) {
if (v == search) {
found = true;
}
return v;
}
}
}