use of org.jikesrvm.compilers.opt.ir.operand.ConditionOperand in project JikesRVM by JikesRVM.
the class BranchOptimizations method generateCondMove.
/**
* Attempt to generate a straight-line sequence using conditional move
* instructions, to replace a diamond control flow structure.
*
* <p>Suppose we have the following code, where e{n} is an expression:
* <pre>
* if (a op b) {
* x = e2;
* y = e3;
* } else {
* z = e4;
* x = e5;
* }
* </pre>
* We would transform this to:
* <pre>
* t1 = a;
* t2 = b;
* t3 = e2;
* t4 = e3;
* t5 = e4;
* t6 = e5;
* COND MOVE [if (t1 op t2) x := t3 else x := t6 ];
* COND MOVE [if (t1 op t2) y := t4 else y := y];
* COND MOVE [if (t1 op t2) z := z else z := t5];
* </pre>
*
* <p>Note that we rely on other optimizations (eg. copy propagation) to
* clean up some of this unnecessary mess.
*
* <p>Note that in this example, we've increased the shortest path by 2
* expression evaluations, 2 moves, and 3 cond moves, but eliminated one
* conditional branch.
*
* <p>We apply a cost heuristic to guide this transformation:
* We will eliminate a conditional branch iff it increases the shortest
* path by no more than 'k' operations. Currently, we count each
* instruction (alu, move, or cond move) as 1 evaluation.
* The parameter k is specified by OPT\_Options.COND_MOVE_CUTOFF.
*
* <p> In the example above, since we've increased the shortest path by
* 6 instructions, we will only perform the transformation if {@code k >= 7}.
*
* <p> TODO items
* <ul>
* <li> consider smarter cost heuristics
* <li> enhance downstream code generation to avoid redundant evaluation
* of condition codes.
* </ul>
*
* @param ir governing IR
* @param bb basic block of cb
* @param cb conditional branch instruction
* @return true if the transformation succeeds, false otherwise
*/
private boolean generateCondMove(IR ir, BasicBlock bb, Instruction cb) {
final boolean VERBOSE = false;
if (!VM.BuildForIA32)
return false;
if (!IfCmp.conforms(cb))
return false;
if (VERBOSE)
System.out.println("CondMove: Looking to optimize " + cb);
// Don't generate CMOVs for branches that can be folded.
if (IfCmp.getVal1(cb).isConstant() && IfCmp.getVal2(cb).isConstant()) {
if (VERBOSE)
System.out.println("CondMove: fail - could be folded");
return false;
}
// see if bb is the root of an if-then-else.
Diamond diamond = Diamond.buildDiamond(bb);
if (diamond == null) {
if (VERBOSE)
System.out.println("CondMove: fail - no diamond");
return false;
}
BasicBlock taken = diamond.getTaken();
BasicBlock notTaken = diamond.getNotTaken();
// has a taboo instruction (eg., a PEI, store or divide).
if (taken != null && hasCMTaboo(taken)) {
if (VERBOSE)
System.out.println("CondMove: fail - taken branch has taboo instruction");
return false;
}
if (notTaken != null && hasCMTaboo(notTaken)) {
if (VERBOSE)
System.out.println("CondMove: fail - not taken branch has taboo instruction");
return false;
}
ConditionOperand cond = IfCmp.getCond(cb);
// Do not generate when we don't know the branch probability or
// when branch probability is high. CMOVs reduce performance of
// the out-of-order engine (Intel Optimization Guide -
// Assembly/Compiler Coding Rule 2).
// Ignore in the case of an abs() method as we can create tighter
// instructions.
BranchProfileOperand profile = IfCmp.getBranchProfile(cb);
if ((Math.abs(profile.takenProbability - 0.5) >= ir.options.CONTROL_WELL_PREDICTED_CUTOFF) && !(cb.position() != null && cb.position().method.getName() == ABS && cond.isFLOATINGPOINT())) {
if (VERBOSE)
System.out.println("CondMove: fail - branch could be well predicted by branch predictor: " + profile.takenProbability);
return false;
}
// if we must generate FCMP, make sure the condition code is OK
if (cond.isFLOATINGPOINT()) {
if (!fpConditionOK(cond)) {
// Condition not OK, but maybe if we flip the operands
if (!fpConditionOK(cond.flipOperands())) {
// still not ok so flip operands back
cond.flipOperands();
// controlling just floating point moves
if (!VM.BuildForSSE2Full || hasFloatingPointDef(taken, true) || hasFloatingPointDef(notTaken, true)) {
if (VERBOSE)
System.out.println("CondMove: fail - fp condition not OK: " + cond);
return false;
}
} else {
// flip operands
Operand val1 = IfCmp.getVal1(cb);
Operand val2 = IfCmp.getVal2(cb);
IfCmp.setVal1(cb, val2);
IfCmp.setVal2(cb, val1);
}
}
}
if (!cond.isFLOATINGPOINT()) {
// compares or for unsigned compares in x87
if (VM.BuildForSSE2Full || !cond.isUNSIGNED()) {
if (hasFloatingPointDef(taken, false) || hasFloatingPointDef(notTaken, false)) {
if (VERBOSE)
System.out.println("CondMove: fail - not allowed integer condition controlling floating conditional move");
return false;
}
}
}
// For now, do not generate CMOVs for longs.
if (hasLongDef(taken) || hasLongDef(notTaken)) {
return false;
}
// count the number of expression evaluations in each side of the
// diamond
int takenCost = 0;
int notTakenCost = 0;
if (taken != null)
takenCost = evaluateCost(taken);
if (notTaken != null)
notTakenCost = evaluateCost(notTaken);
// evaluate whether it's profitable.
int shortestCost = Math.min(takenCost, notTakenCost);
int xformCost = 2 * (takenCost + notTakenCost);
int k = ir.options.CONTROL_COND_MOVE_CUTOFF;
if (xformCost - shortestCost > k) {
if (VERBOSE)
System.out.println("CondMove: fail - cost too high");
return false;
}
// Perform the transformation!
doCondMove(ir, diamond, cb);
return true;
}
use of org.jikesrvm.compilers.opt.ir.operand.ConditionOperand in project JikesRVM by JikesRVM.
the class BURS_Helpers method TRAP_IF_IMM.
/**
* Expansion of TRAP_IF, with an int constant as the second value.
*
* @param s the instruction to expand
* @param longConstant is the argument a long constant?
*/
protected final void TRAP_IF_IMM(Instruction s, boolean longConstant) {
RegisterOperand gRes = TrapIf.getGuardResult(s);
RegisterOperand v1 = (RegisterOperand) TrapIf.getVal1(s);
ConstantOperand v2 = (ConstantOperand) TrapIf.getVal2(s);
ConditionOperand cond = TrapIf.getCond(s);
TrapCodeOperand tc = TrapIf.getTCode(s);
// A little awkward, but probably the easiest workaround...
if (VM.BuildFor32Addr && longConstant) {
if (VM.VerifyAssertions) {
opt_assert((tc.getTrapCode() == RuntimeEntrypoints.TRAP_DIVIDE_BY_ZERO) && (((LongConstantOperand) v2).value == 0L));
}
RegisterOperand vr = v1.copyRO();
vr.setType(TypeReference.Int);
RegisterOperand rr = regpool.makeTempInt();
EMIT(CPOS(s, MIR_Move.create(IA32_MOV, rr, vr)));
EMIT(CPOS(s, MIR_BinaryAcc.create(IA32_OR, rr.copy(), new RegisterOperand(regpool.getSecondReg(v1.getRegister()), TypeReference.Int))));
v1 = rr.copyD2U();
v2 = IC(0);
}
// emit the trap instruction
EMIT(MIR_TrapIf.mutate(s, IA32_TRAPIF, gRes, v1, v2, COND(cond), tc));
}
use of org.jikesrvm.compilers.opt.ir.operand.ConditionOperand in project JikesRVM by JikesRVM.
the class ComplexLIR2MIRExpansion method long_ifcmp_imm.
private static Instruction long_ifcmp_imm(Instruction s, IR ir) {
Instruction nextInstr = s.nextInstructionInCodeOrder();
ConditionOperand cond = IfCmp.getCond(s);
Register xh = ((RegisterOperand) IfCmp.getVal1(s)).getRegister();
Register xl = ir.regpool.getSecondReg(xh);
LongConstantOperand rhs = (LongConstantOperand) IfCmp.getVal2(s);
int low = rhs.lower32();
int high = rhs.upper32();
IntConstantOperand yh = IC(high);
IntConstantOperand yl = IC(low);
if (cond.isEQUAL() || cond.isNOT_EQUAL()) {
// tricky... ((xh^yh)|(xl^yl) == 0) <==> (lhll == rhrl)!!
Register th = ir.regpool.getInteger();
Register tl = ir.regpool.getInteger();
if (high == 0) {
if (low == 0) {
// 0,0
s.insertBefore(MIR_Move.create(IA32_MOV, new RegisterOperand(th, TypeReference.Int), new RegisterOperand(xh, TypeReference.Int)));
s.insertBefore(MIR_BinaryAcc.create(IA32_OR, new RegisterOperand(th, TypeReference.Int), new RegisterOperand(xl, TypeReference.Int)));
} else if (low == -1) {
// 0,-1
s.insertBefore(MIR_Move.create(IA32_MOV, new RegisterOperand(tl, TypeReference.Int), new RegisterOperand(xl, TypeReference.Int)));
s.insertBefore(MIR_UnaryAcc.create(IA32_NOT, new RegisterOperand(tl, TypeReference.Int)));
s.insertBefore(MIR_BinaryAcc.create(IA32_OR, new RegisterOperand(tl, TypeReference.Int), new RegisterOperand(xh, TypeReference.Int)));
} else {
// 0,*
s.insertBefore(MIR_Move.create(IA32_MOV, new RegisterOperand(tl, TypeReference.Int), new RegisterOperand(xl, TypeReference.Int)));
s.insertBefore(MIR_BinaryAcc.create(IA32_XOR, new RegisterOperand(tl, TypeReference.Int), yl));
s.insertBefore(MIR_BinaryAcc.create(IA32_OR, new RegisterOperand(tl, TypeReference.Int), new RegisterOperand(xh, TypeReference.Int)));
}
} else if (high == -1) {
if (low == 0) {
// -1,0
s.insertBefore(MIR_Move.create(IA32_MOV, new RegisterOperand(th, TypeReference.Int), new RegisterOperand(xh, TypeReference.Int)));
s.insertBefore(MIR_UnaryAcc.create(IA32_NOT, new RegisterOperand(th, TypeReference.Int)));
s.insertBefore(MIR_BinaryAcc.create(IA32_OR, new RegisterOperand(th, TypeReference.Int), new RegisterOperand(xl, TypeReference.Int)));
} else if (low == -1) {
// -1,-1
s.insertBefore(MIR_Move.create(IA32_MOV, new RegisterOperand(th, TypeReference.Int), new RegisterOperand(xh, TypeReference.Int)));
s.insertBefore(MIR_UnaryAcc.create(IA32_NOT, new RegisterOperand(th, TypeReference.Int)));
s.insertBefore(MIR_Move.create(IA32_MOV, new RegisterOperand(tl, TypeReference.Int), new RegisterOperand(xl, TypeReference.Int)));
s.insertBefore(MIR_UnaryAcc.create(IA32_NOT, new RegisterOperand(tl, TypeReference.Int)));
s.insertBefore(MIR_BinaryAcc.create(IA32_OR, new RegisterOperand(th, TypeReference.Int), new RegisterOperand(tl, TypeReference.Int)));
} else {
// -1,*
s.insertBefore(MIR_Move.create(IA32_MOV, new RegisterOperand(th, TypeReference.Int), new RegisterOperand(xh, TypeReference.Int)));
s.insertBefore(MIR_UnaryAcc.create(IA32_NOT, new RegisterOperand(th, TypeReference.Int)));
s.insertBefore(MIR_Move.create(IA32_MOV, new RegisterOperand(tl, TypeReference.Int), new RegisterOperand(xl, TypeReference.Int)));
s.insertBefore(MIR_BinaryAcc.create(IA32_XOR, new RegisterOperand(tl, TypeReference.Int), yl));
s.insertBefore(MIR_BinaryAcc.create(IA32_OR, new RegisterOperand(th, TypeReference.Int), new RegisterOperand(tl, TypeReference.Int)));
}
} else {
if (low == 0) {
// *,0
s.insertBefore(MIR_Move.create(IA32_MOV, new RegisterOperand(th, TypeReference.Int), new RegisterOperand(xh, TypeReference.Int)));
s.insertBefore(MIR_BinaryAcc.create(IA32_XOR, new RegisterOperand(th, TypeReference.Int), yh));
s.insertBefore(MIR_BinaryAcc.create(IA32_OR, new RegisterOperand(th, TypeReference.Int), new RegisterOperand(xl, TypeReference.Int)));
} else if (low == -1) {
// *,-1
s.insertBefore(MIR_Move.create(IA32_MOV, new RegisterOperand(th, TypeReference.Int), new RegisterOperand(xh, TypeReference.Int)));
s.insertBefore(MIR_BinaryAcc.create(IA32_XOR, new RegisterOperand(th, TypeReference.Int), yh));
s.insertBefore(MIR_Move.create(IA32_MOV, new RegisterOperand(tl, TypeReference.Int), new RegisterOperand(xl, TypeReference.Int)));
s.insertBefore(MIR_UnaryAcc.create(IA32_NOT, new RegisterOperand(tl, TypeReference.Int)));
s.insertBefore(MIR_BinaryAcc.create(IA32_OR, new RegisterOperand(th, TypeReference.Int), new RegisterOperand(tl, TypeReference.Int)));
} else {
// neither high nor low is special
s.insertBefore(MIR_Move.create(IA32_MOV, new RegisterOperand(th, TypeReference.Int), new RegisterOperand(xh, TypeReference.Int)));
s.insertBefore(MIR_BinaryAcc.create(IA32_XOR, new RegisterOperand(th, TypeReference.Int), yh));
s.insertBefore(MIR_Move.create(IA32_MOV, new RegisterOperand(tl, TypeReference.Int), new RegisterOperand(xl, TypeReference.Int)));
s.insertBefore(MIR_BinaryAcc.create(IA32_XOR, new RegisterOperand(tl, TypeReference.Int), yl));
s.insertBefore(MIR_BinaryAcc.create(IA32_OR, new RegisterOperand(th, TypeReference.Int), new RegisterOperand(tl, TypeReference.Int)));
}
}
MIR_CondBranch.mutate(s, IA32_JCC, new IA32ConditionOperand(cond), IfCmp.getTarget(s), IfCmp.getBranchProfile(s));
return nextInstr;
} else {
// pick up a few special cases where the sign of xh is sufficient
if (rhs.value == 0L) {
if (cond.isLESS()) {
// xh < 0 implies true
s.insertBefore(MIR_Compare.create(IA32_CMP, new RegisterOperand(xh, TypeReference.Int), IC(0)));
MIR_CondBranch.mutate(s, IA32_JCC, IA32ConditionOperand.LT(), IfCmp.getTarget(s), IfCmp.getBranchProfile(s));
return nextInstr;
} else if (cond.isGREATER_EQUAL()) {
s.insertBefore(MIR_Compare.create(IA32_CMP, new RegisterOperand(xh, TypeReference.Int), IC(0)));
MIR_CondBranch.mutate(s, IA32_JCC, IA32ConditionOperand.GE(), IfCmp.getTarget(s), IfCmp.getBranchProfile(s));
return nextInstr;
}
} else if (rhs.value == -1L) {
if (cond.isLESS_EQUAL()) {
s.insertBefore(MIR_Compare.create(IA32_CMP, new RegisterOperand(xh, TypeReference.Int), IC(-1)));
MIR_CondBranch.mutate(s, IA32_JCC, IA32ConditionOperand.LE(), IfCmp.getTarget(s), IfCmp.getBranchProfile(s));
return nextInstr;
} else if (cond.isGREATER()) {
s.insertBefore(MIR_Compare.create(IA32_CMP, new RegisterOperand(xh, TypeReference.Int), IC(0)));
MIR_CondBranch.mutate(s, IA32_JCC, IA32ConditionOperand.GE(), IfCmp.getTarget(s), IfCmp.getBranchProfile(s));
return nextInstr;
}
}
basic_long_ifcmp(s, ir, cond, xh, xl, yh, yl);
return nextInstr;
}
}
use of org.jikesrvm.compilers.opt.ir.operand.ConditionOperand in project JikesRVM by JikesRVM.
the class ComplexLIR2MIRExpansion method fp_ifcmp.
// the fcmoi/fcmoip was generated by burs
// we do the rest of the expansion here because in some
// cases we must remove a trailing goto, and we
// can't do that in burs!
private static Instruction fp_ifcmp(Instruction s) {
Instruction nextInstr = s.nextInstructionInCodeOrder();
BranchOperand testFailed;
BasicBlock bb = s.getBasicBlock();
Instruction lastInstr = bb.lastRealInstruction();
if (lastInstr.operator() == IA32_JMP) {
// We're in trouble if there is another instruction between s and lastInstr!
if (VM.VerifyAssertions)
VM._assert(s.nextInstructionInCodeOrder() == lastInstr);
// Set testFailed to target of GOTO
testFailed = MIR_Branch.getClearTarget(lastInstr);
nextInstr = lastInstr.nextInstructionInCodeOrder();
lastInstr.remove();
} else {
// Set testFailed to label of next (fallthrough basic block)
testFailed = bb.nextBasicBlockInCodeOrder().makeJumpTarget();
}
// Translate condition operand respecting IA32 FCOMI/COMISS/COMISD
Instruction fcomi = s.prevInstructionInCodeOrder();
Operand val1 = MIR_Compare.getVal1(fcomi);
Operand val2 = MIR_Compare.getVal2(fcomi);
ConditionOperand c = IfCmp.getCond(s);
BranchOperand target = IfCmp.getTarget(s).copy().asBranch();
BranchProfileOperand branchProfile = (BranchProfileOperand) IfCmp.getBranchProfile(s).copy();
// propagate the original probability to the second condition.
switch(c.value) {
// (i.e. UNORDERED is a goto to testFailed)
case ConditionOperand.CMPL_EQUAL:
if (VM.VerifyAssertions)
VM._assert(!c.branchIfUnordered());
// Check whether val1 and val2 operands are the same
if (!val1.similar(val2)) {
s.insertBefore(MIR_CondBranch2.create(IA32_JCC2, IA32ConditionOperand.PE(), // PF == 1
testFailed, new BranchProfileOperand(0f), IA32ConditionOperand.EQ(), // ZF == 1
target, branchProfile));
s.insertBefore(MIR_Branch.create(IA32_JMP, (BranchOperand) (testFailed.copy())));
} else {
// As val1 == val2 result of compare must be == or UNORDERED
s.insertBefore(// PF == 0
MIR_CondBranch.create(// PF == 0
IA32_JCC, // PF == 0
IA32ConditionOperand.PO(), target, branchProfile));
s.insertBefore(MIR_Branch.create(IA32_JMP, testFailed));
}
break;
case ConditionOperand.CMPL_GREATER:
if (VM.VerifyAssertions)
VM._assert(!c.branchIfUnordered());
s.insertBefore(// CF == 0 and ZF == 0
MIR_CondBranch.create(// CF == 0 and ZF == 0
IA32_JCC, // CF == 0 and ZF == 0
IA32ConditionOperand.LGT(), target, branchProfile));
s.insertBefore(MIR_Branch.create(IA32_JMP, testFailed));
break;
case ConditionOperand.CMPG_LESS:
if (VM.VerifyAssertions)
VM._assert(!c.branchIfUnordered());
s.insertBefore(MIR_CondBranch2.create(IA32_JCC2, IA32ConditionOperand.PE(), // PF == 1
testFailed, new BranchProfileOperand(0f), IA32ConditionOperand.LLT(), // CF == 1
target, branchProfile));
s.insertBefore(MIR_Branch.create(IA32_JMP, (BranchOperand) (testFailed.copy())));
break;
case ConditionOperand.CMPL_GREATER_EQUAL:
if (VM.VerifyAssertions)
VM._assert(!c.branchIfUnordered());
s.insertBefore(// CF == 0
MIR_CondBranch.create(// CF == 0
IA32_JCC, // CF == 0
IA32ConditionOperand.LGE(), target, branchProfile));
s.insertBefore(MIR_Branch.create(IA32_JMP, testFailed));
break;
case ConditionOperand.CMPG_LESS_EQUAL:
s.insertBefore(MIR_CondBranch2.create(IA32_JCC2, IA32ConditionOperand.PE(), // PF == 1
testFailed, new BranchProfileOperand(0f), IA32ConditionOperand.LGT(), // ZF == 0 and CF == 0
(BranchOperand) (testFailed.copy()), branchProfile));
s.insertBefore(MIR_Branch.create(IA32_JMP, target));
break;
// (i.e. UNORDERED is a goto to target)
case ConditionOperand.CMPL_NOT_EQUAL:
if (VM.VerifyAssertions)
VM._assert(c.branchIfUnordered());
// Check whether val1 and val2 operands are the same
if (!val1.similar(val2)) {
s.insertBefore(MIR_CondBranch2.create(IA32_JCC2, IA32ConditionOperand.PE(), // PF == 1
target, new BranchProfileOperand(0f), IA32ConditionOperand.NE(), // ZF == 0
(BranchOperand) (target.copy()), branchProfile));
s.insertBefore(MIR_Branch.create(IA32_JMP, testFailed));
} else {
// As val1 == val2 result of compare must be == or UNORDERED
s.insertBefore(// PF == 1
MIR_CondBranch.create(// PF == 1
IA32_JCC, // PF == 1
IA32ConditionOperand.PE(), target, branchProfile));
s.insertBefore(MIR_Branch.create(IA32_JMP, testFailed));
}
break;
case ConditionOperand.CMPL_LESS:
if (VM.VerifyAssertions)
VM._assert(c.branchIfUnordered());
s.insertBefore(// CF == 1
MIR_CondBranch.create(// CF == 1
IA32_JCC, // CF == 1
IA32ConditionOperand.LLT(), target, branchProfile));
s.insertBefore(MIR_Branch.create(IA32_JMP, testFailed));
break;
case ConditionOperand.CMPG_GREATER_EQUAL:
if (VM.VerifyAssertions)
VM._assert(c.branchIfUnordered());
s.insertBefore(MIR_CondBranch2.create(IA32_JCC2, IA32ConditionOperand.PE(), // PF == 1
target, new BranchProfileOperand(0f), IA32ConditionOperand.LLT(), // CF == 1
testFailed, branchProfile));
s.insertBefore(MIR_Branch.create(IA32_JMP, (BranchOperand) (target.copy())));
break;
case ConditionOperand.CMPG_GREATER:
if (VM.VerifyAssertions)
VM._assert(c.branchIfUnordered());
s.insertBefore(MIR_CondBranch2.create(IA32_JCC2, IA32ConditionOperand.PE(), // PF == 1
target, new BranchProfileOperand(0f), IA32ConditionOperand.LGT(), // ZF == 0 and CF == 0
(BranchOperand) (target.copy()), branchProfile));
s.insertBefore(MIR_Branch.create(IA32_JMP, testFailed));
break;
case ConditionOperand.CMPL_LESS_EQUAL:
if (VM.VerifyAssertions)
VM._assert(c.branchIfUnordered());
s.insertBefore(// CF == 1 or ZF == 1
MIR_CondBranch.create(// CF == 1 or ZF == 1
IA32_JCC, // CF == 1 or ZF == 1
IA32ConditionOperand.LLE(), target, branchProfile));
s.insertBefore(MIR_Branch.create(IA32_JMP, testFailed));
break;
default:
OptimizingCompilerException.UNREACHABLE();
}
s.remove();
return nextInstr;
}
use of org.jikesrvm.compilers.opt.ir.operand.ConditionOperand in project JikesRVM by JikesRVM.
the class ComplexLIR2MIRExpansion method long_ifcmp.
private static Instruction long_ifcmp(Instruction s, IR ir) {
Instruction nextInstr = s.nextInstructionInCodeOrder();
ConditionOperand cond = IfCmp.getCond(s);
Register xh = ((RegisterOperand) IfCmp.getVal1(s)).getRegister();
Register xl = ir.regpool.getSecondReg(xh);
RegisterOperand yh = (RegisterOperand) IfCmp.getClearVal2(s);
yh.setType(TypeReference.Int);
RegisterOperand yl = new RegisterOperand(ir.regpool.getSecondReg(yh.getRegister()), TypeReference.Int);
basic_long_ifcmp(s, ir, cond, xh, xl, yh, yl);
return nextInstr;
}
Aggregations