/*
* 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.ppc;
import org.jikesrvm.VM;
import org.jikesrvm.compilers.opt.OPT_DefUse;
import org.jikesrvm.compilers.opt.ir.Attempt;
import org.jikesrvm.compilers.opt.ir.Binary;
import org.jikesrvm.compilers.opt.ir.BooleanCmp;
import org.jikesrvm.compilers.opt.ir.IfCmp;
import org.jikesrvm.compilers.opt.ir.MIR_Binary;
import org.jikesrvm.compilers.opt.ir.MIR_Branch;
import org.jikesrvm.compilers.opt.ir.MIR_CondBranch;
import org.jikesrvm.compilers.opt.ir.MIR_CondBranch2;
import org.jikesrvm.compilers.opt.ir.MIR_Load;
import org.jikesrvm.compilers.opt.ir.MIR_Move;
import org.jikesrvm.compilers.opt.ir.MIR_Store;
import org.jikesrvm.compilers.opt.ir.MIR_Unary;
import org.jikesrvm.compilers.opt.ir.Nullary;
import org.jikesrvm.compilers.opt.ir.OPT_BasicBlock;
import org.jikesrvm.compilers.opt.ir.OPT_BranchProfileOperand;
import org.jikesrvm.compilers.opt.ir.OPT_ConditionOperand;
import org.jikesrvm.compilers.opt.ir.OPT_IR;
import org.jikesrvm.compilers.opt.ir.OPT_IRTools;
import org.jikesrvm.compilers.opt.ir.OPT_Instruction;
import org.jikesrvm.compilers.opt.ir.OPT_IntConstantOperand;
import org.jikesrvm.compilers.opt.ir.OPT_LocationOperand;
import org.jikesrvm.compilers.opt.ir.OPT_Operand;
import org.jikesrvm.compilers.opt.ir.OPT_Operator;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.ATTEMPT_ADDR_opcode;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.ATTEMPT_INT_opcode;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.ATTEMPT_LONG_opcode;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.BOOLEAN_CMP_ADDR_opcode;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.BOOLEAN_CMP_INT_opcode;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_2INT_opcode;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_2LONG_opcode;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_CMPG_opcode;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.DOUBLE_CMPL_opcode;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_2INT_opcode;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_2LONG_opcode;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_CMPG_opcode;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.FLOAT_CMPL_opcode;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.GET_TIME_BASE_opcode;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_CMP_opcode;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_IFCMP_opcode;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LONG_SHR_opcode;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PPC64_CMP;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PPC64_CMPI;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PPC64_CMPL;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PPC64_CMPLI;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PPC64_FCTIDZ;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PPC64_LD;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PPC_ADDI;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PPC_B;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PPC_BCOND;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PPC_BCOND2;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PPC_CMP;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PPC_CMPI;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PPC_CMPL;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PPC_CMPLI;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PPC_FCMPU;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PPC_FCTIWZ;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PPC_LDI;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PPC_LInt;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PPC_MFTB;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PPC_MFTBU;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PPC_MOVE;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PPC_OR;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PPC_SLW;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PPC_SRAW;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PPC_SRW;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PPC_STAddrCXr;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PPC_STFD;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PPC_STWCXr;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.PPC_SUBFIC;
import org.jikesrvm.compilers.opt.ir.OPT_Register;
import org.jikesrvm.compilers.opt.ir.OPT_RegisterOperand;
import org.jikesrvm.compilers.opt.ir.Unary;
import org.jikesrvm.compilers.opt.ir.ppc.OPT_PhysicalRegisterSet;
import org.jikesrvm.compilers.opt.ir.ppc.OPT_PowerPCConditionOperand;
/**
* Handles the conversion from LIR to MIR of operators whose
* expansion requires the introduction of new control flow (new basic blocks).
*
* TODO: Make these methods virtual; spilt into Common superclass with
* 32/64 subclasses.
*/
public abstract class OPT_ComplexLIR2MIRExpansion extends OPT_IRTools {
/**
* Converts the given IR to low level PowerPC IR.
*
* @param ir IR to convert
*/
public static void convert(OPT_IR ir) {
for (OPT_Instruction next = null, s = ir.firstInstructionInCodeOrder(); s != null; s = next) {
next = s.nextInstructionInCodeOrder();
switch (s.getOpcode()) {
case DOUBLE_2INT_opcode:
case FLOAT_2INT_opcode:
double_2int(s, ir);
break;
case DOUBLE_2LONG_opcode:
case FLOAT_2LONG_opcode:
if (VM.BuildFor64Addr) {
double_2long(s, ir);
} else {
if (VM.VerifyAssertions) VM._assert(false);
}
break;
case LONG_SHR_opcode:
if (VM.BuildFor32Addr) {
long_shr(s, ir);
} else {
if (VM.VerifyAssertions) VM._assert(false);
}
break;
case LONG_IFCMP_opcode:
if (VM.BuildFor32Addr) {
long_ifcmp(s, ir);
} else {
if (VM.VerifyAssertions) VM._assert(false);
}
break;
case BOOLEAN_CMP_INT_opcode:
boolean_cmp(s, ir, true);
break;
case BOOLEAN_CMP_ADDR_opcode:
boolean_cmp(s, ir, VM.BuildFor32Addr);
break;
case DOUBLE_CMPL_opcode:
case FLOAT_CMPL_opcode:
case DOUBLE_CMPG_opcode:
case FLOAT_CMPG_opcode:
threeValueCmp(s, ir);
break;
case LONG_CMP_opcode:
threeValueLongCmp(s, ir);
break;
case GET_TIME_BASE_opcode:
get_time_base(s, ir);
break;
case ATTEMPT_INT_opcode:
attempt(s, ir, false, false);
break;
case ATTEMPT_LONG_opcode:
attempt(s, ir, false, true);
break;
case ATTEMPT_ADDR_opcode:
attempt(s, ir, true, false);
break;
}
}
OPT_DefUse.recomputeSpansBasicBlock(ir);
}
private static void double_2int(OPT_Instruction s, OPT_IR ir) {
OPT_Register res = Unary.getResult(s).getRegister();
OPT_Register src = ((OPT_RegisterOperand) Unary.getVal(s)).getRegister();
OPT_Register FP = ir.regpool.getPhysicalRegisterSet().getFP();
int p = ir.stackManager.allocateSpaceForConversion();
OPT_Register temp = ir.regpool.getDouble();
OPT_BasicBlock BB1 = s.getBasicBlock();
OPT_BasicBlock BB3 = BB1.splitNodeAt(s, ir);
OPT_BasicBlock BB2 = BB1.createSubBlock(0, ir);
OPT_RegisterOperand cond = ir.regpool.makeTempCondition();
BB1.appendInstruction(MIR_Binary.create(PPC_FCMPU, cond, D(src), D(src)));
BB1.appendInstruction(MIR_Unary.create(PPC_LDI, I(res), IC(0)));
BB1.appendInstruction(MIR_CondBranch.create(PPC_BCOND,
cond.copyD2U(),
OPT_PowerPCConditionOperand.UNORDERED(),
BB3.makeJumpTarget(),
new OPT_BranchProfileOperand()));
BB2.appendInstruction(MIR_Unary.create(PPC_FCTIWZ, D(temp), D(src)));
BB2.appendInstruction(MIR_Store.create(PPC_STFD, D(temp), A(FP), IC(p)));
BB2.appendInstruction(MIR_Load.create(PPC_LInt, I(res), A(FP), IC(p + 4)));
// fix up CFG
BB1.insertOut(BB2);
BB1.insertOut(BB3);
BB2.insertOut(BB3);
ir.cfg.linkInCodeOrder(BB1, BB2);
ir.cfg.linkInCodeOrder(BB2, BB3);
s.remove();
}
private static void double_2long(OPT_Instruction s, OPT_IR ir) {
if (VM.VerifyAssertions) VM._assert(VM.BuildFor64Addr);
OPT_Register res = Unary.getResult(s).getRegister();
OPT_Register src = ((OPT_RegisterOperand) Unary.getVal(s)).getRegister();
OPT_Register FP = ir.regpool.getPhysicalRegisterSet().getFP();
int p = ir.stackManager.allocateSpaceForConversion();
OPT_Register temp = ir.regpool.getDouble();
OPT_BasicBlock BB1 = s.getBasicBlock();
OPT_BasicBlock BB3 = BB1.splitNodeAt(s, ir);
OPT_BasicBlock BB2 = BB1.createSubBlock(0, ir);
OPT_RegisterOperand cond = ir.regpool.makeTempCondition();
BB1.appendInstruction(MIR_Binary.create(PPC_FCMPU, cond, D(src), D(src)));
BB1.appendInstruction(MIR_Unary.create(PPC_LDI, L(res), IC(0)));
BB1.appendInstruction(MIR_CondBranch.create(PPC_BCOND,
cond.copyD2U(),
OPT_PowerPCConditionOperand.UNORDERED(),
BB3.makeJumpTarget(),
new OPT_BranchProfileOperand()));
BB2.appendInstruction(MIR_Unary.create(PPC64_FCTIDZ, D(temp), D(src)));
BB2.appendInstruction(MIR_Store.create(PPC_STFD, D(temp), A(FP), IC(p)));
BB2.appendInstruction(MIR_Load.create(PPC64_LD, L(res), A(FP), IC(p)));
// fix up CFG
BB1.insertOut(BB2);
BB1.insertOut(BB3);
BB2.insertOut(BB3);
ir.cfg.linkInCodeOrder(BB1, BB2);
ir.cfg.linkInCodeOrder(BB2, BB3);
s.remove();
}
private static void boolean_cmp(OPT_Instruction s, OPT_IR ir, boolean cmp32Bit) {
// undo the optimization because it cannot efficiently be generated
OPT_Register res = BooleanCmp.getClearResult(s).getRegister();
OPT_RegisterOperand one = (OPT_RegisterOperand) BooleanCmp.getClearVal1(s);
OPT_Operand two = BooleanCmp.getClearVal2(s);
OPT_ConditionOperand cond = BooleanCmp.getClearCond(s);
res.setSpansBasicBlock();
OPT_BasicBlock BB1 = s.getBasicBlock();
OPT_BasicBlock BB4 = BB1.splitNodeAt(s, ir);
s = s.remove();
OPT_BasicBlock BB2 = BB1.createSubBlock(0, ir);
OPT_BasicBlock BB3 = BB1.createSubBlock(0, ir);
OPT_RegisterOperand t = ir.regpool.makeTempInt();
t.getRegister().setCondition();
OPT_Operator op;
if (VM.BuildFor64Addr && !cmp32Bit) {
if (two instanceof OPT_IntConstantOperand) {
op = cond.isUNSIGNED() ? PPC64_CMPLI : PPC64_CMPI;
} else {
op = cond.isUNSIGNED() ? PPC64_CMPL : PPC64_CMP;
}
} else if (two instanceof OPT_IntConstantOperand) {
op = cond.isUNSIGNED() ? PPC_CMPLI : PPC_CMPI;
} else {
op = cond.isUNSIGNED() ? PPC_CMPL : PPC_CMP;
}
BB1.appendInstruction(MIR_Binary.create(op, t, one, two));
BB1.appendInstruction(MIR_CondBranch.create(PPC_BCOND,
t.copyD2U(),
OPT_PowerPCConditionOperand.get(cond),
BB3.makeJumpTarget(),
new OPT_BranchProfileOperand()));
BB2.appendInstruction(MIR_Unary.create(PPC_LDI, I(res), IC(0)));
BB2.appendInstruction(MIR_Branch.create(PPC_B, BB4.makeJumpTarget()));
BB3.appendInstruction(MIR_Unary.create(PPC_LDI, I(res), IC(1)));
// fix CFG
BB1.insertOut(BB2);
BB1.insertOut(BB3);
BB2.insertOut(BB4);
BB3.insertOut(BB4);
ir.cfg.linkInCodeOrder(BB1, BB2);
ir.cfg.linkInCodeOrder(BB2, BB3);
ir.cfg.linkInCodeOrder(BB3, BB4);
}
/**
* compare to values and set result to -1, 0, 1 for <, =, >, respectively
* @param s the compare instruction
* @param ir the governing IR
*/
private static void threeValueCmp(OPT_Instruction s, OPT_IR ir) {
OPT_PowerPCConditionOperand firstCond = OPT_PowerPCConditionOperand.LESS_EQUAL();
int firstConst = 1;
switch (s.operator.opcode) {
case DOUBLE_CMPG_opcode:
case FLOAT_CMPG_opcode:
firstCond = OPT_PowerPCConditionOperand.GREATER_EQUAL();
firstConst = -1;
break;
case DOUBLE_CMPL_opcode:
case FLOAT_CMPL_opcode:
break;
default:
if (VM.VerifyAssertions) VM._assert(false);
break;
}
OPT_Register res = Binary.getClearResult(s).getRegister();
OPT_RegisterOperand one = (OPT_RegisterOperand) Binary.getClearVal1(s);
OPT_RegisterOperand two = (OPT_RegisterOperand) Binary.getClearVal2(s);
res.setSpansBasicBlock();
OPT_BasicBlock BB1 = s.getBasicBlock();
OPT_BasicBlock BB6 = BB1.splitNodeAt(s, ir);
s = s.remove();
OPT_BasicBlock BB2 = BB1.createSubBlock(0, ir);
OPT_BasicBlock BB3 = BB1.createSubBlock(0, ir);
OPT_BasicBlock BB4 = BB1.createSubBlock(0, ir);
OPT_BasicBlock BB5 = BB1.createSubBlock(0, ir);
OPT_RegisterOperand t = ir.regpool.makeTempInt();
t.getRegister().setCondition();
BB1.appendInstruction(MIR_Binary.create(PPC_FCMPU, t, one, two));
BB1.appendInstruction(MIR_CondBranch.create(PPC_BCOND,
t.copyD2U(),
firstCond,
BB3.makeJumpTarget(),
new OPT_BranchProfileOperand(0.5f)));
BB2.appendInstruction(MIR_Unary.create(PPC_LDI, I(res), IC(firstConst)));
BB2.appendInstruction(MIR_Branch.create(PPC_B, BB6.makeJumpTarget()));
BB3.appendInstruction(MIR_CondBranch.create(PPC_BCOND,
t.copyD2U(),
OPT_PowerPCConditionOperand.EQUAL(),
BB5.makeJumpTarget(),
OPT_BranchProfileOperand.unlikely()));
BB4.appendInstruction(MIR_Unary.create(PPC_LDI, I(res), IC(-firstConst)));
BB4.appendInstruction(MIR_Branch.create(PPC_B, BB6.makeJumpTarget()));
BB5.appendInstruction(MIR_Unary.create(PPC_LDI, I(res), IC(0)));
// fix CFG
BB1.insertOut(BB2);
BB1.insertOut(BB3);
BB2.insertOut(BB6);
BB3.insertOut(BB4);
BB3.insertOut(BB5);
BB4.insertOut(BB6);
BB5.insertOut(BB6);
ir.cfg.linkInCodeOrder(BB1, BB2);
ir.cfg.linkInCodeOrder(BB2, BB3);
ir.cfg.linkInCodeOrder(BB3, BB4);
ir.cfg.linkInCodeOrder(BB4, BB5);
ir.cfg.linkInCodeOrder(BB5, BB6);
}
/**
* compare to values and set result to -1, 0, 1 for <, =, >, respectively
* @param s the compare instruction
* @param ir the governing IR
*/
private static void threeValueLongCmp(OPT_Instruction s, OPT_IR ir) {
if (VM.BuildFor32Addr) {
threeValueLongCmp_32(s, ir);
} else {
threeValueLongCmp_64(s, ir);
}
}
private static void threeValueLongCmp_32(OPT_Instruction s, OPT_IR ir) {
OPT_Register res = Binary.getClearResult(s).getRegister();
OPT_RegisterOperand one = (OPT_RegisterOperand) Binary.getClearVal1(s);
OPT_RegisterOperand two = (OPT_RegisterOperand) Binary.getClearVal2(s);
OPT_RegisterOperand lone = L(ir.regpool.getSecondReg(one.getRegister()));
OPT_RegisterOperand ltwo = L(ir.regpool.getSecondReg(two.getRegister()));
res.setSpansBasicBlock();
OPT_BasicBlock BB1 = s.getBasicBlock();
OPT_BasicBlock BB6 = BB1.splitNodeAt(s, ir);
s = s.remove();
OPT_BasicBlock BB2 = BB1.createSubBlock(0, ir);
OPT_BasicBlock BB3 = BB1.createSubBlock(0, ir);
OPT_BasicBlock BB4 = BB1.createSubBlock(0, ir);
OPT_BasicBlock BB5 = BB1.createSubBlock(0, ir);
OPT_RegisterOperand t = ir.regpool.makeTempInt();
t.getRegister().setCondition();
BB1.appendInstruction(MIR_Binary.create(PPC_CMP, t, one, two));
BB1.appendInstruction(MIR_CondBranch2.create(PPC_BCOND2,
t.copyD2U(),
OPT_PowerPCConditionOperand.LESS(),
BB4.makeJumpTarget(),
new OPT_BranchProfileOperand(0.49f),
OPT_PowerPCConditionOperand.GREATER(),
BB5.makeJumpTarget(),
new OPT_BranchProfileOperand(0.49f)));
BB2.appendInstruction(MIR_Binary.create(PPC_CMPL, t.copyD2D(), lone, ltwo));
BB2.appendInstruction(MIR_CondBranch2.create(PPC_BCOND2,
t.copyD2U(),
OPT_PowerPCConditionOperand.LESS(),
BB4.makeJumpTarget(),
new OPT_BranchProfileOperand(0.49f),
OPT_PowerPCConditionOperand.GREATER(),
BB5.makeJumpTarget(),
new OPT_BranchProfileOperand(0.49f)));
BB3.appendInstruction(MIR_Unary.create(PPC_LDI, I(res), IC(0)));
BB3.appendInstruction(MIR_Branch.create(PPC_B, BB6.makeJumpTarget()));
BB4.appendInstruction(MIR_Unary.create(PPC_LDI, I(res), IC(-1)));
BB4.appendInstruction(MIR_Branch.create(PPC_B, BB6.makeJumpTarget()));
BB5.appendInstruction(MIR_Unary.create(PPC_LDI, I(res), IC(1)));
// fix CFG
BB1.insertOut(BB2);
BB1.insertOut(BB4);
BB1.insertOut(BB5);
BB2.insertOut(BB3);
BB2.insertOut(BB4);
BB2.insertOut(BB5);
BB3.insertOut(BB6);
BB4.insertOut(BB6);
BB5.insertOut(BB6);
ir.cfg.linkInCodeOrder(BB1, BB2);
ir.cfg.linkInCodeOrder(BB2, BB3);
ir.cfg.linkInCodeOrder(BB3, BB4);
ir.cfg.linkInCodeOrder(BB4, BB5);
ir.cfg.linkInCodeOrder(BB5, BB6);
}
private static void threeValueLongCmp_64(OPT_Instruction s, OPT_IR ir) {
OPT_Register res = Binary.getClearResult(s).getRegister();
OPT_RegisterOperand one = (OPT_RegisterOperand) Binary.getClearVal1(s);
OPT_RegisterOperand two = (OPT_RegisterOperand) Binary.getClearVal2(s);
res.setSpansBasicBlock();
OPT_BasicBlock BB1 = s.getBasicBlock();
OPT_BasicBlock BB5 = BB1.splitNodeAt(s, ir);
s = s.remove();
OPT_BasicBlock BB2 = BB1.createSubBlock(0, ir);
OPT_BasicBlock BB3 = BB1.createSubBlock(0, ir);
OPT_BasicBlock BB4 = BB1.createSubBlock(0, ir);
OPT_RegisterOperand t = ir.regpool.makeTempInt();
t.getRegister().setCondition();
BB1.appendInstruction(MIR_Binary.create(PPC64_CMP, t, one, two));
BB1.appendInstruction(MIR_CondBranch2.create(PPC_BCOND2,
t.copyD2U(),
OPT_PowerPCConditionOperand.LESS(),
BB3.makeJumpTarget(),
new OPT_BranchProfileOperand(0.49f),
OPT_PowerPCConditionOperand.GREATER(),
BB4.makeJumpTarget(),
new OPT_BranchProfileOperand(0.49f)));
BB2.appendInstruction(MIR_Unary.create(PPC_LDI, I(res), IC(0)));
BB2.appendInstruction(MIR_Branch.create(PPC_B, BB5.makeJumpTarget()));
BB3.appendInstruction(MIR_Unary.create(PPC_LDI, I(res), IC(-1)));
BB3.appendInstruction(MIR_Branch.create(PPC_B, BB5.makeJumpTarget()));
BB4.appendInstruction(MIR_Unary.create(PPC_LDI, I(res), IC(1)));
// fix CFG
BB1.insertOut(BB2);
BB1.insertOut(BB3);
BB1.insertOut(BB4);
BB2.insertOut(BB5);
BB3.insertOut(BB5);
BB4.insertOut(BB5);
ir.cfg.linkInCodeOrder(BB1, BB2);
ir.cfg.linkInCodeOrder(BB2, BB3);
ir.cfg.linkInCodeOrder(BB3, BB4);
ir.cfg.linkInCodeOrder(BB4, BB5);
}
private static void long_shr(OPT_Instruction s, OPT_IR ir) {
OPT_BasicBlock BB1 = s.getBasicBlock();
OPT_BasicBlock BB2 = BB1.createSubBlock(0, ir);
OPT_BasicBlock BB3 = BB1.splitNodeAt(s, ir);
OPT_Register defHigh = Binary.getResult(s).getRegister();
OPT_Register defLow = ir.regpool.getSecondReg(defHigh);
OPT_RegisterOperand left = (OPT_RegisterOperand) Binary.getVal1(s);
OPT_Register leftHigh = left.getRegister();
OPT_Register leftLow = ir.regpool.getSecondReg(leftHigh);
OPT_RegisterOperand shiftOp = (OPT_RegisterOperand) Binary.getVal2(s);
OPT_Register shift = shiftOp.getRegister();
OPT_Register t31 = ir.regpool.getInteger();
OPT_Register t0 = ir.regpool.getInteger();
OPT_Register cr = ir.regpool.getCondition();
defLow.setSpansBasicBlock();
defHigh.setSpansBasicBlock();
s.insertBefore(MIR_Binary.create(PPC_SUBFIC, I(t31), I(shift), IC(32)));
s.insertBefore(MIR_Binary.create(PPC_SRW, I(defLow), I(leftLow), I(shift)));
s.insertBefore(MIR_Binary.create(PPC_SLW, I(t0), I(leftHigh), I(t31)));
s.insertBefore(MIR_Binary.create(PPC_OR, I(defLow), I(defLow), I(t0)));
s.insertBefore(MIR_Binary.create(PPC_ADDI, I(t31), I(shift), IC(-32)));
s.insertBefore(MIR_Binary.create(PPC_SRAW, I(t0), I(leftHigh), I(t31)));
s.insertBefore(MIR_Binary.create(PPC_SRAW, I(defHigh), I(leftHigh), I(shift)));
s.insertBefore(MIR_Binary.create(PPC_CMPI, I(cr), I(t31), IC(0)));
MIR_CondBranch.mutate(s,
PPC_BCOND,
I(cr),
OPT_PowerPCConditionOperand.LESS_EQUAL(),
BB3.makeJumpTarget(),
new OPT_BranchProfileOperand());
// insert the branch and second compare
BB2.appendInstruction(MIR_Move.create(PPC_MOVE, I(defLow), I(t0)));
// fix up CFG
BB1.insertOut(BB2);
BB1.insertOut(BB3);
BB2.insertOut(BB3);
ir.cfg.linkInCodeOrder(BB1, BB2);
ir.cfg.linkInCodeOrder(BB2, BB3);
}
private static void long_ifcmp(OPT_Instruction s, OPT_IR ir) {
if (VM.VerifyAssertions) VM._assert(!IfCmp.getCond(s).isUNSIGNED());
OPT_BasicBlock BB1 = s.getBasicBlock();
OPT_BasicBlock BB3 = BB1.splitNodeAt(s, ir);
OPT_BasicBlock BB2 = BB1.createSubBlock(0, ir);
BB1.insertOut(BB2);
BB1.insertOut(BB3);
BB2.insertOut(BB3);
ir.cfg.linkInCodeOrder(BB1, BB2);
ir.cfg.linkInCodeOrder(BB2, BB3);
s.remove(); // s is in BB1, we'll mutate it and insert in BB3 below.
OPT_RegisterOperand cr = ir.regpool.makeTempCondition();
OPT_RegisterOperand val1 = (OPT_RegisterOperand) IfCmp.getClearVal1(s);
OPT_RegisterOperand val2 = (OPT_RegisterOperand) IfCmp.getClearVal2(s);
OPT_RegisterOperand lval1 = L(ir.regpool.getSecondReg(val1.getRegister()));
OPT_RegisterOperand lval2 = L(ir.regpool.getSecondReg(val2.getRegister()));
OPT_PowerPCConditionOperand cond = new OPT_PowerPCConditionOperand(IfCmp.getCond(s));
BB1.appendInstruction(MIR_Binary.create(PPC_CMP, cr, val1, val2));
BB1.appendInstruction(MIR_CondBranch.create(PPC_BCOND,
cr.copyD2U(),
OPT_PowerPCConditionOperand.NOT_EQUAL(),
BB3.makeJumpTarget(),
new OPT_BranchProfileOperand()));
BB2.appendInstruction(MIR_Binary.create(PPC_CMPL, cr.copyD2D(), lval1, lval2));
BB3.prependInstruction(MIR_CondBranch.mutate(s,
PPC_BCOND,
cr.copyD2U(),
cond,
IfCmp.getTarget(s),
IfCmp.getBranchProfile(s)));
}
private static void get_time_base(OPT_Instruction s, OPT_IR ir) {
if (VM.BuildFor32Addr) {
OPT_BasicBlock BB1 = s.getBasicBlock();
BB1 = BB1.segregateInstruction(s, ir);
OPT_Register defHigh = Nullary.getResult(s).getRegister();
OPT_Register defLow = ir.regpool.getSecondReg(defHigh);
OPT_Register t0 = ir.regpool.getInteger();
OPT_Register cr = ir.regpool.getCondition();
defLow.setSpansBasicBlock();
defHigh.setSpansBasicBlock();
// Try to get the base
OPT_Register TU = ir.regpool.getPhysicalRegisterSet().getTU();
OPT_Register TL = ir.regpool.getPhysicalRegisterSet().getTL();
s.insertBefore(MIR_Move.create(PPC_MFTBU, I(defHigh), I(TU)));
s.insertBefore(MIR_Move.create(PPC_MFTB, I(defLow), I(TL)));
// Try again to see if it changed
s.insertBefore(MIR_Move.create(PPC_MFTBU, I(t0), I(TU)));
s.insertBefore(MIR_Binary.create(PPC_CMP, I(cr), I(t0), I(defHigh)));
MIR_CondBranch.mutate(s,
PPC_BCOND,
I(cr),
OPT_PowerPCConditionOperand.NOT_EQUAL(),
BB1.makeJumpTarget(),
new OPT_BranchProfileOperand());
// fix up CFG
BB1.insertOut(BB1);
} else {
// We read the 64-bit time base register atomically
OPT_Register def = Nullary.getResult(s).getRegister();
// See PowerPC Architecture, Book II, pp.352-353
OPT_Register TL = ir.regpool.getPhysicalRegisterSet().getTL();
MIR_Move.mutate(s, PPC_MFTB, L(def), L(TL));
}
}
private static void attempt(OPT_Instruction s, OPT_IR ir, boolean isAddress, boolean isLong) {
OPT_BasicBlock BB1 = s.getBasicBlock();
OPT_BasicBlock BB4 = BB1.splitNodeAt(s, ir);
OPT_BasicBlock BB2 = BB1.createSubBlock(0, ir);
OPT_BasicBlock BB3 = BB2.createSubBlock(0, ir);
BB1.insertOut(BB2);
BB1.insertOut(BB3);
BB2.insertOut(BB4);
BB3.insertOut(BB4);
ir.cfg.linkInCodeOrder(BB1, BB2);
ir.cfg.linkInCodeOrder(BB2, BB3);
ir.cfg.linkInCodeOrder(BB3, BB4);
// mutate ATTEMPT into a STWCX
OPT_RegisterOperand newValue = (OPT_RegisterOperand) Attempt.getNewValue(s);
OPT_RegisterOperand address = (OPT_RegisterOperand) Attempt.getAddress(s);
OPT_Operand offset = Attempt.getOffset(s);
OPT_LocationOperand location = Attempt.getLocation(s);
OPT_Operand guard = Attempt.getGuard(s);
OPT_RegisterOperand result = Attempt.getResult(s);
MIR_Store.mutate(s, (isAddress || isLong ? PPC_STAddrCXr : PPC_STWCXr),
newValue, address, offset, location, guard);
// Branch to BB3 iff the STWXC succeeds (CR(0) is EQUAL)
// Else fall through to BB2
OPT_PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet();
BB1.appendInstruction(MIR_CondBranch.create(PPC_BCOND,
I(phys.getConditionRegister(0)),
OPT_PowerPCConditionOperand.EQUAL(),
BB3.makeJumpTarget(),
new OPT_BranchProfileOperand()));
// BB2 sets result to FALSE and jumps to BB4
BB2.appendInstruction(MIR_Unary.create(PPC_LDI, result.copyRO(), IC(0)));
BB2.appendInstruction(MIR_Branch.create(PPC_B, BB4.makeJumpTarget()));
// BB3 sets result to TRUE and falls through to BB4
BB3.appendInstruction(MIR_Unary.create(PPC_LDI, result.copyRO(), IC(1)));
}
}