/*
* 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.IfCmp;
import org.jikesrvm.compilers.opt.ir.Label;
import org.jikesrvm.compilers.opt.ir.OPT_BasicBlock;
import org.jikesrvm.compilers.opt.ir.OPT_BasicBlockEnumeration;
import org.jikesrvm.compilers.opt.ir.OPT_BranchOperand;
import org.jikesrvm.compilers.opt.ir.OPT_Instruction;
/**
* This class represents a diamond (if-then-else) structure in the
* control-flow graph.
*/
final class OPT_Diamond {
/**
* The top of the diamond
*/
private final OPT_BasicBlock top;
/**
* The bottom of the diamond
*/
private final OPT_BasicBlock bottom;
/**
* The "taken" branch of the diamond (might be null)
*/
private final OPT_BasicBlock taken;
/**
* The "not-taken" branch of the diamond (might be null)
*/
private final OPT_BasicBlock notTaken;
/**
* The top of the diamond
*/
OPT_BasicBlock getTop() { return top; }
/**
* The bottom of the diamond
*/
OPT_BasicBlock getBottom() { return bottom; }
/**
* The "taken" branch of the diamond (might be null)
*/
OPT_BasicBlock getTaken() { return taken;}
/**
* The "not-taken" branch of the diamond (might be null)
*/
OPT_BasicBlock getNotTaken() { return notTaken; }
OPT_Diamond(OPT_BasicBlock top, OPT_BasicBlock taken, OPT_BasicBlock notTaken, OPT_BasicBlock bottom) {
this.top = top;
this.taken = taken;
this.notTaken = notTaken;
this.bottom = bottom;
}
/**
* See if bb is the root of a diamond. If so, return an OPT_Diamond
* representing the structure.
*
* @return a structure representing the diamond. null if not
* applicable.
*/
static OPT_Diamond buildDiamond(OPT_BasicBlock bb) {
if (bb.getNumberOfNormalOut() != 2) return null;
// Identify the two out nodes from bb.
OPT_BasicBlockEnumeration outNodes = bb.getNormalOut();
OPT_BasicBlock out1 = outNodes.nextElement();
OPT_BasicBlock out2 = outNodes.nextElement();
int out1In = out1.getNumberOfIn();
int out2In = out2.getNumberOfIn();
if (out1In == 1 && out2In == 1) {
// look for the case where the diamond has four non-empty blocks.
if (out1.getNumberOfNormalOut() == 1 && out2.getNumberOfNormalOut() == 1) {
OPT_BasicBlock b1 = out1.getNormalOut().nextElement();
OPT_BasicBlock b2 = out2.getNormalOut().nextElement();
if (b1 == b2) {
return fourElementDiamond(bb, out1, out2, b1);
}
}
} else if (out1In == 1) {
// check for a 3-element diamond
if (out1.getNumberOfNormalOut() == 1) {
OPT_BasicBlock b1 = out1.getNormalOut().nextElement();
if (b1 == out2) {
return threeElementDiamond(bb, out1, out2);
}
}
} else if (out2In == 1) {
// check for a 3-element diamond
if (out2.getNumberOfNormalOut() == 1) {
OPT_BasicBlock b2 = out2.getNormalOut().nextElement();
if (b2 == out1) {
return threeElementDiamond(bb, out2, out1);
}
}
}
// didn't find a diamond
return null;
}
/**
* Given that four blocks form a diamond, return the correct structure.
*/
private static OPT_Diamond fourElementDiamond(OPT_BasicBlock top, OPT_BasicBlock left, OPT_BasicBlock right,
OPT_BasicBlock bottom) {
OPT_Instruction cb = top.firstBranchInstruction();
// for now we only support IfCmp diamonds.
if (VM.VerifyAssertions) VM._assert(IfCmp.conforms(cb));
OPT_BranchOperand takenTarget = IfCmp.getTarget(cb);
if (Label.getBlock(takenTarget.target).block == left) {
return new OPT_Diamond(top, left, right, bottom);
} else {
return new OPT_Diamond(top, right, left, bottom);
}
}
/**
* Given that three blocks form a diamond, return the correct structure.
*/
private static OPT_Diamond threeElementDiamond(OPT_BasicBlock top, OPT_BasicBlock side, OPT_BasicBlock bottom) {
OPT_Instruction cb = top.firstBranchInstruction();
// for now we only support IfCmp diamonds.
if (VM.VerifyAssertions) VM._assert(IfCmp.conforms(cb));
OPT_BranchOperand takenTarget = IfCmp.getTarget(cb);
if (Label.getBlock(takenTarget.target).block == side) {
return new OPT_Diamond(top, side, null, bottom);
} else {
return new OPT_Diamond(top, null, side, bottom);
}
}
/**
* Return a string representation.
*/
public String toString() {
return "[" + top + "," + taken + "," + notTaken + "," + bottom + "]";
}
}